I would like to create a block tridiagonal matrix starting from three numpy.ndarray. Is there any (direct) way to do that in python?
Thank you in advance!
Ch
For better or worse, all the other answers seem to answer about tridiagonal matrices and not block tridiagonal matrices.
I don't think there is native support for tridiagonal matrices, so I wrote my own code. I had zeros on the main diagonal and my matrix was symmetric.
Here is my code.
n1 = 784
n2 = 256
n3 = 128
n4 = 10
M1 = np.ones((n1,n2))
M2 = np.ones((n2,n3))
M3 = np.ones((n3, n4))
def blockTri(Ms):
#Takes in a list of matrices (not square) and returns a tridiagonal block matrix with zeros on the diagonal
count = 0
idx = []
for M in Ms:
#print(M.shape)
count += M.shape[0]
idx.append(count)
count += Ms[-1].shape[-1]
mat = np.zeros((count,count))
count = 0
for i, M in enumerate(Ms):
mat[count:count+M.shape[0],idx[i]:idx[i]+M.shape[1]] = M
count = count + M.shape[0]
mat = mat + mat.T
return mat
M = blockTri([M1, M2, M3])
Hopefully this can help future people looking for block tridiagonal matrices.
You can also do this with "regular" numpy arrays through fancy indexing:
import numpy as np
data = np.zeros((10,10))
data[np.arange(5), np.arange(5)+2] = [5, 6, 7, 8, 9]
data[np.arange(3)+4, np.arange(3)] = [1, 2, 3]
print data
(You could replace those calls to np.arange
with np.r_
if you wanted to be more concise. E.g. instead of data[np.arange(3)+4, np.arange(3)]
, use data[np.r_[:3]+4, np.r_[:3]]
)
This yields:
[[0 0 5 0 0 0 0 0 0 0]
[0 0 0 6 0 0 0 0 0 0]
[0 0 0 0 7 0 0 0 0 0]
[0 0 0 0 0 8 0 0 0 0]
[1 0 0 0 0 0 9 0 0 0]
[0 2 0 0 0 0 0 0 0 0]
[0 0 3 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]]
However, if you're going to be using sparse matrices anyway, have a look at scipy.sparse.spdiags. (Note that you'll need to prepend fake data onto your row values if you're placing data into a diagonal position with a positive value (e.g. the 3's in position 4 in the example))
As a quick example:
import numpy as np
import scipy as sp
import scipy.sparse
diag_rows = np.array([[1, 1, 1, 1, 1, 1, 1],
[2, 2, 2, 2, 2, 2, 2],
[0, 0, 0, 0, 3, 3, 3]])
positions = [-3, 0, 4]
print sp.sparse.spdiags(diag_rows, positions, 10, 10).todense()
This yields:
[[2 0 0 0 3 0 0 0 0 0]
[0 2 0 0 0 3 0 0 0 0]
[0 0 2 0 0 0 3 0 0 0]
[1 0 0 2 0 0 0 0 0 0]
[0 1 0 0 2 0 0 0 0 0]
[0 0 1 0 0 2 0 0 0 0]
[0 0 0 1 0 0 2 0 0 0]
[0 0 0 0 1 0 0 0 0 0]
[0 0 0 0 0 1 0 0 0 0]
[0 0 0 0 0 0 1 0 0 0]]