function [F_struc,K,KCut] = lmi2sedumistruct(F) %lmi2sedumistruct Internal function: Converts LMI to format needed in SeDuMi % % % Author Johan Löfberg % % $Id: lmi2sedumistruct.m,v 1.21 2006/09/22 08:18:37 joloef Exp $ nvars = yalmip('nvars'); %Needed lot'sa times... % We first browse to see what we have got and the % dimension of F_struc (massive speed improvement) %top = 0; type_of_constraint = zeros(size(F.clauses,2),1); for i = 1:size(F.clauses,2) type_of_constraint(i) = F.clauses{i}.type; % [n,m] = size(F.clauses{i}.data); % [n,m] = size(getbasematrixwithoutcheck(F.clauses{i}.data,0)); % top = top+n*m; % Is it a complex linear cone % if (type_of_constraint(i)==2) & (~isreal(F.clauses{i}.data)) % top = top+n*m; % We will have constraints on Re and Im % end end F_struc = []; sdp_con = find(type_of_constraint == 1 | type_of_constraint == 9); lin_con = find(type_of_constraint == 2 | type_of_constraint == 12); equ_con = find(type_of_constraint == 3); qdr_con = find(type_of_constraint == 4); rlo_con = find(type_of_constraint == 5); % SeDuMi struct K.f = 0; K.l = 0; K.q = 0; K.r = 0; K.s = 0; K.rank = []; K.dualrank = []; K.scomplex = []; K.xcomplex = []; KCut.f = []; KCut.l = []; KCut.q = []; KCut.r = []; KCut.s = []; top = 1; localtop = 1; % Linear equality constraints for i = 1:length(equ_con) constraints = equ_con(i); data = getbase(F.clauses{constraints}.data); [n,m] = size(F.clauses{constraints}.data); % Which variables are needed in this constraint lmi_variables = getvariables(F.clauses{constraints}.data); if isreal(data) ntimesm = n*m; %Just as well pre-calc else % Complex constraint, Expand to real and Imag ntimesm = 2*n*m; %Just as well pre-calc data = [real(data);imag(data)]; end mapX = [1 1+lmi_variables]; [ix,jx,sx] = find(data); F_structemp = sparse(ix,mapX(jx),sx,ntimesm,1+nvars); %F_structemp = spalloc(ntimesm,1+nvars,0); %F_structemp(:,[1 1+lmi_variables(:)'])= data; % ...and add them together (efficient for large structures) % F_struc(top:top+ntimesm-1,:) = F_structemp; F_struc = [F_struc;F_structemp]; if F.clauses{constraints}.cut KCut.f = [KCut.f localtop:localtop+ntimesm-1]; end localtop = localtop+ntimesm; top = top+ntimesm; K.f = K.f+ntimesm; end % Linear inequality constraints localtop = 1; F_struc = F_struc'; % [F_struc,K,KCut] = recursive_lp_fix(F,F_struc,K,KCut,lin_con,nvars,8,1); % F_struc = F_struc'; % for i = 1:length(lin_con) constraints = lin_con(i); data = getbase(F.clauses{constraints}.data); [n,m] = size(F.clauses{constraints}.data); % Which variables are needed in this constraint lmi_variables = getvariables(F.clauses{constraints}.data); % Convert to real problem if isreal(data) ntimesm = n*m; %Just as well pre-calc else % Complex constraint, Expand to real and Imag ntimesm = 2*n*m; %Just as well pre-calc data = [real(data);imag(data)]; end % Add numerical data to complete problem setup mapX = [1 1+lmi_variables]; [ix,jx,sx] = find(data); F_structemp = sparse(mapX(jx),ix,sx,1+nvars,ntimesm); F_struc = [F_struc F_structemp]; if F.clauses{constraints}.cut KCut.l = [KCut.l localtop:localtop+ntimesm-1]; end localtop = localtop+ntimesm; top = top+ntimesm; K.l = K.l+ntimesm; end F_struc = F_struc'; [F_struc,K,KCut] = recursive_socp_fix(F,F_struc',K,KCut,qdr_con,nvars,8,1); F_struc = F_struc'; % Rotated Lorentz cone constraints for i = 1:length(rlo_con) constraints = rlo_con(i); [n,m] = size(F.clauses{constraints}.data); ntimesm = n*m; %Just as well pre-calc % Which variables are needed in this constraint lmi_variables = getvariables(F.clauses{constraints}.data); % We allocate the structure blockwise... F_structemp = spalloc(ntimesm,1+nvars,0); % Add these rows only F_structemp(:,[1 1+lmi_variables(:)'])= getbase(F.clauses{constraints}.data); % ...and add them together (efficient for large structures) % F_struc(top:top+ntimesm-1,:) = F_structemp; F_struc = [F_struc;F_structemp]; top = top+ntimesm; K.r(i) = n; end % Semidefinite constraints % We append the recursively in order to speed up construction % of problems with a lot of medium size SDPs [F_struc,K,KCut] = recursive_sdp_fix(F,F_struc.',K,KCut,sdp_con,nvars,8,1); F_struc = F_struc.'; % Now fix things for the rank constraint % This is currently a hack... % Should not be in this file [rank_variables,dual_rank_variables] = yalmip('rankvariables'); if ~isempty(rank_variables) used_in = find(sum(abs(F_struc(:,1+rank_variables)),2)); if ~isempty(used_in) if used_in >=1+K.f & used_in < 1+K.l+K.f for i = 1:length(used_in) [ii,jj,kk] = find(F_struc(used_in(i),:)); if length(ii)==2 & kk(2)<1 r = floor(kk(1)); var = jj(2)-1; extstruct = yalmip('extstruct',var); X = extstruct.arg{1}; if issymmetric(X) F_structemp = sedumize(X,nvars); else error('Only symmetric matrices can be rank constrained.') end F_struc = [F_struc;F_structemp]; if isequal(K.s,0) K.s(1,1) = size(extstruct.arg{1},1); else K.s(1,end+1) = size(extstruct.arg{1},1); end K.rank(1,end+1) = min(r,K.s(end)); else error('This rank constraint is not supported (only supports rank(X) < r)') end end % Remove the nonlinear operator constraints F_struc(used_in,:) = []; K.l = K.l - length(used_in); else error('You have added a rank constraint on an equality constraint, or a scalar expression?!') end end end if ~isempty(dual_rank_variables) used_in = find(sum(abs(F_struc(:,1+dual_rank_variables)),2)); if ~isempty(used_in) if used_in >=1+K.f & used_in < 1+K.l+K.f for i = 1:length(used_in) [ii,jj,kk] = find(F_struc(used_in(i),:)); if length(ii)==2 & kk(2)<1 r = floor(kk(1)); var = jj(2)-1; extstruct = yalmip('extstruct',var); X = extstruct.arg{1}; id = getlmiid(X); inlist=getlmiid(F); index=find(id==inlist); if ~isempty(index) K.rank(1,index) = min(r,K.s(index)); end else error('This rank constraint is not supported (only supports rank(X) < r)') end end % Remove the nonlinear operator constraints F_struc(used_in,:) = []; K.l = K.l - length(used_in); else error('You have added a rank constraint on an equality constraint, or a scalar expression?!') end end end function F_structemp = sedumize(Fi,nvars) Fibase = getbase(Fi); [n,m] = size(Fi); ntimesm = n*m; lmi_variables = getvariables(Fi); [ix,jx,sx] = find(Fibase); mapX = [1 1+lmi_variables]; F_structemp = sparse(ix,mapX(jx),sx,ntimesm,1+nvars); function [F_struc,K,KCut] = recursive_lp_fix(F,F_struc,K,KCut,lp_con,nvars,maxnlp,startindex) % Check if we should recurse if length(lp_con)>2*maxnlp % recursing costs, so do 4 in one step ind = 1+ceil(length(lp_con)*(0:0.25:1)); [F_struc1,K,KCut] = recursive_lp_fix(F,[],K,KCut,lp_con(ind(1):ind(2)-1),nvars,maxnlp,startindex+ind(1)-1); [F_struc2,K,KCut] = recursive_lp_fix(F,[],K,KCut,lp_con(ind(2):ind(3)-1),nvars,maxnlp,startindex+ind(2)-1); [F_struc3,K,KCut] = recursive_lp_fix(F,[],K,KCut,lp_con(ind(3):ind(4)-1),nvars,maxnlp,startindex+ind(3)-1); [F_struc4,K,KCut] = recursive_lp_fix(F,[],K,KCut,lp_con(ind(4):ind(5)-1),nvars,maxnlp,startindex+ind(4)-1); F_struc = [F_struc F_struc1 F_struc2 F_struc3 F_struc4]; return elseif length(lp_con)>maxnlp mid = ceil(length(lp_con)/2); [F_struc1,K,KCut] = recursive_lp_fix(F,[],K,KCut,lp_con(1:mid),nvars,maxnlp,startindex); [F_struc2,K,KCut] = recursive_lp_fix(F,[],K,KCut,lp_con(mid+1:end),nvars,maxnlp,startindex+mid); F_struc = [F_struc F_struc1 F_struc2]; return end oldF_struc = F_struc; F_struc = []; for i = 1:length(lp_con) constraints = lp_con(i); Fi = F.clauses{constraints}.data; Fibase = getbase(Fi); [n,m] = size(Fi); %ntimesm = n*m; %Just as well pre-calc % Convert to real problem if isreal(Fibase) ntimesm = n*m; %Just as well pre-calc else % Complex constraint, Expand to real and Imag ntimesm = 2*n*m; %Just as well pre-calc Fibase = [real(Fibase);imag(Fibase)]; end % Which variables are needed in this constraint lmi_variables = getvariables(Fi); mapX = [1 1+lmi_variables]; [ix,jx,sx] = find(Fibase); F_structemp = sparse(mapX(jx),ix,sx,1+nvars,ntimesm); F_struc = [F_struc F_structemp]; if F.clauses{constraints}.cut KCut.l = [KCut.l i+startindex-1]; end K.l(i+startindex-1) = n; end K.l = sum(K.l); F_struc = [oldF_struc F_struc]; function [F_struc,K,KCut] = recursive_sdp_fix(F,F_struc,K,KCut,sdp_con,nvars,maxnsdp,startindex) % Check if we should recurse if length(sdp_con)>2*maxnsdp % recursing costs, so do 4 in one step ind = 1+ceil(length(sdp_con)*(0:0.25:1)); [F_struc1,K,KCut] = recursive_sdp_fix(F,[],K,KCut,sdp_con(ind(1):ind(2)-1),nvars,maxnsdp,startindex+ind(1)-1); [F_struc2,K,KCut] = recursive_sdp_fix(F,[],K,KCut,sdp_con(ind(2):ind(3)-1),nvars,maxnsdp,startindex+ind(2)-1); [F_struc3,K,KCut] = recursive_sdp_fix(F,[],K,KCut,sdp_con(ind(3):ind(4)-1),nvars,maxnsdp,startindex+ind(3)-1); [F_struc4,K,KCut] = recursive_sdp_fix(F,[],K,KCut,sdp_con(ind(4):ind(5)-1),nvars,maxnsdp,startindex+ind(4)-1); F_struc = [F_struc F_struc1 F_struc2 F_struc3 F_struc4]; return elseif length(sdp_con)>maxnsdp mid = ceil(length(sdp_con)/2); [F_struc1,K,KCut] = recursive_sdp_fix(F,[],K,KCut,sdp_con(1:mid),nvars,maxnsdp,startindex); [F_struc2,K,KCut] = recursive_sdp_fix(F,[],K,KCut,sdp_con(mid+1:end),nvars,maxnsdp,startindex+mid); F_struc = [F_struc F_struc1 F_struc2]; return end oldF_struc = F_struc; F_struc = []; for i = 1:length(sdp_con) constraints = sdp_con(i); Fi = F.clauses{constraints}.data; Fibase = getbase(Fi); [n,m] = size(Fi); ntimesm = n*m; %Just as well pre-calc % Which variables are needed in this constraint lmi_variables = getvariables(Fi); mapX = [1 1+lmi_variables]; [ix,jx,sx] = find(Fibase); F_structemp = sparse(mapX(jx),ix,sx,1+nvars,ntimesm); F_struc = [F_struc F_structemp]; if F.clauses{constraints}.cut KCut.s = [KCut.s i+startindex-1]; end K.s(i+startindex-1) = n; K.rank(i+startindex-1) = n; K.dualrank(i+startindex-1) = n; % Check for a complex structure if ~isreal(F_structemp) K.scomplex = [K.scomplex i+startindex-1]; end end F_struc = [oldF_struc F_struc]; function [F_struc,K,KCut] = recursive_socp_fix(F,F_struc,K,KCut,qdr_con,nvars,maxnsocp,startindex); % Check if we should recurse if length(qdr_con)>2*maxnsocp % recursing costs, so do 4 in one step ind = 1+ceil(length(qdr_con)*(0:0.25:1)); [F_struc1,K,KCut] = recursive_socp_fix(F,[],K,KCut,qdr_con(ind(1):ind(2)-1),nvars,maxnsocp,startindex+ind(1)-1); [F_struc2,K,KCut] = recursive_socp_fix(F,[],K,KCut,qdr_con(ind(2):ind(3)-1),nvars,maxnsocp,startindex+ind(2)-1); [F_struc3,K,KCut] = recursive_socp_fix(F,[],K,KCut,qdr_con(ind(3):ind(4)-1),nvars,maxnsocp,startindex+ind(3)-1); [F_struc4,K,KCut] = recursive_socp_fix(F,[],K,KCut,qdr_con(ind(4):ind(5)-1),nvars,maxnsocp,startindex+ind(4)-1); F_struc = [F_struc F_struc1 F_struc2 F_struc3 F_struc4]; return elseif length(qdr_con)>maxnsocp mid = ceil(length(qdr_con)/2); [F_struc1,K,KCut] = recursive_socp_fix(F,[],K,KCut,qdr_con(1:mid),nvars,maxnsocp,startindex); [F_struc2,K,KCut] = recursive_socp_fix(F,[],K,KCut,qdr_con(mid+1:end),nvars,maxnsocp,startindex+mid); F_struc = [F_struc F_struc1 F_struc2]; return end % second order cone constraints for i = 1:length(qdr_con) constraints = qdr_con(i); [n,m] = size(F.clauses{constraints}.data); ntimesm = n*m; %Just as well pre-calc % Which variables are needed in this constraint lmi_variables = getvariables(F.clauses{constraints}.data); data = getbase(F.clauses{constraints}.data); if isreal(data) mapX = [1 1+lmi_variables]; [ix,jx,sx] = find(data); F_structemp = sparse(mapX(jx),ix,sx,1+nvars,ntimesm); else n = n+(n-1); ntimesm = n*m; F_structemp = spalloc(ntimesm,1+nvars,0); data = [data(1,:);real(data(2:end,:));imag(data(2:end,:))]; F_structemp(:,[1 1+lmi_variables(:)'])= data; F_structemp = F_structemp'; end % ...and add them together (efficient for large structures) F_struc = [F_struc F_structemp]; K.q(i+startindex-1) = n; end