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

304 lines
9.3 KiB
Matlab
Executable File

function [model,changed] = convert_sigmonial_to_sdpfun(model)
% Always add this dummy struct
model.high_monom_model = [];
% Assume we don't do anything
changed = 0;
found_and_converted = [];
if any(model.variabletype > 3)
% Bugger...
changed = 1;
% Find a higher order term
sigmonials = find(model.variabletype == 4);
model = update_monomial_bounds(model);
monosig = sigmonials(find(sum(model.monomtable(sigmonials,:) | model.monomtable(sigmonials,:),2)==1));
if ~isempty(monosig)
% These are just monomial terms such as x^0.4 etc
for i = 1:length(monosig)
variable = find(model.monomtable(monosig(i),:));
power = model.monomtable(monosig(i),variable);
model = add_sigmonial_eval(model,monosig(i),variable,power);
found_and_converted = [found_and_converted;variable power monosig(i)];
end
end
end
if any(model.variabletype > 3)
% Bugger...we have mixed terms such as x/y etc
% Find a higher order term
sigmonials = find(model.variabletype == 4);
for i = 1:length(sigmonials)
n_old_monoms = size(model.monomtable,1);
monoms = model.monomtable(sigmonials(i),:);
% Which variables have fractional or negative powers
sigs = find((monoms ~= fix(monoms)) | monoms<0);
powers = monoms(sigs);
if ~isempty(found_and_converted)
% Maybe some of the terms have already been defined as new
% variables
for j = 1:length(sigs)
old_index = findrows(found_and_converted(:,1:2),[sigs(j) powers(j)]);
if ~isempty(old_index)
corresponding_variable = found_and_converted(old_index,3);
model.monomtable(sigmonials(i),sigs(j)) = 0;
model.monomtable(sigmonials(i),corresponding_variable) = 1;
sigs(j)=nan;
end
end
end
powers(isnan(sigs)) = [];
sigs(isnan(sigs)) = [];
if length(sigs) > 0
% Terms left that haven't been modeled
model.monomtable(sigmonials(i),sigs) = 0;
model.monomtable = blkdiag(model.monomtable,speye(length(sigs)));
model.monomtable(sigmonials(i),n_old_monoms+1:n_old_monoms+length(sigs)) = 1;
model.variabletype(sigmonials(i)) = 3;
model.variabletype(end+1:end+length(sigs)) = 0;
model.c(end+1:end+length(sigs)) = 0;
model.Q = blkdiag(model.Q,zeros(length(sigs)));
model.F_struc = [model.F_struc zeros(size(model.F_struc,1),length(sigs))];
model.lb = [model.lb;-inf(length(sigs),1)];
model.ub = [model.ub;inf(length(sigs),1)];
if ~isempty(model.x0)
model.x0 = [model.x0;model.x0(sigs).^powers(:)];
end
for j = 1:length(sigs)
model.evalVariables = [model.evalVariables n_old_monoms+j];
model.isevalVariable(model.evalVariables)=1;
if powers(j)==-1
model.evalMap{end+1} = inverse_internal2_operator(model,sigs(j),n_old_monoms+j);
else
model.evalMap{end+1} = power_internal2_operator(model,sigs(j),powers(j));
end
model.evalMap{end}.properties.domain = [-inf inf];
model.evalMap{end}.properties.range = [-inf inf];
model.evalMap{end}.variableIndex = sigs(j);
model.evalMap{end}.argumentIndex = 1;
model.evalMap{end}.computes = n_old_monoms+j;
found_and_converted = [found_and_converted;sigs(j) powers(j) n_old_monoms+j];
end
end
if sum(model.monomtable(sigmonials(i),:))<=2
if nnz(model.monomtable(sigmonials(i),:))==1
model.variabletype(sigmonials(i)) = 2;
else
model.variabletype(sigmonials(i)) = 1;
end
end
end
model = update_eval_bounds(model);
for i = 1:length(model.evalMap)
if isequal(model.evalMap{i}.fcn,'power_internal2')
if isequal(model.evalMap{i}.arg{2},-1)
if model.lb(model.evalMap{i}.variableIndex) > 0
model.evalMap{i}.properties.convexity = 'convex';
model.evalMap{i}.properties.monotonicity='decreasing';
model.evalMap{i}.properties.inverse=@(x)1./x;
elseif model.ub(model.evalMap{i}.variableIndex) < 0
model.evalMap{i}.properties.convexity = 'concave';
model.evalMap{i}.properties.monotonicity='increasing';
model.evalMap{i}.properties.inverse=@(x)1./x;
end
end
end
end
end
function model = add_sigmonial_eval(model,monosig,variable,power)
model.evalVariables = [model.evalVariables monosig];
model.isevalVariable(model.evalVariables)=1;
if power == -1
model.evalMap{end+1} = inverse_internal2_operator(model,variable,variable);
else
model.evalMap{end+1} = power_internal2_operator(model,variable,power);
end
model.evalMap{end}.variableIndex = find(model.monomtable(monosig,:));
model.evalMap{end}.argumentIndex = 1;
model.evalMap{end}.computes = monosig;
model.monomtable(monosig,variable) = 0;
model.monomtable(monosig,monosig) = 1;
model.variabletype(monosig) = 0;
% This should not be hidden here....
function [L,U] = power_bound(xL,xU,power)
if xL >= 0
% This is the easy case
% we use abs since 0 sometimes actually is -0 but still passes the test
% above
if power > 0
L = abs(xL)^power;
U = abs(xU)^power;
else
L = abs(xU)^power;
U = abs(xL)^power;
end
else
if power < 0 & xU > 0
% Nasty crossing around zero
U = inf;
L = -inf;
elseif xU < 0
L = xU^power;
U = xL^power;
else
disp('Not implemented yet')
error
end
end
function [L,U] = inverse_bound(xL,xU)
if xL >= 0
% This is the easy case. We use abs since 0 sometimes actually is -0
% but still passes the test above
L = abs(xU)^-1;
U = abs(xL)^-1;
else
if xU > 0
% Nasty crossing around zero
U = inf;
L = -inf;
elseif xU < 0
L = xU^-1;
U = xL^-1;
else
disp('Not implemented yet')
error
end
end
function [Ax, Ay, b] = power_convexhull(xL,xU,power)
fL = xL^power;
fU = xU^power;
dfL = power*xL^(power-1);
dfU = power*xU^(power-1);
if xL<0 & xU>0
% Nasty crossing
Ax = [];
Ay = [];
b = [];
return
end
average_derivative = (fU-fL)/(xU-xL);
xM = (average_derivative/power).^(1/(power-1));
if xU < 0
xM = -xM;
end
fM = xM^power;
dfM = power*xM^(power-1);
if ((power > 1 | power < 0) & (xL >=0)) | ((power < 1 & power > 0) & (xU <=0))
[Ax,Ay,b] = convexhullConvex(xL,xM,xU,fL,fM,fU,dfL,dfM,dfU);
else
[Ax,Ay,b] = convexhullConcave(xL,xM,xU,fL,fM,fU,dfL,dfM,dfU);
end
if ~isempty(Ax)
if isinf(Ax(1))
Ay(1) = 0;
Ax(1) = -1;
B(1) = 0;
end
end
function [Ax, Ay, b] = inverse_convexhull(xL,xU)
fL = xL^-1;
fU = xU^-1;
dfL = -1*xL^(-2);
dfU = -1*xU^(-2);
if xL<0 & xU>0
% Nasty crossing
Ax = [1;-1];
Ay = [0;0];
b = [xU;-xL];
return
end
average_derivative = (fU-fL)/(xU-xL);
xM = (average_derivative/(-1)).^(1/(-1-1));
if xU < 0
xM = -xM;
end
if ~(xM > xL)
xM = (xL + xU)/2;
end
fM = xM^(-1);
dfM = (-1)*xM^(-2);
if xL >= 0
[Ax,Ay,b] = convexhullConvex(xL,xM,xU,fL,fM,fU,dfL,dfM,dfU);
else
[Ax,Ay,b] = convexhullConcave(xL,xM,xU,fL,fM,fU,dfL,dfM,dfU);
end
function df = power_derivative(x,power)
fL = xL^power;
fU = xU^power;
dfL = power*xL^(power-1);
dfU = power*xU^(power-1);
if xL<0 & xU>0
% Nasty crossing
Ax = [];
Ay = [];
b = [];
return
end
if power > 1 | power < 0
[Ax,Ay,b] = convexhullConvex(xL,xU,fL,fU,dfL,dfU);
else
[Ax,Ay,b] = convexhullConcave(xL,xU,fL,fU,dfL,dfU);
end
if ~isempty(Ax)
if isinf(Ax(1))
Ay(1) = 0;
Ax(1) = -1;
B(1) = 0;
end
end
function f = inverse_internal2_operator(model,variable,in);
f.fcn = 'inverse_internal2';
f.arg{1} = recover(in);
f.arg{2} = [];
f.properties.bounds = @inverse_bound;
f.properties.convexhull = @inverse_convexhull;
f.properties.derivative = @(x) -1./(x.^2);
f.properties.range = [-inf inf];
f.properties.domain = [-inf inf];
flb = 1/model.lb(variable);
fub = 1/model.ub(variable);
if model.lb(variable)>0 | model.ub(variable) < 0
f.properties.monotonicity = 'decreasing';
f.properties.inverse = @(x)(1./x);
f.properties.range = [min(flb,fub) max(flb,fub)];
end
if model.lb(variable) >= 0
f.properties.convexity = 'convex';
f.properties.range = [fub flb];
elseif model.ub(variable) <= 0
f.properties.convexity = 'concave';
f.properties.range = [fub flb];
end
f.properties.inverse = [];
function f = power_internal2_operator(model,variable,power);
f.fcn = 'power_internal2';
f.arg{1} = recover(variable);
f.arg{2} = power;
f.arg{3} = [];
f.properties.bounds = @power_bound;
f.properties.convexhull = @power_convexhull;
f.properties.derivative = eval(['@(x) ' num2str(power) '*x.^(' num2str(power) '-1);']);
f.properties.inverse = [];
if even(power)
f.properties.range = [0 inf];
else
f.properties.range = [-inf inf];
end
f.properties.domain = [-inf inf];