Program Listing for File NewtonFixed.m¶
↰ Return to documentation for file (+Indigo/NewtonFixed.m
)
%
%> Class container for a dumped Newton's method with affine invariant step.
%>
%> **Solution Algorithm:**
%>
%> Given a zeros of a vectorial function problem of the form \f$ \mathbf{F}
%> (\mathbf{x}) = \mathbf{0} \f$, where \f$ \mathbf{F}: \mathbb{R}^n \rightarrow
%> \mathbb{R}^n \f$, then the Newton's method is defined as:
%>
%> \f[
%> \mathbf{JF}(\mathbf{x}_k)\mathbf{h} = -\mathbf{F}(\mathbf{x}_k).
%> \f]
%>
%> The dumped step is defined as:
%>
%> \f[
%> \mathbf{x}_{k+1} = \mathbf{x}_k + \alpha_k \mathbf{h}
%> \f]
%>
%> where \f$ \alpha_k \f$ is a dumping coefficient that satisfies:
%>
%> \f[
%> \left\| \mathbf{JF}(\mathbf{x}_k)^{-1} \mathbf{F}(\mathbf{x}_{k+1}) \right\|
%> \leq \left(1 - \dfrac{\alpha_k}{2}\right) \left\| \mathbf{JF}(\mathbf{x}_k)^{-1}
%> \mathbf{F}(\mathbf{x}_k) \right\| = \left(1 - \dfrac{\alpha_k}{2} \right)
%> \left\| \mathbf{h} \right\|.
%> \f]
%>
%> **Note:**
%>
%> For more details on the Newton's method with affine invariant step refer to:
%> https://www.zib.de/deuflhard/research/algorithm/ainewton.en.html.
%
classdef NewtonFixed < handle
%
properties (Access = private)
%
%> Function handle.
%
m_function_handle;
%
%> Jacobian handle.
%
m_jacobian_handle;
%
%> Algorithm tolerance.
%
m_tolerance = 1e-10;
%
%> Maximum allowed algorithm iterations.
%
m_max_iterations = 50;
%
%> Verbose mode boolean.
%
m_verbose = false;
%
%> Algorithm iterations.
%
m_iterations = 0;
%
%> Function evaluations.
%
m_function_evaluations = 0;
%
%> Jacobian evaluations.
%
m_jacobian_evaluations = 0;
%
%> Function residuals.
%
m_residuals = 0.0;
%
%> Convergence boolean.
%
m_converged = false;
%
end
%
methods
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
%> Newton's solver class constructor.
%>
%> \return The Newton's solver object.
%
function this = NewtonFixed()
end
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
%> Set algorithm tolerance.
%>
%> \param t_tolerance The algorithm tolerance.
%
function set_tolerance( this, t_tolerance )
CMD = 'Indigo.NewtonFixed.set_tolerance(...): ';
assert( ...
~isnan(t_tolerance) && ...
isfinite(t_tolerance) && ...
t_tolerance > 0.0, ...
[CMD, 'invalid input detected.']);
this.m_tolerance = t_tolerance;
end
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
%> Get algorithm tolerance.
%>
%> \return The algorithm tolerance.
%
function out = get_tolerance( this )
out = this.m_tolerance;
end
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
%> Set maximum allowed algorithm iterations.
%>
%> \param t_max_iterations The maximum allowed algorithm iterations.
%
function set_max_iterations( this, t_max_iterations )
CMD = 'Indigo.NewtonFixed.set_max_iterations(...): ';
assert( ...
~isnan(t_max_iterations) && ...
isfinite(t_max_iterations) && ...
t_max_iterations > 0, ...
[CMD, 'invalid input detected.']);
this.m_max_iterations = t_max_iterations;
end
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
%> Set maximum allowed algorithm iterations.
%>
%> \return The maximum allowed algorithm iterations.
%
function out = get_max_iterations( this )
out = this.m_max_iterations;
end
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
%> Enable verbose mode.
%>
%> \param t_alpha The relaxation factor.
%
function enable_verbose( this )
this.m_verbose = true;
end
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
%> Disable verbose mode.
%>
%> \param t_alpha The relaxation factor.
%
function disable_verbose( this )
this.m_verbose = false;
end
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
%> Get algorithm iterations.
%>
%> \return The algorithm iterations.
%
function out = out_iterations( this )
out = this.m_iterations;
end
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
%> Set function evaluations.
%>
%> \return The function evaluations.
%
function out = out_function_evaluations( this )
out = this.m_function_evaluations;
end
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
%> Set Jacobian evaluations.
%>
%> \return The Jacobian evaluations.
%
function out = out_jacobian_evaluations( this )
out = this.m_jacobian_evaluations;
end
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
%> Get function evaluations.
%>
%> \return The function evaluations.
%
function out = out_residuals( this )
out = this.m_residuals;
end
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
%> Get convergence boolean value.
%>
%> \return The convergence boolean value.
%
function out = out_converged( this )
out = this.m_converged;
end
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
%> Solve non-linear system of equations \f$ \mathbf{F}(\mathbf{x}) =
%> \mathbf{0} \f$
%>
%> \param t_function_handle The function handle.
%> \param t_jacobian_handle The Jacobian handle.
%> \param x_ini The initial guess vector \f$ \mathbf{x} \f$.
%>
%> \return The solution vector \f$ \mathbf{x} \f$.
%
function [out, ierr] = solve_handle( this, t_function_handle, t_jacobian_handle, x_ini )
this.m_function_handle = t_function_handle;
this.m_jacobian_handle = t_jacobian_handle;
[out, ierr] = this.solve(x_ini);
end
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
%> Reset solver internal counter and variables.
%>
%> \param t_function_handle The function handle.
%
function reset( this )
this.m_iterations = 0;
this.m_function_evaluations = 0;
this.m_jacobian_evaluations = 0;
this.m_residuals = 0.0;
this.m_converged = false;
end
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
%> Perform function \f$ \mathbf{F}(\mathbf{x}) \f$ evaluation.
%>
%> \param x The input vector \f$ \mathbf{x} \f$.
%>
%> \return The function value \f$ \mathbf{F}(\mathbf{x}) \f$.
%
function out = eval_function( this, x )
this.m_function_evaluations = this.m_function_evaluations + 1;
out = this.m_function_handle(x);
end
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
%> Perform function \f$ \mathbf{JF}(\mathbf{x}) \f$ evaluation.
%>
%> \param x The input vector \f$ \mathbf{x} \f$.
%>
%> \return The Jacobian value \f$ \mathbf{JF}(\mathbf{x}) \f$.
%
function out = eval_jacobian( this, x )
this.m_jacobian_evaluations = this.m_jacobian_evaluations + 1;
out = this.m_jacobian_handle(x);
end
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
%> Solve non-linear system of equations \f$ \mathbf{F} (\mathbf{x}) =
%> \mathbf{0} \f$.
%>
%> \param x_ini The initial guess for the vector \f$ \mathbf{x} \f$.
%>
%> \return The solution \f$ \mathbf{x} \f$ and the output flag:
%> \f$ 0 \f$ = success,
%> \f$ 1 \f$ = failed because of bad initial point,
%> \f$ 2 \f$ = failed because of bad dumping (step got too short).
%
function [x, ierr] = solve( this, x_ini )
CMD = 'Indigo.NewtonFixed.solve(...): ';
% Setup internal variables
this.reset();
% Algorithm iterations
this.m_converged = false;
ierr = 1;
x = x_ini;
for i=1:this.m_max_iterations
this.m_iterations = i;
if ~all(isfinite(x)); break; end
% Evaluate F
F = this.eval_function(x);
if ~all(isfinite(F)); break; end
% Check convergence
if norm(F, inf) < this.m_tolerance
ierr = 0;
this.m_converged = true;
break;
end
% Evaluate JF
J = this.eval_jacobian(x);
if ~all(isfinite(J)); break; end
% Evaluate advancing direction
%D = -J\F;
%[D, ~] = lsqr(J, -F, 1e-8, 50);
if (rcond(J) > 1e-14)
D = -J\F;
else
[D, ~] = lsqr(J, -F, 1e-6, 50);
end
if ~all(isfinite(D)); break; end
% Update solution
x = x+D;
if this.m_verbose
fprintf(1, '%s iter %d: ||F||_inf = %f, tau = %1.4f.\n', CMD, i, norm(F, inf), tau);
end
% Check convergence
%if norm(D,inf) < this.m_tolerance
% this.m_converged = true;
% break;
%end
end
end
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
end
end