Skip to content

Commit 4c978a6

Browse files
committed
Distributed Testing using ReTestItems
1 parent 7bc4411 commit 4c978a6

22 files changed

+440
-388
lines changed

.github/workflows/CI.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ jobs:
4444
- uses: julia-actions/julia-runtest@v1
4545
env:
4646
GROUP: ${{ matrix.group }}
47-
JULIA_NUM_THREADS: 8
47+
JULIA_NUM_THREADS: 11
48+
RETESTITEMS_NWORKERS: 4
49+
RETESTITEMS_NWORKER_THREADS: 2
4850
- uses: julia-actions/julia-processcoverage@v1
4951
with:
5052
directories: src,ext

Project.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "NonlinearSolve"
22
uuid = "8913a72c-1f9b-4ce2-8d82-65094dcecaec"
33
authors = ["SciML"]
4-
version = "3.5.3"
4+
version = "3.5.4"
55

66
[deps]
77
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
@@ -84,6 +84,7 @@ PrecompileTools = "1.2"
8484
Preferences = "1.4"
8585
Printf = "1.10"
8686
Random = "1.91"
87+
ReTestItems = "1"
8788
RecursiveArrayTools = "3.4"
8889
Reexport = "1.2"
8990
SIAMFANLEquations = "1.0.1"
@@ -101,7 +102,6 @@ Symbolics = "5.13"
101102
Test = "1.10"
102103
TimerOutputs = "0.5.23"
103104
Zygote = "0.6.67"
104-
XUnit = "1.1"
105105
julia = "1.10"
106106

107107
[extras]
@@ -123,6 +123,8 @@ NonlinearProblemLibrary = "b7050fa9-e91f-4b37-bcee-a89a063da141"
123123
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
124124
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
125125
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
126+
ReTestItems = "817f1d60-ba6b-4fd5-9520-3cf149f6a823"
127+
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
126128
SIAMFANLEquations = "084e46ad-d928-497d-ad5e-07fa361a48c4"
127129
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
128130
SparseDiffTools = "47a9eef4-7e08-11e9-0b38-333d64bd3804"
@@ -132,8 +134,7 @@ StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
132134
Sundials = "c3572dad-4567-51f8-b174-8c6c989267f4"
133135
Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
134136
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
135-
XUnit = "3e3c03f2-1a94-11e9-2981-050a4ca824ab"
136137
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
137138

138139
[targets]
139-
test = ["Aqua", "Enzyme", "BenchmarkTools", "SafeTestsets", "Pkg", "Test", "ForwardDiff", "StaticArrays", "Symbolics", "LinearSolve", "Random", "LinearAlgebra", "Zygote", "SparseDiffTools", "NonlinearProblemLibrary", "LeastSquaresOptim", "FastLevenbergMarquardt", "NaNMath", "BandedMatrices", "DiffEqBase", "StableRNGs", "MINPACK", "NLsolve", "OrdinaryDiffEq", "SpeedMapping", "FixedPointAcceleration", "SIAMFANLEquations", "Sundials", "XUnit"]
140+
test = ["Aqua", "Enzyme", "BenchmarkTools", "SafeTestsets", "Pkg", "Test", "ForwardDiff", "StaticArrays", "Symbolics", "LinearSolve", "Random", "LinearAlgebra", "Zygote", "SparseDiffTools", "NonlinearProblemLibrary", "LeastSquaresOptim", "FastLevenbergMarquardt", "NaNMath", "BandedMatrices", "DiffEqBase", "StableRNGs", "MINPACK", "NLsolve", "OrdinaryDiffEq", "SpeedMapping", "FixedPointAcceleration", "SIAMFANLEquations", "Sundials", "ReTestItems", "Reexport"]

src/algorithms/levenberg_marquardt.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,11 @@ end
6969
J_diag_cache
7070
J_damped
7171
damping_f
72+
initial_damping
7273
end
7374

7475
function reinit_cache!(cache::LevenbergMarquardtDampingCache, args...; kwargs...)
75-
cache.λ = cache.damping_f.initial_damping
76+
cache.λ = cache.initial_damping
7677
cache.λ_factor = cache.damping_f.increase_factor
7778
if !(cache.DᵀD isa Number)
7879
if can_setindex(cache.DᵀD.diag)
@@ -110,7 +111,7 @@ function __internal_init(prob::AbstractNonlinearProblem,
110111
J_damped = T(initial_damping) .* DᵀD
111112
return LevenbergMarquardtDampingCache(T(f.increase_factor), T(f.decrease_factor),
112113
T(f.min_damping), T(f.increase_factor), T(initial_damping), DᵀD, J_diag_cache,
113-
J_damped, f)
114+
J_damped, f, T(initial_damping))
114115
end
115116

116117
(damping::LevenbergMarquardtDampingCache)(::Nothing) = damping.J_damped

test/core/23_test_problems.jl renamed to test/core/23_test_problems_tests.jl

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using NonlinearSolve, LinearAlgebra, LinearSolve, NonlinearProblemLibrary, XUnit
1+
@testsetup module RobustnessTesting
2+
using NonlinearSolve, LinearAlgebra, LinearSolve, NonlinearProblemLibrary, Test
23

34
problems = NonlinearProblemLibrary.problems
45
dicts = NonlinearProblemLibrary.dicts
@@ -36,7 +37,10 @@ function test_on_library(problems, dicts, alg_ops, broken_tests, ϵ = 1e-4;
3637
end
3738
end
3839

39-
@testcase "NewtonRaphson 23 Test Problems" begin
40+
export test_on_library, problems, dicts
41+
end
42+
43+
@testitem "NewtonRaphson" setup=[RobustnessTesting] begin
4044
alg_ops = (NewtonRaphson(),)
4145

4246
broken_tests = Dict(alg => Int[] for alg in alg_ops)
@@ -45,7 +49,7 @@ end
4549
test_on_library(problems, dicts, alg_ops, broken_tests)
4650
end
4751

48-
@testcase "TrustRegion 23 Test Problems" begin
52+
@testitem "TrustRegion" setup=[RobustnessTesting] begin
4953
alg_ops = (TrustRegion(; radius_update_scheme = RadiusUpdateSchemes.Simple),
5054
TrustRegion(; radius_update_scheme = RadiusUpdateSchemes.Fan),
5155
TrustRegion(; radius_update_scheme = RadiusUpdateSchemes.Hei),
@@ -64,7 +68,9 @@ end
6468
test_on_library(problems, dicts, alg_ops, broken_tests)
6569
end
6670

67-
@testcase "LevenbergMarquardt 23 Test Problems" begin
71+
@testitem "LevenbergMarquardt" setup=[RobustnessTesting] begin
72+
using LinearSolve
73+
6874
alg_ops = (LevenbergMarquardt(),
6975
LevenbergMarquardt(; α_geodesic = 0.1),
7076
LevenbergMarquardt(; linsolve = CholeskyFactorization()))
@@ -77,7 +83,7 @@ end
7783
test_on_library(problems, dicts, alg_ops, broken_tests)
7884
end
7985

80-
@testcase "DFSane 23 Test Problems" begin
86+
@testitem "DFSane" setup=[RobustnessTesting] begin
8187
alg_ops = (DFSane(),)
8288

8389
broken_tests = Dict(alg => Int[] for alg in alg_ops)
@@ -86,7 +92,7 @@ end
8692
test_on_library(problems, dicts, alg_ops, broken_tests)
8793
end
8894

89-
@testcase "Broyden 23 Test Problems" begin
95+
@testitem "Broyden" setup=[RobustnessTesting] begin
9096
alg_ops = (Broyden(),
9197
Broyden(; init_jacobian = Val(:true_jacobian)),
9298
Broyden(; update_rule = Val(:bad_broyden)),
@@ -101,7 +107,7 @@ end
101107
test_on_library(problems, dicts, alg_ops, broken_tests)
102108
end
103109

104-
@testcase "Klement 23 Test Problems" begin
110+
@testitem "Klement" setup=[RobustnessTesting] begin
105111
alg_ops = (Klement(), Klement(; init_jacobian = Val(:true_jacobian_diagonal)))
106112

107113
broken_tests = Dict(alg => Int[] for alg in alg_ops)
@@ -111,7 +117,7 @@ end
111117
test_on_library(problems, dicts, alg_ops, broken_tests)
112118
end
113119

114-
@testcase "PseudoTransient 23 Test Problems" begin
120+
@testitem "PseudoTransient" setup=[RobustnessTesting] begin
115121
# PT relies on the root being a stable equilibrium for convergence, so it won't work on
116122
# most problems
117123
alg_ops = (PseudoTransient(),)

test/core/forward_ad.jl renamed to test/core/forward_ad_tests.jl

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
using ForwardDiff,
2-
NonlinearSolve, MINPACK, NLsolve, StaticArrays, Sundials, XUnit, LinearAlgebra
1+
@testsetup module ForwardADTesting
2+
using Reexport, NonlinearSolve
3+
@reexport using ForwardDiff, MINPACK, NLsolve, StaticArrays, Sundials, LinearAlgebra
34

45
test_f!(du, u, p) = (@. du = u^2 - p)
56
test_f(u, p) = (@. u^2 - p)
@@ -58,50 +59,55 @@ __compatible(::NLsolveJL, ::Val{:oop_cache}) = false
5859
__compatible(::KINSOL, ::Val{:iip_cache}) = false
5960
__compatible(::KINSOL, ::Val{:oop_cache}) = false
6061

61-
@testcase "ForwardDiff.jl Integration: $(alg)" for alg in (NewtonRaphson(), TrustRegion(),
62-
LevenbergMarquardt(), PseudoTransient(; alpha_initial = 10.0), Broyden(), Klement(),
63-
DFSane(), nothing, NLsolveJL(), CMINPACK(),
64-
KINSOL(; globalization_strategy = :LineSearch))
65-
us = (2.0, @SVector[1.0, 1.0], [1.0, 1.0], ones(2, 2), @SArray ones(2, 2))
62+
export test_f!, test_f, jacobian_f, solve_with, __compatible
63+
end
64+
65+
@testitem "ForwardDiff.jl Integration" setup=[ForwardADTesting] begin
66+
for alg in (NewtonRaphson(), TrustRegion(),
67+
LevenbergMarquardt(), PseudoTransient(; alpha_initial = 10.0), Broyden(), Klement(),
68+
DFSane(), nothing, NLsolveJL(), CMINPACK(),
69+
KINSOL(; globalization_strategy = :LineSearch))
70+
us = (2.0, @SVector[1.0, 1.0], [1.0, 1.0], ones(2, 2), @SArray ones(2, 2))
6671

67-
@testset "Scalar AD" begin
68-
for p in 1.0:0.1:100.0, u0 in us, mode in (:iip, :oop, :iip_cache, :oop_cache)
69-
__compatible(u0, alg) || continue
70-
__compatible(u0, Val(mode)) || continue
71-
__compatible(alg, Val(mode)) || continue
72+
@testset "Scalar AD" begin
73+
for p in 1.0:0.1:100.0, u0 in us, mode in (:iip, :oop, :iip_cache, :oop_cache)
74+
__compatible(u0, alg) || continue
75+
__compatible(u0, Val(mode)) || continue
76+
__compatible(alg, Val(mode)) || continue
7277

73-
sol = solve(NonlinearProblem(test_f, u0, p), alg)
74-
if SciMLBase.successful_retcode(sol)
75-
gs = abs.(ForwardDiff.derivative(solve_with(Val{mode}(), u0, alg), p))
76-
gs_true = abs.(jacobian_f(u0, p))
77-
if !(isapprox(gs, gs_true, atol = 1e-5))
78-
@show sol.retcode, sol.u
79-
@error "ForwardDiff Failed for u0=$(u0) and p=$(p) with $(alg)" forwardiff_gradient=gs true_gradient=gs_true
80-
else
81-
@test abs.(gs)abs.(gs_true) atol=1e-5
78+
sol = solve(NonlinearProblem(test_f, u0, p), alg)
79+
if SciMLBase.successful_retcode(sol)
80+
gs = abs.(ForwardDiff.derivative(solve_with(Val{mode}(), u0, alg), p))
81+
gs_true = abs.(jacobian_f(u0, p))
82+
if !(isapprox(gs, gs_true, atol = 1e-5))
83+
@show sol.retcode, sol.u
84+
@error "ForwardDiff Failed for u0=$(u0) and p=$(p) with $(alg)" forwardiff_gradient=gs true_gradient=gs_true
85+
else
86+
@test abs.(gs)abs.(gs_true) atol=1e-5
87+
end
8288
end
8389
end
8490
end
85-
end
8691

87-
@testset "Jacobian" begin
88-
for u0 in us, p in ([2.0, 1.0], [2.0 1.0; 3.0 4.0]),
89-
mode in (:iip, :oop, :iip_cache, :oop_cache)
92+
@testset "Jacobian" begin
93+
for u0 in us, p in ([2.0, 1.0], [2.0 1.0; 3.0 4.0]),
94+
mode in (:iip, :oop, :iip_cache, :oop_cache)
9095

91-
__compatible(u0, p) || continue
92-
__compatible(u0, alg) || continue
93-
__compatible(u0, Val(mode)) || continue
94-
__compatible(alg, Val(mode)) || continue
96+
__compatible(u0, p) || continue
97+
__compatible(u0, alg) || continue
98+
__compatible(u0, Val(mode)) || continue
99+
__compatible(alg, Val(mode)) || continue
95100

96-
sol = solve(NonlinearProblem(test_f, u0, p), alg)
97-
if SciMLBase.successful_retcode(sol)
98-
gs = abs.(ForwardDiff.jacobian(solve_with(Val{mode}(), u0, alg), p))
99-
gs_true = abs.(jacobian_f(u0, p))
100-
if !(isapprox(gs, gs_true, atol = 1e-5))
101-
@show sol.retcode, sol.u
102-
@error "ForwardDiff Failed for u0=$(u0) and p=$(p) with $(alg)" forwardiff_jacobian=gs true_jacobian=gs_true
103-
else
104-
@test abs.(gs)abs.(gs_true) atol=1e-5
101+
sol = solve(NonlinearProblem(test_f, u0, p), alg)
102+
if SciMLBase.successful_retcode(sol)
103+
gs = abs.(ForwardDiff.jacobian(solve_with(Val{mode}(), u0, alg), p))
104+
gs_true = abs.(jacobian_f(u0, p))
105+
if !(isapprox(gs, gs_true, atol = 1e-5))
106+
@show sol.retcode, sol.u
107+
@error "ForwardDiff Failed for u0=$(u0) and p=$(p) with $(alg)" forwardiff_jacobian=gs true_jacobian=gs_true
108+
else
109+
@test abs.(gs)abs.(gs_true) atol=1e-5
110+
end
105111
end
106112
end
107113
end

test/core/nlls.jl renamed to test/core/nlls_tests.jl

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
using NonlinearSolve,
2-
LinearSolve, LinearAlgebra, XUnit, StableRNGs, Random, ForwardDiff, Zygote
1+
@testsetup module CoreNLLSTesting
2+
using Reexport
3+
@reexport using NonlinearSolve,
4+
LinearSolve, LinearAlgebra, StableRNGs, Random, ForwardDiff, Zygote
35

46
true_function(x, θ) = @. θ[1] * exp(θ[2] * x) * cos(θ[3] * x + θ[4])
57
true_function(y, x, θ) = (@. y = θ[1] * exp(θ[2] * x) * cos(θ[3] * x + θ[4]))
@@ -22,11 +24,6 @@ function loss_function(resid, θ, p)
2224
end
2325

2426
θ_init = θ_true .+ randn!(StableRNG(0), similar(θ_true)) * 0.1
25-
prob_oop = NonlinearLeastSquaresProblem{false}(loss_function, θ_init, x)
26-
prob_iip = NonlinearLeastSquaresProblem(NonlinearFunction(loss_function;
27-
resid_prototype = zero(y_target)), θ_init, x)
28-
29-
nlls_problems = [prob_oop, prob_iip]
3027

3128
solvers = []
3229
for linsolve in [nothing, LUFactorization(), KrylovJL_GMRES(), KrylovJL_LSMR()]
@@ -52,36 +49,45 @@ for radius_update_scheme in [RadiusUpdateSchemes.Simple, RadiusUpdateSchemes.Noc
5249
push!(solvers, TrustRegion(; radius_update_scheme))
5350
end
5451

55-
@testcase "General NLLS Solvers" begin
52+
export solvers, θ_init, x, y_target, true_function, θ_true, loss_function
53+
end
54+
55+
@testitem "General NLLS Solvers" setup=[CoreNLLSTesting] begin
56+
prob_oop = NonlinearLeastSquaresProblem{false}(loss_function, θ_init, x)
57+
prob_iip = NonlinearLeastSquaresProblem(NonlinearFunction(loss_function;
58+
resid_prototype = zero(y_target)), θ_init, x)
59+
60+
nlls_problems = [prob_oop, prob_iip]
61+
5662
for prob in nlls_problems, solver in solvers
5763
sol = solve(prob, solver; maxiters = 10000, abstol = 1e-8)
5864
@test SciMLBase.successful_retcode(sol)
5965
@test maximum(abs, sol.resid) < 1e-6
6066
end
6167
end
6268

63-
# This is just for testing that we can use vjp provided by the user
64-
function vjp(v, θ, p)
65-
resid = zeros(length(p))
66-
J = ForwardDiff.jacobian((resid, θ) -> loss_function(resid, θ, p), resid, θ)
67-
return vec(v' * J)
68-
end
69+
@testitem "Custom VJP" setup=[CoreNLLSTesting] begin
70+
# This is just for testing that we can use vjp provided by the user
71+
function vjp(v, θ, p)
72+
resid = zeros(length(p))
73+
J = ForwardDiff.jacobian((resid, θ) -> loss_function(resid, θ, p), resid, θ)
74+
return vec(v' * J)
75+
end
6976

70-
function vjp!(Jv, v, θ, p)
71-
resid = zeros(length(p))
72-
J = ForwardDiff.jacobian((resid, θ) -> loss_function(resid, θ, p), resid, θ)
73-
mul!(vec(Jv), transpose(J), v)
74-
return nothing
75-
end
77+
function vjp!(Jv, v, θ, p)
78+
resid = zeros(length(p))
79+
J = ForwardDiff.jacobian((resid, θ) -> loss_function(resid, θ, p), resid, θ)
80+
mul!(vec(Jv), transpose(J), v)
81+
return nothing
82+
end
7683

77-
probs = [
78-
NonlinearLeastSquaresProblem(NonlinearFunction{true}(loss_function;
79-
resid_prototype = zero(y_target), vjp = vjp!), θ_init, x),
80-
NonlinearLeastSquaresProblem(NonlinearFunction{false}(loss_function;
81-
resid_prototype = zero(y_target), vjp = vjp), θ_init, x),
82-
]
84+
probs = [
85+
NonlinearLeastSquaresProblem(NonlinearFunction{true}(loss_function;
86+
resid_prototype = zero(y_target), vjp = vjp!), θ_init, x),
87+
NonlinearLeastSquaresProblem(NonlinearFunction{false}(loss_function;
88+
resid_prototype = zero(y_target), vjp = vjp), θ_init, x),
89+
]
8390

84-
@testcase "Custom VJP" begin
8591
for prob in probs, solver in solvers
8692
sol = solve(prob, solver; maxiters = 10000, abstol = 1e-8)
8793
@test maximum(abs, sol.resid) < 1e-6

0 commit comments

Comments
 (0)