From ed73616fca8108fc124fd964c8aa9c16d88254d9 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Mon, 26 Jan 2026 06:27:16 -0500 Subject: [PATCH 1/5] Add FastTanhSinhQuadrature.jl interface Add support for FastTanhSinhQuadrature.jl as a new integration backend via package extension. FastTanhSinhQuadrature.jl provides high-performance SIMD-accelerated Tanh-Sinh (double exponential) quadrature with support for 1D, 2D, and 3D integration. Changes: - Add FastTanhSinhQuadratureJL algorithm struct with tol and max_levels parameters - Create IntegralsFastTanhSinhQuadratureExt extension module - Add to Project.toml weakdeps, extensions, compat, extras, and test targets - Add to interface tests with appropriate capability flags - Export FastTanhSinhQuadratureJL from main module Note: FastTanhSinhQuadrature.jl is not yet registered in the General registry. Users can add it from: https://github.com/svretina/FastTanhSinhQuadrature.jl Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.5 --- Project.toml | 6 ++- ext/IntegralsFastTanhSinhQuadratureExt.jl | 55 +++++++++++++++++++++++ src/Integrals.jl | 1 + src/algorithms_extension.jl | 43 ++++++++++++++++++ test/interface_tests.jl | 5 ++- 5 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 ext/IntegralsFastTanhSinhQuadratureExt.jl diff --git a/Project.toml b/Project.toml index 1f9bf2f3..4432e6c3 100644 --- a/Project.toml +++ b/Project.toml @@ -23,6 +23,7 @@ Cuba = "8a292aeb-7a57-582c-b821-06e4c11590b1" Cubature = "667455a9-e2ce-5579-9412-b964f529a492" DifferentiationInterface = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63" FastGaussQuadrature = "442a2c76-b920-505d-bb47-c5924d526838" +FastTanhSinhQuadrature = "b650e0df-f744-4436-b963-b44034668c57" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" HAdaptiveIntegration = "eaa5ad34-b243-48e9-b09c-54bc0655cecf" MCIntegration = "ea1e2de9-7db7-4b42-91ee-0cd1bf6df167" @@ -35,6 +36,7 @@ IntegralsCubaExt = "Cuba" IntegralsCubatureExt = "Cubature" IntegralsDifferentiationInterfaceExt = ["ADTypes", "DifferentiationInterface", "ChainRulesCore"] IntegralsFastGaussQuadratureExt = "FastGaussQuadrature" +IntegralsFastTanhSinhQuadratureExt = "FastTanhSinhQuadrature" IntegralsForwardDiffExt = "ForwardDiff" IntegralsHAdaptiveIntegrationExt = "HAdaptiveIntegration" IntegralsMCIntegrationExt = "MCIntegration" @@ -54,6 +56,7 @@ DifferentiationInterface = "0.7" Distributions = "0.25.87" ExplicitImports = "1.14.0" FastGaussQuadrature = "0.5,1" +FastTanhSinhQuadrature = "1" FiniteDiff = "2.12" ForwardDiff = "0.10.36, 1" HAdaptiveIntegration = "0.2, 1.0" @@ -85,6 +88,7 @@ DifferentiationInterface = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7" FastGaussQuadrature = "442a2c76-b920-505d-bb47-c5924d526838" +FastTanhSinhQuadrature = "b650e0df-f744-4436-b963-b44034668c57" FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" HAdaptiveIntegration = "eaa5ad34-b243-48e9-b09c-54bc0655cecf" @@ -97,4 +101,4 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" [targets] -test = ["ADTypes", "Aqua", "Arblib", "StaticArrays", "FiniteDiff", "SafeTestsets", "Test", "Distributions", "ForwardDiff", "Zygote", "ChainRulesCore", "FastGaussQuadrature", "Cuba", "Cubature", "MCIntegration", "Mooncake", "ExplicitImports", "DifferentiationInterface", "Pkg", "HAdaptiveIntegration"] +test = ["ADTypes", "Aqua", "Arblib", "StaticArrays", "FiniteDiff", "SafeTestsets", "Test", "Distributions", "ForwardDiff", "Zygote", "ChainRulesCore", "FastGaussQuadrature", "FastTanhSinhQuadrature", "Cuba", "Cubature", "MCIntegration", "Mooncake", "ExplicitImports", "DifferentiationInterface", "Pkg", "HAdaptiveIntegration"] diff --git a/ext/IntegralsFastTanhSinhQuadratureExt.jl b/ext/IntegralsFastTanhSinhQuadratureExt.jl new file mode 100644 index 00000000..f6c89484 --- /dev/null +++ b/ext/IntegralsFastTanhSinhQuadratureExt.jl @@ -0,0 +1,55 @@ +module IntegralsFastTanhSinhQuadratureExt + +using Integrals +import FastTanhSinhQuadrature +import FastTanhSinhQuadrature: quad + +function Integrals.__solvebp_call( + prob::IntegralProblem, alg::Integrals.FastTanhSinhQuadratureJL, + sensealg, domain, p; + reltol = nothing, abstol = nothing, + maxiters = nothing + ) + lb, ub = domain + f = prob.f + + @assert f isa IntegralFunction "FastTanhSinhQuadratureJL does not support BatchIntegralFunction" + @assert !isinplace(prob) "FastTanhSinhQuadratureJL does not support in-place integrands" + + # Determine the effective tolerance + tol = alg.tol + if reltol !== nothing + tol = reltol + end + max_levels = alg.max_levels + + # Determine dimensionality + dim = lb isa Number ? 1 : length(lb) + + if dim == 1 + # 1D integration + _lb = lb isa Number ? lb : only(lb) + _ub = ub isa Number ? ub : only(ub) + _f = x -> f.f(x, p) + val = quad(_f, _lb, _ub; tol = tol, max_levels = max_levels) + elseif dim == 2 + # 2D integration - use Vectors which quad() converts to SVector internally + _lb = collect(lb) + _ub = collect(ub) + _f = (x, y) -> f.f([x, y], p) + val = quad(_f, _lb, _ub; tol = tol, max_levels = max_levels) + elseif dim == 3 + # 3D integration - use Vectors which quad() converts to SVector internally + _lb = collect(lb) + _ub = collect(ub) + _f = (x, y, z) -> f.f([x, y, z], p) + val = quad(_f, _lb, _ub; tol = tol, max_levels = max_levels) + else + error("FastTanhSinhQuadratureJL only supports 1D, 2D, and 3D integration. Got dimension = $dim") + end + + err = nothing + return SciMLBase.build_solution(prob, alg, val, err, retcode = ReturnCode.Success) +end + +end diff --git a/src/Integrals.jl b/src/Integrals.jl index 7d08992b..49a430b1 100644 --- a/src/Integrals.jl +++ b/src/Integrals.jl @@ -428,6 +428,7 @@ export CubaVegas, CubaSUAVE, CubaDivonne, CubaCuhre export CubatureJLh, CubatureJLp export ArblibJL export HAdaptiveIntegrationJL +export FastTanhSinhQuadratureJL export ChangeOfVariables export transformation_if_inf, transformation_tan_inf, transformation_cot_inf diff --git a/src/algorithms_extension.jl b/src/algorithms_extension.jl index 6147156c..474df292 100644 --- a/src/algorithms_extension.jl +++ b/src/algorithms_extension.jl @@ -326,3 +326,46 @@ function HAdaptiveIntegrationJL(; kws...) error("HAdaptiveIntegrationJL requires `using HAdaptiveIntegration`") return HAdaptiveIntegrationJL(NamedTuple(kws)) end + +""" + FastTanhSinhQuadratureJL(; tol = 1e-12, max_levels = 10) + +One-dimensional adaptive Tanh-Sinh (double exponential) quadrature from FastTanhSinhQuadrature.jl. +This method uses a double exponential transformation that provides excellent convergence properties, +especially for integrands with endpoint singularities or infinite derivatives at endpoints. + +## Keyword Arguments + + - `tol`: Relative tolerance for convergence (default: `1e-12`) + - `max_levels`: Maximum number of refinement levels in adaptive integration (default: `10`) + +## Limitations + + - Only supports 1D, 2D, and 3D integration + - Does not support batched evaluation + - Does not support in-place integrands + +## References + +```tex +@article{takahasi1974double, +title={Double exponential formulas for numerical integration}, +author={Takahasi, Hidetosi and Mori, Masatake}, +journal={Publications of the Research Institute for Mathematical Sciences}, +volume={9}, +number={3}, +pages={721--741}, +year={1974}, +publisher={Research Institute for Mathematical Sciences} +} +``` +""" +struct FastTanhSinhQuadratureJL{T} <: AbstractIntegralExtensionAlgorithm + tol::T + max_levels::Int +end +function FastTanhSinhQuadratureJL(; tol = 1e-12, max_levels = 10) + isnothing(Base.get_extension(@__MODULE__, :IntegralsFastTanhSinhQuadratureExt)) && + error("FastTanhSinhQuadratureJL requires `using FastTanhSinhQuadrature`") + return FastTanhSinhQuadratureJL(tol, max_levels) +end diff --git a/test/interface_tests.jl b/test/interface_tests.jl index 306f0caa..4aa141bd 100644 --- a/test/interface_tests.jl +++ b/test/interface_tests.jl @@ -1,5 +1,5 @@ using Integrals -using Cuba, Cubature, Arblib, FastGaussQuadrature, MCIntegration +using Cuba, Cubature, Arblib, FastGaussQuadrature, FastTanhSinhQuadrature, MCIntegration using Test max_dim_test = 2 @@ -61,6 +61,9 @@ alg_req = Dict( ), ArblibJL() => ( nout = 1, allows_batch = false, min_dim = 1, max_dim = 1, allows_iip = false, + ), + FastTanhSinhQuadratureJL() => ( + nout = Inf, allows_batch = false, min_dim = 1, max_dim = 3, allows_iip = false, ) ) From 792b05561ba1b16aaedb7c5ce16259feba0d48b9 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Fri, 3 Apr 2026 21:22:02 -0400 Subject: [PATCH 2/5] Add verbose kwarg to FastTanhSinhQuadrature extension The upstream master added a verbose keyword argument passed through the IntegralCache fallback. The extension needs to accept it to avoid MethodError on the kwarg mismatch. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.6 (1M context) --- ext/IntegralsFastTanhSinhQuadratureExt.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/IntegralsFastTanhSinhQuadratureExt.jl b/ext/IntegralsFastTanhSinhQuadratureExt.jl index f6c89484..e717d2ec 100644 --- a/ext/IntegralsFastTanhSinhQuadratureExt.jl +++ b/ext/IntegralsFastTanhSinhQuadratureExt.jl @@ -8,7 +8,8 @@ function Integrals.__solvebp_call( prob::IntegralProblem, alg::Integrals.FastTanhSinhQuadratureJL, sensealg, domain, p; reltol = nothing, abstol = nothing, - maxiters = nothing + maxiters = nothing, + verbose = Integrals.DEFAULT_VERBOSE ) lb, ub = domain f = prob.f From 8b9fce92977b2d375aa57d3a3034a2dcbc12bcb0 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Fri, 3 Apr 2026 21:32:28 -0400 Subject: [PATCH 3/5] Fix Runic formatting: 1e-12 -> 1.0e-12 Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.6 (1M context) --- src/algorithms_extension.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms_extension.jl b/src/algorithms_extension.jl index 474df292..81d5dbcf 100644 --- a/src/algorithms_extension.jl +++ b/src/algorithms_extension.jl @@ -364,7 +364,7 @@ struct FastTanhSinhQuadratureJL{T} <: AbstractIntegralExtensionAlgorithm tol::T max_levels::Int end -function FastTanhSinhQuadratureJL(; tol = 1e-12, max_levels = 10) +function FastTanhSinhQuadratureJL(; tol = 1.0e-12, max_levels = 10) isnothing(Base.get_extension(@__MODULE__, :IntegralsFastTanhSinhQuadratureExt)) && error("FastTanhSinhQuadratureJL requires `using FastTanhSinhQuadrature`") return FastTanhSinhQuadratureJL(tol, max_levels) From 31a8da609e10cad3dccce5c165fd92757454dbf0 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Fri, 3 Apr 2026 23:09:13 -0400 Subject: [PATCH 4/5] Restrict FastTanhSinhQuadratureJL to scalar integrands in tests FastTanhSinhQuadrature.quad does not support vector-valued integrands (it attempts scalar addition on vector results). Set nout = 1 to skip vector integrand tests for this algorithm. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.6 (1M context) --- test/interface_tests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/interface_tests.jl b/test/interface_tests.jl index 4aa141bd..8c334ea0 100644 --- a/test/interface_tests.jl +++ b/test/interface_tests.jl @@ -63,7 +63,7 @@ alg_req = Dict( nout = 1, allows_batch = false, min_dim = 1, max_dim = 1, allows_iip = false, ), FastTanhSinhQuadratureJL() => ( - nout = Inf, allows_batch = false, min_dim = 1, max_dim = 3, allows_iip = false, + nout = 1, allows_batch = false, min_dim = 1, max_dim = 3, allows_iip = false, ) ) From 79de5fe8c2afdcd6f909cdda37801d06e5462338 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Fri, 3 Apr 2026 23:49:56 -0400 Subject: [PATCH 5/5] Set nout = 0 for FastTanhSinhQuadratureJL to skip all vector integrand tests Even nout=1 creates a length-1 Vector output which FastTanhSinhQuadrature.quad cannot handle (it requires scalar return values). Setting nout=0 skips all vector-valued integrand tests. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.6 (1M context) --- test/interface_tests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/interface_tests.jl b/test/interface_tests.jl index 8c334ea0..963fcef8 100644 --- a/test/interface_tests.jl +++ b/test/interface_tests.jl @@ -63,7 +63,7 @@ alg_req = Dict( nout = 1, allows_batch = false, min_dim = 1, max_dim = 1, allows_iip = false, ), FastTanhSinhQuadratureJL() => ( - nout = 1, allows_batch = false, min_dim = 1, max_dim = 3, allows_iip = false, + nout = 0, allows_batch = false, min_dim = 1, max_dim = 3, allows_iip = false, ) )