408 lines
16 KiB
Matlab
Executable File
408 lines
16 KiB
Matlab
Executable File
function varargout = subsref(self,subs)
|
|
|
|
if isequal(subs.type,'()')
|
|
|
|
% Previously not allowed and user was to use cell format for some now
|
|
% forgotten reason (ideas about other functionalities for () perhaps)
|
|
% We support it now though, so throw to the previously required {}
|
|
subs.type ='{}';
|
|
[varargout{1:nargout}] = subsref(self,subs);
|
|
|
|
elseif isequal(subs.type,'.')
|
|
|
|
if length(subs) == 1
|
|
switch subs.subs
|
|
case 'options'
|
|
varargout{1} = self.model.options;
|
|
case 'model'
|
|
varargout{1} = self.model;
|
|
otherwise
|
|
error('Field not accesible. You can only acsess P.options')
|
|
end
|
|
else
|
|
error('Field not accesible. You can only acsess P.options')
|
|
end
|
|
|
|
elseif isequal(subs.type,'{}')
|
|
|
|
% User has typed X();
|
|
if isempty(subs.subs)
|
|
subs.subs = {[]};
|
|
else
|
|
% Flatten the expression to account for various cell calls
|
|
aux = {};
|
|
for i = 1:length(subs.subs)
|
|
if isa(subs.subs{i},'cell')
|
|
for j = 1:length(subs.subs{i});
|
|
aux = {aux{:},subs.subs{i}{j}};
|
|
end
|
|
else
|
|
aux = {aux{:},subs.subs{i}};
|
|
end
|
|
end
|
|
subs.subs = aux;
|
|
end
|
|
|
|
if length(self.dimin)==0
|
|
if length(subs.subs)==1
|
|
if ~isempty(subs.subs{1})
|
|
error('No parameters left to assign.');
|
|
end
|
|
elseif length(subs.subs)>1
|
|
error('No parameters left to assign.');
|
|
end
|
|
end
|
|
|
|
NoSolve = 0;
|
|
% Check for nosolve flag
|
|
if length(subs.subs)>0 && isequal(subs.subs{end},'nosolve')
|
|
NoSolve = 1;
|
|
subs.subs = {subs.subs{1:end-1}};
|
|
end
|
|
|
|
if isa(subs.subs{1},'lmi') || isa(subs.subs{1},'constraint')
|
|
% User instantiates as P{[x == 1, y == ...]}
|
|
cells = cell(1,length(self.diminOrig));
|
|
for i = 1:length(cells)
|
|
cells{i} = []; % Default user has not specified, partial inst.
|
|
end
|
|
List = subs.subs{1};
|
|
for i = 2:length(subs.subs);List = [List, subs.subs{i}];end
|
|
matched = zeros(1,length(List));
|
|
for i = 1:length(List)
|
|
xi = recover(depends(List(i)));
|
|
for j = 1:length(self.diminOrig)
|
|
if isequal(getvariables(xi), getvariables(self.input.xoriginal{j}))
|
|
if isequal(getbase(xi),getbase(self.input.xoriginal{j}))
|
|
B = getbase(List(i));
|
|
if any(B(:,2:end)>0)
|
|
matched(i) = 1;
|
|
cells{j} = full(reshape(-B(:,1),self.diminOrig{j}));
|
|
else
|
|
matched(i) = 1;
|
|
cells{j} = full(reshape(B(:,1),self.diminOrig{j}));
|
|
end
|
|
else
|
|
error('Only simple expressions allowed when declaring variable values')
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if ~all(matched)
|
|
error('Only simple expressions allowed. Could not match assignments in optimizer call');
|
|
end
|
|
subs.subs = cells;
|
|
end
|
|
|
|
if ~isempty(self.ParametricSolution)
|
|
x = subs.subs{1};
|
|
x = x(:);
|
|
[found,j] = isinside(self.ParametricSolution{1}.Pn,x);
|
|
if found
|
|
j = j(1);
|
|
u = self.ParametricSolution{1}.Fi{j}*x + self.ParametricSolution{1}.Gi{j};
|
|
u = reshape(u,self.dimoutOrig{1});
|
|
varargout{1} = u;
|
|
varargout{2} = 0;
|
|
else
|
|
varargout{1} = nan(self.dimoutOrig{1});
|
|
varargout{2} = 1;
|
|
end
|
|
return
|
|
end
|
|
|
|
if self.model.options.usex0
|
|
if nargout < 5
|
|
warning('If you intend to use initial guesses, you must use a fifth output as [sol,problem,~,~,P] = P(p)');
|
|
end
|
|
end
|
|
|
|
% This is not really supported yet...
|
|
if isa(subs.subs{1},'sdpvar')
|
|
varargout{1} = yalmip('definemulti','optimizer_operator',subs(1).subs{1},self,self.dimout);
|
|
return
|
|
end
|
|
|
|
if ~isempty(self.diminOrig)
|
|
|
|
% Check number of cells
|
|
if length(subs.subs)~=length(self.diminOrig) && ~isempty(self.diminOrig)
|
|
error('The number of cell elements in input does not match OPTIMIZER declaration');
|
|
end
|
|
|
|
% Realify...
|
|
for i = 1:length(subs.subs)
|
|
if self.complexInput(i)
|
|
subs.subs{i} = [real(subs.subs{i});imag(subs.subs{i})];
|
|
end
|
|
end
|
|
|
|
% Check for garbage call
|
|
for i = 1:length(subs.subs)
|
|
if isnan(subs.subs{i})
|
|
if length(self.dimoutOrig)>1
|
|
for j = 1:length(self.dimoutOrig)
|
|
sol{j} = nan(self.dimoutOrig{j});
|
|
end
|
|
else
|
|
sol = nan(self.dimoutOrig{1});
|
|
end
|
|
varargout{1} = sol;
|
|
varargout{2} = -10;
|
|
varargout{3} = yalmiperror(-10);
|
|
varargout{4} = [];
|
|
varargout{5} = self;
|
|
varargout{6} = self;
|
|
return
|
|
end
|
|
end
|
|
|
|
|
|
% If blocked call, check so that there are as many blocks for every
|
|
% argument. Note, we only analyze instantiated blocks
|
|
dimBlocks = nan(length(subs.subs),1);
|
|
for i = 1:length(subs.subs)
|
|
dimBlocks(i) = numel(subs.subs{i}) / prod(self.diminOrig{i});
|
|
end
|
|
if any(dimBlocks)>1 && any(dimBlocks==0)
|
|
error('Blocked data in partial instantiation is not possible');
|
|
end
|
|
if all(dimBlocks)
|
|
if ~isnan(dimBlocks)
|
|
if ~all(dimBlocks == dimBlocks(i))
|
|
error('Dimension mismatch on the input arguments compared to definition');
|
|
end
|
|
if any(dimBlocks ~= fix(dimBlocks))
|
|
error('Dimension mismatch on the input arguments compared to definition');
|
|
end
|
|
end
|
|
end
|
|
|
|
% Just pick out any element, it the number of blocks, as all should
|
|
% be the same
|
|
nBlocks = max(dimBlocks(find(dimBlocks)));
|
|
|
|
left = ones(1,length(subs.subs));
|
|
aux = [];
|
|
aux2 = [];
|
|
suppliedData = [];
|
|
for i = 1:nBlocks
|
|
aux2 = [];
|
|
try
|
|
for j = 1:length(subs.subs)
|
|
data = subs.subs{j};
|
|
if isempty(data)
|
|
temp = nan(self.diminOrig{j});
|
|
temp = temp(:);
|
|
suppliedData(j) = 0;
|
|
else
|
|
temp = data(:,left(j):self.diminOrig{j}(2)+left(j)-1,:);
|
|
suppliedData(j) = 1;
|
|
end
|
|
temp = temp(:);
|
|
temp = temp(self.mask{j});
|
|
aux2 = [aux2;temp];
|
|
left(j) = left(j) + self.diminOrig{j}(2);
|
|
end
|
|
catch
|
|
error('The dimension on a supplied parameter value does not match the definition.');
|
|
end
|
|
%left = left + self.diminOrig{1}(2);
|
|
aux = [aux aux2];
|
|
end
|
|
subs.subs = aux;
|
|
|
|
% Input is now given as [x1 x2 ... xn]
|
|
u = [];
|
|
% nBlocks = dimBlocks(1);
|
|
start = 1;
|
|
if isnan(nBlocks)
|
|
nBlocks = 1;
|
|
end
|
|
else
|
|
u = [];
|
|
start = 0;
|
|
nBlocks = 1;
|
|
end
|
|
|
|
for i = 1:nBlocks
|
|
|
|
if ~isempty(self.diminOrig)
|
|
thisData = subs.subs(:,start:start + self.dimin(2)-1);
|
|
else
|
|
thisData = [];
|
|
end
|
|
|
|
originalModel = self.model;
|
|
|
|
if any(isnan(thisData))
|
|
% Partial elimination)
|
|
currentParametricIndex = self.model.parameterIndex(~isnan(thisData));
|
|
thisData = thisData(~isnan(thisData));
|
|
|
|
allParametricIndex = self.model.parameterIndex;
|
|
globalParametricIndex = find(ismember(self.orginal_usedvariables,self.model.used_variables(currentParametricIndex)));
|
|
self.instatiatedvalues(globalParametricIndex) = thisData;
|
|
|
|
evalParameters = [];
|
|
for k = 1:length(self.model.evalMap)
|
|
for j = 1:length(currentParametricIndex)
|
|
if isequal(self.model.evalMap{k}.variableIndex,currentParametricIndex(j))
|
|
evalParameters = [evalParameters self.model.evalMap{k}.computes];
|
|
end
|
|
end
|
|
end
|
|
self.model.evalParameters = evalParameters;
|
|
|
|
|
|
% Crate an object with a reduced set of variables to
|
|
% eliminate
|
|
self.model.parameterIndex = currentParametricIndex;
|
|
self = optimizer_precalc(self);
|
|
[self.model,keptvariablesIndex] = eliminatevariables(self.model,currentParametricIndex,thisData(:),allParametricIndex);
|
|
|
|
% Update as new optimizer in remaining variables, remap
|
|
% parameters to currently used variables
|
|
remainingParametersIndex = setdiff(allParametricIndex,currentParametricIndex,'stable');
|
|
[~,loc] = ismember(remainingParametersIndex,keptvariablesIndex);
|
|
self.model.parameterIndex = loc;
|
|
|
|
% Remap all evaluation operators
|
|
for k = 1:length(self.model.evalMap)
|
|
self.model.evalMap{k}.computes = find(self.model.evalMap{k}.computes == keptvariablesIndex);
|
|
self.model.evalMap{k}.variableIndex = find(self.model.evalMap{k}.variableIndex == keptvariablesIndex);
|
|
end
|
|
|
|
evalParameters = [];
|
|
for k = 1:length(self.model.evalMap)
|
|
for j = 1:length(self.model.parameterIndex)
|
|
if isequal(self.model.evalMap{k}.variableIndex,self.model.parameterIndex(j))
|
|
evalParameters = [evalParameters self.model.evalMap{k}.computes];
|
|
end
|
|
end
|
|
end
|
|
self.model.evalParameters = evalParameters;
|
|
|
|
self.dimin = [length(self.model.parameterIndex) 1];
|
|
self.diminOrig = {self.diminOrig{find(~suppliedData)}};
|
|
self.input.xoriginal = {self.input.xoriginal{find(~suppliedData)}};
|
|
self.mask = {self.mask{find(~suppliedData)}};
|
|
self = optimizer_precalc(self);
|
|
varargout{1} = self;
|
|
return
|
|
else
|
|
% Standard case where we eliminate all variables left
|
|
self.instatiatedvalues(ismember(self.orginal_usedvariables,self.model.used_variables(self.model.parameterIndex))) = thisData(:);
|
|
[self.model,keptvariablesIndex] = eliminatevariables(self.model,self.model.parameterIndex,thisData(:),self.model.parameterIndex);
|
|
|
|
% Remap all evaluation operators
|
|
self.model.evalVariables = [];
|
|
for k = 1:length(self.model.evalMap)
|
|
self.model.evalMap{k}.computes = find(self.model.evalMap{k}.computes == keptvariablesIndex);
|
|
self.model.evalMap{k}.variableIndex = find(self.model.evalMap{k}.variableIndex == keptvariablesIndex);
|
|
self.model.evalVariables = [self.model.evalVariables self.model.evalMap{k}.computes];
|
|
end
|
|
self.model.evalVariables = sort(self.model.evalVariables);
|
|
end
|
|
|
|
% Turn off equality presolving for simple programs. equality
|
|
% presolve has benefits when the are stuff like log
|
|
self.model.presolveequalities = length(self.model.evalMap) > 0;
|
|
if ~self.model.infeasible
|
|
if self.model.options.usex0 && ~isempty(self.lastsolution)
|
|
self.model.x0 = zeros(length(self.model.c),1);
|
|
self.model.x0 = self.lastsolution;
|
|
elseif ~self.model.options.usex0
|
|
self.model.x0 = [];
|
|
end
|
|
if NoSolve
|
|
% We just returns the presolved model
|
|
self.model.parameterIndex = [];
|
|
self.dimin = [];
|
|
self.diminOrig = {};
|
|
varargout{1} = self;
|
|
return
|
|
else
|
|
eval(['output = ' self.model.solver.call '(self.model);']);
|
|
end
|
|
|
|
if output.problem == 0 && self.model.options.usex0
|
|
self.lastsolution = output.Primal;
|
|
end
|
|
x = self.instatiatedvalues;
|
|
x(ismember(self.orginal_usedvariables,self.model.used_variables)) = output.Primal;
|
|
output.Primal = x;
|
|
|
|
else
|
|
output.problem = 1;
|
|
output.Primal = originalModel.c*0;
|
|
output.Dual = [];
|
|
end
|
|
originalModel.precalc = self.model.precalc;
|
|
self.model = originalModel;
|
|
|
|
if output.problem==1
|
|
output.Primal = output.Primal+nan;
|
|
end
|
|
if isempty(self.output.z)
|
|
if ~isempty(output.Primal)
|
|
% Make sure we map index 0 to Nans
|
|
% 0 corresponds to variables which weren't visible in
|
|
% problem
|
|
output.Primal = [nan;output.Primal];
|
|
u = [u reshape(output.Primal(1+self.map),self.dimout)];
|
|
else
|
|
u = [u reshape(0*self.map+nan,self.dimout)];
|
|
end
|
|
else
|
|
if ~isempty(output.Primal)
|
|
% Make sure we map index 0 to Nans
|
|
% 0 corresponds to variables which weren't visible in
|
|
% problem
|
|
output.Primal = [nan;output.Primal];
|
|
assign(self.output.z,output.Primal(1+self.map));
|
|
assign(self.input.expression,thisData);
|
|
u = [u reshape(double(self.output.expression),self.dimout)];
|
|
end
|
|
end
|
|
varargout{2}(i) = output.problem;
|
|
varargout{3}{i} = yalmiperror(output.problem);
|
|
varargout{4}{i} = output.Dual;
|
|
if ~isempty(self.dimin)
|
|
start = start + self.dimin(2);
|
|
end
|
|
end
|
|
if length(self.dimoutOrig)>1
|
|
% top = 1;
|
|
realDimOut = self.dimoutOrig;
|
|
allu = cell(1, length(self.dimoutOrig));
|
|
for k = 1:nBlocks
|
|
top = 1;
|
|
for i = 1:length(self.dimoutOrig)
|
|
n = prod(self.dimoutOrig{i});
|
|
uvec = reshape(u(top:top+n-1,k),self.dimoutOrig{i});
|
|
if self.complexOutput(i)
|
|
uvec = uvec(1:size(uvec,1)/2,:) + uvec(1+size(uvec,1)/2:end,:)*sqrt(-1);
|
|
end
|
|
allu{i} = [allu{i} uvec];
|
|
top = top + n;
|
|
end
|
|
end
|
|
varargout{1} = allu;
|
|
elseif nBlocks==1
|
|
varargout{1} = reshape(u(:),self.dimoutOrig{1});
|
|
if self.complexOutput(1)
|
|
if length(self.dimoutOrig{1})==2
|
|
varargout{1} = varargout{1}(1:self.dimoutOrig{1}(1)/2,:) + sqrt(-1)*varargout{1}(self.dimoutOrig{1}(1)/2+1:end,:);
|
|
else
|
|
% FIXME: This only works for 3D...
|
|
varargout{1} = varargout{1}(1:self.dimoutOrig{1}(1)/2,:,:) + sqrt(-1)*varargout{1}(self.dimoutOrig{1}(1)/2+1:end,:,:);
|
|
end
|
|
end
|
|
else
|
|
varargout{1} = u;
|
|
end
|
|
varargout{5} = self;
|
|
varargout{6} = output;
|
|
end
|