Mercurial > octave
changeset 20695:6faaab833605
fminunc.m: Clean up function to meet Octave coding standards.
* fminunc.m: Rename xsiz variable to xsz. Use double quotes for strings.
Use in-place accumulation operator +=1 instead of ++ for performance.
Use '__' prefix and postfix for internal functions. Use two spaces between
end of sentence period and start of next sentence. Only calculate third
output argument if requested.
author | Rik <rik@octave.org> |
---|---|
date | Wed, 11 Nov 2015 16:58:18 -0800 |
parents | a7dbc4fc3732 |
children | 0dfeb5c82750 |
files | scripts/optimization/fminunc.m |
diffstat | 1 files changed, 40 insertions(+), 38 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/optimization/fminunc.m Mon Feb 03 17:25:32 2014 +0200 +++ b/scripts/optimization/fminunc.m Wed Nov 11 16:58:18 2015 -0800 @@ -41,7 +41,7 @@ ## @qcode{"AutoScaling"}. ## ## If @qcode{"GradObj"} is @qcode{"on"}, it specifies that @var{fcn}, when -## called with 2 output arguments, also returns the Jacobian matrix of partial +## called with two output arguments, also returns the Jacobian matrix of partial ## first derivatives at the requested point. @code{TolX} specifies the ## termination tolerance for the unknown variables @var{x}, while @code{TolFun} ## is a tolerance for the objective function value @var{fval}. The default is @@ -80,8 +80,8 @@ ## (@var{output}), the output gradient (@var{grad}) at the solution @var{x}, ## and approximate Hessian (@var{hess}) at the solution @var{x}. ## -## Application Notes: If have only a single nonlinear equation of one variable -## then using @code{fminbnd} is usually a better choice. +## Application Notes: If the objective function is a single nonlinear equation +## of one variable then using @code{fminbnd} is usually a better choice. ## ## The algorithm used by @code{fminsearch} is a gradient search which depends ## on the objective function being differentiable. If the function has @@ -96,7 +96,7 @@ function [x, fval, info, output, grad, hess] = fminunc (fcn, x0, options = struct ()) ## Get default options if requested. - if (nargin == 1 && ischar (fcn) && strcmp (fcn, 'defaults')) + if (nargin == 1 && strcmp (fcn, "defaults")) x = optimset ("MaxIter", 400, "MaxFunEvals", Inf, "GradObj", "off", "TolX", 1e-7, "TolFun", 1e-7, "OutputFcn", [], "FunValCheck", "off", @@ -113,7 +113,7 @@ fcn = str2func (fcn, "global"); endif - xsiz = size (x0); + xsz = size (x0); n = numel (x0); has_grad = strcmpi (optimget (options, "GradObj", "off"), "on"); @@ -122,8 +122,8 @@ maxfev = optimget (options, "MaxFunEvals", Inf); outfcn = optimget (options, "OutputFcn"); - ## Get scaling matrix using the TypicalX option. If set to "auto", the - ## scaling matrix is estimated using the jacobian. + ## Get scaling matrix using the TypicalX option. If set to "auto", the + ## scaling matrix is estimated using the Jacobian. typicalx = optimget (options, "TypicalX"); if (isempty (typicalx)) typicalx = ones (n, 1); @@ -140,7 +140,7 @@ fcn = @(x) guarded_eval (fcn, x); endif - ## These defaults are rather stringent. I think that normally, user + ## These defaults are rather stringent. I think that normally, user ## prefers accuracy to performance. macheps = eps (class (x0)); @@ -159,7 +159,7 @@ info = 0; ## Initial evaluation. - fval = fcn (reshape (x, xsiz)); + fval = fcn (reshape (x, xsz)); n = length (x); if (! isempty (outfcn)) @@ -167,7 +167,7 @@ optimvalues.funccount = nfev; optimvalues.fval = fval; optimvalues.searchdirection = zeros (n, 1); - state = 'init'; + state = "init"; stop = outfcn (x, optimvalues, state); if (stop) info = -1; @@ -187,11 +187,11 @@ ## Calculate function value and gradient (possibly via FD). if (has_grad) - [fval, grad] = fcn (reshape (x, xsiz)); + [fval, grad] = fcn (reshape (x, xsz)); grad = grad(:); - nfev ++; + nfev += 1; else - grad = __fdjac__ (fcn, reshape (x, xsiz), fval, typicalx, cdif)(:); + grad = __fdjac__ (fcn, reshape (x, xsz), fval, typicalx, cdif)(:); nfev += (1 + cdif) * length (x); endif @@ -202,11 +202,11 @@ ## Use the damped BFGS formula. y = grad - grad0; sBs = sumsq (w); - Bs = hesr'*w; - sy = y'*s; + Bs = hesr' * w; + sy = y' * s; theta = 0.8 / max (1 - sy / sBs, 0.8); r = theta * y + (1-theta) * Bs; - hesr = cholupdate (hesr, r / sqrt (s'*r), "+"); + hesr = cholupdate (hesr, r / sqrt (s' * r), "+"); [hesr, info] = cholupdate (hesr, Bs / sqrt (sBs), "-"); if (info) hesr = eye (n); @@ -214,8 +214,8 @@ endif if (autoscale) - ## Second derivatives approximate the hessian. - d2f = norm (hesr, 'columns').'; + ## Second derivatives approximate the Hessian. + d2f = norm (hesr, "columns").'; if (niter == 1) dg = d2f; else @@ -251,8 +251,8 @@ delta = min (delta, sn); endif - fval1 = fcn (reshape (x + s, xsiz)) (:); - nfev ++; + fval1 = fcn (reshape (x + s, xsz))(:); + nfev += 1; if (fval1 < fval) ## Scaled actual reduction. @@ -261,7 +261,7 @@ actred = -1; endif - w = hesr*s; + w = hesr * s; ## Scaled predicted reduction, and ratio. t = 1/2 * sumsq (w) + grad'*s; if (t < 0) @@ -276,7 +276,7 @@ if (ratio < min (max (0.1, 0.8*lastratio), 0.9)) delta *= decfac; decfac ^= 1.4142; - if (delta <= 1e1*macheps*xn) + if (delta <= 10*macheps*xn) ## Trust region became uselessly small. info = -3; break; @@ -300,7 +300,7 @@ suc = true; endif - niter ++; + niter += 1; ## FIXME: should outputfcn be called only after a successful iteration? if (! isempty (outfcn)) @@ -308,7 +308,7 @@ optimvalues.funccount = nfev; optimvalues.fval = fval; optimvalues.searchdirection = s; - state = 'iter'; + state = "iter"; stop = outfcn (x, optimvalues, state); if (stop) info = -1; @@ -316,18 +316,18 @@ endif endif - ## Tests for termination conditions. A mysterious place, anything + ## Tests for termination conditions. A mysterious place, anything ## can happen if you change something here... ## The rule of thumb (which I'm not sure M*b is quite following) ## is that for a tolerance that depends on scaling, only 0 makes - ## sense as a default value. But 0 usually means uselessly long + ## sense as a default value. But 0 usually means uselessly long ## iterations, so we need scaling-independent tolerances wherever ## possible. ## The following tests done only after successful step. if (ratio >= 1e-4) - ## This one is classic. Note that we use scaled variables again, + ## This one is classic. Note that we use scaled variables again, ## but compare to scaled step, so nothing bad. if (sn <= tolx*xn) info = 2; @@ -340,14 +340,14 @@ endwhile endwhile - ## When info != 1, recalculate the gradient and hessian using the final x. + ## When info != 1, recalculate the gradient and Hessian using the final x. if (nargout > 4 && (info == -1 || info == 2 || info == 3)) grad0 = grad; if (has_grad) - [fval, grad] = fcn (reshape (x, xsiz)); + [fval, grad] = fcn (reshape (x, xsz)); grad = grad(:); else - grad = __fdjac__ (fcn, reshape (x, xsiz), fval, typicalx, cdif)(:); + grad = __fdjac__ (fcn, reshape (x, xsz), fval, typicalx, cdif)(:); endif if (nargout > 5) @@ -362,15 +362,17 @@ hesr = cholupdate (hesr, Bs / sqrt (sBs), "-"); endif ## Return the gradient in the same shape as x - grad = reshape (grad, xsiz); + grad = reshape (grad, xsz); endif ## Restore original shapes. - x = reshape (x, xsiz); + x = reshape (x, xsz); - output.iterations = niter; - output.successful = nsuciter; - output.funcCount = nfev; + if (nargout > 3) + output.iterations = niter; + output.successful = nsuciter; + output.funcCount = nfev; + endif if (nargout > 5) hess = hesr'*hesr; @@ -397,19 +399,19 @@ endfunction -%!function f = __rosenb (x) +%!function f = __rosenb__ (x) %! n = length (x); %! f = sumsq (1 - x(1:n-1)) + 100 * sumsq (x(2:n) - x(1:n-1).^2); %!endfunction %! %!test -%! [x, fval, info, out] = fminunc (@__rosenb, [5, -5]); +%! [x, fval, info, out] = fminunc (@__rosenb__, [5, -5]); %! tol = 2e-5; %! assert (info > 0); %! assert (x, ones (1, 2), tol); %! assert (fval, 0, tol); %!test -%! [x, fval, info, out] = fminunc (@__rosenb, zeros (1, 4)); +%! [x, fval, info, out] = fminunc (@__rosenb__, zeros (1, 4)); %! tol = 2e-5; %! assert (info > 0); %! assert (x, ones (1, 4), tol);