Reuse nonlinear caches for ImplicitDiscreteSolve reinitialization - #4042
Merged
ChrisRackauckas merged 1 commit intoJul 28, 2026
Conversation
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
This was referenced Jul 27, 2026
ChrisRackauckas
marked this pull request as ready for review
July 28, 2026 08:03
Member
Author
|
Release metadata follow-up: the reusable cache API was ultimately registered as NonlinearSolveBase 2.38.0 after the unreleased version sequence was normalized, while this merged PR still left |
This was referenced Jul 29, 2026
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.
Important
Ignore this draft until reviewed by @ChrisRackauckas.
Summary
NonlinearSolveBase.solve_cache!driver.reinit!, including rectangular nonlinear least-squares problems.save_startduring integrator reinitialization and preserveInitialFailureinstead of resetting it afterward.Dependencies
This draft depends on NonlinearSolve.jl #1100, specifically
NonlinearSolveBase.solve_cache!in NonlinearSolveBase 2.40. The tested dependency head wasdca80d83c2d74483d1308c70f4315b69a9cbdf85.QA also exposed an independent SciMLTesting clean-master harness regression. It was bisected and fixed in SciMLTesting.jl #38; both QA runs below used its exact head
0afa642162a91f8e4df88803690664ded5c52daf. This is not a runtime dependency of the patch.The related reusable homotopy-cache integration is OrdinaryDiffEq.jl #3985. The final design/benchmark follow-up is also recorded on the merged controller PR #3908.
Root cause
The ImplicitDiscrete initialization added in #2624/#2626 only ran on initial integrator construction. Generic OrdinaryDiffEq
reinit!saved the rawu0before the ImplicitDiscrete consistency solve, and its later retcode reset could erase an initialization failure.ImplicitDiscreteSolve also rebuilt and solved a fresh
NonlinearProblemduring every initialization. Its time-step path reused a cache, but drove it by reading and mutating private NonlinearSolve fields and helpers. Reinitializing only the parameters left the previous nonlinear iterate in place instead of applying the documented constant extrapolant.This patch keeps the native IDS Newton/Kantorovich controller rather than replacing it with an artificial per-step
HomotopyProblem. It shares the new reusable NonlinearSolve cache-driving path with the homotopy solvers while retaining the substantially faster native recurrence solve measured below.Correctness and allocation coverage
The new tests cover:
reinit!+ reused solve, withsave_start=trueandfalse;step!and public integratorreinit!on Julia 1.11+.A separate 20-sample warmed probe on Julia 1.12.6 produced:
step!: first measurement-site warmup 144 B, then 0 B for all 19 samples;reinit!with a preallocatedu0: first measurement-site warmup 144 B, then 0 B for all 19 samples;solve!: 80 B in every sample because it constructs/returns the solution wrapper.The official regression asserts the two cache operations that are expected to be allocation-free; it does not disguise the solution-construction allocation.
Performance comparison
Twenty warmed Julia 1.12.6 samples, using
AutoFiniteDiffconsistently and solving the same 50-step implicit recurrence:(1.5531006208104776, 0.4090814367409633)(1.5531006208104776, 0.4090814367409633)(1.5531006208114124, 0.4090814367406754)(1.5531006208114124, 0.4090814367406754)(1.5531006237647473, 0.4090814358834119)(1.5531006237647473, 0.4090814358834119)Cache reuse makes IDS 1.85x faster and removes 8,704 B (97.84%) while preserving the endpoint exactly and using four fewer residual evaluations. Cached IDS is 2.70x faster than cached Kantorovich and 2.83x faster than cached HomotopySweep on this recurrence. Between the two homotopy methods, cached Kantorovich is 4.52% faster and uses 13.04% fewer residual calls than Sweep. The Kantorovich and Sweep endpoint deltas from IDS are approximately
(9.35e-13, -2.88e-13)and(2.95e-9, -8.58e-10), respectively.These numbers support retaining the IDS-specific solve strategy; they are workload-specific rather than a general ranking of homotopy algorithms.
Local validation
All commands ran from the exact upstream
masterbasefd8861edd500f8bba76a4f2a865e304d10881fe8on Julia 1.12:ODEDIFFEQ_TEST_GROUP=Core ... Pkg.test()for ImplicitDiscreteSolve: 53/53 passed, including cached allocation 2/2, reinitialization 15/15, constant extrapolant 2/2, NLLS 3/3, null state 3/3, and initialization failure 3/3.GROUP=Integrators_I ... Pkg.test()at the repository root: all active checks passed, including reinitialization 31/31 and integrator interface 36/36. The two existing marked-broken checks remained marked broken.--inplaceand--check: exit 0.git diff --check: exit 0.No test was skipped, silenced, deleted, loosened, or converted to a warning.
Process notes
The work followed the request to evaluate whether IDS should become a homotopy adapter, then narrowed the actual issue to reusable
init/cache solving. It traced the initialization history, benchmarked fresh and cached IDS against both current homotopy solvers, added the required public cache-driver API upstream instead of depending on private NonlinearSolve internals, implemented the downstream reuse path, reproduced the QA failure on clean master, and validated the independently bisected SciMLTesting fix before publishing this draft.