40
$\begingroup$

For example, like this:

enter image description here

I know Join works, but it is a bit troublesome for multiple matrices. I also tried DiagonalMatrix, but it can only form a matrix from a list of elements.

$\endgroup$
  • 5
    $\begingroup$ Have a look at ArrayFlatten. $\endgroup$ – b.gates.you.know.what Feb 18 '13 at 9:17
  • $\begingroup$ @Mr.Wizard, thanks. $\endgroup$ – novice Nov 12 '14 at 10:29
  • $\begingroup$ Related: (18224) $\endgroup$ – Mr.Wizard Jun 11 '17 at 12:12
53
$\begingroup$

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)

$\endgroup$
  • $\begingroup$ Mr.Wizard What about a list of Matrices? I only examplified two matrices to form one block-diagonal matrix. Better automatic method. $\endgroup$ – novice Feb 18 '13 at 9:31
  • $\begingroup$ @user5463 what do you mean? $\endgroup$ – Mr.Wizard Feb 18 '13 at 9:31
  • $\begingroup$ Suppose my matrices are not predefined, but generated in the middle of my program. $\endgroup$ – novice Feb 18 '13 at 9:37
  • $\begingroup$ @user5463 see my updated answer; is that what you want? $\endgroup$ – Mr.Wizard Feb 18 '13 at 9:43
  • 1
    $\begingroup$ @huotuichang Let me see if I can explain in a comment. Diagonal needs to "see" a simple vector (list) of elements (i.e. not matrices themselves) for it to work in the manner I need here. Unevaluated @ {a, b, c, d} works because {a, b, c, d} is expressly a vector of elements, and Unevaluated keeps the evaluator from changing it before Diagonal "sees" it. However Table[. . .] is not expressly a vector and therefore Diagonal doesn't know how to operate on it. This is what I meant by "may be harder to apply in a program." (continued) $\endgroup$ – Mr.Wizard Apr 17 '17 at 16:26
33
$\begingroup$

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

$\endgroup$
  • 1
    $\begingroup$ I forgot about that. Nice. $\endgroup$ – Mr.Wizard Feb 18 '13 at 10:16
  • $\begingroup$ If I am not mistaken this function can be reduced to: diagF = SparseArray[Band[{1, 1}] -> {##}] & $\endgroup$ – Mr.Wizard Feb 18 '13 at 10:21
  • $\begingroup$ @Mr.Wizard, you are right! (somehow I did not get that form working when I first tried; need to use ClearAll more often.) $\endgroup$ – kglr Feb 18 '13 at 10:31
  • 3
    $\begingroup$ +1 Great solution. It may be worth pointing out, though, that the example is not a block-diagonal matrix. By definition, a block-diagonal matrix represents an endomorphism of a product of vector spaces in which each component space is mapped to itself; ergo, the blocks must be square. But it is evident that this solution will work correctly when its input matrices are all square; it can be thought of as a generalization of the block-diagonal form in which the matrix represents a Cartesian product of arbitrary linear maps (rather than just endomorphisms). $\endgroup$ – whuber Feb 18 '13 at 18:10
  • $\begingroup$ @whuber, thanks. Great observation. $\endgroup$ – kglr Feb 18 '13 at 18:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.