# How to concatenate matrices views without copying memory?

**URL:** <https://discourse.julialang.org/t/how-to-concatenate-matrices-views-without-copying-memory/118760>\
**Category:** Performance\
**Tags:** question, matrices, views\
**Created:** [August 29, 2024, 9:22am UTC](https://discourse.julialang.org/t/how-to-concatenate-matrices-views-without-copying-memory/118760 "2024-08-29T09:22:39Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Blumenkranz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/blumenkranz/32/210335_2.png) [@Blumenkranz](https://discourse.julialang.org/u/Blumenkranz)\
**Post date:** [August 29, 2024, 9:22am UTC](https://discourse.julialang.org/t/how-to-concatenate-matrices-views-without-copying-memory/118760/1 "2024-08-29T09:22:39Z")

</div>

Using vcat to catenate views leads to memory allocation which is contrary to the original intent of @views. CatViews.jl can address the issue to some extent, but it is only applicable to vectors. I wonder if there is a way to concatenate the views of two matrices while avoiding memory copying.

```julia
using CatViews
using BenchmarkTools
a = rand(2000,2)
b = rand(2000,2)
@btime c = vcat(@view(a[1:1000,:]),@view(b[1:1000,:])) # 10 allocations: 31.61 KiB
c = vcat(@view(a[1:1000,:]),@view(b[1:1000,:]))
d = CatView(@view(a[1:1000,:]),@view(b[1:1000,:])) # 4000-element CatView{2, Float64}
findfirst(x->x==a[1,2],c) # (1,2)
findfirst(x->x==a[1,2],reshape(d,:,2)) # (1001,1)

```

---

<div class="post-metadata">

**Author:** ![Blumenkranz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/blumenkranz/32/210335_2.png) [@Blumenkranz](https://discourse.julialang.org/u/Blumenkranz)\
**Post date:** [August 29, 2024, 10:00am UTC](https://discourse.julialang.org/t/how-to-concatenate-matrices-views-without-copying-memory/118760/2 "2024-08-29T10:00:35Z")

</div>

A possible solution for size(A)=2:

```julia
function CatView(A::SubArray{T,2,Matrix{T}}, B::SubArray{T,2,Matrix{T}}) where {T}
    size(A,2)==2&&return reshape(
        CatView(@view(A[:, 1]), @view(B[:, 1]), @view(A[:, 2]), @view(B[:, 2])),
        :,
        2,
    )
end

```

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [August 29, 2024, 12:50pm UTC](https://discourse.julialang.org/t/how-to-concatenate-matrices-views-without-copying-memory/118760/4 "2024-08-29T12:50:15Z")

</div>

Maybe you want LazyArrays.jl? But timing the construction isn’t the whole story – composite arrays like this are typically much slower to access, which may cancel out any savings. (This is generally not true of views, which is roughly why Base has SubArray but no CatView-like types.)

```julia
using LazyArrays, BenchmarkTools
a = rand(2000,2);
b = rand(2000,2);

c1 = @btime @views vcat($a[1:1000,:], $b[1:1000,:]); # 2μs
summary(c1)
c2 = @btime @views Vcat($a[1:1000,:], $b[1:1000,:]); # 3ns, much faster
c1 == c2 # true

@btime sum(abs2, $c1) # 377.8 ns
@btime sum(abs2, $c2) # 2.824 μs, slower overall (at least min time)

```

---

<div class="post-metadata">

**Author:** ![Blumenkranz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/blumenkranz/32/210335_2.png) [@Blumenkranz](https://discourse.julialang.org/u/Blumenkranz)\
**Post date:** [August 29, 2024, 1:08pm UTC](https://discourse.julialang.org/t/how-to-concatenate-matrices-views-without-copying-memory/118760/5 "2024-08-29T13:08:21Z")

</div>

Thank you for the reminder! Accessing CatView is indeed extremely slow, so the proposed solution might not be a good idea after all. Perhaps the memory copying here is worth it…

```julia
function CatView(A::SubArray{T,2,Matrix{T}}, B::SubArray{T,2,Matrix{T}}) where {T}
    size(A,2)==2&&return reshape(
        CatView(@view(A[:, 1]), @view(B[:, 1]), @view(A[:, 2]), @view(B[:, 2])),
        :,
        2,
    )
end
a = rand(2000,2)
b = rand(2000,2)
c1 = @views CatView(a[1:1000,:],b[1:1000,:])
c2 = @views vcat(a[1:1000,:],b[1:1000,:])
@btime sum($c1) # 2.599 ms (100888 allocations: 1.72 MiB) Catastrophic...
@btime sum($c2) # 270.470 ns (0 allocations: 0 bytes)

```
