Dynamic-Calibration/utils/YALMIP-master/extras/@optimizer/subsref.m

408 lines
16 KiB
Mathematica
Raw Permalink Normal View History

2019-12-18 11:25:45 +00:00
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