304 lines
9.3 KiB
Mathematica
304 lines
9.3 KiB
Mathematica
|
|
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];
|