行列式:面积的账本
如果给「大学线代应试恶梦」评选头牌,行列式赢面很大:按行展开、代数余子式、三阶对角线口诀……一套繁文缛节背下来,没人告诉你它是什么。今天平反:行列式是一个体检指标,一个数,回答一个问题——这个变换把面积放大了几倍?正负号是赠品:负号说明空间被翻了个面。就这些。带着这句话去玩 Demo,你会在五分钟内获得当年一学期没得到的东西;至于那些手算技巧,NumPy 一行就好,我们不练。
只需要盯住一块方砖
先把这一章的纲领用三行账本写在最前面,后文全是它的展开:|det| 记倍数,符号记翻转,零记压扁。
想给一个变换量「面积改变率」,听起来要检查无穷多个图形——其实只需要一块:由 î、ĵ 围成的单位方块。理由是上一卷反复出现的老朋友「线性」:线性变换把所有网格方块以同样的方式变形(网格保持平行等距),所以一块方砖的面积变几倍,所有方砖就都变几倍;而任何曲线图形都能用极细的方砖铺出来(微积分的做法),所以它的面积也按同一倍数变。盯住一块砖,就是盯住了整个空间的面积账。
单位方块经过矩阵 A 变换后,变成由两根新基(A 的两列)张成的平行四边形。这个平行四边形的有向面积,就是行列式,记作 det A 或 |A|:
先别管公式怎么来的(马上讲),先去 Demo 里拖两根柱子,把「面积账本」的体感建立起来:
玩之前先校准一下眼睛:两支箭头是矩阵的两列(上一章的说明书读法——î 和 ĵ 的去向),阴影平行四边形就是「单位方块被变换后的样子」,青色细网格是整张坐标纸的变形结果。读数栏实时用 ad − bc 记账,并且把四个数按「列」上色:橙红是第一列的 a、c,青蓝是第二列的 b、d——公式与图形又一次同色互指。
实验清单:① 复位后把 列₁ 拖长一倍,面积翻倍——det 对「列的缩放」是线性的;② 让两列的夹角慢慢合拢,看面积读数滑向 0——这正是第 03 章「共线检测 v×w」的现场,当年那个神秘表达式 v₁w₂ − v₂w₁,就是 det;③ 点「试一个翻转」或者手动把两列交换位置,填充色由橙转紫,det 变负——空间被镜像了,顺时针的表盘变成逆时针;④ 点「压到 det=0」,平行四边形塌成线段;⑤ 压扁之后继续拖,让两列「穿过」彼此,看阴影从紫色那一侧重新张开——你刚才亲历了一次定向翻转的全过程,det 的符号在共线的一瞬间换了主人。
ad − bc 是怎么来的
不用展开式也能把 2×2 公式推出来,靠一条几何观察:剪切不改变面积(底不变、高不变,平行四边形像一摞扑克牌被推斜)。任何平行四边形都可以通过剪切「扶正」成一个矩形而面积不变:先沿一个方向剪切消掉第一列的纵向分量,再消掉第二列的横向分量,剩下一个 a′×d′ 的正矩形。把这个过程用代数写一遍,消元的结果恰好是 ad − bc。这也顺便解释了为什么高斯消元(第 09 章)能顺路算出行列式:消元的每一步剪切都不动面积,最后对角线一乘就是答案——数值库里 np.linalg.det 真的就是这么算的(LU 分解),没人用课本上的按行展开,那个的复杂度是灾难级的 O(n!)。
正负号的判据也很好记:看两列的相对姿态。从第一列逆时针转到第二列不超过 180°(像 î 到 ĵ 那样),det 为正;顺时针,det 为负。翻转发生的瞬间,两列恰好共线,det 恰好过零——「负数」不是凭空跳出来的,它是连续地穿过压扁点走到镜像世界的。
为什么要「有向」面积,普通面积不香吗?因为有向面积才是线性的好公民:两块同向面积相加、反向面积相消,代数运算才能顺畅进行(和「有向长度」——也就是负数——被发明的理由一模一样)。定向在图形学里是实打实的工程量:三角形顶点按逆时针还是顺时针排,决定 GPU 认为它朝向你还是背对你(背面剔除);网格里出现负面积三角形,通常意味着模型被翻穿了。det 的符号,就是这套定向系统的总开关。
det = 0:空间的降维打击
账本上最重要的一行是零。det A = 0 意味着单位方块被压成零面积——平面被拍进一条直线甚至一个点。这样的矩阵叫奇异矩阵(singular),它是一台信息粉碎机:无穷多个不同的输入被压到同一个输出上,变换不可撤销。这一句话就是下一章「可逆性」的全部剧透:A 可逆 ⇔ det A ≠ 0。压扁的世界回不去,不是技术不行,是数学不许。
顺手收编第 03 章的伏笔:两支向量共线 ⇔ 它们张成的平行四边形面积为零 ⇔ 以它们为列的矩阵 det = 0。「共线检测」「压扁检测」「可逆检测」,三件事从此是同一件事。
压扁对解方程意味着什么,下一章会展开,这里先把画面给你:解 Ax = b 是在问「哪个输入 x 被 A 送到了 b」。A 奇异时,整个平面被压到一条线上——如果 b 恰好躺在那条线上,曾经被压到这里的输入有一整条直线那么多(无穷多解);如果 b 不在线上,压扁后的世界根本没有这个地址(无解)。「唯一解」这个待遇,只有 det ≠ 0 的世界才发得出来。大学时代死记的「系数行列式为零则无解或无穷解」,画面就是这么一次拍扁。
叉积:行列式的孪生兄弟
第 03 章的共线检测当时写成 v×w,这个记号其实另有其主:三维空间里的叉积(cross product)。两支三维向量的叉积是一支新向量:方向垂直于两者张成的平面(右手定则定朝向),长度等于两者张开的平行四边形面积。它的三个分量,恰好是三个 2×2 行列式——叉积就是「行列式的向量化包装」。图形学里它无处不在:三角形的法线 = 两条边的叉积(GPU 靠它算光照),判断点在线段哪一侧 = 叉积的符号。二维「叉积」v₁w₂ − v₂w₁ 是它的简化版:只剩 z 分量,正负号报告「w 在 v 的逆时针侧还是顺时针侧」。地图应用判断「用户偏离路线往左还是往右」,写出来就是这一个减法。
三维行列式还有个「体积配方」的读法:det[u v w](三支向量按列排)= u · (v × w),先叉积得底面法向与面积,再点积投影出高——底乘高,平行六面体体积。这条「混合积」公式在物理和图形引擎里当体积计算器用,而在我们的账本视角下,它只是「det = 体积」的展开式而已。
性质套餐:全部几何秒证
教材里一页页证明的行列式性质,在「面积账本」视角下全是一句话的事:
- det(BA) = det(B) · det(A):流水线接力,先放大 3 倍再放大 2 倍,总共 6 倍。乘法性质是行列式最深刻的性质,几何上却是显然的。
- det(I) = 1:什么都不做,面积不变。
- det(A⁻¹) = 1/det(A):撤销一个放大 3 倍的变换,就是缩小 3 倍。(也解释了奇异矩阵没有逆:1/0 没得除。)
- det(kA) = k²·det(A)(二维):两个方向各放大 k 倍,面积放大 k² 倍;n 维就是 kⁿ——这是新手常踩的地雷,det(2A) 不是 2·det(A)。
- 交换两列,det 变号:交换两根柱子 = 镜像一次。
- 旋转矩阵 det = 1:旋转不改面积不翻面。剪切也是 det = 1——扑克牌推斜,面积照旧。
套餐里还能白嫖一条「圆的命运」:上一章说过圆被线性变换映成椭圆。设椭圆半轴为 a、b,圆面积 π 变成椭圆面积 πab——所以 |det| = ab,两根半轴的乘积。这两根半轴各自是多少?那是奇异值的地盘(第 17 章),但它们的乘积,行列式今天就告诉你了。
再预支一条卷四的甜头:第 15 章你会学到,一个矩阵藏着几个「特征值」——它在特定方向上的纯缩放倍数。行列式与它们的关系美得冒泡:det = 所有特征值的乘积。几何上一目了然:如果变换在一个方向拉长 λ₁ 倍、另一个方向拉长 λ₂ 倍,面积当然放大 λ₁λ₂ 倍。到时候「det = 0 ⇔ 存在一个特征值为 0 ⇔ 某个方向被彻底压死」,三句话会咔哒一声扣在一起。
到三维,行列式变成「单位立方体的像的有向体积」,负号对应左手系右手系之翻转;到 n 维就是超体积。有一件事永远不变:行列式只对方阵有定义——一个 3×2 矩阵把平面贴进三维,「二维面积在三维里的改变率」依然有意义(那是第 17 章奇异值的活),但「体积倍数」无从谈起,det 不接这单生意。
弯曲世界的面积账:雅可比行列式
「线性变换才有统一的面积倍数」——那非线性函数怎么办?比如一个把图像扭曲变形的 warp,或者神经网络这种弯弯绕绕的映射?微积分给出标准答案:局部放大看,一切光滑函数都近似线性。在每一个点附近,非线性函数都有一个「本地线性替身」,替身的矩阵叫雅可比矩阵(Jacobian,第 21 章的主角),而替身的行列式——雅可比行列式——就是「这个点附近的面积缩放率」。地图投影每个纬度的面积失真、图像扭曲后每块像素该采样多大区域、概率密度在非线性变换下怎么换算,全靠它逐点记账。一句话总结这层关系:行列式是全局账本,雅可比行列式是分店账本,分店开在函数的每一个点上。
行列式在 AI 里的黄金岗位是概率密度的记账员。想象一团概率「沙子」铺在空间上,把空间用可逆变换拧一把,沙子还是那些沙子,但铺的面积变了——密度必须除以面积倍数,也就是 |det|,才能保证总概率还是 1。这正是 Normalizing Flows 这类生成模型的核心公式:用一串可逆变换把简单分布(高斯)扭成复杂分布(人脸图像),每层都老老实实记一笔 log|det|,模型的损失函数里明晃晃写着它。工程上从不直接算 det(上万维的 det 会溢出到天上),而是用 slogdet(符号 + 对数)或干脆把网络设计成「det 好算」的三角结构——又一个「数学概念的工程变形记」。
android.graphics.Matrix.invert() 返回 boolean——返回 false 的那一刻,你就在和 det = 0 打交道:比如把 View 的 scaleX 动画到 0 的那一帧,变换矩阵奇异,触摸事件的坐标逆映射直接失败,这是「点不到缩放到 0 的控件」的底层原因。另外你在 Canvas.scale(2f, 2f) 后 drawCircle,圆的面积变四倍不是两倍——det(2I) = 4 的日常版。图形调试时「图元面积不对劲」,先查变换矩阵的 det 是个好习惯。
两个工程陷阱。① det 不是矩阵的「大小」:det 很小不代表矩阵元素小(旋转矩阵 det=1 但可以在别的意义上「很强」;一个各方向都缩小的矩阵 det 极小却毫无病态)。② 用 det 判断「接近奇异」不可靠:det(0.1·I₁₀₀) = 10⁻¹⁰⁰ 看起来吓死人,但 0.1·I 是个健康得不能再健康的矩阵。数值上判断「病不病」,正确的指标是条件数(第 17 章奇异值的比值),不是行列式。det 的正确用法是精确的理论判据(可逆性、定向、体积),不是模糊的健康度量。
为什么手算流程该扔:一笔复杂度账
教材主推的「按行展开」(拉普拉斯展开)把 n 阶行列式拆成 n 个 n−1 阶的,递归下去,总计算量约 n! 级——20 阶就是 2.4×10¹⁸ 次操作,宇宙热寂前算不完一个中型协方差矩阵。而「剪切扶正」路线(高斯消元 / LU 分解)是 O(n³):20 阶只要几千次运算,4096 阶也就几百亿次、GPU 眨眼的事。两条路线差的不是常数,是阶乘对多项式——这就是「为什么手算流程不值得练」的定量版本:它不仅无聊,还是条死路,真实软件里没有任何一行代码走它。
同一把复杂度尺子也宣判了「克拉默法则」的命运:那套「用 n+1 个行列式解方程组」的公式,理论上优雅,数值上又慢又不稳,教材把它当解题工具是历史惯性。你只需要知道它存在、并且知道为什么不用它——面试聊到「为什么数值库不用克拉默法则」,答「复杂度和数值稳定性双输给 LU 分解」即可满分。
顺便补一段冷知识给爱刨根的你:行列式比「矩阵」这个词早出生约一百五十年(莱布尼茨和日本的关孝和在 17 世纪末就在研究它,「matrix」1850 年才被造出来),它最初就是为判断方程组有没有唯一解服务的。所以不是「矩阵派生出行列式」,历史恰好相反——这也解释了为什么老教材总把行列式放在矩阵前面讲:那是按历史顺序,不是按理解顺序。本书按理解顺序来:先有变换,才谈它的体检指标。
写成代码:一行,以及一个更稳的一行
import numpy as np A = np.array([[1.6, 0.4], [0.4, 1.3]]) np.linalg.det(A) # 1.92 —— 面积放大 1.92 倍 R = np.array([[0, -1], [1, 0]]) np.linalg.det(R) # 1.0 —— 旋转不动面积 F = np.array([[0, 1], [1, 0]]) np.linalg.det(F) # -1.0 —— 交换两轴 = 镜像 # 高维下防溢出的写法:返回 (符号, log|det|) sign, logdet = np.linalg.slogdet(np.random.randn(500, 500))
① 不动笔,说出 [3, 0; 0, 2] 的 det 和几何含义;
② 在 Demo 里把两列拖成「先重合、再穿过去」,det 的符号轨迹是什么?为什么翻转必须路过零?
③ det(A) = 5,那 det(A³) 和 det(2A)(二维)各是多少?
④ 为什么 3×2 矩阵没有行列式,但它依然可能「把面积放大 1.7 倍」?这句话矛盾吗?
⑤ 你的同事用 if abs(det(W)) < 1e-6 判断权重矩阵退化,这个检查有什么问题,该换成什么?
小结
行列式 = 单位方块的像的有向面积:绝对值记缩放,符号记翻转,零记压扁;ad − bc 出身于「剪切不改面积」的扶正过程;det(AB) = det(A)det(B) 在流水线视角下是废话文学;奇异 = 压扁 = 不可逆 = 共线,四位一体;叉积是它的向量化包装,雅可比行列式是它开在每个点上的分店,特征值的乘积是它的另一个名字;AI 里它以 log|det| 的身份在生成模型里记概率账;判断数值健康请找条件数,别难为它——精确判据是它的本职,模糊体检不是。从此看到 det,不要伸手拿公式,先在脑子里放那块会变形的方砖。账本已经建好,下一章正式处理「撤销」:什么样的变换能回滚?回滚的说明书(逆矩阵)长什么样?以及把这一切连到你初中就会解的方程组上——Ax = b 的两种世界观。