跳到正文
格致开物MATHWIKI

幂法

幂法(power method)反复用矩阵乘一个向量并归一化,以提取模最大的特征值方向。它不需要完整矩阵分解,适合能够快速计算矩阵向量积的大型问题。成功的关键是主特征值的模严格占优,以及初始向量确实含有该方向的分量。

同一矩阵连续放大一个方向

取 A=(2112)、x0=(1,0)T。乘一次得到 (2,1)T,用最大分量归一化为 x1=(1,1/2)T;下一次得到 (5/2,2)T,归一化为 x2=(1,4/5)T;再一次为 x3=(1,13/14)T。方向逐渐接近 (1,1)T。

这个矩阵沿 (1,1)T 放大三倍,沿 (1,−1)T 只放大一倍。初始向量恰好是两个方向各一半,因此 Akx0=12(3k+13k−1),xk=(1(3k−1)/(3k+1)). 归一化避免数值随 3k 增长,却保留方向的相对比例。

幂法归一化向量从横轴方向逐渐转向对角线特征方向
按最大分量归一化后第一坐标恒为一,第二坐标逐步趋于一。图展示方向变化,而不是向量长度的指数增长。

模占优条件的收敛证明

设矩阵可对角化,特征向量为 v1,…,vn,特征值按模排序满足 |λ1|>|λ2|≥⋯。将初始向量写成 x0=∑icivi,并要求 c1≠0。则 Akx0=λ1kc1[v1+∑i=2ncic1(λiλ1)kvi]. 所有括号内的次要分量都以模小于一的比值衰减,因此归一化方向收敛到 v1,渐近方向误差主要由 |λ2/λ1|k 控制。主特征值为负时向量可能每轮变号,所以应比较方向或残差,不能要求带符号向量本身收敛。

可对角化假设使上式直接成立。含 Jordan 块的矩阵可能多出多项式因子,非正规矩阵也可能出现很长的暂态;不能只按两个特征值的比值预报从第一轮起的误差。幂法、逆迭代与正交迭代的关系可参见 FNC 的特征值迭代章节。[1]

特征值估计与残差验收

非零向量的 Rayleigh 商为 μ(x)=xTAx/(xTx)。在实对称情形,将单位向量写成 x=cos⁡θv1+sin⁡θw,其中 w⊥v1、‖w‖=1,交叉项消失,得到 μ(x)−λ1=sin2θ(wTAw−λ1). 因此特征值误差对小方向夹角为二阶;这个结论依赖对称性。主例有精确公式 μ(xk)=3−29k+1, 所以首两轮估计分别为 14/5=2.8、122/41≈2.97560976。

验收还应计算 r=Ax−μx。对单位向量和实对称矩阵,若正交特征展开为 x=∑jcjvj,则 ‖r‖2=∑jcj2(λj−μ)2≥minj|λj−μ|2。所以至少存在一个特征值距 μ 不超过残差范数;这不自动证明该值就是模最大的一个,也不在缺少谱间隔时单独保证特征向量准确。

有解变式把初始向量改成 (1,−1)T。它与主方向正交,所有迭代都停留在特征值一的方向,得到的是正确的次特征对。另一个反例是平面九十度旋转矩阵,两个复特征值模相同,实向量不断旋转,不会选择一个实主方向。二者分别说明初始分量和严格模间隔的重要性。

可运行的归一化迭代

代码接受实矩阵和非零初始向量,返回 Rayleigh 商、单位向量和迭代数,不修改输入。它以实际特征对残差停止,并不验证模占优条件;调用者应根据上述条件解释输出。稠密每轮 O(n2),稀疏算子每轮可为 O(nnz⁡(A)),幂迭代的向量工作区为 O(n);下面的教学实现另行复制并缩放稠密矩阵,总额外存储为 O(n2)。

Python 3
import numpy as np


def power_iteration(A, start, tol=1e-12, maxiter=1000):
    A, x = np.array(A, dtype=float, copy=True), np.array(start, dtype=float, copy=True)
    if x.ndim != 1 or not x.size or A.shape != (x.size, x.size):
        raise ValueError("square matrix matching vector required")
    if not np.isfinite(A).all() or not np.isfinite(x).all() or np.max(np.abs(x)) == 0:
        raise ValueError("finite data and nonzero start required")
    if not np.isfinite(tol) or tol <= 0 or not isinstance(maxiter, int) or maxiter < 0:
        raise ValueError("positive tolerance and nonnegative integer limit required")
    x /= np.max(np.abs(x)); x /= np.linalg.norm(x)
    matrix_scale = float(np.max(np.abs(A)))
    C = A/matrix_scale if matrix_scale > 0 else A.copy()
    scale = max(1.0, np.linalg.norm(C))
    threshold = tol*scale
    if not np.isfinite(threshold):
        raise ArithmeticError("nonfinite stopping threshold")
    for k in range(maxiter+1):
        w = C@x; mu_scaled = float(x@w)
        mu = mu_scaled*matrix_scale
        if not np.isfinite(w).all() or not np.isfinite(mu):
            raise ArithmeticError("nonfinite matrix-vector product")
        if np.linalg.norm(w-mu_scaled*x) <= threshold:
            return mu, x, k
        if k == maxiter:
            break
        length = np.linalg.norm(w)
        if length == 0 or not np.isfinite(length):
            raise ArithmeticError("cannot normalize next iterate")
        x = w/length
    raise RuntimeError("eigenpair residual did not reach tolerance")


print(power_iteration([[2, 1], [1, 2]], [1, 0])[:1])  # near (3.0,)
print(power_iteration([[2, 1], [1, 2]], [1, -1])[:1]) # (1.0,), a different invariant direction

若要查找靠近指定数值的特征值,可以使用逆幂法;同时追踪多个方向则需要子空间迭代或 Arnoldi、Lanczos 方法。它们改变搜索空间或算子,不能仅靠多运行几次同一随机初值幂法替代完整的特征值算法。

参考资料

  1. ↑ Tobin A. Driscoll, Richard J. Braun. Fundamentals of Numerical Computation: Power iteration。