Dynamic-Calibration/utils/SDPT3-4.0/Solver/detect_lblk.m

128 lines
4.3 KiB
Matlab
Executable File

%%*****************************************************************
%% detect_lblk: detect diagonal blocks in the SDP data.
%%
%% [blk,At,C,diagblkinfo,blockchange,parbarrier,X,Z] = ...
%% detect_lblk(blk,At,C,b,parbarrier,X,Z);
%%*****************************************************************
%% SDPT3: version 4.0
%% Copyright (c) 1997 by
%% Kim-Chuan Toh, Michael J. Todd, Reha H. Tutuncu
%% Last Modified: 16 Sep 2004
%%*****************************************************************
function [blk,At,C,diagblkinfo,blockchange,parbarrier,X,Z] = ...
detect_lblk(blk,At,C,b,parbarrier,X,Z,printlevel);
if (nargin < 8); printlevel = 1; end
%%
%% Acum = abs(C) + sum_{k=1}^m abs(Ak)
%% but with diagonal elements removed.
%%
blkold = blk;
m = length(b);
ee = ones(m,1);
numdiagelt = 0;
numblknew = 0;
blockchange = zeros(size(blk,1),1);
Acum = cell(size(blk,1),1);
diagblkinfo = cell(size(blk,1),3);
for p=1:size(blk,1)
pblk = blk(p,:);
n = sum(pblk{2});
if strcmp(pblk{1},'s') & (length(pblk{2}) == 1) & (size(At{p,1},2)==m)
Acumtmp = smat(blk(p,:),abs(At{p})*ee,1) + abs(C{p});
Acum{p} = Acumtmp - spdiags(diag(Acumtmp),0,n,n);
rownorm = sqrt(sum(Acum{p}.*Acum{p}))';
idxdiag = find(rownorm < 1e-15);
if ~isempty(idxdiag)
blockchange(p) = 1;
numdiagelt = numdiagelt + length(idxdiag);
idxnondiag = setdiff([1:n]',idxdiag);
diagblkinfo{p,2} = idxdiag;
diagblkinfo{p,3} = idxnondiag;
if ~isempty(idxnondiag)
numblknew = numblknew + 1;
diagblkinfo{p,1} = numblknew;
end
else
numblknew = numblknew + 1;
diagblkinfo{p,1} = numblknew;
end
else
numblknew = numblknew + 1;
diagblkinfo{p,1} = numblknew;
end
end
%%
%% extract diagonal sub-blocks in nondiagonal blocks
%% into a single linear block
%%
if any(blockchange)
numblk = size(blkold,1);
idx_keepblk = [];
Atmp = cell(1,m);
Adiag = cell(1,m);
C(numblk+1,1) = cell(1,1);
Cdiag = []; Xdiag = []; Zdiag = [];
parbarrierdiag = [];
for p = 1:numblk
n = sum(blkold{p,2});
if (blockchange(p)==1)
idxdiag = diagblkinfo{p,2};
idxnondiag = diagblkinfo{p,3};
if ~isempty(idxdiag);
blk{p,2} = length(idxnondiag);
len = length(idxdiag);
for k = 1:m;
Ak = mexsmat(blkold,At,1,p,k);
tmp = diag(Ak);
Atmp{k} = Ak(idxnondiag,idxnondiag);
Adiag{k} = [Adiag{k}; tmp(idxdiag)];
end
tmp = diag(C{p,1});
Cdiag = [Cdiag; tmp(idxdiag)];
C{p,1} = C{p,1}(idxnondiag,idxnondiag);
At(p) = svec(blk(p,:),Atmp,1);
if (nargin >= 7)
parbarrierdiag = [parbarrierdiag, parbarrier{p}*ones(1,len)];
tmp = diag(X{p,1});
Xdiag = [Xdiag; tmp(idxdiag)];
tmp = diag(Z{p,1});
Zdiag = [Zdiag; tmp(idxdiag)];
X{p,1} = X{p,1}(idxnondiag,idxnondiag);
Z{p,1} = Z{p,1}(idxnondiag,idxnondiag);
end
end
if ~isempty(idxnondiag)
idx_keepblk = [idx_keepblk, p];
else
if (printlevel)
fprintf(' %2.0dth semidefinite block is actually diagonal\n',p);
end
end
else
idx_keepblk = [idx_keepblk, p];
end
end
blk{numblk+1,1} = 'l';
blk{numblk+1,2} = numdiagelt;
C{numblk+1,1} = Cdiag;
At(numblk+1,1) = svec(blk(numblk+1,:),Adiag,1);
idx_keepblk = [idx_keepblk, numblk+1];
blk = blk(idx_keepblk,:);
C = C(idx_keepblk,:);
At = At(idx_keepblk,:);
if (nargin >= 7)
parbarrier{numblk+1,1} = parbarrierdiag;
X{numblk+1,1} = Xdiag;
Z{numblk+1,1} = Zdiag;
parbarrier = parbarrier(idx_keepblk);
X = X(idx_keepblk);
Z = Z(idx_keepblk);
end
end
%%******************************************************************