# Separate Sparse Matrix Blocks into Matrices

**URL:** https://discourse.julialang.org/t/separate-sparse-matrix-blocks-into-matrices/129147
**Category:** General Usage
**Tags:** question
**Created:** [May 19, 2025, 1:56pm UTC](https://discourse.julialang.org/t/separate-sparse-matrix-blocks-into-matrices/129147 "2025-05-19T13:56:41Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![wes648](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wes648/32/43541_2.png) [@wes648](https://discourse.julialang.org/u/wes648)
#### Post date: [May 19, 2025, 1:56pm UTC](https://discourse.julialang.org/t/separate-sparse-matrix-blocks-into-matrices/129147/1 "2025-05-19T13:56:41Z")

</div>

Is there an efficient way to convert a block diagonalizable sparse matrix into the separate dense/near dense sub-blocks?

As a small example, I have the following matrix:

```julia
julia> mat
5×5 SparseMatrixCSC{Float64, Int64} with 13 stored entries:
 14.5 ⋅ ⋅ 0.3 ⋅ 
   ⋅ 8.5 0.173205 ⋅ 0.3
   ⋅ 0.173205 7.5 ⋅ 0.866025
  0.3 ⋅ ⋅ 10.0 ⋅ 
   ⋅ 0.3 0.866025 ⋅ 14.5

```

And would like to automatically generate the permutations to produce the following sub-matrices

```julia
julia> sub1 = mat[[1;4],[1;4]]
2×2 SparseMatrixCSC{Float64, Int64} with 4 stored entries:
 14.5 0.3
  0.3 10.0

julia> sub2 = mat[[2;3;5],[2;3;5]]
3×3 SparseMatrixCSC{Float64, Int64} with 9 stored entries:
 8.5 0.173205 0.3
 0.173205 7.5 0.866025
 0.3 0.866025 14.5

```

Thank you in advance and apologies if this is similar to another post

---

<div class="post-metadata">

### Author: ![mtfishman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mtfishman/32/30755_2.png) [@mtfishman](https://discourse.julialang.org/u/mtfishman)
#### Post date: [May 19, 2025, 2:34pm UTC](https://discourse.julialang.org/t/separate-sparse-matrix-blocks-into-matrices/129147/2 "2025-05-19T14:34:26Z")

</div>

Maybe related to the bandwidth minimization problem ([Graph bandwidth - Wikipedia](https://en.wikipedia.org/wiki/Graph_bandwidth), [Cuthill–McKee algorithm - Wikipedia](https://en.wikipedia.org/wiki/Cuthill%E2%80%93McKee_algorithm), [GitHub - PetrKryslUCSD/SymRCM.jl: Reverse Cuthill-McKee node-renumbering algorithm.](https://github.com/PetrKryslUCSD/SymRCM.jl)). Though you may need additional permutations to identify larger blocks.

I’d be curious to hear other ideas, we are interested in this problem as well.

---

<div class="post-metadata">

### Author: ![mtfishman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mtfishman/32/30755_2.png) [@mtfishman](https://discourse.julialang.org/u/mtfishman)
#### Post date: [May 19, 2025, 2:48pm UTC](https://discourse.julialang.org/t/separate-sparse-matrix-blocks-into-matrices/129147/3 "2025-05-19T14:48:52Z")

</div>

It looks like SymRCM.jl does the job, at least in this case:

```julia
julia> using SparseArrays

julia> using SymRCM

julia> Is = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]
5-element Vector{Tuple{Int64, Int64}}:
 (1, 1)
 (2, 2)
 (3, 3)
 (4, 4)
 (5, 5)

julia> Js = [(1, 4), (2, 3), (2, 5), (3, 5)]
4-element Vector{Tuple{Int64, Int64}}:
 (1, 4)
 (2, 3)
 (2, 5)
 (3, 5)

julia> a = spzeros(5, 5)
5×5 SparseMatrixCSC{Float64, Int64} with 0 stored entries:
  ⋅ ⋅ ⋅ ⋅ ⋅ 
  ⋅ ⋅ ⋅ ⋅ ⋅ 
  ⋅ ⋅ ⋅ ⋅ ⋅ 
  ⋅ ⋅ ⋅ ⋅ ⋅ 
  ⋅ ⋅ ⋅ ⋅ ⋅ 

julia> foreach(I -> (a[I...] = 10I[1] + I[2]), Is)

julia> foreach(I -> (a[I...] = 10I[1] + I[2]), [Js; reverse.(Js)])

julia> a
5×5 SparseMatrixCSC{Float64, Int64} with 13 stored entries:
 11.0 ⋅ ⋅ 14.0 ⋅ 
   ⋅ 22.0 23.0 ⋅ 25.0
   ⋅ 32.0 33.0 ⋅ 35.0
 41.0 ⋅ ⋅ 44.0 ⋅ 
   ⋅ 52.0 53.0 ⋅ 55.0

julia> p = symrcm(a)
5-element Vector{Int64}:
 5
 3
 2
 4
 1

julia> a[p, p]
5×5 SparseMatrixCSC{Float64, Int64} with 13 stored entries:
 55.0 53.0 52.0 ⋅ ⋅ 
 35.0 33.0 32.0 ⋅ ⋅ 
 25.0 23.0 22.0 ⋅ ⋅ 
   ⋅ ⋅ ⋅ 44.0 41.0
   ⋅ ⋅ ⋅ 14.0 11.0

```

---

<div class="post-metadata">

### Author: ![wes648](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wes648/32/43541_2.png) [@wes648](https://discourse.julialang.org/u/wes648)
#### Post date: [May 19, 2025, 2:56pm UTC](https://discourse.julialang.org/t/separate-sparse-matrix-blocks-into-matrices/129147/4 "2025-05-19T14:56:48Z")

</div>

This looks great! Thank you!

Do you happen to know if there is a good way to split the permutation along the blocks of the matrix? My ultimate goal is to extra the blocks to diagonalize separately rather than diagonalizing the larger matrix

---

<div class="post-metadata">

### Author: ![mtfishman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mtfishman/32/30755_2.png) [@mtfishman](https://discourse.julialang.org/u/mtfishman)
#### Post date: [May 19, 2025, 3:04pm UTC](https://discourse.julialang.org/t/separate-sparse-matrix-blocks-into-matrices/129147/5 "2025-05-19T15:04:13Z")

</div>

One way to do that could be by identifying the [connected components](https://juliagraphs.org/Graphs.jl/dev/algorithms/connectivity/#Graphs.connected_components-Union%7BTuple%7BAbstractGraph%7BT%7D) of the graph that is derived by interpreting the matrix as an adjacency matrix:

```julia
julia> using Graphs

julia> using LinearAlgebra

julia> connected_components(Graph(Symmetric(a[p, p])))
2-element Vector{Vector{Int64}}:
 [1, 2, 3]
 [4, 5]

```

Note that appears to be another way to find the blocks, without needing bandwidth minimization to begin with:

```julia
julia> connected_components(Graph(Symmetric(a)))
2-element Vector{Vector{Int64}}:
 [1, 4]
 [2, 3, 5]

```

Again, I’d be curious to hear if anyone has other suggestions, there may be a more efficient/robust way to do this.
