Should lsqcurvefit reshape the initializing parameter vector?
Show older comments
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 Comments
Bruno Luong
on 11 Oct 2018
In the doc it witten "If the user-defined values for x and F are arrays, they are converted to vectors using linear indexing (see Array Indexing (MATLAB))."
So obviously the vector conversion is under lsqcurvefit control, and it obviously prefers a row-vector.
Matt J
on 11 Oct 2018
Bruno Luong
on 11 Oct 2018
Edited: Bruno Luong
on 11 Oct 2018
R2018b
>> doc lsqcurvefit
In the part 'Input Arguments fun — Function you want to fit"
10 lines down
Not it's not a BUG as I understood, that means user can pass X0 as matrix; but lsqnonlin converts it to vector. Same for F.
Alan Weiss
on 6 May 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
Accepted Answer
More Answers (1)
Alan Weiss
on 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 Comments
Alan Weiss
on 11 Oct 2018
Yes, I'll have to look at this again. When I wrote that documentation, I was thinking only of fmincon and fminunc, which do behave that way. But for least-squares solvers, well, I wasn't thinking of them, and you have discovered that they don't behave the same way, which is why I put the sheepish comment "It is possible that the behavior of solvers is inconsistent..."
Alan Weiss
MATLAB mathematical toolbox documentation
Bruno Luong
on 11 Oct 2018
Conclusion: it's a big mess. Just take control over the shape and fo not rely on MATLAB or the doc.
dong
on 27 Apr 2021
How to deal with the solver of lsqcurvefit when there is an lb(i)=ub(i) condition.
issure:
when there is an lb(i)=ub(i) condition is the xstart, the function of snlsFixedVar first removes the fixed variables from the problem, it means the size of xstart is changed,as a results, the function of funfcn cannot index the correct parameter form the xstart.
Bruno Luong
on 27 Apr 2021
Edited: Bruno Luong
on 27 Apr 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
on 6 May 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
Categories
Find more on Choose a Solver in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!