Hi! I am having trouble with the type stability of quadgk when the integrand function is using quadgk itself. Here is the MWE:
using QuadGK
f(x) = quadgk(y -> x*y, 0., 1.)[1]
quadgk(f, 0., 1.)
Using code_warntype on the latter function gives that the return type is Tuple{Any, Any}:
julia> @code_warntype quadgk(f, 0., 1.)
MethodInstance for QuadGK.quadgk(::typeof(f), ::Float64, ::Float64)
from quadgk(f, segs::T...; atol, rtol, maxevals, order, norm, segbuf, eval_segbuf) where T @ QuadGK ~/.julia/packages/QuadGK/7rND3/src/api.jl:80
Static Parameters
T = Float64
Arguments
#self#::Core.Const(QuadGK.quadgk)
f::Core.Const(f)
segs::Tuple{Float64, Float64}
Locals
atol::Nothing
rtol::Nothing
maxevals::Int64
order::Int64
norm::typeof(LinearAlgebra.norm)
segbuf::Nothing
eval_segbuf::Nothing
Body::Tuple{Any, Any}
1 ─ %1 = QuadGK.nothing::Core.Const(nothing)
│ (atol = %1)
│ %3 = QuadGK.nothing::Core.Const(nothing)
│ (rtol = %3)
│ %5 = QuadGK.:^::Core.Const(^)
│ %6 = Core.apply_type(Base.Val, 7)::Core.Const(Val{7})
│ %7 = (%6)()::Core.Const(Val{7}())
│ %8 = Base.literal_pow(%5, 10, %7)::Core.Const(10000000)
│ (maxevals = %8)
│ %10 = 7::Core.Const(7)
│ (order = %10)
│ %12 = QuadGK.norm::Core.Const(LinearAlgebra.norm)
│ (norm = %12)
│ %14 = QuadGK.nothing::Core.Const(nothing)
│ (segbuf = %14)
│ %16 = QuadGK.nothing::Core.Const(nothing)
│ (eval_segbuf = %16)
│ %18 = QuadGK.:(var"#quadgk#49")::Core.Const(QuadGK.var"#quadgk#49")
│ %19 = Core.tuple(atol, rtol, maxevals::Core.Const(10000000), order::Core.Const(7), norm, segbuf, eval_segbuf, #self#, f)::Core.Const((nothing, nothing, 10000000, 7, LinearAlgebra.norm, nothing, nothing, QuadGK.quadgk, f))
│ %20 = Core._apply_iterate(Base.iterate, %18, %19, segs)::Tuple{Any, Any}
└── return %20
I initially thought that maybe this was due to performance of captured variables in closures · Issue #15276 · JuliaLang/julia · GitHub, but the usual fix does not seem to help:
function g(x)
G = let x=x
y -> x*y
end
quadgk(G, 0., 1.)[1]
end
quadgk(g, 0., 1.)
The code_warntype here shows the same type unstable result Tuple{Any, Any}:
julia> @code_warntype quadgk(g, 0., 1.)
MethodInstance for QuadGK.quadgk(::typeof(g), ::Float64, ::Float64)
from quadgk(f, segs::T...; atol, rtol, maxevals, order, norm, segbuf, eval_segbuf) where T @ QuadGK ~/.julia/packages/QuadGK/7rND3/src/api.jl:80
Static Parameters
T = Float64
Arguments
#self#::Core.Const(QuadGK.quadgk)
f::Core.Const(g)
segs::Tuple{Float64, Float64}
Locals
atol::Nothing
rtol::Nothing
maxevals::Int64
order::Int64
norm::typeof(LinearAlgebra.norm)
segbuf::Nothing
eval_segbuf::Nothing
Body::Tuple{Any, Any}
1 ─ %1 = QuadGK.nothing::Core.Const(nothing)
│ (atol = %1)
│ %3 = QuadGK.nothing::Core.Const(nothing)
│ (rtol = %3)
│ %5 = QuadGK.:^::Core.Const(^)
│ %6 = Core.apply_type(Base.Val, 7)::Core.Const(Val{7})
│ %7 = (%6)()::Core.Const(Val{7}())
│ %8 = Base.literal_pow(%5, 10, %7)::Core.Const(10000000)
│ (maxevals = %8)
│ %10 = 7::Core.Const(7)
│ (order = %10)
│ %12 = QuadGK.norm::Core.Const(LinearAlgebra.norm)
│ (norm = %12)
│ %14 = QuadGK.nothing::Core.Const(nothing)
│ (segbuf = %14)
│ %16 = QuadGK.nothing::Core.Const(nothing)
│ (eval_segbuf = %16)
│ %18 = QuadGK.:(var"#quadgk#49")::Core.Const(QuadGK.var"#quadgk#49")
│ %19 = Core.tuple(atol, rtol, maxevals::Core.Const(10000000), order::Core.Const(7), norm, segbuf, eval_segbuf, #self#, f)::Core.Const((nothing, nothing, 10000000, 7, LinearAlgebra.norm, nothing, nothing, QuadGK.quadgk, g))
│ %20 = Core._apply_iterate(Base.iterate, %18, %19, segs)::Tuple{Any, Any}
└── return %20
Both f and g seem to be type-stable. Is there something I am missing here?