JuliaPhysics / JuliaPhysics/Unitful.jl

u"A^(3/2)" fails to infer

Open
#367 7 comments 0 reactions 0 assignees View on GitHub
Dominant language
Julia
Stars
675
Forks
124
Avg merge
3h 38m
Merged PRs (30d)
1

Description

I need to work with some values with non-integer powers, and ran into some issue getting code to run without allocations. I think it's due to an inference failure. In the following example (with Unitful 1.3) I call `Base.literal_pow` explicitly to try to make sure the exponent is known at compile time, and despite this the output of `@code_warntype` shows the return value as `::Any` and `@btime` shows 3 allocation.

Related discourse post: https://discourse.julialang.org/t/calculate-i-a-2-3-with-no-allocations-with-unitful/42998/2

```
julia> I = 1u"A"
1 A

julia> A = 1.0u"A/K^(3/2)"
1.0 A K⁻³ᐟ²

julia> f(I, A) = Base.literal_pow(^,I/A, Val(2//3))
f (generic function with 1 method)

julia> @code_warntype f(I, A)
Variables
#self#::Core.Compiler.Const(f, false)
I::Quantity{Int64,𝐈,Unitful.FreeUnits{(A,),𝐈,nothing}}
A::Quantity{Float64,𝐈 𝚯⁻³ᐟ²,Unitful.FreeUnits{(A, K⁻³ᐟ²),𝐈 𝚯⁻³ᐟ²,nothing}}

Body::Any
1 ─ %1 = Base.literal_pow::Core.Compiler.Const(Base.literal_pow, false)
│ %2 = (I / A)::Quantity{Float64,𝚯³ᐟ²,Unitful.FreeUnits{(K³ᐟ²,),𝚯³ᐟ²,nothing}}
│ %3 = (2 // 3)::Rational{Int64}
│ %4 = Main.Val(%3)::Val{_A} where _A
│ %5 = (%1)(Main.:^, %2, %4)::Any
└── return %5

julia> @btime f($I, $A)
7.500 μs (3 allocations: 64 bytes)
1.0 K

julia> @which Base.literal_pow(^, A, Val(3//2))
literal_pow(::typeof(^), x::Unitful.AbstractQuantity, ::Val{v}) where v in Unitful at /Users/user/.julia/packages/Unitful/MOEUx/src/quantities.jl:461

julia> versioninfo()
Julia Version 1.4.0
Commit b8e9a9ecc6 (2020-03-21 16:36 UTC)
Platform Info:
OS: macOS (x86_64-apple-darwin18.6.0)
CPU: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-8.0.1 (ORCJIT, skylake)

```

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with Unitful/src/quantities.jl around the literal_pow method at line 461, then reproduce the example using Julia 1.4 with @code_warntype and @btime. Trace why Base.literal_pow(^, I/A, Val(2//3)) returns Any and allocations; done means the reported expression has inferred output and no unexpected allocations, with regression coverage if the existing tests provide a suitable location.

Written by the indexing model from the issue text.

Assessment

Tech stack
julia
Domain
performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.