From f7edc1363529026147e8ec89b663d8deb2b99caa Mon Sep 17 00:00:00 2001 From: ChrisRackauckas Date: Sat, 9 Aug 2025 17:52:25 -0400 Subject: [PATCH 1/4] Move Enzyme tests to NoPre test group MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change addresses CI failures on Julia prerelease versions by: - Creating a new 'nopre' test group for tests that use Enzyme - Adding the nopre group to CI configuration for NonlinearSolve and SimpleNonlinearSolve - Excluding nopre tests from running on Julia 'pre' version in CI - Creating enzyme_tests.jl with example Enzyme tests that skip on prerelease All existing Enzyme tests in subpackages already have VERSION.prerelease checks, but this change provides an additional CI-level control to prevent these tests from running on prerelease Julia versions. Fixes test failures seen in https://github.com/SciML/NonlinearSolve.jl/actions/runs/16851672503/job/47738829623 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .github/workflows/CI_NonlinearSolve.yml | 5 ++ .github/workflows/CI_SimpleNonlinearSolve.yml | 1 + test/enzyme_tests.jl | 54 +++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 test/enzyme_tests.jl diff --git a/.github/workflows/CI_NonlinearSolve.yml b/.github/workflows/CI_NonlinearSolve.yml index 943073d94..e045e1e37 100644 --- a/.github/workflows/CI_NonlinearSolve.yml +++ b/.github/workflows/CI_NonlinearSolve.yml @@ -36,6 +36,7 @@ jobs: - downstream - wrappers - misc + - nopre version: - "1" - "lts" @@ -43,6 +44,10 @@ jobs: os: - ubuntu-latest - macos-latest + exclude: + # Don't run nopre tests on prerelease Julia + - group: nopre + version: "pre" steps: - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v2 diff --git a/.github/workflows/CI_SimpleNonlinearSolve.yml b/.github/workflows/CI_SimpleNonlinearSolve.yml index 4c95a3f99..80398109a 100644 --- a/.github/workflows/CI_SimpleNonlinearSolve.yml +++ b/.github/workflows/CI_SimpleNonlinearSolve.yml @@ -34,6 +34,7 @@ jobs: - core - adjoint - alloc_check + - nopre steps: - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v2 diff --git a/test/enzyme_tests.jl b/test/enzyme_tests.jl new file mode 100644 index 000000000..d0ee0029a --- /dev/null +++ b/test/enzyme_tests.jl @@ -0,0 +1,54 @@ +@testitem "PolyAlgorithms with Enzyme" tags=[:nopre] skip=!isempty(VERSION.prerelease) begin + using ADTypes + + # Only run these tests on non-prerelease Julia versions + @info "Running Enzyme tests (Julia $(VERSION))" + + cache = zeros(2) + function f(du, u, p) + cache .= u .* u + du .= cache .- 2 + end + u0 = [1.0, 1.0] + probN = NonlinearProblem{true}(f, u0) + + # Test with AutoEnzyme for autodiff + if isempty(VERSION.prerelease) + using Enzyme + sol = solve(probN, RobustMultiNewton(; autodiff = AutoEnzyme())) + @test SciMLBase.successful_retcode(sol) + + sol = solve( + probN, FastShortcutNonlinearPolyalg(; autodiff = AutoEnzyme()); abstol = 1e-9 + ) + @test SciMLBase.successful_retcode(sol) + end +end + +@testitem "ForwardDiff with Enzyme backend" tags=[:nopre] skip=!isempty(VERSION.prerelease) begin + using ForwardDiff, ADTypes + + # Only run these tests on non-prerelease Julia versions + @info "Running ForwardDiff-Enzyme integration tests (Julia $(VERSION))" + + test_f!(du, u, p) = (@. du = u^2 - p) + test_f(u, p) = (@. u^2 - p) + + function solve_oop(p) + solve(NonlinearProblem(test_f, 2.0, p), NewtonRaphson(; autodiff = AutoEnzyme())).u + end + + if isempty(VERSION.prerelease) + using Enzyme + + # Test scalar AD with Enzyme backend + for p in 1.0:0.1:10.0 + sol = solve(NonlinearProblem(test_f, 2.0, p), NewtonRaphson(; autodiff = AutoEnzyme())) + if SciMLBase.successful_retcode(sol) + gs = abs.(ForwardDiff.derivative(solve_oop, p)) + gs_true = abs.(1 / (2 * √p)) + @test abs.(gs) ≈ abs.(gs_true) atol=1e-5 + end + end + end +end \ No newline at end of file From aebeba28c30616721f8cf065d2fc9dce67fc870f Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Sun, 10 Aug 2025 06:48:24 -0400 Subject: [PATCH 2/4] Update .github/workflows/CI_SimpleNonlinearSolve.yml --- .github/workflows/CI_SimpleNonlinearSolve.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/CI_SimpleNonlinearSolve.yml b/.github/workflows/CI_SimpleNonlinearSolve.yml index 80398109a..a4dbf4464 100644 --- a/.github/workflows/CI_SimpleNonlinearSolve.yml +++ b/.github/workflows/CI_SimpleNonlinearSolve.yml @@ -35,6 +35,10 @@ jobs: - adjoint - alloc_check - nopre + exclude: + # Don't run nopre tests on prerelease Julia + - group: nopre + version: "pre" steps: - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v2 From f0e95bf0f9538fc6bbd24f10cdc99cef2d0f39ff Mon Sep 17 00:00:00 2001 From: ChrisRackauckas Date: Sun, 10 Aug 2025 07:26:06 -0400 Subject: [PATCH 3/4] Move existing tests that may use Enzyme to nopre group MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of creating new tests, this moves existing tests that could potentially use Enzyme through default autodiff settings to the nopre group: - Basic PolyAlgorithms: Uses RobustMultiNewton() and FastShortcutNonlinearPolyalg() - PolyAlgorithms Autodiff: Tests autodiff with polyalgorithms - 23 Test Problems: PolyAlgorithms: Tests with default polyalgorithms - ForwardDiff.jl Integration: Tests with FastShortcutNonlinearPolyalg() and nothing - Ensemble Nonlinear Problems: Uses nothing as algorithm - Out-of-place Matrix Resizing: Uses polyalgorithms without explicit autodiff - Inplace Matrix Resizing: Uses polyalgorithms without explicit autodiff - Default Algorithm Singular Handling: Uses default solver These tests may trigger Enzyme usage through default autodiff backends, so moving them to nopre group ensures they don't run on Julia prerelease. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- test/23_test_problems_tests.jl | 2 +- test/core_tests.jl | 12 ++++---- test/enzyme_tests.jl | 54 ---------------------------------- test/forward_ad_tests.jl | 2 +- 4 files changed, 8 insertions(+), 62 deletions(-) delete mode 100644 test/enzyme_tests.jl diff --git a/test/23_test_problems_tests.jl b/test/23_test_problems_tests.jl index 684dc8967..c4215cebb 100644 --- a/test/23_test_problems_tests.jl +++ b/test/23_test_problems_tests.jl @@ -39,7 +39,7 @@ end export test_on_library, problems, dicts end -@testitem "23 Test Problems: PolyAlgorithms" setup=[RobustnessTesting] tags=[:core] begin +@testitem "23 Test Problems: PolyAlgorithms" setup=[RobustnessTesting] tags=[:nopre] begin alg_ops=(RobustMultiNewton(), FastShortcutNonlinearPolyalg()) broken_tests=Dict(alg=>Int[] for alg in alg_ops) diff --git a/test/core_tests.jl b/test/core_tests.jl index fc0bb2026..76a3a9187 100644 --- a/test/core_tests.jl +++ b/test/core_tests.jl @@ -17,7 +17,7 @@ @test sol1.u ≈ sol2.u end -@testitem "Basic PolyAlgorithms" tags=[:core] begin +@testitem "Basic PolyAlgorithms" tags=[:nopre] begin f(u, p) = u .* u .- 2 u0 = [1.0, 1.0] @@ -60,7 +60,7 @@ end end end -@testitem "PolyAlgorithms Autodiff" tags=[:core] begin +@testitem "PolyAlgorithms Autodiff" tags=[:nopre] begin cache = zeros(2) function f(du, u, p) cache .= u .* u @@ -126,7 +126,7 @@ end @test SciMLBase.successful_retcode(sol.retcode) end -@testitem "Ensemble Nonlinear Problems" tags=[:core] begin +@testitem "Ensemble Nonlinear Problems" tags=[:nopre] begin prob_func(prob, i, repeat) = remake(prob; u0 = prob.u0[:, i]) prob_nls_oop = NonlinearProblem((u, p) -> u .* u .- p, rand(4, 128), 2.0) @@ -350,7 +350,7 @@ end end end -@testitem "Out-of-place Matrix Resizing" tags=[:core] begin +@testitem "Out-of-place Matrix Resizing" tags=[:nopre] begin using StableRNGs ff(u, p) = u .* u .- p @@ -368,7 +368,7 @@ end end end -@testitem "Inplace Matrix Resizing" tags=[:core] begin +@testitem "Inplace Matrix Resizing" tags=[:nopre] begin using StableRNGs fiip(du, u, p) = (du .= u .* u .- p) @@ -437,7 +437,7 @@ end @test sol.retcode == ReturnCode.StalledSuccess end -@testitem "Default Algorithm Singular Handling" tags=[:core] begin +@testitem "Default Algorithm Singular Handling" tags=[:nopre] begin f(u, p) = [u[1]^2 - 2u[1] + 1, sum(u)] prob = NonlinearProblem(f, [1.0, 1.0]) sol = solve(prob) diff --git a/test/enzyme_tests.jl b/test/enzyme_tests.jl deleted file mode 100644 index d0ee0029a..000000000 --- a/test/enzyme_tests.jl +++ /dev/null @@ -1,54 +0,0 @@ -@testitem "PolyAlgorithms with Enzyme" tags=[:nopre] skip=!isempty(VERSION.prerelease) begin - using ADTypes - - # Only run these tests on non-prerelease Julia versions - @info "Running Enzyme tests (Julia $(VERSION))" - - cache = zeros(2) - function f(du, u, p) - cache .= u .* u - du .= cache .- 2 - end - u0 = [1.0, 1.0] - probN = NonlinearProblem{true}(f, u0) - - # Test with AutoEnzyme for autodiff - if isempty(VERSION.prerelease) - using Enzyme - sol = solve(probN, RobustMultiNewton(; autodiff = AutoEnzyme())) - @test SciMLBase.successful_retcode(sol) - - sol = solve( - probN, FastShortcutNonlinearPolyalg(; autodiff = AutoEnzyme()); abstol = 1e-9 - ) - @test SciMLBase.successful_retcode(sol) - end -end - -@testitem "ForwardDiff with Enzyme backend" tags=[:nopre] skip=!isempty(VERSION.prerelease) begin - using ForwardDiff, ADTypes - - # Only run these tests on non-prerelease Julia versions - @info "Running ForwardDiff-Enzyme integration tests (Julia $(VERSION))" - - test_f!(du, u, p) = (@. du = u^2 - p) - test_f(u, p) = (@. u^2 - p) - - function solve_oop(p) - solve(NonlinearProblem(test_f, 2.0, p), NewtonRaphson(; autodiff = AutoEnzyme())).u - end - - if isempty(VERSION.prerelease) - using Enzyme - - # Test scalar AD with Enzyme backend - for p in 1.0:0.1:10.0 - sol = solve(NonlinearProblem(test_f, 2.0, p), NewtonRaphson(; autodiff = AutoEnzyme())) - if SciMLBase.successful_retcode(sol) - gs = abs.(ForwardDiff.derivative(solve_oop, p)) - gs_true = abs.(1 / (2 * √p)) - @test abs.(gs) ≈ abs.(gs_true) atol=1e-5 - end - end - end -end \ No newline at end of file diff --git a/test/forward_ad_tests.jl b/test/forward_ad_tests.jl index f3dd8746e..9984c0a0b 100644 --- a/test/forward_ad_tests.jl +++ b/test/forward_ad_tests.jl @@ -62,7 +62,7 @@ compatible(::KINSOL, ::Val{:oop_cache}) = false export test_f!, test_f, jacobian_f, solve_with, compatible end -@testitem "ForwardDiff.jl Integration" setup=[ForwardADTesting] tags=[:core] begin +@testitem "ForwardDiff.jl Integration" setup=[ForwardADTesting] tags=[:nopre] begin @testset for alg in ( NewtonRaphson(), TrustRegion(), From 35a8bb0aec283aed2f259038e38b13491ca68d11 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas Date: Sun, 10 Aug 2025 13:18:07 -0400 Subject: [PATCH 4/4] Make Enzyme a conditional test dependency loaded only for nopre group MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove Enzyme from regular test dependencies in Project.toml - Add Enzyme as an EXTRA_PKG that's loaded conditionally in runtests.jl - Only load Enzyme for the nopre group when not on prerelease Julia - This ensures Enzyme is only loaded when needed and won't cause issues on prerelease This complements the previous change of moving tests to the nopre group, ensuring Enzyme is truly optional and only loaded when appropriate. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- Project.toml | 4 +--- test/runtests.jl | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Project.toml b/Project.toml index aa91c7420..6e897bae3 100644 --- a/Project.toml +++ b/Project.toml @@ -69,7 +69,6 @@ CommonSolve = "0.2.4" ConcreteStructs = "0.2.3" DiffEqBase = "6.158.3" DifferentiationInterface = "0.6.18, 0.7" -Enzyme = "0.13.11" ExplicitImports = "1.5" FastClosures = "0.3.2" FastLevenbergMarquardt = "0.1" @@ -123,7 +122,6 @@ Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" BandedMatrices = "aae01518-5342-5314-be14-df237901396f" BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" -Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7" FastLevenbergMarquardt = "7a0df574-e128-4d35-8cbd-3d84502bf7ce" FixedPointAcceleration = "817d07cb-a79a-5c30-9a31-890123675176" @@ -170,5 +168,5 @@ path = "lib/NonlinearSolveSpectralMethods" path = "lib/SimpleNonlinearSolve" [targets] -test = ["Aqua", "BandedMatrices", "BenchmarkTools", "CUDA", "Enzyme", "ExplicitImports", "FastLevenbergMarquardt", "FixedPointAcceleration", "Hwloc", "InteractiveUtils", "LeastSquaresOptim", "LineSearches", "MINPACK", "NLSolvers", "NLsolve", "NaNMath", "NonlinearProblemLibrary", "OrdinaryDiffEqTsit5", "PETSc", "Pkg", "PolyesterForwardDiff", "Random", "ReTestItems", "SIAMFANLEquations", "SparseConnectivityTracer", "SpeedMapping", "StableRNGs", "StaticArrays", "Sundials", "Test", "Zygote"] +test = ["Aqua", "BandedMatrices", "BenchmarkTools", "CUDA", "ExplicitImports", "FastLevenbergMarquardt", "FixedPointAcceleration", "Hwloc", "InteractiveUtils", "LeastSquaresOptim", "LineSearches", "MINPACK", "NLSolvers", "NLsolve", "NaNMath", "NonlinearProblemLibrary", "OrdinaryDiffEqTsit5", "PETSc", "Pkg", "PolyesterForwardDiff", "Random", "ReTestItems", "SIAMFANLEquations", "SparseConnectivityTracer", "SpeedMapping", "StableRNGs", "StaticArrays", "Sundials", "Test", "Zygote"] diff --git a/test/runtests.jl b/test/runtests.jl index bfdd07b35..16f697d67 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -9,6 +9,12 @@ if GROUP == "all" || GROUP == "downstream" push!(EXTRA_PKGS, Pkg.PackageSpec("ModelingToolkit")) push!(EXTRA_PKGS, Pkg.PackageSpec("SymbolicIndexingInterface")) end +if GROUP == "all" || GROUP == "nopre" + # Only add Enzyme for nopre group if not on prerelease Julia + if isempty(VERSION.prerelease) + push!(EXTRA_PKGS, Pkg.PackageSpec("Enzyme")) + end +end length(EXTRA_PKGS) ≥ 1 && Pkg.add(EXTRA_PKGS) const RETESTITEMS_NWORKERS = parse(