Dynamic-Calibration/utils/YALMIP-master/modules/moment/extractsolution.m

119 lines
3.0 KiB
Mathematica
Raw Normal View History

2019-12-18 11:25:45 +00:00
function x_extract = extractsolution(momentdata,options)
%EXTRACTSOLUTIONS Tries to extract solutions from moment matrices
%
%
% xoptimal = extractsolution(momentstructure)
%
% xoptimal : Extracted solutions
%
% momentdata : Problem data, obtained from SOLVEMOMENT (or SOLVESDP)
% options : Options structure from SDPSETTINGS
%
% See also SOLVEMOMENT, SDPSETTINGS
% Author Johan L<EFBFBD>fberg
% $Id: extractsolution.m,v 1.1 2006-03-30 13:36:38 joloef Exp $
moment = momentdata.moment;
x = momentdata.x;
monomials = momentdata.monomials;
n = momentdata.n;
d = momentdata.d;
[U,S,V,ranks] = numranks(moment);
if options.moment.extractrank>0
% We try a extraction from highest order moment no matter what
flat = length(moment);
ranks(flat) = options.moment.extractrank;
else
% Find a flat extension
flat = d+min(find(ranks(1+d:end)-ranks(1:end-d)==0));
end
if ~isempty(flat)
% Find a basis
r = ranks(flat);
V = U{flat}(:,1:r)*sqrt(diag(diag(S{flat}(1:r,1:r))));
if options.moment.rceftol >= 0
[R,pivot] = rref(V',options.moment.rceftol);R = R';
else
% Try to find a reasonable tolerance by avoiding severly badly
% conditioned R. Hack.., but seem to behave rather robustly.
cV = cond(V);
tol = 1e-10;
[R,pivot] = rref(V',tol);R = R';
while tol<1 & (cond(R)/cond(cV)>1e4)
tol = tol*5;
[R,pivot] = rref(V',tol);R = R';
end
end
% Figure out multiplying matrices using YALMIP code
w = monomials(pivot);
for i = 1:n
xw = x(i)*w;
k = [];
for j = 1:length(xw)
k = [k;find(ismember(xw(j),monomials))];
end
N{i} = R(k,:);
end
% Things missing in the basis...
if ~all(cellfun('prodofsize',N)==length(w)^2)
x_extract = {[]};
return;
end
% Create random convex combination
rands = rand(n,1);rands = rands/sum(rands);
M = 0;
for i = 1:n
M = M + rands(i)*N{i};
end
[Q,T] = schur(M);
% Extract solution
for i = 1:r
for j = 1:n
x_extract{i}(j,1) = Q(:,i)'*N{j}*Q(:,i);
end
end
% Refine solutions v-Rw = e(x)=0
if options.moment.refine>0
xtemp = double(x);
e = monomials(1:size(R,1))-R*w;
dedx = jacobian(e,x);
for j = 1:r
assign(x,x_extract{j});
for i = 1:options.moment.refine
assign(x,double(x)-double(dedx)\double(e));
end
x_extract{j} = double(x);
end
assign(x,xtemp);
end
else
x_extract = {};
end
% Somewhat more stable rank detection
% looking for sharp drops in singular value
function [U,S,V,ranks] = numranks(moment)
for i = 1:length(moment)
[U{i},S{i},V{i}] = svd(moment{i});
s = diag(S{i});
decay = s(2:end)./(eps+s(1:end-1));
r = min(find(decay<1e-3));
if isempty(r)
ranks(i) = rank(moment{i},1e-8);
else
ranks(i) = min(r,rank(moment{i},1e-8));
end
end