Should lsqcurvefit reshape the initializing parameter vector?

4 vues (au cours des 30 derniers jours)
Matt J
Matt J le 10 Oct 2018
Commenté : Matt J le 21 Mai 2021
When I run the following simple test of lsqcurvefit in R2018a,
function test
ctrue=[1;2;3];
xdata=rand(3);
ydata=F(ctrue,xdata);
lb=-inf(3,1); ub=+inf(3,1);
lb(1)=1; ub(1)=1;
opts=optimoptions(@lsqcurvefit, 'SpecifyObjectiveGradient',true);
c=lsqcurvefit(@F,[0;0;0],xdata,ydata,lb,ub,opts);
with this model function,
function [out,Jac]=F(c,xd)
assert( isequal(size(c),[3,1]) , ...
['c is expected to be 3x1, but it is ',...
num2str(size(c,1)),'x' num2str(size(c,2)) ])
out=xd*c;
Jac=xd;
the assert is triggered and I get,
Error using test>F (line 21)
c is expected to be 3x1, but it is 1x3
So lsqcurvefit is passing c as a 1x3 row vector, even though the initial c that I provided was a 3x1 column vector [0;0;0]. Should this occur? Shouldn't I be able to count on the initial vector's shape to determine the shape of the parameter arrays that get passed to the model function?
  5 commentaires
Matt J
Matt J le 11 Oct 2018
Modifié(e) : Matt J le 11 Oct 2018
I think that section of the documentation is mis-written. It is inconsistent with both the other documentation page that I cited for you, as well as the modification of my test below. Now, F(c,xd) expects c to be a 3x3 matrix. In this case, I find that the assert() is not triggered and the optimization completes successfully. In other words, c is being successfully passed as intended in 3x3 form.
function test
ctrue=eye(3);
xdata=rand(3);
ydata=F(ctrue,xdata);
c=lsqcurvefit(@F,zeros(3),xdata,ydata);
function out=F(c,xd)
assert( isequal(size(c),[3,3]) , ...
['c is expected to be 3x3, but it is ',...
num2str(size(c,1)),'x' num2str(size(c,2)) ])
out=xd*c;
Alan Weiss
Alan Weiss le 6 Mai 2021
Both documentation sections are correct, but I can now see that the section on linear indices is not helpful. What happens is that, internally, solvers use linear indices for computing values, but for nonlinear objective and constraint functions the arguments are reshaped back to the x0 shape when used.
I will update the doc.
FYI, linear indices are crucial for linear constraint matrices A and Aeq, because for those arguments the x argument is reshaped to a column vector no matter the shape of x0.
Alan Weiss
MATLAB mathematical toolbox documentation

Connectez-vous pour commenter.

Réponse acceptée

Matt J
Matt J le 15 Oct 2018
Modifié(e) : Matt J le 15 Oct 2018
After a bit of investigation, I think I've found where the problem is coming from and now that I understand it better, I'm pretty convinced it's a coding bug.
The problem occurs when one of the input upper/lower bounds pairs are equal, lb(i)=ub(i), meaning x(i) is known a priori. To handle this, lsqcurvefit tries to sift out those variables using the function snlsFixedVar, so that the optimization can be done in terms of the free variables only.
function [xcurr, fvec, LAMBDA, JACOB, EXITFLAG, OUTPUT, msgData] = ...
snlsFixedVar(funfcn, xstart, l, u, verb, options, defaultopt, ...
fval, JACval, caller, Jstr, computeLambda, mtxmpy, ...
detailedExitMsg, optionFeedback, finDiffFlags, varargin)
%
%SNLSFIXEDVAR Sparse nonlinear least squares solver with fixed variables
%
% Locate a local solution to the box-constrained nonlinear least-squares
% problem:
%
% min { ||F(x)||^2 : l <= x <= u }
%
% where F:R^n -> R^m, m > n, and || || is the 2-norm. Also, at least one
% element of x(i) is fixed, that is l(i) = x(i) = u(i).
%
% This function first removes the fixed variables from the problem. The
% reduced problem is passed to SNLS to be solved. Once the reduced
% problem solution has been found, the fixed variables are added back to
% the solution.
From comments in the first line of this function, it is clear the code intends to take control of the shape for the purpose of evaluating the user function:
% Save shape of xstart so we can reshape for user function and output
sizeX = size(xstart);
However, the saved shape sizeX is never passed to the reduced objective function, so this intent is never fulfilled.
% Restrict objective function to "free" variables.
funfcn = i_createObjectiveFcn(funfcn, l, idxFree, hasJacobMult);
Aside from this, I have to believe it is a bug if for no other reason than because the error only occurs when there is an lb(i)=ub(i) condition. In all other cases, the objective function appears to receive input in the shape of the initializing array, x0, consistent with existing documentation.
  5 commentaires
dong
dong le 21 Mai 2021
Bingo,the bug has been corrected in R2021a.Thank you very much.
Matt J
Matt J le 21 Mai 2021

Connectez-vous pour commenter.

Plus de réponses (1)

Alan Weiss
Alan Weiss le 11 Oct 2018
It is possible that the behavior of solvers is inconsistent, so when the vector orientation matters, I suggest that you be proactive and force the dimensions you like. For example,
function [out,Jac]=F(c,xd)
c = c(:); % for column c
c = c(:).'; % for row c
c = reshape(c,3,1); % another possibility
Alan Weiss
MATLAB mathematical toolbox documentation
  7 commentaires
Bruno Luong
Bruno Luong le 27 Avr 2021
Modifié(e) : Bruno Luong le 27 Avr 2021
You can do like this (I use Matt's example)
ctrue=[1;2;3];
xdata=rand(3);
ydata=F(ctrue,xdata);
lb=-inf(3,1);
ub=+inf(3,1);
lb(1)=1; ub(1)=1;
opts=optimoptions(@lsqcurvefit, 'SpecifyObjectiveGradient',true);
% This is original code, that throw error
%c=lsqcurvefit(@F,[0;0;0],xdata,ydata,lb,ub,opts);
% Use a wrapper
c=lsqcurvefit(@(varargin) Fexpand(lb < ub, varargin{:}), ...
[0;0;0],xdata,ydata,lb,ub,opts);
% Wrarpper to expand back decision variables
function varargout = Fexpand(b, varargin)
c = varargin{1};
try % newer MATLAB has fix the bug
c(b) = c;
end
varargout = cell(1,nargout);
[varargout{:}] = F(c, varargin{2:end}); % <- Call original model
end
% This is the original model, intended to used with lsqcurvefit
function [out,Jac]=F(c,xd)
out=xd*c;
Jac=xd;
end
dong
dong le 6 Mai 2021
Thank you very much!
It is appreciate that you offer me the function Fexpand. it is useful.
% Wrarpper to expand back decision variables
function varargout = Fexpand(b, varargin)
c = varargin{1};
try % newer MATLAB has fix the bug
c(b) = c;
end
varargout = cell(1,nargout);
[varargout{:}] = F(c, varargin{2:end}); % <- Call original model
end
Though I understand it with a little bit difficult, it successfully solves the problems I have encountered.
But I had a new problem.
What does this line codes mean below?
@(varargin) Fexpand(lb < ub, varargin{:})
and if the original model “F” return a function handle,how can I use the function of Fexpand?
I'm so depressed that I don't know how to solve the problem. Hope to get your help,thanks.
email:lidong@nim.ac.cn

Connectez-vous pour commenter.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by