5

I am trying to generate a matrix from square blocks. Effectively, I have three blocks, call them $A_{diag}$, $A_{up}$, $A_{down}$, and a block of zeroes, which I'll just call $0$. I have some integer $L$ such that if $L=1$ then I am generating the matrix

$$M = \begin{pmatrix} A_{diag} \end{pmatrix}$$

If $L=2$ then I should generate

$$M = \begin{pmatrix} A_{diag} & A_{up} \\ A_{down} & A_{diag} \end{pmatrix}$$

If $L=3$ then

$$M = \begin{pmatrix} A_{diag} & A_{up} & 0 \\ A_{down} & A_{diag} & A_{up} \\ 0 & A_{down} & A_{diag} \end{pmatrix}$$

If $L=4$ then

$$M = \begin{pmatrix} A_{diag} & A_{up} & 0 & 0\\ A_{down} & A_{diag} & A_{up} & 0 \\ 0 & A_{down} & A_{diag} & A_{up} \\ 0 & 0 & A_{down} & A_{diag}\end{pmatrix}$$

and so forth. I suspect this is relatively simple, I found other questions which were similar but more complicated and specific. Any help appreciated, thank you.

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
Kai
  • 2,099
  • 8
  • 17

4 Answers4

4

You can use ArrayFlatten and DiagonalMatrix:

mat[diag_, up_, down_, n_] := ArrayFlatten @ Block[{Identity},
    DiagonalMatrix[ConstantArray[Identity[diag], n]]+
    DiagonalMatrix[ConstantArray[Identity[up], n-1], 1]+
    DiagonalMatrix[ConstantArray[Identity[down], n-1], -1]
]

I used a blocked Identity head so that DiagonalMatrix didn't complain.

Example:

mat[Array[a, {2,2}], Array[b, {2,2}], Array[c, {2,2}], 3] //TeXForm

$\left( \begin{array}{cccccc} a(1,1) & a(1,2) & b(1,1) & b(1,2) & 0 & 0 \\ a(2,1) & a(2,2) & b(2,1) & b(2,2) & 0 & 0 \\ c(1,1) & c(1,2) & a(1,1) & a(1,2) & b(1,1) & b(1,2) \\ c(2,1) & c(2,2) & a(2,1) & a(2,2) & b(2,1) & b(2,2) \\ 0 & 0 & c(1,1) & c(1,2) & a(1,1) & a(1,2) \\ 0 & 0 & c(2,1) & c(2,2) & a(2,1) & a(2,2) \\ \end{array} \right)$

Carl Woll
  • 130,679
  • 6
  • 243
  • 355
4

While the other posted methods work, this is the one I wound up using, based on corey979's suggestion:

If[L == 1,
  A[r_] := Adiag[r],
  mup   = SparseArray[Band[{1, 2}] -> 1, {L, L}];
  mdown = SparseArray[Band[{2, 1}] -> 1, {L, L}];
  mdiag = SparseArray[Band[{1, 1}] -> 1, {L, L}];
  A[r_] :=
    KroneckerProduct[mup  ,   Aup[r]] + 
    KroneckerProduct[mdown, Adown[r]] + 
    KroneckerProduct[mdiag, Adiag[r]];
  ];

It has the advantage of using SparseArray's, which is desirable if L is large. One can always use Normal to convert the SparseArray's into regular matrices for small L. For my application for example I found that using normal matrices was faster for L < 3 but using SparseArray's was faster for L > 3, with both being equally fast for L = 3.

Kai
  • 2,099
  • 8
  • 17
4

The "SparseArray`" context contains many hidden gems, for example this one:

SparseArray`SparseBlockMatrix[{
   Band[{1, 1}] -> SparseArray@Array[a, {2, 2}],
   Band[{1, 2}] -> SparseArray@Array[b, {2, 2}],
   Band[{2, 1}] -> SparseArray@Array[c, {2, 2}]
   }, {3, 3}] // MatrixForm

$$\left( \begin{array}{cccccc} a(1,1) & a(1,2) & b(1,1) & b(1,2) & 0 & 0 \\ a(2,1) & a(2,2) & b(2,1) & b(2,2) & 0 & 0 \\ c(1,1) & c(1,2) & a(1,1) & a(1,2) & b(1,1) & b(1,2) \\ c(2,1) & c(2,2) & a(2,1) & a(2,2) & b(2,1) & b(2,2) \\ 0 & 0 & c(1,1) & c(1,2) & a(1,1) & a(1,2) \\ 0 & 0 & c(2,1) & c(2,2) & a(2,1) & a(2,2) \\ \end{array} \right)$$

It's not very efficient, though...

Henrik Schumacher
  • 106,770
  • 7
  • 179
  • 309
2

There it is,

M[n_] := Adiag IdentityMatrix[n] + 
Table[Aup KroneckerDelta[i + 1, j], {i, 1, n}, {j, 1, n}] + 
Table[Adown KroneckerDelta[i - 1, j], {i, 1, n}, {j, 1, n}];

MatrixForm[M[3]]

to elaborate more, you can have Aup[i, j] and Adown[i, j] and Adiag[i, i].

Navid Rajil
  • 378
  • 1
  • 7