function [stp, x, f, iter, iflag, usr_par] = lnsrch_bt( x, d, dg, f, stp, options, usr_par ) % % [stp, x, f, iter, iflag, usr_par] = lnsrch_bt( x, d, dg, f, stp, options, usr_par ) % % Use backtracking to find a step size stp > 0 such that % % f(x+stp*d) <= f(x) + ftol * stp* < gradf(x), d >, % % where gradf(x) is the gradient at x and d is a search direction. % % This function calls the following usr provided functions % function [fx] = f(x, usr_par) % function [usr_par] = xnew( x, iter, usr_par). % % This is the algorithm described in the book % Dennis and Schnabel "Numerical Methods for Nonlinear Equations % and Unconstrained Optimization", Prentice-Hall (1983), reprinted % by SIAM (1996), Section 6.3.2. % % Inputs % x current iterate % d search direction % dg < gradf(x), d > % f objective function value at x % stp initial step size % options line search parameters % option.iprint print if ~=0, default = 0 % option.fid file identifier, default = 1 % option.stpmin minimum step length, default = 1.e-8 % option.ftol ftol in sufficient decrease, default = 1.e-4 % if lnsrch_bt is called with options =[], then defauls % are used. % usr_par user parameters. These are never referenced % in this function, but are passed to the % user provided functions f and xnew. % % Outputs % stp final step size % x x + stp * d % f objective function at x+ stp * d % iter number of iterations in lnsrch_ds % (=number of fctn. evals. in lnsrch_ds) % iflag return flag % iflag = 0 line search was successful % iflag = 1 d is not a descent direction % iflag = 2 initial stp < 0 % iflag = 3 maximum number of LS % iterations exceeded % % usr_par user parameters. may be changed inside this function % through a call to the user provided function xnew. % % % Matthias Heinkenschloss % Department of Computational and Applied Mathematics % Rice University % June 6, 2008 %% set linear search parameters iprint = 0; fid = 1; stpmin = 1.e-8; ftol = 1.e-4; if( ~isempty(options) ) if( isfield(options,'iprint') ); iprint = options.iprint; end if( isfield(options,'fid') ); fid = options.fid; end if( isfield(options,'stpmin') ); stpmin = options.stpmin; end if( isfield(options,'ftol') ); ftol = options.ftol; end end %% check inputs if( dg >= 0 ) % d is not a descent direction iflag = 1; return end if( stp <= stpmin ) % initial step too small iflag = 2; return end %% if( iprint > 0 ) fprintf(fid,' lnsrch_bt with \n') fprintf(fid,' option.stpmin = %12.5e \n', stpmin) fprintf(fid,' option.ftol = %12.5e \n', ftol) fprintf(fid,' iter stepsize Obj_fctn required decrease \n'); end %% initialize iter = 0; stp_c = stp; f0 = f; x0 = x; fc = f; %% start linear search loop while (stp > stpmin) % trial iterate x = x0 + stp * d; % compute the function value at x+stp*d usr_par = xnew( x, iter, usr_par); f = fval( x, usr_par); % print iteration info if( iprint > 0 ) fprintf(fid, '%4d %12.5e %12.5e %12.5e \n', ... iter, stp, f, f0 + stp*ftol*dg ) end % check decrease condition and return if successful if( f < f0 + stp*ftol*dg ) iflag = 0; return end stp_p = stp_c; stp_c = stp; fp = fc; fc = f; % compute next step size stp if( iter == 0 ) % first backtrack: quadratic fit stp = - dg / ( 2 * (fc - f0 - dg) ); else % all subsequent backtracks: cubic fit t1 = fc - f0 - stp_c*dg; t2 = fp - f0 - stp_p*dg; t3 = 1 / (stp_c - stp_p); a = t3 * ( t1/(stp_c^2) - t2/(stp_p^2) ); b = t3 * ( t2*stp_c/(stp_p^2) - t1*stp_p/(stp_c^2) ); disc = b^2 - 3*a*dg; if( a ~= 0 ) % cubic has unique minimum stp = (-b + sqrt( disc ) ) / (3 * a ); else % cubic is a quadratic stp = -dg / ( 2 * b ); end end % saveguard the step size if( stp > 0.5*stp_c ); stp = 0.5*stp_c; end if( stp < stp_c/10 ); stp = stp_c/10; end iter = iter + 1; end %% stp < stpmin iflag = 3;