Dynamic-Calibration/utils/YALMIP-master/extras/bisection_core.m

210 lines
6.1 KiB
Mathematica
Raw Normal View History

2019-12-18 11:25:45 +00:00
function diagnostic = bisection_core(Constraints,Objective,options)
%BISECTION Core engine
% Note, outer layer added to enable arbitrary sign on ojective.
% Code here initially assumed maximization of scalar, so now we tweak the
% code a bit with swtchedsign to run any case. Fugly.
diagnostic.yalmiptime = 0;
diagnostic.solvertime = 0;
diagnostic.info = '';
diagnostic.problem = 0;
the_sign = 1;
if options.bisection.switchedsign
the_sign = -1;
end
if length(getvariables(Objective)) > 1
diagnostic.problem = -4;
return
end
if ~(isequal(getbase(Objective),[0 1]))
diagnostic.problem = -4;
return
end
if nargin < 3 || isempty(options)
options = sdpsettings;
end
% Initialize the lower bound
% Typically a good guess
lower = 0;
% Silly upper bound
bestUpper = inf;
% Create an optimizer object which solves feasibility problem for a
% particular value of the sought variable
x = recover(setdiff(depends(Constraints),depends(Objective)));
if isempty(options) || isequal(options.solver,'')
% We must figure out suitable solver
[~,~,~,model] = export(replace(Constraints,Objective,pi));
options.solver = model.solver.tag;
end
P = optimizer(Constraints,[],options,Objective,x);
% Safe-guard aganst using LMILAB
if ~isempty(strfind(struct(P).model.options.solver,'lmilab'))
disp('Selected solver LMILAB lacks features making it unsuitable for BISECTION')
disp('See why here https://yalmip.github.io/solver/lmilab/');
disp('Select another SDP solver or/and install a better SDP solver');
error('Cannot proceed due to poor SDP solver');
return
end
if options.verbose;
disp(['Selected solver: ' options.solver]);
fprintf(['Generating initial bound: ' num2str(lower*the_sign)]);
end
% Make sure we actually can solve the lower problem
solvertime = tic;
[sol, flag] = P{lower};
diagnostic.solvertime = diagnostic.solvertime + toc(solvertime);
if flag == 1
% This was infeasible, hernce we can use it as an upper bound
i = 1;
while flag
bestUpper = lower;
lower = lower - 2^(-4+i);i = i+1;
if options.verbose;
fprintf([' (fail), ' num2str(lower*the_sign)]);
end
try
solvertime = tic;
[sol, flag] = P{lower};
diagnostic.solvertime = diagnostic.solvertime + toc(solvertime);
if lower < -1e6
if options.verbose;
fprintf([' (fail). Giving up, never feasible\n']);
end
diagnostic.problem = 21;
diagnostic.info = yalmiperror(diagnostic.problem,'BISECTION');
return
end
catch
diagnostic.problem = 1;
diagnostic.info = yalmiperror(diagnostic.problem,'BISECTION');
return
end
end
if options.verbose;
fprintf([' (ok).']);
end
elseif flag == 0
else
diagnostic.problem = flag;
diagnostic.info = yalmiperror(diagnostic.problem,'BISECTION');
return
end
v = sol;
optimal = lower;
upper = bestUpper;
if isinf(upper)
upper = lower+1;
if options.verbose;
fprintf([' (ok), ' num2str(upper*the_sign)]);
end
[sol, flag] = P{upper};
i = 1;
while ~flag
upper = upper + 2^i;i = i+1;
try
solvertime = tic;
if options.verbose;
fprintf([' (ok), ' num2str(upper*the_sign)]);
end
[sol, flag] = P{upper};
diagnostic.solvertime = diagnostic.solvertime + toc(solvertime);
catch
upper
diagnostic.problem = -1;
diagnostic.info = yalmiperror(diagnostic.problem,'BISECTION');
return
end
if upper > 1e6
if options.verbose;
fprintf([' (oj). Giving up, always feasible!\n']);
end
diagnostic.problem = 2;
diagnostic.info = yalmiperror(diagnostic.problem,'BISECTION');
return
end
end
if options.verbose;
fprintf([' (fail).']);
end
end
if options.verbose
fprintf(['\n']);
end
% Perform bisection
iter = 1;
if options.verbose
disp('Iteration Lower bound Test Upper bound Gap Solver status at test');
end
working_sol = [];
while upper - lower > options.bisection.absgaptol
test = (upper + lower)/2;
solvertime = tic;
[sol, flag] = P{test};
diagnostic.solvertime = diagnostic.solvertime + toc(solvertime);
if options.verbose;
if options.bisection.switchedsign
L = -upper;
T = -test;
U = -lower;
else
L = lower;
T = test;
U = upper;
end
if flag
if flag~=1 && ~any(isnan(sol))
assign(x,sol);assign(Objective,test);res = check(Constraints);
if min(res) >= -1e-6
fprintf(' %4.0f : %12.5E %12.5E %12.5E %12.5E %s\n',iter,L,T,U,U-L,[yalmiperror(flag) '(looks ok)'] );
flag = 0;
else
fprintf(' %4.0f : %12.5E %12.5E %12.5E %12.5E %s\n',iter,L,T,U,U-L,[yalmiperror(flag) '(assumed infeasible)']);
end
else
fprintf(' %4.0f : %12.5E %12.5E %12.5E %12.5E %s\n',iter,L,T, U,U-L,yalmiperror(flag));
end
else
fprintf(' %4.0f : %12.5E %12.5E %12.5E %12.5E %s\n',iter,L,T, U,U-L,yalmiperror(flag));
end
end
if flag == 0
working_sol = sol;
optimal = test;
lower = test;
else
upper = test;
end
iter = iter + 1;
end
if options.bisection.switchedsign
optimal = -optimal;
end
if isempty(working_sol)
diagnostic.problem = 1;
else
% Assign computed solution
assign(x,working_sol);
assign(Objective,optimal);
end
if options.verbose
if diagnostic.problem==0
disp(['Bisection terminated successfully with objective ' num2str(optimal)]);
end
end