SciML / LabelledArrays.jl

Arrays which also have a label for each element for easy scientific machine learning (SciML)
https://docs.sciml.ai/LabelledArrays/stable/
Other
120 stars 21 forks source link

Compiler cannot infer size of LArray? #153

Closed zauster closed 7 months ago

zauster commented 7 months ago

Question❓

Since LArrays are not resizable (correct?) I figured the compiler would be able to infer the size of the array. For SLArrays the compiler guesses it correctly.

Reprex:

## LArray
function length_larray(x::LArray{Int64, 1, Vector{Int64}, (:a, :b, :c)})
    length(x)
end

y = @LArray [1, 2, 3] (:a, :b, :c)
@code_warntype length_larray(y)
# MethodInstance for length_larray(::LArray{Int64, 1, Vector{Int64}, (:a, :b, :c)})
#   from length_larray(x::LArray{Int64, 1, Vector{Int64}, (:a, :b, :c)}) @ Main ~/Arbeit/Julia/test_flatten/src/test_labelledarrays.jl:23
# Arguments
#   #self#::Core.Const(length_larray)
#   x::LArray{Int64, 1, Vector{Int64}, (:a, :b, :c)}
# Body::Int64
# 1 ─ %1 = Main.length(x)::Int64
# └──      return %1

## SLArray
function length_slarray(x::SLArray{Tuple{3}, Int64, 1, 3, (:a, :b, :c)})
    length(x)
end

ABC = @SLVector (:a, :b, :c)
A = ABC(1, 2, 3)
@code_warntype length_slarray(A)
# MethodInstance for length_slarray(::SLArray{Tuple{3}, Int64, 1, 3, (:a, :b, :c)})
#   from length_slarray(x::SLArray{Tuple{3}, Int64, 1, 3, (:a, :b, :c)}) @ Main ~/Arbeit/Julia/test_flatten/src/test_labelledarrays.jl:43
# Arguments
#   #self#::Core.Const(length_slarray)
#   x::SLArray{Tuple{3}, Int64, 1, 3, (:a, :b, :c)}
# Body::Int64
# 1 ─ %1 = Main.length(x)::Core.Const(3) ## <== Compiler knows the length of 3
# └──      return %1

For a simulation model, I would like to use mutable, fixed-size, labelled arrays and I thought LArrays are exactly that. Is there something that I am missing or misunderstanding?

Thanks for any help or feedback!

ChrisRackauckas commented 7 months ago

The length of the array is not static but LArrays have the symbols in the types and that is static information. So something like:

function length_larray(x::LArray{Int64, 1, Vector{Int64}, S}) where S
    length(S)
end

would be static.

zauster commented 7 months ago

Thanks, but if the array cannot be resized (with push! or pop! or similar) why is its length not static?

ChrisRackauckas commented 7 months ago

It is, the compiler just isn't able to infer that.

ChrisRackauckas commented 7 months ago

In Julia v1.10 there's the new Memory object and we could in theory use that to make it inferable.

zauster commented 7 months ago

Thanks again for your quick response. I think I figured a way out, initialize the LArray with a SizedVector:

function length_larray2(x::LArray{Int64, 1, SizedVector{3, Int64}, (:a, :b, :c)})
    length(x)
end
y2 = LArray{Int64, 1, SizedVector{3, Int64}, (:a, :b, :c)}([1, 2, 3])
@code_warntype length_larray2(y2)
# MethodInstance for length_larray2(::LArray{Int64, 1, SizedVector{3, Int64, TData} where TData<:AbstractVector{Int64}, (:a, :b, :c)})
#   from length_larray2(x::LArray{Int64, 1, SizedVector{3, Int64, TData} where TData<:AbstractVector{Int64}, (:a, :b, :c)}) @ Main REPL[41]:1
# Arguments
#   #self#::Core.Const(length_larray2)
#   x::LArray{Int64, 1, SizedVector{3, Int64, TData} where TData<:AbstractVector{Int64}, (:a, :b, :c)}
# Body::Int64
# 1 ─ %1 = Main.length(x)::Core.Const(3)
# └──      return %1

Or is this somehow unadvisable?

ChrisRackauckas commented 7 months ago

Nope, that would be fine. We should probably do that internally.

zauster commented 7 months ago

Thanks for your help!