# Constructing SVector with a loop

Suppose I want to construct an `SVector` with known length `S` and type `T`, but a loop (with a known number of iterations) would be the most comfortable way of doing it. What is the standard idiom for this in 1.0?

My problem is a bit complex, but for an example, consider

``````using StaticArrays

function SFib1(::Val{S}) where S
values = Vector{Int}(undef, S)
@inbounds for i in 1:S
values[i] = (i == 1 || i == 2) ? 1 : values[i-1] + values[i-2]
end
SVector{S}(values)
end
``````

Is it possible to allocate the SVector, then manipulate it with `reinterpret` or similar before returning it?

It looks like you’re looking for `MVector`?

I am not sure. Should I construct an `MVector`, then convert to an `SVector`? It appears to be slower than using a `Vector`, eg

``````function SFibM(::Val{S}) where S
values = MVector{S, Int}(undef)
@inbounds for i in 1:S
values[i] = (i == 1 || i == 2) ? 1 : values[i-1] + values[i-2]
end
SVector{S}(values)
end

julia> @btime SFib1(Val(10));
40.800 ns (1 allocation: 160 bytes)

julia> @btime SFibM(Val(10));
65.488 ns (0 allocations: 0 bytes)
``````

It seems the crossover point is 7.

``````julia> @btime SFibM(Val(7))
31.316 ns (0 allocations: 0 bytes)

julia> @btime SFib1(Val(7))
48.441 ns (1 allocation: 144 bytes)
``````

without the additional conversion, I get:

``````julia> @btime SFibM2(Val(7))
10.438 ns (1 allocation: 64 bytes)
``````

Probably not a valid solution, but fun anyway:

``````function SFibNtuple(::Val{S}) where S
val_i_minus_2 = Ref(1)
val_i_minus_1 = Ref(1)
tup = ntuple(S) do i
if i == 1 || i == 2
1
else
val = val_i_minus_2[] + val_i_minus_1[]
val_i_minus_2[] = val_i_minus_1[]
val_i_minus_1[] = val
end
end
SVector(tup)
end
``````

This infers up to `Val(10)`.

``````using BenchmarkTools
@btime SFibNtuple(Val(10));
``````

prints `1.702 ns (0 allocations: 0 bytes)`.

1 Like

You could use a generated function to unroll the loop.

`Setfield.@set` is a great tool for manipulating `StaticArrays` efficiently

``````using Setfield
using StaticArrays

function SFib1(::Val{S}) where S
values = zeros(SVector{S, Int})
@inbounds for i in 1:S
values = @set values[i] = (i == 1 || i == 2) ? 1 : values[i-1] + values[i-2]
end
values
end
``````
``````julia> @code_llvm SFib1(Val(4))

; Function SFib1
; Location: REPL:2
define void @julia_SFib1_38655({ [4 x i64] }* noalias nocapture sret) {
L45.3:
; Location: REPL:4
; Function macro expansion; {
; Location: /home/takafumi/.julia/packages/Setfield/X9IQb/src/sugar.jl:77
%1 = bitcast { [4 x i64] }* %0 to <4 x i64>*
store <4 x i64> <i64 1, i64 1, i64 2, i64 3>, <4 x i64>* %1, align 8
ret void
;}
}
``````
6 Likes

Neither a loop nor necessarily a good idea, but here is this:

``````function raise_(N)
if N == 0
:(args...)
elseif N == 1
:(f(args...))
else
expr = raise_(N-1)
return :(f(\$expr))
end
end

@generated function raise(f, ::Val{N}, args...) where N
raise_(N)
end

using StaticArrays, BenchmarkTools
fib(_) = (1, 1)
fib(t::NTuple) = (t..., t[end] + t[end-1])
fibs(::Val{N}) where N = SVector(raise(fib, Val(N-1), nothing))
``````
``````; Function fibs
; Location: /Users/schauermr/.julia/v0.6/Bridge/project/ntuple.jl:20
define void @julia_fibs_38351({ [4 x i64] }* noalias nocapture sret) {
top:
%1 = bitcast { [4 x i64] }* %0 to <4 x i64>*
store <4 x i64> <i64 1, i64 1, i64 2, i64 3>, <4 x i64>* %1, align 8
ret void
}
``````