How to form a block-diagonal matrix from a list of matrices?

ybeltukov's blockArray from Speeding up generation of block diagonal matrix blows the methods below out of the water by orders of magnitude, in terms of performance.


a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

b = {{1, 2}, {3, 4}};

ArrayFlatten[{{a, 0}, {0, b}}] // MatrixForm

Mathematica graphics

You can Fold this operation over a list of matrices to get a diagonal:

a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
b = {{1, 2}, {3, 4}};
c = {{1, 2, 3}, {4, 5, 6}};
d = {{1, 2}, {3, 4}, {5, 6}};

Fold[ArrayFlatten[{{#, 0}, {0, #2}}] &, a, {b, c, d}] // MatrixForm

Mathematica graphics

Here is another way to do this, illustrating a forcing of DiagonalMatrix by using an arbitrary head (Hold) on top of List:

DiagonalMatrix[Hold /@ {a, b, c, d}] // ReleaseHold // ArrayFlatten // MatrixForm

(same output)

Or a bit more cleanly using Unevaluated (though this may be harder to apply in a program as opposed to interactive input because the elements of your matrix list will probably not be named):

DiagonalMatrix[Unevaluated @ {a, b, c, d}] // ArrayFlatten // MatrixForm

(same output)


Update: Just bumped into this: SparseArray`SparseBlockMatrix:

bmF = With[{r = MapIndexed[#2[[1]] {1, 1}-># &, #, 1]}, SparseArray`SparseBlockMatrix[r]]&;

a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
b = {{1, 2}, {3, 4}};
c = {{x, y, z}, {u, v, w}};

bmF[{a, b, c}]  // MatrixForm

Mathematica graphics

Original post:

 diagF = With[{dims = Total@(Dimensions /@ {##})}, 
    SparseArray[Band[{1, 1}, dims] -> {##}, dims]] &;

Edit: Much more elegant form (thanks to Mr.Wizard)

 diagF = SparseArray[Band[{1, 1}] -> {##}] &

Example:

 a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
 b = {{1, 2}, {3, 4}};
 c = {{1, 2, 3}, {4, 5, 6}};
 d = {{1, 2}, {3, 4}, {5, 6}};
 diagF[a, b, d, b, c] // MatrixForm

enter image description here



a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

b = {{1, 2}, {3, 4}}; SparseArray[Band[{1, 1}] -> {a, b}] // MatrixForm

enter image description here