diff --git a/lsqnonlin.m b/lsqnonlin.m index 05e2068..fca0d06 100644 --- a/lsqnonlin.m +++ b/lsqnonlin.m @@ -71,10 +71,8 @@ ## iteration in the following fields: ## "iteration"- number of current iteration. ## "residual"- residuals. -## "fval"- value of the objective function. -## -## @code{FunValCheck} -## If "on", the output of user functions will be sanity-checked. Default: "off". +## @code{state} is the state of the algorithm: "init" at start, +## "iter" after each iteration and "done" at the end. ## ## @code{Display} ## String indicating the degree of verbosity. Default: "off". @@ -123,7 +121,7 @@ ## @var{options} then @var{fun} must return a second argument providing a user-sepcified Jacobian . ## @end table ## -## This function calls Octave's @code{nonlin_residmin} function internally. +## This function is a compatibility wrapper. It calls the more general @code{nonlin_residmin} function internally. ## @end deftypefn ## PKG_ADD: __all_opts__ ("lsqnonlin"); @@ -137,19 +135,18 @@ function varargout = lsqnonlin (varargin) TypicalX_default = 1; if (nargs == 1 && ischar (varargin{1}) && strcmp (varargin{1}, "defaults")) - varargout{1} = optimset ("FinDiffRelStep", [],... - "FinDiffType", "forward",... - "TypicalX", TypicalX_default,... - "TolFun", TolFun_default,... - "MaxIter", MaxIter_default,... - "Display", "off",... - "Jacobian", "off",... - "OutputFcn", {},... - "FunValCheck", "off"... + varargout{1} = optimset ("FinDiffRelStep", [], ... + "FinDiffType", "forward", ... + "TypicalX", TypicalX_default, ... + "TolFun", TolFun_default, ... + "MaxIter", MaxIter_default, ... + "Display", "off", ... + "Jacobian", "off", ... + "OutputFcn", {}, ... "Algorithm", "lm_svd_feasible"); return; endif - + if (nargs < 2 || nargs==3 || nargs > 5) print_usage (); endif @@ -157,23 +154,22 @@ function varargout = lsqnonlin (varargin) if (! isreal (varargin{2})) error ("Function does not accept complex inputs. Split into real and imaginary parts") endif - + modelfun = varargin{1}; out_args = nargout (); varargout = cell (1, out_args); in_args{1} = varargin{1}; in_args{2} = varargin{2}(:); - + if (nargs >= 4) - settings = struct (); ## bounds are specified in a different way for nonlin_residmin - settings = optimset (settings, "lbound", varargin{3}(:), + settings = optimset ("lbound", varargin{3}(:), "ubound", varargin{4}(:)); - if (nargs == 5) + if (nargs == 5) ## Jacobian function is specified in a different way for ## nonlin_residmin - if (strcmpi (optimget (varargin{5}, "Jacobian"), "on")) + if (strcmpi (optimget (varargin{5}, "Jacobian"), "on")) settings = optimset (settings, "dfdp", @(p) computeJacob (modelfun, p)); endif @@ -189,47 +185,45 @@ function varargout = lsqnonlin (varargin) error ("unknown value of option 'FinDiffType': %s", FinDiffType); endif - FinDiffRelStep = optimget (varargin{5}, "FinDiffRelStep", + FinDiffRelStep = optimget (varargin{5}, "FinDiffRelStep", FinDiffRelStep_default); TolFun = optimget (varargin{5}, "TolFun", TolFun_default); MaxIter = optimget (varargin{5}, "MaxIter", MaxIter_default); TypicalX = optimget (varargin{5}, "TypicalX", TypicalX_default); - FunValCheck = optimget (varargin{5}, "FunValCheck", "off"); Display = optimget (varargin{5}, "Display", "off"); - OutputFcn = optimget (varargin{5}, "OutputFcn", {}); - + if (! iscell (OutputFcn = optimget (varargin{5}, "OutputFcn", {}))) + OutputFcn = {OutputFcn}; + endif + if (! strcmpi (Display, "off")) if (strcmpi (Display, "iter-detailed") || strcmpi (Display, "final")... || strcmpi (Display, "final-detailed")) - Display = "iter"; + Display = "iter"; endif endif - - if (! isempty (OutputFcn)) - ## Octave's user_interaction must return an additional informational - ## output argument - user_interaction = compute_user_interaction (OutputFcn); - endif - + + ## 'user_interaction' must return an additional informational + ## output argument + user_interaction = compute_user_interaction (OutputFcn); + settings = optimset (settings, "FinDiffRelStep", FinDiffRelStep, "FinDiffType", FinDiffType, "TolFun", TolFun, "TypicalX", TypicalX, "MaxIter", MaxIter, - "FunValCheck", FunValCheck, "Display", Display, "user_interaction", user_interaction); endif - in_args{3} = settings; + in_args{3} = settings; endif - n_out = max (1, min (out_args, 5)); - + n_out = max (1, min (out_args, 5)); + if (n_out > 2) n_out--; endif - + residmin_out = cell (1, n_out); [residmin_out{:}] = nonlin_residmin (in_args{:}); @@ -239,11 +233,11 @@ function varargout = lsqnonlin (varargin) if (out_args >= 2) varargout{2} = sumsq (residmin_out{2}); endif - + if (out_args >= 3) varargout{3} = residmin_out{2}; endif - + if (out_args >= 4) varargout{4} = residmin_out{3}; endif @@ -251,18 +245,22 @@ function varargout = lsqnonlin (varargin) if (out_args >= 5) outp = residmin_out{4}; outp = rmfield (outp, "lambda"); + if (isfield (outp, "user_interaction")) + outp = rmfield (outp, "user_interaction"); + endif varargout{5} = outp; endif - + if (out_args >= 6) - varargout{6} = residmin_out{4}.lambda; + varargout{6}.lower = residmin_out{4}.lambda.lower; + varargout{6}.upper = residmin_out{4}.lambda.upper; endif - + if (out_args >= 7) info = residmin_stat (modelfun, residmin_out{1}, optimset (settings, "ret_dfdp", true)); varargout{7} = info.dfdp; endif - + endfunction function Jacob = computeJacob (modelfun, p) @@ -274,7 +272,7 @@ function user_interaction = compute_user_interaction (OutputFcn) user_interaction = cell (1, n); for i = 1:n; user_interaction{i} = @(p, vals, state) deal (OutputFcn{i} (p, vals, state), {} ) ; - endfor + endfor endfunction %!test @@ -293,16 +291,16 @@ endfunction %! %% model function: %! function [F,J] = myfun (p, x, y) %! F = p(1) * exp (-p(2) * x) - y; -%! if nargout > 1 -%! J =[exp (- p(2) * x), - p(1) * x .* exp (- p(2) * x)]; +%! if nargout > 1 +%! J = [exp(- p(2) * x), - p(1) * x .* exp(- p(2) * x)]; %! endif %! endfunction -%! +%! %! %% independents -%! x = [1:10:100]'; +%! x = [1:10:100]'; %! %% observed data %! y =[9.2160e-001, 3.3170e-001, 8.9789e-002, 2.8480e-002, 2.6055e-002,... -%! 8.3641e-003, 4.2362e-003, 3.1693e-003, 1.4739e-004, 2.9406e-004]'; +%! 8.3641e-003, 4.2362e-003, 3.1693e-003, 1.4739e-004, 2.9406e-004]'; %! %% initial values: %! p0=[0.8; 0.05]; %! %% bounds @@ -310,5 +308,5 @@ endfunction %! %% Jacobian setting %! opts = optimset ("Jacobian", "on") %! -%! [c, resnorm, residual, flag, output, lambda, jacob] = ... -%! lsqnonlin(@(p) myfun(p, x, y), p0, lb, ub, opts) \ No newline at end of file +%! [c, resnorm, residual, flag, output, lambda, jacob] = ... +%! lsqnonlin(@(p) myfun(p, x, y), p0, lb, ub, opts)