Python 压缩格式块对角矩阵的有效线性代数
我有一个线性系统,其中所有的矩阵都是块对角的。它们具有形状相同的Python 压缩格式块对角矩阵的有效线性代数,python,numpy,multidimensional-array,vectorization,linear-algebra,Python,Numpy,Multidimensional Array,Vectorization,Linear Algebra,我有一个线性系统,其中所有的矩阵都是块对角的。它们具有形状相同的N块 矩阵以压缩格式存储为numpy数组,其形状为(N,N,m),而向量的形状为(N,m) 我目前将矩阵向量积实现为 import numpy as np def mvdot(m, v): return (m * np.expand_dims(v, -2)).sum(-1) 多亏了广播规则,如果一个矩阵的所有块都是相同的,我只需要在一个数组中存储一次它的形状(1,n,m):带有向量(n,m)的乘积仍然给出正确的(n,n)
N
块
矩阵以压缩格式存储为numpy数组,其形状为(N,N,m)
,而向量的形状为(N,m)
我目前将矩阵向量积实现为
import numpy as np
def mvdot(m, v):
return (m * np.expand_dims(v, -2)).sum(-1)
多亏了广播规则,如果一个矩阵的所有块都是相同的,我只需要在一个数组中存储一次它的形状(1,n,m)
:带有向量(n,m)
的乘积仍然给出正确的(n,n)
向量
我的问题是:
- 如何实现一个有效的矩阵积,从两个形状为
和(N,N,p)
的矩阵生成形状为(N,p,m)
(N,N,m)
- 有没有办法使用
内置(可能更快)功能执行这些操作?像numpy
这样的函数让我觉得np.linalg.inv
是为支持块对角矩阵的这种压缩格式而设计的numpy
(N,N,p)
和(N,p,m)
,它们的乘积应该是shape(N,N,m)
,其中元素[I,:,:]
是M1[I,:,,,:][/code>和M2[I,:,:,:]的矩阵积。这可以通过以下方式实现:
Numpy的einsum
对于复杂的线性运算来说是一种难以置信的多功能结构,它通常对两个操作数非常有效。我们的想法是以索引方式重写操作:您需要的是将M1[i,j,k]
与M2[i,k,l]
相乘,然后对每个i,j,l
求和k
。这正是上面对einsum
的调用所做的:它折叠索引k
,并按照给定顺序沿其余维度执行必要的产品和分配
矩阵向量积可以类似地进行:
M = np.random.rand(N,n,m)
v = np.random.rand(N,m)
Mvprod = np.einsum('ijk,ik->ij',M,v)
有可能numpy.dot
可以通过适当的转置和维度技巧强制直接执行您想要的操作,但我无法做到这一点
通过在einsum
中允许隐式的维度数,可以在同一个函数调用中完成上述两个操作:
def mvdot(M1,M2):
return np.einsum('ijk,ik...->ij...',M1,M2)
Mprod = mvdot(M1,M2)
Mvprod = mvdot(M,v)
如果输入参数M2
是块矩阵,则会在结果后附加一个前导维度,从而创建一个块矩阵。如果M2
是一个“块向量”,则结果将是一个块向量。由于Python 3.5及以上版本,可以使用矩阵乘法运算符@
()简化前面的示例,它将这种情况视为驻留在最后两个索引中的矩阵堆栈,并相应地广播:
import numpy as np
N = 7
n,p,m = 3,4,5
M1 = np.random.rand(N,n,p)
M2 = np.random.rand(N,p,m)
Mprod = M1 @ M2 # similar to np.matmul(M1, M2)
all([np.allclose(np.dot(M1[k,...],M2[k,...]),Mprod[k,...]) for k in range(N)])
#True
听起来你也可以用标准矩阵乘法和稀疏表示法来表示块对角系统。你是什么意思?使用dot
方法?是的,不使用张量(N,N,m)作为压缩格式,您可以将它们保留为具有稀疏表示的二维矩阵(Nn,Nm),并使用稀疏矩阵乘法或矩阵向量乘法。您考虑使用哪种备用矩阵类?
import numpy as np
N = 7
n,p,m = 3,4,5
M1 = np.random.rand(N,n,p)
M2 = np.random.rand(N,p,m)
Mprod = M1 @ M2 # similar to np.matmul(M1, M2)
all([np.allclose(np.dot(M1[k,...],M2[k,...]),Mprod[k,...]) for k in range(N)])
#True