320 lines
8.1 KiB
Mathematica
320 lines
8.1 KiB
Mathematica
|
|
function [ x , status ] = GMQ( Q , q , varargin )
|
||
|
|
|
||
|
|
%function [ x , status ] = GMQ( Q , q , x , fStar , alpha , MaxIter , eps )
|
||
|
|
%
|
||
|
|
% Apply the Gradient Method (a.k.a., Steepest Descent algorithm) to the
|
||
|
|
% minimization of the quadratic function
|
||
|
|
%
|
||
|
|
% f( x ) = 1/2 x^T Q x + q x
|
||
|
|
%
|
||
|
|
% Input:
|
||
|
|
%
|
||
|
|
% - Q ([ n x n ] real symmetric matrix, not necessarily positive
|
||
|
|
% semidefinite): the quadratic part of f
|
||
|
|
%
|
||
|
|
% - q ([ n x 1 ] real column vector): the linear part of f
|
||
|
|
%
|
||
|
|
% - x ([ n x 1 ] real column vector or empty, optional): the point where to
|
||
|
|
% start the algorithm from; if not provided or empty, the all-0 n-vector
|
||
|
|
% is used
|
||
|
|
%
|
||
|
|
% - fStar (real scalar, optional, default value Inf): optimal value of f.
|
||
|
|
% if a non-Inf value is provided it is used to print out stasistics about
|
||
|
|
% the convergence speed of the algorithm
|
||
|
|
%
|
||
|
|
% - alpha (real scalar, optional, default value 0): if alpha > 0, then the
|
||
|
|
% fixed-stepsize version of the algorithm is run with alpha as the fixed
|
||
|
|
% stepsize, otherwise the standard exact line search is used
|
||
|
|
%
|
||
|
|
% - MaxIter (integer scalar, optional, default value 1000): the maximum
|
||
|
|
% number of iterations
|
||
|
|
%
|
||
|
|
% - eps (real scalar, optional, default value 1e-6): the accuracy in the
|
||
|
|
% stopping criterion: the algorithm is stopped when the norm of the
|
||
|
|
% gradient is less than or equal to eps
|
||
|
|
%
|
||
|
|
% Output:
|
||
|
|
%
|
||
|
|
% - x ([ n x 1 ] real column vector): either the best solution found so far
|
||
|
|
% (possibly the optimal one) or a direction proving the problem is
|
||
|
|
% unbounded below, depending on case
|
||
|
|
%
|
||
|
|
% - 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 norm of the gradient at x
|
||
|
|
% is less than the required threshold
|
||
|
|
%
|
||
|
|
% = 'unbounded': the algorithm terminated having proven that the problem
|
||
|
|
% is unbounded below: x contains a direction along which f is
|
||
|
|
% decreasing to - Inf, either because f is linear along x and the
|
||
|
|
% directional derivative is not zero, or because x is a direction with
|
||
|
|
% negative curvature
|
||
|
|
%
|
||
|
|
% = '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
|
||
|
|
%
|
||
|
|
%{
|
||
|
|
=======================================
|
||
|
|
Author: Antonio Frangioni
|
||
|
|
Date: 26-12-22
|
||
|
|
Version 0.2
|
||
|
|
Copyright Antonio Frangioni
|
||
|
|
=======================================
|
||
|
|
%}
|
||
|
|
|
||
|
|
Plotf = 2;
|
||
|
|
% 0 = nothing is plotted
|
||
|
|
% 1 = the function value / gap are plotted
|
||
|
|
% 2 = the level sets of f and the trajectory are plotted (when n = 2)
|
||
|
|
|
||
|
|
Interactive = true; % if we pause at every iteration
|
||
|
|
|
||
|
|
Streamlined = true; % if the streamlined version of the algorithm, with
|
||
|
|
% only one O( n^2 ) operation per iteration, is used
|
||
|
|
|
||
|
|
% reading and checking input- - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
|
||
|
|
if ~ isreal( Q )
|
||
|
|
error( 'Q not a real matrix' );
|
||
|
|
end
|
||
|
|
|
||
|
|
n = size( Q , 1 );
|
||
|
|
|
||
|
|
if n <= 1
|
||
|
|
error( 'Q is too small' );
|
||
|
|
end
|
||
|
|
|
||
|
|
if n ~= size( Q , 2 )
|
||
|
|
error( 'Q is not square' );
|
||
|
|
end
|
||
|
|
|
||
|
|
if ~ isreal( q )
|
||
|
|
error( 'q not a real vector' );
|
||
|
|
end
|
||
|
|
|
||
|
|
if size( q , 2 ) ~= 1
|
||
|
|
error( 'q is not a (column) vector' );
|
||
|
|
end
|
||
|
|
|
||
|
|
if size( q , 1 ) ~= n
|
||
|
|
error( 'q size does not match with Q' );
|
||
|
|
end
|
||
|
|
|
||
|
|
if isempty( varargin ) || isempty( varargin{ 1 } )
|
||
|
|
x = zeros( n , 1 );
|
||
|
|
else
|
||
|
|
x = varargin{ 1 };
|
||
|
|
|
||
|
|
if ~ isreal( x )
|
||
|
|
error( 'x not a real vector' );
|
||
|
|
end
|
||
|
|
|
||
|
|
if size( x , 2 ) ~= 1
|
||
|
|
error( 'x is not a (column) vector' );
|
||
|
|
end
|
||
|
|
|
||
|
|
if size( x , 1 ) ~= n
|
||
|
|
error( 'x size does not match with Q' );
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if length( varargin ) > 1
|
||
|
|
fStar = varargin{ 2 };
|
||
|
|
if ~ isreal( fStar ) || ~ isscalar( fStar )
|
||
|
|
error( 'fStar is not a real scalar' );
|
||
|
|
end
|
||
|
|
else
|
||
|
|
fStar = - Inf;
|
||
|
|
end
|
||
|
|
|
||
|
|
if length( varargin ) > 2
|
||
|
|
alpha = varargin{ 3 };
|
||
|
|
if ~ isreal( alpha ) || ~ isscalar( alpha )
|
||
|
|
error( 'alpha is not a real scalar' );
|
||
|
|
end
|
||
|
|
else
|
||
|
|
alpha = 0;
|
||
|
|
end
|
||
|
|
|
||
|
|
if length( varargin ) > 3
|
||
|
|
MaxIter = round( varargin{ 4 } );
|
||
|
|
if ~ isscalar( MaxIter )
|
||
|
|
error( 'MaxIter is not an integer scalar' );
|
||
|
|
end
|
||
|
|
if MaxIter < 1
|
||
|
|
error( 'MaxIter too small' );
|
||
|
|
end
|
||
|
|
else
|
||
|
|
MaxIter = 1000;
|
||
|
|
end
|
||
|
|
|
||
|
|
if length( varargin ) > 4
|
||
|
|
eps = varargin{ 5 };
|
||
|
|
if ~ isreal( eps ) || ~ isscalar( eps )
|
||
|
|
error( 'eps is not a real scalar' );
|
||
|
|
end
|
||
|
|
if eps < 0
|
||
|
|
error( 'eps can not be negative' );
|
||
|
|
end
|
||
|
|
else
|
||
|
|
eps = 1e-6;
|
||
|
|
end
|
||
|
|
|
||
|
|
% initializations - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
|
||
|
|
fprintf( 'Gradient method for quadratic functions ' );
|
||
|
|
if alpha == 0
|
||
|
|
fprintf( '(optimal stepsize)\n' );
|
||
|
|
else
|
||
|
|
fprintf( '(fixed stepsize)\n' );
|
||
|
|
end
|
||
|
|
fprintf( 'iter\tf(x)\t\t\t||g||');
|
||
|
|
if fStar > - Inf
|
||
|
|
fprintf( '\t\tgap\t\trate');
|
||
|
|
prevf = Inf;
|
||
|
|
end
|
||
|
|
if alpha == 0
|
||
|
|
fprintf( '\t\talpha' );
|
||
|
|
end
|
||
|
|
fprintf( '\n\n' );
|
||
|
|
|
||
|
|
i = 0;
|
||
|
|
|
||
|
|
if Plotf == 1
|
||
|
|
gap = [];
|
||
|
|
end
|
||
|
|
|
||
|
|
if Streamlined
|
||
|
|
g = Q * x + q;
|
||
|
|
end
|
||
|
|
|
||
|
|
% main loop - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
|
||
|
|
while true
|
||
|
|
% compute function value and gradient - - - - - - - - - - - - - - - - -
|
||
|
|
|
||
|
|
if ~ Streamlined
|
||
|
|
g = Q * x + q;
|
||
|
|
end
|
||
|
|
|
||
|
|
ng = norm( g );
|
||
|
|
f = ( g + q )' * x / 2; % 1/2 x^T Q x + q x = 1/2 ( x^T Q x + 2 q x )
|
||
|
|
% = 1/2 x^T ( Q x + q + q ) = 1/2 ( q + g ) x
|
||
|
|
i = i + 1;
|
||
|
|
|
||
|
|
% output statistics - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
|
||
|
|
fprintf( '%4d\t%1.8e\t\t%1.4e' , i , f , ng );
|
||
|
|
if fStar > - Inf
|
||
|
|
gapk = ( f - fStar ) / max( [ abs( fStar ) 1 ] );
|
||
|
|
|
||
|
|
fprintf( '\t%1.4e' , gapk );
|
||
|
|
if prevf < Inf
|
||
|
|
fprintf( '\t%1.4e' , ( f - fStar ) / ( prevf - fStar ) );
|
||
|
|
else
|
||
|
|
fprintf( '\t\t' );
|
||
|
|
end
|
||
|
|
prevf = f;
|
||
|
|
|
||
|
|
if Plotf == 1
|
||
|
|
gap( end + 1 ) = gapk;
|
||
|
|
semilogy( gap , 'Color' , 'k' , 'LineWidth' , 2 );
|
||
|
|
xlim( [ 0 MaxIter ] );
|
||
|
|
ylim( [ 1e-15 inf ] );
|
||
|
|
ax = gca;
|
||
|
|
ax.FontSize = 16;
|
||
|
|
ax.Position = [ 0.03 0.07 0.95 0.92 ];
|
||
|
|
ax.Toolbar.Visible = 'off';
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
% stopping criteria - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
if ng <= eps
|
||
|
|
status = 'optimal';
|
||
|
|
if alpha == 0
|
||
|
|
fprintf( '\n' );
|
||
|
|
end
|
||
|
|
break;
|
||
|
|
end
|
||
|
|
|
||
|
|
if i > MaxIter
|
||
|
|
status = 'stopped';
|
||
|
|
if alpha == 0
|
||
|
|
fprintf( '\n' );
|
||
|
|
end
|
||
|
|
break;
|
||
|
|
end
|
||
|
|
|
||
|
|
% compute step size - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
% meanwhile, check if f is unbounded below
|
||
|
|
% note that if alpha > 0 this is only used for the unboundedness check
|
||
|
|
% which is a bit of a waste, but there you go; anyway, in the
|
||
|
|
% streamlined version this only costs O( n )
|
||
|
|
|
||
|
|
if Streamlined
|
||
|
|
v = Q * g;
|
||
|
|
den = g' * v;
|
||
|
|
else
|
||
|
|
den = g' * Q * g;
|
||
|
|
end
|
||
|
|
|
||
|
|
if den <= 1e-14
|
||
|
|
% this is actually two different cases:
|
||
|
|
%
|
||
|
|
% - g' * Q * g = 0, i.e., f is linear along g, and since the
|
||
|
|
% gradient is not zero, it is unbounded below
|
||
|
|
%
|
||
|
|
% - g' * Q * g < 0, i.e., g is a direction of negative curvature for
|
||
|
|
% f, which is then necessarily unbounded below
|
||
|
|
%
|
||
|
|
if alpha == 0
|
||
|
|
fprintf( '\n' );
|
||
|
|
end
|
||
|
|
fprintf( 'g'' * Q * g = %1.4e ==> unbounded\n' , den );
|
||
|
|
status = 'unbounded';
|
||
|
|
break;
|
||
|
|
end
|
||
|
|
|
||
|
|
if alpha > 0
|
||
|
|
t = alpha;
|
||
|
|
else
|
||
|
|
t = ng^2 / den; % stepsize
|
||
|
|
fprintf( '\t%1.2e' , t );
|
||
|
|
end
|
||
|
|
|
||
|
|
fprintf( '\n' );
|
||
|
|
|
||
|
|
% compute new point - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
|
||
|
|
% possibly plot the trajectory
|
||
|
|
if n == 2 && Plotf == 2
|
||
|
|
PXY = [ x , x - t * g ];
|
||
|
|
line( 'XData' , PXY( 1 , : ) , 'YData' , PXY( 2 , : ) , ...
|
||
|
|
'LineStyle' , '-' , 'LineWidth' , 2 , 'Marker' , 'o' , ...
|
||
|
|
'Color' , [ 0 0 0 ] );
|
||
|
|
end
|
||
|
|
|
||
|
|
x = x - t * g;
|
||
|
|
|
||
|
|
if Streamlined
|
||
|
|
g = g - t * v;
|
||
|
|
end
|
||
|
|
|
||
|
|
% iterate - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
|
||
|
|
if Interactive
|
||
|
|
pause;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
% end of main loop- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
|
||
|
|
end % the end- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|