Repository navigation
Balance the stale-W Newton rescale for ODE DIRK stages; replace chaotic ROBER step-count test - #4882
Draft
ChrisRackauckas-Claude wants to merge 3 commits into
Draft
ChrisRackauckas-Claude wants to merge 3 commits into
ChrisRackauckas-Claude wants to merge 3 commits into
Conversation
W is assembled as J - I/W_γdt, while the stage residual is scaled by the current 1/γdt, so a stale W leaves a multiplier between 1 (stiff) and γdt/W_γdt (nonstiff) on each mode. The Kennedy-Carpenter factor 2/(1+r) was derived for I - γhJ with an unscaled residual; in this formulation the balanced factor is 2/(1 + W_γdt/γdt). Apply it in in-place NLNewton and in NonlinearSolveAlg's rescale_stale_W_rhs!. DAE and coefficient-multistep stages keep the previous factor. Replace the ROBER step-count testset, whose counts are chaotic in the tolerances, with a contraction test on a linear Prothero-Robinson stage where the expected Newton contraction is known in closed form. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Claude <noreply@anthropic.com> Agent-Harness: Claude Code Agent-Model: claude-opus-5-5[1m] Agent-Session: https://claude.ai/code/session_011aK5Xvp9NpdkzKuEwtiMGd
The stale iteration matrix W(W_γdt)⁻¹W(γdt) tends to 1/r in the nonstiff limit, not r. State the unchanged-J, r > 0, real λ ≤ 0 assumptions behind the contraction bound. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Claude <noreply@anthropic.com> Agent-Harness: Claude Code Agent-Model: claude-opus-5-5[1m] Agent-Session: https://claude.ai/code/session_011aK5Xvp9NpdkzKuEwtiMGd
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Claude <noreply@anthropic.com> Agent-Harness: Claude Code 2.1.325 Agent-Model: claude-sonnet-5-5 Agent-Session: local fixer job SciML__OrdinaryDiffEq.jl__4882 (no session URL)
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft for a decision by @ChrisRackauckas: please ignore until he has reviewed it. This PR changes default
NLNewtonbehaviour for DIRK methods and needs a work-precision benchmark sweep before it can merge.What and why
Wis assembled asJ - I/W_γdt, but the stage right-hand side is scaled by the current1/γdt(invγdtis reset ininitialize!). On an eigenmodeλ, the stale iteration matrixW(W_γdt)⁻¹W(γdt) = (λ - 1/γdt)/(λ - 1/W_γdt)therefore runs from1(stiff) to1/r(nonstiff), withr = γdt/W_γdt. The Kennedy–Carpenter factor2/(1+r)(DIRK review, eq. 90) was derived forI - γhJwith an unscaled residual. Carried over to this formulation, the balanced factor is2r/(1+r) = 2/(1 + W_γdt/γdt). For unchangedJ,r > 0and realλ ≤ 0, it bounds the contraction of a linear stage by|r-1|/(r+1). The code applied2/(1 + γdt/W_γdt), which makes a linear stage contract worse than no correction, in both the stiff and the nonstiff limit.The factor is now
stale_W_scaleand is used by in-placeNLNewtonand byNonlinearSolveAlg'srescale_stale_W_rhs!(the copy added in #4028). The DAE branch (W_γdtstorescj = α/γdt) and the coefficient-multistep branch (effective stepγdt/α) are deliberately left on the old factor. The independent review below found the DAE orientation already balanced and the multistep one in need of a separate derivation. Out-of-placeNLNewtonapplies no rescale at all, and this PR does not add one.The ROBER testset in
nsa_jacobian_reuse_tests.jl(red on master since the OrdinaryDiffEqCore 4.18.1 dt rounding,45869 < 44710) compared accepted-step counts. Those counts are chaotic in the tolerances. KenCarp4 withnlsolve = NonlinearSolveAlg(NewtonRaphson()), ROBER, tspan 1e11, accepted steps:Raising the threshold would only hide this noise. The testset is replaced by a test of the property the rescale is supposed to provide. On the linear Prothero–Robinson problem
u' = λ(u - cos t) - sin t,ImplicitEulertakes three steps, thendtis set tor·W_γdtso thatWis reused (asserted). The Newton iterates are read off the pointsfis evaluated at and compared against the exact implicit-Euler stage root. The first contraction must equal(r-1)/(r+1)·(1+h₀λ)/(1-h₀λ)(rtol 1e-4), for r ∈ {0.9, 1.1}, λ ∈ {-1e6, -1e-2}, and bothNonlinearSolveAlgandNLNewton. The problem is linear and the step sequence is fixed, so nothing in the test depends on step-count chaos. This replaces a chaotic step-count assertion with a stronger, exact property. It is not a loosening: the new test fails both on master and with the rescale removed.Verification
Measured contraction
e₁/e₀(ImplicitEuler, r = 1.1):New testset with the master factor restored (in-process
@evalredefinition ofstale_W_scaleto2/(1+γdt/W_γdt), which applies to both the NLNewton andNonlinearSolveAlgpaths):With the rescale removed (
stale_W_scale ≡ 1):All 8 contraction assertions fail in each variant. The W-reuse, ratio and iterate-count assertions pass, so the test cannot pass vacuously when W is rebuilt.
With this PR, the whole
nsa_jacobian_reuse_tests.jlfile:GROUP=Corefor OrdinaryDiffEqNonlinearSolve (Pkg.test, Julia 1.12):Developer API Tests | 27 27, thenNewton Testserrors withLineSearchException: Search direction is not a direction of descent(Trapezoid +NLNewton(relax = BackTracking()), LineSearches 7.8.2). That is the pre-existing master failure addressed by #4714. Because it is a top-level@safetestseterror, it aborts the remaining files. A rerun of the rest of the group with Newton Tests excluded (local edit, not committed) was still running at push time: unverified.OrdinaryDiffEqSDIRKGROUP=Core([sources]pick up this branch's NonlinearSolve; Julia 1.12,--check-bounds=yes):The
DAE testsfile was cut off by my local 2-hourtimeoutand is unverified. The 2 broken results come from existing@test_brokenassertions.typosis clean on both changed files. Runic--checkis clean on both changed files.Validation still needed
From the independent review (Codex gpt-6.1-sol, round 1, CHANGES). These items are required before merging:
NLNewtonpath and forNonlinearSolveAlg, comparing the old factor, this PR's factor, and no rescale. DIRK methods: at least TRBDF2, KenCarp4, Kvaerno5, and the ESDIRK family. Problems: the SciMLBenchmarks stiff ODE set (ROBER, HIRES, OREGO, POLLU, Van der Pol, E5). Measure error against a reference vsnf, Jacobian/W builds and wall time.GROUP=Coreruns of OrdinaryDiffEqNonlinearSolve (blocked here by the pre-existing BackTracking error, fix NLNewton BackTracking when FD residual-norm slope is noisy #4714) and OrdinaryDiffEqSDIRK (DAE testsnot completed locally), plus CI.A small spot check (not a sweep): final-time error vs a
Rodas5Preference (reltol 1e-13) for three tolerances (abstol = 1e-3·reltol).oldswaps the previous factor in at runtime;newis this branch. All 72 solves returnedSuccess. On ROBER (tspan 1e5) and HIRES, the new factor used fewerfevaluations in all 24 cases (often 5–20% fewer, up to 33%). It gave a lower final error in only 6 of the 24, so most points trade some accuracy for less work and these points cannot settle the question. On Van der Pol (μ = 1e6), the final-point error is phase-dominated and moves both ways.KenCarp4+nsatracksKenCarp4(NLNewton) closely. Script and raw output: wp.jl, old, new.Spot-check table
Not verified
NLNewtonwith DIRK methods on nonlinear problems. This changes the defaultNLNewtonfor every SDIRK/ESDIRK method and must be benchmarked (SciMLBenchmarks stiff ODE work-precision sweep) before merging. Dropping the rescale entirely is the other option: it is near-exact in the stiff limit, where W reuse matters most.Unrelated, not fixed here:
Trapezoid(nlsolve = NonlinearSolveAlg(NewtonRaphson(autodiff = AutoForwardDiff())))returnsUnstableat t = 0 on the stiff Prothero–Robinson problem above, whereNLNewtonsucceeds.Risk assessment
NLNewtoniteration for every DIRK/SDIRK/ESDIRK method on in-place problems, plusNonlinearSolveAlgon the same methods, whereverWis reused across adtchange. No public API change. BDF/multistep, DAE and out-of-place paths are unchanged.🤖 Generated with Claude Code (model: claude-opus-5-5[1m])
https://claude.ai/code/session_011aK5Xvp9NpdkzKuEwtiMGd
Fix by Claude Code 2.1.325 claude-sonnet-5-5 (head f8d87c0)
Failing check:
SciMLSensitivity.jl/Core4/1 / Downstream Tests - Core4. The failure is an Enzyme compile error,AssertionError: mi2 !== nothinginthreadsfor_common(Enzymeparallelrules.jl), raised inensembles.jl"EnsembleAlg = EnsembleThreads". It does not involve this PR's change.Pre-existing on master at the time: the Downstream Core4 job failed with the identical assertion on master pushes between 2026-10-16 and 2026-10-20, for example run 38971870042. Core4 on master pushes from 2026-11-04 onward (runs 41772749111, 43401095529, 43443284988) is
success. This PR had not merged master since 2026-10-16.Change: a normal merge of
upstream/master(66 commits) into the branch. There are no conflicts and no source changes of my own. The PR diff against master is unchanged:lib/OrdinaryDiffEqNonlinearSolve/src/newton.jlandtest/nsa_jacobian_reuse_tests.jl.Validation, run locally on the merged head (Julia 1.13.3):
GROUP=Corefor OrdinaryDiffEqNonlinearSolve with onlynsa_jacobian_reuse_tests.jlselected (runtests.jl trimmed temporarily, restored, not committed):nsa_jacobian_reuse | 50 50 44.1s, thenTesting OrdinaryDiffEqNonlinearSolve tests passed.GROUP=Core, same Julia:Newton Testserrors withLineSearchException: Search direction is not a direction of descent(4 passed, 1 errored). A cleanupstream/masterworktree gives the identical error, so it is not caused by this PR. It aborts the rest of the group, so the remaining Core files were not run in the full-group run.Not verified: the Downstream Core4 job itself (needs CI; not run locally). The
OrdinaryDiffEqSDIRKCore group and the work-precision sweep listed under "Validation still needed" above are unchanged and still open.Next counted review must come from a smart model in a fresh session, not this fix session (risk.md § Independent reviews).
🤖 Posted by an AI agent — harness: Claude Code 2.1.325 · model: claude-sonnet-5-5
Conversation: local fixer job SciML__OrdinaryDiffEq.jl__4882 (no session URL)