@@ -17,3 +17,36 @@ function supremum(r1::AbstractUnitRange, r2::AbstractUnitRange)
1717 return r2
1818 end
1919end
20+
21+ function blockdiagonalize (A:: AbstractBlockSparseMatrix )
22+ # sort in order to avoid depending on internal details such as dictionary order
23+ bIs = sort! (collect (eachblockstoredindex (A)); by= Int ∘ last ∘ Tuple)
24+
25+ # obtain permutation for the blocks that are present
26+ rowperm = map (first ∘ Tuple, bIs)
27+ colperm = map (last ∘ Tuple, bIs)
28+
29+ # These checks might be expensive but are convenient for now
30+ allunique (rowperm) || throw (ArgumentError (" input contains more than one block per row" ))
31+ allunique (colperm) ||
32+ throw (ArgumentError (" input contains more than one block per column" ))
33+
34+ # post-process empty rows and columns: this pairs them up in order of occurance,
35+ # putting empty rows and columns due to rectangularity at the end
36+ emptyrows = setdiff (Block .(1 : blocksize (A, 1 )), rowperm)
37+ append! (rowperm, emptyrows)
38+ emptycols = setdiff (Block .(1 : blocksize (A, 2 )), colperm)
39+ append! (colperm, emptycols)
40+
41+ return A[rowperm, colperm], rowperm, colperm
42+ end
43+
44+ function isblockdiagonal (A:: AbstractBlockSparseMatrix )
45+ for bI in eachblockstoredindex (A)
46+ row, col = Tuple (bI)
47+ row == col || return false
48+ end
49+ # don't need to check for rows and cols appearing only once
50+ # this is guaranteed as long as eachblockstoredindex is unique, which we assume
51+ return true
52+ end
0 commit comments