# Specifying StaticArray Types

If a struct’s field is a StaticArray, then how do I (generically) specify its type? As seen below, not specifying the type has an effect on performance, but my attempt is obviously no good either, as it’s far to specific.

``````using BenchmarkTools, StaticArrays

mutable struct TypedModel
A::SArray{Tuple{6,6},Float64,2,36}
Atranspose::SArray{Tuple{6,6},Float64,2,36}
u::SArray{Tuple{6},Float64,1,6}
R::SArray{Tuple{6,6},Float64,2,36}
end

mutable struct Model
A
Atranspose
u
R
end

function multiplythings!(μ, Σ, A, Atranspose, u, R, n)
for i = 1:n
μ[i] = A * μ[i] + u
Σ[i] = A * Σ[i] * Atranspose + R
end
end

function multiplythings!(μ, Σ, model, n)
for i = 1:n
μ[i] = model.A * μ[i] + model.u
Σ[i] = model.A * Σ[i] * model.Atranspose + model.R
end
end

# Model
xdim = 6
n = 1000
A = @SMatrix rand(xdim, xdim)
Atranspose = A'
u = @SVector rand(xdim)
R = @SMatrix rand(xdim, xdim)
# State estimate parameters
μ = [@SVector rand(xdim) for _ = 1:n]
Σ = [@SMatrix rand(xdim, xdim) for _ = 1:n]
# Create models
model = Model(A, Atranspose, u, R)
typedmodel = TypedModel(A, Atranspose, u, R)
@btime multiplythings!(\$μ, \$Σ, \$A, \$Atranspose, \$u, \$R, \$n)
@btime multiplythings!(\$μ, \$Σ, \$typedmodel, \$n)
@btime multiplythings!(\$μ, \$Σ, \$model, \$n)
``````

A `StaticVector` is characterized by its length (`VecN`) and the element type (`VecT`). A `StaticMatrix` is characterized by its size (nrows `MatR`, ncolumns `MatC`) and the element type (`MatT`). These characterizing features can be given as parameters. That is likely the most general way to get most specific.

``````struct S{VecN, VecT, MatR, MatC, MatT}
staticvec::SArray{Tuple{VecN}, VecT}
staticmat::SArray{Tuple{MatR,MatC}, MatT}
end

function S(vec::Vector{VecT}, mat::Matrix{MatT}) where {VecT, MatT}
VecN = length(vec)
MatR, MatC = size(mat)
return S{VecN, VecT, MatR, MatC, MatT}(vec, mat)
end
``````
``````julia> test = S([1, 2, 3], [1 2; 3 4])
S{3,Int64,2,2,Int64}([1, 2, 3], [1 2; 3 4])

julia> test.staticvec
3-element SArray{Tuple{3},Int64,1,3} with indices SOneTo(3):
1
2
3

julia> test.staticmat
2×2 SArray{Tuple{2,2},Int64,2,4} with indices SOneTo(2)×SOneTo(2):
1  2
3  4
``````

To pass your vector as a tuple, define another constructor. To pass your matrix as a tuple with a two-tuple size (nrows, ncolumns) define another constructor.

I tried this and it works, but my performance suffers. I tried:

``````mutable struct TypedModel{X, T}
A::SArray{Tuple{X, X}, T}
Atranspose::SArray{Tuple{X, X}, T}
u::SArray{Tuple{X}, T}
R::SArray{Tuple{X, X}, T}
end

typedmodel = TypedModel{xdim, Float64}(A, Atranspose, u, R)
@btime multiplythings!(\$μ, \$Σ, \$typedmodel, \$n)
287.900 μs (7978 allocations: 1.48 MiB)
``````

What is going wrong here?

I don’t know what you are doing (see points 3 & 4 here).
Show me that the performance suffers using my minimal example (perhaps with a larger vector and a larger matrix). Include the vector and matrix explicitly, so we have something specific to compare.

OK, I tracked it down. To get the performance you need to provide all the parameters. My oversight. `N` is the vector length, `N2` is N*N, the matrix length, `T` is the shared element type.

``````mutable struct TypedModel3{N, N2, T}
A::SArray{Tuple{N, N}, T, 2, N2}
Atranspose::SArray{Tuple{N, N}, T, 2, N2}
u::SArray{Tuple{N}, T, 1, N}
R::SArray{Tuple{N, N}, T, 2, N2}
end

x2dim = xdim * xdim
typedmodel3 = TypedModel3{xdim, x2dim, Float64}(A, Atranspose, u, R)

julia> @btime multiplythings!(\$μ, \$Σ, \$typedmodel3, \$n)
46.600 μs (0 allocations: 0 bytes)
``````

As far as I understand it is not enough to specify the length of the two dimensions of an `SMatrix`, you also have to give the number of elements. Even though it’s in principle trivial to calculate the latter from the former, the compiler isn’t able to.

Edit: oops, to late.