如何在numpy中反转矩阵的体积?
How to invert volume of matrices in numpy?
请假设一个可逆矩阵向量:
import numpy as np
a = np.arange(120).reshape((2, 2, 5, 6))
我想在定义的轴上反转矩阵:
b = np.linalg.inv(a, axis1=0, axis2=1)
但这似乎不受支持。
如何实现?
如果您知道矩阵是 2x2,则可以使用标准公式轻松地求逆此类矩阵;否则,我担心唯一合理的解决方案是使用 for 循环吗?例如,以下适用于任何形状(适当修改尺寸):
b = np.stack([np.linalg.inv(a[:, :, i, j]) for i in range(a.shape[2]) for j in range(a.shape[3])], axis=2)
b = b.reshape(2, 2, 5, 6)
由
检查
for i in range(a.shape[2]):
for j in range(a.shape[3]):
assert np.allclose(np.dot(a[:,:,i,j], b[:,:,i,j]), np.eye(2))
在特定的 2x2 情况下,您可以执行以下操作,它是完全矢量化的,因此可能更快:
determinants = a[0, 0] * a[1, 1] - a[0, 1] * a[1, 0]
b = 1 / determinants * np.stack([
np.stack([a[1, 1], -a[0, 1]]),
np.stack([-a[1, 0], a[0, 0]]),
])
在特定(小)输入大小上,第二种解决方案在我的测试中快了大约 10 倍(43us 对 537us)。
inv
文档将其数组输入指定为:
a : (..., M, M) array_like
Matrix to be inverted.
你有一个
a = np.arange(120).reshape((2, 2, 5, 6))
(M,M,...)
尺寸顺序错误 - 更改它们!
In [44]: a = np.arange(120).reshape((2, 2, 5, 6))
将轴更改为 inv
接受的顺序:
In [45]: A = a.transpose(2,3,0,1)
In [46]: Ai = np.linalg.inv(A)
In [47]: Ai.shape
Out[47]: (5, 6, 2, 2)
In [48]: ai = Ai.transpose(2,3,0,1) # and back
In [49]: ai.shape
Out[49]: (2, 2, 5, 6)
我正要测试结果,但是得到了:
In [50]: x = a@ai
Traceback (most recent call last):
File "<ipython-input-50-9dfe3616745d>", line 1, in <module>
x = a@ai
ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 5 is different from 6)
与 inv
一样,matmul
将最后两个维度视为 matrix
,将前两个维度视为 'batch':
In [51]: x = A@Ai
In [52]: x[0,0]
Out[52]:
array([[1., 0.],
[0., 1.]])
In [53]: x[0,3]
Out[53]:
array([[1.00000000e+00, 1.38777878e-17],
[4.44089210e-16, 1.00000000e+00]])
我们可以用einsum
做同样的事情:
In [55]: x = np.einsum('ijkl,jmkl->imkl',a,ai)
In [56]: x[:,:,0,0]
Out[56]:
array([[1., 0.],
[0., 1.]])
您可能想要更改原始规范以匹配 inv
和 matmul
用法。它可以让你的生活更轻松。还要记住,在 numpy
中,尾部维度是最里面的维度。
请假设一个可逆矩阵向量:
import numpy as np
a = np.arange(120).reshape((2, 2, 5, 6))
我想在定义的轴上反转矩阵:
b = np.linalg.inv(a, axis1=0, axis2=1)
但这似乎不受支持。
如何实现?
如果您知道矩阵是 2x2,则可以使用标准公式轻松地求逆此类矩阵;否则,我担心唯一合理的解决方案是使用 for 循环吗?例如,以下适用于任何形状(适当修改尺寸):
b = np.stack([np.linalg.inv(a[:, :, i, j]) for i in range(a.shape[2]) for j in range(a.shape[3])], axis=2)
b = b.reshape(2, 2, 5, 6)
由
检查for i in range(a.shape[2]):
for j in range(a.shape[3]):
assert np.allclose(np.dot(a[:,:,i,j], b[:,:,i,j]), np.eye(2))
在特定的 2x2 情况下,您可以执行以下操作,它是完全矢量化的,因此可能更快:
determinants = a[0, 0] * a[1, 1] - a[0, 1] * a[1, 0]
b = 1 / determinants * np.stack([
np.stack([a[1, 1], -a[0, 1]]),
np.stack([-a[1, 0], a[0, 0]]),
])
在特定(小)输入大小上,第二种解决方案在我的测试中快了大约 10 倍(43us 对 537us)。
inv
文档将其数组输入指定为:
a : (..., M, M) array_like
Matrix to be inverted.
你有一个
a = np.arange(120).reshape((2, 2, 5, 6))
(M,M,...)
尺寸顺序错误 - 更改它们!
In [44]: a = np.arange(120).reshape((2, 2, 5, 6))
将轴更改为 inv
接受的顺序:
In [45]: A = a.transpose(2,3,0,1)
In [46]: Ai = np.linalg.inv(A)
In [47]: Ai.shape
Out[47]: (5, 6, 2, 2)
In [48]: ai = Ai.transpose(2,3,0,1) # and back
In [49]: ai.shape
Out[49]: (2, 2, 5, 6)
我正要测试结果,但是得到了:
In [50]: x = a@ai
Traceback (most recent call last):
File "<ipython-input-50-9dfe3616745d>", line 1, in <module>
x = a@ai
ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 5 is different from 6)
与 inv
一样,matmul
将最后两个维度视为 matrix
,将前两个维度视为 'batch':
In [51]: x = A@Ai
In [52]: x[0,0]
Out[52]:
array([[1., 0.],
[0., 1.]])
In [53]: x[0,3]
Out[53]:
array([[1.00000000e+00, 1.38777878e-17],
[4.44089210e-16, 1.00000000e+00]])
我们可以用einsum
做同样的事情:
In [55]: x = np.einsum('ijkl,jmkl->imkl',a,ai)
In [56]: x[:,:,0,0]
Out[56]:
array([[1., 0.],
[0., 1.]])
您可能想要更改原始规范以匹配 inv
和 matmul
用法。它可以让你的生活更轻松。还要记住,在 numpy
中,尾部维度是最里面的维度。