From c1e9eafef62d779093dd89dbfb2e2b7c381ff974 Mon Sep 17 00:00:00 2001 From: Avik Pal Date: Thu, 8 Feb 2024 21:44:23 -0500 Subject: [PATCH] Distributed Testing using ReTestItems --- .github/workflows/CI.yml | 4 +- Project.toml | 9 +- ..._problems.jl => 23_test_problems_tests.jl} | 22 ++-- .../{forward_ad.jl => forward_ad_tests.jl} | 82 +++++++------ test/core/{nlls.jl => nlls_tests.jl} | 60 +++++----- test/core/{rootfind.jl => rootfind_tests.jl} | 29 +++-- test/gpu/Project.toml | 2 +- test/gpu/core.jl | 49 ++++---- test/misc/banded_matrices.jl | 9 -- test/misc/banded_matrices_tests.jl | 8 ++ test/misc/bruss.jl | 76 ------------ test/misc/bruss_tests.jl | 76 ++++++++++++ test/misc/matrix_resizing.jl | 25 ---- test/misc/matrix_resizing_tests.jl | 31 +++++ test/misc/{polyalgs.jl => polyalg_tests.jl} | 69 ++++++----- test/misc/{qa.jl => qa_tests.jl} | 4 +- test/runtests.jl | 29 ++--- .../{fixedpoint.jl => fixedpoint_tests.jl} | 11 +- test/wrappers/nlls.jl | 105 ----------------- test/wrappers/nlls_tests.jl | 111 ++++++++++++++++++ .../{rootfind.jl => rootfind_tests.jl} | 10 +- 21 files changed, 435 insertions(+), 386 deletions(-) rename test/core/{23_test_problems.jl => 23_test_problems_tests.jl} (88%) rename test/core/{forward_ad.jl => forward_ad_tests.jl} (50%) rename test/core/{nlls.jl => nlls_tests.jl} (57%) rename test/core/{rootfind.jl => rootfind_tests.jl} (96%) delete mode 100644 test/misc/banded_matrices.jl create mode 100644 test/misc/banded_matrices_tests.jl delete mode 100644 test/misc/bruss.jl create mode 100644 test/misc/bruss_tests.jl delete mode 100644 test/misc/matrix_resizing.jl create mode 100644 test/misc/matrix_resizing_tests.jl rename test/misc/{polyalgs.jl => polyalg_tests.jl} (76%) rename test/misc/{qa.jl => qa_tests.jl} (90%) rename test/wrappers/{fixedpoint.jl => fixedpoint_tests.jl} (92%) delete mode 100644 test/wrappers/nlls.jl create mode 100644 test/wrappers/nlls_tests.jl rename test/wrappers/{rootfind.jl => rootfind_tests.jl} (92%) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 5fb920004..6f59b6b2b 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -44,7 +44,9 @@ jobs: - uses: julia-actions/julia-runtest@v1 env: GROUP: ${{ matrix.group }} - JULIA_NUM_THREADS: 8 + JULIA_NUM_THREADS: 11 + RETESTITEMS_NWORKERS: 4 + RETESTITEMS_NWORKER_THREADS: 2 - uses: julia-actions/julia-processcoverage@v1 with: directories: src,ext diff --git a/Project.toml b/Project.toml index fd602834a..ff61a9212 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "NonlinearSolve" uuid = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" authors = ["SciML"] -version = "3.5.3" +version = "3.5.4" [deps] ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" @@ -84,6 +84,7 @@ PrecompileTools = "1.2" Preferences = "1.4" Printf = "1.10" Random = "1.91" +ReTestItems = "1" RecursiveArrayTools = "3.4" Reexport = "1.2" SIAMFANLEquations = "1.0.1" @@ -101,7 +102,6 @@ Symbolics = "5.13" Test = "1.10" TimerOutputs = "0.5.23" Zygote = "0.6.67" -XUnit = "1.1" julia = "1.10" [extras] @@ -123,6 +123,8 @@ NonlinearProblemLibrary = "b7050fa9-e91f-4b37-bcee-a89a063da141" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +ReTestItems = "817f1d60-ba6b-4fd5-9520-3cf149f6a823" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" SIAMFANLEquations = "084e46ad-d928-497d-ad5e-07fa361a48c4" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" SparseDiffTools = "47a9eef4-7e08-11e9-0b38-333d64bd3804" @@ -132,8 +134,7 @@ StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Sundials = "c3572dad-4567-51f8-b174-8c6c989267f4" Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -XUnit = "3e3c03f2-1a94-11e9-2981-050a4ca824ab" Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" [targets] -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"] +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"] diff --git a/test/core/23_test_problems.jl b/test/core/23_test_problems_tests.jl similarity index 88% rename from test/core/23_test_problems.jl rename to test/core/23_test_problems_tests.jl index 3146d49f5..cf6fa129f 100644 --- a/test/core/23_test_problems.jl +++ b/test/core/23_test_problems_tests.jl @@ -1,4 +1,5 @@ -using NonlinearSolve, LinearAlgebra, LinearSolve, NonlinearProblemLibrary, XUnit +@testsetup module RobustnessTesting +using NonlinearSolve, LinearAlgebra, LinearSolve, NonlinearProblemLibrary, Test problems = NonlinearProblemLibrary.problems dicts = NonlinearProblemLibrary.dicts @@ -36,7 +37,10 @@ function test_on_library(problems, dicts, alg_ops, broken_tests, ϵ = 1e-4; end end -@testcase "NewtonRaphson 23 Test Problems" begin +export test_on_library, problems, dicts +end + +@testitem "NewtonRaphson" setup=[RobustnessTesting] begin alg_ops = (NewtonRaphson(),) broken_tests = Dict(alg => Int[] for alg in alg_ops) @@ -45,7 +49,7 @@ end test_on_library(problems, dicts, alg_ops, broken_tests) end -@testcase "TrustRegion 23 Test Problems" begin +@testitem "TrustRegion" setup=[RobustnessTesting] begin alg_ops = (TrustRegion(; radius_update_scheme = RadiusUpdateSchemes.Simple), TrustRegion(; radius_update_scheme = RadiusUpdateSchemes.Fan), TrustRegion(; radius_update_scheme = RadiusUpdateSchemes.Hei), @@ -64,7 +68,9 @@ end test_on_library(problems, dicts, alg_ops, broken_tests) end -@testcase "LevenbergMarquardt 23 Test Problems" begin +@testitem "LevenbergMarquardt" setup=[RobustnessTesting] begin + using LinearSolve + alg_ops = (LevenbergMarquardt(), LevenbergMarquardt(; α_geodesic = 0.1), LevenbergMarquardt(; linsolve = CholeskyFactorization())) @@ -77,7 +83,7 @@ end test_on_library(problems, dicts, alg_ops, broken_tests) end -@testcase "DFSane 23 Test Problems" begin +@testitem "DFSane" setup=[RobustnessTesting] begin alg_ops = (DFSane(),) broken_tests = Dict(alg => Int[] for alg in alg_ops) @@ -86,7 +92,7 @@ end test_on_library(problems, dicts, alg_ops, broken_tests) end -@testcase "Broyden 23 Test Problems" begin +@testitem "Broyden" setup=[RobustnessTesting] begin alg_ops = (Broyden(), Broyden(; init_jacobian = Val(:true_jacobian)), Broyden(; update_rule = Val(:bad_broyden)), @@ -101,7 +107,7 @@ end test_on_library(problems, dicts, alg_ops, broken_tests) end -@testcase "Klement 23 Test Problems" begin +@testitem "Klement" setup=[RobustnessTesting] begin alg_ops = (Klement(), Klement(; init_jacobian = Val(:true_jacobian_diagonal))) broken_tests = Dict(alg => Int[] for alg in alg_ops) @@ -111,7 +117,7 @@ end test_on_library(problems, dicts, alg_ops, broken_tests) end -@testcase "PseudoTransient 23 Test Problems" begin +@testitem "PseudoTransient" setup=[RobustnessTesting] begin # PT relies on the root being a stable equilibrium for convergence, so it won't work on # most problems alg_ops = (PseudoTransient(),) diff --git a/test/core/forward_ad.jl b/test/core/forward_ad_tests.jl similarity index 50% rename from test/core/forward_ad.jl rename to test/core/forward_ad_tests.jl index b0b4fee03..22882cbec 100644 --- a/test/core/forward_ad.jl +++ b/test/core/forward_ad_tests.jl @@ -1,5 +1,6 @@ -using ForwardDiff, - NonlinearSolve, MINPACK, NLsolve, StaticArrays, Sundials, XUnit, LinearAlgebra +@testsetup module ForwardADTesting +using Reexport, NonlinearSolve +@reexport using ForwardDiff, MINPACK, NLsolve, StaticArrays, Sundials, LinearAlgebra test_f!(du, u, p) = (@. du = u^2 - p) test_f(u, p) = (@. u^2 - p) @@ -58,50 +59,55 @@ __compatible(::NLsolveJL, ::Val{:oop_cache}) = false __compatible(::KINSOL, ::Val{:iip_cache}) = false __compatible(::KINSOL, ::Val{:oop_cache}) = false -@testcase "ForwardDiff.jl Integration: $(alg)" for alg in (NewtonRaphson(), TrustRegion(), - LevenbergMarquardt(), PseudoTransient(; alpha_initial = 10.0), Broyden(), Klement(), - DFSane(), nothing, NLsolveJL(), CMINPACK(), - KINSOL(; globalization_strategy = :LineSearch)) - us = (2.0, @SVector[1.0, 1.0], [1.0, 1.0], ones(2, 2), @SArray ones(2, 2)) +export test_f!, test_f, jacobian_f, solve_with, __compatible +end + +@testitem "ForwardDiff.jl Integration" setup=[ForwardADTesting] begin + for alg in (NewtonRaphson(), TrustRegion(), + LevenbergMarquardt(), PseudoTransient(; alpha_initial = 10.0), Broyden(), Klement(), + DFSane(), nothing, NLsolveJL(), CMINPACK(), + KINSOL(; globalization_strategy = :LineSearch)) + us = (2.0, @SVector[1.0, 1.0], [1.0, 1.0], ones(2, 2), @SArray ones(2, 2)) - @testset "Scalar AD" begin - for p in 1.0:0.1:100.0, u0 in us, mode in (:iip, :oop, :iip_cache, :oop_cache) - __compatible(u0, alg) || continue - __compatible(u0, Val(mode)) || continue - __compatible(alg, Val(mode)) || continue + @testset "Scalar AD" begin + for p in 1.0:0.1:100.0, u0 in us, mode in (:iip, :oop, :iip_cache, :oop_cache) + __compatible(u0, alg) || continue + __compatible(u0, Val(mode)) || continue + __compatible(alg, Val(mode)) || continue - sol = solve(NonlinearProblem(test_f, u0, p), alg) - if SciMLBase.successful_retcode(sol) - gs = abs.(ForwardDiff.derivative(solve_with(Val{mode}(), u0, alg), p)) - gs_true = abs.(jacobian_f(u0, p)) - if !(isapprox(gs, gs_true, atol = 1e-5)) - @show sol.retcode, sol.u - @error "ForwardDiff Failed for u0=$(u0) and p=$(p) with $(alg)" forwardiff_gradient=gs true_gradient=gs_true - else - @test abs.(gs)≈abs.(gs_true) atol=1e-5 + sol = solve(NonlinearProblem(test_f, u0, p), alg) + if SciMLBase.successful_retcode(sol) + gs = abs.(ForwardDiff.derivative(solve_with(Val{mode}(), u0, alg), p)) + gs_true = abs.(jacobian_f(u0, p)) + if !(isapprox(gs, gs_true, atol = 1e-5)) + @show sol.retcode, sol.u + @error "ForwardDiff Failed for u0=$(u0) and p=$(p) with $(alg)" forwardiff_gradient=gs true_gradient=gs_true + else + @test abs.(gs)≈abs.(gs_true) atol=1e-5 + end end end end - end - @testset "Jacobian" begin - for u0 in us, p in ([2.0, 1.0], [2.0 1.0; 3.0 4.0]), - mode in (:iip, :oop, :iip_cache, :oop_cache) + @testset "Jacobian" begin + for u0 in us, p in ([2.0, 1.0], [2.0 1.0; 3.0 4.0]), + mode in (:iip, :oop, :iip_cache, :oop_cache) - __compatible(u0, p) || continue - __compatible(u0, alg) || continue - __compatible(u0, Val(mode)) || continue - __compatible(alg, Val(mode)) || continue + __compatible(u0, p) || continue + __compatible(u0, alg) || continue + __compatible(u0, Val(mode)) || continue + __compatible(alg, Val(mode)) || continue - sol = solve(NonlinearProblem(test_f, u0, p), alg) - if SciMLBase.successful_retcode(sol) - gs = abs.(ForwardDiff.jacobian(solve_with(Val{mode}(), u0, alg), p)) - gs_true = abs.(jacobian_f(u0, p)) - if !(isapprox(gs, gs_true, atol = 1e-5)) - @show sol.retcode, sol.u - @error "ForwardDiff Failed for u0=$(u0) and p=$(p) with $(alg)" forwardiff_jacobian=gs true_jacobian=gs_true - else - @test abs.(gs)≈abs.(gs_true) atol=1e-5 + sol = solve(NonlinearProblem(test_f, u0, p), alg) + if SciMLBase.successful_retcode(sol) + gs = abs.(ForwardDiff.jacobian(solve_with(Val{mode}(), u0, alg), p)) + gs_true = abs.(jacobian_f(u0, p)) + if !(isapprox(gs, gs_true, atol = 1e-5)) + @show sol.retcode, sol.u + @error "ForwardDiff Failed for u0=$(u0) and p=$(p) with $(alg)" forwardiff_jacobian=gs true_jacobian=gs_true + else + @test abs.(gs)≈abs.(gs_true) atol=1e-5 + end end end end diff --git a/test/core/nlls.jl b/test/core/nlls_tests.jl similarity index 57% rename from test/core/nlls.jl rename to test/core/nlls_tests.jl index daddc9f3f..1720d77fa 100644 --- a/test/core/nlls.jl +++ b/test/core/nlls_tests.jl @@ -1,5 +1,7 @@ -using NonlinearSolve, - LinearSolve, LinearAlgebra, XUnit, StableRNGs, Random, ForwardDiff, Zygote +@testsetup module CoreNLLSTesting +using Reexport +@reexport using NonlinearSolve, + LinearSolve, LinearAlgebra, StableRNGs, Random, ForwardDiff, Zygote true_function(x, θ) = @. θ[1] * exp(θ[2] * x) * cos(θ[3] * x + θ[4]) true_function(y, x, θ) = (@. y = θ[1] * exp(θ[2] * x) * cos(θ[3] * x + θ[4])) @@ -22,11 +24,6 @@ function loss_function(resid, θ, p) end θ_init = θ_true .+ randn!(StableRNG(0), similar(θ_true)) * 0.1 -prob_oop = NonlinearLeastSquaresProblem{false}(loss_function, θ_init, x) -prob_iip = NonlinearLeastSquaresProblem(NonlinearFunction(loss_function; - resid_prototype = zero(y_target)), θ_init, x) - -nlls_problems = [prob_oop, prob_iip] solvers = [] for linsolve in [nothing, LUFactorization(), KrylovJL_GMRES(), KrylovJL_LSMR()] @@ -52,7 +49,16 @@ for radius_update_scheme in [RadiusUpdateSchemes.Simple, RadiusUpdateSchemes.Noc push!(solvers, TrustRegion(; radius_update_scheme)) end -@testcase "General NLLS Solvers" begin +export solvers, θ_init, x, y_target, true_function, θ_true, loss_function +end + +@testitem "General NLLS Solvers" setup=[CoreNLLSTesting] begin + prob_oop = NonlinearLeastSquaresProblem{false}(loss_function, θ_init, x) + prob_iip = NonlinearLeastSquaresProblem(NonlinearFunction(loss_function; + resid_prototype = zero(y_target)), θ_init, x) + + nlls_problems = [prob_oop, prob_iip] + for prob in nlls_problems, solver in solvers sol = solve(prob, solver; maxiters = 10000, abstol = 1e-8) @test SciMLBase.successful_retcode(sol) @@ -60,28 +66,28 @@ end end end -# This is just for testing that we can use vjp provided by the user -function vjp(v, θ, p) - resid = zeros(length(p)) - J = ForwardDiff.jacobian((resid, θ) -> loss_function(resid, θ, p), resid, θ) - return vec(v' * J) -end +@testitem "Custom VJP" setup=[CoreNLLSTesting] begin + # This is just for testing that we can use vjp provided by the user + function vjp(v, θ, p) + resid = zeros(length(p)) + J = ForwardDiff.jacobian((resid, θ) -> loss_function(resid, θ, p), resid, θ) + return vec(v' * J) + end -function vjp!(Jv, v, θ, p) - resid = zeros(length(p)) - J = ForwardDiff.jacobian((resid, θ) -> loss_function(resid, θ, p), resid, θ) - mul!(vec(Jv), transpose(J), v) - return nothing -end + function vjp!(Jv, v, θ, p) + resid = zeros(length(p)) + J = ForwardDiff.jacobian((resid, θ) -> loss_function(resid, θ, p), resid, θ) + mul!(vec(Jv), transpose(J), v) + return nothing + end -probs = [ - NonlinearLeastSquaresProblem(NonlinearFunction{true}(loss_function; - resid_prototype = zero(y_target), vjp = vjp!), θ_init, x), - NonlinearLeastSquaresProblem(NonlinearFunction{false}(loss_function; - resid_prototype = zero(y_target), vjp = vjp), θ_init, x), -] + probs = [ + NonlinearLeastSquaresProblem(NonlinearFunction{true}(loss_function; + resid_prototype = zero(y_target), vjp = vjp!), θ_init, x), + NonlinearLeastSquaresProblem(NonlinearFunction{false}(loss_function; + resid_prototype = zero(y_target), vjp = vjp), θ_init, x), + ] -@testcase "Custom VJP" begin for prob in probs, solver in solvers sol = solve(prob, solver; maxiters = 10000, abstol = 1e-8) @test maximum(abs, sol.resid) < 1e-6 diff --git a/test/core/rootfind.jl b/test/core/rootfind_tests.jl similarity index 96% rename from test/core/rootfind.jl rename to test/core/rootfind_tests.jl index d6e36ade9..412d7f1ac 100644 --- a/test/core/rootfind.jl +++ b/test/core/rootfind_tests.jl @@ -1,5 +1,7 @@ -using BenchmarkTools, LinearSolve, NonlinearSolve, StaticArrays, Random, LinearAlgebra, - XUnit, ForwardDiff, Zygote, Enzyme, SparseDiffTools, DiffEqBase +@testsetup module CoreRootfindTesting +using Reexport +@reexport using BenchmarkTools, LinearSolve, NonlinearSolve, StaticArrays, Random, + LinearAlgebra, ForwardDiff, Zygote, Enzyme, SparseDiffTools, DiffEqBase function __autosparseenzyme() @static if Sys.iswindows() @@ -57,9 +59,14 @@ function nlprob_iterator_interface(f, p_range, ::Val{iip}, solver) where {iip} return sols end +export nlprob_iterator_interface, benchmark_nlsolve_oop, benchmark_nlsolve_iip, + TERMINATION_CONDITIONS, _nameof, newton_fails, quadratic_f, quadratic_f!, + __autosparseenzyme +end + # --- NewtonRaphson tests --- -@testcase "NewtonRaphson" begin +@testitem "NewtonRaphson" setup=[CoreRootfindTesting] begin @testset "LineSearch: $(_nameof(lsmethod)) LineSearch AD: $(_nameof(ad))" for lsmethod in (Static(), StrongWolfe(), BackTracking(), HagerZhang(), MoreThuente()), ad in (AutoFiniteDiff(), AutoZygote()) @@ -121,7 +128,7 @@ end # --- TrustRegion tests --- -@testcase "TrustRegion" begin +@testitem "TrustRegion" setup=[CoreRootfindTesting] begin radius_update_schemes = [RadiusUpdateSchemes.Simple, RadiusUpdateSchemes.NocedalWright, RadiusUpdateSchemes.NLsolve, RadiusUpdateSchemes.Hei, RadiusUpdateSchemes.Yuan, RadiusUpdateSchemes.Fan, RadiusUpdateSchemes.Bastin] @@ -233,7 +240,7 @@ end # --- LevenbergMarquardt tests --- -@testcase "LevenbergMarquardt" begin +@testitem "LevenbergMarquardt" setup=[CoreRootfindTesting] begin u0s = ([1.0, 1.0], @SVector[1.0, 1.0], 1.0) @testset "[OOP] u0: $(typeof(u0))" for u0 in u0s sol = benchmark_nlsolve_oop(quadratic_f, u0; solver = LevenbergMarquardt()) @@ -315,7 +322,7 @@ end # --- DFSane tests --- -@testcase "DFSane" begin +@testitem "DFSane" setup=[CoreRootfindTesting] begin u0s = ([1.0, 1.0], @SVector[1.0, 1.0], 1.0) @testset "[OOP] u0: $(typeof(u0))" for u0 in u0s @@ -391,7 +398,7 @@ end # --- PseudoTransient tests --- -@testcase "PseudoTransient" begin +@testitem "PseudoTransient" setup=[CoreRootfindTesting] begin # These are tests for NewtonRaphson so we should set alpha_initial to be high so that we # converge quickly @testset "PT: alpha_initial = 10.0 PT AD: $(ad)" for ad in (AutoFiniteDiff(), @@ -453,7 +460,7 @@ end # --- Broyden tests --- -@testcase "Broyden" begin +@testitem "Broyden" setup=[CoreRootfindTesting] begin @testset "LineSearch: $(_nameof(lsmethod)) LineSearch AD: $(_nameof(ad)) Init Jacobian: $(init_jacobian) Update Rule: $(update_rule)" for lsmethod in (Static(), StrongWolfe(), BackTracking(), HagerZhang(), MoreThuente(), LiFukushimaLineSearch()), @@ -503,7 +510,7 @@ end # --- Klement tests --- -@testcase "Klement" begin +@testitem "Klement" setup=[CoreRootfindTesting] begin @testset "LineSearch: $(_nameof(lsmethod)) LineSearch AD: $(_nameof(ad)) Init Jacobian: $(init_jacobian)" for lsmethod in (Static(), StrongWolfe(), BackTracking(), HagerZhang(), MoreThuente()), ad in (AutoFiniteDiff(), AutoZygote()), @@ -552,7 +559,7 @@ end # --- LimitedMemoryBroyden tests --- -@testcase "LimitedMemoryBroyden" begin +@testitem "LimitedMemoryBroyden" setup=[CoreRootfindTesting] begin @testset "LineSearch: $(_nameof(lsmethod)) LineSearch AD: $(_nameof(ad))" for lsmethod in (Static(), StrongWolfe(), BackTracking(), HagerZhang(), MoreThuente(), LiFukushimaLineSearch()), @@ -602,7 +609,7 @@ end end # Miscellaneous Tests -@testcase "Custom JVP" begin +@testitem "Custom JVP" setup=[CoreRootfindTesting] begin function F(u::Vector{Float64}, p::Vector{Float64}) Δ = Tridiagonal(-ones(99), 2 * ones(100), -ones(99)) return u + 0.1 * u .* Δ * u - p diff --git a/test/gpu/Project.toml b/test/gpu/Project.toml index 6ec065323..5b5241a2e 100644 --- a/test/gpu/Project.toml +++ b/test/gpu/Project.toml @@ -2,5 +2,5 @@ CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" +ReTestItems = "817f1d60-ba6b-4fd5-9520-3cf149f6a823" StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3" -XUnit = "3e3c03f2-1a94-11e9-2981-050a4ca824ab" diff --git a/test/gpu/core.jl b/test/gpu/core.jl index bd4c2e4f6..074098072 100644 --- a/test/gpu/core.jl +++ b/test/gpu/core.jl @@ -1,35 +1,38 @@ -using CUDA, NonlinearSolve, LinearSolve, StableRNGs, XUnit +@testitem "CUDA Tests" begin + using CUDA, NonlinearSolve, LinearSolve, StableRNGs -CUDA.allowscalar(false) + CUDA.allowscalar(false) -A = cu(rand(StableRNG(0), 4, 4)) -u0 = cu(rand(StableRNG(0), 4)) -b = cu(rand(StableRNG(0), 4)) + A = cu(rand(StableRNG(0), 4, 4)) + u0 = cu(rand(StableRNG(0), 4)) + b = cu(rand(StableRNG(0), 4)) -linear_f(du, u, p) = (du .= A * u .+ b) + linear_f(du, u, p) = (du .= A * u .+ b) -prob = NonlinearProblem(linear_f, u0) + prob = NonlinearProblem(linear_f, u0) -SOLVERS = (NewtonRaphson(), LevenbergMarquardt(; linsolve = QRFactorization()), - LevenbergMarquardt(; linsolve = KrylovJL_GMRES()), PseudoTransient(), Klement(), - Broyden(; linesearch = LiFukushimaLineSearch()), - LimitedMemoryBroyden(; threshold = 2, linesearch = LiFukushimaLineSearch()), - DFSane(), TrustRegion(; linsolve = QRFactorization()), - TrustRegion(; linsolve = KrylovJL_GMRES(), concrete_jac = true), # Needed if Zygote not loaded - nothing) + SOLVERS = (NewtonRaphson(), LevenbergMarquardt(; linsolve = QRFactorization()), + LevenbergMarquardt(; linsolve = KrylovJL_GMRES()), PseudoTransient(), Klement(), + Broyden(; linesearch = LiFukushimaLineSearch()), + LimitedMemoryBroyden(; threshold = 2, linesearch = LiFukushimaLineSearch()), + DFSane(), TrustRegion(; linsolve = QRFactorization()), + TrustRegion(; linsolve = KrylovJL_GMRES(), + concrete_jac = true), # Needed if Zygote not loaded + nothing) -@testcase "[IIP] GPU Solvers" begin - for alg in SOLVERS - @test_nowarn sol = solve(prob, alg; abstol = 1.0f-5, reltol = 1.0f-5) + @testset "[IIP] GPU Solvers" begin + for alg in SOLVERS + @test_nowarn sol = solve(prob, alg; abstol = 1.0f-5, reltol = 1.0f-5) + end end -end -linear_f(u, p) = A * u .+ b + linear_f(u, p) = A * u .+ b -prob = NonlinearProblem{false}(linear_f, u0) + prob = NonlinearProblem{false}(linear_f, u0) -@testcase "[OOP] GPU Solvers" begin - for alg in SOLVERS - @test_nowarn sol = solve(prob, alg; abstol = 1.0f-5, reltol = 1.0f-5) + @testset "[OOP] GPU Solvers" begin + for alg in SOLVERS + @test_nowarn sol = solve(prob, alg; abstol = 1.0f-5, reltol = 1.0f-5) + end end end diff --git a/test/misc/banded_matrices.jl b/test/misc/banded_matrices.jl deleted file mode 100644 index ff5951089..000000000 --- a/test/misc/banded_matrices.jl +++ /dev/null @@ -1,9 +0,0 @@ -# Miscellaneous Tests -using BandedMatrices, LinearAlgebra, NonlinearSolve, SparseArrays, XUnit - -b = BandedMatrix(Ones(5, 5), (1, 1)) -d = Diagonal(ones(5, 5)) - -@testcase "BandedMatrix vcat" begin - @test NonlinearSolve._vcat(b, d) == vcat(sparse(b), d) -end diff --git a/test/misc/banded_matrices_tests.jl b/test/misc/banded_matrices_tests.jl new file mode 100644 index 000000000..d4b8fbee5 --- /dev/null +++ b/test/misc/banded_matrices_tests.jl @@ -0,0 +1,8 @@ +@testitem "Banded Matrix vcat" begin + using BandedMatrices, LinearAlgebra, SparseArrays + + b = BandedMatrix(Ones(5, 5), (1, 1)) + d = Diagonal(ones(5, 5)) + + @test NonlinearSolve._vcat(b, d) == vcat(sparse(b), d) +end diff --git a/test/misc/bruss.jl b/test/misc/bruss.jl deleted file mode 100644 index 25dd3b026..000000000 --- a/test/misc/bruss.jl +++ /dev/null @@ -1,76 +0,0 @@ -using NonlinearSolve, LinearAlgebra, SparseArrays, Symbolics, XUnit - -const N = 32 -const xyd_brusselator = range(0, stop = 1, length = N) - -brusselator_f(x, y) = (((x - 0.3)^2 + (y - 0.6)^2) <= 0.1^2) * 5.0 -limit(a, N) = a == N + 1 ? 1 : a == 0 ? N : a - -function brusselator_2d_loop(du, u, p) - A, B, alpha, dx = p - alpha = alpha / dx^2 - @inbounds for I in CartesianIndices((N, N)) - i, j = Tuple(I) - x, y = xyd_brusselator[I[1]], xyd_brusselator[I[2]] - ip1, im1, jp1, jm1 = limit(i + 1, N), limit(i - 1, N), limit(j + 1, N), - limit(j - 1, N) - du[i, j, 1] = alpha * (u[im1, j, 1] + u[ip1, j, 1] + u[i, jp1, 1] + u[i, jm1, 1] - - 4u[i, j, 1]) + - B + u[i, j, 1]^2 * u[i, j, 2] - (A + 1) * u[i, j, 1] + - brusselator_f(x, y) - du[i, j, 2] = alpha * (u[im1, j, 2] + u[ip1, j, 2] + u[i, jp1, 2] + u[i, jm1, 2] - - 4u[i, j, 2]) + - A * u[i, j, 1] - u[i, j, 1]^2 * u[i, j, 2] - end -end - -p = (3.4, 1.0, 10.0, step(xyd_brusselator)) - -function init_brusselator_2d(xyd) - N = length(xyd) - u = zeros(N, N, 2) - for I in CartesianIndices((N, N)) - x = xyd[I[1]] - y = xyd[I[2]] - u[I, 1] = 22 * (y * (1 - y))^(3 / 2) - u[I, 2] = 27 * (x * (1 - x))^(3 / 2) - end - return u -end - -@testcase "Brusselator" begin - u0 = init_brusselator_2d(xyd_brusselator) - prob_brusselator_2d = NonlinearProblem(brusselator_2d_loop, u0, p) - sol = solve(prob_brusselator_2d, NewtonRaphson(); abstol = 1e-8) - @test norm(sol.resid, Inf) < 1e-8 - - sol = solve(prob_brusselator_2d, NewtonRaphson(autodiff = AutoSparseForwardDiff()); - abstol = 1e-8) - @test norm(sol.resid, Inf) < 1e-8 - - sol = solve(prob_brusselator_2d, NewtonRaphson(autodiff = AutoSparseFiniteDiff()); - abstol = 1e-8) - @test norm(sol.resid, Inf) < 1e-8 - - du0 = copy(u0) - jac_sparsity = Symbolics.jacobian_sparsity((du, u) -> brusselator_2d_loop(du, u, p), - du0, u0) - jac_prototype = float.(jac_sparsity) - fill!(jac_prototype, 0) - @test all(iszero, jac_prototype) - - ff_iip = NonlinearFunction(brusselator_2d_loop; jac_prototype) - prob_brusselator_2d = NonlinearProblem(ff_iip, u0, p) - - sol = solve(prob_brusselator_2d, NewtonRaphson(); abstol = 1e-8) - @test norm(sol.resid, Inf) < 1e-8 - @test !all(iszero, jac_prototype) - - sol = solve(prob_brusselator_2d, NewtonRaphson(autodiff = AutoSparseFiniteDiff()); - abstol = 1e-8) - @test norm(sol.resid, Inf) < 1e-8 - - cache = init(prob_brusselator_2d, NewtonRaphson(; autodiff = AutoSparseForwardDiff())) - @test maximum(cache.jac_cache.jac_cache.coloring.colorvec) == 12 - @test cache.jac_cache.autodiff isa AutoSparseForwardDiff -end diff --git a/test/misc/bruss_tests.jl b/test/misc/bruss_tests.jl new file mode 100644 index 000000000..12eaa8329 --- /dev/null +++ b/test/misc/bruss_tests.jl @@ -0,0 +1,76 @@ +@testitem "Brusselator 2D" begin + using LinearAlgebra, SparseArrays, Symbolics + + const N = 32 + const xyd_brusselator = range(0, stop = 1, length = N) + + brusselator_f(x, y) = (((x - 0.3)^2 + (y - 0.6)^2) <= 0.1^2) * 5.0 + limit(a, N) = a == N + 1 ? 1 : a == 0 ? N : a + + function brusselator_2d_loop(du, u, p) + A, B, alpha, dx = p + alpha = alpha / dx^2 + @inbounds for I in CartesianIndices((N, N)) + i, j = Tuple(I) + x, y = xyd_brusselator[I[1]], xyd_brusselator[I[2]] + ip1, im1, jp1, jm1 = limit(i + 1, N), limit(i - 1, N), limit(j + 1, N), + limit(j - 1, N) + du[i, j, 1] = alpha * (u[im1, j, 1] + u[ip1, j, 1] + u[i, jp1, 1] + u[i, jm1, 1] - + 4u[i, j, 1]) + + B + u[i, j, 1]^2 * u[i, j, 2] - (A + 1) * u[i, j, 1] + + brusselator_f(x, y) + du[i, j, 2] = alpha * (u[im1, j, 2] + u[ip1, j, 2] + u[i, jp1, 2] + u[i, jm1, 2] - + 4u[i, j, 2]) + + A * u[i, j, 1] - u[i, j, 1]^2 * u[i, j, 2] + end + end + + p = (3.4, 1.0, 10.0, step(xyd_brusselator)) + + function init_brusselator_2d(xyd) + N = length(xyd) + u = zeros(N, N, 2) + for I in CartesianIndices((N, N)) + x = xyd[I[1]] + y = xyd[I[2]] + u[I, 1] = 22 * (y * (1 - y))^(3 / 2) + u[I, 2] = 27 * (x * (1 - x))^(3 / 2) + end + return u + end + + u0 = init_brusselator_2d(xyd_brusselator) + prob_brusselator_2d = NonlinearProblem(brusselator_2d_loop, u0, p) + sol = solve(prob_brusselator_2d, NewtonRaphson(); abstol = 1e-8) + @test norm(sol.resid, Inf) < 1e-8 + + sol = solve(prob_brusselator_2d, NewtonRaphson(autodiff = AutoSparseForwardDiff()); + abstol = 1e-8) + @test norm(sol.resid, Inf) < 1e-8 + + sol = solve(prob_brusselator_2d, NewtonRaphson(autodiff = AutoSparseFiniteDiff()); + abstol = 1e-8) + @test norm(sol.resid, Inf) < 1e-8 + + du0 = copy(u0) + jac_sparsity = Symbolics.jacobian_sparsity((du, u) -> brusselator_2d_loop(du, u, p), + du0, u0) + jac_prototype = float.(jac_sparsity) + fill!(jac_prototype, 0) + @test all(iszero, jac_prototype) + + ff_iip = NonlinearFunction(brusselator_2d_loop; jac_prototype) + prob_brusselator_2d = NonlinearProblem(ff_iip, u0, p) + + sol = solve(prob_brusselator_2d, NewtonRaphson(); abstol = 1e-8) + @test norm(sol.resid, Inf) < 1e-8 + @test !all(iszero, jac_prototype) + + sol = solve(prob_brusselator_2d, NewtonRaphson(autodiff = AutoSparseFiniteDiff()); + abstol = 1e-8) + @test norm(sol.resid, Inf) < 1e-8 + + cache = init(prob_brusselator_2d, NewtonRaphson(; autodiff = AutoSparseForwardDiff())) + @test maximum(cache.jac_cache.jac_cache.coloring.colorvec) == 12 + @test cache.jac_cache.autodiff isa AutoSparseForwardDiff +end diff --git a/test/misc/matrix_resizing.jl b/test/misc/matrix_resizing.jl deleted file mode 100644 index 49e07d245..000000000 --- a/test/misc/matrix_resizing.jl +++ /dev/null @@ -1,25 +0,0 @@ -using NonlinearSolve, XUnit, StableRNGs - -ff(u, p) = u .* u .- p -u0 = rand(StableRNG(0), 2, 2) -p = 2.0 -vecprob = NonlinearProblem(ff, vec(u0), p) -prob = NonlinearProblem(ff, u0, p) - -@testcase "$(alg)" for alg in (NewtonRaphson(), TrustRegion(), LevenbergMarquardt(), - PseudoTransient(), RobustMultiNewton(), FastShortcutNonlinearPolyalg(), Broyden(), - Klement(), LimitedMemoryBroyden(; threshold = 2)) - @test vec(solve(prob, alg).u) == solve(vecprob, alg).u -end - -fiip(du, u, p) = (du .= u .* u .- p) -u0 = rand(StableRNG(0), 2, 2) -p = 2.0 -vecprob = NonlinearProblem(fiip, vec(u0), p) -prob = NonlinearProblem(fiip, u0, p) - -@testcase "$(alg)" for alg in (NewtonRaphson(), TrustRegion(), LevenbergMarquardt(), - PseudoTransient(), RobustMultiNewton(), FastShortcutNonlinearPolyalg(), Broyden(), - Klement(), LimitedMemoryBroyden(; threshold = 2)) - @test vec(solve(prob, alg).u) == solve(vecprob, alg).u -end diff --git a/test/misc/matrix_resizing_tests.jl b/test/misc/matrix_resizing_tests.jl new file mode 100644 index 000000000..e13704c96 --- /dev/null +++ b/test/misc/matrix_resizing_tests.jl @@ -0,0 +1,31 @@ +@testitem "Out-of-place Matrix Resizing" begin + using StableRNGs + + ff(u, p) = u .* u .- p + u0 = rand(StableRNG(0), 2, 2) + p = 2.0 + vecprob = NonlinearProblem(ff, vec(u0), p) + prob = NonlinearProblem(ff, u0, p) + + for alg in (NewtonRaphson(), TrustRegion(), LevenbergMarquardt(), + PseudoTransient(), RobustMultiNewton(), FastShortcutNonlinearPolyalg(), Broyden(), + Klement(), LimitedMemoryBroyden(; threshold = 2)) + @test vec(solve(prob, alg).u) == solve(vecprob, alg).u + end +end + +@testitem "Inplace Matrix Resizing" begin + using StableRNGs + + fiip(du, u, p) = (du .= u .* u .- p) + u0 = rand(StableRNG(0), 2, 2) + p = 2.0 + vecprob = NonlinearProblem(fiip, vec(u0), p) + prob = NonlinearProblem(fiip, u0, p) + + for alg in (NewtonRaphson(), TrustRegion(), LevenbergMarquardt(), + PseudoTransient(), RobustMultiNewton(), FastShortcutNonlinearPolyalg(), Broyden(), + Klement(), LimitedMemoryBroyden(; threshold = 2)) + @test vec(solve(prob, alg).u) == solve(vecprob, alg).u + end +end diff --git a/test/misc/polyalgs.jl b/test/misc/polyalg_tests.jl similarity index 76% rename from test/misc/polyalgs.jl rename to test/misc/polyalg_tests.jl index 13cd8ecd4..761270c9a 100644 --- a/test/misc/polyalgs.jl +++ b/test/misc/polyalg_tests.jl @@ -1,6 +1,4 @@ -using NonlinearSolve, XUnit, NaNMath, OrdinaryDiffEq, StaticArrays, LinearAlgebra - -@testcase "Basic PolyAlgorithms" begin +@testitem "Basic PolyAlgorithms" begin f(u, p) = u .* u .- 2 u0 = [1.0, 1.0] probN = NonlinearProblem{false}(f, u0) @@ -32,7 +30,7 @@ using NonlinearSolve, XUnit, NaNMath, OrdinaryDiffEq, StaticArrays, LinearAlgebr @test SciMLBase.successful_retcode(solver) end -@testcase "Testing #153 Singular Exception" begin +@testitem "Testing #153 Singular Exception" begin # https://github.com/SciML/NonlinearSolve.jl/issues/153 function f(du, u, p) s1, s1s2, s2 = u @@ -48,7 +46,9 @@ end @test SciMLBase.successful_retcode(sol) end -@testcase "Simple Scalar Problem #187" begin +@testitem "Simple Scalar Problem #187" begin + using NaNMath + # https://github.com/SciML/NonlinearSolve.jl/issues/187 # If we use a General Nonlinear Solver the solution might go out of the domain! ff_interval(u, p) = 0.5 / 1.5 * NaNMath.log.(u ./ (1.0 .- u)) .- 2.0 * u .+ 1.0 @@ -68,7 +68,9 @@ end # Shooting Problem: Taken from BoundaryValueDiffEq.jl # Testing for Complex Valued Root Finding. For Complex valued inputs we drop some of the # algorithms which dont support those. -@testcase "Complex Valued Problems: Single-Shooting" begin +@testitem "Complex Valued Problems: Single-Shooting" begin + using OrdinaryDiffEq + function ode_func!(du, u, p, t) du[1] = u[2] du[2] = -u[1] @@ -93,31 +95,37 @@ end maxiters = 10) end -no_ad_fast = FastShortcutNonlinearPolyalg(autodiff = AutoFiniteDiff()) -no_ad_robust = RobustMultiNewton(autodiff = AutoFiniteDiff()) -no_ad_algs = Set([no_ad_fast, no_ad_robust, no_ad_fast.algs..., no_ad_robust.algs...]) -@testcase "[IIP] no AD" begin - f_iip = Base.Experimental.@opaque (du, u, p) -> du .= u .* u .- p - u0 = [0.5] - prob = NonlinearProblem(f_iip, u0, 1.0) - for alg in no_ad_algs - sol = solve(prob, alg) - @test isapprox(only(sol.u), 1.0) - @test SciMLBase.successful_retcode(sol.retcode) +@testitem "No AD" begin + no_ad_fast = FastShortcutNonlinearPolyalg(autodiff = AutoFiniteDiff()) + no_ad_robust = RobustMultiNewton(autodiff = AutoFiniteDiff()) + no_ad_algs = Set([no_ad_fast, no_ad_robust, no_ad_fast.algs..., no_ad_robust.algs...]) + + @testset "Inplace" begin + f_iip = Base.Experimental.@opaque (du, u, p) -> du .= u .* u .- p + u0 = [0.5] + prob = NonlinearProblem(f_iip, u0, 1.0) + for alg in no_ad_algs + sol = solve(prob, alg) + @test isapprox(only(sol.u), 1.0) + @test SciMLBase.successful_retcode(sol.retcode) + end end -end -@testcase "[OOP] no AD" begin - f_oop = Base.Experimental.@opaque (u, p) -> u .* u .- p - u0 = [0.5] - prob = NonlinearProblem{false}(f_oop, u0, 1.0) - for alg in no_ad_algs - sol = solve(prob, alg) - @test isapprox(only(sol.u), 1.0) - @test SciMLBase.successful_retcode(sol.retcode) + @testset "Out of Place" begin + f_oop = Base.Experimental.@opaque (u, p) -> u .* u .- p + u0 = [0.5] + prob = NonlinearProblem{false}(f_oop, u0, 1.0) + for alg in no_ad_algs + sol = solve(prob, alg) + @test isapprox(only(sol.u), 1.0) + @test SciMLBase.successful_retcode(sol.retcode) + end end end +@testsetup module InfeasibleFunction +using LinearAlgebra, StaticArrays + # this is infeasible function f1_infeasible!(out, u, p) μ = 3.986004415e14 @@ -157,7 +165,10 @@ function f1_infeasible(u, p) return [a - 42.0e6, e - 1e-5, i - 1e-5] end -@testcase "[IIP] Infeasible" begin +export f1_infeasible!, f1_infeasible +end + +@testitem "[IIP] Infeasible" setup=[InfeasibleFunction] begin u0 = [0.0, 0.0, 0.0] prob = NonlinearProblem(f1_infeasible!, u0) sol = solve(prob) @@ -166,7 +177,9 @@ end @test !SciMLBase.successful_retcode(sol.retcode) end -@testcase "[OOP] Infeasible" begin +@testitem "[OOP] Infeasible" setup=[InfeasibleFunction] begin + using StaticArrays + u0 = [0.0, 0.0, 0.0] prob = NonlinearProblem(f1_infeasible, u0) sol = solve(prob) diff --git a/test/misc/qa.jl b/test/misc/qa_tests.jl similarity index 90% rename from test/misc/qa.jl rename to test/misc/qa_tests.jl index 9cfbe2421..e182ac22f 100644 --- a/test/misc/qa.jl +++ b/test/misc/qa_tests.jl @@ -1,6 +1,6 @@ -using NonlinearSolve, Aqua, XUnit +@testitem "Aqua" begin + using NonlinearSolve, Aqua -@testcase "Aqua" begin Aqua.find_persistent_tasks_deps(NonlinearSolve) Aqua.test_ambiguities(NonlinearSolve; recursive = false) Aqua.test_deps_compat(NonlinearSolve) diff --git a/test/runtests.jl b/test/runtests.jl index 7777a0e30..378fd0cf7 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,4 @@ -using Pkg, SafeTestsets, XUnit +using Pkg, ReTestItems const GROUP = get(ENV, "GROUP", "All") @@ -8,24 +8,13 @@ function activate_env(env) Pkg.instantiate() end -@testset runner=ParallelTestRunner() "NonlinearSolve.jl" begin - if GROUP == "All" || GROUP == "Core" - @safetestset "Basic Root Finding Tests" include("core/rootfind.jl") - @safetestset "Forward AD" include("core/forward_ad.jl") - @safetestset "Basic NLLS Solvers" include("core/nlls.jl") - @safetestset "Fixed Point Solvers" include("wrappers/fixedpoint.jl") - @safetestset "Root Finding Solvers" include("wrappers/rootfind.jl") - @safetestset "Nonlinear Least Squares Solvers" include("wrappers/nlls.jl") - @safetestset "23 Test Problems" include("core/23_test_problems.jl") - @safetestset "Quality Assurance" include("misc/qa.jl") - @safetestset "Sparsity Tests" include("misc/bruss.jl") - @safetestset "Polyalgs" include("misc/polyalgs.jl") - @safetestset "Matrix Resizing" include("misc/matrix_resizing.jl") - @safetestset "Banded Matrices" include("misc/banded_matrices.jl") - end +if GROUP == "All" || GROUP == "Core" + ReTestItems.runtests(joinpath(@__DIR__, "core/"), + joinpath(@__DIR__, "misc/"), + joinpath(@__DIR__, "wrappers/")) +end - if GROUP == "GPU" - activate_env("gpu") - @safetestset "GPU Tests" include("gpu/core.jl") - end +if GROUP == "GPU" + activate_env("gpu") + ReTestItems.runtests(joinpath(@__DIR__, "gpu/")) end diff --git a/test/wrappers/fixedpoint.jl b/test/wrappers/fixedpoint_tests.jl similarity index 92% rename from test/wrappers/fixedpoint.jl rename to test/wrappers/fixedpoint_tests.jl index 52ca1963d..3d5713844 100644 --- a/test/wrappers/fixedpoint.jl +++ b/test/wrappers/fixedpoint_tests.jl @@ -1,8 +1,11 @@ -using NonlinearSolve, LinearAlgebra, XUnit +@testsetup module WrapperFixedPointImports +using Reexport +@reexport using LinearAlgebra import SIAMFANLEquations, FixedPointAcceleration, SpeedMapping, NLsolve +end # Simple Scalar Problem -@testcase "Simple Scalar Problem" begin +@testitem "Simple Scalar Problem" setup=[WrapperFixedPointImports] begin f1(x, p) = cos(x) - x prob = NonlinearProblem(f1, 1.1) @@ -19,7 +22,7 @@ import SIAMFANLEquations, FixedPointAcceleration, SpeedMapping, NLsolve end # Simple Vector Problem -@testcase "Simple Vector Problem" begin +@testitem "Simple Vector Problem" setup=[WrapperFixedPointImports] begin f2(x, p) = cos.(x) .- x prob = NonlinearProblem(f2, [1.1, 1.1]) @@ -38,7 +41,7 @@ end # Fixed Point for Power Method # Taken from https://github.com/NicolasL-S/SpeedMapping.jl/blob/95951db8f8a4457093090e18802ad382db1c76da/test/runtests.jl -@testcase "Power Method" begin +@testitem "Power Method" setup=[WrapperFixedPointImports] begin C = [1 2 3; 4 5 6; 7 8 9] A = C + C' B = Hermitian(ones(10) * ones(10)' .* im + Diagonal(1:10)) diff --git a/test/wrappers/nlls.jl b/test/wrappers/nlls.jl deleted file mode 100644 index fed44ac6f..000000000 --- a/test/wrappers/nlls.jl +++ /dev/null @@ -1,105 +0,0 @@ -using NonlinearSolve, - LinearAlgebra, XUnit, StableRNGs, StaticArrays, Random, ForwardDiff, Zygote -import FastLevenbergMarquardt, LeastSquaresOptim, MINPACK - -true_function(x, θ) = @. θ[1] * exp(θ[2] * x) * cos(θ[3] * x + θ[4]) -true_function(y, x, θ) = (@. y = θ[1] * exp(θ[2] * x) * cos(θ[3] * x + θ[4])) - -θ_true = [1.0, 0.1, 2.0, 0.5] - -x = [-1.0, -0.5, 0.0, 0.5, 1.0] - -const y_target = true_function(x, θ_true) - -function loss_function(θ, p) - ŷ = true_function(p, θ) - return ŷ .- y_target -end - -function loss_function(resid, θ, p) - true_function(resid, p, θ) - resid .= resid .- y_target - return resid -end - -θ_init = θ_true .+ randn!(StableRNG(0), similar(θ_true)) * 0.1 -prob_oop = NonlinearLeastSquaresProblem{false}(loss_function, θ_init, x) -prob_iip = NonlinearLeastSquaresProblem(NonlinearFunction(loss_function; - resid_prototype = zero(y_target)), θ_init, x) - -nlls_problems = [prob_oop, prob_iip] - -solvers = [LeastSquaresOptimJL(alg; autodiff) for alg in (:lm, :dogleg), -autodiff in (nothing, AutoForwardDiff(), AutoFiniteDiff(), :central, :forward)] - -@testcase "LeastSquaresOptim.jl" begin - for prob in nlls_problems, solver in solvers - sol = solve(prob, solver; maxiters = 10000, abstol = 1e-8) - @test SciMLBase.successful_retcode(sol) - @test norm(sol.resid, Inf) < 1e-6 - end -end - -function jac!(J, θ, p) - resid = zeros(length(p)) - ForwardDiff.jacobian!(J, (resid, θ) -> loss_function(resid, θ, p), resid, θ) - return J -end - -jac(θ, p) = ForwardDiff.jacobian(θ -> loss_function(θ, p), θ) - -probs = [ - NonlinearLeastSquaresProblem(NonlinearFunction{true}(loss_function; - resid_prototype = zero(y_target), jac = jac!), θ_init, x), - NonlinearLeastSquaresProblem(NonlinearFunction{false}(loss_function; - resid_prototype = zero(y_target), jac = jac), θ_init, x), - NonlinearLeastSquaresProblem(NonlinearFunction{false}(loss_function; jac), θ_init, x), -] - -solvers = Any[FastLevenbergMarquardtJL(linsolve) for linsolve in (:cholesky, :qr)] -push!(solvers, CMINPACK()) - -@testcase "FastLevenbergMarquardt.jl + CMINPACK: Jacobian Provided" begin - for solver in solvers, prob in probs - sol = solve(prob, solver; maxiters = 10000, abstol = 1e-8) - @test maximum(abs, sol.resid) < 1e-6 - end -end - -probs = [ - NonlinearLeastSquaresProblem(NonlinearFunction{true}(loss_function; - resid_prototype = zero(y_target)), θ_init, x), - NonlinearLeastSquaresProblem(NonlinearFunction{false}(loss_function; - resid_prototype = zero(y_target)), θ_init, x), - NonlinearLeastSquaresProblem(NonlinearFunction{false}(loss_function), θ_init, x), -] - -solvers = vec(Any[FastLevenbergMarquardtJL(linsolve; autodiff) - for linsolve in (:cholesky, :qr), -autodiff in (nothing, AutoForwardDiff(), AutoFiniteDiff())]) -append!(solvers, [CMINPACK(; method) for method in (:auto, :lm, :lmdif)]) - -@testcase "FastLevenbergMarquardt.jl + CMINPACK: Jacobian Not Provided" begin - for solver in solvers, prob in probs - sol = solve(prob, solver; maxiters = 10000, abstol = 1e-8) - @test norm(sol.resid, Inf) < 1e-6 - end -end - -# Static Arrays -- Fast Levenberg-Marquardt -x_sa = SA[-1.0, -0.5, 0.0, 0.5, 1.0] - -const y_target_sa = true_function(x_sa, θ_true) - -function loss_function_sa(θ, p) - ŷ = true_function(p, θ) - return ŷ .- y_target_sa -end - -θ_init_sa = SVector{4}(θ_init) -prob_sa = NonlinearLeastSquaresProblem{false}(loss_function_sa, θ_init_sa, x) - -@testcase "FastLevenbergMarquardt.jl + StaticArrays" begin - sol = solve(prob_sa, FastLevenbergMarquardtJL()) - @test norm(sol.resid, Inf) < 1e-6 -end diff --git a/test/wrappers/nlls_tests.jl b/test/wrappers/nlls_tests.jl new file mode 100644 index 000000000..fbcf3cf84 --- /dev/null +++ b/test/wrappers/nlls_tests.jl @@ -0,0 +1,111 @@ +@testsetup module WrapperNLLSSetup +using Reexport +@reexport using LinearAlgebra, StableRNGs, StaticArrays, Random, ForwardDiff, Zygote +import FastLevenbergMarquardt, LeastSquaresOptim, MINPACK + +true_function(x, θ) = @. θ[1] * exp(θ[2] * x) * cos(θ[3] * x + θ[4]) +true_function(y, x, θ) = (@. y = θ[1] * exp(θ[2] * x) * cos(θ[3] * x + θ[4])) + +θ_true = [1.0, 0.1, 2.0, 0.5] + +x = [-1.0, -0.5, 0.0, 0.5, 1.0] + +const y_target = true_function(x, θ_true) + +function loss_function(θ, p) + ŷ = true_function(p, θ) + return ŷ .- y_target +end + +function loss_function(resid, θ, p) + true_function(resid, p, θ) + resid .= resid .- y_target + return resid +end + +θ_init = θ_true .+ randn!(StableRNG(0), similar(θ_true)) * 0.1 + +export loss_function, θ_init, y_target, true_function, x, θ_true +end + +@testitem "LeastSquaresOptim.jl" setup=[WrapperNLLSSetup] begin + prob_oop = NonlinearLeastSquaresProblem{false}(loss_function, θ_init, x) + prob_iip = NonlinearLeastSquaresProblem(NonlinearFunction(loss_function; + resid_prototype = zero(y_target)), θ_init, x) + + nlls_problems = [prob_oop, prob_iip] + + solvers = [LeastSquaresOptimJL(alg; autodiff) for alg in (:lm, :dogleg), + autodiff in (nothing, AutoForwardDiff(), AutoFiniteDiff(), :central, :forward)] + + for prob in nlls_problems, solver in solvers + sol = solve(prob, solver; maxiters = 10000, abstol = 1e-8) + @test SciMLBase.successful_retcode(sol) + @test norm(sol.resid, Inf) < 1e-6 + end +end + +@testitem "FastLevenbergMarquardt.jl + CMINPACK: Jacobian Provided" setup=[ + WrapperNLLSSetup] begin + function jac!(J, θ, p) + resid = zeros(length(p)) + ForwardDiff.jacobian!(J, (resid, θ) -> loss_function(resid, θ, p), resid, θ) + return J + end + + jac(θ, p) = ForwardDiff.jacobian(θ -> loss_function(θ, p), θ) + + probs = [ + NonlinearLeastSquaresProblem(NonlinearFunction{true}(loss_function; + resid_prototype = zero(y_target), jac = jac!), θ_init, x), + NonlinearLeastSquaresProblem(NonlinearFunction{false}(loss_function; + resid_prototype = zero(y_target), jac = jac), θ_init, x), + NonlinearLeastSquaresProblem(NonlinearFunction{false}(loss_function; jac), + θ_init, x), + ] + + solvers = Any[FastLevenbergMarquardtJL(linsolve) for linsolve in (:cholesky, :qr)] + push!(solvers, CMINPACK()) + for solver in solvers, prob in probs + sol = solve(prob, solver; maxiters = 10000, abstol = 1e-8) + @test maximum(abs, sol.resid) < 1e-6 + end +end + +@testitem "FastLevenbergMarquardt.jl + CMINPACK: Jacobian Not Provided" setup=[ + WrapperNLLSSetup] begin + probs = [ + NonlinearLeastSquaresProblem(NonlinearFunction{true}(loss_function; + resid_prototype = zero(y_target)), θ_init, x), + NonlinearLeastSquaresProblem(NonlinearFunction{false}(loss_function; + resid_prototype = zero(y_target)), θ_init, x), + NonlinearLeastSquaresProblem(NonlinearFunction{false}(loss_function), θ_init, x), + ] + + solvers = vec(Any[FastLevenbergMarquardtJL(linsolve; autodiff) + for linsolve in (:cholesky, :qr), + autodiff in (nothing, AutoForwardDiff(), AutoFiniteDiff())]) + append!(solvers, [CMINPACK(; method) for method in (:auto, :lm, :lmdif)]) + + for solver in solvers, prob in probs + sol = solve(prob, solver; maxiters = 10000, abstol = 1e-8) + @test norm(sol.resid, Inf) < 1e-6 + end +end + +@testitem "FastLevenbergMarquardt.jl + StaticArrays" setup=[WrapperNLLSSetup] begin + x_sa = SA[-1.0, -0.5, 0.0, 0.5, 1.0] + + const y_target_sa = true_function(x_sa, θ_true) + + function loss_function_sa(θ, p) + ŷ = true_function(p, θ) + return ŷ .- y_target_sa + end + + θ_init_sa = SVector{4}(θ_init) + prob_sa = NonlinearLeastSquaresProblem{false}(loss_function_sa, θ_init_sa, x) + + sol = solve(prob_sa, FastLevenbergMarquardtJL()) + @test norm(sol.resid, Inf) < 1e-6 +end diff --git a/test/wrappers/rootfind.jl b/test/wrappers/rootfind_tests.jl similarity index 92% rename from test/wrappers/rootfind.jl rename to test/wrappers/rootfind_tests.jl index 5600dbc56..889fa8b57 100644 --- a/test/wrappers/rootfind.jl +++ b/test/wrappers/rootfind_tests.jl @@ -1,7 +1,9 @@ -using NonlinearSolve, LinearAlgebra, SciMLBase, XUnit -import NLsolve, SIAMFANLEquations, MINPACK +@testsetup module WrapperRootfindImports +using Reexport +@reexport using LinearAlgebra, NLsolve, SIAMFANLEquations, MINPACK +end -@testcase "Steady State Problems" begin +@testitem "Steady State Problems" setup=[WrapperRootfindImports] begin # IIP Tests function f_iip(du, u, p, t) du[1] = 2 - 2u[1] @@ -28,7 +30,7 @@ import NLsolve, SIAMFANLEquations, MINPACK end end -@testcase "Nonlinear Root Finding Problems" begin +@testitem "Nonlinear Root Finding Problems" setup=[WrapperRootfindImports] begin # IIP Tests function f_iip(du, u, p) du[1] = 2 - 2u[1]