I am working on a function to do the opposite operation of How to form a block-diagonal Matrix from a list of matrices?
Here is my current algorithm: For i
starting at 1, scan the elements of index (i,1...i-1)
and (1...i-1,i)
, if they are all zero, take the top left $(i-1)(i-1)$ matrix out and return the rest matrix from (i,i)
as (1,1)
.
extractBDM[mat_?MatrixQ] :=
Flatten[Last@Reap@NestWhile[
Module[{pos},
pos = FirstPosition[
Table[Plus @@ (#[[i + 1, ;; i]] ~
Join~#[[;; i, i + 1]])^2, {i, 1, Length@# - 1}], 0];
If[MissingQ[pos], Sow[#]; {}, pos = pos[[1]];
Sow[#[[;; pos, ;; pos]]]; #[[pos + 1 ;;, pos + 1 ;;]]]] &,
mat, # != {} &], 1]
However this algorithm does not support the existence of non-square matrices on the diagonal, and the Table
inside is calculating the whole matrix, while this is unnecessary. Are there better ways to solve this problem?
On uniqueness: In the result matrices, for every diagonal element, say it is index is {i,i}
, there should be at least one non-zero element among {1,i}, {2,i}, ...,{i-1,i} and {i,1}, {i,2}, ...,{i,i-1}
; also the diagonal elements are all non-zero.
0
in blocks:SplitBy[m, Unitize] /. (0 -> Nothing) // Map@MatrixForm
$\endgroup$