Skip to content

Commit 56ffb52

Browse files
ChrisRackauckas-ClaudeChrisRackauckasclaude
authored
Newton-Krylov integrators default to Hegedüs warm start (require LinearSolve 5.1) (#3991)
* Default Newton-Krylov integrators to Hegedus warm starting Resolves a Krylov linear solver left at the new LinearSolve.WarmStart.Auto default to WarmStart.Hegedus on the Newton nonlinear-solver path, so implicit integrators using KrylovJL_GMRES()/KrylovJL_FGMRES() reuse the previous solution (Hegedus-scaled) across the correlated linear solves of a Newton iteration. Rosenbrock/W-method integrators never call the resolver, so their Auto solver stays a cold start -- warm starting is unsafe there (no outer Newton iteration absorbs the within-tolerance stage-solve perturbation, which can trigger step-rejection feedback loops). Explicit WarmStart.None/Previous/Hegedus are always respected. The resolver is guarded on isdefined(LinearSolve, :WarmStart), so it is a no-op on LinearSolve < 5.1 and this compiles unchanged there. Bumps the LinearSolve compat of the two touched sublibraries to allow 5; umbrella-wide activation additionally requires the OrdinaryDiffEq LinearSolve 5 compat migration across the remaining sublibraries. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Make downgrade compat floors consistent in the two touched sublibraries Two stale minimum-version declarations were mutually unsatisfiable, which is what the Downgrade Sublibraries CI hits: - LinearSolve floor 3.75.0 was inconsistent with the NonlinearSolveBase 2.34.1 floor, which itself requires LinearSolve >= 4.3.0. Raised to 4.3.0. - OrdinaryDiffEqNonlinearSolve declared SciMLOperators >= 1.24.3 while its path dependency OrdinaryDiffEqDifferentiation requires >= 1.24.4. Raised to 1.24.4. Neither drops any actually-installable configuration. The warm-start resolver remains guarded on isdefined(LinearSolve, :WarmStart), so it still no-ops on LinearSolve 4.x and activates on 5.1+. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Require LinearSolve 5.1 across the monorepo and drop the WarmStart guard Makes the Newton-Krylov Hegedus warm-start default unconditionally live instead of silently dormant: - OrdinaryDiffEqNonlinearSolve and OrdinaryDiffEqDifferentiation require LinearSolve = "5.1" (where WarmStart exists), and default_krylov_warm_start drops its isdefined(LinearSolve, :WarmStart) guard. - Every other monorepo sublibrary that declared a LinearSolve compat is moved to "5.1" as well. These all depend (transitively) on NonlinearSolve/Differentiation, so they can never resolve with LinearSolve < 5.1 anyway; keeping a 3/4 lower bound would be dead metadata and would re-break the Downgrade CI (which floors deps to their minimum). Test sub-environments updated to match. - Minor version bumps for each sublibrary whose compat changed. Verified: fresh resolution pins LinearSolve 5.1.0; resolver unit test passes (7/7); FBDF and Rodas5P solve with a default KrylovJL_GMRES(); the resolver maps Auto -> Hegedus with the guard removed. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: ChrisRackauckas-Claude <accounts@chrisrackauckas.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent bc534d7 commit 56ffb52

18 files changed

Lines changed: 79 additions & 28 deletions

File tree

lib/DelayDiffEq/Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "DelayDiffEq"
22
uuid = "bcd4f6db-9728-5f36-b5f7-82caef46ccdb"
33
authors = ["Chris Rackauckas <accounts@chrisrackauckas.com>"]
4-
version = "6.0.7"
4+
version = "6.1.0"
55

66
[deps]
77
ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
@@ -70,7 +70,7 @@ FastBroadcast = "1.3"
7070
FiniteDiff = "2.27"
7171
ForwardDiff = "1.3.3"
7272
LinearAlgebra = "1"
73-
LinearSolve = "3.75.0, 4"
73+
LinearSolve = "5.1"
7474
Logging = "1"
7575
OrdinaryDiffEqBDF = "2"
7676
OrdinaryDiffEqCore = "4"

lib/OrdinaryDiffEqAMF/Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "OrdinaryDiffEqAMF"
22
uuid = "08082164-f6a1-4363-b3df-3aa6fcf571ad"
33
authors = ["Utkarsh <rajpututkarsh530@gmail.com>"]
4-
version = "2.1.1"
4+
version = "2.2.0"
55

66
[deps]
77
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
@@ -15,7 +15,7 @@ SciMLOperators = "c0aeaf25-5076-4817-a8d5-81caf7dfa961"
1515
SciMLTesting = "2.1"
1616
LinearAlgebra = "1.10"
1717
SafeTestsets = "0.1.0"
18-
LinearSolve = "3.75.0, 4"
18+
LinearSolve = "5.1"
1919
OrdinaryDiffEqCore = "4"
2020
Reexport = "1.2.2"
2121
SciMLBase = "3.35.1"

lib/OrdinaryDiffEqBDF/Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "OrdinaryDiffEqBDF"
22
uuid = "6ad6398a-0878-4a85-9266-38940aa047c8"
33
authors = ["ParamThakkar123 <paramthakkar864@gmail.com>"]
4-
version = "2.3.2"
4+
version = "2.4.0"
55

66
[deps]
77
FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898"
@@ -56,7 +56,7 @@ Random = "<0.0.1, 1"
5656
DiffEqDevTools = "3"
5757
DifferentiationInterface = "0.7.18"
5858
MuladdMacro = "0.2.4"
59-
LinearSolve = "3.75.0, 4"
59+
LinearSolve = "5.1"
6060
PrecompileTools = "1.2.1, 1.3"
6161
LinearAlgebra = "1.10"
6262
OrdinaryDiffEqDifferentiation = "3"

lib/OrdinaryDiffEqDefault/Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "OrdinaryDiffEqDefault"
22
uuid = "50262376-6c5a-4cf5-baba-aaf4f84d72d7"
33
authors = ["ParamThakkar123 <paramthakkar864@gmail.com>"]
4-
version = "2.3.0"
4+
version = "2.4.0"
55

66
[deps]
77
OrdinaryDiffEqTsit5 = "b1df2697-797e-41e3-8120-5422d3b24e4a"
@@ -50,7 +50,7 @@ Random = "<0.0.1, 1"
5050
DiffEqDevTools = "3"
5151
OrdinaryDiffEqBDF = "2"
5252
OrdinaryDiffEqVerner = "2"
53-
LinearSolve = "3.75.0, 4"
53+
LinearSolve = "5.1"
5454
PrecompileTools = "1.2.1, 1.3"
5555
EnumX = "1.0.4"
5656
LinearAlgebra = "1.10"

lib/OrdinaryDiffEqDifferentiation/Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name = "OrdinaryDiffEqDifferentiation"
2-
version = "3.4.1"
2+
version = "3.5.0"
33
uuid = "4302a76b-040a-498a-8c04-15b101fed76b"
44
authors = ["Chris Rackauckas <accounts@chrisrackauckas.com>", "Yingbo Ma <mayingbo5@gmail.com>"]
55

@@ -21,7 +21,7 @@ DiffEqDevTools = "3"
2121
Test = "<0.0.1, 1"
2222
FiniteDiff = "2.27"
2323
DifferentiationInterface = "0.7.18"
24-
LinearSolve = "3.75.0, 4"
24+
LinearSolve = "5.1"
2525
ConstructionBase = "1.5.8"
2626
LinearAlgebra = "1.10"
2727
SciMLBase = "3.35.1"

lib/OrdinaryDiffEqDifferentiation/src/linsolve_utils.jl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,29 @@ function dolinsolve(
5252
return linres
5353
end
5454

55+
"""
56+
default_krylov_warm_start(linsolver) -> linsolver
57+
58+
Resolve a Krylov linear solver left at `LinearSolve.WarmStart.Auto` to the mode
59+
appropriate for a Newton-based integrator, `LinearSolve.WarmStart.Hegedus`
60+
(Hegedüs-scaled reuse of the previous solution — the recommended mode for the
61+
sequence of correlated preconditioned solves inside a Newton iteration).
62+
63+
Only the `Auto` default is resolved: an explicit `WarmStart.None`/`Previous`/
64+
`Hegedus` or a non-Krylov solver is returned unchanged. This is called on the
65+
Newton nonlinear-solver path only; Rosenbrock/W-method integrators never call
66+
it, so their `Auto` solver stays a cold start (warm starting is unsafe there —
67+
no outer Newton iteration absorbs the within-tolerance stage-solve
68+
perturbation).
69+
"""
70+
function default_krylov_warm_start(linsolver)
71+
(
72+
linsolver isa LinearSolve.KrylovJL &&
73+
linsolver.warm_start === LinearSolve.WarmStart.Auto
74+
) || return linsolver
75+
return SciMLBase.remake(linsolver; warm_start = LinearSolve.WarmStart.Hegedus)
76+
end
77+
5578
"""
5679
wrapprecs(linsolver, W, weight) -> linsolver
5780

lib/OrdinaryDiffEqDifferentiation/test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ if TEST_GROUP ∉ ("QA", "Sparse", "ModelingToolkit")
3737
@time @safetestset "Autodiff Error Tests" include("autodiff_error_tests.jl")
3838
@time @safetestset "No Jac Tests" include("nojac_tests.jl")
3939
@time @safetestset "Stale W Linear Operator Tests" include("stale_w_linear_operator_tests.jl")
40+
@time @safetestset "Krylov warm_start default" include("warm_start_default_tests.jl")
4041
end
4142

4243
# Run sparse tests (separate environment due to ComponentArrays dep conflicts)

lib/OrdinaryDiffEqDifferentiation/test/sparse/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ OrdinaryDiffEqSDIRK = {path = "../../../OrdinaryDiffEqSDIRK"}
1313

1414
[compat]
1515
ComponentArrays = "0.15, 1"
16-
LinearSolve = "3, 4"
16+
LinearSolve = "5.1"
1717
OrdinaryDiffEq = "7"
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using OrdinaryDiffEqDifferentiation: default_krylov_warm_start
2+
using LinearSolve
3+
using Test
4+
5+
@testset "default_krylov_warm_start resolves Auto for the Newton path" begin
6+
# Non-Krylov solvers are always returned unchanged.
7+
@test default_krylov_warm_start(LUFactorization()) isa LUFactorization
8+
9+
# Auto (the KrylovJL default) resolves to Hegedus on the Newton path.
10+
@test default_krylov_warm_start(KrylovJL_GMRES()).warm_start ===
11+
LinearSolve.WarmStart.Hegedus
12+
# Explicit choices are respected, never overridden.
13+
for ws in (
14+
LinearSolve.WarmStart.None, LinearSolve.WarmStart.Previous,
15+
LinearSolve.WarmStart.Hegedus,
16+
)
17+
@test default_krylov_warm_start(KrylovJL_GMRES(warm_start = ws)).warm_start === ws
18+
end
19+
# Other fields survive the remake.
20+
precs = (A, p) -> (I, I)
21+
resolved = default_krylov_warm_start(KrylovJL_GMRES(; precs))
22+
@test resolved.warm_start === LinearSolve.WarmStart.Hegedus
23+
@test resolved.precs === precs
24+
end

lib/OrdinaryDiffEqExponentialRK/Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "OrdinaryDiffEqExponentialRK"
22
uuid = "e0540318-69ee-4070-8777-9e2de6de23de"
33
authors = ["ParamThakkar123 <paramthakkar864@gmail.com>"]
4-
version = "2.1.1"
4+
version = "2.2.0"
55

66
[deps]
77
FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898"
@@ -48,7 +48,7 @@ Random = "<0.0.1, 1"
4848
DiffEqDevTools = "3"
4949
MuladdMacro = "0.2.4"
5050
OrdinaryDiffEqVerner = "2"
51-
LinearSolve = "3.75.0, 4"
51+
LinearSolve = "5.1"
5252
ExponentialUtilities = "1.27"
5353
LinearAlgebra = "1.10"
5454
OrdinaryDiffEqDifferentiation = "3"

0 commit comments

Comments
 (0)