I have a code which calculates complicated integral and which one should be used depends on the parameters. The code is chronically type-unstable (union with Core.Box appears) which makes it few times slower than it should be. The MWE is like this
using QuadGK
function f1(x,b)
x < 0 && ( b = -b )
I, _err = quadgk(t->exp(-t*b),0,1)
return I
end
You can also try b = sign(x)*b, result is the same. In this case I can fix it by switching to
function f2(x,b)
I, _err = if x < 0
quadgk(t->exp(-t*b),0,1)
else
quadgk(t->exp(t*b),0,1)
end
return I
end
But it is hard to understand why this behaviour occurs, and in the full code I have multiple conditions to deal with.
Reassigning a captured variable like b at any point currently makes the lowerer implement it as a Core.Box field in the closureβs type. In your fix, you donβt reassign b, you just switch between different closures. Alternatively, you could capture a new local variable b2 = if x < 0; -b else b end or the branchless b2 = ifelse(x<0, -b, b).
I think this is the usual problem with captured mutated variables in closures (julia#15276). A simple workaround is to re-assign b to a local variable in a let block before capturing it:
The part of your @code_warntype f3(-1.,1.) printout that pertains to the closure is concretely typed. The type instability starts with Main.quadgk::Any, compared with my Main.quadgk::Core.Const(QuadGK.quadgk). I can replicate that if I did using QuadGK; quadgk = QuadGK.quadgk in a module, though itβs hard for me to imagine you doing that. The const-ness of global variables is irreversible, but you can still try using QuadGK: quadgk and a duplicate f3 in a fresh module or session.
I doubt itβs version dependent, but Iβm using QuadGK v2.11.3, Julia v1.12.6.
All right, sorry for the confusion. I canβt say for sure what happened before but likely at some point I switched to Julia instance with QuadGK unloaded, which did not change the result much for other variants but obviously did for ifelse one. Thanks for checking thoroughly!
Thank you for all the responses. I managed to remove all instabilities. I defined internal functions too call them out in main if else statements, and then I treated smaller branches inside these functions with ifelse. The function now runs 3x faster.