MENU

sympy 库计算矩阵行列式

• February 19, 2024 • Read: 210 • 学习笔记,解决方案,Python,知识库

sympy 库计算矩阵行列式

220502

线性代数背景

计算行列式的特征值是一件很简单的事情,直接用定义都可以计算:

$M_{ij}$ 是 $A$ 划去第 $i$ 行第 $j$ 列得到的 $n-1$ 阶矩阵

余子式: $\det M_{ij}$

代数余子式: $C_{ij}=(-1)^{i+j}\det M_{ij}$

行列式展开定理

$$ \det A=|{a_{ij}}|_ {n\times n}=a_ {i1}C_ {i1}+a_{i2}C_{i2}+\cdots+a_{in}C_{in},\forall i,j=1,\cdots,n $$

这样计算的方式中只有乘法和加法

sympy计算

使用Python第三方库计算当然也是最简单不过的啦

from sympy import *

M = Matrix([[1, 0, 0], [0, 1, 2], [0, 3, 4]])
print(M.det()) # -2

当然我们也可以定义一些符号来做符号运算

from sympy import *

a, b, c, d = symbols("a,b,c,d")
M = [[1, 0, 0], [0, a, b], [0, c, d]]
print(Matrix(M).det())  # a*d - b*c

出现的问题

下面是我在固体物理课程中计算能带时列出的式子:

>>> print(M) 
[[3.23e-17 - E, 2.50e-20, 1.06e-20], 
[2.50e-20, 3.18e-20 - E, 2.50e-20],
[1.00e-20, 2.50e-20, 3.23e-17 - E]]
>>> eq = Matrix(M).det()
-E**3 + 6.47e-17*E**2 - 1.04e-33*E + 3.32e-53

可以看到,这是三阶的情况,计算的行列式无误。但是当达到四阶的时候,意想不到的事情发生了

>>> print(M) 
[[3.23e-17 - E, 2.50e-20, 1.06e-20, 0], 
[2.50e-20, 3.18e-20 - E, 2.50e-20, 1.06e-20],
[1.06e-20, 2.50e-20, 3.23e-17 - E, 2.50e-20],
[0, 1.06e-20, 2.50e-20, 1.29e-16 - E]]
>>> eq = Matrix(M).det()
(1.00*E**8 - 2.91e-16*E**7 + 3.13e-32*E**6 - 1.69e-48*E**5 + 4.92e-65*E**4 - 7.45e-82*E**3 + 4.61e-99*E**2 - 2.91e-118*E + 4.62e-138)/(1.0*E**4 - 9.70e-17*E**3 + 3.14e-33*E**2 - 3.39e-50*E + 1.07e-69)

你可以看到,当M为四阶的时候,M的结构和三阶时是一样的,可是行列式算出来却有分母?直接展开来思考,肯定是一个四阶多项式啊。虽然次数好像没问题,但这让人匪夷所思。

在我的计算过程中,计算好行列式之后下面需要令行列式等于0解出E:对于三阶的情况,这就是一个三阶多项式;但是对于四阶的情况,这可能直接变成了八阶多项式……我实际计算的是五阶的情况,甚至出了十七阶多项式。

调查

上SO搜了一下,也有人出现过相似的问题,主题是关于sympy计算符号行列式

Speeding up computation of symbolic determinant in SymPy

在这篇问答中,有人提到

It looks like Matrix.det is calling a simplification function. For matrices 3x3 and smaller, the determinant formula is written out explicitly, but for larger matrices, it is computed using the Bareis algorithm. -- https://stackoverflow.com/a/37056325/14298786

简单来说 就是smypy对于高阶符号运算使用 Bareis算法 这个算法中用到了除法。

为什么要用呢?复杂度低呗(详见Bareis算法)。当然是好事情 但是对我来说就是大麻烦。

解决方案

查看sympy文档

(method) det: (method: str = "bareiss", iszerofunc: Any | None = None) -> Any

method:
If it is set to 'bareiss', Bareiss’ fraction-free algorithm will be used.
If it is set to 'berkowitz', Berkowitz’ algorithm will be used.
Otherwise, if it is set to 'lu', LU decomposition will be used.

Samuelson–Berkowitz算法试一下:

..., it performs no divisions, so may be applied to a wider range of algebraic structures.
>>> print(M)
[[3.23e-17 - E, 2.50e-20, 1.06e-20, 0], 
[2.50e-20, 3.18e-20 - E, 2.50e-20, 1.06e-20],
[1.06e-20, 2.50e-20, 3.23e-17 - E, 2.50e-20],
[0, 1.06e-20, 2.50e-20, 1.29e-16 - E]]
>>> eq = Matrix(M).det(method='berkowitz')
1.0*E**4 - 1.93e-16*E**3 + 9.41e-33*E**2 - 1.35e-49*E + 4.29e-69

好了,这样问题就解决了,省去了我手写四阶展开式的时间。

版权属于:字节星球/肥柴之家 (转载请联系作者授权)
原文链接:https://www.bytecho.net/archives/2368.html
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

Archives QR Code
QR Code for this page
Tipping QR Code
Leave a Comment