# Flattening view of \`Vector{SVector{N}}\`

**URL:** <https://discourse.julialang.org/t/flattening-view-of-vector-svector-n/106353>\
**Category:** General Usage\
**Tags:** question\
**Created:** [November 17, 2023, 11:47am UTC](https://discourse.julialang.org/t/flattening-view-of-vector-svector-n/106353 "2023-11-17T11:47:22Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [November 17, 2023, 11:47am UTC](https://discourse.julialang.org/t/flattening-view-of-vector-svector-n/106353/1 "2023-11-17T11:47:22Z")

</div>

Suppose that `v` is a `Vector` of `SVector` (a concrete type), eg

```julia
using StaticArrays
v = [rand(SVector{3}) for _ in 1:10]

```

Is there a package that implements a non-allocationg _view_ equivalent to `reduce(vcat, v)::Vector`?

Note that

1. `Iterators.flatten` kind of does this, but not special-cased for `SVector`s, so size calculation goes through all elements
2. I can use `vec(SplitApplyCombine.combinedimsview(v))`, but again that does not specialize to `SVector`s.

In my actual application `length(v)` is large. I can implement this easily, just asking if there is a package already.

---

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [November 17, 2023, 11:51am UTC](https://discourse.julialang.org/t/flattening-view-of-vector-svector-n/106353/2 "2023-11-17T11:51:24Z")

</div>

Does `reinterpret(Float64, v)` not do what you want?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [November 17, 2023, 11:58am UTC](https://discourse.julialang.org/t/flattening-view-of-vector-svector-n/106353/3 "2023-11-17T11:58:30Z")

</div>

yes, it does, thank you!

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [November 17, 2023, 12:31pm UTC](https://discourse.julialang.org/t/flattening-view-of-vector-svector-n/106353/4 "2023-11-17T12:31:43Z")

</div>

Also consider `b = ccall(:jl_reshape_array, Array{Float64,1}, (Any, Any, Any), Array{Float64,1}, v, (sizeof(v)>>3,))`, if the reinterpret array gives you performance trouble on read/write access.

At the very least, benchmark `jl_reshape` against reinterpret.

If reinterpret-array gives you perf trouble, then best ask around here for help.

The `jl_reshape` is really what you want, except that it lies to the compiler about TBAA, in a way that may or may not lead to UB / miscompile in very specific circumstances in current, past or future versions of julia. (I’m insufficiently up-to-date about the details)

The code for reinterpretArray is, on a naive reading, a complete performance-killing abomination. In many cases, llvm manages to remove the extraneous frills and the end result is OK; in some cases, llvm fails to optimize that, and you get a big slowdown.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [November 17, 2023, 1:55pm UTC](https://discourse.julialang.org/t/flattening-view-of-vector-svector-n/106353/5 "2023-11-17T13:55:34Z")

</div>

What you mean, afaiu it just creates a new container for the same data. Thus, is usually very fast:

```julia
julia> x = rand(SVector{3,Float64}, 10^6);

julia> @btime reinterpret(Float64, $x);
  2.534 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [November 17, 2023, 2:07pm UTC](https://discourse.julialang.org/t/flattening-view-of-vector-svector-n/106353/6 "2023-11-17T14:07:05Z")

</div>

> [@lmiq](#):
>
> What you mean, afaiu it just creates a new container for the same data. Thus, is usually very fast:

Yes, creation of the reinterpret array is fast, but accessing the same data through the new ReinterpretArray is sometimes very slow.

It is unfortunate that afaiu Base does not supply a safe and reliably semi-performant way of doing that (the current ReinterpretArray is very hit-and-miss performance-wise, because it tries to work on the level of AbstractArray instead of the level of raw memory).

```julia
julia> using StaticArrays,BenchmarkTools

julia> v = [rand(SVector{8}) for _ in 1:1024]; r = reinterpret(Float64, v); b = ccall(:jl_reshape_array, Array{Float64,1}, (Any, Any, Any), Array{Float64,1}, v, (sizeof(v)>>3,));

julia> @benchmark sum(b)
BenchmarkTools.Trial: 10000 samples with 181 evaluations.
 Range (min … max): 592.331 ns … 1.384 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 615.978 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 624.047 ns ± 42.785 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

  ▂▄▆▇██▇▆▅▃▂▂▁▁ ▂
  ████████████████▆▅▁▅▄▅▅▅▆▆▆▇▆▆▅▆▇██▇▇▇▆▆▇▆▅▆▆▃▄▃▆▅▆▆▅▅▆▅▆▇▇▇ █
  592 ns Histogram: log(frequency) by time 851 ns <

 Memory estimate: 16 bytes, allocs estimate: 1.

julia> @benchmark sum(r)
BenchmarkTools.Trial: 10000 samples with 4 evaluations.
 Range (min … max): 7.024 μs … 18.987 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 7.041 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 7.117 μs ± 651.430 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

  █▂▁ ▁
  ███▇█▇▇▇▇▇▆▅▄▃▃▃▁▁▁▄▁▁▁▃▃▁▃▁▃▁▃▁▁▁▁▁▁▁▁▃▁▁▁▁▁▃▁▁▁▁▁▁▁▁▁▃▃▃▅ █
  7.02 μs Histogram: log(frequency) by time 10.5 μs <

 Memory estimate: 16 bytes, allocs estimate: 1.

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [November 17, 2023, 2:15pm UTC](https://discourse.julialang.org/t/flattening-view-of-vector-svector-n/106353/7 "2023-11-17T14:15:09Z")

</div>

Are you aware of any open issue regarding that? If there isn’t probably it is a good idea to fill one.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [November 17, 2023, 2:30pm UTC](https://discourse.julialang.org/t/flattening-view-of-vector-svector-n/106353/8 "2023-11-17T14:30:41Z")

</div>

FWIW, the `TensorCast.jl` flattening view has the same performance on access as the `ccall()`:

```julia
using StaticArrays
v = [rand(SVector{8}) for _ in 1:1024]
r = reinterpret(Float64, v)
b = ccall(:jl_reshape_array, Array{Float64,1}, (Any, Any, Any), Array{Float64,1}, v, (sizeof(v)>>3,))

using TensorCast
@cast c[j⊗i] := v[i][j] 

@btime sum($r) # 5.367 μs (0 allocs: 0 bytes)
@btime sum($b) # 730 ns (0 allocs: 0 bytes)
@btime sum($c) # 729 ns (0 allocs: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [November 17, 2023, 2:45pm UTC](https://discourse.julialang.org/t/flattening-view-of-vector-svector-n/106353/9 "2023-11-17T14:45:13Z")

</div>

> [@lmiq](#):
>
> Are you aware of any open issue regarding that? If there isn’t probably it is a good idea to fill one.

Lots of them, cf [Issues · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues?q=is%3Aissue+is%3Aopen+reinterpret)

Keno occasionally tries to fix Reinterpret performance by coaxing llvm to propertly optimize yet another case, but that’s whack-a-mole.

Only reliably fast way is “interpret this chunk of memory in the following way” (and yes, this means that strided views or transpose matrices fundamentally should not be reinterpreted! Because you don’t reinterpret arrays / sequences of numbers, you reinterpret ranges of raw memory. And sure this will expose rather sharp edges to users in relation to structure padding).

But that approach sits in the the unfortunate position of having to wait for proper formalization of julia’s aliasing model / TBAA for several years.

If you want to help by either writing a fix or increasing awareness / pestering people, godspeed!

(I personally use jl\_reshape, sprinkle @noinline and pray that the compiler doesn’t get smart enough to call me out)

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [November 17, 2023, 3:00pm UTC](https://discourse.julialang.org/t/flattening-view-of-vector-svector-n/106353/10 "2023-11-17T15:00:42Z")

</div>

> [@rafael.guerra](#):
>
> FWIW, the `TensorCast.jl` flattening view has the same performance on access as the `ccall()`:

It doesn’t. It creates a copy:

```julia
julia> v= [rand(SVector{8}) for _ in 1:1024]; @cast c[j⊗i] := v[i][j] ;

julia> pointer(v), pointer(c)
(Ptr{SVector{8, Float64}} @0x00000000043ab280, Ptr{Float64} @0x0000000004907a00)

```

In many cases, the entire point of the flattened view is that it becomes possible to mutate single entries (i.e. you reinterpret `Vector{SVector}` as `Matrix`).

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [November 17, 2023, 5:13pm UTC](https://discourse.julialang.org/t/flattening-view-of-vector-svector-n/106353/11 "2023-11-17T17:13:38Z")

</div>

@Elrod has a package that handles the strided arrays case:

> **[GitHub - JuliaSIMD/StrideArrays.jl: Library supporting the ArrayInterface.jl...](https://github.com/JuliaSIMD/StrideArrays.jl)**
>
> Library supporting the ArrayInterface.jl strided array interface. - GitHub - JuliaSIMD/StrideArrays.jl: Library supporting the ArrayInterface.jl strided array interface.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [November 18, 2023, 7:39am UTC](https://discourse.julialang.org/t/flattening-view-of-vector-svector-n/106353/12 "2023-11-18T07:39:34Z")

</div>

Thanks @fooobar\_lv2. And sorry for the bad `TensorCast.jl` pointer, as the expression with the `:=` does not produce a view in this case.
