符号线性代数 · 精确的矩阵,与一次漂亮的「打脸」

符号地做线性代数:精确的行列式、逆、特征值,矩阵元素还能是变量。这一章最精彩的是一处回扣——孪生的数值专栏千叮万嘱「绝不要用特征多项式求特征值」,符号世界里却正大光明地这么做。同一件事,两种世界,答案相反。

作者 David更新于 第 14 篇(共 18 篇)

符号线性代数 · 精确的矩阵,与一次漂亮的「打脸」

精确求解的第二块,是线性代数。孪生专栏花了整整四章讲数值线性代数的种种小心翼翼(主元、条件数、迭代法)。到了符号世界,画风一变——因为没有舍入误差,很多数值上的「禁忌」在这里烟消云散。这一章的高潮,是一处让人会心一笑的「打脸」。

精确的矩阵运算

Matrix 做起线性代数,处处精确:

from sympy import *
M = Matrix([[1, 2], [3, 4]])

print(M.det())          # -2               —— 精确行列式
print(M.inv())          # Matrix([[-2, 1], [3/2, -1/2]])   —— 精确逆(有理数,不是小数!)

行列式 −2-2、逆矩阵全是精确的有理数 32,−12\frac32,-\frac12——不是 1.5, -0.5000001。数值里为了防止小主元放大误差,要费心搞「部分主元」;符号世界里根本不需要——精确算术下,除以一个小数不会带来任何误差,主元随便选。「数值稳定性」这个数值计算的头等大事,在符号世界里干脆不存在。

矩阵元素可以是符号

更强的是,矩阵元素能直接是变量,于是你得到的是公式:

a, b, c, d = symbols('a b c d')
M = Matrix([[a, b], [c, d]])

print(M.det())     # a*d - b*c                      —— 行列式公式
print(M.inv())     # Matrix([[d/(a*d-b*c), -b/(a*d-b*c)], [-c/(a*d-b*c), a/(a*d-b*c)]])

2×22\times2 行列式公式 ad−bcad-bc、逆矩阵的一般公式——符号地推导出来,而不是对某个具体矩阵求值。这是符号线性代数独有的能力:它算的是「任意矩阵」的规律,不是「某个矩阵」的数。

高潮:一次漂亮的「打脸」

现在来看这一章的重头戏。求特征值,eigenvals 给出精确的结果:

M = Matrix([[1, 2], [3, 4]])
print(M.charpoly().as_expr())   # lambda**2 - 5*lambda - 2    —— 特征多项式
print(M.eigenvals())            # {5/2 - sqrt(33)/2: 1, 5/2 + sqrt(33)/2: 1}

两个精确的特征值 5±332\frac{5\pm\sqrt{33}}{2}。关键在于它是怎么算出来的:先求特征多项式 λ2−5λ−2\lambda^2-5\lambda-2,再解这个方程的根。可是——

等一下!孪生专栏的特征值那章不是斩钉截铁地说「绝对不要用特征多项式的根来求特征值」吗?这里怎么正大光明地这么干?

这不是矛盾,而是**「对的方法取决于你在符号世界还是数值世界」**最精彩的一课:

  • 数值世界里,这么做是灾难。多项式的根对系数极度敏感(病态,Wilkinson 的经典警告),浮点系数的一点点舍入误差,会让算出的根面目全非。所以数值上要绕开特征多项式,改用 QR 算法那种稳定的迭代。
  • 符号世界里,这么做完全正确、而且标准。因为根本没有舍入误差——特征多项式的系数是精确的整数 / 有理数,解出的根也精确。那个让数值方法崩溃的「敏感性」,在精确算术下无处施展。

同一个算法,在一个世界里是禁忌,在另一个世界里是正道。 差别不在算法,而在你脚下的地面是「精确」还是「近似」。这正是本专栏与孪生专栏合起来想让你看见的:没有绝对最好的方法,只有「适合当前世界的方法」。

当然,符号特征值也有它的天花板:5×55\times5 以上的一般矩阵,特征多项式是五次以上,撞上Abel-Ruffini 的墙——特征值写不成根式,只能用 CRootOf 表示。精确与否是一回事,能否用根式写出来是另一回事。

还能做什么

符号线性代数的精确性,让一批操作变得干净利落:

  • 行简化(RREF):M.rref() 给出精确的最简行阶梯形,没有数值 RREF 里「这个数到底算不算零」的煎熬(精确算术下,零就是零)。
  • 符号求解 Ax=bAx=b:系数带参数,解出的 xx 是关于参数的公式。
  • 矩阵的秩、零空间、若尔当标准形:都能精确算,用于理论推导。

这些在理论推导、教学、以及需要「精确结构」的场合(比如判断一族矩阵何时奇异)无可替代——代价依然是可能的表达式膨胀,大矩阵的符号逆能长得吓人。

小结与下一站

符号线性代数精确地算行列式、逆、特征值,元素还能是变量(给出 ad−bcad-bc 这样的公式);没有舍入误差,所以数值世界的主元、稳定性顾虑在此统统消失。最深刻的一课:求特征值用特征多项式的根——数值上是禁忌(病态、Wilkinson),符号上却是正道(精确无误)。同一算法,两个世界,答案相反;方法的对错,取决于脚下是精确还是近似。 天花板依旧是 Abel-Ruffini 与表达式膨胀。

精确求解讲完,我们对符号计算的能力已经了如指掌。最后一站,退后一步看全局:业内主流的 CAS 工具都有谁、各擅胜场?符号计算最大的软肋是什么?它和数值计算到底该怎么选?先看工具全景。👉 主流 CAS 全景。

参考文献

  • [1] SymPy 文档.「Matrices (det, inv, eigenvals, rref, charpoly).」https://docs.sympy.org/latest/modules/matrices/matrices.html
  • [2] J. H. Wilkinson.《The Algebraic Eigenvalue Problem》—— 特征多项式求根的数值病态(反面教材,符号世界的反衬)。
  • [3] Geddes, Czapor & Labahn.《Algorithms for Computer Algebra》, ch. 9 —— 符号线性代数。

本页目录