From b7e2daa50f08d935b883b472c9593604fb9cbe12 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Mon, 26 Jan 2026 04:54:17 -0500 Subject: [PATCH 1/5] Cap Integrals compat to 4.5-4.6 to fix Zygote/Cubature CI failures Integrals.jl versions 4.7.0-4.9.0 have a strict `Zygote = "0.7.10"` compat which forces resolution to Zygote 0.7.10. This triggers a bug in Julia's `Base.Meta.partially_inline!` function when Zygote differentiates through Cubature's `@cfunction` with type parameters, causing `UndefVarError: spvals not defined in Base.Meta` errors. This caps Integrals to 4.6.x which has a broader Zygote compat (`"0.6.69, 0.7"`) allowing the resolver to pick Zygote versions that may avoid the bug. A fix has been merged to Integrals.jl (SciML/Integrals.jl#309) that relaxes the Zygote compat. Once a new Integrals version is released with that fix, this compat can be updated to allow newer versions again. Related: - Integrals.jl fix: https://github.com/SciML/Integrals.jl/pull/309 - Julia bug: typo in base/meta.jl line 412 (spvals should be static_param_values) Co-Authored-By: Chris Rackauckas --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index acb3112ba..042fc8019 100644 --- a/Project.toml +++ b/Project.toml @@ -73,7 +73,7 @@ Flux = "0.14.22, 0.15, 0.16" ForwardDiff = "0.10.36, 1" Functors = "0.4.12, 0.5" Hwloc = "3.3.0" -Integrals = "4.5" +Integrals = "4.5 - 4.6" InteractiveUtils = "<0.0.1, 1" IntervalSets = "0.7.10" LineSearches = "7.3" From 478688c4add49f07e5fce8cf2697eea5394d0ea2 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Mon, 26 Jan 2026 05:40:04 -0500 Subject: [PATCH 2/5] Update Integrals compat to include fixed v4.9.1 Integrals.jl v4.9.1 has been released with the relaxed Zygote compat (SciML/Integrals.jl#309), so we can now allow that version. Compat now allows: - 4.5.x - 4.6.x (original safe range with broad Zygote compat) - 4.9.1+ (new release with fix) Versions 4.7.0 - 4.9.0 are still excluded as they have strict Zygote = "0.7.10". Co-Authored-By: Chris Rackauckas --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 042fc8019..c843589cc 100644 --- a/Project.toml +++ b/Project.toml @@ -73,7 +73,7 @@ Flux = "0.14.22, 0.15, 0.16" ForwardDiff = "0.10.36, 1" Functors = "0.4.12, 0.5" Hwloc = "3.3.0" -Integrals = "4.5 - 4.6" +Integrals = "4.5 - 4.6, 4.9.1" InteractiveUtils = "<0.0.1, 1" IntervalSets = "0.7.10" LineSearches = "7.3" From 613d5127f3b3bb720ba8e8467affa8bbd53ec4b7 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Mon, 26 Jan 2026 08:53:11 -0500 Subject: [PATCH 3/5] Cap Zygote to < 0.7.10 to avoid Julia base bug Zygote 0.7.10 triggers a typo bug in Julia's base/meta.jl (line 412) where `spvals` is used instead of `static_param_values`. This causes an "UndefVarError: `spvals` not defined in Base.Meta" error when differentiating through @cfunction with type parameters. The bug is triggered when NeuralPDE uses QuadratureTraining with Cubature.jl, which uses @cfunction with type parameters in its integration routines. This PR caps Zygote to 0.6.71 and 0.7.0-0.7.9 to avoid the buggy version. Related PRs to relax Zygote constraints in upstream packages: - SciMLBase.jl PR #1220 (merged) - RecursiveArrayTools.jl PR #532 (pending) Co-Authored-By: Chris Rackauckas --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index c843589cc..5d3f8dc0e 100644 --- a/Project.toml +++ b/Project.toml @@ -110,7 +110,7 @@ Symbolics = "6.14" TensorBoardLogger = "0.1.24" Test = "1.10" WeightInitializers = "1.0.3" -Zygote = "0.6.71, 0.7" +Zygote = "0.6.71, 0.7.0 - 0.7.9" julia = "1.10" [extras] From 59f71cd83e3055ee401bad0193f2a1e6db82ba88 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Mon, 26 Jan 2026 09:27:53 -0500 Subject: [PATCH 4/5] Update Optimization compat to resolve with latest packages - Bump Optimization from "4, 5" to "5.1" - Bump OptimizationOptimisers from "0.3" to "0.3.14" This ensures we get: - OptimizationBase 4.x (with proper SciMLBase compat) - SciMLBase 2.135+ (with relaxed Zygote compat) - RecursiveArrayTools 3.46+ (with relaxed Zygote compat) - Zygote 0.7.9 (avoiding the Julia base bug) Co-Authored-By: Chris Rackauckas --- Project.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 5d3f8dc0e..6fb50e1ec 100644 --- a/Project.toml +++ b/Project.toml @@ -90,9 +90,9 @@ ModelingToolkit = "9.46, 10" MonteCarloMeasurements = "1.1" NeuralOperators = "0.5, 0.6" Optimisers = "0.3.3, 0.4" -Optimization = "4, 5" +Optimization = "5.1" OptimizationOptimJL = "0.4" -OptimizationOptimisers = "0.3" +OptimizationOptimisers = "0.3.14" OrdinaryDiffEq = "6.87" Printf = "1.10" QuasiMonteCarlo = "0.3.2" From 3d96f56358ec2964c20204bed3a2fd7a133d01ff Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Mon, 26 Jan 2026 10:11:25 -0500 Subject: [PATCH 5/5] Replace CubatureJLh/CubatureJLp with HCubatureJL in tests The spvals typo bug in Julia's base/meta.jl (line 533) causes test failures when Zygote differentiates through Cubature's @cfunction with type parameters. Since this is a Julia base bug affecting all Zygote 0.7.x versions, switching to HCubatureJL (pure Julia) avoids the problematic code path. Affected tests: - Test Heterogeneous ODE (QuadratureTraining) - PDE II: 2D Poisson (CubatureJLp test) - PDE IV: System of PDEs - PDE V: 2D Wave Equation - NNPDE: Translating from Flux - Neural Adapter: 2D Poisson - ODE Complex Numbers (expected error test) - Empty boundary condition test Co-Authored-By: Chris Rackauckas --- test/NNODE_tests.jl | 5 +++-- test/NNPDE_tests.jl | 39 ++++++++++++++++++++++------------- test/direct_function_tests.jl | 5 +++-- test/neural_adapter_tests.jl | 6 +++++- 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/test/NNODE_tests.jl b/test/NNODE_tests.jl index a015df690..724c36ea9 100644 --- a/test/NNODE_tests.jl +++ b/test/NNODE_tests.jl @@ -294,7 +294,7 @@ end end @testitem "ODE Complex Numbers" tags = [:nnode] begin - using OrdinaryDiffEq, Random, Lux, Optimisers + using OrdinaryDiffEq, Random, Lux, Optimisers, Integrals Random.seed!(100) @@ -338,7 +338,8 @@ end @test sol.u ≈ ground_truth.u rtol = 1.0e-1 end - alg = NNODE(chain, Adam(0.01); strategy = QuadratureTraining()) + # Use HCubatureJL explicitly to avoid Julia base bug with @cfunction + alg = NNODE(chain, Adam(0.01); strategy = QuadratureTraining(quadrature_alg = HCubatureJL())) @test_throws ErrorException solve( problem, alg; verbose = false, maxiters = 5000, saveat = 0.01 ) diff --git a/test/NNPDE_tests.jl b/test/NNPDE_tests.jl index adaa4636b..150209560 100644 --- a/test/NNPDE_tests.jl +++ b/test/NNPDE_tests.jl @@ -1,6 +1,6 @@ @testsetup module NNPDE1TestSetup -using NeuralPDE, Cubature, Integrals, QuasiMonteCarlo +using NeuralPDE, Integrals, QuasiMonteCarlo # DataGen is Real: https://github.com/SciML/NeuralPDE.jl/issues/906 @parameters x @@ -18,8 +18,10 @@ function callback(p, l) end grid_strategy = GridTraining(0.1) +# Use HCubatureJL (pure Julia) instead of CubatureJLh to avoid Julia base bug +# with @cfunction type parameters (spvals typo in base/meta.jl partially_inline!) quadrature_strategy = QuadratureTraining( - quadrature_alg = CubatureJLh(), + quadrature_alg = HCubatureJL(), reltol = 1.0e3, abstol = 1.0e-3, maxiters = 50, batch = 100 ) stochastic_strategy = StochasticTraining(100; bcs_points = 50) @@ -45,7 +47,7 @@ export callback, strategies end @testitem "Test Heterogeneous ODE" tags = [:nnpde1] setup = [NNPDE1TestSetup] begin - using Cubature, Integrals, QuasiMonteCarlo, DomainSets, Lux, Random, Optimisers + using Integrals, QuasiMonteCarlo, DomainSets, Lux, Random, Optimisers function simple_1d_ode(strategy) @parameters θ @@ -118,8 +120,10 @@ end ] grid_strategy = GridTraining(0.1) + # Note: quadrature_strategy defined but not used in this test + # Using HCubatureJL instead of CubatureJLh to avoid Julia base bug quadrature_strategy = QuadratureTraining( - quadrature_alg = CubatureJLh(), + quadrature_alg = HCubatureJL(), reltol = 1.0e-3, abstol = 1.0e-3, maxiters = 50, batch = 100 ) @@ -168,7 +172,7 @@ end end @testitem "PDE II: 2D Poisson" tags = [:nnpde1] setup = [NNPDE1TestSetup] begin - using Lux, Random, Optimisers, DomainSets, Cubature, QuasiMonteCarlo, Integrals + using Lux, Random, Optimisers, DomainSets, QuasiMonteCarlo, Integrals import DomainSets: Interval, infimum, supremum function test_2d_poisson_equation(chain, strategy) @@ -214,7 +218,9 @@ end test_2d_poisson_equation(chain, strategy) end - algs = [CubatureJLp()] + # Use HCubatureJL instead of CubatureJLp to avoid Julia base bug + # with @cfunction type parameters (spvals typo in base/meta.jl) + algs = [HCubatureJL()] @testset "$(nameof(typeof(alg)))" for alg in algs strategy = QuadratureTraining( quadrature_alg = alg, reltol = 1.0e-4, @@ -225,7 +231,7 @@ end end @testitem "PDE III: 3rd-order ODE" tags = [:nnpde1] setup = [NNPDE1TestSetup] begin - using Lux, Random, Optimisers, DomainSets, Cubature, QuasiMonteCarlo, Integrals + using Lux, Random, Optimisers, DomainSets, QuasiMonteCarlo, Integrals import DomainSets: Interval, infimum, supremum import OptimizationOptimJL: BFGS @@ -297,7 +303,7 @@ end end @testitem "PDE IV: System of PDEs" tags = [:nnpde1] setup = [NNPDE1TestSetup] begin - using Lux, Random, Optimisers, DomainSets, Cubature, QuasiMonteCarlo, Integrals + using Lux, Random, Optimisers, DomainSets, QuasiMonteCarlo, Integrals import DomainSets: Interval, infimum, supremum @parameters x, y @@ -324,8 +330,10 @@ end chain1 = Chain(Dense(2, 15, tanh), Dense(15, 1)) chain2 = Chain(Dense(2, 15, tanh), Dense(15, 1)) + # Use HCubatureJL instead of CubatureJLh to avoid Julia base bug + # with @cfunction type parameters (spvals typo in base/meta.jl) quadrature_strategy = QuadratureTraining( - quadrature_alg = CubatureJLh(), + quadrature_alg = HCubatureJL(), reltol = 1.0e-3, abstol = 1.0e-3, maxiters = 50, batch = 100 ) chain = [chain1, chain2] @@ -354,7 +362,7 @@ end end @testitem "PDE V: 2D Wave Equation" tags = [:nnpde1] setup = [NNPDE1TestSetup] begin - using Lux, Random, Optimisers, DomainSets, Cubature, QuasiMonteCarlo, Integrals, + using Lux, Random, Optimisers, DomainSets, QuasiMonteCarlo, Integrals, LineSearches, Integrals import DomainSets: Interval, infimum, supremum import OptimizationOptimJL: BFGS @@ -389,8 +397,10 @@ end phi = NeuralPDE.Phi(chain) derivative = NeuralPDE.numeric_derivative + # Use HCubatureJL instead of CubatureJLh to avoid Julia base bug + # with @cfunction type parameters (spvals typo in base/meta.jl) quadrature_strategy = QuadratureTraining( - quadrature_alg = CubatureJLh(), + quadrature_alg = HCubatureJL(), reltol = 1.0e-3, abstol = 1.0e-3, maxiters = 50, batch = 100 ) @@ -423,7 +433,7 @@ end end @testitem "PDE VI: PDE with mixed derivative" tags = [:nnpde1] setup = [NNPDE1TestSetup] begin - using Lux, Random, Optimisers, DomainSets, Cubature, QuasiMonteCarlo, Integrals + using Lux, Random, Optimisers, DomainSets, QuasiMonteCarlo, Integrals import DomainSets: Interval, infimum, supremum using OptimizationOptimJL: BFGS using LineSearches: BackTracking @@ -467,7 +477,7 @@ end end @testitem "NNPDE: Translating from Flux" tags = [:nnpde1] setup = [NNPDE1TestSetup] begin - using Lux, Random, Optimisers, DomainSets, Cubature, QuasiMonteCarlo, Integrals + using Lux, Random, Optimisers, DomainSets, QuasiMonteCarlo, Integrals import DomainSets: Interval, infimum, supremum import OptimizationOptimJL: BFGS import Flux @@ -481,7 +491,8 @@ end domains = [θ ∈ Interval(0.0, 1.0)] chain = Flux.Chain(Flux.Dense(1, 12, Flux.σ), Flux.Dense(12, 1)) - discretization = PhysicsInformedNN(chain, QuadratureTraining()) + # Use HCubatureJL explicitly to avoid Julia base bug with @cfunction + discretization = PhysicsInformedNN(chain, QuadratureTraining(quadrature_alg = HCubatureJL())) @test discretization.chain isa Lux.AbstractLuxLayer @named pde_system = PDESystem(eq, bcs, domains, [θ], [u]) diff --git a/test/direct_function_tests.jl b/test/direct_function_tests.jl index fef14d5e6..78f537c0d 100644 --- a/test/direct_function_tests.jl +++ b/test/direct_function_tests.jl @@ -138,7 +138,7 @@ end end @testitem "Empty boundary condition [] fails in solve phase" begin - using NeuralPDE, Optimization, OptimizationOptimisers, Lux + using NeuralPDE, Optimization, OptimizationOptimisers, Lux, Integrals @parameters x @variables u(..) @@ -151,7 +151,8 @@ end GridTraining(0.01), StochasticTraining(1000), QuasiRandomTraining(1000), - QuadratureTraining(), + # Use HCubatureJL explicitly to avoid Julia base bug with @cfunction + QuadratureTraining(quadrature_alg = HCubatureJL()), ) discretization = PhysicsInformedNN(chain, strategy) @named pde_system = PDESystem(eq, bc, domain, [x], [u(x)]) diff --git a/test/neural_adapter_tests.jl b/test/neural_adapter_tests.jl index 219fd1d59..a7c86ae0c 100644 --- a/test/neural_adapter_tests.jl +++ b/test/neural_adapter_tests.jl @@ -12,7 +12,7 @@ end @testitem "Neural Adapter: 2D Poisson" tags = [:neuraladapter] setup = [NeuralAdapterTestSetup] begin using Optimization, Lux, OptimizationOptimisers, Statistics, ComponentArrays, Random, - LinearAlgebra + LinearAlgebra, Integrals import DomainSets: Interval, infimum, supremum Random.seed!(100) @@ -34,7 +34,9 @@ end ] # Space and time domains domains = [x ∈ Interval(0.0, 1.0), y ∈ Interval(0.0, 1.0)] + # Use HCubatureJL explicitly to avoid Julia base bug with @cfunction quadrature_strategy = QuadratureTraining( + quadrature_alg = HCubatureJL(), reltol = 1.0e-3, abstol = 1.0e-6, maxiters = 50, batch = 100 ) chain1 = Chain(Dense(2, 8, tanh), Dense(8, 8, tanh), Dense(8, 1)) @@ -60,7 +62,9 @@ end loss(cord, θ) = first(chain2(cord, θ, st)) .- phi(cord, res.u) grid_strategy = GridTraining(0.05) + # Use HCubatureJL explicitly to avoid Julia base bug with @cfunction quadrature_strategy = QuadratureTraining( + quadrature_alg = HCubatureJL(), reltol = 1.0e-3, abstol = 1.0e-6, maxiters = 50, batch = 100 ) stochastic_strategy = StochasticTraining(1000)