Whats the difference between a regular array and an array from StaticArrays


#1

Whats the difference between a regular array and an array from StaticArrays? From the docs, it seems that the size of array is known to the compiler based on the type, but isn’t this the same for a regular array as well, say Array{Int64}(3)?

Also, in what scenarios would we use either case? Up until now I’ve always used the regular built-in array but I am wondering if I can get a speed up using StaticArrays.


#2

The type of a regular Julia Array only includes the number of dimensions, not the size:

julia> typeof(Array{Int64}(3))
Array{Int64,1}

julia> typeof(Array{Int64}(10))
Array{Int64,1}

julia> typeof(Array{Int64}(1000000))
Array{Int64,1}

so the difference between a StaticArray and an Array is exactly what the docs here say: https://github.com/JuliaArrays/StaticArrays.jl , namely that the size of a StaticArray is actually part of the type:

julia> typeof(SVector(0, 0))
StaticArrays.SArray{Tuple{2},Int64,1,2}

julia> typeof(SVector(0, 0, 0))
StaticArrays.SArray{Tuple{3},Int64,1,3}

julia> typeof(SVector(0, 0, 0, 0))
StaticArrays.SArray{Tuple{4},Int64,1,4}

You would use StaticArrays when your program handles lots of small arrays (typically less than 100 elements) whose sizes are fixed or at least inferrable by the compiler. For example, if you’re storing points in 3D space, it will be much more efficient to use an SVector{3, Float64} than a regular Array{Float64} with 3 elements.

StaticArrays.jl also implements some optimized unrolled algorithms for small vectors and matrices. For example, StaticArrays.jl knows the closed-form of the matrix inverse for a 2x2 matrix:

julia> @btime inv($(rand(2, 2)))
  892.575 ns (10 allocations: 1.73 KiB)

julia> @btime inv($(rand(SMatrix{2, 2, Float64})))
  3.155 ns (0 allocations: 0 bytes)

but these optimizations are only really helpful for very small matrices. So a 2x2 or 3x3 or even 10x10 StaticArrays.SMatrix might make sense, but a 100x100 matrix is better left as a regular Julia Array.


#3

To give an example of the optimized unrolled functions, let’s adapt the code from https://github.com/JuliaArrays/StaticArrays.jl/blob/1bc691df971d324d9e0e6c8f1aa2048163159f5b/src/linalg.jl#L225.

The code above uses @generated. This special macro will generate the function based on the types of the inputs allowing extreme specializations to happen for a specific input type. To actually see the body of the function generated, you can remove @generated as follows:

using StaticArrays

@inline mydot(a::StaticVector, b::StaticVector) = _vecdot(StaticArrays.same_size(a, b), a, b)
function _vecdot(::Size{S}, a::StaticArray, b::StaticArray) where {S}
    if prod(S) == 0
        return :(zero(promote_op(*, eltype(a), eltype(b))))
    end

    expr = :(conj(a[1]) * b[1])
    for j = 2:prod(S)
        expr = :($expr + conj(a[$j]) * b[$j])
    end

    return quote
        @_inline_meta
        @inbounds return $expr
    end
end

sv = SVector{3,Float64}([1.0,2.0,3.0]);
mydot(sv, sv)

This will give:

quote
    #= REPL[9]:12 =#
    #= REPL[9]:12 =# @_inline_meta
    #= REPL[9]:13 =#
    #= REPL[9]:13 =# @inbounds return (conj(a[1]) * b[1] + conj(a[2]) * b[2]) + conj(a[3]) * b[3]
end

So you see the “loop” that you would normally use to find the dot product of 2 vectors is now unrolled as an expression. This turns out to be faster when the expression is small enough because the loop adds a non-trivial overhead.


#4

How can you declare StaticArrarys without declaring a global constant? For instance

struct MyType
    A::SVector{N, Float64}
    function MyType(x, y)
        A = x * rand(N) .+ y
    end
end

MyType(4)
MyType(6)


#5

I think you need to read about parametric types https://docs.julialang.org/en/v1/manual/types/index.html#Parametric-Types-1.


#6

Why is better for large matrices to use regular Julia Array (with fixed sizes)?
Do StaticArrays work well they contain Missings?


#7

Please don’t necro old threads for barely related questions. Just open a new thread instead.


#8

I’m sorry. The thread is only two months old and I’m asking about how the results posted by rdeits scale with size.