function retval = wolfelinesrch(fngrad,fn,x,p) % usage: alpha = wolfelinesrch(fngrad,fn,x,p) % description: returns the value alpha in the interval % [a,b] at which strong Wolfe conditions are satisfied. % Passed parameters: % fngrad: gradient function name % fn: function name % x: starting point % p: search direction % shorthand: phi(alpha) = f(x + alpha*p) so that % phip(alpha) = gradf(x+alpha*p)'*p. % global variables: global parms; % local variables: % rho: growth factor % c1: Wolfe condition 1 parameter % c2: Wolfe condition 2 parameter % alpha1: initial step length % alphamax: maximum allowable step size % alphaold,alphanew: successive approxns to alpha % phi0,phip0: phi(0), phip(0) % phiold, phinew: phi(alpha*) % phipold,phipnew: phip(alpha*) % psi1,psi2: convenient constants % doneflag: done flag % no bulletproofing here rho = parms.wolferho; c1 = parms.c1; c2 = parms.c2; alpha1 = parms.alpha1; alphamax = parms.alphamax; alphaold = 0; alphanew = alpha1; phi0 = feval(fn,x); phip0 = feval(fngrad,x)'*p; psi1 = c1*phip0; psi2 = -c2*phip0; doneflag = 0; phinew = phi0; phipnew = phip0; while (~doneflag) phiold = phinew; phipold = phipnew; phinew = feval(fn,x+alphanew*p); phipnew = feval(fngrad,x+alphanew*p)'*p; % test if new phi value is above Wolfe1 line if (phinew > phi0 + alphanew*psi1) | ((phinew >= phiold) & (alphanew ~= alpha1)) retval = zoom(alphaold, alphanew, phi0, psi1, psi2, fn, fngrad, x, p); doneflag = 1; else if (abs(phipnew) <= psi2) % passes Wolfe2? retval = alphanew; doneflag = 1; else if (phipnew >= 0) % positive slope on right? retval = zoom(alphanew, alphaold, phi0, psi1, psi2, fn, fngrad, x, p); doneflag = 1; else alphaold = alphanew; alphanew = rho*alphanew; if (alphanew >= alphamax) | (alphanew <= 100*eps) retval = alphamax; doneflag = 1; end end end end end end % end this main function so that locals are hidden from function below % function alphaopt = zoom(alphalo, alphahi, phi0, psi1, psi2, fn, fngrad, x, p) % Passed parameters: % alphalo: alpha satisfying suff decrease and smallest fn value so far % alphahi: chosen so that phip(alphalo)*(alphahi-alphalo) < 0 % phi0: as in main function % psi1: as in main function % psi2: as in main function % fn: as in main function % fngrad: as in main function % x: as in main function % p: as in main function % local variables: % doneflag: done flag % philo,phihi,phitest: phi(*) % phiplo,phiphi,phiptest: phip(*) % alphatest,alphaopt: test and optimal values of alpha % Initialize doneflag = 0; while (~doneflag) philo = feval(fn,x+alphalo*p); phiplo = feval(fngrad,x+alphalo*p)'*p; phihi = feval(fn,x+alphahi*p); phiphi = feval(fngrad,x+alphahi*p)'*p; if (alphalo < alphahi) % must do cubicmin in right order alphatest = cubicmin(alphalo,alphahi, philo, phihi, phiplo, phiphi); else alphatest = cubicmin(alphahi, alphalo, phihi, philo, phiphi, phiplo); end if (alphatest == alphalo) || (alphatest == alphahi) % bad news..min not interior disp('Warning: numeric failure in line search'); alphaopt = alphahi; return; end phitest = feval(fn,x+alphatest*p); if ((phitest > phi0 + alphatest*psi1) | (phitest >= philo) ) alphahi = alphatest; else phiptest = feval(fngrad,x+alphatest*p)'*p; if (abs(phiptest) <= psi2) % pass Wolfe2? alphaopt = alphatest; doneflag = 1; else if (phiptest*(alphahi-alphalo) >= 0) % keep entry condition alphahi = alphalo; end alphalo = alphatest; end end end end