Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive unitless element type

I am trying to come up with a function that gives me the recursive unitless element type. So for example, to shorten it let's call it ruet, I would like to have:

A = zeros(5,5)
reut(A) == Float64
using Unitful
A = zeros(5,5)*1u"kg"
reut(A) == Float64
AA = [zeros(5,5) for i in 1:5]
reut(AA) == Array{Float64,2}
AofA = [copy(A) for i in 1:5]
reut(AofA) == Array{Float64,2}
using StaticArrays
AofSA = [@SVector [2.0,3.0] for i in 1:5]
reut(AofSA) == SVector{2,Float64}
AofuSA = [@SVector [2.0u"kg",3.0u"kg"] for i in 1:5]
reut(AofuSA) == SVector{2,Float64}

So basically strip away the units but still return the correct element type, which could be an array. It's the array part that's hard. I can recurse:

recursive_eltype(a) = recursive_eltype(eltype(a))
recursive_eltype{T<:Number}(a::Type{T}) = eltype(a)

and then get the unitless element type:

uEltype = recursive_eltype(u)
uEltypeNoUnits = typeof(one(uEltype))

but then this is always the number type, and I can't seem to find a good way to get back the array types when it's an array of arrays, i.e. this method is returning Float64 in all of the examples above. I am wondering if dispatching on static arrays and using similar_type is required here.

Note that I would like the solution to, if possible, not have a requirement on Unitful.jl. Getting the unitless type for the number can be done via one(u), so I think this should be possible.

(Somewhat related Julia issue: https://github.com/JuliaLang/julia/issues/22216)

like image 987
Chris Rackauckas Avatar asked Sep 27 '26 14:09

Chris Rackauckas


2 Answers

I came up with:

Base.@pure recursive_unitless_eltype(a) = recursive_unitless_eltype(eltype(a))
Base.@pure recursive_unitless_eltype{T<:StaticArray}(a::Type{T}) = similar_type(a,recursive_unitless_eltype(eltype(a)))
Base.@pure recursive_unitless_eltype{T<:Array}(a::Type{T}) = Array{recursive_unitless_eltype(eltype(a)),ndims(a)}
Base.@pure recursive_unitless_eltype{T<:Number}(a::Type{T}) = typeof(one(eltype(a)))

This still isn't fully generic, but works on quite a broad range of things.

like image 196
Chris Rackauckas Avatar answered Sep 29 '26 04:09

Chris Rackauckas


Using Julia version 0.6.2-something (code surely not very portable):

function _reut(T)
    try
        T.name == Quantity.body.body.body.name && return _reut(T.parameters[1])
        getfield(T.name.module, T.name.name){_reut.(collect(T.parameters))...}
    catch
        T
    end
end
reut(T) = _reut(eltype(T))

And the tests in the question pass. Still not inferrable, but replaced eval with getfield(Module,Symbol). Where do you get these questions?

like image 33
Dan Getz Avatar answered Sep 29 '26 03:09

Dan Getz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!