
1. 为什么 Jordan 块的“个数”和“阶数”值得单独拿出来讲很多人第一次接触Jordan 标准形记住的是那句结论任意复方阵都相似于一个 Jordan 形矩阵。但真正做题、做工程计算、写代码的时候卡住人的往往不是这个结论而是一个更细的问题——给定矩阵里某个特征值到底对应几个 Jordan 块每个块又是几阶的这个问题的分量其实很重。举个工程场景解线性常微分方程组 dx/dt Ax解里会出现 t^k e^{λt} 这种项其中的 k 直接由 λ 对应的最大 Jordan 块阶数决定再比如算矩阵幂 A^n 或者矩阵函数 f(A)收敛性和增长阶也依赖块结构。如果只知道特征值和代数重数你连解里会不会冒出 t 的一次项都判断不了。我带过几轮习题课发现学生的典型错误高度集中把几何重数当成 Jordan 块总数之后就收手以为万事大吉或者把最小多项式里 (x-λ) 的重数误当成某种“块数”。这两种理解都只抓住了问题的一半。代数重数 m 告诉你这个特征值“占多大地方”几何重数 s 告诉你“分成几块”但“每块多大”这个信息两者联手都给不出来。真正能把结构钉死的是一个看起来很朴素的量rank((A-λI)^j) 随 j 的变化序列。只要把这个序列算出来块的阶数和个数就是一次简单差分的产物几乎不需要动脑子。下面我按“为什么这样想—公式怎么来—手算怎么做—代码怎么验—坑在哪”的顺序把这套东西完整拆一遍配合两个能直接抄的例子和一个可运行的 Python 脚本。无论你是正在备考、还是要在程序里自动判定块结构看完都能直接上手。2. 把问题拆开决定 Jordan 块结构的三个层次2.1 代数重数 m 能告诉你什么不能告诉你什么特征多项式 det(xI - A) 在复数域上一定能分解成det(xI - A) (x - λ₁)^{m₁} (x - λ₂)^{m₂} … (x - λ_t)^{m_t}指数 mᵢ 就是 λᵢ 的代数重数含义是“λᵢ 这个特征值一共占据多少个计数单位”同时它等于所有属于 λᵢ 的 Jordan 块的阶数之和。这句话很关键m Σ (λ 对应各 Jordan 块的阶数)也就是说如果 λ 对应两个块一个 3 阶一个 1 阶那 m 4如果是两个 2 阶块m 还是 4。代数重数只约束总和不约束分配方式。这就是为什么单靠特征多项式永远定不出结构同样是 m 4可能的分配有 4、31、22、211、1111一共五种每一种对应完全不同的矩阵。顺带说一句代数重数还有一个等价刻画它是 λ 的“广义特征子空间” N((A-λI)^k) 在 k 足够大时的维数。这个刻画后面会反复用到因为它把 m 和“幂次核空间”直接绑在了一起而不是只挂在特征多项式上。2.2 几何重数 s 给出块的“总个数”但只到这一步几何重数是特征空间的维数s dim ker(A - λI) n - rank(A - λI)它的物理意义非常直白属于 λ 的线性无关特征向量有几个。而每一个 Jordan 块在“最顶端”恰好贡献一个特征向量块与块之间不会共享特征向量于是s λ 对应的 Jordan 块个数这个结论是“个数”这一半问题的答案。但麻烦在于几何重数只数“有几条链”不告诉你“每条链有多长”。回到刚才 m 4 的例子s 2 时可能是 3 阶加 1 阶也可能是两个 2 阶。两种情况的 Jordan 标准形长得完全不一样一个最小多项式是 (x-λ)³另一个是 (x-λ)²解微分方程时一个会出现 t²e^{λt}另一个最高只到 te^{λt}。差别是实质性的。所以真实流程一定是先用特征多项式定 m再用一次求秩定 s也就是块数如果发现 s m说明存在高阶块此时必须再往下算一层。往下算什么就是下一节的主角。2.3 真正的主角d_j dim ker((A - λI)^j)定义d_j dim ker((A - λI)^j)j 0, 1, 2, …约定 d₀ 0。这个序列有几个一眼可见的性质全部来自“幂次核空间随幂次单调膨胀”这一事实N(B) ⊆ N(B²) ⊆ N(B³) ⊆ …其中 B A - λI。所以 d₀ ≤ d₁ ≤ d₂ ≤ …而且一旦不再增长后面就永远不变了因为稳定之后 ker(B^{j1}) ker(B^j)。这个序列的妙处在于它把“块的长度分布”编码成了一串单调不减的整数。你可以把它想成一段阶梯每上一级台阶就说明有若干条链“长到了这个高度”。最终 d_∞ 就等于代数重数 m因为幂零部分在广义特征子空间上最终会彻底归零。用秩写会更方便数值计算d_j n - rank((A - λI)^j)算秩比算零空间维数稳定得多尤其在有浮点误差的时候。下面所有公式我都同时给出 d 版本和 rank 版本你喜欢哪个用哪个。3. 从 d_j 序列读出块结构的完整推导3.1 先看单个 Jordan 块J_k(0)^j 的秩是 k - j拿单个 k 阶幂零 Jordan 块 J_k(0) 开刀。它的结构是次对角线上一排 1其余全 0。它的 j 次幂就是把那排 1 整体“上移”j 格当 j k 时J_k(0)^j 恰好有 k - j 个 1且位置互不冲突所以rank(J_k(0)^j) k - jj k 0j ≥ k对应的核空间维数是d_j k - (k - j) jj k kj ≥ k也就是 d_j min(j, k)。这个式子非常干净一个 k 阶块它的核维数序列就是 0, 1, 2, …, k, k, k, …前 k 步每步涨 1第 k 步之后彻底躺平。换个说法d_j - d_{j-1} 1 恰好成立 j 1, 2, …, k 这 k 次之后就一直是 0。也就是说“d 序列每涨一格就代表有一条链达到了这个高度”。顺便解释一下为什么上面的推导对一般特征值 λ 也成立因为 A - λI 作用在 λ 的广义特征子空间上就是幂零的把它限制在这个子空间上就是一个幂零矩阵。至于 λ 之外的特征子空间B 在其上是可逆的核维数贡献为 0。所以下面所有讨论都可以“先按 λ 切开再在各自子空间内讨论”互不干扰。3.2 直和叠加d_j Σ min(j, k_i)现在有多个块。关键事实是幂次核空间的维数在直和下是可加的。原因是 B^j 作用在整个空间上把不同特征值的广义特征子空间互相映到自身而在 λ 自己的子空间内如果它分解成若干 Jordan 块那么 B^j 就是各个块幂的直和核空间维数直接相加。于是设 λ 对应的块阶数为 k₁, k₂, …, k_s共 s 个得到d_j Σ_{i1}^{s} min(j, k_i)这一个公式就是全部理论的源头。两边做差分d_j - d_{j-1} Σ_i [min(j, k_i) - min(j-1, k_i)] Σ_i 1_{k_i ≥ j}其中 1_{·} 是示性函数。所以d_j - d_{j-1} 阶数 ≥ j 的 Jordan 块个数用大白话翻译d 序列在第 j 步涨了多少就等于“长度至少为 j 的链有几条”。这就是那把钥匙。有了它剩下的都是记账。3.3 两条等价公式一阶差分定“至少 j 阶”二阶差分定“恰好 j 阶”从上面的关系立刻得到两组实用公式。第一组定义“阶数至少为 j 的块数”A_j : d_j - d_{j-1} rank((A-λI)^{j-1}) - rank((A-λI)^j)序列 A₁ ≥ A₂ ≥ A₃ ≥ … 单调不增因为条件“k_i ≥ j”随着 j 增大只会越来越苛刻。而且 A₁ 就是几何重数 s。第二组我们要的是“恰好等于 j 阶”的块数记为 N_j。显然N_j A_j - A_{j1} (d_j - d_{j-1}) - (d_{j1} - d_j) 2d_j - d_{j-1} - d_{j1}换成秩版本N_j rank((A-λI)^{j-1}) - 2·rank((A-λI)^j) rank((A-λI)^{j1})这条公式我习惯叫它“二阶差分公式”因为右边就是秩序列的离散二阶导数取负号。它的几何解释也很直观块长分布就是秩随幂次下降速度的“减速”位置——每减速一次就说明有一条链到头了。两个现成的校验条件做题时强烈建议逐条对一遍能拦住绝大多数计算失误Σ_j N_j s 几何重数块的总数对Σ_j j·N_j m 代数重数阶数加权和对如果这两个和不等于预期值别急着往下算先回头检查哪一步秩算错了。3.4 最大块阶数与最小多项式的关系还有一个特别容易和“块数”搞混的量最大块阶数。它是满足 d_k m 的最小 k也就是序列彻底躺平的位置通常叫 λ 处的幂零指数。它等于最小多项式中 (x - λ) 的幂次m_A(x) Π_i (x - λ_i)^{k_max,i}所以想快速判断“最大块几阶”只要看最小多项式的重根重数就行不需要算全部秩。但要注意最大块阶数只是分布中的最大值它一个数替代不了整个分布。比如 J₃ ⊕ J₁ 和 J₃ ⊕ J₃ ⊕ J₁ 的最大块阶数都是 3但块的个数一个 2 一个 3代数重数一个 4 一个 7。所以“看最小多项式”是快速估算不是完整答案。顺带一个常见结论A 可对角化 ⟺ 每个特征值的几何重数等于代数重数 ⟺ 所有 Jordan 块都是 1 阶 ⟺ 最小多项式没有重根。这四个说法完全等价串在一起记效率最高。4. 手算实战从矩阵出发一步步把块结构钉死4.1 第一步定特征值与代数重数拿一个 3 阶上三角矩阵当靶子A [[3, 1, -1], [0, 2, 1], [0, 0, 2]]上三角矩阵的特征值就在对角线上λ 3重数 1λ 2重数 2。于是 m(3) 1m(2) 2。这里要提醒一句只有三角矩阵和已知谱的矩阵能这样直接读一般矩阵老老实实算 det(xI - A) 然后用因式分解或数值求根。对 λ 3代数重数 1意味着它只能对应一个 1 阶块没有第二种可能所以结构直接定为 J₁(3)不用再算秩。这也是一个省时间的经验代数重数为 1 的特征值不需要任何进一步分析。真正要花功夫的是 λ 2m 2。可能的分配只有两种一个 2 阶块或者两个 1 阶块。接下来一步就能区分。4.2 第二步逐次求秩把 d 和 rank 序列都列出来先算 B A - 2IB [[1, 1, -1], [0, 0, 1], [0, 0, 0]]三行里第一行 (1,1,-1)、第二行 (0,0,1) 显然不共线第三行是零行所以 rank(B) 2d₁ 3 - 2 1。这一步已经给出结论λ 2 只有1 个Jordan 块。因为代数重数是 2 而块数只有 1那这个块必然是 2 阶的问题其实已经解决。但为了把流程完整演示一遍也为了展示公式怎么用继续算 B²B² [[1, 1, 0], [0, 0, 0], [0, 0, 0]]只有第一行非零rank(B²) 1d₂ 3 - 1 2。再算 B³ B²·B还是 [[1,1,0],[0,0,0],[0,0,0]]rank 1d₃ 2。此后不再变化。整理成表jrank(B^j)d_j 3 - rankd_j - d_{j-1}含义030—起点1211阶数 ≥ 1 的块数 12121阶数 ≥ 2 的块数 13120阶数 ≥ 3 的块数 04.3 第三步套公式算 N_j并做两道校验用 N_j 2d_j - d_{j-1} - d_{j1}N₁ 2×1 - 0 - 2 0N₂ 2×2 - 1 - 2 1N₃ 2×2 - 2 - 2 0所以 λ 2 对应一个 2 阶块没有 1 阶块。合并 λ 3 的结果整个矩阵的 Jordan 标准形是J diag( J₁(3), J₂(2) ) [[3, 0, 0], [0, 2, 1], [0, 0, 2]]校验一下Σ N 1 1 2 几何重数之和Σ jN 1×1 2×1 3 n。都过。顺便说一个替代做法既然已经知道 s 1 而 m 2其实直接用“最大块阶数 min{k : d_k m}”就够了d₁ 1 2d₂ 2 m所以最大块阶数是 2块数又只有 1结论自然唯一。这说明当 s 和 m 的差距很小时不需要把全部 N_j 都算出来抓住最大块阶数和块数两个量就能反推结构。4.4 完整 Python 实现精确版和数值版都给你手工算小矩阵没问题真到 10 阶以上就得上代码。下面是精确版用 sympy 的秩适合验证习题答案import sympy as sp def jordan_structure_exact(A, lam): n A.shape[0] B A - lam * sp.eye(n) M sp.eye(n) d [0] while True: M M * B nullity n - M.rank() if nullity d[-1]: # 序列稳定停 break d.append(nullity) # d[j] dim ker B^j用二阶差分求各阶块数 N {} for k in range(1, len(d) - 1): cnt 2 * d[k] - d[k - 1] - d[k 1] if cnt 0: N[k] cnt return d, N A sp.Matrix([[3, 1, -1], [0, 2, 1], [0, 0, 2]]) print(jordan_structure_exact(A, sp.Integer(2))) # 输出d [0, 1, 2, 2]N {2: 1}数值版要处理浮点秩判定这里用奇异值的相对阈值比直接比大小靠谱import numpy as np def jordan_structure_num(A, lam, rel_tol1e-9): n A.shape[0] B A - lam * np.eye(n) M np.eye(n) d [0] while True: M M B s np.linalg.svd(M, compute_uvFalse) tol rel_tol * max(s[0], 1.0) # 相对阈值 rank int(np.sum(s tol)) nullity n - rank if nullity d[-1]: break d.append(nullity) N {} for k in range(1, len(d) - 1): cnt 2 * d[k] - d[k - 1] - d[k 1] if cnt 0: N[k] cnt return d, N A np.array([[3., 1., -1.], [0., 2., 1.], [0., 0., 2.]]) print(jordan_structure_num(A, 2.0)) # 输出d [0, 1, 2, 2]N {2: 1}注意数值版里rel_tol不能设得太小。矩阵幂次一高B^k 的元素会迅速衰减甚至溢出用绝对阈值判定几乎必然出错。用“相对最大奇异值”的阈值是工程上的常规做法。5. 一个帮你区分“同 m 同 s”两种结构的判别例子理论讲完了来一个专门用来打脸的对比。假设 n 4某个 λ 的代数重数 m 4你算出几何重数 s 2。此时有两种可能J₃ ⊕ J₁ 或者 J₂ ⊕ J₂。两者的 d₁ 都是 2光靠前两步区分不了必须往下一步看。算 d₂ dim ker(B²)若是 J₃ ⊕ J₁J₃ 贡献 min(2,3) 2J₁ 贡献 min(2,1) 1合计 d₂ 3。若是 J₂ ⊕ J₂两个块各贡献 min(2,2) 2合计 d₂ 4。差别就出来了d₂ 3 对应 31d₂ 4 对应 22。继续算 d₃ 可以进一步区分 31 和更高阶的情况但在这里已经足够了。对应的秩序列也顺手列一下方便你对着表读数情形rank(B)rank(B²)rank(B³)d₁d₂d₃J₃ ⊕ J₁211234J₂ ⊕ J₂200244再给一个更完整的抽象例子练手。某 6 阶矩阵在 λ 处满足 rank(B) 4rank(B²) 2rank(B³) 1rank(B⁴) 0rank(B⁵) 0。那么 d [0, 2, 4, 5, 6, 6]。逐层差分d₁ - d₀ 2 → 2 个块d₂ - d₁ 2 → 阶数 ≥ 2 的块 2 个d₃ - d₂ 1 → 阶数 ≥ 3 的块 1 个d₄ - d₃ 1 → 阶数 ≥ 4 的块 1 个d₅ - d₄ 0 → 没有更高阶的块于是 N₁ 2 - 2 0N₂ 2 - 1 1N₃ 1 - 1 0N₄ 1 - 0 1。结构是 J₄(λ) ⊕ J₂(λ)。校验块数 2 d₁总阶数 4 2 6 n。都吻合。注意这个例子里 rank(B³) 1 和 rank(B⁴) 0 这两步很容易抄错一位一旦错一位N₃ 就会虚报成 1整个结构就崩了。6. 常见坑与排查技巧实录6.1 坑一把几何重数当成块的总数就收工这是出现频率最高的错误前面已经反复强调。判断标准很简单只要 s m就一定有高阶块必须继续求 rank(B²)。我一般建议的流程是固定的三步——定 m、定 s、未确定则继续求幂次秩——照着走不会漏。6.2 坑二数值计算里秩判定失准浮点环境下 rank(B) 的判定太依赖阈值。B 的特征值里如果本来就有接近零的说明 λ 只是近似特征值B 几乎是奇异的奇异值会呈现“一小撮接近 1e-3、另一小撮接近 1e-12”的分布这时候阈值放哪儿都别扭。处理办法有两个。一是先把特征值精修一遍用 2×2 或 3×3 的幂零结构做牛顿迭代把 λ 收敛到机器精度再算 B 的秩。二是改用符号计算或高精度比如 sympy 或 mpmath教学和验证场景下这是最省心的。若矩阵是精确整数矩阵sympy 的rank()会给出严格答案不用纠结阈值。还有一个实用技巧不要直接累乘 B^k而是每次做一次秩判定后保留矩阵并用np.linalg.svd的相对阈值。累乘会让数值误差累积放大到第 4、5 次幂时误差已经能污染秩判定。6.3 坑三代数重数算错导致满盘皆输如果特征多项式没分解对后面算出来的 d 序列永远对不上 mΣ N 和 Σ jN 两道校验会立刻报警。所以我把这两道校验放在流程里强制检查。一旦 Σ jN ≠ m九成是 m 错了剩下一成是秩算错。养成本能见到数字不匹配就回头查比盲算下去效率高得多。6.4 坑四对复特征值的处理实矩阵的特征值可能是复的这时 Jordan 块成共轭对出现。注意复特征值的代数重数要按复重数算不要强行在实数域上讨论标准形——实数域上并不总有 Jordan 标准形只能得到实 Jordan 形把共轭的两个块拼成一个实块。编程时 A 直接转成复数类型秩判定用复数奇异值逻辑完全一样。6.5 排查速查表现象可能原因处理办法Σ N_j 几何重数秩序列抄错一位重新逐次求秩检查 d_j 单调性Σ j·N_j ≠ 代数重数特征多项式分解有误重算 det(xI - A) 并分解d_j 序列非单调计算或代码错误d_j 必须单调不减这是硬约束数值秩反复跳动阈值不合理或 λ 不精确精修特征值改用相对阈值或高精度程序死循环不退出退出条件写错退出条件应为 d 序列不再增长6.6 几个能省时间的经验技巧第一先处理代数重数为 1 的特征值它们直接就是 1 阶块不占计算量。第二对每个 λ 独立计算不同特征值之间的秩互不影响可以并行。第三一旦 d_j 达到 m立刻停止该特征值的计算不必继续求更高次幂。第四如果只是想知道最大块阶数直接算最小多项式更快只有需要完整的块分布时才值得把秩序列全部算出来。第五编程时用“幂次 秩 核维数 差分”四列一起打表输出人眼扫一遍就能发现问题比只看最终结果可靠得多。7. 换一个视角初等因子和行列式因子怎么和这套方法对上如果你翻过更偏代数的教材会发现另一套语言——不变因子、初等因子、行列式因子。它们和这里的秩方法是同一件事的两种说法理解二者的对应关系做题时会多一条退路。思路是这样的设 D_k(x) 为矩阵 xI - A 的所有 k 阶子式的最大公因式叫 k 阶行列式因子规定 D₀ 1。再令 d_k(x) D_k(x) / D_{k-1}(x)称为不变因子。这些不变因子满足整除链 d₁ | d₂ | … | d_n且乘积为特征多项式。把每个不变因子在复数域上彻底分解得到的那些形如 (x - λ)^e 的因子就叫初等因子。关键结论是初等因子和 Jordan 块一一对应一个 (x - λ)^e 就对应一个 e 阶的 Jordan 块。所以“λ 对应几个块、各几阶”在这套语言里就是“在 xI - A 的初等因子里(x - λ) 出现了几次、每次的指数是多少”。指数组合就是块阶数的多重集。举个小例子核对一下。若特征多项式是 (x-2)⁴不变因子是 d₃ (x-2)²d₄ (x-2)²那么初等因子是两个 (x-2)²对应 J₂(2) ⊕ J₂(2)。用秩方法检验B A - 2Id₁ 2d₂ 4d₃ 4N₂ 2×4 - 2 - 4 2其余为 0。完全一致。两种方法的取舍很清楚初等因子在理论上更完整能一次性给出全部信息包括相似判定的充要条件——两个矩阵相似当且仅当它们的初等因子完全相同但手工计算量大要算一堆子式的最大公因式秩方法计算量小、适合编程和手算但要一个特征值一个特征值地处理。我的习惯是用秩方法做实际计算用初等因子做理论证明和结果核对两条腿走路最稳。最后补一句关于应用的话。Jordan 块的阶数分布之所以重要是因为它决定了矩阵幂 A^k 的增长行为和幂零部分的作用深度。工程上做线性系统分析时如果发现某个特征值的最大块阶数达到 3就意味着解里会出现 t² 量级的项做数值离散时必须加密时间步否则精度会崩。这也是我一直坚持把 d 序列算完整、而不是只记个结论的原因——分布里藏着的正是这些实际影响。我个人在写教学脚本时的体会是把秩序列和差分序列并排打印出来比只输出最终的 N 字典有用得多。前者能让你看到“推理过程”后者只是一行结果一旦不对光看结果根本不知道错在哪一步。要是你想再往下扩展可以试着把这段逻辑接到符号计算上对含参数 a 的矩阵做块结构分类看参数取什么值时结构发生跃变——那正好是工程里最需要小心的临界点。