这是一个小例子。它有多慢让我感到惊讶。
import numpy as np
import sympy as sp
X = np.empty(shape=(10,3), dtype=object)
for i in range(10):
for j in range(3):
X[i,j] = sp.Symbol(f'X{i}{j}')
X = sp.Matrix(X.T @ X)
print(X.inv()) # This is really slow...
我本来以为取一个相对较小的矩阵的逆会很快。我是否遗漏了有关预期用例的某些信息?
这是你的矩阵:
In [43]: X
Out[43]:
⎡ 2 2 2 2 2 2 2 2 2 2 ⎤
⎢ X₀₀ + X₁₀ + X₂₀ + X₃₀ + X₄₀ + X₅₀ + X₆₀ + X₇₀ + X₈₀ + X₉₀ X₀₀⋅X₀₁ + X₁₀⋅X₁₁ + X₂₀⋅X₂₁ + X₃₀⋅X₃₁ + X₄₀⋅X₄₁ + X₅₀⋅X₅₁ + X₆₀⋅X₆₁ + X₇₀⋅X₇₁ + X₈₀⋅X₈₁ + X₉₀⋅X₉₁ X₀₀⋅X₀₂ + X₁₀⋅X₁₂ + X₂₀⋅X₂₂ + X₃₀⋅X₃₂ + X₄₀⋅X₄₂ + X₅₀⋅X₅₂ + X₆₀⋅X₆₂ + X₇₀⋅X₇₂ + X₈₀⋅X₈₂ + X₉₀⋅X₉₂⎥
⎢ ⎥
⎢ 2 2 2 2 2 2 2 2 2 2 ⎥
⎢X₀₀⋅X₀₁ + X₁₀⋅X₁₁ + X₂₀⋅X₂₁ + X₃₀⋅X₃₁ + X₄₀⋅X₄₁ + X₅₀⋅X₅₁ + X₆₀⋅X₆₁ + X₇₀⋅X₇₁ + X₈₀⋅X₈₁ + X₉₀⋅X₉₁ X₀₁ + X₁₁ + X₂₁ + X₃₁ + X₄₁ + X₅₁ + X₆₁ + X₇₁ + X₈₁ + X₉₁ X₀₁⋅X₀₂ + X₁₁⋅X₁₂ + X₂₁⋅X₂₂ + X₃₁⋅X₃₂ + X₄₁⋅X₄₂ + X₅₁⋅X₅₂ + X₆₁⋅X₆₂ + X₇₁⋅X₇₂ + X₈₁⋅X₈₂ + X₉₁⋅X₉₂⎥
⎢ ⎥
⎢ 2 2 2 2 2 2 2 2 2 2 ⎥
⎣X₀₀⋅X₀₂ + X₁₀⋅X₁₂ + X₂₀⋅X₂₂ + X₃₀⋅X₃₂ + X₄₀⋅X₄₂ + X₅₀⋅X₅₂ + X₆₀⋅X₆₂ + X₇₀⋅X₇₂ + X₈₀⋅X₈₂ + X₉₀⋅X₉₂ X₀₁⋅X₀₂ + X₁₁⋅X₁₂ + X₂₁⋅X₂₂ + X₃₁⋅X₃₂ + X₄₁⋅X₄₂ + X₅₁⋅X₅₂ + X₆₁⋅X₆₂ + X₇₁⋅X₇₂ + X₈₁⋅X₈₂ + X₉₁⋅X₉₂ X₀₂ + X₁₂ + X₂₂ + X₃₂ + X₄₂ + X₅₂ + X₆₂ + X₇₂ + X₈₂ + X₉₂ ⎦
计算矩阵的符号逆通常不是一个好主意,除非矩阵非常小、稀疏或具有某些特殊的对称性或其他东西。如果矩阵是完全符号化的,并且没有理由简化逆矩阵中的表达式,那么你应该预料到逆矩阵的符号表达式会非常复杂。 SymPy 的
inv
方法将尝试为您简化这些,因为如果表达式不能被简化,它就不太可能有多大用处。为了确定矩阵是否实际上是可逆的,也需要这种简化。这是简化部分在这里很慢。
如果您不想简化并且很乐意假设矩阵是可逆的,那么您可以使用标准逆公式快速计算逆矩阵的表达式:
In [34]: %time Xinv = X.adjugate() / X.det()
CPU times: user 543 ms, sys: 957 µs, total: 544 ms
Wall time: 543 ms
即使在这里也只需要 0.5 秒,因为
det
尝试了一些简化。
我不会显示
Xinv
返回的结果,因为它很大。相反,我将只显示它的字符串表示形式有多长:
In [38]: len(str(Xinv))
Out[38]: 618867
In [39]: len(str(Xinv[0,0]))
Out[39]: 68219
即使只是这个矩阵的第一个元素也有一个太长的字符串表示,无法粘贴到 SO 的答案中。