Part I · 第 1 章 线性代数 · 1.6

逆、秩与零空间

矩阵把空间变了形,我们能不能把这部电影倒着放?信息没丢的时候可以,这就是逆。平面被压成一条线时就不行了:有些输入被压到同一点(被压掉的方向叫零空间),有些输出再也够不到(够得到的部分叫列空间)。冗余机械臂正是靠这份“多余的自由”,在手纹丝不动的同时把手肘摆来摆去。

约 30 分钟 前置:1.3 · 1.4 · 1.5 6 个交互

    1为什么机器人需要它

    机器人每天都在解“反问题”。我想让手以 0.1 m/s 向前走,每个关节该转多快?写成方程就是 \(J\,\dot{\mathbf q} = \dot{\mathbf x}\):矩阵 \(J\)(雅可比,3.3 节)和想要的手速 \(\dot{\mathbf x}\) 已知,要求关节速度 \(\dot{\mathbf q}\)。又比如:激光雷达看到了这些点,到底是哪个位姿产生了这些测量?

    这类问题的答案有三种可能:恰好一个,一个也没有,或者无穷多个。六关节机械臂在一般姿态下,每个手速恰好对应一组关节速度。手想去的方向被关节锁死时,没有答案。而七关节机械臂有个有趣的现象:手可以纹丝不动,手肘却还能绕着转,于是有无穷多组关节速度给出同一个手速。这份多出来的自由叫零空间,机器人用它躲障碍、避开关节限位。

    这一节回答三个问题:什么时候能“倒放”(逆)?不能倒放时,到底丢了什么(列空间与零空间)?答案有多少个(解集)?

    2直觉:倒放电影

    把矩阵 \(A\) 想成一部电影:每个点从原位置出发,滑到新位置。逆 \(A^{-1}\) 就是倒放这部电影,让每个点滑回去。要能倒放,有一个条件:不能有信息丢失。只要每个终点都能唯一地告诉你“我是从哪里来的”,倒放就成立。

    剪切、旋转、拉伸都满足这个条件。但如果电影把整个平面压到一条线上(行列式 \(=0\),1.5 节),不同的起点就会挤到同一个终点,倒放时你根本不知道该把它送回哪里。下面选一种变换,把滑块拖到 1 看正放,再拖到 2 看倒放。

    FIG 1能倒放吗?
    九个彩色圆点代表平面上的九个起点,空心圆圈标出它们的原位置。滑块 0 到 1 是用 \(A\) 正放,1 到 2 是用 \(A^{-1}\) 倒放。试试“压扁”:倒放无从下手,因为有几个点已经叠在一起了(图上的 ×2 就是两点重合)。再试试“几乎压扁”:能倒放,但 \(A^{-1}\) 要把几乎被压没的方向大幅拉回来。
    核心洞见

    能不能求逆,问的是有没有信息被丢掉。丢掉的那部分有两个名字:被压成零的输入方向叫零空间;输出里真正够得到的那部分叫列空间,够不到的输出就是“信息缺口”。没有方向被压掉、所有输出都够得到,\(A\) 才可逆。

    3动手玩:逆与压扁

    这是 1.3 节矩阵实验室的升级版。拖动红绿箭头尖(或直接改矩阵里的数)。不带颜色的箭头是输入 \(\mathbf x\),黄色箭头是输出 \(A\mathbf x\)。右侧实时给出 \(A^{-1}\),以及它的元素有多大。点“▶”看 \(A\) 把网格拉变形,再由 \(A^{-1}\) 拉回来。把矩阵压成秩 1,看看会发生什么:青色线是列空间,紫色线是零空间,紫色虚线上的所有输入会落在同一个输出点上。

    FIG 2逆与零空间实验室
    矩阵 A(拖动或输入)
    预设
    淡色网格是原坐标,青色网格是 \(A\) 变换后的网格。秩为 1 时,青色粗线是列空间,紫色粗线是零空间,细的紫色虚线是“输出相同”的输入集合,每条虚线对应青线上的一个小圆点。\(\mathbf x\) 的手柄靠近零空间时会吸附上去。
    试一试
    • 让 \(A\) 仍然可逆,但 \(A^{-1}\) 里某个元素的绝对值超过 10(右侧的“逆有多大”条会变红)。
    • 做一个秩为 1 的矩阵,使零空间正好是直线 y = x。提示:输入 (1, 1) 要被压成 0,这对两列意味着什么?
    • 在一个秩为 1 的矩阵上,把输入 \(\mathbf x\) 拖到一个非零位置,使 \(A\mathbf x = \mathbf 0\)。

    小游戏:把它撤销掉

    紫色网格是某个矩阵 \(A\) 作用后的样子。你的任务是找出它的逆 \(B\):拖动红绿箭头(\(B\) 的两列,也就是 \(B\hat\imath\) 和 \(B\hat\jmath\)),使 \(B\) 作用在紫色网格上之后,青色网格正好回到标准网格。读法提示:\(BA = I\) 的意思是 \(B\) 要把 \(A\hat\imath\) 送回 \(\hat\imath\),把 \(A\hat\jmath\) 送回 \(\hat\jmath\)。

    FIG 3找出逆矩阵
    紫色实线箭头是 \(A\) 的两列;青色细箭头是 \(B\) 作用在它们上面的结果 \(BA\hat\imath\)、\(BA\hat\jmath\)。两根青箭头同时压在 \(\hat\imath\)、\(\hat\jmath\) 上,就成功了。
    • 不看答案,累计撤销 3 个矩阵。

    4第二个视角:解方程 Ax = b 的几何

    “倒放”换一种说法,就是解方程:给定想要的输出 \(\mathbf b\),哪个输入 \(\mathbf x\) 会产生它?两个面板对应两个空间:左边是输入空间(\(\mathbf x\) 住在这里),右边是输出空间(\(\mathbf b\) 住在这里)。拖动右边的黄色目标 \(\mathbf b\),左边会显示解的集合;也可以拖动左边的输入 \(\mathbf x\),右边会显示 \(A\mathbf x\)。

    先用“可逆”预设:每个 \(\mathbf b\) 都有且只有一个 \(\mathbf x\)。再切到“秩 1”:输出被压在青色的列空间上。\(\mathbf b\) 在线上,解有一整条线;\(\mathbf b\) 离开了线,则一个解也没有。

    FIG 4解 Ax = b:输入空间与输出空间
    输入空间:x
    输出空间:b
    黄色是“答案”:右边的目标 \(\mathbf b\),左边的解(一个点,或一整条线)。紫色是零空间,青色是列空间。秩 1 时,左边黄线永远平行于紫线:解集 = 一个特解 + 零空间。\(\mathbf b\) 离开青线时变红,虚线是它到列空间的差距(“最接近的解”是 1.13 节的内容)。
    试一试
    • 选“秩 1”预设,让 \(\mathbf b\) 落在青色列空间上(且 \(\mathbf b \ne \mathbf 0\)),看解变成一整条线。拖动输入 \(\mathbf x\) 沿黄线滑动:\(\mathbf b\) 不动。
    • 在秩 1 的矩阵上,找一个没有解的 \(\mathbf b\)。

    5第三个视角:三维里的秩与零空间

    在三维里,一个 \(3\times3\) 矩阵把单位立方体变成平行六面体。如果有信息丢失,六面体会塌掉:秩 3 是实心的,秩 2 压成一片平行四边形,秩 1 压成一根线,秩 0 压成一个点。能到达的地方(列空间)有多大,取决于秩;被压掉的方向(零空间)有多大,取决于“还剩多少自由”。两者的维数之和永远等于 3:

    $$ \underbrace{\dim C(A)}_{\text{rank}} \;+\; \underbrace{\dim N(A)}_{\text{nullity}} \;=\; 3. $$

    转动视角,点预设,或者直接编辑矩阵。立方体的红、绿、蓝三类边是 \(A\) 的第 1、2、3 列。

    FIG 5立方体的塌缩:列空间与零空间
    矩阵 A(3×3)
    预设
    灰色细线是原来的单位立方体,彩色是它的像。青色的片或线是列空间,紫色的线或片是零空间(被 \(A\) 压成零的方向)。拖动画面转动视角。
    试一试
    • 不用预设,只改矩阵里的数,让立方体压成一片(秩 2)。提示:把第 3 行全部改成 0。
    • 让立方体压成一根线(秩 1),然后数一数:零空间的维数是几?

    6再看数学

    提示:把鼠标悬停在公式中带底色的符号上,FIG 2 和 FIG 4 里对应的元素会被加粗。

    逆

    如果存在矩阵 \(A^{-1}\),使得

    $$ A^{-1}A = A A^{-1} = I, $$

    就说 \(A\) 可逆,\(A^{-1}\) 是它的逆。\(A^{-1}A = I\) 的意思是:先做 \(A\),再做 \(A^{-1}\),等于什么都没做(回忆 1.4 节:右边的先作用)。对 \(2\times2\) 矩阵,逆有一个封闭公式:

    $$ A = \begin{bmatrix} a & b \\ c & d \end{bmatrix} \;\Longrightarrow\; A^{-1} = \frac{1}{ad - bc}\begin{bmatrix} d & -b \\ -c & a \end{bmatrix}. $$

    不必死记,验证一下就会了。把两个矩阵乘起来:

    $$ \begin{bmatrix} a & b \\ c & d \end{bmatrix}\begin{bmatrix} d & -b \\ -c & a \end{bmatrix} = \begin{bmatrix} ad - bc & -ab + ba \\ cd - dc & -cb + da \end{bmatrix} = (ad - bc)\, I. $$

    除以 \(ad - bc\)(就是行列式)后得到 \(I\)。例如 \(A = \begin{bmatrix}2&1\\4&3\end{bmatrix}\),\(\det A = 6 - 4 = 2\),所以 \(A^{-1} = \tfrac12\begin{bmatrix}3&-1\\-4&2\end{bmatrix} = \begin{bmatrix}1.5&-0.5\\-2&1\end{bmatrix}\)。把两者相乘,确实得到 \(I\)。

    这个公式怎么读

    除以行列式,是在抵消 \(A\) 对面积的缩放(1.5 节)。\(\det A \to 0\) 时分母趋于零,\(A^{-1}\) 的元素爆炸:这正是 FIG 2 里“逆有多大”条变红的原因。\(\det A = 0\) 时没有逆。

    乘积的逆:先穿袜子,后穿鞋

    \(AB\) 的意思是“先 \(B\) 后 \(A\)”(1.4 节)。撤销一串动作,要倒着撤:先脱鞋(撤销 \(A\)),再脱袜子(撤销 \(B\)):

    $$ (AB)^{-1} = B^{-1}A^{-1}. $$

    验证:\((AB)(B^{-1}A^{-1}) = A(BB^{-1})A^{-1} = AA^{-1} = I\)。数值例子:\(A = \begin{bmatrix}1&1\\0&1\end{bmatrix}\),\(B = \begin{bmatrix}2&0\\0&1\end{bmatrix}\),则 \(AB = \begin{bmatrix}2&1\\0&1\end{bmatrix}\),\((AB)^{-1} = \begin{bmatrix}0.5&-0.5\\0&1\end{bmatrix}\),恰好等于 \(B^{-1}A^{-1}\),而 \(A^{-1}B^{-1} = \begin{bmatrix}0.5&-1\\0&1\end{bmatrix}\) 不对。

    列空间与秩

    \(A\mathbf x\) 是 \(A\) 各列的线性组合,系数是 \(\mathbf x\) 的各个分量(1.3 节的列视角)。所以所有能够作为输出的向量,恰好是各列的张成(1.2 节)。这个集合叫 \(A\) 的列空间:

    $$ \hl{col}{C(A)} = \{\, A\mathbf x : \mathbf x \in \R^n \,\} = \operatorname{span}\{\text{columns of } A\}. $$

    它的维数叫秩(rank):\(\operatorname{rank}A = \dim C(A)\),也就是线性无关的列的个数。一个 \(2\times2\) 矩阵的秩是 2(列空间是整个平面)、1(一条线)或 0(只有原点)。同一个矩阵,线性无关的行也同样多(这是个定理,证明见 Strang)。

    零空间与秩–零化度定理

    被 \(A\) 压成零向量的所有输入,叫 \(A\) 的零空间:

    $$ \hl{null}{N(A)} = \{\, \mathbf x : A\mathbf x = \mathbf 0 \,\}. $$

    它总是包含 \(\mathbf 0\),而且是子空间:若 \(A\mathbf u = A\mathbf w = \mathbf 0\),则 \(A(\mathbf u + s\mathbf w) = \mathbf 0\)。它的维数叫零化度(nullity)。例如 \(A = \begin{bmatrix}1&2\\2&4\end{bmatrix}\):第二列是第一列的 2 倍,列空间是 \((1,2)\) 方向的直线;\(A\mathbf x = \mathbf 0\) 等价于 \(x + 2y = 0\),零空间是 \((-2, 1)\) 方向的直线。

    每个输入方向,要么“活下来”(贡献一维列空间),要么“被压掉”(贡献一维零空间),没有第三种命运。这就是秩–零化度定理:对有 \(n\) 列的矩阵,

    $$ \operatorname{rank} A \;+\; \operatorname{nullity} A \;=\; n. $$

    FIG 5 里 \(n = 3\):秩 3 → 零化度 0;秩 2 → 1;秩 1 → 2;秩 0 → 3。

    \(A\mathbf x = \mathbf b\) 的解集

    $$ A\,\hl{x}{\mathbf x} = \hl{b}{\mathbf b} \quad\Longrightarrow\quad \text{solutions} = \hl{xp}{\mathbf x_p} + \hl{null}{N(A)}. $$

    有没有解:当且仅当 \(\mathbf b \in C(A)\)。有几个解:只要有一个特解 \(\mathbf x_p\)(\(A\mathbf x_p = \mathbf b\)),再加上零空间里任意向量 \(\mathbf n\),\(A(\mathbf x_p + \mathbf n) = \mathbf b + \mathbf 0 = \mathbf b\) 仍然成立。反过来,两个解的差 \(\mathbf x - \mathbf x_p\) 被 \(A\) 送到 \(\mathbf 0\),所以落在零空间里。因此解集就是零空间平移到 \(\mathbf x_p\),维数等于零化度:零空间只有 \(\{\mathbf 0\}\) 时解唯一,否则无穷多。例:\(A = \begin{bmatrix}1&2\\2&4\end{bmatrix}\),\(\mathbf b = (3, 6)\)。\(\mathbf x_p = (3, 0)\) 是一个特解,通解是 \((3,0) + t(-2, 1)\);取 \(t = 1\) 得 \((1,1)\),确有 \(A(1,1) = (3,6)\)。而 \(\mathbf b = (3,5)\) 不是 \((1,2)\) 的倍数,无解。

    方阵:五句话说的是同一件事

    对 \(n\times n\) 方阵 \(A\),下面几条互相等价:

    $$ A \text{ invertible} \;\Leftrightarrow\; \det A \ne 0 \;\Leftrightarrow\; \operatorname{rank}A = n \;\Leftrightarrow\; N(A) = \{\mathbf 0\} \;\Leftrightarrow\; C(A) = \R^n. $$

    几何读法:没有方向被压掉(零空间只有 \(\mathbf 0\)),所以也没有输出够不到(列空间是全空间),所以每个 \(\mathbf b\) 恰好有一个解 \(\mathbf x = A^{-1}\mathbf b\)。“压扁”这件事在 \(\det A = 0\) 时发生,它同时意味着零空间变大、列空间变小。对非方阵(\(m \ne n\))没有逆,\(m < n\) 时必有非零的零空间,\(m > n\) 时一般有够不到的 \(\mathbf b\),处理办法见 1.13 节。

    实际怎么算

    教科书里 \(\mathbf x = A^{-1}\mathbf b\) 很漂亮,代码里很少这么写。库函数(np.linalg.solve、Eigen 的 A.lu().solve(b))先把 \(A\) 做 LU 分解(高斯消元的矩阵形式),再回代,既快又准。秩也不是靠行列式判断的:np.linalg.matrix_rank 会计算奇异值(1.12 节),把小于阈值的当作零。

    7机器人中的它:手不动,肘在动

    考虑一个平面三连杆机械臂:3 个关节 \(\mathbf q = (q_1,q_2,q_3)\),而手的位置只有 2 个坐标 \(\mathbf x = (x, y)\)。手速和关节速度之间是一个 \(2\times3\) 的雅可比矩阵:\(\dot{\mathbf x} = J(\mathbf q)\,\dot{\mathbf q}\)(3.3 节)。第 \(i\) 列是“只转第 \(i\) 个关节时手怎么动”:手相对于关节 \(i\) 的位置向量逆时针转 90°,即 \((-(y_h - y_i),\, x_h - x_i)\)。

    \(J\) 有 3 列、2 行,秩至多是 2。由秩–零化度定理,零空间至少是 \(3 - 2 = 1\) 维:存在一个关节速度方向 \(\mathbf n\),使 \(J\mathbf n = \mathbf 0\)。沿着它转动关节,手一动也不动,但手肘和手腕都在动。这个方向可以直接算出来:\(J\) 的两行都是 \(\mathbb R^3\) 里的向量,\(\mathbf n\) 与两行都垂直,所以 \(\mathbf n\) 平行于两行的叉积(1.8 节)。

    下面是这个想法的完整演示。拖动黄色的手,机械臂用阻尼伪逆迭代自己找关节角(伪逆见 1.13 节,这里是页内自带的简单实现)。拖动手肘(空心圆圈)或下方的“自运动”滑块,关节沿着零空间方向 \(\mathbf n(\mathbf q)\) 积分:\(\dot{\mathbf q} = \alpha\,\mathbf n(\mathbf q)\)。注意积分只在一阶意义上保持手不动,所以每一步都要小步前进、重新归一化,再用牛顿修正把手拉回原位。紫色小箭头是 \(\mathbf n\) 引起的各关节点的速度:手上的那个是零。

    FIG 6三连杆机械臂的自运动
    零空间方向 n(单位向量)
    不带颜色的粗线是机械臂,淡色的“鬼影”是自运动经过的姿态,青色虚线是手肘和手腕走过的轨迹。紫色圆环是任务点,红色圆盘是障碍物。条形图是 \(\mathbf n\) 的三个分量:三个关节怎样配合,才能让手不动。
    • 挑战:手保持在紫色任务点上,把手肘摆到连线的另一侧,整个过程不碰红色障碍物。提示:自运动有两个方向,其中一个会撞上去。一旦碰到,点“重置”重来。
    真实系统里

    Franka Panda、KUKA iiwa 这类 7 关节机械臂,手的位姿是 6 维(3 个位置加 3 个姿态),\(J\) 是 \(6\times7\),一般姿态下秩为 6,零空间正好 1 维:手肘可以绕着“肩–腕连线”转一圈,手完全不动。控制器常写成 \(\dot{\mathbf q} = J^{+}\dot{\mathbf x} + (I - J^{+}J)\,\mathbf z\):第一项完成手的任务,第二项把任意想要的关节运动 \(\mathbf z\)(离关节限位远一点、离障碍物远一点)投影进零空间,保证不影响手。伪逆 \(J^{+}\) 在 1.13 节展开。

    8常见误区

    误区 1:用 inv(A) @ b 来解 Ax = b

    先显式求逆再乘,比直接解方程慢,数值上也更不准,还会白白算出你根本不需要的整个矩阵。写 np.linalg.solve(A, b)。只有当你真的需要 \(A^{-1}\) 本身(比如要它的元素)时才去求逆。

    误区 2:“只要 det ≠ 0 就没问题”

    几乎奇异的矩阵会把噪声放大。取 \(A = \begin{bmatrix}1&2\\0.5&1.1\end{bmatrix}\),\(\det A = 0.1\),\(A^{-1} = \begin{bmatrix}11&-20\\-5&10\end{bmatrix}\)。若 \(\mathbf b = (3, 1.6)\),解是 \((1, 1)\);传感器只让 \(b_2\) 变了 0.01,变成 \(\mathbf b = (3, 1.61)\),解就变成 \((0.8, 1.1)\)。输入误差 0.01,输出误差 0.22:约 20 倍。放大倍数由条件数决定(1.12 节),而不是行列式本身的大小:1.5 节说过,\(0.1\,I\) 的行列式也很小,却一点也不病态。这里各元素都是 1 左右的量级,行列式小才恰好意味着接近奇异。

    误区 3:给非方阵求逆

    \(2\times3\) 的雅可比没有逆:列比行多,必有零空间,不可能“一一对应”。需要的是伪逆(最小范数解或最小二乘解),见 1.13 节。

    误区 4:\((AB)^{-1} = A^{-1}B^{-1}\)

    错,顺序要反过来:\((AB)^{-1} = B^{-1}A^{-1}\)。穿袜子再穿鞋,脱的时候必须先脱鞋。上一节的数值例子里,\(A^{-1}B^{-1}\) 和正确答案差一个元素。机器人里常见的情形:\(({}^{A}T_{B}\,{}^{B}T_{C})^{-1} = ({}^{B}T_{C})^{-1}({}^{A}T_{B})^{-1}\)。

    误区 5:浮点数里“秩”是个阈值问题

    数学上秩 1 的矩阵,经过浮点运算常常变成“秩 2,但第二个奇异值是 \(10^{-17}\)”。比如 0.1*3 - 0.3 的结果是 \(5.55\times10^{-17}\),不是 0。所以“\(\det = 0\)”这种判断在代码里几乎永远不成立;要看奇异值(1.12 节),并和一个相对阈值比较。

    9小练习

    1. 矩阵 \(A = \begin{bmatrix}1&2\\2&4\end{bmatrix}\),下面哪个向量在它的零空间里?
    \(A(2,-1) = (2-2,\ 4-4) = (0,0)\)。其余三个:\(A(1,2) = (5,10)\),\(A(2,1) = (4,8)\),\(A(1,-2) = (-3,-6)\),都不是零。零空间就是方程 \(x + 2y = 0\) 的解,即 \((-2,1)\) 方向的直线。
    2. 一个 7 关节机械臂要跟踪 6 维的手部位姿,雅可比 \(J\) 是 \(6\times7\),在某个姿态下秩为 6。它的零空间有几维?
    秩–零化度:\(\operatorname{rank} + \operatorname{nullity} = n = 7\)(列数,也就是关节数),所以零化度 \(= 7 - 6 = 1\)。这 1 维自由就是“手不动,肘在动”的自运动。
    3. 你对点云先做 \(B\)(缩放),再做 \(A\)(剪切)。要把点云恢复原状,应该用哪个矩阵?
    做过的是 \(AB\)(右边的先作用)。要撤销,先撤销最后做的 \(A\),再撤销 \(B\):\(B^{-1}\) 在 \(A^{-1}\) 的左边,\(B^{-1}A^{-1}\)。检验:\(B^{-1}A^{-1}AB = B^{-1}B = I\)。
    4. 还是 \(A = \begin{bmatrix}1&2\\2&4\end{bmatrix}\),方程 \(A\mathbf x = (3, 5)\) 有几个解?
    列空间是 \((1,2)\) 方向的直线,输出只能是 \((t, 2t)\)。\((3,5)\) 不在这条线上(\(3\) 的两倍是 \(6\) 而不是 \(5\)),所以无解。如果换成 \(\mathbf b = (3,6)\),则有一整条直线的解,见上一节的例子。
    5. 你要在代码里反复解 \(A\mathbf x = \mathbf b\),\(A\) 是一个 \(50\times50\) 的良态方阵。最合适的做法是?
    直接分解后回代,更快也更准;1/det 公式在高维里运算量爆炸,且数值上很差。显式求逆只有在真的需要 \(A^{-1}\) 的元素时才值得。

    10延伸阅读

    • 3Blue1Brown, Essence of Linear Algebra — 第 7 章(逆矩阵、列空间与零空间)
    • G. Strang, Introduction to Linear Algebra, Ch. 3 — 向量空间与子空间(列空间、零空间、秩与解 Ax = b);逆矩阵见 §2.5
    • K. Lynch & F. Park, Modern Robotics, §6.2–6.3 — 数值逆运动学与冗余机械臂的速度求解
    • B. Siciliano, L. Sciavicco, L. Villani, G. Oriolo, Robotics: Modelling, Planning and Control, Ch. 3 — 微分运动学,其中讲冗余分析与零空间投影(约 §3.4–3.5)