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

203 lines
8.1 KiB
Mathematica
Raw Normal View History

2019-12-18 11:25:45 +00:00
function varargout = pwq_yalmip(varargin)
%PWQ_YALMIP Defines a piecewise quadratic function using data from MPT
%
%Only intended for internal use in YALMIP
%
% Currently only a container for PWQ functions. Can not be
% used in actual optmization problem.
switch class(varargin{1})
case {'struct','cell'} % Should only be called internally
if isa(varargin{2},'double')
% Called from YALMIP to get double
pwastruct = varargin{1};
x = varargin{2};
index = varargin{5};
val = inf;
for i = 1:length(pwastruct)
[ii,jj] = isinside(pwastruct{i}.Pn,x);
if ii
for k = 1:length(jj)
Q = pwastruct{i}.Ai{jj(k)};
if index>1 | min(size(pwastruct{i}.Bi{jj(k)}))>1
% FIX: Why?? Where is this feature used
val = min(val,x'*Q*x + reshape(pwastruct{i}.Bi{jj(k)}(index,:),1,[])*x+pwastruct{i}.Ci{jj(k)}(index));
else
val = min(val,x'*Q*x + reshape(pwastruct{i}.Bi{jj(k)},1,[])*x+pwastruct{i}.Ci{jj(k)});
end
end
end
end
if isinf(val)
val = nan;
end
varargout{1} = min(val);
return
end
if nargin<3
pwaclass = 'general'
end
if isa(varargin{1},'struct')
varargin{1} = {varargin{1}};
end
% Put in standard format
if ~isfield(varargin{1}{1},'Bi')
if ~isfield(varargin{1}{1},'Fi')
error('Wrong format on input to PWQ (requires Bi or Fi)');
else
for i = 1:length(varargin{1})
varargin{1}{1}.Ai = cell(1, varargin{1}{i}.Fi);
varargin{1}{i}.Bi = varargin{1}{i}.Fi
varargin{1}{i}.Ci = varargin{1}{i}.Gi
end
end
end
if ~isfield(varargin{1}{1},'Pfinal')
error('Wrong format on input to PWQ (requires field Pn)');
end
% This will be a container for binary variables in the furture
varargin{end+1} = binvar(length(varargin{1}{1}.Pn),1);
% Create one variable for each row
% Inefficient but the only way currently in YALMIP
varargout{1} = [];
varargin{end+1} = 1;
for i = 1:length(varargin{1}{1}.Ci{1})
varargin{end} = i;
varargout{1} = [varargout{1};yalmip('define',mfilename,varargin{:})];
end
case 'char' % YALMIP sends 'model' when it wants the epigraph or hypograph
switch varargin{1}
case 'graph'
varargout{1} = [];
varargout{2} = struct('convexity','none','monotoncity','none','definiteness','none');
varargout{3} = [];
case {'integer','exact'}
% FIX : Should create case for overlapping convex PWAs,
% used in a nonconvex fashion...
% Can only generate the first class of PWA functions
t = varargin{2}; % The YALMIP variables modelling this pwa
pwq_struct = varargin{3};% MPT structure
x = varargin{4}; % Argument
flag = varargin{5}; % Type of PWA function
d = varargin{6}; % Binary for nonconvex cases
index = varargin{7}; % Which row in Bix+Ci
switch flag
case {'general','convex'}
if length(d)==1
% Don't introduce any binary variables when
% there is only one quadratic cost
F = ([]);
cost = x'*pwq_struct{1}.Ai{1}*x+pwq_struct{1}.Bi{1}*x+pwq_struct{1}.Ci{1};
else
n = length(x);
m = length(d);
z = sdpvar(n,m,'full');
F = (sum(d) == 1);
cost = 0;
[Mm,mm] = derivebounds(x);
try
[aux,mx,Mx] = bounding_box(pwq_struct{1}.Pfinal);
catch
Mx = 10000*ones(length(x),1);
mx = -10000*ones(length(x),1);
end
Mx = min([Mx Mm],[],2);
mx = max([mx mm],[],2);
for i = 1:m
% bounds(z(:,i),mx,Mx);
F = F + (-(Mx-mx)*(1-d(i)) <= z(:,i)-x <= (Mx-mx)*(1-d(i)));
F = F + (mx*d(i) <= z(:,i) <= Mx*d(i));
[H,K] = double(pwq_struct{1}.Pn(i));
[M,m] = derivebounds(H*x-K);
F = F + (H*x-K <= M*(1-d(i)));
cost = cost + z(:,i)'*pwq_struct{1}.Ai{i}*z(:,i)+pwq_struct{1}.Bi{i}(:)'*z(:,i)+d(i)*pwq_struct{1}.Ci{i};
end
end
varargout{1} = F;
varargout{2} = struct('convexity','none','monotoncity','none','definiteness','none','model','integer');
varargout{2}.replacer = cost;
varargout{3} = x;
case {'convexoverlapping'}
n = length(x);
cost = 0;
r = binvar(length(pwq_struct),1);
d = {};
% Derive bounds from polytopes
[aux,mx,Mx] = bounding_box(pwq_struct{1}.Pfinal);
for i = 2:length(pwq_struct)
[aux,L,U] = bounding_box(pwq_struct{i}.Pfinal);
Mx = max([Mx U],[],2);
mx = min([mx L],[],2);
end
bounds(x,mx,Mx);
% Some overlapping function is active
% (it will automatically be the smallest one)
F = (sum(r) == 1);
for j = 1:length(pwq_struct)
if length(pwq_struct{j}.Pn) == 1
d{j} = r(j);
else
d{j} = binvar(length(pwq_struct{j}.Pn),1);
F = F + (sum(d{j}) == r(j));
end
m = length(d{j});
z = sdpvar(n,m,'full');
for i = 1:m
bounds(z(:,i),mx,Mx);
F = F + (-(Mx-mx)*(1-d{j}(i)) <= z(:,i)-x <= (Mx-mx)*(1-d{j}(i)));
F = F + (mx*d{j}(i) <= z(:,i) <= Mx*d{j}(i));
[H,K] = double(pwq_struct{j}.Pn(i));
[M,m] = derivebounds(H*x-K);
F = F + (H*x-K <= M*(1-d{j}(i)));
cost = cost + z(:,i)'*pwq_struct{j}.Ai{i}*z(:,i)+pwq_struct{j}.Bi{i}*z(:,i)+d{j}(i)*pwq_struct{j}.Ci{i};
end
end
varargout{1} = F;
varargout{2} = struct('convexity','none','monotoncity','none','definiteness','none','model','integer');
varargout{2}.replacer = cost;
varargout{3} = x;
otherwise
varargout{1} = [];
varargout{2} = struct('convexity','convex','monotoncity','none','definiteness','none');
varargout{3} = [];
return
end
otherwise
error('PWA_YALMIP called with CHAR argument?');
end
otherwise
error('Strange type on first argument in PWQ_YALMIP');
end