48
$\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$
3
  • 5
    $\begingroup$ Have a look at ArrayFlatten. $\endgroup$ Feb 18, 2013 at 9:17
  • $\begingroup$ @Mr.Wizard, thanks. $\endgroup$
    – novice
    Nov 12, 2014 at 10:29
  • 1
    $\begingroup$ Related: (18224) $\endgroup$
    – Mr.Wizard
    Jun 11, 2017 at 12:12

3 Answers 3

64
$\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$
14
  • $\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, 2013 at 9:31
  • $\begingroup$ @user5463 what do you mean? $\endgroup$
    – Mr.Wizard
    Feb 18, 2013 at 9:31
  • $\begingroup$ Suppose my matrices are not predefined, but generated in the middle of my program. $\endgroup$
    – novice
    Feb 18, 2013 at 9:37
  • $\begingroup$ @user5463 see my updated answer; is that what you want? $\endgroup$
    – Mr.Wizard
    Feb 18, 2013 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, 2017 at 16:26
38
$\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$
18
  • 1
    $\begingroup$ I forgot about that. Nice. $\endgroup$
    – Mr.Wizard
    Feb 18, 2013 at 10:16
  • 2
    $\begingroup$ If I am not mistaken this function can be reduced to: diagF = SparseArray[Band[{1, 1}] -> {##}] & $\endgroup$
    – Mr.Wizard
    Feb 18, 2013 at 10:21
  • 1
    $\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, 2013 at 10:31
  • 4
    $\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, 2013 at 18:10
  • $\begingroup$ @whuber, thanks. Great observation. $\endgroup$
    – kglr
    Feb 18, 2013 at 18:32
3
$\begingroup$

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

$\endgroup$

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.