function [x,OPTIONS] = fminu(FUN,x,OPTIONS,GRADFUN,varargin) %FMINU Finds the minimum of a function of several variables. % FMINU has been replaced with FMINUNC. FMINU currently works but % will be removed in the future. Use FMINUNC instead. % % X=FMINU('FUN',X0) starts at the matrix X0 and finds a minimum to the % function which is described in FUN (usually an M-file: FUN.M). % The function 'FUN' should return a scalar function value: F=FUN(X). % % X=FMINU('FUN',X0,OPTIONS) allows a vector of optional parameters to % be defined. OPTIONS(1) controls how much display output is given; set % to 1 for a tabular display of results, (default is no display: 0). % OPTIONS(2) is a measure of the precision required for the values of % X at the solution. OPTIONS(3) is a measure of the precision % required of the objective function at the solution. % For more information type HELP FOPTIONS. % % X=FMINU('FUN',X0,OPTIONS,'GRADFUN') enables a function'GRADFUN' % to be entered which returns the partial derivatives of the function, % df/dX, at the point X: gf = GRADFUN(X). % % X=FMINU('FUN',X0,OPTIONS,'GRADFUN',P1,P2,...) passes the problem- % dependent parameters P1,P2,... directly to the functions FUN % and GRADFUN: FUN(X,P1,P2,...) and GRADFUN(X,P1,P2,...). Pass % empty matrices for OPTIONS, and 'GRADFUN' to use the default % values. % % [X,OPTIONS]=FMINU('FUN',X0,...) returns the parameters used in the % optimization method. For example, options(10) contains the number % of function evaluations used. % % The default algorithm is the BFGS Quasi-Newton method with a % mixed quadratic and cubic line search procedure. % Copyright (c) 1990-98 by The MathWorks, Inc. % $Revision: 1.28 $ $Date: 1998/08/31 22:29:16 $ % Andy Grace 7-9-90. % ------------Initialization---------------- XOUT=x(:); nvars=length(XOUT); if nargin < 2, error('fminu requires two input arguments');end if nargin < 3, OPTIONS=[]; end if nargin < 4, GRADFUN=[]; end % Convert to inline function as needed. if ~isempty(FUN) [funfcn, msg] = fcnchk(FUN,length(varargin)); if ~isempty(msg) error(msg); end else error('FUN must be a function name or valid expression.') end if ~isempty(GRADFUN) [gradfcn, msg] = fcnchk(GRADFUN,length(varargin)); if ~isempty(msg) error(msg); end else gradfcn = []; end f = feval(funfcn,x,varargin{:}); n = length(XOUT); GRAD=zeros(nvars,1); OLDX=XOUT; MATX=zeros(3,1); MATL=[f;0;0]; OLDF=f; FIRSTF=f; [OLDX,OLDF,HESS,OPTIONS]=optint(XOUT,f,OPTIONS); CHG = 1e-7*abs(XOUT)+1e-7*ones(nvars,1); SD = zeros(nvars,1); diff = zeros(nvars,1); PCNT = 0; how = ''; OPTIONS(10)=2; % Function evaluation count (add 1 for last evaluation) status =-1; while status ~= 1 % Work Out Gradients if isempty(gradfcn) | OPTIONS(9) OLDF=f; % Finite difference perturbation levels % First check perturbation level is not less than search direction. f = find(10*abs(CHG)>abs(SD)); CHG(f) = -0.1*SD(f); % Ensure within user-defined limits CHG = sign(CHG+eps).*min(max(abs(CHG),OPTIONS(16)),OPTIONS(17)); for gcnt=1:nvars XOUT(gcnt,1)=XOUT(gcnt)+CHG(gcnt); x(:) = XOUT; f = feval(funfcn,x,varargin{:}); GRAD(gcnt)=(f-OLDF)/(CHG(gcnt)); if f < OLDF OLDF=f; else XOUT(gcnt)=XOUT(gcnt)-CHG(gcnt); end end % Try to set difference to 1e-8 for next iteration % Add eps for machines that can't handle divide by zero. CHG = 1e-8./(GRAD + eps); f = OLDF; OPTIONS(10)=OPTIONS(10)+nvars; % Gradient check if OPTIONS(9) == 1 GRADFD = GRAD; x(:)=XOUT; GRAD(:) = feval(gradfcn,x,varargin{:}); if isa(gradfcn,'inline') graderr(GRADFD, GRAD, formula(gradfcn)); else graderr(GRADFD, GRAD, gradfcn); end OPTIONS(9) = 0; end else OPTIONS(11)=OPTIONS(11)+1; x(:)=XOUT; GRAD(:) = feval(gradfcn,x,varargin{:}); end %---------------Initialization of Search Direction------------------ if status == -1 SD=-GRAD; FIRSTF=f; OLDG=GRAD; GDOLD=GRAD'*SD; % For initial step-size guess assume the minimum is at zero. OPTIONS(18) = max(0.001, min([1,2*abs(f/GDOLD)])); if OPTIONS(1)>0 disp([sprintf('%5.0f %12.6g %12.6g ',OPTIONS(10),f,OPTIONS(18)),sprintf('%12.3g ',GDOLD)]); end XOUT=XOUT+OPTIONS(18)*SD; status=4; if OPTIONS(7)==0; PCNT=1; end else %-------------Direction Update------------------ gdnew=GRAD'*SD; if OPTIONS(1)>0, num=[sprintf('%5.0f %12.6g %12.6g ',OPTIONS(10),f,OPTIONS(18)),sprintf('%12.3g ',gdnew)]; end if (gdnew>0 & f>FIRSTF)|~finite(f) % Case 1: New function is bigger than last and gradient w.r.t. SD -ve % ...interpolate. how='inter'; [stepsize]=cubici1(f,FIRSTF,gdnew,GDOLD,OPTIONS(18)); if stepsize<0|isnan(stepsize), stepsize=OPTIONS(18)/2; how='C1f '; end if OPTIONS(18)<0.1&OPTIONS(6)==0 if stepsize*norm(SD)1e-20 % Case 2: New function less than old fun. and OK for updating HESS % .... update and calculate new direction. how=''; if gdnew<0 how='incstep'; if newstep0 if OPTIONS(18)>0.9 how='int_st'; OPTIONS(18)=min([1,abs(newstep)]); end end %if gdnew [HESS,SD]=updhess(XOUT,OLDX,GRAD,OLDG,HESS,OPTIONS); gdnew=GRAD'*SD; OLDX=XOUT; status=4; % Save Variables for next update FIRSTF=f; OLDG=GRAD; GDOLD=gdnew; % If mixed interpolation set PCNT if OPTIONS(7)==0, PCNT=1; MATX=zeros(3,1); MATL(1)=f; end elseif gdnew>0 %sk<=0 % Case 3: No good for updating HESSIAN .. interpolate or halve step length. how='inter_st'; if OPTIONS(18)>0.01 OPTIONS(18)=0.9*newstep; XOUT=OLDX; end if OPTIONS(18)>1, OPTIONS(18)=1; end else % Increase step, replace starting point OPTIONS(18)=max([min([newstep-OPTIONS(18),3]),0.5*OPTIONS(18)]); how='incst2'; OLDX=XOUT; FIRSTF=f; OLDG=GRAD; GDOLD=GRAD'*SD; OLDX=XOUT; end % if sk> % Case 4: New function bigger than old but gradient in on % ...reduce step length. else %gdnew<0 & F>FIRSTF if gdnew<0&f>FIRSTF how='red_step'; if norm(GRAD-OLDG)<1e-10; HESS=eye(nvars); end if abs(OPTIONS(18))0 end % if (gdnew>0 & F>FIRSTF)|~finite(F) XOUT=XOUT+OPTIONS(18)*SD; if isinf(OPTIONS(1)) disp([num,how]) elseif OPTIONS(1)>0 disp(num) end end %----------End of Direction Update------------------- % Check Termination if max(abs(SD))<2*OPTIONS(2) & (-GRAD'*SD) < 2*OPTIONS(3) if OPTIONS(1) > 0 disp('Optimization Terminated Successfully') disp(' Search direction less than 2*options(2)') disp(' Gradient in the search direction less than 2*options(3)') disp([' NUMBER OF FUNCTION EVALUATIONS=', int2str(OPTIONS(10))]); end status=1; elseif OPTIONS(10)>OPTIONS(14) if OPTIONS(1) >= 0 disp('Maximum number of function evaluations exceeded;') disp(' increase options(14).') end status=1; else % Line search using mixed polynomial interpolation and extrapolation. if PCNT~=0 while PCNT > 0 & OPTIONS(10) <= OPTIONS(14) x(:) = XOUT; f = feval(funfcn,x,varargin{:}); OPTIONS(10)=OPTIONS(10)+1; [PCNT,MATL,MATX,steplen,f, how]=searchq(PCNT,f,OLDX,MATL,MATX,SD,GDOLD,OPTIONS(18), how); OPTIONS(18)=steplen; XOUT=OLDX+steplen*SD; end if OPTIONS(10)>OPTIONS(14) if OPTIONS(1) >= 0 disp('Maximum number of function evaluations exceeded;') disp(' increase options(14).') end status=1; end else x(:)=XOUT; f = feval(funfcn,x,varargin{:}); OPTIONS(10)=OPTIONS(10)+1; end end end x(:)=XOUT; f = feval(funfcn,x,varargin{:}); if f > FIRSTF OPTIONS(8) = FIRSTF; x(:)=OLDX; else OPTIONS(8) = f; end