Dynamic-Calibration/utils/YALMIP-master/extras/@lmi/check.m

284 lines
8.1 KiB
Mathematica
Raw Normal View History

2019-12-18 11:25:45 +00:00
function [pres,dres] = check(F)
% CHECK(F) Displays/calculates constraint residuals on constraint F
%
% [pres,dres] = check(F)
%
% pres : Primal constraint residuals
% dres : Dual constraint residuals
%
% If no output argument is supplied, tabulated results are displayed
%
% Primal constraint residuals are calculated as:
%
% Semidefinite constraint F(x)>=0 : min(eig(F))
% Element-wise constraint F(x)>=0 : min(min(F))
% Equality constraint F==0 : -max(max(abs(F)))
% Second order cone t>=||x|| : t-||x||
% Exponential cone constraint : x(3) - exp(x(1)/x(2))*x(2)
% Integrality constraint on x : max(abs(x-round(x)))
% Sum-of-square constraint : Minus value of largest (absolute value) coefficient
% in the polynomial p-v'*v
%
% Dual constraints are evaluated similarily.
%
% See also SOLVESDP, SOLVESOS, SOSD, DUAL
% Check if solution avaliable
currsol = evalin('caller','yalmip(''getsolution'')');
if isempty(currsol)
disp('No solution available.')
return
end
F = flatten(F);
nlmi = length(F.LMIid);
spaces = [' '];
if (nlmi == 0)
if nargout == 0
disp('empty LMI')
else
pres = [];
dres = [];
end
return
end
lmiinfo{1} = 'Matrix inequality';
lmiinfo{2} = 'Elementwise inequality';
lmiinfo{3} = 'Equality constraint';
lmiinfo{4} = 'Second order cone constraint';
lmiinfo{5} = 'Rotated Lorentz constraint';
lmiinfo{7} = 'Integer constraint';
lmiinfo{8} = 'Binary constraint';
lmiinfo{9} = 'KYP constraint';
lmiinfo{10} = 'Eigenvalue constraint';
lmiinfo{11} = 'SOS constraint';
lmiinfo{15} = 'Uncertainty declaration';
lmiinfo{54} = 'Vectorized second order cone constraints';
lmiinfo{55} = 'Complementarity constraint';
lmiinfo{56} = 'Logic constraint';
header = {'ID','Constraint','Primal residual','Dual residual','Tag'};
if nargout==0
disp(' ');
end
% Checkset is very slow for multiple SOS
% The reason is that REPLACE has to be called
% for every SOS. Instead, precalc on one vector
p=[];
ParVar=[];
soscount=1;
for j = 1:nlmi
if F.clauses{j}.type==11
pi = F.clauses{j}.data;
[v,ParVari] = sosd(pi);
if isempty(v)
p=[p;0];
else
p=[p;pi];
ParVar=unique([ParVar(:);ParVari(:)]);
end
end
end
if ~isempty(ParVar)
ParVar = recover(ParVar);
p = replace(p,ParVar,double(ParVar));
end
for j = 1:nlmi
constraint_type = F.clauses{j}.type;
if constraint_type~=11 && constraint_type~=56
F0 = double(F.clauses{j}.data);
end
if ~((constraint_type == 56) || (constraint_type==11)) && any(isnan(F0(:)))
res(j,1) = NaN;
else
switch F.clauses{j}.type
case {1,9}
if isa(F0,'intval')
res(j,1) = full(min(inf_(veigsym(F0))));
else
res(j,1) = full(min(real(eig(F0))));
end
case 2
if isa(F0,'intval')
res(j,1) = full(min(min(inf_(F0))));
else
res(j,1) = full(min(min(F0)));
end
case 3
res(j,1) = -full(max(max(abs(F0))));
case 4
res(j,1) = full(F0(1)-norm(F0(2:end)));
case 5
res(j,1) = full(2*F0(1)*F0(2)-norm(F0(3:end))^2);
case 7
res(j,1) = -full(max(max(abs(F0-round(F0)))));
case 8
res(j,1) = -full(max(max(abs(F0-round(F0)))));
res(j,1) = min(res(j,1),-(any(F0>1) | any(F0<0)));
case 21
res(j,1) = F0(3) - F0(2)*exp(F0(1)/F0(2));
case 54
res(j,1) = inf;
for k = 1:size(F0,2)
res(j,1) = min(res(j,1),full(F0(1,k)-norm(F0(2:end,k))));
end
case 11
if 0
p = F.clauses{j}.data;
[v,ParVar] = sosd(p);
if ~isempty(ParVar)
ParVar = recover(ParVar);
p = replace(p,ParVar,double(ParVar));
end
if isempty(v)
res(j,1)=nan;
else
h = p-v'*v;
res(j,1) = full(max(max(abs(getbase(h)))));
end
else
%p = F.clauses{j}.data;
[v,ParVar] = sosd(F.clauses{j}.data);
if isempty(v)
res(j,1)=nan;
else
h = p(soscount)-v'*v;
res(j,1) = full(max(max(abs(getbase(h)))));
end
soscount=soscount+1;
end
case 56
res(j,1) = logicSatisfaction(F.clauses{j}.data);
otherwise
res(j,1) = nan;
end
end
% Get the internal index
LMIid = F.LMIid(j);
dual = yalmip('dual',LMIid);
if isempty(dual) | any(isnan(dual))
resdual(j,1) = NaN;
else
switch F.clauses{j}.type
case {1,9}
resdual(j,1) = min(eig(dual));
case 2
resdual(j,1) = min(min(dual));
case 3
resdual(j,1) = -max(max(abs(dual)));
case 4
resdual(j,1) = dual(1)-norm(dual(2:end));
case 5
resdual(j,1) = 2*dual(1)*dual(2)-norm(dual(3:end))^2;
case 7
resdual(j,1) = nan;
case 54
resdual(j,1) = inf;
for k = 1:size(dual,2)
resdual(j,1) = min(resdual(j,1),full(dual(1,k)-norm(dual(2:end,k))));
end
otherwise
gap = nan;
end
end
if nargout==0
data{j,1} = ['#' num2str(j)];
data{j,2} = lmiinfo{F.clauses{j}.type};
data{j,3} = res(j,1);
data{j,4} = resdual(j,1);
data{j,5} = F.clauses{j}.handle;
if ~islinear(F.clauses{j}.data)
if is(F.clauses{j}.data,'sigmonial')
classification = 'sigmonial';
elseif is(F.clauses{j}.data,'bilinear')
classification = 'bilinear';
elseif is(F.clauses{j}.data,'quadratic')
classification = 'quadratic';
else
classification = 'polynomial';
end
data{j,2} = [data{j,2} ' (' classification ')'];
end
end
end
if nargout>0
pres = res;
dres = resdual;
else
keep = ones(1,5);
if length([data{:,5}])==0
keep(5) = 0;
end
header = {header{:,find(keep)}};
temp = {data{:,find(keep)}};
data = reshape(temp,length(temp)/nnz(keep),nnz(keep));
post{1} = 'A primal-dual optimal solution would show non-negative residuals.';
post{end+1} = 'In practice, many solvers converge to slightly infeasible';
post{end+1} = 'solutions, which may cause some residuals to be negative.';
post{end+1} = 'It is up to the user to judge the importance and impact of';
post{end+1} = 'slightly negative residuals (i.e. infeasibilities)';
post{end+1} = 'https://yalmip.github.io/command/check/';
post{end+1} = 'https://yalmip.github.io/faq/solutionviolated/';
yalmiptable('',header,data,[],post);
disp(' ');
end
function res = logicSatisfaction(clause);
a = clause{2};
b = clause{3};
if isa(a,'sdpvar')
aval = double(a);
if is(a,'binary')
atruth = aval == 1;
else
atruth = aval>=0;
end
elseif isa(a,'lmi') | isa(a,'constraint')
aval = check(lmi(a));
atruth = aval >= 0;
end
if isa(b,'sdpvar')
bval = double(b);
if is(b,'binary')
btruth = bval == 1;
else
btruth = bval>=0;
end
elseif isa(b,'lmi') | isa(b,'constraint')
bval = check(lmi(b));
btruth = bval >= 0;
end
if isnan(aval) | isnan(bval)
res = nan;
else
switch clause{1}
case 'implies'
if all(btruth >= atruth)
res = 1;
else
res = -1;
end
case 'iff'
if all(btruth == atruth);
res = 1;
else
res = -1;
end
otherwise
res = nan;
end
end