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?
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)
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
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[132]:2
define void @julia_SFib1_38655({ [4 x i64] }* noalias nocapture sret) {
L45.3:
; Location: REPL[132]: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
;}
}
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
}