Mercurial > hg > octave-lyh
diff scripts/optimization/fsolve.m @ 8986:22c8272af34b
improvements to fsolve & family
author | Jaroslav Hajek <highegg@gmail.com> |
---|---|
date | Tue, 17 Mar 2009 08:49:08 +0100 |
parents | 20589a8f1a33 |
children | 315828058e0d |
line wrap: on
line diff
--- a/scripts/optimization/fsolve.m +++ b/scripts/optimization/fsolve.m @@ -72,10 +72,48 @@ ## @item -3 ## The trust region radius became excessively small. ## @end table -## +## ## Note: If you only have a single nonlinear equation of one variable, using ## @code{fzero} is usually a much better idea. ## @seealso{fzero, optimset} +## +## Note about user-supplied jacobians: +## As an inherent property of the algorithm, jacobian is always requested for a +## solution vector whose residual vector is already known, and it is the last +## accepted successful step. Often this will be one of the last two calls, but +## not always. If the savings by reusing intermediate results from residual +## calculation in jacobian calculation are significant, the best strategy is to +## employ OutputFcn: After a vector is evaluated for residuals, if OutputFcn is +## called with that vector, then the intermediate results should be saved for +## future jacobian evaluation, and should be kept until a jacobian evaluation +## is requested or until outputfcn is called with a different vector, in which +## case they should be dropped in favor of this most recent vector. A short +## example how this can be achieved follows: +## @example +## function [fvec, fjac] = my_optim_func (x, optimvalues, state) +## persistent sav = [], sav0 = []; +## if (nargin == 1) +## ## evaluation call +## if (nargout == 1) +## sav0.x = x; # mark saved vector +## ## calculate fvec, save results to sav0. +## elseif (nargout == 2) +## ## calculate fjac using sav. +## endif +## else +## ## outputfcn call. +## if (all (x == sav0.x)) +## sav = sav0; +## endif +## ## maybe output iteration status etc. +## endif +## endfunction +## +## ## .... +## +## fsolve (@my_optim_func, x0, optimset ("OutputFcn", @my_optim_func, @dots{})) +## @end example +### ## @end deftypefn ## PKG_ADD: __all_opts__ ("fsolve"); @@ -129,11 +167,34 @@ autodg = true; niter = 1; - nfev = 0; + nfev = 1; x = x0(:); info = 0; + ## Initial evaluation. + fvec = fcn (reshape (x, xsiz)); + fsiz = size (fvec); + fvec = fvec(:); + fn = norm (fvec); + m = length (fvec); + n = length (x); + + if (! isempty (outfcn)) + optimvalues.iter = niter; + optimvalues.funccount = nfev; + optimvalues.fval = fn; + optimvalues.searchdirection = zeros (n, 1); + state = 'init'; + stop = outfcn (x, optimvalues, state); + if (stop) + info = -1; + break; + endif + endif + + nsuciter = 0; + ## Outer loop. while (niter < maxiter && nfev < maxfev && ! info) @@ -145,16 +206,12 @@ if (issparse (fjac)) updating = false; endif + fvec = fvec(:); nfev ++; else - [fvec, fjac] = __fdjac__ (fcn, reshape (x, xsiz)); - nfev += 1 + length (x); + fjac = __fdjac__ (fcn, reshape (x, xsiz), fvec); + nfev += length (x); endif - fsiz = size (fvec); - fvec = fvec(:); - fn = norm (fvec); - m = length (fvec); - n = length (x); ## For square and overdetermined systems, we update a QR ## factorization of the jacobian to avoid solving a full system in each @@ -199,6 +256,7 @@ ## of course, how to define the above terms :) endif + lastratio = 0; nfail = 0; nsuc = 0; ## Inner loop. @@ -249,7 +307,7 @@ endif ## Update delta. - if (ratio < 0.1) + if (ratio < min(max(0.1, lastratio), 0.9)) nsuc = 0; nfail ++; delta *= 0.5; @@ -259,6 +317,7 @@ break; endif else + lastratio = ratio; nfail = 0; nsuc ++; if (abs (1-ratio) <= 0.1) @@ -274,6 +333,7 @@ xn = norm (dg .* x); fvec = fvec1; fn = fn1; + nsuciter ++; endif niter ++; @@ -321,7 +381,7 @@ endif ## Criterion for recalculating jacobian. - if (! updating || nfail == 2) + if (! updating || nfail == 2 || nsuciter < 2) break; endif @@ -347,6 +407,7 @@ fvec = reshape (fvec, fsiz); output.iterations = niter; + output.successful = nsuciter; output.funcCount = nfev; endfunction