Block tridiagonal matrix python

后端 未结 8 1487
甜味超标
甜味超标 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:30

    Use the function scipy.sparse.diags.

    Example:

    from scipy.sparse import diags
    import numpy as np
    #
    n = 10
    k = np.array([np.ones(n-1),-2*np.ones(n),np.ones(n-1)])
    offset = [-1,0,1]
    A = diags(k,offset).toarray()
    

    This returns:

    array([[-2.,  1.,  0.,  0.,  0.],
           [ 1., -2.,  1.,  0.,  0.],
           [ 0.,  1., -2.,  1.,  0.],
           [ 0.,  0.,  1., -2.,  1.],
           [ 0.,  0.,  0.,  1., -2.]])
    
    0 讨论(0)
  • 2020-11-28 15:31

    Since tridiagonal matrix is a sparse matrix using a sparse package could be a nice option, see http://pysparse.sourceforge.net/spmatrix.html#matlab-implementation, there are some examples and comparisons with MATLAB even...

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

    For building a block-wise tridiagonal matrix from the three individual blocks (and repeat the blocks for N times), one solution can be:

    import numpy as np
    from scipy.linalg import block_diag
    
    def tridiag(c, u, d, N): 
        # c, u, d are center, upper and lower blocks, repeat N times
        cc = block_diag(*([c]*N)) 
        shift = c.shape[1]
        uu = block_diag(*([u]*N)) 
        uu = np.hstack((np.zeros((uu.shape[0], shift)), uu[:,:-shift]))
        dd = block_diag(*([d]*N)) 
        dd = np.hstack((dd[:,shift:],np.zeros((uu.shape[0], shift))))
        return cc+uu+dd
    

    For example:

    c=np.matrix([[1,2],[3,4]])
    u = np.matrix([[5,6],[7,8]])
    d = -1*u
    N=4
    H = tridiag(c,u,d,N)
    print(H)
    

    gives the answer

    [[ 1.  2.  5.  6.  0.  0.  0.  0.]
     [ 3.  4.  7.  8.  0.  0.  0.  0.]
     [-5. -6.  1.  2.  5.  6.  0.  0.]
     [-7. -8.  3.  4.  7.  8.  0.  0.]
     [ 0.  0. -5. -6.  1.  2.  5.  6.]
     [ 0.  0. -7. -8.  3.  4.  7.  8.]
     [ 0.  0.  0.  0. -5. -6.  1.  2.]
     [ 0.  0.  0.  0. -7. -8.  3.  4.]]
    
    0 讨论(0)
  • 2020-11-28 15:33

    @TheCorwoodRep's answer can actually be done in a single line. No need for a seperate function.

    np.eye(3,3,k=-1) + np.eye(3,3)*2 + np.eye(3,3,k=1)*3
    

    This produces:

    array([[ 2.,  3.,  0.],
           [ 1.,  2.,  3.],
           [ 0.,  1.,  2.]])
    
    0 讨论(0)
  • 2020-11-28 15:33

    My answer builds of @TheCorwoodRep's answer. I am just posting it because I made a few changes to make it more modular so that it would work for different orders of matrices and also changing the values of k1,k2,k3 i.e which decide where the diagonal appears, will take care of the overflow automatically. While calling the function you can specify what values should appear on the diagonals.

    import numpy as np
    def tridiag(T,x,y,z,k1=-1, k2=0, k3=1):
        a = [x]*(T-abs(k1)); b = [y]*(T-abs(k2)); c = [z]*(T-abs(k3))
        return np.diag(a, k1) + np.diag(b, k2) + np.diag(c, k3)
    
    D=tridiag(10,-1,2,-1)
    
    0 讨论(0)
  • 2020-11-28 15:37

    With "regular" numpy arrays, using numpy.diag:

    def tridiag(a, b, c, k1=-1, k2=0, k3=1):
        return np.diag(a, k1) + np.diag(b, k2) + np.diag(c, k3)
    
    a = [1, 1]; b = [2, 2, 2]; c = [3, 3]
    A = tridiag(a, b, c)
    
    0 讨论(0)
提交回复
热议问题