The package provides a range of different useful built-in StaticArray types, which include mutable and immutable arrays based upon tuples, arrays based upon structs, and wrappers of Array. There is a relatively simple interface for creating your own, custom StaticArray types, too.
I tried I to mutate a simple SVector, but there is no setindex! defined for it:
using StaticArrays
v = @SVector [1,2,3]
v[1] = 0
julia> v[1] = 0
ERROR: setindex!(::SVector{3,Int64}, value, ::Int) is not defined.
Stacktrace:
[1] setindex!(::SVector{3,Int64}, ::Int64, ::Int64) at /home/juliohm/.julia/v0.6/StaticArrays/src/indexing.jl:3
There is actually a setindex method for SVectors. It’s not in-place, but replaces the entire vector (note the absense of a !).
For short vectors setindex(::SVector, val, ind) has similar performance to setindex!(::MVector, ...), but as the vector lengths grow performance degrades.
Try it out:
v = @SVector [1,2,3]
v = setindex(v, 0, 1)
This one is as fast as an MVector, so you can stick to SVectors.
In my application, these vectors will be of very small length like 3 in most cases. I have a normalization operation that I would like to perform in place, so I picked MVector for now:
"""
Composition{D}(parts)
A D-part composition as defined by Aitchison 1986.
"""
struct Composition{D}
parts::MVector{D,Float64}
end
Composition(parts) = Composition{length(parts)}(parts)
"""
Normalize composition `c` in place.
"""
function normalize!(c::Composition)
p = c.parts
s = sum(p)
for i in eachindex(p)
p[i] /= s
end
end
If you have many of these points stored in something like a Vector then I would use static vectors and just update in place as a[i] = a[i] / sum(a) , where a is the collection of points. Static vectors are stored inline and fetching memory is often a bottleneck in computation heavy code.
The big advantage of SVectors is that they are isbits types, so they can be cheaply allocated on the stack and stored inline in arrays. MVectors are mutable, and thus not isbits, so allocating them is more expensive. MVectors can still be useful, since their fixed size enables lots of specialized algorithms and loop unrolling, but I find that I almost always end up using SVectors in my work.
julia> using StaticArrays
julia> x = [ rand(SVector{2,Float64}) for _ in 1:2 ] # x is mutable
2-element Vector{SVector{2, Float64}}:
[0.8394020601377467, 0.028511506698374878]
[0.4393314594143619, 0.021740546734858035]
julia> x[1] = zeros(SVector{2,Float64}) # mutating the first element of x
2-element SVector{2, Float64} with indices SOneTo(2):
0.0
0.0
julia> x
2-element Vector{SVector{2, Float64}}:
[0.0, 0.0]
[0.4393314594143619, 0.021740546734858035]
x[1] was mutated, but the static array inside it was not, it was just replaced by another one.