Block tridiagonal matrix python

后端 未结 8 1488
甜味超标
甜味超标 2020-11-28 14:52

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

相关标签:
8条回答
  • 2020-11-28 15:41

    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.

    0 讨论(0)
  • 2020-11-28 15:54

    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]]
    
    0 讨论(0)
提交回复
热议问题