There have been a handful of threads on this forum regarding long compilation times for nested quadgk calls (e.g. here) and I was wondering what are some of the possible reasons that type inference may be failing in this case. As an example
julia> using QuadGK
julia> mysin(x) = quadgk(cos, 0, x, atol=1e-8)[1]
mysin (generic function with 1 method)
julia> mycos(x) = quadgk(mysin, 0, 1, atol=1e-7)[1]
mycos (generic function with 1 method)
julia> @code_warntype mycos(1.0) # returns Any
julia> @code_warntype mysin(1.0) # returns Float64
julia> @code_warntype mycos(1.0) # returns Float64
With tests like these we can only see the inference of mycos
fail if mysin
hasn’t been inferred before.
Since mysin
is inferrable, but mycos
is not (at least until mysin
is inferred), does the success/failure of inference suggest that the code of quadgk
too large/expensive to infer when doubly nested? Are closures (such as this) possibly responsible and in general are there any tips on writing code that is easier to infer when multiply nested?
I will add that we can make inference succeed by calling Base.promote_op
on the inner integral, for example (in a fresh session):
julia> using QuadGK
julia> mysin(x) = quadgk(cos, 0, x, atol=1e-8)[1]
mysin (generic function with 1 method)
julia> function mycos2(x)
F = float(typeof(x))
O = Base.promote_op(mysin, F)
return quadgk(mysin, 0, x, atol=1e-7)[1]
end
mycos2 (generic function with 1 method)
julia> @code_warntype mycos2(1.0) # returns Float64
Getting inference to work this way, or with FunctionWrappers, seems artificial, but it works.