API

API

Guide

SVector

The simplest static array is the type SVector{N,T}, which provides an immutable vector of fixed length N and type T.

SVector defines a series of convenience constructors, so you can just type e.g. SVector(1,2,3). Alternatively there is an intelligent @SVector macro where you can use native Julia array literals syntax, comprehensions, and the zeros(), ones(), fill(), rand() and randn() functions, such as @SVector [1,2,3], @SVector Float64[1,2,3], @SVector [f(i) for i = 1:10], @SVector zeros(3), @SVector randn(Float32, 4), etc (Note: the range of a comprehension is evaluated at global scope by the macro, and must be made of combinations of literal values, functions, or global variables, but is not limited to just simple ranges. Extending this to (hopefully statically known by type-inference) local-scope variables is hoped for the future. The zeros(), ones(), fill(), rand() and randn() functions do not have this limitation.)

SMatrix

Statically sized N×M matrices are provided by SMatrix{N,M,T,L}.

Here L is the length of the matrix, such that N × M = L. However, convenience constructors are provided, so that L, T and even M are unnecessary. At minimum, you can type SMatrix{2}(1,2,3,4) to create a 2×2 matrix (the total number of elements must divide evenly into N). A convenience macro @SMatrix [1 2; 3 4] is provided (which also accepts comprehensions and the zeros(), ones(), fill(), rand(), randn() and eye() functions).

SArray

A container with arbitrarily many dimensions is defined as struct SArray{Size,T,N,L} <: StaticArray{Size,T,N}, where Size = Tuple{S1, S2, ...} is a tuple of Ints. You can easily construct one with the @SArray macro, supporting all the features of @SVector and @SMatrix (but with arbitrary dimension).

The main reason SVector and SMatrix are defined is to make it easier to define the types without the extra tuple characters (compare SVector{3} to SArray{Tuple{3}}).

Scalar

Sometimes you want to broadcast an operation, but not over one of your inputs. A classic example is attempting to displace a collection of vectors by the same vector. We can now do this with the Scalar type:

[[1,2,3], [4,5,6]] .+ Scalar([1,0,-1]) # [[2,2,2], [5,5,5]]

Scalar is simply an implementation of an immutable, 0-dimensional StaticArray.

The Size trait

The size of a statically sized array is a static parameter associated with the type of the array. The Size trait is provided as an abstract representation of the dimensions of a static array. An array sa::SA of size (dims...) is associated with Size{(dims...)}(). The following are equivalent (@pure) constructors:

Size{(dims...)}()
Size(dims...)
Size(sa::StaticArray)
Size(SA) # SA <: StaticArray

This is extremely useful for (a) performing dispatch depending on the size of an array, and (b) passing array dimensions that the compiler can reason about.

An example of size-based dispatch for the determinant of a matrix would be:

det(x::StaticMatrix) = _det(Size(x), x)
_det(::Size{(1,1)}, x::StaticMatrix) = x[1,1]
_det(::Size{(2,2)}, x::StaticMatrix) = x[1,1]*x[2,2] - x[1,2]*x[2,1]
# and other definitions as necessary

Examples of using Size as a compile-time constant include

reshape(svector, Size(2,2))  # Convert SVector{4} to SMatrix{2,2}
Size(3,3)(rand(3,3))         # Construct a random 3×3 SizedArray (see below)

Indexing

Statically sized indexing can be realized by indexing each dimension by a scalar, a StaticVector or :. Indexing in this way will result a statically sized array (even if the input was dynamically sized, in the case of StaticVector indices) of the closest type (as defined by similar_type).

Conversely, indexing a statically sized array with a dynamically sized index (such as a Vector{Integer} or UnitRange{Integer}) will result in a standard (dynamically sized) Array.

similar_type()

Since immutable arrays need to be constructed "all-at-once", we need a way of obtaining an appropriate constructor if the element type or dimensions of the output array differs from the input. To this end, similar_type is introduced, behaving just like similar, except that it returns a type. Relevant methods are:

similar_type{A <: StaticArray}(::Type{A}) # defaults to A
similar_type{A <: StaticArray, ElType}(::Type{A}, ::Type{ElType}) # Change element type
similar_type{A <: AbstractArray}(::Type{A}, size::Size) # Change size
similar_type{A <: AbstractArray, ElType}(::Type{A}, ::Type{ElType}, size::Size) # Change both

These setting will affect everything, from indexing, to matrix multiplication and broadcast. Users wanting introduce a new array type should only overload the last method in the above.

Use of similar will fall back to a mutable container, such as a MVector (see below), and it requires use of the Size trait if you wish to set a new static size (or else a dynamically sized Array will be generated when specifying the size as plain integers).

Mutable arrays: MVector, MMatrix and MArray

These statically sized arrays are identical to the above, but are defined as mutable structs, instead of immutable structs. Because they are mutable, they allow setindex! to be defined (achieved through pointer manipulation, into a tuple).

As a consequence of Julia's internal implementation, these mutable containers live on the heap, not the stack. Their memory must be allocated and tracked by the garbage collector. Nevertheless, there is opportunity for speed improvements relative to Base.Array because (a) there may be one less pointer indirection, (b) their (typically small) static size allows for additional loop unrolling and inlining, and consequentially (c) their mutating methods like map! are extremely fast. Benchmarking shows that operations such as addition and matrix multiplication are faster for MMatrix than Matrix, at least for sizes up to 14 × 14, though keep in mind that optimal speed will be obtained by using mutating functions (like map! or A_mul_B!) where possible, rather than reallocating new memory.

Mutable static arrays also happen to be very useful containers that can be constructed on the heap (with the ability to use setindex!, etc), and later copied as e.g. an immutable SVector to the stack for use, or into e.g. an Array{SVector} for storage.

Convenience macros @MVector, @MMatrix and @MArray are provided.

SizedArray: a decorate size wrapper for Array

Another convenient mutable type is the SizedArray, which is just a wrapper-type about a standard Julia Array which declares its knwon size. For example, if we knew that a was a 2×2 Matrix, then we can type sa = SizedArray{Tuple{2,2}}(a) to construct a new object which knows the type (the size will be verified automatically). A more convenient syntax for obtaining a SizedArray is by calling a Size object, e.g. sa = Size(2,2)(a).

Then, methods on sa will use the specialized code provided by the StaticArrays pacakge, which in many cases will be much, much faster. For example, calling eig(sa) will be signficantly faster than eig(a) since it will perform a specialized 2×2 matrix diagonalization rather than a general algorithm provided by Julia and LAPACK.

In some cases it will make more sense to use a SizedArray, and in other cases an MArray might be preferable.

FieldVector

Sometimes it might be useful to imbue your own types, having multiple fields, with vector-like properties. StaticArrays can take care of this for you by allowing you to inherit from FieldVector{N, T}. For example, consider:

struct Point3D <: FieldVector{3, Float64}
    x::Float64
    y::Float64
    z::Float64
end

With this type, users can easily access fields to p = Point3D(x,y,z) using p.x, p.y or p.z, or alternatively via p[1], p[2], or p[3]. You may even permute the coordinates with p[SVector(3,2,1)]). Furthermore, Point3D is a complete AbstractVector implementation where you can add, subtract or scale vectors, multiply them by matrices, etc.

It is also worth noting that FieldVectors may be mutable or immutable, and that setindex! is defined for use on mutable types. For immutable containers, you may want to define a method for similar_type so that operations leave the type constant (otherwise they may fall back to SVector). For mutable containers, you may want to define a default constructor (no inputs) and an appropriate method for similar,

Implementing your own types

You can easily create your own StaticArray type, by defining linear getindex (and optionally setindex! for mutable types - see setindex(::MArray, val, i) in MArray.jl for an example of how to achieve this through pointer manipulation). Your type should define a constructor that takes a tuple of the data (and mutable containers may want to define a default constructor).

Other useful functions to overload may be similar_type (and similar for mutable containers).

Conversions from Array

In order to convert from a dynamically sized AbstractArray to one of the statically sized array types, you must specify the size explicitly. For example,

v = [1,2]

m = [1 2;
     3 4]

# ... a lot of intervening code

sv = SVector{2}(v)
sm = SMatrix{2,2}(m)
sa = SArray{(2,2)}(m)

sized_v = Size(2)(v)     # SizedArray{(2,)}(v)
sized_m = Size(2,2)(m)   # SizedArray{(2,2)}(m)

We have avoided adding SVector(v::AbstractVector) as a valid constructor to help users avoid the type instability (and potential performance disaster, if used without care) of this innocuous looking expression. However, the simplest way to deal with an Array is to create a SizedArray by calling a Size instance, e.g. Size(2)(v).

Arrays of static arrays

Storing a large number of static arrays is convenient as an array of static arrays. For example, a collection of positions (3D coordinates - SVector{3,Float64}) could be represented as a Vector{SVector{3,Float64}}.

Another common way of storing the same data is as a 3×N Matrix{Float64}. Rather conveniently, such types have exactly the same binary layout in memory, and therefore we can use reinterpret to convert between the two formats

function svectors(x::Matrix{Float64})
    @assert size(x,1) == 3
    reinterpret(SVector{3,Float64}, x, (size(x,2),))
end

Such a conversion does not copy the data, rather it refers to the same memory referenced by two different Julia Arrays. Arguably, a Vector of SVectors is preferable to a Matrix because (a) it provides a better abstraction of the objects contained in the array and (b) it allows the fast StaticArrays methods to act on elements.

Working with mutable and immutable arrays

Generally, it is performant to rebind an immutable array, such as

function average_position(positions::Vector{SVector{3,Float64}})
    x = zeros(SVector{3,Float64})
    for pos ∈ positions
        x = x + pos
    end
    return x / length(positions)
end

so long as the Type of the rebound variable (x, above) does not change.

On the other hand, the above code for mutable containers like Array, MArray or SizedArray is not very efficient. Mutable containers in Julia 0.5 must be allocated and later garbage collected, and for small, fixed-size arrays this can be a leading contribution to the cost. In the above code, a new array will be instantiated and allocated on each iteration of the loop. In order to avoid unnecessary allocations, it is best to allocate an array only once and apply mutating functions to it:

function average_position(positions::Vector{SVector{3,Float64}})
    x = zeros(MVector{3,Float64})
    for pos ∈ positions
        # Take advantage of Julia 0.5 broadcast fusion
        x .= (+).(x, pos) # same as broadcast!(+, x, x, positions[i])
    end
    x .= (/).(x, length(positions))
    return x
end

Keep in mind that Julia 0.5 does not fuse calls to .+, etc (or .+= etc), however the .= and (+).() syntaxes are fused into a single, efficient call to broadcast!. The simpler syntax x .+= pos is expected to be non-allocating (and therefore faster) in Julia 0.6.

The functions setindex, push, pop, shift, unshift, insert and deleteat are provided for performing certain specific operations on static arrays, in analogy with the standard functions setindex!, push!, pop!, etc. (Note that if the size of the static array changes, the type of the output will differ from the input.)

SIMD optimizations

It seems Julia and LLVM are smart enough to use processor vectorization extensions like SSE and AVX - however they are currently partially disabled by default. Run Julia with julia -O or julia -O3 to enable these optimizations, and many of your (immutable) StaticArray methods should become significantly faster!

Docstrings

abstract FieldVector{N, T} <: StaticVector{N, T}

Inheriting from this type will make it easy to create your own vector types. A FieldVector will automatically define getindex and setindex! appropriately. An immutable FieldVector will be as performant as an SVector of similar length and element type, while a mutable FieldVector will behave similarly to an MVector.

For example:

struct Point3D <: FieldVector{3, Float64}
    x::Float64
    y::Float64
    z::Float64
end
source
MArray{S, T, L}()
MArray{S, T, L}(x::NTuple{L, T})
MArray{S, T, L}(x1, x2, x3, ...)

Construct a statically-sized, mutable array MArray. The data may optionally be provided upon construction and cannot be mutated later. The S parameter is a Tuple-type specifying the dimensions, or size, of the array - such as Tuple{3,4,5} for a 3×4×5-sized array. The L parameter is the length of the array and is always equal to prod(S). Constructors may drop the L and T parameters if they are inferrable from the input (e.g. L is always inferrable from S).

MArray{S}(a::Array)

Construct a statically-sized, mutable array of dimensions S (expressed as a Tuple{...}) using the data from a. The S parameter is mandatory since the size of a is unknown to the compiler (the element type may optionally also be specified).

source
MMatrix{S1, S2, T, L}()
MMatrix{S1, S2, T, L}(x::NTuple{L, T})
MMatrix{S1, S2, T, L}(x1, x2, x3, ...)

Construct a statically-sized, mutable matrix MMatrix. The data may optionally be provided upon construction and can be mutated later. The L parameter is the length of the array and is always equal to S1 * S2. Constructors may drop the L, T and even S2 parameters if they are inferrable from the input (e.g. L is always inferrable from S1 and S2).

MMatrix{S1, S2}(mat::Matrix)

Construct a statically-sized, mutable matrix of dimensions S1 × S2 using the data from mat. The parameters S1 and S2 are mandatory since the size of mat is unknown to the compiler (the element type may optionally also be specified).

source
MVector{S,T}()
MVector{S,T}(x::NTuple{S, T})
MVector{S,T}(x1, x2, x3, ...)

Construct a statically-sized, mutable vector MVector. Data may optionally be provided upon construction, and can be mutated later. Constructors may drop the T and S parameters if they are inferrable from the input (e.g. MVector(1,2,3) constructs an MVector{3, Int}).

MVector{S}(vec::Vector)

Construct a statically-sized, mutable vector of length S using the data from vec. The parameter S is mandatory since the length of vec is unknown to the compiler (the element type may optionally also be specified).

source
SArray{S, T, L}(x::NTuple{L, T})
SArray{S, T, L}(x1, x2, x3, ...)

Construct a statically-sized array SArray. Since this type is immutable, the data must be provided upon construction and cannot be mutated later. The S parameter is a Tuple-type specifying the dimensions, or size, of the array - such as Tuple{3,4,5} for a 3×4×5-sized array. The L parameter is the length of the array and is always equal to prod(S). Constructors may drop the L and T parameters if they are inferrable from the input (e.g. L is always inferrable from S).

SArray{S}(a::Array)

Construct a statically-sized array of dimensions S (expressed as a Tuple{...}) using the data from a. The S parameter is mandatory since the size of a is unknown to the compiler (the element type may optionally also be specified).

source
SMatrix{S1, S2, T, L}(x::NTuple{L, T})
SMatrix{S1, S2, T, L}(x1, x2, x3, ...)

Construct a statically-sized matrix SMatrix. Since this type is immutable, the data must be provided upon construction and cannot be mutated later. The L parameter is the length of the array and is always equal to S1 * S2. Constructors may drop the L, T and even S2 parameters if they are inferrable from the input (e.g. L is always inferrable from S1 and S2).

SMatrix{S1, S2}(mat::Matrix)

Construct a statically-sized matrix of dimensions S1 × S2 using the data from mat. The parameters S1 and S2 are mandatory since the size of mat is unknown to the compiler (the element type may optionally also be specified).

source
SVector{S, T}(x::NTuple{S, T})
SVector{S, T}(x1, x2, x3, ...)

Construct a statically-sized vector SVector. Since this type is immutable, the data must be provided upon construction and cannot be mutated later. Constructors may drop the T and S parameters if they are inferrable from the input (e.g. SVector(1,2,3) constructs an SVector{3, Int}).

SVector{S}(vec::Vector)

Construct a statically-sized vector of length S using the data from vec. The parameter S is mandatory since the length of vec is unknown to the compiler (the element type may optionally also be specified).

source
Scalar{T}(x::T)

Construct a statically-sized 0-dimensional array that contains a single element, x. This type is particularly useful for influencing broadcasting operations.

source
Size(dims::Int...)

Size is used extensively in throughout the StaticArrays API to describe the size of a static array desired by the user. The dimensions are stored as a type parameter and are statically propagated by the compiler, resulting in efficient, type inferrable code. For example, to create a static matrix of zeros, use zeros(Size(3,3)) (rather than zeros(3,3), which constructs a Base.Array).

Size(a::StaticArray)
Size(::Type{T<:StaticArray})

Extract the Size corresponding to the given static array. This has multiple uses, including using for "trait"-based dispatch on the size of a statically sized array. For example:

det(x::StaticMatrix) = _det(Size(x), x)
_det(::Size{(1,1)}, x::StaticMatrix) = x[1,1]
_det(::Size{(2,2)}, x::StaticMatrix) = x[1,1]*x[2,2] - x[1,2]*x[2,1]
# and other definitions as necessary
source
StaticArrays.SizeMethod.
Size(dims)(array)

Creates a SizedArray wrapping array with the specified statically-known dims, so to take advantage of the (faster) methods defined by the static array package.

source
SizedArray{Tuple{dims...}}(array)

Wraps an Array with a static size, so to take advantage of the (faster) methods defined by the static array package. The size is checked once upon construction to determine if the number of elements (length) match, but the array may be reshaped.

(Also, Size(dims...)(array) acheives the same thing)

source
abstract type StaticArray{S, T, N} <: AbstractArray{T, N} end
StaticScalar{T}     = StaticArray{Tuple{}, T, 0}
StaticVector{N,T}   = StaticArray{Tuple{N}, T, 1}
StaticMatrix{N,M,T} = StaticArray{Tuple{N,M}, T, 2}

StaticArrays are Julia arrays with fixed, known size.

Dev docs

They must define the following methods:

  • Constructors that accept a flat tuple of data.

  • getindex() with an integer (linear indexing) (preferably @inline with @boundscheck).

  • Tuple(), returning the data in a flat Tuple.

It may be useful to implement:

  • similar_type(::Type{MyStaticArray}, ::Type{NewElType}, ::Size{NewSize}), returning a type (or type constructor) that accepts a flat tuple of data.

For mutable containers you may also need to define the following:

  • setindex! for a single element (linear indexing).

  • similar(::Type{MyStaticArray}, ::Type{NewElType}, ::Size{NewSize}).

  • In some cases, a zero-parameter constructor, MyStaticArray{...}() for unintialized data is assumed to exist.

(see also SVector, SMatrix, SArray, MVector, MMatrix, MArray, SizedArray and FieldVector)

source
similar_type(static_array)
similar_type(static_array, T)
similar_type(array, ::Size)
similar_type(array, T, ::Size)

Returns a constructor for a statically-sized array similar to the input array (or type) static_array/array, optionally with different element type T or size Size. If the input array is not a StaticArray then the Size is mandatory.

This differs from similar() in that the resulting array type may not be mutable (or define setindex!()), and therefore the returned type may need to be constructed with its data.

Note that the (optional) size must be specified as a static Size object (so the compiler can infer the result statically).

New types should define the signature similar_type{A<:MyType,T,S}(::Type{A},::Type{T},::Size{S}) if they wish to overload the default behavior.

source
Base.LinAlg.qrFunction.
qr(A::StaticMatrix, pivot=Val{false}; thin=true) -> Q, R, [p]

Compute the QR factorization of A such that A = Q*R or A[:,p] = Q*R, see qr. This function does not support thin=false keyword option due to type inference instability. To use this option call qr(A, pivot, Val{false}) instead.

source
Base.similarMethod.
similar(static_array)
similar(static_array, T)
similar(array, ::Size)
similar(array, T, ::Size)

Constructs and returns a mutable but statically-sized array (i.e. a StaticArray). If the input array is not a StaticArray, then the Size is required to determine the output size (or else a dynamically sized array will be returned).

source
StaticArrays._sizeMethod.

Return either the statically known Size() or runtime size()

source
arithmetic_closure(T)

Return the type which values of type T will promote to under a combination of the arithmetic operations +, -, * and /.

julia> import StaticArrays.arithmetic_closure

julia> arithmetic_closure(Bool)
Float64

julia> arithmetic_closure(Int32)
Float64

julia> arithmetic_closure(BigFloat)
BigFloat

julia> arithmetic_closure(BigInt)
BigFloat
source

Returns the common Size of the inputs (or else throws a DimensionMismatch)

source