How do I convert a large Array to a StaticArray

What is the best way to convert a larger array to a StaticArray. I have tried the following which works fine for a small array but not for a medium size.

using StaticArrays

# this works
A1 = zeros(UInt16, (3, 4, 5));
@time S1 = SArray{Tuple{3, 4, 5}, UInt16, 3, length(A1)}(A1);

# this hangs and does not finish in 10 min
A2 = zeros(UInt16, (64, 64, 30));
@time S2 = SArray{Tuple{64, 64, 30}, UInt16, 3, length(A2)}(A2)
1 Like

From the docs:

Note that in the current implementation, working with large StaticArray s puts a lot of stress on the compiler, and becomes slower than Base.Array as the size increases. A very rough rule of thumb is that you should consider using a normal Array for arrays larger than 100 elements.

1 Like

Thank you for the answer. I will have to refactor some code then. I liked to use the static arrays because I could have the size as part of the type but I will just find another way to handle it.

See also What's the deal with StaticArrays? - #2 by stevengj

1 Like

In case it’s relevant to your use case, it’s okay to have large Arrays of small-ish StaticArrays. For example, zeros(SVector{64, UInt16}, 64, 30) (i.e., a Matrix{<:SVector{64}}) is still within the usable size for SVector. A common example of this pattern is storing large sets of 3D coordinates as a Vector{SVector{3,Float64}}.

Although zeros(SMatrix{64, 64, UInt16}, 30) is too large a SMatrix to be useful, so this pattern only goes so far. It would probably compile in a mostly-usable amount of time, but its performance would be similar to or worse than a similarly-sized Matrix.

1 Like

Did you consider to use a SizedArray? API · StaticArrays.jl

Thanks for the answers. For context I am implementing a data reader EUMETlab / Cross-Cutting Tools / MetopNative.jl · GitLab

I was autogenerating structs for each record type and many of the fields are fixed sized Arrays. I was using StaticArrays for these fields so the record type contained all necessary information to read the record from disk.

Sized Array could be the answer for this. I will try it out. Alternatively I will just switch to regular arrays and pipe the array sizes around separately.

A regular array has a size attached, just not as part of the type — just call size(A). You don’t need to pass the array size separately.

Why do you want the size to be part of the type, as opposed to being stored in the object?

I have just tried SizedArray. It is easy to construct large SizedArrays but I quick run into compile issues again when I try to use the large SizedArrays. I am sure I can find workaround for many of the things but right now it is cleaner just to switch to regular Arrays. Here is a dummy example:

using StaticArrays

# Construction works fine now 
A = zeros(UInt16, (10, 10, 10));
T = SizedArray{Tuple{size(A)...}, eltype(A), ndims(A), ndims(A), typeof(A)}
@time S = T(A);
S2 = T(copy(A));

# using the SizedArray uses a lot of compile time 
@time all(S .== S2) # 8.2 seconds, 100 % compile time
@time all(A .== S2) # 13.12 seconds, 100 % compile time

I am reading several fixed sized array fields from a binary file format. Reading these fields I need to know that they are arrays, the element type and the size of the array. It was therefore convenient to have the size as part of the type.