yaeos__newton_solver Module

# newton_solver Robust Newton-Raphson solver for systems of nonlinear equations F(x) = 0.

@note Note This module was generated by a LLM.

Algorithm: Pure Newton with Levenberg-Marquardt (LM) regularization and Armijo backtracking line search used as a globalization strategy. The solver starts as pure Newton (lambda = 0) and promotes to LM whenever the Jacobian is detected to be singular or ill-conditioned, or when the line search cannot find a sufficient decrease.

Dependencies: LAPACK – dgetrf (LU factorisation with partial pivoting) dgetrs (triangular back-substitution) dgecon (1-norm condition number estimator)

## Examples ### Minimal call:

call newton(my_sub, x)

### Full call:

type(newton_settings) :: s
type(newton_result)   :: r
s%atol      = 1.0e-10_pr
s%verbosity = 2
call newton(my_sub, x, s, r)
if (r%status /= NEWTON_SUCCESS) write(*,*) newton_status_msg(r%status)

Uses

  • module~~yaeos__newton_solver~~UsesGraph module~yaeos__newton_solver yaeos__newton_solver iso_fortran_env iso_fortran_env module~yaeos__newton_solver->iso_fortran_env

Variables

Type Visibility Attributes Name Initial
integer, public, parameter :: NEWTON_LINE_SEARCH_FAIL = 5
integer, public, parameter :: NEWTON_MAX_ITS = 1
integer, public, parameter :: NEWTON_NAN_INF = 2
integer, public, parameter :: NEWTON_SINGULAR = 3
integer, public, parameter :: NEWTON_STAGNATION = 4
integer, public, parameter :: NEWTON_SUCCESS = 0

Abstract Interfaces

abstract interface

  • private subroutine to_solve(X, F, J)

    Arguments

    Type IntentOptional Attributes Name
    real(kind=pr), intent(in) :: X(:)
    real(kind=pr), intent(out) :: F(:)
    real(kind=pr), intent(out) :: J(:,:)

Derived Types

type, public ::  newton_result

Components

Type Visibility Attributes Name Initial
real(kind=pr), public :: cond_est = 0.0_pr

Estimated condition number of J (or J^T J + lambda I when LM active) at the final iteration, via LAPACK dgecon. Dimensionless.

real(kind=pr), public :: dx_norm = 0.0_pr

||dX||_inf of the last computed Newton step at exit. Units: same as x.

real(kind=pr), public, allocatable :: f_history(:)

||F||_inf at iterations 0, 1, …, result%iterations. Allocated only when settings%save_history = .true. Size: (iterations + 1).

real(kind=pr), public :: f_norm = 0.0_pr

||F(x)||_inf at exit. Should be < atol on NEWTON_SUCCESS. Units: same as F.

integer, public :: iterations = 0

Total number of Newton iterations performed (accepted + rejected).

real(kind=pr), public :: lambda = 0.0_pr

Value of the LM regularisation parameter at exit. 0.0 means the final solve was a pure Newton step. Units: [J]^2.

integer, public :: status = 0

Exit status code. Compare with NEWTON_SUCCESS, NEWTON_MAX_ITS, etc. Use newton_status_msg(status) for a human-readable string.

type, public ::  newton_settings

Components

Type Visibility Attributes Name Initial
real(kind=pr), public :: armijo_c = 1.0e-4_pr

Sufficient decrease constant (Wolfe c1 condition). Smaller values accept more steps but give weaker convergence guarantees. Must satisfy 0 < armijo_c < 0.5. Dimensionless. Default: 1e-4.

integer, public :: armijo_max_its = 50

Maximum number of backtracking halvings per Newton step. If reached without satisfying Armijo, ls_failed is set .true. Default: 50.

real(kind=pr), public :: armijo_tau = 0.5_pr

Step-length reduction factor applied each backtracking iteration. t_new = armijo_tau * t_old until Armijo or t < t_min. Must satisfy 0 < armijo_tau < 1. Dimensionless. Default: 0.5.

real(kind=pr), public :: atol = 1.0e-9_pr

Absolute residual tolerance. Converged when max_i |F_i(x)| < atol. Units: same as F. Default: 1e-8.

real(kind=pr), public :: cond_max = 1.0e10_pr

Condition number threshold above which LM regularization is activated (or strengthened) to stabilise the linear solve. Estimated via LAPACK dgecon. Dimensionless. Default: 1e10.

real(kind=pr), public :: lambda0 = 0.0_pr

Initial value of the LM damping parameter. 0.0 = start as pure Newton; the solver activates LM automatically if conditioning is poor. Set > 0 to force LM from the first iteration. Units: [J]^2 (scales with the Jacobian entries squared). Default: 0.

real(kind=pr), public :: lambda_down = 5.0_pr

Factor by which lambda is divided after a successful step with t > 0.1. Drives the solver back toward pure Newton as the iterate improves. Dimensionless. Default: 5.

real(kind=pr), public :: lambda_max = 1.0e8_pr

Maximum lambda, expressed as a multiplier of jacobian_scale. If lambda exceeds this ceiling the solver returns NEWTON_LINE_SEARCH_FAIL. Dimensionless multiplier. Default: 1e8.

real(kind=pr), public :: lambda_min = 1.0e-6_pr

Minimum non-zero lambda, expressed as a multiplier of jacobian_scale. Effective floor = lambda_min * ||J||_F^2/n. Prevents lambda from decaying to numerical zero after a good step. Dimensionless multiplier. Default: 1e-6.

real(kind=pr), public :: lambda_up = 10.0_pr

Factor by which lambda is multiplied on a line-search failure. Larger values recover faster from bad Jacobians but may overshoot. Dimensionless. Default: 10.

integer, public :: max_its = 100

Maximum number of Newton iterations before returning NEWTON_MAX_ITS. Default: 100.

real(kind=pr), public :: rtol = 1.0e-9_pr

Relative step tolerance. Converged when max_i |dX_i| < rtol * (max_i |x_i| + atol). Catches the case where the step becomes negligible compared to x. Dimensionless. Default: 1e-6.

logical, public :: save_history = .false.

If .true., allocate result%f_history(0:iterations) and store ||F||_inf at each iteration. Slightly increases memory use. Default: .false.

integer, public :: stagnation_nits = 5

Number of consecutive iterations with negligible change in ||dX|| before the solver exits with NEWTON_STAGNATION. Default: 5.

real(kind=pr), public :: stagnation_tol = 1.0e-12_pr

Relative threshold for stagnation: iteration is counted as stagnant when |||dX||_prev - ||dX||_curr| < stagnation_tol * (||dX|| + 1). Dimensionless. Default: 1e-12.

real(kind=pr), public :: t_min = 1.0e-8_pr

Minimum accepted step length. If t < t_min the line search declares failure instead of accepting a micro-step that satisfies Armijo trivially (m changes by ~machine eps). Dimensionless (fraction of the full Newton step). Default: 1e-8.

integer, public :: verbosity = 0

Controls stdout output. 0 – silent 1 – print header + one-line summary at exit 2 – also print one line per accepted iteration Default: 0.


Functions

public function newton_status_msg(status) result(msg)

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: status

Return Value character(len=48)

private pure function has_nan_inf(v)

Arguments

Type IntentOptional Attributes Name
real(kind=pr), intent(in) :: v(:)

Return Value logical

private pure function jacobian_scale(J)

Arguments

Type IntentOptional Attributes Name
real(kind=pr), intent(in) :: J(:,:)

Jacobian matrix, shape (n,n)

Return Value real(kind=pr)

private pure function mat1norm(A)

Arguments

Type IntentOptional Attributes Name
real(kind=pr), intent(in) :: A(:,:)

Return Value real(kind=pr)

private pure function norm_inf(v)

Arguments

Type IntentOptional Attributes Name
real(kind=pr), intent(in) :: v(:)

Return Value real(kind=pr)


Subroutines

public subroutine newton(sub, x, settings, result)

Arguments

Type IntentOptional Attributes Name
procedure(to_solve) :: sub
real(kind=pr), intent(inout) :: x(:)
type(newton_settings), intent(in), optional :: settings
type(newton_result), intent(out), optional :: result

private subroutine add_diagonal(A, val)

Arguments

Type IntentOptional Attributes Name
real(kind=pr), intent(inout) :: A(:,:)
real(kind=pr), intent(in) :: val

private subroutine armijo_backtrack(sub, X_old, F, J, dX, s, t, F_new, J_new, f_norm_new, failed)

Arguments

Type IntentOptional Attributes Name
procedure(to_solve) :: sub
real(kind=pr), intent(in) :: X_old(:)
real(kind=pr), intent(in) :: F(:)
real(kind=pr), intent(in) :: J(:,:)
real(kind=pr), intent(in) :: dX(:)
type(newton_settings), intent(in) :: s
real(kind=pr), intent(inout) :: t
real(kind=pr), intent(inout) :: F_new(:)
real(kind=pr), intent(inout) :: J_new(:,:)
real(kind=pr), intent(inout) :: f_norm_new
logical, intent(out) :: failed

private subroutine pack_result(res, res_out, s, hist_buf, its, f_norm, dx_norm, lambda, cond_est)

Arguments

Type IntentOptional Attributes Name
type(newton_result), intent(inout) :: res
type(newton_result), intent(out), optional :: res_out
type(newton_settings), intent(in) :: s
real(kind=pr), intent(in), optional :: hist_buf(:)
integer, intent(in) :: its

Iterations done

real(kind=pr), intent(in) :: f_norm

||F||_inf at exit

real(kind=pr), intent(in) :: dx_norm

||dX||_inf at exit

real(kind=pr), intent(in) :: lambda

LM lambda at exit

real(kind=pr), intent(in) :: cond_est

cond(J) at exit

private subroutine print_header(n)

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: n

private subroutine print_summary(res)

Arguments

Type IntentOptional Attributes Name
type(newton_result), intent(in) :: res

private subroutine solve_lm(J, F, lambda, jscale, s, dX, cond_est)

Arguments

Type IntentOptional Attributes Name
real(kind=pr), intent(in) :: J(:,:)

Jacobian at x

real(kind=pr), intent(in) :: F(:)

Residual at x

real(kind=pr), intent(inout) :: lambda

LM damping (absolute)

real(kind=pr), intent(in) :: jscale

||J||_F^2/n

type(newton_settings), intent(in) :: s

Solver settings

real(kind=pr), intent(out) :: dX(:)

Computed Newton/LM step

real(kind=pr), intent(out) :: cond_est

cond(A) estimate