为什么 `sympy.Matrix.inv` 慢?

问题描述 投票:0回答:1

这是一个小例子。它有多慢让我感到惊讶。

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

我本来以为取一个相对较小的矩阵的逆会很快。我是否遗漏了有关预期用例的某些信息?

python matrix sympy symbolic-math matrix-inverse
1个回答
0
投票

这是你的矩阵:

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 的答案中。

© www.soinside.com 2019 - 2024. All rights reserved.