505 lines
19 KiB
Matlab
Executable File
505 lines
19 KiB
Matlab
Executable File
function [problem,integer_variables,binary_variables,parametric_variables,uncertain_variables,semicont_variables,quad_info] = categorizeproblem(F,P,h,relax,parametric,evaluation,F_vars,exponential_cone)
|
|
%categorizeproblem Internal function: tries to determine the type of optimization problem
|
|
|
|
F = flatten(F);
|
|
Counter = length(F.LMIid);
|
|
Ftype = zeros(Counter,1);
|
|
|
|
real_data = 1;
|
|
int_data = 0;
|
|
interval_data = 0;
|
|
bin_data = 0;
|
|
par_data = 0;
|
|
scn_data = 0;
|
|
|
|
poly_constraint = 0;
|
|
bilin_constraint = 0;
|
|
sigm_constraint = 0;
|
|
rank_constraint = 0;
|
|
rank_objective = 0;
|
|
exp_cone = 0;
|
|
|
|
parametric_variables = [];
|
|
kyp_prob = 0;
|
|
gkyp_prob = 0;
|
|
|
|
% ***********************************************
|
|
% Setup an empty problem definition
|
|
% ***********************************************
|
|
problem.objective.linear = 0;
|
|
problem.objective.quadratic.convex = 0;
|
|
problem.objective.quadratic.nonconvex = 0;
|
|
problem.objective.quadratic.nonnegative = 0;
|
|
problem.objective.polynomial = 0;
|
|
problem.objective.maxdet.convex = 0;
|
|
problem.objective.maxdet.nonconvex = 0;
|
|
problem.objective.sigmonial = 0;
|
|
|
|
problem.constraint.equalities.linear = 0;
|
|
problem.constraint.equalities.quadratic = 0;
|
|
problem.constraint.equalities.polynomial = 0;
|
|
problem.constraint.equalities.sigmonial = 0;
|
|
|
|
problem.constraint.inequalities.elementwise.linear = 0;
|
|
problem.constraint.inequalities.elementwise.quadratic.convex = 0;
|
|
problem.constraint.inequalities.elementwise.quadratic.nonconvex = 0;
|
|
problem.constraint.inequalities.elementwise.sigmonial = 0;
|
|
problem.constraint.inequalities.elementwise.polynomial = 0;
|
|
|
|
problem.constraint.inequalities.semidefinite.linear = 0;
|
|
problem.constraint.inequalities.semidefinite.quadratic = 0;
|
|
problem.constraint.inequalities.semidefinite.polynomial = 0;
|
|
problem.constraint.inequalities.semidefinite.sigmonial = 0;
|
|
|
|
problem.constraint.inequalities.rank = 0;
|
|
|
|
problem.constraint.inequalities.secondordercone.linear = 0;
|
|
problem.constraint.inequalities.secondordercone.nonlinear = 0;
|
|
problem.constraint.inequalities.rotatedsecondordercone.linear = 0;
|
|
problem.constraint.inequalities.rotatedsecondordercone.nonlinear = 0;
|
|
problem.constraint.inequalities.powercone = 0;
|
|
|
|
problem.constraint.complementarity.variable = 0;
|
|
problem.constraint.complementarity.linear = 0;
|
|
problem.constraint.complementarity.nonlinear = 0;
|
|
|
|
problem.constraint.integer = 0;
|
|
problem.constraint.binary = 0;
|
|
problem.constraint.semicont = 0;
|
|
problem.constraint.sos1 = 0;
|
|
problem.constraint.sos2 = 0;
|
|
|
|
problem.complex = 0;
|
|
problem.parametric = parametric;
|
|
problem.interval = 0;
|
|
problem.evaluation = evaluation;
|
|
problem.exponentialcone = exponential_cone;
|
|
|
|
% ********************************************************
|
|
% Make a list of all globally available discrete variables
|
|
% ********************************************************
|
|
integer_variables = yalmip('intvariables');
|
|
binary_variables = yalmip('binvariables');
|
|
semicont_variables = yalmip('semicontvariables');
|
|
uncertain_variables = yalmip('uncvariables');
|
|
for i = 1:Counter
|
|
switch F.clauses{i}.type
|
|
case 7
|
|
integer_variables = union(integer_variables,getvariables(F.clauses{i}.data));
|
|
case 8
|
|
binary_variables = union(binary_variables,getvariables(F.clauses{i}.data));
|
|
case 13
|
|
parametric_variables = union(parametric_variables,getvariables(F.clauses{i}.data));
|
|
case 52
|
|
semicont_variables = union(semicont_variables,getvariables(F.clauses{i}.data));
|
|
otherwise
|
|
end
|
|
end
|
|
|
|
% ********************************************************
|
|
% Logarithmic objective?
|
|
% ********************************************************
|
|
if ~isempty(P)
|
|
problem.objective.maxdet.convex = 1;
|
|
problem.objective.maxdet.nonconvex = 1;
|
|
problem.objective.maxdet.convex = all(P.gain<=0);
|
|
problem.objective.maxdet.nonconvex = any(P.gain>0);
|
|
end
|
|
%problem.objective.maxdet = ~isempty(P);
|
|
|
|
% ********************************************************
|
|
% Rank variables
|
|
% ********************************************************
|
|
rank_variables = yalmip('rankvariables');
|
|
any_rank_variables = ~isempty(rank_variables);
|
|
|
|
% ********************************************************
|
|
% Make a list of all globally available nonlinear variables
|
|
% ********************************************************
|
|
[monomtable,variabletype] = yalmip('monomtable');
|
|
|
|
linear_variables = find(variabletype==0);
|
|
nonlinear_variables = find(variabletype~=0);
|
|
sigmonial_variables = find(variabletype==4);
|
|
|
|
if isempty(F_vars)
|
|
allvars = getvariables(F);
|
|
else
|
|
allvars = F_vars;
|
|
end
|
|
|
|
members = ismembcYALMIP(nonlinear_variables,allvars);
|
|
any_nonlinear_variables =~isempty(find(members));
|
|
any_discrete_variables = ~isempty(integer_variables) | ~isempty(binary_variables) | ~isempty(semicont_variables);
|
|
|
|
interval_data = isinterval(h);
|
|
|
|
problem.constraint.equalities.multiterm = 0;
|
|
|
|
for i = 1:Counter
|
|
|
|
Fi = F.clauses{i};
|
|
% Only real-valued data?
|
|
real_data = real_data & isreal(Fi.data);
|
|
interval_data = interval_data | isinterval(Fi.data);
|
|
|
|
% Any discrete variables used
|
|
if any_discrete_variables
|
|
Fvar = getvariables(Fi.data);
|
|
int_data = int_data | any(ismembcYALMIP(Fvar,integer_variables));
|
|
bin_data = bin_data | any(ismembcYALMIP(Fvar,binary_variables));
|
|
par_data = par_data | any(ismembcYALMIP(Fvar,parametric_variables));
|
|
scn_data = scn_data | any(ismembcYALMIP(Fvar,semicont_variables));
|
|
end
|
|
|
|
if any_rank_variables
|
|
rank_constraint = rank_constraint | any(ismember(getvariables(Fi.data),rank_variables));
|
|
end
|
|
|
|
% Check for equalities violating GP definition
|
|
if problem.constraint.equalities.multiterm == 0
|
|
if Fi.type==3
|
|
if isempty(strfind(Fi.handle,'Expansion of'))
|
|
if multipletermsInEquality(Fi)
|
|
problem.constraint.equalities.multiterm = 1;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if ~any_nonlinear_variables % No nonlinearly parameterized constraints
|
|
|
|
switch Fi.type
|
|
case {1,9,40}
|
|
problem.constraint.inequalities.semidefinite.linear = 1;
|
|
case 2
|
|
problem.constraint.inequalities.elementwise.linear = 1;
|
|
case 3
|
|
problem.constraint.equalities.linear = 1;
|
|
case {4,54}
|
|
problem.constraint.inequalities.secondordercone.linear = 1;
|
|
case 5
|
|
problem.constraint.inequalities.rotatedsecondordercone.linear = 1;
|
|
case 20
|
|
problem.constraint.inequalities.powercone = 1;
|
|
case 21
|
|
problem.exponentialcone = 1;
|
|
case 50
|
|
problem.constraint.sos2 = 1;
|
|
case 51
|
|
problem.constraint.sos1 = 1;
|
|
case 55
|
|
problem.constraint.complementarity.linear = 1;
|
|
otherwise
|
|
end
|
|
else
|
|
% Can be nonlinear stuff
|
|
vars = getvariables(Fi.data);
|
|
usednonlins = find(ismembcYALMIP(nonlinear_variables,vars));
|
|
if ~isempty(usednonlins)
|
|
usedsigmonials = find(ismember(sigmonial_variables,vars));
|
|
if ~isempty(usedsigmonials)
|
|
switch Fi.type
|
|
case 1
|
|
problem.constraint.inequalities.semidefinite.sigmonial = 1;
|
|
case 2
|
|
problem.constraint.inequalities.elementwise.sigmonial = 1;
|
|
case 3
|
|
problem.constraint.equalities.sigmonial = 1;
|
|
case {4,54}
|
|
problem.constraint.inequalities.secondordercone.nonlinear = 1;
|
|
case 5
|
|
error('Sigmonial RSOCP not supported');
|
|
otherwise
|
|
error('Report bug in problem classification (sigmonial constraint)');
|
|
end
|
|
else
|
|
%deg = degree(Fi.data);
|
|
types = variabletype(getvariables(Fi.data));
|
|
if ~any(types)
|
|
deg = 1;
|
|
elseif any(types==1) || any(types==2)
|
|
deg = 2;
|
|
else
|
|
deg = NaN;
|
|
end
|
|
|
|
switch deg
|
|
|
|
case 1
|
|
switch Fi.type
|
|
case 1
|
|
problem.constraint.inequalities.semidefinite.linear = 1;
|
|
case 2
|
|
problem.constraint.inequalities.elementwise.linear = 1;
|
|
case 3
|
|
problem.constraint.equalities.linear = 1;
|
|
case {4,54}
|
|
problem.constraint.inequalities.secondordercone.linear = 1;
|
|
case 5
|
|
problem.constraint.inequalities.rotatedsecondordercone.linear = 1;
|
|
case 20
|
|
problem.constraint.inequalities.powercone = 1;
|
|
|
|
otherwise
|
|
error('Report bug in problem classification (linear constraint)');
|
|
end
|
|
case 2
|
|
switch Fi.type
|
|
case 1
|
|
problem.constraint.inequalities.semidefinite.quadratic = 1;
|
|
case 2
|
|
% FIX : This should be re-used from
|
|
% convertconvexquad
|
|
convex = 1;
|
|
f = Fi.data;f = f(:);
|
|
ii = 1;
|
|
while convex & ii<=length(f)
|
|
[Q,caux,faux,xaux,info] = quaddecomp(f(ii));
|
|
|
|
if info | any(eig(full(Q)) > 0)
|
|
convex = 0;
|
|
end
|
|
ii= ii + 1;
|
|
end
|
|
if convex
|
|
problem.constraint.inequalities.elementwise.quadratic.convex = 1;
|
|
else
|
|
problem.constraint.inequalities.elementwise.quadratic.nonconvex = 1;
|
|
end
|
|
case 3
|
|
problem.constraint.equalities.quadratic = 1;
|
|
case {4,54}
|
|
problem.constraint.inequalities.secondordercone.nonlinear = 1;
|
|
case 5
|
|
problem.constraint.inequalities.rotatedsecondordercone.nonlinear = 1;
|
|
case 55
|
|
problem.constraint.complementarity.nonlinear = 1;
|
|
otherwise
|
|
error('Report bug in problem classification (quadratic constraint)');
|
|
end
|
|
otherwise
|
|
switch Fi.type
|
|
case 1
|
|
problem.constraint.inequalities.semidefinite.polynomial = 1;
|
|
case 2
|
|
problem.constraint.inequalities.elementwise.polynomial = 1;
|
|
case 3
|
|
problem.constraint.equalities.polynomial = 1;
|
|
case {4,54}
|
|
problem.constraint.inequalities.secondordercone.nonlinear = 1;
|
|
case 5
|
|
problem.constraint.inequalities.rotatedsecondordercone.nonlinear = 1;
|
|
case 55
|
|
problem.constraint.complementarity.nonlinear = 1;
|
|
otherwise
|
|
error('Report bug in problem classification (polynomial constraint)');
|
|
end
|
|
|
|
end
|
|
end
|
|
else
|
|
switch Fi.type
|
|
case 1
|
|
problem.constraint.inequalities.semidefinite.linear = 1;
|
|
case 2
|
|
problem.constraint.inequalities.elementwise.linear = 1;
|
|
case 3
|
|
problem.constraint.equalities.linear = 1;
|
|
case {4,54}
|
|
problem.constraint.inequalities.secondordercone.linear = 1;
|
|
case 5
|
|
problem.constraint.inequalities.rotatedsecondordercone = 1;
|
|
case 20
|
|
problem.constraint.inequalities.powercone = 1;
|
|
case 7
|
|
problem.constraint.integer = 1;
|
|
case 8
|
|
problem.constraint.binary = 1;
|
|
case 16
|
|
problem.random = 1;
|
|
case 21
|
|
problem.exponentialcone = 1;
|
|
case 50
|
|
problem.constraint.sos2 = 1;
|
|
case 51
|
|
problem.constraint.sos1 = 1;
|
|
case 52
|
|
problem.constraint.semicont = 1;
|
|
case 55
|
|
problem.constraint.complementarity.linear = 1;
|
|
otherwise
|
|
error('Report bug in problem classification (linear constraint)');
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if int_data
|
|
problem.constraint.integer = 1;
|
|
end
|
|
if bin_data
|
|
problem.constraint.binary = 1;
|
|
end
|
|
if scn_data
|
|
problem.constraint.semicont = 1;
|
|
end
|
|
if ~real_data
|
|
problem.complex = 1;
|
|
end
|
|
if interval_data
|
|
problem.interval = 1;
|
|
end
|
|
if rank_constraint
|
|
problem.constraint.inequalities.rank = 1;
|
|
end
|
|
if ~isempty(uncertain_variables)
|
|
problem.uncertain = 1;
|
|
end
|
|
|
|
if (relax==1) | (relax==3)
|
|
problem.constraint.equalities.linear = problem.constraint.equalities.linear | problem.constraint.equalities.quadratic | problem.constraint.equalities.polynomial | problem.constraint.equalities.sigmonial;
|
|
problem.constraint.equalities.quadratic = 0;
|
|
problem.constraint.equalities.polynomial = 0;
|
|
problem.constraint.equalities.sigmonial = 0;
|
|
|
|
problem.constraint.inequalities.elementwise.linear = problem.constraint.inequalities.elementwise.linear | problem.constraint.inequalities.elementwise.quadratic.convex | problem.constraint.inequalities.elementwise.quadratic.nonconvex | problem.constraint.inequalities.elementwise.sigmonial | problem.constraint.inequalities.elementwise.polynomial;
|
|
problem.constraint.inequalities.elementwise.quadratic.convex = 0;
|
|
problem.constraint.inequalities.elementwise.quadratic.nonconvex = 0;
|
|
problem.constraint.inequalities.elementwise.sigmonial = 0;
|
|
problem.constraint.inequalities.elementwise.polynomial = 0;
|
|
|
|
problem.constraint.inequalities.semidefinite.linear = problem.constraint.inequalities.semidefinite.linear | problem.constraint.inequalities.semidefinite.quadratic | problem.constraint.inequalities.semidefinite.polynomial | problem.constraint.inequalities.semidefinite.sigmonial;
|
|
problem.constraint.inequalities.semidefinite.quadratic = 0;
|
|
problem.constraint.inequalities.semidefinite.polynomial = 0;
|
|
problem.constraint.inequalities.semidefinite.sigmonial = 0;
|
|
|
|
problem.constraint.inequalities.elementwise.secondordercone.linear = problem.constraint.inequalities.secondordercone.linear | problem.constraint.inequalities.secondordercone.nonlinear ;
|
|
problem.constraint.inequalities.elementwise.secondordercone.nonlinear = 0;
|
|
|
|
poly_constraint = 0;
|
|
bilin_constraint = 0;
|
|
sigm_constraint = 0;
|
|
problem.evaluation = 0;
|
|
problem.exponentialcone = 0;
|
|
end
|
|
|
|
% Analyse the objective function
|
|
quad_info = [];
|
|
if isa(h,'sdpvar')
|
|
h_is_linear = is(h,'linear');
|
|
else
|
|
h_is_linear = 0;
|
|
end
|
|
|
|
if (~isempty(h)) & ~h_is_linear &~(relax==1) &~(relax==3)
|
|
if ~(isempty(binary_variables) & isempty(integer_variables))
|
|
h_var = depends(h);
|
|
if any(ismember(h_var,binary_variables))
|
|
problem.constraint.binary = 1;
|
|
end
|
|
if any(ismember(h_var,integer_variables))
|
|
problem.constraint.integer = 1;
|
|
end
|
|
end
|
|
if any(ismember(getvariables(h),sigmonial_variables))
|
|
problem.objective.sigmonial = 1;
|
|
else
|
|
[Q,c,f,x,info] = quaddecomp(h);
|
|
if ~isreal(Q) % Numerical noise common on imaginary parts
|
|
Qr = real(Q);
|
|
Qi = imag(Q);
|
|
Qr(abs(Qr)<1e-10) = 0;
|
|
Qi(abs(Qi)<1e-10) = 0;
|
|
cr = real(c);
|
|
ci = imag(c);
|
|
cr(abs(cr)<1e-10) = 0;
|
|
ci(abs(ci)<1e-10) = 0;
|
|
Q = Qr + sqrt(-1)*Qi;
|
|
c = cr + sqrt(-1)*ci;
|
|
end
|
|
if info==0
|
|
% OK, we have some kind of quadratic expression
|
|
% Find involved variables
|
|
if all(nonzeros(Q)>=0)
|
|
problem.objective.quadratic.nonnegative = 1;
|
|
else
|
|
problem.objective.quadratic.nonnegative = 0;
|
|
end
|
|
index = find(any(Q,2));
|
|
if length(index) < length(Q)
|
|
Qsub = Q(index,index);
|
|
[Rsub,p]=chol(Qsub);
|
|
if p
|
|
% Maybe just some silly numerics
|
|
[Rsub,p]=chol(Qsub+1e-12*eye(length(Qsub)));
|
|
end
|
|
if p==0
|
|
[i,j,k] = find(Rsub);
|
|
R = sparse((i),index(j),k,length(Qsub),length(Q));
|
|
% R = Q*0;
|
|
% R(index,index) = Rsub;
|
|
else
|
|
R = [];
|
|
end
|
|
else
|
|
[R,p]=chol(Q);
|
|
end
|
|
if p~=0
|
|
R = [];
|
|
if any(~diag(Q) & any(triu(Q,1),2))
|
|
% Diagonal zero but non-zero outside, cannot be convex
|
|
else
|
|
Q = full(Q);
|
|
if min(eig(Q))>=-1e-10
|
|
p=0;
|
|
try
|
|
[U,S,V]=svd(Q);
|
|
catch
|
|
[U,S,V]=svd(full(Q));
|
|
end
|
|
i = find(diag(S)>1e-10);
|
|
R = sqrt(S(1:max(i),1:max(i)))*V(:,1:max(i))';
|
|
end
|
|
end
|
|
end
|
|
if p==0
|
|
problem.objective.quadratic.convex = 1;
|
|
else
|
|
problem.objective.quadratic.nonconvex = 1;
|
|
end
|
|
quad_info.Q = Q;
|
|
quad_info.c = c;
|
|
quad_info.f = f;
|
|
quad_info.x = x;
|
|
quad_info.R = R;
|
|
quad_info.p = p;
|
|
else
|
|
problem.objective.polynomial = 1;
|
|
end
|
|
end
|
|
else
|
|
problem.objective.linear = ~isempty(h);
|
|
end
|
|
|
|
if (relax==1) | (relax==2)
|
|
problem.constraint.integer = 0;
|
|
problem.constraint.binary = 0;
|
|
problem.constraint.sos2 = 0;
|
|
problem.constraint.semicont = 0;
|
|
int_data = 0;
|
|
bin_data = 0;
|
|
scn_data = 0;
|
|
end
|
|
|
|
function p = multipletermsInEquality(Fi);
|
|
p = 0;
|
|
Fi = sdpvar(Fi.data);
|
|
if length(getvariables(Fi))>1
|
|
B = getbase(Fi);
|
|
if ~isreal(B)
|
|
B = [real(B);imag(B)];
|
|
end
|
|
p = any(sum(B | B,2)-(B(:,1) == 0) > 1);
|
|
end
|