Skip to content

Commit 356512e

Browse files
Merge pull request #2805 from ChrisRackauckas-Claude/fix-compat-alignment
Add comprehensive QA testing infrastructure for solver allocations and type stability
2 parents 30116b6 + ea0c9db commit 356512e

File tree

75 files changed

+925
-166
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+925
-166
lines changed

.github/workflows/DowngradeSublibraries.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ jobs:
5959
version: ${{ matrix.julia-version }}
6060
- uses: julia-actions/julia-downgrade-compat@v2
6161
with:
62-
project: ${{ matrix.project }}
62+
projects: ${{ matrix.project }}
6363
skip: Pkg,TOML
6464
- uses: julia-actions/julia-buildpkg@v1
6565
with:

.typos.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ linearization = "linearization"
1919
parameterized = "parameterized"
2020
discretized = "discretized"
2121
vectorized = "vectorized"
22+
extrapolant = "extrapolant"
23+
# Person names in citations - these are correct spellings
24+
Sigal = "Sigal" # Sigal Gottlieb is a real person/author
25+
26+
# Common journal abbreviations
27+
Numer = "Numer" # As in "P. Numer. Math." (Periodica Numerica Mathematica)
28+
29+
# Technical variable names
30+
dorder = "dorder" # Parameter for delta order / order change
31+
2232

2333
# Common variable patterns in Julia/SciML
2434
ists = "ists"

lib/ImplicitDiscreteSolve/Project.toml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,20 @@ authors = ["vyudu <[email protected]>"]
44
version = "1.0.0"
55

66
[deps]
7-
SimpleNonlinearSolve = "727e6d20-b764-4bd8-a329-72de5adea6c7"
8-
SymbolicIndexingInterface = "2efcf032-c050-4f8e-a9bb-153293bab1f5"
7+
OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8"
8+
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
99
UnPack = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
1010
DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e"
11+
SymbolicIndexingInterface = "2efcf032-c050-4f8e-a9bb-153293bab1f5"
12+
SimpleNonlinearSolve = "727e6d20-b764-4bd8-a329-72de5adea6c7"
1113
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
12-
OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8"
13-
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
1414

1515
[extras]
1616
JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b"
1717
OrdinaryDiffEqSDIRK = "2d112036-d095-4a1e-ab9a-08536f3ecdbf"
1818
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1919
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
20+
AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a"
2021

2122
[compat]
2223
Test = "1.10.0"
@@ -29,11 +30,12 @@ SymbolicIndexingInterface = "0.3.38"
2930
julia = "1.10"
3031
JET = "0.9.18, 0.10.4"
3132
UnPack = "1.0.2"
33+
AllocCheck = "0.2"
3234
DiffEqBase = "6.164.1"
3335
Reexport = "1.2.2"
3436

3537
[targets]
36-
test = ["OrdinaryDiffEqSDIRK", "Test", "JET", "Aqua"]
38+
test = ["OrdinaryDiffEqSDIRK", "Test", "JET", "Aqua", "AllocCheck"]
3739

3840
[sources.OrdinaryDiffEqCore]
3941
path = "../OrdinaryDiffEqCore"

lib/OrdinaryDiffEqAdamsBashforthMoulton/Project.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ authors = ["ParamThakkar123 <[email protected]>"]
44
version = "1.3.0"
55

66
[deps]
7-
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
7+
OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8"
88
Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588"
99
Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
1010
FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898"
1111
OrdinaryDiffEqLowOrderRK = "1344f307-1e59-4825-a18e-ace9aa3fa4c6"
1212
RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd"
1313
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
14+
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
1415
DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e"
1516
MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221"
16-
OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8"
1717

1818
[extras]
1919
JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b"
@@ -22,6 +22,7 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
2222
DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d"
2323
ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5"
2424
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
25+
AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a"
2526
DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e"
2627
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
2728

@@ -41,12 +42,13 @@ julia = "1.10"
4142
JET = "0.9.18, 0.10.4"
4243
RecursiveArrayTools = "3.27.0"
4344
ODEProblemLibrary = "0.1.8"
45+
AllocCheck = "0.2"
4446
DiffEqBase = "6.152.2"
4547
Reexport = "1.2.2"
4648
SafeTestsets = "0.1.0"
4749

4850
[targets]
49-
test = ["DiffEqDevTools", "ODEProblemLibrary", "Random", "SafeTestsets", "Test", "DiffEqBase", "JET", "Aqua"]
51+
test = ["DiffEqDevTools", "ODEProblemLibrary", "Random", "SafeTestsets", "Test", "DiffEqBase", "JET", "Aqua", "AllocCheck"]
5052

5153
[sources.OrdinaryDiffEqLowOrderRK]
5254
path = "../OrdinaryDiffEqLowOrderRK"

lib/OrdinaryDiffEqBDF/Project.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ OrdinaryDiffEqSDIRK = "2d112036-d095-4a1e-ab9a-08536f3ecdbf"
1313
TruncatedStacktraces = "781d530d-4396-4725-bb49-402e4bee1e77"
1414
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
1515
OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8"
16-
ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
1716
Preferences = "21216c6a-2e73-6563-6e65-726566657250"
17+
ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
1818
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
1919
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
2020
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
@@ -35,6 +35,7 @@ Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9"
3535
JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b"
3636
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
3737
ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5"
38+
AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a"
3839
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
3940

4041
[compat]
@@ -65,12 +66,13 @@ ADTypes = "1.11"
6566
RecursiveArrayTools = "3.27.0"
6667
ODEProblemLibrary = "0.1.8"
6768
OrdinaryDiffEqNonlinearSolve = "1.6"
69+
AllocCheck = "0.2"
6870
DiffEqBase = "6.169.1"
6971
Reexport = "1.2.2"
7072
SafeTestsets = "0.1.0"
7173

7274
[targets]
73-
test = ["DiffEqDevTools", "ForwardDiff", "Random", "SafeTestsets", "Test", "ODEProblemLibrary", "NonlinearSolve", "StaticArrays", "Enzyme", "LinearSolve", "JET", "Aqua"]
75+
test = ["DiffEqDevTools", "ForwardDiff", "Random", "SafeTestsets", "Test", "ODEProblemLibrary", "NonlinearSolve", "StaticArrays", "Enzyme", "LinearSolve", "JET", "Aqua", "AllocCheck"]
7476

7577
[sources.OrdinaryDiffEqSDIRK]
7678
path = "../OrdinaryDiffEqSDIRK"
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
using OrdinaryDiffEqBDF
2+
using OrdinaryDiffEqCore
3+
using AllocCheck
4+
using Test
5+
6+
"""
7+
Allocation tests for OrdinaryDiffEqBDF solvers using AllocCheck.jl.
8+
These tests verify that the step! operation should not allocate during stepping.
9+
Currently, many BDF solvers are allocating and marked with @test_broken.
10+
"""
11+
12+
@testset "BDF Allocation Tests" begin
13+
# Test problem for standard ODE BDF methods
14+
function simple_system!(du, u, p, t)
15+
du[1] = -0.5 * u[1]
16+
du[2] = -1.5 * u[2]
17+
end
18+
prob = ODEProblem(simple_system!, [1.0, 1.0], (0.0, 1.0))
19+
20+
# Split problem for IMEX methods
21+
function f1!(du, u, p, t)
22+
du[1] = -0.5 * u[1]
23+
du[2] = 0.0
24+
end
25+
function f2!(du, u, p, t)
26+
du[1] = 0.0
27+
du[2] = -1.5 * u[2]
28+
end
29+
split_prob = SplitODEProblem(f1!, f2!, [1.0, 1.0], (0.0, 1.0))
30+
31+
# DAE problem for DAE solvers
32+
function dae_f!(resid, du, u, p, t)
33+
resid[1] = -0.5 * u[1] + u[2] - du[1]
34+
resid[2] = u[1] - u[2] - du[2]
35+
end
36+
du0 = zeros(2)
37+
differential_vars = [true, false]
38+
dae_prob = DAEProblem(dae_f!, du0, [1.0, 1.0], (0.0, 1.0), differential_vars=differential_vars)
39+
40+
# Test all exported BDF solvers for allocation-free behavior
41+
# Standard ODE BDF methods
42+
bdf_solvers = [ABDF2(), QNDF1(), QBDF1(), QNDF2(), QBDF2(), QNDF(), QBDF(), FBDF(), MEBDF2()]
43+
44+
# IMEX/Split methods need SplitODEProblem
45+
imex_solvers = [SBDF(order=2), SBDF2(), SBDF3(), SBDF4(), IMEXEuler(), IMEXEulerARK()]
46+
47+
# DAE methods need DAEProblem
48+
dae_solvers = [DABDF2(), DImplicitEuler(), DFBDF()]
49+
50+
@testset "BDF Solver Allocation Analysis" begin
51+
for solver in bdf_solvers
52+
@testset "$(typeof(solver)) allocation check" begin
53+
integrator = init(prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6)
54+
step!(integrator) # Setup step may allocate
55+
56+
# Use AllocCheck to verify step! is allocation-free
57+
allocs = check_allocs(step!, (typeof(integrator),))
58+
59+
# These solvers should be allocation-free, but mark as broken for now
60+
# to verify with AllocCheck (more accurate than @allocated)
61+
@test length(allocs) == 0 broken=true
62+
63+
if length(allocs) > 0
64+
println("AllocCheck found $(length(allocs)) allocation sites in $(typeof(solver)) step!:")
65+
for (i, alloc) in enumerate(allocs[1:min(3, end)]) # Show first 3
66+
println(" $i. $alloc")
67+
end
68+
else
69+
println("$(typeof(solver)) appears allocation-free with AllocCheck")
70+
end
71+
end
72+
end
73+
end
74+
75+
@testset "IMEX Solver Allocation Analysis" begin
76+
for solver in imex_solvers
77+
@testset "$(typeof(solver)) allocation check" begin
78+
integrator = init(split_prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6)
79+
step!(integrator) # Setup step may allocate
80+
81+
# Use AllocCheck to verify step! is allocation-free
82+
allocs = check_allocs(step!, (typeof(integrator),))
83+
84+
# These solvers should be allocation-free, but mark as broken for now
85+
# to verify with AllocCheck (more accurate than @allocated)
86+
@test length(allocs) == 0 broken=true
87+
88+
if length(allocs) > 0
89+
println("AllocCheck found $(length(allocs)) allocation sites in $(typeof(solver)) step!:")
90+
for (i, alloc) in enumerate(allocs[1:min(3, end)]) # Show first 3
91+
println(" $i. $alloc")
92+
end
93+
else
94+
println("$(typeof(solver)) appears allocation-free with AllocCheck")
95+
end
96+
end
97+
end
98+
end
99+
100+
@testset "DAE Solver Allocation Analysis" begin
101+
for solver in dae_solvers
102+
@testset "$(typeof(solver)) allocation check" begin
103+
integrator = init(dae_prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6)
104+
step!(integrator) # Setup step may allocate
105+
106+
# Use AllocCheck to verify step! is allocation-free
107+
allocs = check_allocs(step!, (typeof(integrator),))
108+
109+
# These solvers should be allocation-free, but mark as broken for now
110+
# to verify with AllocCheck (more accurate than @allocated)
111+
@test length(allocs) == 0 broken=true
112+
113+
if length(allocs) > 0
114+
println("AllocCheck found $(length(allocs)) allocation sites in $(typeof(solver)) step!:")
115+
for (i, alloc) in enumerate(allocs[1:min(3, end)]) # Show first 3
116+
println(" $i. $alloc")
117+
end
118+
else
119+
println("$(typeof(solver)) appears allocation-free with AllocCheck")
120+
end
121+
end
122+
end
123+
end
124+
end

lib/OrdinaryDiffEqBDF/test/jet.jl

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,78 @@
11
import OrdinaryDiffEqBDF
2+
using OrdinaryDiffEqBDF
3+
using OrdinaryDiffEqCore
4+
using DiffEqBase: SplitODEProblem, DAEProblem
25
using JET
6+
using Test
37

48
@testset "JET Tests" begin
9+
# Test package for typos - now passing
510
test_package(
611
OrdinaryDiffEqBDF, target_defined_modules = true, mode = :typo)
12+
13+
# Test individual solver type stability
14+
@testset "Solver Type Stability Tests" begin
15+
# Test problem - use a simple linear problem for stiff solvers
16+
linear_prob = ODEProblem((u, p, t) -> -u, 1.0, (0.0, 1.0))
17+
18+
# Split problem for SBDF solvers (which require SplitODEProblem)
19+
split_prob = SplitODEProblem((u, p, t) -> -u, (u, p, t) -> 0.0, 1.0, (0.0, 1.0))
20+
21+
# DAE problem for DAE solvers
22+
function simple_dae!(resid, du, u, p, t)
23+
resid[1] = -u[1] - du[1]
24+
end
25+
u0 = [1.0]
26+
du0 = [-1.0]
27+
dae_prob = DAEProblem(simple_dae!, du0, u0, (0.0, 1.0))
28+
29+
# Regular BDF solvers (ODEProblem)
30+
regular_bdf_solvers = [ABDF2(), QNDF1(), QBDF1(), QNDF2(), QBDF2(), QNDF(), QBDF(), FBDF(),
31+
MEBDF2(), IMEXEuler(), IMEXEulerARK()]
32+
33+
# DAE solvers (DAEProblem)
34+
dae_solvers = [DABDF2(), DImplicitEuler(), DFBDF()]
35+
36+
# Test SBDF solvers separately with required order parameter and SplitODEProblem
37+
sbdf_solvers = [SBDF(order=2), SBDF(order=3), SBDF(order=4), SBDF2(), SBDF3(), SBDF4()]
38+
39+
for solver in regular_bdf_solvers
40+
@testset "$(typeof(solver)) type stability" begin
41+
try
42+
@test_opt broken=true init(linear_prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6)
43+
integrator = init(linear_prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6)
44+
@test_opt broken=true step!(integrator)
45+
catch e
46+
@test_broken false # Mark as broken if solver fails to initialize
47+
println("$(typeof(solver)) failed with: $e")
48+
end
49+
end
50+
end
51+
52+
for solver in dae_solvers
53+
@testset "$(typeof(solver)) DAE type stability" begin
54+
try
55+
@test_opt broken=true init(dae_prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6)
56+
integrator = init(dae_prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6)
57+
@test_opt broken=true step!(integrator)
58+
catch e
59+
@test_broken false # Mark as broken if solver fails to initialize
60+
println("$(typeof(solver)) failed with: $e")
61+
end
62+
end
63+
end
64+
65+
for solver in sbdf_solvers
66+
@testset "$(typeof(solver)) type stability" begin
67+
try
68+
@test_opt broken=true init(split_prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6)
69+
integrator = init(split_prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6)
70+
@test_opt broken=true step!(integrator)
71+
catch e
72+
@test_broken false # Mark as broken if solver fails to initialize
73+
println("$(typeof(solver)) failed with: $e")
74+
end
75+
end
76+
end
77+
end
778
end

lib/OrdinaryDiffEqBDF/test/runtests.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,9 @@ using SafeTestsets
99
@time @safetestset "BDF Convergence Tests" include("bdf_convergence_tests.jl")
1010
@time @safetestset "BDF Regression Tests" include("bdf_regression_tests.jl")
1111

12-
@time @safetestset "JET Tests" include("jet.jl")
13-
@time @safetestset "Aqua" include("qa.jl")
12+
# Only run QA and allocation tests on stable Julia versions
13+
if isempty(VERSION.prerelease)
14+
@time @safetestset "JET Tests" include("jet.jl")
15+
@time @safetestset "Aqua" include("qa.jl")
16+
@time @safetestset "Allocation Tests" include("allocation_tests.jl")
17+
end

0 commit comments

Comments
 (0)