Divide a matrix into 4 submatrices

Hi, I’m given a 2*38 matrix.

-7.002 -6.94768 -6.92167 -6.85372 … -3.67384 -3.61184 -3.51171
-1.00187 -1.15017 -1.08179 -1.09073 -0.389809 -0.730911 -0.813239

And I want to get four submatrices. The first three ones would be 210 matrices. And the last one would be a 28 matrix.
I tried

matrix[1:10]
But didn’t work.

Is there anyway to get that?

There appears to be typos in your description. Assuming you need a 2 X 10 sub-matrix, you need to specify the range of the first dimension:

matrix[1:2,1:10]

The size of the first dimension is 2, which means you can use


matrix[:, 1:10]

for simplicity.

using SplitApplyCombine

A = your matrix
submatrices = combinedims.(Iterators.partition(splitdims(A), 10))

should give the four submatrices.

1 Like

A packageless option:

x = rand(2,38)
y = reduce.(hcat, Iterators.partition(eachcol(x), 10))
2 Likes

Same result, but instead of partitioning the array we partition the indices, which is faster:

julia> x = rand(2,38);

julia> m = [x[:, ax2] for ax2 in Iterators.partition(axes(x,2), 10)]
4-element Vector{Matrix{Float64}}:
 [0.904705750749821 0.89098630758476 … 0.0858392997086902 0.5148424692100146; 0.4269731549291972 0.6437199317364444 … 0.09762794727478441 0.2914246434802973]
 [0.24813277171941672 0.7528059317416134 … 0.138920960237655 0.37400443614388357; 0.9669781731841847 0.017065106733320068 … 0.7448520415962544 0.13803101847512966]
 [0.42658976306258567 0.3065657481592433 … 0.7828512257915194 0.3755535656510294; 0.29531362851265053 0.4489025029925201 … 0.6823570780073742 0.710501907163102]
 [0.7784440666703072 0.7317438098094589 … 0.6476143013715214 0.23107949964776875; 0.12731524958584162 0.9071662545609575 … 0.8694040829128722 0.3029390510048475]

julia> y = @btime reduce.(hcat, Iterators.partition(eachcol($x), 10));
  9.596 μs (272 allocations: 18.52 KiB)

julia> m = @btime [$x[:, ax2] for ax2 in Iterators.partition(axes($x,2), 10)];
  309.531 ns (5 allocations: 944 bytes)

julia> m == y
true

Of course, we may wrap views instead of slices, which is even faster:

julia> v = [@view(x[:, ax2]) for ax2 in Iterators.partition(axes(x,2), 10)]
4-element Vector{SubArray{Float64, 2, Matrix{Float64}, Tuple{Base.Slice{Base.OneTo{Int64}}, UnitRange{Int64}}, true}}:
 [0.904705750749821 0.89098630758476 … 0.0858392997086902 0.5148424692100146; 0.4269731549291972 0.6437199317364444 … 0.09762794727478441 0.2914246434802973]
 [0.24813277171941672 0.7528059317416134 … 0.138920960237655 0.37400443614388357; 0.9669781731841847 0.017065106733320068 … 0.7448520415962544 0.13803101847512966]
 [0.42658976306258567 0.3065657481592433 … 0.7828512257915194 0.3755535656510294; 0.29531362851265053 0.4489025029925201 … 0.6823570780073742 0.710501907163102]
 [0.7784440666703072 0.7317438098094589 … 0.6476143013715214 0.23107949964776875; 0.12731524958584162 0.9071662545609575 … 0.8694040829128722 0.3029390510048475]

julia> v = @btime [@view($x[:, ax2]) for ax2 in Iterators.partition(axes($x,2), 10)];
  70.397 ns (1 allocation: 256 bytes)

julia> v == y
true

Each of these produces a Vector of matrices, where the elements are sub-matrices of the sizes that you want.

julia> size.(v)
4-element Vector{Tuple{Int64, Int64}}:
 (2, 10)
 (2, 10)
 (2, 10)
 (2, 8)
2 Likes
julia> m=[$x[:, ax2] for ax2 in Iterators.partition(axes($x,2), 10)]
ERROR: syntax: "$" expression outside quote around REPL[4]:1
Stacktrace:
 [1] top-level scope
   @ REPL[4]:1



julia> [@view($x[:, ax2]) for ax2 in Iterators.partition(axes($x,2), 10)];
ERROR: syntax: "$" expression outside quote around REPL[8]:1
Stacktrace:
 [1] top-level scope
   @ REPL[8]:1

julia>   70.397 ns (1 allocation: 256 bytes)
VERSION

julia> versioninfo()
Julia Version 1.7.3
Commit 742b9abb4d (2022-05-06 12:58 UTC)
Platform Info:
OS: Windows (x86_64-w64-mingw32)
CPU: Intel(R) Core™ i5-4570 CPU @ 3.20GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-12.0.1 (ORCJIT, haswell)

You need to run these without the dollar signs, those are for interpolation while benchmarking