203 lines
8.1 KiB
Mathematica
203 lines
8.1 KiB
Mathematica
|
|
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
|