Should lsqcurvefit reshape the initializing parameter vector?

조회 수: 4 (최근 30일)
Matt J
Matt J 2018년 10월 10일
댓글: Matt J 2021년 5월 21일
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
Matt J
Matt J 2018년 10월 11일
편집: Matt J 2018년 10월 11일
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 2021년 5월 6일
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

댓글을 달려면 로그인하십시오.

채택된 답변

Matt J
Matt J 2018년 10월 15일
편집: Matt J 2018년 10월 15일
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
dong
dong 2021년 5월 21일
Bingo,the bug has been corrected in R2021a.Thank you very much.

댓글을 달려면 로그인하십시오.

추가 답변 (1개)

Alan Weiss
Alan Weiss 2018년 10월 11일
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
Bruno Luong
Bruno Luong 2021년 4월 27일
편집: Bruno Luong 2021년 4월 27일
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 2021년 5월 6일
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

댓글을 달려면 로그인하십시오.

Community Treasure Hunt

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

Start Hunting!

Translated by