LogarithmicNumbers.jl
LogarithmicNumbers.jl copied to clipboard
QuadGK is type unstable for `ULogFloat64`
I noticed a somewhat odd interaction with QuadGK.jl and a type instability for ULogFloat64.
Below is a MWE.
import LogarithmicNumbers, QuadGK
QuadGK.quadgk(x -> x^2, LogarithmicNumbers.LogFloat64(0), LogarithmicNumbers.LogFloat64(1))
# (+exp(-1.0986122886681098), 0.0)
QuadGK.quadgk(x -> x^2, LogarithmicNumbers.ULogFloat64(0), LogarithmicNumbers.ULogFloat64(1))
# (+exp(-1.0986122886681098), 0.0)
both work, although I noticed that the error term has type Float64 instead of LogFloat64. However,
@code_warntype QuadGK.quadgk(x -> x^2, LogarithmicNumbers.ULogFloat64(0), LogarithmicNumbers.ULogFloat64(1))
shows type instabilities. Specifically,
import LinearAlgebra
f(x) = x^2
segs = (zero(LogarithmicNumbers.ULogFloat64), one(LogarithmicNumbers.ULogFloat64))
atol=nothing; rtol=nothing; maxevals=10^7; order=7; segbuf=nothing; eval_segbuf=nothing
@code_warntype QuadGK.handle_infinities(f, segs) do f, s, _
QuadGK.do_quadgk(f, s, order, atol, rtol, maxevals, LinearAlgebra.norm, segbuf, eval_segbuf)
end
is type unstable:
MethodInstance for QuadGK.handle_infinities(::var"#19#20", ::typeof(f), ::Tuple{LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.ULogFloat64})
from handle_infinities(workfunc, f, s) @ QuadGK ~/.julia/packages/QuadGK/wnfvV/src/adapt.jl:163
Arguments
#self#::Core.Const(QuadGK.handle_infinities)
workfunc::Core.Const(var"#19#20"())
f::Core.Const(f)
s::Tuple{LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.ULogFloat64}
Locals
#14::QuadGK.var"#14#23"{LogarithmicNumbers.ULogFloat64}
#13::QuadGK.var"#13#22"
#12::QuadGK.var"#12#21"{typeof(f), LogarithmicNumbers.ULogFloat64}
inf2::Bool
inf1::Bool
s2::LogarithmicNumbers.ULogFloat64
s1::LogarithmicNumbers.ULogFloat64
#20::QuadGK.var"#20#29"{LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.ULogFloat64}
#19::QuadGK.var"#19#28"{LogarithmicNumbers.ULogFloat64}
#18::QuadGK.var"#18#27"{typeof(f), LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.ULogFloat64}
#17::QuadGK.var"#17#26"{LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.ULogFloat64}
#16::QuadGK.var"#16#25"{LogarithmicNumbers.ULogFloat64}
#15::QuadGK.var"#15#24"{typeof(f), LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.ULogFloat64}
@_18::Int64
si::LogarithmicNumbers.ULogFloat64
s0::LogarithmicNumbers.ULogFloat64
@_21::Tuple{LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.ULogFloat64}
Body::Tuple
1 ── Core.NewvarNode(:(#14))
│ Core.NewvarNode(:(#13))
│ Core.NewvarNode(:(#12))
│ Core.NewvarNode(:(inf2))
│ Core.NewvarNode(:(inf1))
│ %6 = Base.getindex(s, 1)::LogarithmicNumbers.ULogFloat64
│ %7 = Base.lastindex(s)::Core.Const(2)
│ %8 = Base.getindex(s, %7)::LogarithmicNumbers.ULogFloat64
│ (s1 = %6)
│ (s2 = %8)
│ %11 = QuadGK.realone(s1)::Core.Const(true)
└─── goto #16 if not %11
2 ── %13 = QuadGK.realone(s2)::Core.Const(true)
└─── goto #16 if not %13
3 ── %15 = QuadGK.isinf(s1)::Bool
│ %16 = QuadGK.isinf(s2)::Bool
│ (inf1 = %15)
│ (inf2 = %16)
└─── goto #5 if not inf1
4 ── goto #6
5 ── goto #16 if not inf2
6 ┄─ goto #9 if not inf1
7 ── goto #9 if not inf2
8 ── %24 = QuadGK.:(var"#12#21")::Core.Const(QuadGK.var"#12#21")
│ %25 = Core.typeof(f)::Core.Const(typeof(f))
│ %26 = Core.typeof(s1)::Core.Const(LogarithmicNumbers.ULogFloat64)
│ %27 = Core.apply_type(%24, %25, %26)::Core.Const(QuadGK.var"#12#21"{typeof(f), LogarithmicNumbers.ULogFloat64})
│ (#12 = %new(%27, f, s1))
│ %29 = #12::QuadGK.var"#12#21"{typeof(f), LogarithmicNumbers.ULogFloat64}
│ (#13 = %new(QuadGK.:(var"#13#22")))
│ %31 = #13::Core.Const(QuadGK.var"#13#22"())
│ %32 = QuadGK.map(%31, s)::Tuple{Union{LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.LogFloat64}, Union{LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.LogFloat64}}
│ %33 = QuadGK.:(var"#14#23")::Core.Const(QuadGK.var"#14#23")
│ %34 = Core.typeof(s1)::Core.Const(LogarithmicNumbers.ULogFloat64)
│ %35 = Core.apply_type(%33, %34)::Core.Const(QuadGK.var"#14#23"{LogarithmicNumbers.ULogFloat64})
│ (#14 = %new(%35, s1))
│ %37 = #14::QuadGK.var"#14#23"{LogarithmicNumbers.ULogFloat64}
│ %38 = (workfunc)(%29, %32, %37)::Tuple
└─── return %38
9 ┄─ goto #11 if not inf1
10 ─ (@_21 = Core.tuple(s2, s1))
└─── goto #12
11 ─ (@_21 = Core.tuple(s1, s2))
12 ┄ %44 = @_21::Tuple{LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.ULogFloat64}
│ Core.NewvarNode(:(#20))
│ Core.NewvarNode(:(#19))
│ Core.NewvarNode(:(#18))
│ Core.NewvarNode(:(#17))
│ Core.NewvarNode(:(#16))
│ Core.NewvarNode(:(#15))
│ %51 = Base.indexed_iterate(%44, 1)::Core.PartialStruct(Tuple{LogarithmicNumbers.ULogFloat64, Int64}, Any[LogarithmicNumbers.ULogFloat64, Core.Const(2)])
│ (s0 = Core.getfield(%51, 1))
│ (@_18 = Core.getfield(%51, 2))
│ %54 = Base.indexed_iterate(%44, 2, @_18::Core.Const(2))::Core.PartialStruct(Tuple{LogarithmicNumbers.ULogFloat64, Int64}, Any[LogarithmicNumbers.ULogFloat64, Core.Const(3)])
│ (si = Core.getfield(%54, 1))
│ %56 = si::LogarithmicNumbers.ULogFloat64
│ %57 = QuadGK.zero(si)::Core.Const(exp(-Inf))
│ %58 = (%56 < %57)::Bool
└─── goto #15 if not %58
13 ─ %60 = QuadGK.:(var"#15#24")::Core.Const(QuadGK.var"#15#24")
│ %61 = Core.typeof(f)::Core.Const(typeof(f))
│ %62 = Core.typeof(s1)::Core.Const(LogarithmicNumbers.ULogFloat64)
│ %63 = Core.typeof(s0)::Core.Const(LogarithmicNumbers.ULogFloat64)
│ %64 = Core.apply_type(%60, %61, %62, %63)::Core.Const(QuadGK.var"#15#24"{typeof(f), LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.ULogFloat64})
│ %65 = s1::LogarithmicNumbers.ULogFloat64
│ (#15 = %new(%64, f, %65, s0))
│ %67 = #15::QuadGK.var"#15#24"{typeof(f), LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.ULogFloat64}
│ %68 = QuadGK.:(var"#16#25")::Core.Const(QuadGK.var"#16#25")
│ %69 = Core.typeof(s0)::Core.Const(LogarithmicNumbers.ULogFloat64)
│ %70 = Core.apply_type(%68, %69)::Core.Const(QuadGK.var"#16#25"{LogarithmicNumbers.ULogFloat64})
│ (#16 = %new(%70, s0))
│ %72 = #16::QuadGK.var"#16#25"{LogarithmicNumbers.ULogFloat64}
│ %73 = QuadGK.map(%72, s)::Tuple{LogarithmicNumbers.LogFloat64, LogarithmicNumbers.LogFloat64}
│ %74 = QuadGK.reverse(%73)::Tuple{LogarithmicNumbers.LogFloat64, LogarithmicNumbers.LogFloat64}
│ %75 = QuadGK.:(var"#17#26")::Core.Const(QuadGK.var"#17#26")
│ %76 = Core.typeof(s1)::Core.Const(LogarithmicNumbers.ULogFloat64)
│ %77 = Core.typeof(s0)::Core.Const(LogarithmicNumbers.ULogFloat64)
│ %78 = Core.apply_type(%75, %76, %77)::Core.Const(QuadGK.var"#17#26"{LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.ULogFloat64})
│ %79 = s1::LogarithmicNumbers.ULogFloat64
│ (#17 = %new(%78, %79, s0))
│ %81 = #17::QuadGK.var"#17#26"{LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.ULogFloat64}
│ %82 = (workfunc)(%67, %74, %81)::Tuple
└─── return %82
14 ─ Core.Const(:(goto %108))
15 ┄ %85 = QuadGK.:(var"#18#27")::Core.Const(QuadGK.var"#18#27")
│ %86 = Core.typeof(f)::Core.Const(typeof(f))
│ %87 = Core.typeof(s1)::Core.Const(LogarithmicNumbers.ULogFloat64)
│ %88 = Core.typeof(s0)::Core.Const(LogarithmicNumbers.ULogFloat64)
│ %89 = Core.apply_type(%85, %86, %87, %88)::Core.Const(QuadGK.var"#18#27"{typeof(f), LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.ULogFloat64})
│ %90 = s1::LogarithmicNumbers.ULogFloat64
│ (#18 = %new(%89, f, %90, s0))
│ %92 = #18::QuadGK.var"#18#27"{typeof(f), LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.ULogFloat64}
│ %93 = QuadGK.:(var"#19#28")::Core.Const(QuadGK.var"#19#28")
│ %94 = Core.typeof(s0)::Core.Const(LogarithmicNumbers.ULogFloat64)
│ %95 = Core.apply_type(%93, %94)::Core.Const(QuadGK.var"#19#28"{LogarithmicNumbers.ULogFloat64})
│ (#19 = %new(%95, s0))
│ %97 = #19::QuadGK.var"#19#28"{LogarithmicNumbers.ULogFloat64}
│ %98 = QuadGK.map(%97, s)::Tuple{LogarithmicNumbers.LogFloat64, LogarithmicNumbers.LogFloat64}
│ %99 = QuadGK.:(var"#20#29")::Core.Const(QuadGK.var"#20#29")
│ %100 = Core.typeof(s1)::Core.Const(LogarithmicNumbers.ULogFloat64)
│ %101 = Core.typeof(s0)::Core.Const(LogarithmicNumbers.ULogFloat64)
│ %102 = Core.apply_type(%99, %100, %101)::Core.Const(QuadGK.var"#20#29"{LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.ULogFloat64})
│ %103 = s1::LogarithmicNumbers.ULogFloat64
│ (#20 = %new(%102, %103, s0))
│ %105 = #20::QuadGK.var"#20#29"{LogarithmicNumbers.ULogFloat64, LogarithmicNumbers.ULogFloat64}
│ %106 = (workfunc)(%92, %98, %105)::Tuple
└─── return %106
16 ┄ %108 = (workfunc)(f, s, QuadGK.identity)::Tuple
└─── return %108
the highlighting on GitHub doesn't quite show it but all output from workfunc returns an untyped Tuple.
I played around with some ways to resolve this but it's not entirely clear to me what the best way to fix this would be. In addition, I had a few questions.
- Why is it that
Logarithmic <: Real, instead ofLogarithmic <: AbstractFloat? - Why isn't
floatdefined asfloat(x::Logarithmic) = x?
As a learning project, I ported the R package Brobdingag to Julia (which does essentially the same as this package). There, I did make those decisions and then QuadGK worked without issues, although I'm sure there are reasons for doing otherwise.