📄 dualize.m
字号:
% 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
% 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 = ismembc(all_variables,t_variables);
t_in_all = find(ind);
t = recover(t_variables);
end
ind = ismembc(all_variables,x_variables);
x_in_all = find(ind);
ind = ismembc(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(ismembc(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;
[dummy,uniquerows] = uniquesafe(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(ismembc(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(ismembc(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(ismembc(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: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(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);
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
y = sdpvar(length(b),1);
yvars = getvariables(y);
cf = [];
Af = [];
Fdual = set([]);
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,ns(j),1);
S = C{j}-Ay;
Fdual = Fdual + lmi(cone(S(2:end),S(1)));
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 + set(z);
x =x(keep);
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 + set(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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -