function [ x , status ] = UNM( f , varargin ) %function [ x , status ] = UNM( f , x , eps , finf , MaxFeval ) % % Apply the pure, non-globalised Newton Method for the minimization (or % maximization, since the method does not distinguish between the two) of % the provided one-dimensional (Univariate) function f, which must have % the following interface: % % [ v , varargout ] = f( x ) % % Input: % % - x is either a scalar real denoting the input of f(), or [] (empty). % % Output: % % - v (real, scalar): if x == [] this is the best known lower bound on % the global optimum of f() on the standard interval in which f() is % supposed to be minimised (see next). If x ~= [] then v = f(x). % % - g (real, either scalar or a [ 2 x 1 ] matrix denoting an interval) is % the first optional argument. This also depends on x. if x == [] then % g is a [ 2 x 1 ] matrix denoting the standard interval in which f() % is supposed to be minimised (into which v is the minimum). f() is % never called with x ~= []. % % - H (real, scalar) is the second optional argument. This must only be % specified if x ~= [], and it is the second derivative h = f''(x). % If no such information is available, the function throws error. % % IMPORTANT NOTE: the function requires f() to be able to provide both the % first and the second derivative. % % The other [optional] input parameters: % % - x: (either a real scalar or [], default []): the starting point; if % x == [], the left extreme of default range point provided by f() is % used. % % - eps (real scalar, default value 1e-6): the accuracy in the stopping % criterion: the algorithm is stopped when a point is found such that % the absolute value of the derivative is less than or equal to eps. % % - finf (real scalar, default value 1e+8): since the non-globalised % Newton Method may diverge, a very rough divergence test is % implemented whereby if | f( x ) | >= finf then the algorithm is % stopped with an error condition. % % - MaxFeval (integer scalar, default value 30): the maximum number of % function evaluations (hence, iterations will be not more than % MaxFeval - 2 because at each iteration one function evaluation is % performed, except in the first one when two are). % % Output: % % - x (real scalar): the best solution found so far. % % - status (string): a string describing the status of the algorithm at % termination % % = 'optimal': the algorithm terminated having proven that x is a(n % approximately) optimal solution, i.e., the diameter of the % restricted range is less than or equal to delta. % % = 'stopped': the algorithm terminated having exhausted the maximum % number of iterations: x is the best solution found so far, but not % necessarily the optimal one % % = 'error': the algorithm found a numerical error that prevents it from % continuing optimization, such as finding f''( x ) very close to 0, % or it is found to be diverging (see finf above). % %{ ======================================= Author: Antonio Frangioni Date: 19-10-23 Version 0.21 Copyright Antonio Frangioni ======================================= %} Plotg = 3; % 0 = nothing is plotted % 1 = the function value / gap are plotted % 2 = the function and the second-order model are plotted % 3 = the function, the first-order model and the second-order model are % plotted (the first-order model has no role in the algorithm, but % this shows how much better the second-order model is than the % first-order one) Interactive = true; % if we pause at every iteration % reading and checking input- - - - - - - - - - - - - - - - - - - - - - - - % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if ~ isa( f , 'function_handle' ) error( 'f not a function' ); end [ fStar , range ] = f( [] ); if isempty( varargin ) || isempty( varargin{ 1 } ) x = range( 1 ); else x = varargin{ 1 }; if ~ isreal( x ) || ~ isscalar( x ) error( 'x not a real scakar' ); end end if length( varargin ) > 1 eps = varargin{ 2 }; if ~ isreal( eps ) || ~ isscalar( eps ) error( 'eps is not a real scalar' ); end else eps = 1e-6; end if length( varargin ) > 2 finf = varargin{ 3 }; if ~ isreal( finf ) || ~ isscalar( finf ) error( 'finf is not a real scalar' ); end if finf <= 0 error( 'finf must be in > 0' ); end else finf = 1e+8; end if length( varargin ) > 3 MaxFeval = round( varargin{ 4 } ); if ~ isscalar( MaxFeval ) error( 'MaxFeval is not an integer scalar' ); end else MaxFeval = 30; end % initializations - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - feval = 0; status = 'optimal'; fbest = Inf; if Plotg == 1 gap = []; end fprintf( 'Univariate Newton''s Method\n'); if fStar > - Inf fprintf( 'feval\trel gap\t\tx\t\tf(x)\t\tf''(x)\t\tf''''(x)\n'); else fprintf( 'feval\tfbest\t\tx\t\tf''(x)\t\tf''(x)\t\tf''''(x)\n'); end % main loop - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - while true % compute f( x ), f'( x ), f''( x ) - - - - - - - - - - - - - - - - - - [ fx , f1x , f2x ] = f( x ); feval = feval + 1; if fx < fbest fbest = fx; end if abs( f2x ) <= 1e-16 status = 'stopped'; fprintf( 'numerical issue: f''''(x) = %1.4e\n' , f2x ); break; end % main logic- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - xn = x - f1x / f2x; % output statistics - - - - - - - - - - - - - - - - - - - - - - - - - - if fStar > - Inf gapk = ( fx - fStar ) / max( [ abs( fStar ) 1 ] ); if Plotg == 1 gap( end + 1 ) = gapk; semilogy( gap , 'Color' , 'k' , 'LineWidth' , 2 ); xlim( [ 0 35 ] ); ylim( [ 1e-15 inf ] ); ax = gca; ax.FontSize = 16; ax.Position = [ 0.03 0.07 0.95 0.92 ]; ax.Toolbar.Visible = 'off'; end else gapk = fbest; end fprintf( '%4d\t%1.4e\t%1.8e\t%1.4e\t%1.4e\t%1.4e\n' , feval , ... gapk , x , fx , f1x , f2x ); if Plotg > 1 xm = min( [ x xn ] ) - abs( x - xn ) / 5; xp = max( [ x xn ] ) + abs( x - xn ) / 5; warning( 'off' , 'all' ); fplot( @(x) f( x ) , [ xm xp ] , 'Color' , 'k' , 'LineWidth' , 1 ); xlim( [ xm xp ] ); yticks( [] ); ax = gca; ax.FontSize = 16; ax.Toolbar.Visible = 'off'; hold on; if Plotg == 3 % first-order model is % f( y ) = f( x ) + f'( x )( y - x ) % = [ f( x ) - f'( x ) x ] % + f'( x ) y b = f1x; c = fx - f1x * x; fplot( @(x) b * x + c , [ xm xp ] , ... 'Color' , 'r' , 'LineWidth' , 1 ); end % second-order model is % f( y ) = f( x ) + f'( x )( y - x ) + f''( x )( y - x )^2 / 2 % = [ f( x ) - f'( x ) x + f''( x ) x^2 / 2 ] % + [ f'( x ) - f''( x ) x ] y % + f''( x )y^2 / 2 a = f2x / 2; b = f1x - f2x * x; c = fx - f1x * x + f2x * x^2 / 2; fplot( @(x) a * x^2 + b * x + c , [ xm xp ] , ... 'Color' , 'b' , 'LineWidth' , 1 ); if x < xn xticks( [ xm x xn xp ] ); xticklabels( { num2str( xm , '%1.1g' ) , 'x^k' , ... 'x^{k+1}' , num2str( xp , '%1.1g' ) } ); else xticks( [ xm xn x xp ] ); xticklabels( { num2str( xm , '%1.1g' ) , 'x^{k+1}' , ... 'x^k' , num2str( xp , '%1.1g' ) } ); end warning( 'on' , 'all' ); hold off; end % stopping criteria - - - - - - - - - - - - - - - - - - - - - - - - - - if abs( f1x ) <= eps break; end if feval > MaxFeval status = 'stopped'; break; end if abs( fx ) > finf status = 'error'; break; end if Interactive pause; end % iterate - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x = xn; end % end of main loop- - - - - - - - - - - - - - - - - - - - - - - - - - - - - % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - end % the end- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -