Dynamic-Calibration/utils/YALMIP-master/extras/dualize.m

876 lines
25 KiB
Matlab
Executable File

function [Fdual,objdual,X,t,err,complexInfo] = dualize(F,obj,auto,extlp,extend,options)
% DUALIZE Create the dual of an SDP given in primal form
%
% [Fd,objd,X,t,err] = dualize(F,obj,auto)
%
% Input
% F : Primal constraint in form AX=b+dt, X>0, t free.
% obj : Primal cost CX+ct
% auto : If set to 0, YALMIP will not automatically handle variables
% and update variable values when the dual problem is solved.
% extlp: If set to 0, YALMIP will not try to perform variables changes in
% order to convert simple translated LP cones (as in x>1) to
% standard unit cone constraints (x>0)
%
% Output
% Fd : Dual constraints in form C-A'y>0, c-dy==0
% obj : Dual cost b'y (to be MAXIMIZED!)
% X : The detected primal cone variables
% t : The detected primal free variables
% err : Error status (returns 0 if no problems)
%
% Example
% See the HTML help.
%
% See also DUAL, SOLVESDP, PRIMALIZE
% Check for unsupported problems
if isempty(F)
F = ([]);
end
complexInfo = [];
LogDetTerm = 0;
if nargin < 2
obj = [];
elseif isa(obj,'logdet')
Plogdet = getP(obj);
gainlogdet = getgain(obj);
if ~all(gainlogdet <= 0)
error('There are nonconvex logdet terms in the objective')
end
if ~all(gainlogdet == -1)
error('DUALIZE does currently not support coefficients before LOGDET terms')
end
obj = getcx(obj);
if ~isempty(obj)
if ~is(obj,'linear')
error('DUALIZE does not support nonlinear terms in objective (except logdet terms)')
end
end
LogDetTerm = 1;
Ftemp = ([]);
for i = 1:length(Plogdet)
Ftemp = Ftemp + [(Plogdet{i} >= 0) : 'LOGDET'];
end
F = Ftemp + F;
end
err = 0;
p1 = ~isreal(obj);%~(isreal(F) & isreal(obj));
p2 = ~(islinear(F) & islinear(obj));
p3 = any(is(F,'integer')) | any(is(F,'binary'));
if p1 | p2 | p3
if nargout == 5
Fdual = ([]);objdual = [];y = []; X = []; t = []; err = 1;
else
problems = {'Cannot dualize complex-valued problems','Cannot dualize nonlinear problems','Cannot dualize discrete problems'};
error(problems{min(find([p1 p2 p3]))});
end
end
if nargin<5 || isempty(extend)
extend = 1;
end
if extend
if nargin < 6 || isempty(options)
options = sdpsettings;
end
options.dualize = 1;
options.allowmilp = 0;
options.solver = '';
[F,failure,cause] = expandmodel(F,obj,options);
if failure
error('Failed during convexity propagation. Avoid nonlinear operators when applying dualization.');
end
end
if nargin<3 || isempty(auto)
auto = 1;
end
if nargin<4 || isempty(extlp)
extlp = 1;
end
% Cones and equalities
F_AXb = ([]);
% Shiftmatrix is a bit messy at the moment.
% We want to be able to allow cones X>shift
% by using a new variable X-shift = Z
shiftMatrix = {};
X={};
% First, get variables in initial SDP cones
% We need this to avoid adding the same variable twice
% when we add simple LP constraints (as in P>0, P(1,3)>0)
varSDP = [];
SDPset = zeros(length(F),1);
ComplexSDPset = zeros(length(F),1);
isSDP = is(F,'sdp');
for i = 1:length(F)
if isSDP(i);
Fi = sdpvar(F(i));
if is(Fi,'shiftsdpcone')
vars = getvariables(Fi);
if isempty(findrows(varSDP,[vars(1) vars(end)]))
SDPset(i) = 1;
varSDP = [varSDP;vars(1) vars(end)];
shiftMatrix{end+1} = getbasematrix(Fi,0);
X{end+1}=Fi;
if is(Fi,'complex')
ComplexSDPset(i) = 1;
end
end
end
end
end
F_SDP = F(find(SDPset));
F = F(find(~SDPset));
% Same thing for second order cones
% However, we must not add any SOC cones
% that we already defined as SDP cones
varSOC = [];
SOCset = zeros(length(F),1);
isSOCP = is(F,'socp');
for i = 1:length(F)
if isSOCP(i);%is(F(i),'socp')
Fi = sdpvar(F(i));
if is(Fi,'socone')
vars = getvariables(Fi);
% Make sure these variables are not SDP cone variables
% This can actually only happen for (X>0) + (Xcone((2:end,1),X(1)))
if ~isempty(varSDP)
inSDP = any(varSDP(:,1)<=vars(1)& vars(1) <=varSDP(:,2)) | any(varSDP(:,1)<=vars(end)& vars(end) <=varSDP(:,2));
else
inSDP = 0;
end
if ~inSDP
SOCset(i) = 1;
vars = getvariables(Fi);
varSOC = [varSOC;vars(1) vars(end)];
shiftMatrix{end+1} = getbasematrix(Fi,0);
X{end+1}=Fi;
end
end
end
end
F_SOC = F(find(SOCset));
F = F(find(~SOCset));
% Merge SDP and SOC data
varCONE = [varSDP;varSOC];
F_CONE = F_SDP + F_SOC;
% Detect primal-variables from SDP diagonals (not tested substantially...)
implicit_positive = detect_diagonal_terms(F);
% Find all LP constraints, add slacks and extract simple cones
% to speed up things, we treat LP cone somewhat different
% compared to the conceptually similiar SOCP/SDP cones
% This code is pretty messy, since there are a lot off odd
% cases to take care of (x>0 and x>1 etc etc)
elementwise = is(F,'element-wise');
elementwise_index = find(elementwise);
if ~isempty(elementwise_index)
% Find element-wise inequalities
Flp = F(elementwise_index);
% Add constraint originating from diagonals in dual-type LMIs
if ~isempty(implicit_positive)
implicit_positive = setdiff(implicit_positive,getvariables(F_CONE));
if ~isempty(implicit_positive)
Flp = Flp + (recover(implicit_positive) >= 0);
end
end
F = F(find(~elementwise)); % remove these LPs
% Find LP cones
lpconstraint = [];
for i = 1:length(Flp)
temp = sdpvar(Flp(i));
if min(size(temp))>1
temp = temp(:);
end
lpconstraint = [lpconstraint reshape(temp,1,length(temp))];
end
% Find all constraints of type a_i+x_i >0 and extract the unique and
% most constraining inequalities (i.e. remove redundant lower bounds)
base = getbase(lpconstraint);
temp = sum(base(:,2:end)~=0,2)==1;
candidates = find(temp);
if length(candidates)>0
% The other ones...
alwayskeep = find(sum(base(:,2:end)~=0,2)~=1);
w1 = lpconstraint(alwayskeep);
if all(temp)
w2 = lpconstraint;
else
w2 = lpconstraint(candidates);
end
% Find unique rows
base = getbase(w2);
[i,uniquerows,k] = unique(base(:,2:end)*randn(size(base,2)-1,1));
aUniqueRow=k(:)';
keep = [];
rhsLP = base(:,1);
rr = histc(k,[1:max(k)]);
if all(rr==1)
lpconstraint = [w1 w2];
else
for i=1:length(k)
sameRow=find(k==k(i));
if length(sameRow)==1
keep = [keep sameRow];
else
rhs=base(sameRow,1);
[val,pos]=min(rhsLP(sameRow));
keep = [keep sameRow(pos)];
end
end
lpconstraint = [w1 w2(unique(keep))];
end
end
% LP cone will be saved in a vector for speed
x = [];
% Pure cones of the type x>0
base = getbase(lpconstraint);
purelpcones = (base(:,1)==0) & (sum(abs(base(:,2:end)),2)==1) & (sum(base(:,2:end)==1,2)==1);
if ~isempty(purelpcones)
if all(purelpcones)
x = [x lpconstraint];
else
x = [x lpconstraint(purelpcones)];
end
lpconstraint = lpconstraint(find(~purelpcones));
end
% Translated cones x>k, k positive
% User does not want to make variable changes based on k
% But if k>=0, we can at-least mark x as a simple LP cone variable and
% thus avoid a free variable.
if ~extlp & ~isempty(lpconstraint)
base = getbase(lpconstraint);
lpcones = (base(:,1)<0) & (sum(abs(base(:,2:end)),2)==1) & (sum(base(:,2:end)==1,2)==1);
if ~isempty(find(lpcones))
s = recover(getvariables(lpconstraint(find(lpcones))));
x = [x reshape(s,1,length(s))];
end
end
% Translated cones x>k
% Extract these and perform the associated variable change y=x-k
if ~isempty(lpconstraint)%Avoid warning in 5.3.1
base = getbase(lpconstraint);
lpcones = (sum(abs(base(:,2:end)),2)==1) & (sum(base(:,2:end)==1,2)==1);
if ~isempty(lpcones) & extlp
x = [x lpconstraint(find(lpcones))];
nlp = lpconstraint(find(~lpcones));
if ~isempty(nlp)
s = sdpvar(1,length(nlp));
F_AXb = F_AXb + (nlp-s==0);
x = [x s];
end
elseif length(lpconstraint) > 0
s = sdpvar(1,length(lpconstraint));
x = [x s]; % New LP cones
F_AXb = F_AXb + (lpconstraint-s==0);
end
end
% Sort asccording to variable index
% (Code below assumes x is sorted in increasing variables indicies)
base = getbase(x);base = base(:,2:end);[i,j,k] = find(base);
if ~isequal(i,(1:length(x))')
x = x(i);
end
xv = getvariables(x);
% For mixed LP/SDP problems, we must ensure that LP cone variables are
% not actually an element in a SDP cone variable
if ~isempty(varCONE)
keep = zeros(length(x),1);
for i = 1:length(xv)
if any(varCONE(:,1)<=xv(i) & xv(i) <=varCONE(:,2))
else
keep(i) = 1;
end
end
if ~all(keep)
% We need to add some explicit constraints on some elements and
% remove the x variables since they are already in a cone
% variable
xcone = x(find(~keep));
s = sdpvar(1,length(xcone));
F_AXb = F_AXb + (xcone-s==0);
x = x(find(keep));
x = [x s];
end
end
else
x = [];
end
% Check for mixed cones, ie terms C-A'y > 0.
keep = ones(length(F),1);
isSDP = is(F,'sdp');
isSOCP = is(F,'socp');
isVecSOCP = is(F,'vecsocp');
% Pre-allocate all SDP slacks in one call
% This is a lot faster
if nnz(isSDP) > 0
SDPindicies = find(isSDP)';
for i = 1:length(SDPindicies)%find(isSDP)'
Fi = sdpvar(F(SDPindicies(i)));
ns(i) = size(Fi,1);
ms(i) = ns(i);
isc(i) = is(Fi,'complex');
end
if any(isc)
for i = 1:length(ns)
if isc(i)
Slacks{i} = sdpvar(ns(i),ns(i),'hermitian','complex');
else
Slacks{i} = sdpvar(ns(i),ns(i));
end
end
else
Slacks = sdpvar(ns,ms);
end
if ~isa(Slacks,'cell')
Slacks = {Slacks};
end
end
prei = 1;
for i = 1:length(F)
if isSDP(i)
% Semidefinite dual-form cone
Fi = sdpvar(F(i));
n = size(Fi,1);
% S = sdpvar(n,n);
S = Slacks{prei};prei = prei + 1;
slack = Fi-S;
ind = find(triu(reshape(1:n^2,n,n)));
if is(slack,'complex')
F_AXb = F_AXb + (real(slack(ind))==0) + (imag(slack(ind))==0);
else
F_AXb = F_AXb + (slack(ind)==0);
end
F_CONE = F_CONE + lmi(S,[],[],[],1);
shiftMatrix{end+1} = spalloc(n,n,0);
X{end+1}=S;
keep(i)=0;
elseif isSOCP(i)
% SOC dual-form cone
Fi = sdpvar(F(i));
n = size(Fi,1);
S = sdpvar(n,1);
% S = Slacks{i};
slack = Fi-S;
if is(slack,'complex')
F_AXb = F_AXb + (real(slack)==0) + (imag(slack)==0);
else
F_AXb = F_AXb + (slack==0);
end
F_CONE = F_CONE + (cone(S(2:end),S(1)));
shiftMatrix{end+1} = spalloc(n,1,0);
X{end+1}=S;
keep(i)=0;
elseif isVecSOCP(i)
% Vectorized SOC dual-form cone
Fi = sdpvar(F(i));
[n,m] = size(Fi);
S = sdpvar(n,m,'full');
slack = Fi-S;
if is(slack,'complex')
F_AXb = F_AXb + (real(slack)==0) + (imag(slack)==0);
else
F_AXb = F_AXb + (slack==0);
end
F_CONE = F_CONE + (cone(S));
shiftMatrix{end+1} = spalloc(n,m,0);
X{end+1}=S;
keep(i)=0;
end
end
% Now, remove all mixed cones...
F = F(find(keep));
% Get the equalities
AXbset = is(F,'equality');
if any(AXbset)
% Get the constraints
F_AXb = F_AXb + F(find(AXbset));
complex = find(is(F_AXb,'complex'));
if ~isempty(complex)
F_AXb_complex = F_AXb(complex);
F_AXb(complex)=[];
rEQ = real(sdpvar(F_AXb_complex));
iEQ = imag(sdpvar(F_AXb_complex));
if ~isempty(rEQ) && isa(rEQ,'sdpvar')
F_AXb = F_AXb + (rEQ == 0);
end
if ~isempty(iEQ) && isa(iEQ,'sdpvar')
F_AXb = F_AXb + (iEQ == 0);
end
end
F = F(find(~AXbset));
end
% Is there something we missed in our tests?
if length(F)>0
error('DUALIZE can only treat standard SDPs (and LPs) at the moment.')
end
% If complex SDP cone, we reformulate and call again on a real-valued
% problem. This leads to twice the amount of work, but it is a quick fix
% for the moment
if any(is(F_CONE,'complexsdpcone'))
F_NEWCONES = [];
top = 1;
for i = 1:length(X)
if is(X{i},'complexsdpcone')
Xreplace{top} = X{i};
n = length(X{i});
Xnew{top} = sdpvar(2*n);
rQ = real(Xreplace{top});
iQ = imag( Xreplace{top});
L1 = Xnew{top}(1:n,1:n);
L3 = Xnew{top}(n+1:end,n+1:end);
L2 = Xnew{top}(1:n,n + 1:end);
s0r = getvariables(rQ);
s1r = getvariables(L1);
s2r = getvariables(L3);
r0 = recover(s0r);
r1 = recover(s1r);
r2 = recover(s2r);
s0i = getvariables(iQ);
s1i = getvariables(triu(L2,1))';
s2i = getvectorvariables(L2(find(tril(ones(length(L2)),-1))));
i0 = recover(s0i);
i1 = recover(s1i);
i2 = recover(s2i);
replacement = [r1+r2;i1-i2];
if ~isempty(F_AXb)
F_AXb = remap(F_AXb,[s0r s0i],replacement);
end
if ~isempty(obj)
obj = remap(obj,[s0r s0i],replacement);
end
X{i} = Xnew{top};
top = top + 1;
end
if is(X{i},'hermitian')
F_NEWCONES = [F_NEWCONES, X{i} >= 0];
else
F_NEWCONES = [F_NEWCONES, cone(X{i})];
end
end
F_reformulated = [F_NEWCONES, F_AXb, x>=0];
complexInfo.replaced = Xreplace;
complexInfo.new = Xnew;
[Fdual,objdual,X,t,err] = dualize(F_reformulated,obj,auto,extlp,extend);
return
end
% Sort the SDP cone variables X according to YALMIP
% This is just to simplify some indexing later
ns = [];
first_var = [];
for i = 1:length(F_CONE)
ns = [ns length(X{i})];
first_var = [first_var min(getvariables(X{i}))];
end
[sorted,index] = sort(first_var);
X={X{index}};
shiftMatrix={shiftMatrix{index}};
shift = [];
for i = 1:length(F_CONE)
ns(i) = length(X{i});
if size(X{i},2)==1 | (size(X{i},1) ~= size(X{i},2))
% SOCP
shift = [shift;shiftMatrix{i}(:)];
else
% SDP
ind = find(tril(reshape(1:ns(i)^2,ns(i),ns(i))));
shift = [shift;shiftMatrix{i}(ind)];
end
end
% Free variables (here called t) is everything except the cone variables
X_variables = getvariables(F_CONE);
x_variables = getvariables(x);
Xx_variables = [X_variables x_variables];
other_variables = [getvariables(obj) getvariables(F_AXb)];
% For quadratic case
%other_variables = [depends(obj) getvariables(F_AXb)];
all_variables = uniquestripped([other_variables Xx_variables]);
% Avoid set-diff
if isequal(all_variables,Xx_variables)
t_variables = [];
t_in_all = [];
t = [];
else
t_variables = setdiff(all_variables,Xx_variables);
ind = ismembcYALMIP(all_variables,t_variables);
t_in_all = find(ind);
t = recover(t_variables);
end
ind = ismembcYALMIP(all_variables,x_variables);
x_in_all = find(ind);
ind = ismembcYALMIP(all_variables,X_variables);
X_in_all = find(ind);
vecF1 = [];
nvars = length(all_variables);
for i = 1:length(F_AXb)
AXb = sdpvar(F_AXb(i));
mapper = find(ismembcYALMIP(all_variables,getvariables(AXb)));
[n,m] = size(AXb);
data = getbase(AXb);
[iF,jF,sF] = find(data);
if 1 % New
smapper = [1 1+mapper(:)'];
F_structemp = sparse(iF,smapper(jF),sF,n*m,1+nvars);
else
F_structemp = spalloc(n*m,1+nvars,nnz(data));
F_structemp(:,[1 1+mapper(:)'])= data;
end
vecF1 = [vecF1;F_structemp];
end
%Remove trivially redundant constraints
h = 1+rand(size(vecF1,2),1);
h = vecF1*h;
% INTVAL possibility
%[dummy,uniquerows] = uniquesafe(h);
[dummy,uniquerows] = uniquesafe(mid(h));
if length(uniquerows) < length(h)
% Sort to ensure run-to-run consistency
vecF1 = vecF1((sort(uniquerows)),:);
end
if isempty(obj)
vecF1(end+1,1) = 0;
else
if is(obj,'linear')
mapper = find(ismembcYALMIP(all_variables,getvariables(obj)));
[n,m] = size(obj);
data = getbase(obj);
[iF,jF,sF] = find(data);
if 1
smapper = [1 1+mapper(:)'];
F_structemp = sparse(iF,smapper(jF),sF,n*m,1+nvars);
else
F_structemp = spalloc(n*m,1+nvars,nnz(data));
F_structemp(:,[1 1+mapper(:)'])= data;
end
vecF1 = [vecF1;F_structemp];
else
% FIX: Generalize to QP duality
% min c'x+0.5x'Qx, Ax==b, x>=0
% max b'y-0.5x'Qx, c-A'y+Qx >=0
[Q,c,xreally,info] = quaddecomp(obj,recover(all_variables))
mapper = find(ismembcYALMIP(all_variables,getvariables(c'*xreally)));
[n,m] = size(c'*xreally);
data = getbase(c'*xreally);
F_structemp = spalloc(n*m,1+nvars,nnz(data));
F_structemp(:,[1 1+mapper(:)'])= data;
vecF1 = [vecF1;F_structemp]
end
end
vecF1(end+1,1) = 0;
Fbase = vecF1;
%Fbase = unique(Fbase','rows')';
b = Fbase(1:end-2,1);
Fbase = -Fbase(1:end-1,2:end);
vecA = [];
Fbase_t = Fbase(:,t_in_all);
Fbase_x = Fbase(:,x_in_all);
Fbase_X = Fbase;
%Fbase_X(:,unionstripped(t_in_all,x_in_all)) = [];
if 1
removethese = unique([t_in_all x_in_all]);
if length(removethese) > 0.5*size(Fbase_X,2)
Fbase_X = Fbase_X(:,setdiff(1:size(Fbase_X,2),removethese));
else
Fbase_X(:,[t_in_all x_in_all]) = [];
end
else
removecols = uniquestripped([t_in_all x_in_all]);
if ~isempty(removecols)
[i,j,k] = find(Fbase_X);
keep = find(~ismember(j,removecols));
i = i(keep);
k = k(keep);
j = j(keep);
map = find(1:length(unique(j)),j);
end
end
% Shift due to translated dual cones X = Z+shift
if length(shift > 0)
b = b + Fbase_X(1:end-1,:)*shift;
end
if length(x)>0
% Arrgh
base = getbase(x);
constant = base(:,1);
base = base(:,2:end);[i,j,k] = find(base);
b = b + Fbase_x(1:end-1,:)*constant(i);
end
start = 0;
n_cones = length(ns);
% All LPs in one cone
if length(x)>0
n_lp = 1;
else
n_lp = 0;
end
n_free = length(t_variables);
% SDP cones
for j = 1:1:n_cones
if size(X{j},1)==size(X{j},2)
% SDP cone
ind = reshape(1:ns(j)^2,ns(j),ns(j));
ind = find(tril(ind));
% Get non-symmetric constraint AiX=b
Fi = Fbase_X(1:length(b),start+(1:length(ind)))'/2;
if 1
[iF,jF,sF] = find(Fi);
iA = ind(iF);
jA = jF;
sA = sF;
the_col = 1+floor((iA-1)/ns(j));
the_row = iA-(the_col-1)*ns(j);
these_must_be_transposed = find(the_row > the_col);
if ~isempty(these_must_be_transposed)
new_rowcols = the_col(these_must_be_transposed) + (the_row(these_must_be_transposed)-1)*ns(j);
iA = [iA;new_rowcols];
jA = [jA;jA(these_must_be_transposed)];
sA = [sA;sA(these_must_be_transposed)];
end
% Fix diagonal term
diags = find(diag(1:ns(j)));
id = find(ismembcYALMIP(iA,diags));
sA(id) = 2*sA(id);
Ai = sparse(iA,jA,sA,ns(j)^2,length(b));
else % Old slooooooow version
Ai = spalloc(ns(j)^2,length(b),nnz(Fi));
Ai(ind,:) = Fi;
% Symmetrize
[rowcols,varindicies,vals]=find(Ai);
the_col = 1+floor((rowcols-1)/ns(j));
the_row = rowcols-(the_col-1)*ns(j);
these_must_be_transposed = find(the_row > the_col);
if ~isempty(these_must_be_transposed)
new_rowcols = the_col(these_must_be_transposed) + (the_row(these_must_be_transposed)-1)*ns(j);
Ai(sub2ind(size(Ai),new_rowcols,varindicies(these_must_be_transposed))) = vals(these_must_be_transposed);
end
% Fix diagonal term
diags = find(diag(1:ns(j)));
Ai(diags,:) = 2*Ai(diags,:);
end
% if norm(Ai-Ai2,inf)>1e-12
% error
% end
vecA{j} = Ai;
start = start + length(ind);
else
% Second order cone
ind = 1:prod(size(X{j}));
%ind = 1:ns(j);
% Get constraint AiX=b
Fi = Fbase_X(1:length(b),start+(1:length(ind)))';
%Ai = spalloc(ns(j),length(b),nnz(Fi));
Ai = spalloc(prod(size(X{j})),length(b),nnz(Fi));
Ai(ind,:) = Fi;
vecA{j} = Ai;
start = start + length(ind);
end
end
% LP Cone
if n_lp>0
Alp=Fbase_x(1:length(b),:)';
end
% FREE VARIABLES
start = 0;
if n_free>0
Afree=Fbase_t(1:length(b),:)';
end
% COST MATRIX
% SDP CONE
start = 0;
for j = 1:1:n_cones
if size(X{j},1)==size(X{j},2)
%ind = reshape(1:ns(j)^2,ns(j),ns(j));
%ind = find(tril(ind));
%C{j} = spalloc(ns(j),ns(j),0);
%C{j}(ind) = -Fbase_X(end,start+(1:length(ind)));
%C{j} = (C{j}+ C{j}')/2;
%start = start + length(ind);
ind = reshape(1:ns(j)^2,ns(j),ns(j));
[indi,indj] = find(tril(ind));
C{j} = sparse(indi,indj,-Fbase_X(end,start+(1:length(indi))),ns(j),ns(j));
C{j} = (C{j}+ C{j}')/2;
start = start + length(indi);
else
%ind = 1:ns(j);
ind = 1:prod(size(X{j}));
C{j} = spalloc(ns(j),1,0);
C{j}(ind) = -Fbase_X(end,start+(1:length(ind)));
start = start + length(ind);
end
end
% LP CONE
for j = 1:1:n_lp
Clp = -Fbase_x(end,:)';
end
% FREE CONE
if n_free>0
Cfree = -Fbase_t(end,1:end)';
end
% Create dual
if length(b) == 0
error('Dual program is somehow trivial (0 variables in dual)');
end
y = sdpvar(length(b),1);
yvars = getvariables(y);
cf = [];
Af = [];
Fdual = ([]);
for j = 1:n_cones
if size(X{j},1)==size(X{j},2)
% Yep, this is optimized...
S = sdpvar(ns(j),ns(j),[],yvars,[C{j}(:) -vecA{j}]);
% Fast call avoids symmetry check
Fdual = Fdual + lmi(S,[],[],[],1);
else
Ay = reshape(vecA{j}*y,[],1);
%Ay = reshape(vecA{j}*y,ns(j),1);
S = C{j}-Ay;
S = reshape(S,size(X{j},1),[]);
%Fdual = Fdual + lmi(cone(S(2:end),S(1)));
Fdual = Fdual + lmi(cone(S));
end
end
if n_lp > 0
keep = any(Alp,2);
if ~all(keep)
% Fix for unused primal cones
preset=find(~keep);
xfix = x(preset);
assign(xfix(:),Clp(preset(:)));
end
keep = find(keep);
if ~isempty(keep)
z = Clp(keep)-Alp(keep,:)*y;
if isa(z,'double')
assign(x(:),z(:));
else
Fdual = Fdual + lmi(z);
if ~isequal(keep,(1:length(x))')
x = x(keep);
end
X{end+1} = x(:); % We have worked with a row for performance reasons
end
end
end
if n_free > 0
CfreeAfreey = Cfree-Afree*y;
if isa(CfreeAfreey,'double')
if nnz(CfreeAfreey)>0
error('Trivially unbounded!');
end
else
Fdual = Fdual + (0 == CfreeAfreey);
end
end
objdual = b'*y;
if auto
for i = 1:length(X)
yalmip('associatedual',getlmiid(Fdual(i)),X{i});
end
if n_free>0
yalmip('associatedual',getlmiid(Fdual(end)),t);
end
end
if LogDetTerm
for i = 1:length(Plogdet)
objdual = objdual + logdet(sdpvar(Fdual(i))) + length(sdpvar(Fdual(1)));
end
Fdual = Fdual - Fdual(1:length(Plogdet));
end
Fdual = setdualize(Fdual,1);
function implicit_positive = detect_diagonal_terms(F)
F = F(find(is(F,'sdp')));
implicit_positive = [];
for i = 1:length(F)
Fi = sdpvar(F(i));
B = getbase(Fi);
n = sqrt(size(B,1));
d = 1:(n+1):n^2;
B = B(d,:);
candidates = find((B(:,1) == 0) & (sum(B | B,2) == 1) & (sum(B,2) == 1));
if ~isempty(candidates)
vars = getvariables(Fi);
[ii,jj,kk] = find(B(candidates,2:end)');
ii = ii(:)';
implicit_positive = [implicit_positive vars(ii)];
end
end