我有一个4x4矩阵A
,在每个条目中都有相当长但很简单的符号表达式。涉及约30个不同的符号。 “简单”是指这些符号仅使用加法/减法,乘法/除法和整数幂组合。 “长”是指如果我打印出矩阵,它会覆盖三到四个屏幕值。
我需要这个矩阵的决定因素。或者,更具体地说,我知道行列式是一个特定符号中的四阶多项式,我需要这个多项式的系数。 A.det()
在运行数小时后不会终止,因此我需要采用不同的方法。有任何想法吗?到目前为止,我已尝试在simplify
的每个元素上抛出各种A
函数,但没有成功。
我是否有一些策略可以让SymPy知道我的表达式的简单结构,或者我知道结果是其中一个符号中的多项式?
答案 0 :(得分:3)
也许可以创建4x4行列式的通用表达式
In [30]: A = Matrix(4, 4, symbols('A:4:4'))
In [31]: A
Out[31]:
⎡A₀₀ A₀₁ A₀₂ A₀₃⎤
⎢ ⎥
⎢A₁₀ A₁₁ A₁₂ A₁₃⎥
⎢ ⎥
⎢A₂₀ A₂₁ A₂₂ A₂₃⎥
⎢ ⎥
⎣A₃₀ A₃₁ A₃₂ A₃₃⎦
In [32]: A.det()
Out[32]:
A₀₀⋅A₁₁⋅A₂₂⋅A₃₃ - A₀₀⋅A₁₁⋅A₂₃⋅A₃₂ - A₀₀⋅A₁₂⋅A₂₁⋅A₃₃ + A₀₀⋅A₁₂⋅A₂₃⋅A₃₁ + A₀₀⋅A₁₃⋅A₂₁⋅A₃₂ - A₀₀⋅A₁₃⋅A₂₂⋅A₃₁ - A₀₁⋅A₁₀⋅A₂₂⋅A₃₃ + A₀₁⋅A₁₀⋅A₂₃⋅A₃₂ + A₀₁⋅A₁₂⋅A₂₀⋅
A₃₃ - A₀₁⋅A₁₂⋅A₂₃⋅A₃₀ - A₀₁⋅A₁₃⋅A₂₀⋅A₃₂ + A₀₁⋅A₁₃⋅A₂₂⋅A₃₀ + A₀₂⋅A₁₀⋅A₂₁⋅A₃₃ - A₀₂⋅A₁₀⋅A₂₃⋅A₃₁ - A₀₂⋅A₁₁⋅A₂₀⋅A₃₃ + A₀₂⋅A₁₁⋅A₂₃⋅A₃₀ + A₀₂⋅A₁₃⋅A₂₀⋅A₃₁ - A₀₂⋅A₁
₃⋅A₂₁⋅A₃₀ - A₀₃⋅A₁₀⋅A₂₁⋅A₃₂ + A₀₃⋅A₁₀⋅A₂₂⋅A₃₁ + A₀₃⋅A₁₁⋅A₂₀⋅A₃₂ - A₀₃⋅A₁₁⋅A₂₂⋅A₃₀ - A₀₃⋅A₁₂⋅A₂₀⋅A₃₁ + A₀₃⋅A₁₂⋅A₂₁⋅A₃₀
然后在条目中替换
之类的内容A.det().subs(zip(list(A), list(your_matrix)))
但是,生成4x4行列式的SymPy很慢是一个错误。您应该在https://github.com/sympy/sympy/issues/new报告。
编辑(这不适合评论)
看起来Matrix.det
正在调用简化函数。对于3x3和更小的矩阵,明确地写出行列式公式,但对于较大的矩阵,使用Bareis算法计算。您可以看到简化函数(cancel
)被称为here的位置,这是计算的一部分,但最终会做很多工作,因为它试图简化您的非常大的表达式。仅进行取消决定因素本身所需的简化可能更为明智。我为此打开了an issue。
加快这种速度的另一种可能性,即我不确定是否有效,将是选择不同的决定因素算法。选项为Matrix.det(method=alg)
,其中alg
是"bareis"
(默认值),"berkowitz"
或"det_LU"
之一。
答案 1 :(得分:0)
您描述为多项式比率的就是所谓的有理函数: https://en.wikipedia.org/wiki/Rational_function
SymPy的polys模块确实具有表示有理函数的方法,尽管它们可能很慢,尤其是在有很多变量的情况下。
在sympy 1.7中有一个新的矩阵实现,该实现仍处于实验阶段,但是基于polys模块并且可以处理有理函数。我们可以通过快速创建随机矩阵来对其进行测试:
In [35]: import random
In [36]: from sympy import random_poly, symbols, Matrix
In [37]: randpoly = lambda : random_poly(random.choice(symbols('x:z')), 2, 0, 2)
In [38]: randfunc = lambda : randpoly() / randpoly()
In [39]: M = Matrix([randfunc() for _ in range(16)]).reshape(4, 4)
In [40]: M
Out[40]:
⎡ 2 2 2 2 ⎤
⎢ 2⋅z + 1 2⋅z + z 2⋅z + z + 2 x + 2 ⎥
⎢ ──────── ──────────── ──────────── ────────── ⎥
⎢ 2 2 2 2 ⎥
⎢ y + 2⋅y y + 2⋅y + 1 x + 1 2⋅z + 2⋅z ⎥
⎢ ⎥
⎢ 2 2 2 2 ⎥
⎢ y + y + 1 2⋅x + 2⋅x + 1 z z + 2⋅z + 1⎥
⎢ ────────── ────────────── ────── ────────────⎥
⎢ 2 2 2 2 ⎥
⎢ 2⋅y + 2 y + 2⋅y y + 1 x + x + 2 ⎥
⎢ ⎥
⎢ 2 2 2 2 ⎥
⎢ 2⋅z + 2 2⋅z + 2⋅z + 2 y + 1 2⋅y + y + 2⎥
⎢──────────── ────────────── ────────── ────────────⎥
⎢ 2 2 2 2 ⎥
⎢2⋅z + z + 1 2⋅x + 2⋅x + 2 2⋅y + 2⋅y x + 2 ⎥
⎢ ⎥
⎢ 2 2 2 2 ⎥
⎢ 2⋅y + 2⋅y 2⋅y + y 2⋅x + x + 1 2⋅x + x + 1⎥
⎢ ────────── ──────── ──────────── ────────────⎥
⎢ 2 2 2 2 ⎥
⎣ z + 2 x + 2 2⋅y x + 2 ⎦
如果将其转换为新的矩阵实现,则可以使用charpoly方法计算行列式:
In [41]: from sympy.polys.domainmatrix import DomainMatrix
In [42]: dM = DomainMatrix.from_list_sympy(*M.shape, M.tolist())
In [43]: dM.domain
Out[43]: ZZ(x,y,z)
In [44]: dM.domain.field
Out[44]: Rational function field in x, y, z over ZZ with lex order
In [45]: %time det = dM.charpoly()[-1] * (-1)**M.shape[0]
CPU times: user 22 s, sys: 231 ms, total: 22.3 s
Wall time: 23 s
这比上面@asmeurer建议的方法要慢,但是它以规范形式输出作为扩展多项式的比率。特别是,这意味着您可以立即确定行列式是否为零(对于所有x,y,z)。时间也花费了等效的cancel
,但是实现比Matrix.det更有效。
这花了多长时间很大程度上取决于最终输出的复杂程度,您可以从其字符串表示的长度中了解到这一点(我不会展示全部!):
In [46]: len(str(det))
Out[46]: 54458
In [47]: str(det)[:80]
Out[47]: '(16*x**16*y**7*z**4 + 48*x**16*y**7*z**2 + 32*x**16*y**7 + 80*x**16*y**6*z**4 + '
在某个时候,应该可以将其集成到主要的Matrix类中,或者以其他方式使DomainMatrix类更可公开访问。