242 lines
6.8 KiB
Matlab
Executable File
242 lines
6.8 KiB
Matlab
Executable File
function model = yalmip2nonlinearsolver(model)
|
|
|
|
global newmodel
|
|
|
|
newmodel = 1;
|
|
|
|
model.dense = 0;
|
|
if ~model.equalitypresolved
|
|
model = propagate_bounds_from_equalities(model);
|
|
end
|
|
|
|
K = model.K;
|
|
lb = model.lb;
|
|
ub = model.ub;
|
|
x0 = model.x0;
|
|
c = model.c;
|
|
|
|
% Pick out the positive conditions from cones ||Ax+b|| <= c'*x+d which will
|
|
% be treated as (Ax+b)'*(ax+b) <= (c'*x+d)^2, c'*x+d >= 0
|
|
if any(K.q)
|
|
aux = [];
|
|
top = 1 + K.f + K.l;
|
|
for i = 1:length(K.q)
|
|
row = model.F_struc(top,:);
|
|
if any(row(2:end))
|
|
aux = [aux;row];
|
|
end
|
|
top = top + model.K.q(i);
|
|
end
|
|
model.F_struc = [model.F_struc(1:K.f+K.l,:);aux;model.F_struc(K.f+K.l+1:end,:)];
|
|
model.K.l = model.K.l + size(aux,1);
|
|
end
|
|
|
|
if isempty(model.evaluation_scheme)
|
|
model = build_recursive_scheme(model);
|
|
end
|
|
model = compress_evaluation_scheme(model);
|
|
|
|
% Do some pre-calc to be used in calls from fmincon
|
|
nonlinearindicies = union(find(model.variabletype~=0),model.evalVariables);
|
|
linearindicies = setdiff(find(model.variabletype==0),nonlinearindicies);
|
|
model.nonlinearindicies = nonlinearindicies;
|
|
model.linearindicies = linearindicies;
|
|
|
|
model.Anonlinineq = [];
|
|
model.bnonlinineq = [];
|
|
model.Anonlineq = [];
|
|
model.bnonlineq = [];
|
|
|
|
% Extract linear and nonlinear equality constraints
|
|
if K.f>0
|
|
Aeq = -model.F_struc(1:1:K.f,2:end);
|
|
beq = model.F_struc(1:1:model.K.f,1);
|
|
|
|
nonlinear_equalities_indicies = find(any(Aeq(:,nonlinearindicies),2));
|
|
model.Anonlineq = Aeq(nonlinear_equalities_indicies,:);
|
|
model.bnonlineq = beq(nonlinear_equalities_indicies);
|
|
|
|
Aeq(nonlinear_equalities_indicies,:) = [];
|
|
beq(nonlinear_equalities_indicies,:) = [];
|
|
Aeq(:,nonlinearindicies) = [];
|
|
model.F_struc(1:model.K.f,:) = [];
|
|
model.K.f = 0;
|
|
else
|
|
Aeq = [];
|
|
beq = [];
|
|
end
|
|
|
|
% Find nonlinear eualities implied by lower and upper bounds
|
|
if ~isempty(ub) && ~isempty(lb)
|
|
nonlinearequality = find(lb(nonlinearindicies) == ub(nonlinearindicies));
|
|
if ~isempty(nonlinearequality)
|
|
for i = 1:length(nonlinearequality)
|
|
model.Anonlineq = [model.Anonlineq;eyev(length(c),nonlinearindicies(nonlinearequality(i)))'];
|
|
model.bnonlineq = [model.bnonlineq;lb(nonlinearindicies(nonlinearequality(i)))];
|
|
end
|
|
end
|
|
end
|
|
|
|
% Extract linear and nonlinear inequality constraints
|
|
if model.K.l>0
|
|
A = -model.F_struc(1:model.K.l,2:end);
|
|
b = model.F_struc(1:model.K.l,1);
|
|
|
|
nonlinear_inequalities_indicies = find(any(A(:,nonlinearindicies),2));
|
|
|
|
model.Anonlinineq = A(nonlinear_inequalities_indicies,:);
|
|
model.bnonlinineq = b(nonlinear_inequalities_indicies);
|
|
|
|
A(nonlinear_inequalities_indicies,:) = [];
|
|
b(nonlinear_inequalities_indicies,:) = [];
|
|
A(:,nonlinearindicies) = [];
|
|
|
|
model.F_struc(1:model.K.l,:) = [];
|
|
model.K.l = 0;
|
|
else
|
|
A = [];
|
|
b = [];
|
|
end
|
|
|
|
% This helps with robustness in bnb in some cases
|
|
x0candidate = zeros(length(c),1);
|
|
if ~isempty(lb) && ~isempty(ub)
|
|
bounded = find(~isinf(lb) & ~isinf(ub));
|
|
x0candidate(bounded) = (lb(bounded) + ub(bounded))/2;
|
|
bounded_below = find(~isinf(lb) & isinf(ub));
|
|
x0candidate(bounded_below) = lb(bounded_below) + 0.5;
|
|
bounded_above = find(~isinf(lb) & isinf(ub));
|
|
x0candidate(bounded_above) = lb(bounded_above) + 0.5;
|
|
end
|
|
|
|
if isempty(x0)
|
|
x0 = x0candidate(linearindicies);
|
|
else
|
|
if ~isempty(lb) && ~isempty(ub)
|
|
x0((x0 < lb) | (x0 > ub)) = x0candidate((x0 < lb) | (x0 > ub));
|
|
end
|
|
x0 = x0(linearindicies);
|
|
end
|
|
|
|
if ~isempty(lb)
|
|
lb = lb(linearindicies);
|
|
end
|
|
if ~isempty(ub)
|
|
ub = ub(linearindicies);
|
|
end
|
|
|
|
lb_old = lb;
|
|
ub_old = ub;
|
|
[lb,ub,A,b] = remove_bounds_from_Ab(A,b,lb,ub);
|
|
[lb,ub,Aeq,beq] = remove_bounds_from_Aeqbeq(Aeq,beq,lb,ub);
|
|
|
|
if any(model.variabletype == 4)
|
|
problematic = find(any(model.monomtable(:,linearindicies) < 0 ,1));
|
|
if ~isempty(problematic)
|
|
problematic = problematic(find(x0(problematic)==0));
|
|
Oneisfeas = problematic(find(ub(problematic) > 1));
|
|
x0(Oneisfeas) = 1;
|
|
end
|
|
|
|
problematic = find(any(model.monomtable(:,linearindicies)~=fix(model.monomtable(:,linearindicies)) ,1));
|
|
lb(problematic) = max(lb(problematic),0);
|
|
end
|
|
x0(find(lb==ub)) = lb(find(lb==ub));
|
|
|
|
if size(A,1) == 0
|
|
A = [];
|
|
end
|
|
|
|
if size(b,1) == 0
|
|
b = [];
|
|
end
|
|
|
|
if size(Aeq,1) == 0
|
|
Aeq = [];
|
|
end
|
|
|
|
if size(beq,1) == 0
|
|
beq = [];
|
|
end
|
|
|
|
if model.presolveequalities
|
|
if ~isempty(beq) & (~model.equalitypresolved | ~(isequal(lb,lb_old) & isequal(ub,ub_old)))
|
|
% This helps when there are artificial variables introduced to model
|
|
% nonlinear operators such as log(2*x+1)
|
|
p.F_struc = [beq -Aeq];
|
|
p.K.f = size(beq,1);
|
|
p.lb = lb;
|
|
p.ub = ub;
|
|
p.variabletype = zeros(1,length(lb));
|
|
p.binary_variables = [];
|
|
p.integer_variables = [];
|
|
p = propagate_bounds_from_equalities(p);
|
|
lb = p.lb;
|
|
ub = p.ub;
|
|
end
|
|
end
|
|
|
|
model.A = A;
|
|
model.b = b;
|
|
model.Aeq = Aeq;
|
|
model.beq = beq;
|
|
model.lb = lb;
|
|
model.ub = ub;
|
|
model.x0 = x0;
|
|
|
|
model = setup_fmincon_params(model);
|
|
|
|
% Check if all derivatives are available
|
|
model.derivative_available = 1;
|
|
for i = 1:length(model.evalMap)
|
|
if isempty(model.evalMap{i}.properties.derivative)
|
|
model.derivative_available = 0;
|
|
break
|
|
end
|
|
end
|
|
|
|
% Some precomputation of computational scheme for Jacobian
|
|
allA = [model.Anonlineq;model.Anonlinineq];
|
|
if any(model.K.q)
|
|
allA = [allA;model.F_struc(1+model.K.f + model.K.f:end,2:end)];
|
|
end
|
|
requested = any(allA',2);
|
|
[i,j] = find((model.deppattern(find(requested),:)));
|
|
requested(j) = 1;
|
|
if ~isempty(model.evalMap)
|
|
% Recursive stuff is only possible if we have evaluation-based
|
|
% operators
|
|
model.Crecursivederivativeprecompute = precomputeDerivative(model,requested);
|
|
end
|
|
|
|
% Some precomputation of computational scheme for gradient
|
|
requested = model.c | any(model.Q,2);
|
|
[i,j,k] = find((model.deppattern(find(requested),:)));
|
|
requested(j) = 1;
|
|
model.frecursivederivativeprecompute = precomputeDerivative(model,requested);
|
|
|
|
% Precomputed list of bilinear expressions, used in
|
|
% apply_recursive_differentiation
|
|
Bilinears = find(model.variabletype==1);
|
|
BilinearsList = zeros(length(model.c),2);
|
|
for i = Bilinears
|
|
vars = find(model.monomtable(i,:));
|
|
BilinearsList(i,:) = vars(:)';
|
|
end
|
|
model.Bilinears = Bilinears;
|
|
model.BilinearsList = BilinearsList;
|
|
% Precomputed list of quadratic expressions, used in
|
|
% apply_recursive_differentiation
|
|
Quadratics = find(model.variabletype==2);
|
|
QuadraticsList = zeros(length(model.c),2);
|
|
for i = Quadratics
|
|
vars = find(model.monomtable(i,:));
|
|
QuadraticsList(i,:) = vars(:)';
|
|
end
|
|
model.Quadratics = Quadratics;
|
|
model.QuadraticsList = QuadraticsList;
|
|
|
|
model.binary_variables = find(ismember(linearindicies,model.binary_variables));
|
|
model.integer_variables = find(ismember(linearindicies,model.integer_variables));
|
|
model.semicont_variables = find(ismember(linearindicies,model.semicont_variables));
|