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

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

- 作者：David（道雾轩）
- 专栏：符号计算的艺术（https://daiw.org/manual/symbolic-computing.md）
- 最后更新：2026-09-13
- 原文：https://daiw.org/manual/symbolic-computing/symbolic-linalg
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

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

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

## 精确的矩阵运算

`Matrix` 做起线性代数，处处精确：

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

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

行列式 $-2$、逆矩阵全是**精确的有理数** $\frac32,-\frac12$——不是 `1.5, -0.5000001`。[数值](https://daiw.org/manual/numerical-computing/pivoting)里为了防止小主元放大误差，要费心搞「部分主元」；符号世界里**根本不需要**——精确算术下，除以一个小数不会带来任何误差，主元随便选。**「数值稳定性」这个数值计算的头等大事，在符号世界里干脆不存在。**

## 矩阵元素可以是符号

更强的是，矩阵元素能直接是**变量**，于是你得到的是**公式**：

```python
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\times2$ 行列式公式 $ad-bc$、逆矩阵的一般公式——**符号地推导出来**，而不是对某个具体矩阵求值。这是符号线性代数独有的能力：**它算的是「任意矩阵」的规律，不是「某个矩阵」的数。**

## 高潮：一次漂亮的「打脸」

现在来看这一章的重头戏。求特征值，`eigenvals` 给出**精确**的结果：

```python
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}
```

两个精确的特征值 $\frac{5\pm\sqrt{33}}{2}$。**关键在于它是怎么算出来的**：先求**特征多项式** $\lambda^2-5\lambda-2$，再[解这个方程](https://daiw.org/manual/symbolic-computing/equation-solving)的根。可是——

<Callout type="warn">
  **等一下！孪生专栏的[特征值那章](https://daiw.org/manual/numerical-computing/eigenvalues)不是斩钉截铁地说「绝对不要用特征多项式的根来求特征值」吗？这里怎么正大光明地这么干？**

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

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

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

当然，符号特征值也有它的天花板：$5\times5$ 以上的一般矩阵，特征多项式是五次以上，撞上[Abel-Ruffini 的墙](https://daiw.org/manual/symbolic-computing/equation-solving)——特征值**写不成根式**，只能用 `CRootOf` 表示。精确与否是一回事，能否用根式写出来是另一回事。

## 还能做什么

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

- **行简化（RREF）**：`M.rref()` 给出精确的最简行阶梯形，没有[数值 RREF](https://daiw.org/manual/numerical-computing/pivoting) 里「这个数到底算不算零」的煎熬（精确算术下，零就是零）。
- **符号求解 $Ax=b$**：系数带参数，解出的 $x$ 是关于参数的公式。
- **矩阵的秩、零空间、若尔当标准形**：都能精确算，用于理论推导。

这些在**理论推导、教学、以及需要「精确结构」的场合**（比如判断一族矩阵何时奇异）无可替代——代价依然是可能的[表达式膨胀](https://daiw.org/manual/symbolic-computing/expression-swell)，大矩阵的符号逆能长得吓人。

## 小结与下一站

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

精确求解讲完，我们对符号计算的**能力**已经了如指掌。最后一站，退后一步看**全局**：业内主流的 CAS 工具都有谁、各擅胜场？符号计算最大的软肋是什么？它和数值计算到底该怎么选？先看工具全景。👉 [主流 CAS 全景](https://daiw.org/manual/symbolic-computing/cas-landscape)。

## 参考文献

- [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 —— 符号线性代数。
