You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
NonlinearSolveAlg(LevenbergMarquardt()) returns ReturnCode.Success with answers that are
wrong by many orders of magnitude. This is the last surviving member of the family tracked in #4125, which was auto-closed by #4142's Fixes #4125 — #4142 repaired the DFSane and Broyden + BackTracking cases and explicitly did not repair LevenbergMarquardt, so the
tracking for it was lost. This issue is the successor.
Measured on merged master (5cf083900), reltol = 1e-6, abstol = 1e-9, maxiters = 1e7,
error = max absolute deviation from Rodas5P at reltol = 1e-13 / abstol = 1e-15:
problem
ODE alg
inner alg
retcode
naccept
abs err
ROBER
KenCarp4
NewtonRaphson
Success
7177
9.2830e-10
ROBER
KenCarp4
LevenbergMarquardt
Success
31609
5.0291e+07
ROBER
FBDF
NewtonRaphson
Success
634
8.8870e-10
ROBER
FBDF
LevenbergMarquardt
MaxIters
3846912
1.2830e-02
OREGO
KenCarp4
NewtonRaphson
Success
142
2.2699e-01
OREGO
KenCarp4
LevenbergMarquardt
Success
1082095
1.2156e+02
OREGO
FBDF
NewtonRaphson
Success
740
4.2322e-02
OREGO
FBDF
LevenbergMarquardt
Success
103360
1.4069e+03
The FBDF/ROBER row fails loudly, which is fine. The three bolded rows are silent wrong
answers.
Instrumented nlsolve! / compute_step! (printing ndz, θ, η, the relative stage
residual, and the linear-model defect ‖W·δ + fu_prev‖ / ‖fu_prev‖ at every outer iteration).
LevenbergMarquardt in NonlinearSolve is a GeneralizedFirstOrderAlgorithm built from a DampedNewtonDescent (wrapped in GeodesicAcceleration). Its step therefore solves a damped
Newton system, and — measured directly — covers only a fraction c ∈ (0, 1) of the Newton
step:
W·δ = -c·fu_prev and fu_new = (1 - c)·fu_prev
The instrumentation confirms this identity exactly. ROBER + KenCarp4 at t ≈ 1.44e5, per outer
iteration (linmodel is ‖W·δ - fu_prev‖/‖fu_prev‖, so linmodel = 1 + c; fratio is ‖fu_new‖/‖fu_prev‖ = 1 - c):
For contrast, NewtonRaphson on the same problem at t ≈ 1.47e5 (linmodel = 2.0000000000000013,
i.e. c = 1 to 15 digits — the displacement is the Newton step):
NR iter=3 ndz=0.18144 theta=0.01452 eta=0.01473 eta*ndz=0.00267 kappa=0.01
linmodel=1.9999999999982587 fratio=0.01340 br_eta=true
Now the failure. Deeper into the ROBER integration the damping stops covering any of the
Newton step at all, and the outer test accepts anyway. First accepted step whose state departs
from the reference is #3743 at t = 1.4552e5; the two steps around it:
Read that line: one outer iteration; the stage residual rose from 1.1502e-9 to 1.1930e-9 (c ≈ -0.037, i.e. the step accomplished nothing); and the stage was nonetheless
declared converged because η·ndz = 0.0086 < κ = 0.01.
η there is 0.0989, from θ = 0.09. That θ is stale. nlsolve! reads θ off the
ratio of consecutive displacements, which only exists from the second iteration of a stage
onwards; on the first iteration it falls back to nlsolver.prev_θ, carried over from an
earlier stage. Once these stages start converging at iter == 1, no second iteration ever
runs, prev_θ is never re-measured, and it stays frozen at 0.09 for the rest of the solve.
The convergence test degenerates into the bare displacement threshold ndz < κ/η = 0.101,
with a contraction factor measured on a different stage at a different step size.
The consequence is that every stage is accepted with a fraction of the correction applied. The
embedded error estimator does not see it (both stages are wrong the same way), so the step is
accepted, dt collapses (31609 accepted steps against NewtonRaphson's 7177), and the
solution drifts to 5e7 while retcode stays Success.
NSA: gate iter-1 convergence on inner solver retcode (#3817) #3893 (_uninformative_step) requires the inner step! to have left the iterate exactly unmoved (iszero(ndz)) with the cache not terminated — a TrustRegion that
rejected its trial step. LM's accepted steps move the iterate by ndz ≈ 0.087 in the
weighted norm, ~13 orders of magnitude above the predicate's trigger.
NonlinearSolveAlg: let the residual veto a stalled inner step #4142 (stalled_inner_step / stage_unsolved) requires the displacement to be below 8·eps·‖z‖and the residual not to have decreased. LM's displacement is far above
roundoff, and over most of the integration its residual does decrease (by the factor 1 - c ≈ 0.5 above), so the predicate is false on both counts.
Both predicates ask "did the inner solver produce a step at all?". LM does produce a step. The
question neither of them asks is "is the step it produced the Newton step the η/κ
contraction argument assumes?", and for a damped method the answer is no.
Notes for a fix
A plain "the residual must be small" gate does not work here, for the reason recorded in #4125:
for a stiff stage the residual at a perfectly converged iterate is (M - γΔt·J)·dz, amplified
by the stiffness, so no threshold on ‖γΔt·fu‖ separates a converged NewtonRaphson stage
from a stalled LevenbergMarquardt one. (Measured: at declared convergence NewtonRaphson
sits at relative residual ~8e-6 on this problem, not at any machine-precision floor.)
What does discriminate, costs no linear algebra, and is invariant both to the problem's units
and to the inner solver's deliberately-zeroed tolerances, is the residual contraction the
step actually achieved, ‖fu_new‖ / ‖fu_prev‖. Under the linearisation the residual and the
error are related by the constant W, so they contract by the same factor; unlike the
displacement ratio it needs no predecessor iteration, so it is available exactly where the
current code is forced to inherit a stale θ. In the table above it reads 0.5014 where the
damping is covering half the Newton step (correctly permitting convergence: the remaining
error really is ≈ ndz), and 1.037 at the failing stage (correctly refusing).
Summary
NonlinearSolveAlg(LevenbergMarquardt())returnsReturnCode.Successwith answers that arewrong by many orders of magnitude. This is the last surviving member of the family tracked in
#4125, which was auto-closed by #4142's
Fixes #4125— #4142 repaired theDFSaneandBroyden + BackTrackingcases and explicitly did not repairLevenbergMarquardt, so thetracking for it was lost. This issue is the successor.
Measured on merged master (
5cf083900),reltol = 1e-6,abstol = 1e-9,maxiters = 1e7,error = max absolute deviation from
Rodas5Patreltol = 1e-13 / abstol = 1e-15:NewtonRaphsonLevenbergMarquardtNewtonRaphsonLevenbergMarquardtNewtonRaphsonLevenbergMarquardtNewtonRaphsonLevenbergMarquardtThe
FBDF/ROBER row fails loudly, which is fine. The three bolded rows are silent wronganswers.
Reproduction
Root cause
Instrumented
nlsolve!/compute_step!(printingndz,θ,η, the relative stageresidual, and the linear-model defect
‖W·δ + fu_prev‖ / ‖fu_prev‖at every outer iteration).LevenbergMarquardtin NonlinearSolve is aGeneralizedFirstOrderAlgorithmbuilt from aDampedNewtonDescent(wrapped inGeodesicAcceleration). Its step therefore solves a dampedNewton system, and — measured directly — covers only a fraction
c ∈ (0, 1)of the Newtonstep:
The instrumentation confirms this identity exactly. ROBER + KenCarp4 at
t ≈ 1.44e5, per outeriteration (
linmodelis‖W·δ - fu_prev‖/‖fu_prev‖, solinmodel = 1 + c;fratiois‖fu_new‖/‖fu_prev‖ = 1 - c):For contrast,
NewtonRaphsonon the same problem att ≈ 1.47e5(linmodel = 2.0000000000000013,i.e.
c = 1to 15 digits — the displacement is the Newton step):Now the failure. Deeper into the ROBER integration the damping stops covering any of the
Newton step at all, and the outer test accepts anyway. First accepted step whose state departs
from the reference is #3743 at
t = 1.4552e5; the two steps around it:Read that line: one outer iteration; the stage residual rose from
1.1502e-9to1.1930e-9(c ≈ -0.037, i.e. the step accomplished nothing); and the stage was nonethelessdeclared converged because
η·ndz = 0.0086 < κ = 0.01.ηthere is0.0989, fromθ = 0.09. Thatθis stale.nlsolve!readsθoff theratio of consecutive displacements, which only exists from the second iteration of a stage
onwards; on the first iteration it falls back to
nlsolver.prev_θ, carried over from anearlier stage. Once these stages start converging at
iter == 1, no second iteration everruns,
prev_θis never re-measured, and it stays frozen at0.09for the rest of the solve.The convergence test degenerates into the bare displacement threshold
ndz < κ/η = 0.101,with a contraction factor measured on a different stage at a different step size.
The consequence is that every stage is accepted with a fraction of the correction applied. The
embedded error estimator does not see it (both stages are wrong the same way), so the step is
accepted,
dtcollapses (31609 accepted steps againstNewtonRaphson's 7177), and thesolution drifts to
5e7whileretcodestaysSuccess.Why #3893 and #4142 do not fire
_uninformative_step) requires the innerstep!to have left the iterateexactly unmoved (
iszero(ndz)) with the cache not terminated — aTrustRegionthatrejected its trial step. LM's accepted steps move the iterate by
ndz ≈ 0.087in theweighted norm, ~13 orders of magnitude above the predicate's trigger.
stalled_inner_step/stage_unsolved) requires the displacement to be below8·eps·‖z‖and the residual not to have decreased. LM's displacement is far aboveroundoff, and over most of the integration its residual does decrease (by the factor
1 - c ≈ 0.5above), so the predicate is false on both counts.Both predicates ask "did the inner solver produce a step at all?". LM does produce a step. The
question neither of them asks is "is the step it produced the Newton step the
η/κcontraction argument assumes?", and for a damped method the answer is no.
Notes for a fix
A plain "the residual must be small" gate does not work here, for the reason recorded in #4125:
for a stiff stage the residual at a perfectly converged iterate is
(M - γΔt·J)·dz, amplifiedby the stiffness, so no threshold on
‖γΔt·fu‖separates a convergedNewtonRaphsonstagefrom a stalled
LevenbergMarquardtone. (Measured: at declared convergenceNewtonRaphsonsits at relative residual
~8e-6on this problem, not at any machine-precision floor.)What does discriminate, costs no linear algebra, and is invariant both to the problem's units
and to the inner solver's deliberately-zeroed tolerances, is the residual contraction the
step actually achieved,
‖fu_new‖ / ‖fu_prev‖. Under the linearisation the residual and theerror are related by the constant
W, so they contract by the same factor; unlike thedisplacement ratio it needs no predecessor iteration, so it is available exactly where the
current code is forced to inherit a stale
θ. In the table above it reads0.5014where thedamping is covering half the Newton step (correctly permitting convergence: the remaining
error really is
≈ ndz), and1.037at the failing stage (correctly refusing)./cc @ChrisRackauckas