Dynamic-Calibration/utils/YALMIP-master/operators/sdpfun.m

147 lines
5.2 KiB
Matlab
Executable File

function varargout = sdpfun(varargin)
%SDPFUN Gateway to general (elementwise) functions on SDPVAR variables (overloaded)
if ~isa(varargin{1},'char') && any(strcmp(cellfun(@class,varargin,'UniformOutput',0),'sdpvar'))
fun_handles = zeros(nargin,1);
for i = 1:nargin
if isstr(varargin{end}) && isequal(varargin{i}(1),'@')
fun = eval(varargin{i});
varargin{i} = fun;
fun_handles(i) = 1;
elseif isa(varargin{i},'function_handle')
fun_handles(i) = 1;
end
end
% Temporarily remove derivative info (to avoid change of legacy
% code below)
if nnz(fun_handles) == 2
derivative = varargin{end};
varargin = {varargin{1:end-1}}
else
derivative = [];
end
for i = 1:length(varargin)
% we don't know in which order arguments are applied. If some argument
% is an sdpvar, it means the user is defining the operator
if isa(varargin{i},'sdpvar')
% Overloaded operator for SDPVAR objects. Pass on args and save them.
% try to figure out size of expected output (many->1 or many->many
varargin_copy = varargin;
for j = 1:length(varargin)-1
% Create zero arguments
if isa(varargin_copy{j},'sdpvar')
varargin_copy{j} = zeros(size(varargin_copy{j},1),size(varargin_copy{j},2));
dataExample = varargin_copy{j};
end
end
output = feval(varargin_copy{end},varargin_copy{1:end-1});
if prod(size(output)) == 1
% MANY -> 1
% Append derivative (might be empty)
varargin{end+1} = derivative;
if numel(dataExample)>1
f = varargin{end-1};
[n,m] = size(dataExample);
g = @(x)f(reshape(x,n,m));
varargin{end-1} = g;
end
varargout{1} = yalmip('define',mfilename,varargin{:});
else
% MANY -> MANY
y = [];
[n,m] = size(varargin{1});
varargin{1} = varargin{1}(:);
for i = 1:length(varargin{1})
varargin_copy = varargin;
varargin_copy{1} = varargin_copy{1}(i);
varargin_copy{end+1} = derivative;
y = [y;yalmip('define',mfilename,varargin_copy{:})];
end
varargout{1} = reshape(y,n,m);
end
return
end
end
end
switch class(varargin{1})
case {'struct','double'} % What is the numerical value of this argument (needed for displays etc)
varargout{1} = feval(varargin{end-1},varargin{1:end-2});
case 'sdpvar'
% Should not happen
error('Report bug. Call to SDPFUN with SDPVAR object');
case 'char' % YALMIP sends 'model' when it wants the epigraph or hypograph
operator = struct('convexity','none','monotonicity','none','definiteness','none','model','callback');
operator.bounds = @bounds;
operator.convexhull = @convexhull;
if ~isempty(varargin{end})
operator.derivative = varargin{end};
end
varargout{1} = [];
varargout{2} = operator;
% Figure out which argument actually is the SDPVAR object (not
% necessarily the first argument
for i = 3:length(varargin)
if isa(varargin{i},'sdpvar')
varargout{3} = varargin{i};
return
end
end
error('SDPFUN arguments seem weird. Could not find any SDPVAR object');
otherwise
error('SDPVAR/SDPFUN called with CHAR argument?');
end
function [Ax,Ay,b] = convexhull(xL,xU,varargin)
if length(xL)==1 && ~(isinf(xL) | isinf(xU))
z = linspace(xL,xU,100);
fz = feval(varargin{end-1},z,varargin{1:end-2});
% create 4 bounding planes
% f(z) < k1*(x-XL) + f(xL)
% f(z) > k2*(x-XL) + f(xL)
% f(z) < k3*(x-XU) + f(xU)
% f(z) > k4*(x-XU) + f(xU)
% f(z) < k5*(x-XM) + f(xM)
% f(z) > k6*(x-XM) + f(xM)
k1 = max((fz(2:end)-fz(1))./(z(2:end)-xL))+1e-12;
k2 = min((fz(2:end)-fz(1))./(z(2:end)-xL))-1e-12;
k3 = min((fz(1:end-1)-fz(end))./(z(1:end-1)-xU))+1e-12;
k4 = max((fz(1:end-1)-fz(end))./(z(1:end-1)-xU))-1e-12;
Ax = [-k1;k2;-k3;k4];
Ay = [1;-1;1;-1];
b = [k1*(-z(1)) + fz(1);-(k2*(-z(1)) + fz(1));k3*(-z(end)) + fz(end);-(k4*(-z(end)) + fz(end))];
else
Ax = [];
Ay = [];
b = [];
end
function [L,U] = bounds(xL,xU,varargin)
if length(xL)==1 && ~isinf(xL) & ~isinf(xU)
xtest = linspace(xL,xU,100);
values = feval(varargin{end-1},xtest,varargin{1:end-2});
[minval,minpos] = min(values);
[maxval,maxpos] = max(values);
% Concetrate search around the extreme regions
xtestmin = linspace(xtest(max([1 minpos-5])),xtest(min([100 minpos+5])),100);
xtestmax = linspace(xtest(max([1 maxpos-5])),xtest(min([100 maxpos+5])),100);
values1 = feval(varargin{end-1},xtestmin,varargin{1:end-2});
values2 = feval(varargin{end-1},xtestmax,varargin{1:end-2});
L = min([values1 values2]);
U = max([values1 values2]);
else
L = -inf;
U = inf;
end