-
Notifications
You must be signed in to change notification settings - Fork 24
Support for Union{Nothing, <:IEEEFloat}
#620
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Mooncake.jl documentation for PR #620 is available at: |
|
I don't understand the Unbound type parameters detected:
[1] tangent_type(::Type{NoFData}, ::Type{Union{NoRData, T}}) where T<:Union{Float16, Float32, Float64} @ Mooncake ~/work/Mooncake.jl/Mooncake.jl/src/fwds_rvs_data.jl:864
[2] tangent_type(::Type{Union{NoFData, T}}, ::Type{NoRData}) where T<:(Array{<:Union{Float16, Float32, Float64}}) @ Mooncake ~/work/Mooncake.jl/Mooncake.jl/src/fwds_rvs_data.jl:867
Unbound type parameters: Test Failed at /home/runner/.julia/packages/Aqua/1UuaV/src/unbound_args.jl:37
Expression: isempty(unbounds)
Evaluated: isempty(Method[tangent_type(::Type{NoFData}, ::Type{Union{NoRData, T}}) where T<:Union{Float16, Float32, Float64} @ Mooncake ~/work/Mooncake.jl/Mooncake.jl/src/fwds_rvs_data.jl:864, tangent_type(::Type{Union{NoFData, T}}, ::Type{NoRData}) where T<:(Array{<:Union{Float16, Float32, Float64}}) @ Mooncake ~/work/Mooncake.jl/Mooncake.jl/src/fwds_rvs_data.jl:867]) |
|
I wonder if that is an Aqua.jl bug? Usually that error would be for things like f(x::Union{Float16,T}) where {T} = Twhich is a real issue. But when inside |
|
Performance Ratio: |
module Foo
struct Wat end
function f(::Type{Union{Wat,T}}) where {T <: Base.IEEEFloat}
return T
end
end
using Aqua
Aqua.test_unbound_args(Foo)
# ERROR: ...
Foo.f(Foo.Wat)
# Union {}
Foo.Wat isa Type{Union{Foo.Wat,T}} where {T <: Base.IEEEFloat}
# trueI have to confess that the last line is entirely unintuitive to me (but I suppose given this behaviour, Aqua is technically correct...?). (Edit: And then:) Float64 isa Type{Union{Foo.Wat,T}} where {T <: Base.IEEEFloat}
# false |
|
Ugh. Maybe it's special handling of |
julia> Float64 isa Type{Union{Foo.Wat,T}} where {T <: Base.IEEEFloat}
false
julia> Foo.Wat isa Type{Union{Foo.Wat,T}} where {T <: Base.IEEEFloat}
trueVery weird indeed |
|
Even weirder! julia> Union{Foo.Wat,Float32} isa Type{Union{Foo.Wat,T}} where {T <: Base.IEEEFloat}
trueOk @yebai I think the best solution is to just manually declare for each element of Base.IEEEFloat rather than use the union. |
|
It appears to be an edge behaviour of Julia that we don't understand... julia> Float64 isa Type{Union{Foo.Wat,T}} where {T <: Base.IEEEFloat}
false
julia> Foo.Wat isa Type{Union{Foo.Wat,T}} where {T <: Base.IEEEFloat}
true
julia> Union{Float16} isa Type{Union{Foo.Wat,T}} where {T <: Base.IEEEFloat}
false
julia> Union{Float16, Float32} isa Type{Union{Foo.Wat,T}} where {T <: Base.IEEEFloat}
false
julia> Union{Float16, Float32, Float64} isa Type{Union{Foo.Wat,T}} where {T <: Base.IEEEFloat}
false
julia> Union{Float16, Float32, Foo.Wat} isa Type{Union{Foo.Wat,T}} where {T <: Base.IEEEFloat}
true@ChrisRackauckas, @ViralBShah, maybe you have additional insights? |
|
@MilesCranmer, this is ready for another look. |
|
Thanks. Got some explanation here: https://discourse.julialang.org/t/weirdness-of-type-union-a-b-where-b-superb/130234/2?u=milescranmer. But at the moment I'm not sure any efficient way of writing this so let's just go with the current |
Co-authored-by: Miles Cranmer <[email protected]> Signed-off-by: Hong Ge <[email protected]>
|
Actually, I think it's fine as-is. Because that unbounded form is never actually matched! julia> struct Foo end
julia> f(::Type{Union{Foo,T}}) where {T<:Base.IEEEFloat} = T
f (generic function with 1 method)
julia> f(Foo) # If we hadn't defined another method - we WOULD see the unbounded form
Union{}
julia> f(::Type{Foo}) = Foo
f (generic function with 2 methods)
julia> f(Foo)
Foo
julia> f(Union{Foo,Float32})
Float32
julia> f(Union{Foo})
FooSo just need to skip that single Aqua error. I think it is preferable to match all |
|
Should be okay now -- Aqua has been annoying (though useful)! |
|
@MilesCranmer, I have invited you to this organisation so you can make new releases using @JuliaRegistrator. |
| for T in [Float16, Float32, Float64] | ||
| @eval @foldable tangent_type(::Type{NoFData}, ::Type{Union{NoRData,$T}}) = Union{ | ||
| NoTangent,tangent_type($T) | ||
| } | ||
| for N in 0:5 # Just go up to N=5 until general solution to https://github.com/chalk-lab/Mooncake.jl/pull/620 available | ||
| @eval @foldable tangent_type(::Type{Union{NoFData,Array{$T,$N}}}, ::Type{NoRData}) = Union{ | ||
| NoTangent,tangent_type(Array{$T,$N}) | ||
| } | ||
| end | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty sure it would be nicer to the compiler not to eval three duplicate methods. Something like this, for example:
| for T in [Float16, Float32, Float64] | |
| @eval @foldable tangent_type(::Type{NoFData}, ::Type{Union{NoRData,$T}}) = Union{ | |
| NoTangent,tangent_type($T) | |
| } | |
| for N in 0:5 # Just go up to N=5 until general solution to https://github.com/chalk-lab/Mooncake.jl/pull/620 available | |
| @eval @foldable tangent_type(::Type{Union{NoFData,Array{$T,$N}}}, ::Type{NoRData}) = Union{ | |
| NoTangent,tangent_type(Array{$T,$N}) | |
| } | |
| end | |
| end | |
| let f(@nospecialize x::Type) = Type{Union{NoRData, x}}, | |
| f16 = f(Float16), | |
| f32 = f(Float32), | |
| f64 = f(Float64) | |
| global tangent_type | |
| @foldable function tangent_type(::Type{NoFData}, u::Union{f16, f32, f64}) | |
| if u === f16 | |
| t = Float16 | |
| elseif u === f32 | |
| t = Float32 | |
| elseif u === f64 | |
| t = Float64 | |
| end | |
| Union{NoTangent, tangent_type(t)} | |
| end | |
| end | |
| for T in [Float16, Float32, Float64] | |
| for N in 0:5 # Just go up to N=5 until general solution to https://github.com/chalk-lab/Mooncake.jl/pull/620 available | |
| @eval @foldable tangent_type(::Type{Union{NoFData,Array{$T,$N}}}, ::Type{NoRData}) = Union{ | |
| NoTangent,tangent_type(Array{$T,$N}) | |
| } | |
| end | |
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will apply the same deduplication to the for N in 0:5 loop, if you wish.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could just use the unbounded form right? It's only an issue if there is ambiguity. But since Type{NoFData}, Type{NoRData} are defined, it never gets matched.
julia> struct Foo end
julia> foo(::Type{Union{Foo,B}}) where {B<:AbstractFloat} = B
foo (generic function with 1 method)
julia> foo(Foo) # Only issue here
Union{}
julia> foo(::Type{Foo}) = Foo
foo (generic function with 2 methods)
julia> foo(Foo)
Foo
julia> foo(Union{Foo,Float32})
Float32which would let us match to any N for the arrays rather than only up to 5.
| for T in [Float16, Float32, Float64] | ||
| @eval @foldable tangent_type(::Type{NoFData}, ::Type{Union{NoRData,$T}}) = Union{ | ||
| NoTangent,tangent_type($T) | ||
| } | ||
| for N in 0:5 # Just go up to N=5 until general solution to https://github.com/chalk-lab/Mooncake.jl/pull/620 available | ||
| @eval @foldable tangent_type(::Type{Union{NoFData,Array{$T,$N}}}, ::Type{NoRData}) = Union{ | ||
| NoTangent,tangent_type(Array{$T,$N}) | ||
| } | ||
| end | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| for T in [Float16, Float32, Float64] | |
| @eval @foldable tangent_type(::Type{NoFData}, ::Type{Union{NoRData,$T}}) = Union{ | |
| NoTangent,tangent_type($T) | |
| } | |
| for N in 0:5 # Just go up to N=5 until general solution to https://github.com/chalk-lab/Mooncake.jl/pull/620 available | |
| @eval @foldable tangent_type(::Type{Union{NoFData,Array{$T,$N}}}, ::Type{NoRData}) = Union{ | |
| NoTangent,tangent_type(Array{$T,$N}) | |
| } | |
| end | |
| end | |
| tangent_type(::Type{NoFData}, ::Type{Union{NoRData,T}}) where {T<:Base.IEEEFloat} = Union{ | |
| NoTangent,tangent_type(T) | |
| } | |
| tangent_type(::Type{Union{NoFData,Array{T,N}}}, ::Type{NoRData}) where {T<:Base.IEEEFloat,N} = Union{ | |
| NoTangent,tangent_type(Array{T,N}) | |
| } |
since NoFData and NoRData already have a method, the unbounded method issue never actually occurs. So just need to somehow inform Aqua that this particular instance is not an issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When T = Union{}, Array{T,N} would be problematic. But since this case is never called, as you noticed, it might be okay.
|
Please feel free to take over this PR or replace it with a new one! |
Codecov ReportAttention: Patch coverage is
📢 Thoughts on this report? Let us know! |
Fix #597 (again).