python分块三对角矩阵

发布于 2024-11-04 03:32:30 字数 95 浏览 5 评论 0原文

我想从三个 numpy.ndarray 开始创建一个块三对角矩阵。 有没有任何(直接)方法可以在 python 中做到这一点?

先感谢您!

干杯

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!

Cheers

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

温柔戏命师 2024-11-11 03:32:30

对于“常规”numpy 数组,使用 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)

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)
双马尾 2024-11-11 03:32:30

使用函数scipy.sparse.diags

示例:

from scipy.sparse import diags
import numpy as np

n = 10
k = [np.ones(n-1),-2*np.ones(n),np.ones(n-1)]
offset = [-1,0,1]
A = diags(k,offset).toarray()

这将返回:

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.]])

Use the function scipy.sparse.diags.

Example:

from scipy.sparse import diags
import numpy as np

n = 10
k = [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.]])
〗斷ホ乔殘χμё〖 2024-11-11 03:32:30

您还可以通过花哨的索引使用“常规”numpy 数组来执行此操作:(

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

如果您想更简洁,您可以将这些对 np.arange 的调用替换为 np.r_例如,使用 data[np.r_[:3]+4, np.r_[,而不是 data[np.arange(3)+4, np.arange(3)] :3]]

这会产生:

[[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]]

但是,如果您无论如何都要使用稀疏矩阵,请查看 scipy.sparse.spdiags。 示例中位置 4 中的 3),则需要在行值上添加假数据))

(请注意,如果您将数据放入具有正值的对角线位置(例如 简单的例子:

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()

这会产生:

[[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]]

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]]
作业与我同在 2024-11-11 03:32:30

@TheCorwoodRep 的答案实际上可以在一行中完成。不需要单独的函数。

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

这会产生:

array([[ 2.,  3.,  0.],
       [ 1.,  2.,  3.],
       [ 0.,  1.,  2.]])

@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.]])
权谋诡计 2024-11-11 03:32:30

为了从三个单独的块构建分块三对角矩阵(并重复这些块 N 次),一种解决方案可以是:

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

例如:

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

给出答案

[[ 1.  1.  2.  2.  0.  0.  0.  0.]
 [ 1.  1.  2.  2.  0.  0.  0.  0.]
 [-2. -2.  1.  1.  2.  2.  0.  0.]
 [-2. -2.  1.  1.  2.  2.  0.  0.]
 [ 0.  0. -2. -2.  1.  1.  2.  2.]
 [ 0.  0. -2. -2.  1.  1.  2.  2.]
 [ 0.  0.  0.  0. -2. -2.  1.  1.]
 [ 0.  0.  0.  0. -2. -2.  1.  1.]]

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,1],[1,1]])
u = np.matrix([[2,2],[2,2]])
d = -1*u
N =4
H = tridiag(c,u,d,N)
print(H)

gives the answer

[[ 1.  1.  2.  2.  0.  0.  0.  0.]
 [ 1.  1.  2.  2.  0.  0.  0.  0.]
 [-2. -2.  1.  1.  2.  2.  0.  0.]
 [-2. -2.  1.  1.  2.  2.  0.  0.]
 [ 0.  0. -2. -2.  1.  1.  2.  2.]
 [ 0.  0. -2. -2.  1.  1.  2.  2.]
 [ 0.  0.  0.  0. -2. -2.  1.  1.]
 [ 0.  0.  0.  0. -2. -2.  1.  1.]]
屋顶上的小猫咪 2024-11-11 03:32:30

无论好坏,所有其他答案似乎都回答了三对角矩阵,而不是三对角矩阵。

我认为没有对三对角矩阵的原生支持,所以我编写了自己的代码。我的主对角线上有零,并且我的矩阵是对称的。

这是我的代码。

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])

希望这可以帮助未来寻找三对角矩阵的人。

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.

娇纵 2024-11-11 03:32:30

我的答案是基于@TheCorwoodRep 的答案。我只是发布它,因为我做了一些更改以使其更加模块化,以便它适用于不同阶的矩阵,并且还更改了 k1k2 的值, k3 即决定对角线出现的位置,将自动处理溢出问题。调用该函数时,您可以指定对角线上应显示的值。

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)

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)
醉态萌生 2024-11-11 03:32:30

由于三对角矩阵是一个稀疏矩阵,使用稀疏包可能是一个不错的选择,请参阅 http:// /pysparse.sourceforge.net/spmatrix.html#matlab-implementation,有一些示例以及与 MATLAB 的比较,甚至...

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...

病女 2024-11-11 03:32:30

我只需要类似的东西。我也分享我的解决方法。

from  functools import reduce
import numpy as np
size = 5
vals = [1,3,4]
res = reduce(lambda a, b: a+np.eye(size,k=b[0])*b[1], enumerate(vals), np.zeros((size, size)))
print(res)
# [[1. 3. 4. 0. 0.]
#  [0. 1. 3. 4. 0.]
#  [0. 0. 1. 3. 4.]
#  [0. 0. 0. 1. 3.]
#  [0. 0. 0. 0. 1.]]
size = 7
vals = [1,3,4,7,6]
offset = -2
res = reduce(lambda a, b: a+np.eye(size,k=b[0]+offset)*b[1], enumerate(vals), np.zeros((size, size)))
print(res)
# [[4. 7. 6. 0. 0. 0. 0.]
#  [3. 4. 7. 6. 0. 0. 0.]
#  [1. 3. 4. 7. 6. 0. 0.]
#  [0. 1. 3. 4. 7. 6. 0.]
#  [0. 0. 1. 3. 4. 7. 6.]
#  [0. 0. 0. 1. 3. 4. 7.]
#  [0. 0. 0. 0. 1. 3. 4.]]

I just needed something similar. I share my workaround too.

from  functools import reduce
import numpy as np
size = 5
vals = [1,3,4]
res = reduce(lambda a, b: a+np.eye(size,k=b[0])*b[1], enumerate(vals), np.zeros((size, size)))
print(res)
# [[1. 3. 4. 0. 0.]
#  [0. 1. 3. 4. 0.]
#  [0. 0. 1. 3. 4.]
#  [0. 0. 0. 1. 3.]
#  [0. 0. 0. 0. 1.]]
size = 7
vals = [1,3,4,7,6]
offset = -2
res = reduce(lambda a, b: a+np.eye(size,k=b[0]+offset)*b[1], enumerate(vals), np.zeros((size, size)))
print(res)
# [[4. 7. 6. 0. 0. 0. 0.]
#  [3. 4. 7. 6. 0. 0. 0.]
#  [1. 3. 4. 7. 6. 0. 0.]
#  [0. 1. 3. 4. 7. 6. 0.]
#  [0. 0. 1. 3. 4. 7. 6.]
#  [0. 0. 0. 1. 3. 4. 7.]
#  [0. 0. 0. 0. 1. 3. 4.]]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文