前面几章里,我们一直在讨论如何求解或者近似求解
Ax=b
如果 A 是一个规模不大的矩阵,那么我们可以考虑直接分解它,比如使用 LU decomposition、QR decomposition,或者在最小二乘问题中使用 SVD 和伪逆
但是在很多数值计算问题里,A 可能非常大,而且通常是 sparse matrix
这时直接求
x=A−1b
往往不是一个好主意
第一,显式求逆本身很贵;第二,即使 A 是稀疏矩阵,A−1 通常也会变成稠密矩阵;第三,我们很多时候并不真的需要整个 A−1,而只需要它作用在当前右端项 b 上的结果
也就是说,我们真正想要的是
A−1b
而不是完整的矩阵 A−1
Krylov subspace method 的核心思想就是:不直接构造 A−1,而是用矩阵-向量乘法和一个低维优化问题,隐式构造出 A−1b 的近似
Av
这里矩阵-向量乘法 Av 很关键,因为对于稀疏矩阵来说,它通常比矩阵分解或者显式求逆便宜得多
为了看清楚这种方法为什么可能成立,最好先从一个理想化的谱分解视角开始
从多项式逼近逆矩阵开始
先假设 A 是可对角化的,也就是
A=VΛV−1
其中
Λ=diag(λ1,λ2,…,λn)
先看为什么逆矩阵会对应特征值的倒数。若
Avi=λivi
并且 λi=0,那么两边同时左乘 A−1,得到
A−1Avivi=A−1(λivi)=λiA−1vi
所以
A−1vi=λi1vi
也就是说,A 在方向 vi 上放大 λi 倍,而 A−1 在同一个方向上就要做相反的事情,也就是缩放 1/λi 倍
因此如果 A 可对角化,且所有 λi=0,就有
A−1=VΛ−1V−1
其中
Λ−1=diag(λ11,λ21,…,λn1)
现在我们想做的事情是:不用真的构造 A−1,而是找一个更容易计算的对象来扮演它
一种自然的想法是构造某个 矩阵函数 matrix function
f(A)
希望它能够近似
A−1
这里说的矩阵函数,不是指输入一个矩阵然后输出一个 子空间,而是指输入一个矩阵,输出另一个矩阵
例如对于标量函数
f(t)=t2+3t+1
输入一个数 t 会输出一个数;对应地,把矩阵 A 代进去,就得到矩阵函数
f(A)=A2+3A+I
它输入的是矩阵 A,输出的仍然是一个矩阵
如果我们想让某个矩阵函数 f(A) 像 A−1,最自然的一类候选就是 多项式矩阵函数
p(t)=c0+c1t+c2t2+⋯+cktk
把矩阵 A 代入这个多项式,得到
p(A)=c0I+c1A+c2A2+⋯+ckAk
先看它对单个特征方向的作用。因为
Avi=λivi
而对于 多项式 的每一项,实际上就是反复作用 A ,我们知道这在 特征向量 方向上会得到
Akvi=λikvi
于是
p(A)vi=(c0I+c1A+c2A2+⋯+ckAk)vi=(c0+c1λi+c2λi2+⋯+ckλik)vi=p(λi)vi
也就是说,p(A) 在特征方向 vi 上的作用,就是把这个方向缩放 p(λi) 倍
如果我们让
p(λi)≈λi
那么 p(A) 在每个特征方向上的缩放就接近 A,于是可以认为 p(A) 也逼近 A
p(A)≈A
因为如果一个多项式在所有相关特征值上都给出和 A 一样的缩放,那么它就在这些特征方向上表达了和 A 一样的变换
当然,这件事本身没有太大意义,因为 A 已经在手里了
真正有用的是:如果我们想逼近的不是 A,而是 A−1,那么就要看 A−1 在同一个特征方向上做了什么
前面已经知道
A−1vi=λi1vi
所以如果希望 p(A) 像 A−1,就应该让
p(λi)≈λi1
把这件事写成完整的矩阵形式时,要先说明为什么可以把多项式直接作用到 Λ 上
由于
A=VΛV−1
所以 A 的平方是
A2=(VΛV−1)(VΛV−1)=VΛ(V−1V)ΛV−1=VΛ2V−1
同理,反复相乘会得到
Am=VΛmV−1
于是把 A 代入多项式
p(A)=c0I+c1A+c2A2+⋯+ckAk
就有
p(A)=c0I+c1VΛV−1+c2VΛ2V−1+⋯+ckVΛkV−1=V(c0I+c1Λ+c2Λ2+⋯+ckΛk)V−1=Vp(Λ)V−1
所以
p(A)=Vp(Λ)V−1
其中 p(Λ) 只是把多项式逐个作用到特征值上
p(Λ)=p(λ1)0⋮00p(λ2)⋮0⋯⋯⋱⋯00⋮p(λn)
如果把每个 p(λi) 展开,就是
p(Λ)=c0+c1λ1+⋯+ckλ1k0⋮00c0+c1λ2+⋯+ckλ2k⋮0⋯⋯⋱⋯00⋮c0+c1λn+⋯+ckλnk
而逆矩阵对应的是
Λ−1=λ110⋮00λ21⋮0⋯⋯⋱⋯00⋮λn1
所以如果想让
p(A)=Vp(Λ)V−1
逼近
A−1=VΛ−1V−1
就需要让每一个对角位置上的多项式值都逼近对应特征值的倒数
c0+c1λ1+⋯+ckλ1kc0+c1λ2+⋯+ckλ2kc0+c1λn+⋯+ckλnk≈λ11≈λ21⋮≈λn1
注意这里不是对每个 λi 分别选择一组新的系数,而是同一组
c0,c1,…,ck
必须同时让这个多项式在所有相关特征值上逼近倒数函数。也就是说,我们是在用一个多项式 p(t) 同时拟合这些点
(λi,λi1)
如果真的能做到这一点,那么由同一组系数 c0,c1,…,ck 构造出来的多项式矩阵函数
p(A)=c0I+c1A+⋯+ckAk
就会在所有这些特征方向上模拟 A−1 的作用,因此可以认为
p(A)≈A−1
这就是 Krylov 方法背后的第一个直觉:
如果一个多项式在 A 的特征值上像倒数函数 1/t,那么把 A 代入这个多项式,就会像 A−1
严格来说,只有当
p(λi)=λi1
对所有相关特征值都成立时,才有
p(A)=A−1
但实际计算里,我们通常不需要完整恢复 A−1,而只是想求当前这个线性系统的解
x=A−1b
所以更现实的目标是
p(A)b≈A−1b
这一点很重要,因为它说明 Krylov 方法通常是在近似 A−1 对当前 b 的作用,而不是显式构造整个逆矩阵
换句话说,如果想让 p(A) 对所有可能的右端项都像 A−1,那就必须在所有相关特征方向上都逼近得很好;但如果只要求当前这个 b 成立,那么主要需要照顾的是 b 分量较大的那些特征方向
多项式逼近倒数函数
接下来还有一个自然问题:为什么可以指望一个多项式去逼近倒数函数?
原因是 1/t 虽然不是多项式,但只要讨论的区域远离 0,它就是一个光滑函数。光滑函数在有限区间上通常可以被多项式很好地近似
例如在 t=1 附近,可以写成
t1=1+(t−1)1
如果令
s=t−1
接下来使用几何级数公式
1−r1=1+r+r2+r3+⋯,∣r∣<1
由于
1+s1=1−(−s)1
相当于令 r=−s,所以
t1=1+s1=1−s+s2−s3+⋯
把 s=t−1 代回去,就得到一个关于 t 的多项式级数
t1=1−(t−1)+(t−1)2−(t−1)3+⋯
取前有限项,就是一个多项式近似
当然,这个直觉有一个关键限制:特征值不能太靠近 0。如果某些 λi 很接近 0,那么 1/λi 会非常大,低阶多项式就很难稳定逼近它。这也正是病态矩阵难求解的原因之一
当前右端项决定哪些方向重要
继续使用可对角化的直觉。若 Avi=λivi,并且把右端项展开为
b=i∑αivi
即将 b 表示在 vi 这组基向量上,αi 是在这组基上的 坐标
那么真实解是
A−1b=i∑λiαivi
而多项式近似给出的是
p(A)b=i∑αip(λi)vi
于是误差为
A−1b−p(A)b=i∑αi(λi1−p(λi))vi
这说明:并不是所有特征值都同等重要
如果 b 在某个特征方向上的系数 αi 很小,那么即使 p(λi) 没有很好逼近 1/λi,它对当前解的影响也可能很小
所以实际 Krylov 方法更准确地说,是为当前输入 b 找一个合适的低阶多项式,而不是为所有可能的右端项一次性构造完整的 A−1
为什么不显式做特征值插值
从上面的讨论看,如果能知道所有特征值 λi,似乎可以直接构造插值多项式,让
p(λi)=λi1
然后得到 p(A)≈A−1
但这在大型问题里通常不可行
第一,显式求出全部特征值和特征向量本身就很贵,往往已经接近直接求解问题的代价
第二,即使原矩阵 A 是稀疏的,完整的 A−1 通常也是稠密的,显式构造它会带来很大的计算和存储代价
第三,我们多数时候只需要当前这个 b 对应的解 A−1b,并不需要得到能处理所有右端项的完整逆矩阵
所以 Krylov 方法换了一种做法:不显式求特征值,也不显式构造 A−1,而是只通过反复计算
Ab,A2b,A3b,…
隐式地寻找一个好的多项式 p(A)
这就是 Krylov 子空间出现的地方
Krylov 子空间
前面说过,我们希望用一个低阶多项式矩阵函数
pj−1(A)=c0I+c1A+⋯+cj−1Aj−1
去近似 A−1 对 b 的作用。把它作用到 b 上,就得到
pj−1(A)b=(c0I+c1A+⋯+cj−1Aj−1)b=c0b+c1Ab+⋯+cj−1Aj−1b
因此任何形如 pj−1(A)b 的向量,一定都落在下面这些向量张成的空间里
第 j 阶 Krylov 子空间定义为
Kj(A,b)=span{b,Ab,A2b,…,Aj−1b}
这个空间里的任意向量都可以写成
xj=c0b+c1Ab+c2A2b+⋯+cj−1Aj−1b=pj−1(A)b
其中
pj−1(t)=c0+c1t+c2t2+⋯+cj−1tj−1
所以“在 Krylov 子空间里找近似解”,本质上就是“在所有次数不超过 j−1 的多项式里,找一个最适合当前 b 的多项式”
换句话说,Krylov 方法不是显式求特征值再插值,而是通过
b,Ab,A2b,…
这些矩阵-向量乘法,隐式生成一族候选多项式近似
上面的讨论默认了初始解是 x0=0,所以我们直接用 pj−1(A)b 去近似 A−1b
但在实际迭代方法里,我们经常已经有一个当前近似解 x0。这时新的问题不是“从零开始找整个解”,而是“在 x0 的基础上再补一个修正量”
所以接下来要把
b
换成当前还没有被解释掉的那部分,也就是初始 residual
从 b 推广到一般初始解
如果初始解不是 0,而是某个已有近似解 x0,那么我们不再直接从 b 出发,而是先看当前还差多少
定义初始 residual
r0=b−Ax0
这个式子的含义很直接:当前近似解 x0 经过矩阵 A 作用后,得到的是 Ax0,但我们真正希望得到的是 b,两者之间还差的那一部分就是 r0
如果要把当前近似解 x0 修正成真解,可以设还需要补上的量为
e0
并写成
x∗=x0+e0
把它代回原方程
Ax∗=b
得到
A(x0+e0)Ax0+Ae0Ae0=b=b=b−Ax0=r0
所以真实修正量满足
e0=A−1r0
此时 Krylov 方法要近似的不是 A−1b,而是这个修正量
A−1r0
因此搜索空间变成
Kj(A,r0)=span{r0,Ar0,A2r0,…,Aj−1r0}
当我们选择用 Kj(A,r0) 作为 j 维搜索空间时,候选近似解也就被限制在
xj∈x0+Kj(A,r0)
也就是说,先在 x0 的基础上加一个 Krylov 子空间里的修正量
xj=x0+sj,sj∈Kj(A,r0)
由于 sj 在 Krylov 子空间里,所以它一定可以写成
sj=pj−1(A)r0
这就是 Krylov 方法和多项式之间的关系:
Krylov 子空间里的每一个候选修正量,都是某个低阶多项式 pj−1(A) 作用在初始 residual 上得到的向量
为什么需要 Gram-Schmidt
到这里为止,我们已经把 Krylov 方法理解成了一个多项式搜索问题:候选修正量都来自
pj−1(A)r0
也就是来自
r0,Ar0,A2r0,…
这些向量的线性组合
因此,一个自然想法是直接使用
r0,Ar0,A2r0,…
作为基底
但这样做在数值上很不稳定
这些向量很容易变得接近线性相关。尤其当 A 反复作用以后,某些方向会被不断放大,另一些方向会被压小,最后得到的一组向量可能几乎都指向相近的方向
这会导致两个问题
- 子空间的表示不稳定
- 在这个空间里求系数时会变得病态
所以我们不直接使用原始 Krylov 序列,而是用 Gram-Schmidt 把它们正交化,得到一组正交归一基
q1,q2,…,qj
并记
Qj=[q1,…,qj]
它们满足
Qj⊤Qj=I
同时张成同一个 Krylov 子空间
Kj(A,r0)=span{q1,…,qj}
因此 Gram-Schmidt 的作用并非直接求出解,而是稳定地组织搜索空间
GS 造空间的正交基,优化问题决定在这个空间里的具体位置
Arnoldi 过程
在 Krylov 方法里,对 Krylov 序列做 Gram-Schmidt 正交化的标准过程叫做 Arnoldi iteration
前面已经说明,一般初始解 x0 下的搜索空间从初始 residual 开始:
Kj(A,r0)=span{r0,Ar0,…,Aj−1r0}
所以 Arnoldi 要做的第一件事,就是把这个空间里的第一个方向 r0 变成单位向量。这个长度记作
先令
β=∥r0∥2,q1=βr0
也就是说,q1 和 r0 指向同一个方向,只是长度被归一化成 1
如果 β=0,说明
r0=b−Ax0=0
此时 x0 已经是精确解,不需要继续构造 Krylov 子空间。下面默认 β=0
假设现在已经有了
q1,q2,…,qj
下一步不是把当前近似解 xj 乘以 A,而是把最后一个 Krylov 正交基向量 qj 乘以 A
v=Aqj
然后把 v 对所有已有基向量都做正交化
hij=qi⊤v,i=1,…,j
并更新
v←v−i=1∑jhijqi
注意这里不是只和上一个向量 qj 正交化,而是要和所有已有向量
q1,…,qj
正交化
这样才能保证新的方向同时垂直于整个旧空间
最后令
hj+1,j=∥v∥2
如果 hj+1,j=0,就归一化得到
qj+1=hj+1,jv
所以一轮 Arnoldi 的结构可以概括为
qj×AAqjGS against q1,…,qjqj+1
Arnoldi 过程还会得到一个重要关系
AQj=Qj+1Hj
这个式子其实只是把前面每一步 Gram-Schmidt 正交化的结果,用矩阵形式压缩写在一起
先看单独一列。为了生成下一个 Krylov 基向量,我们从已有的最后一个基向量 qj 出发,先计算
Aqj
然后把它在已有基底
q1,…,qj
上的分量减掉,最后留下一个新的正交方向 qj+1
所以这一整步等价于把 Aqj 写成
Aqj=h1jq1+h2jq2+⋯+hjjqj+hj+1,jqj+1
这里前 j 项是它在旧空间里的投影,而最后一项是新产生的正交方向
同样地,对更早的列也成立。例如
Aq1=h11q1+h21q2
以及
Aq2=h12q1+h22q2+h32q3
可以看出,第 k 列一般满足
Aqk=i=1∑k+1hikqi
也就是说,A 作用在第 k 个基向量上之后,结果仍然落在
span{q1,…,qk+1}
里
现在把这些列并排放在一起。左边变成
A[q1,…,qj]=AQj
右边则变成
[q1,…,qj+1]h11h210⋮0h12h22h32⋮0⋯⋯⋯⋱⋯h1jh2jh3j⋮hj+1,j=Qj+1Hj
于是就得到
AQj=Qj+1Hj
这里 Hj 之所以是 upper Hessenberg matrix,原因也很直接:第 k 列只会用到
q1,…,qk+1
所以在第 k+1 行以下全都是 0
这个关系的意义是:虽然原矩阵 A 可能很大,但它作用在当前 Krylov 正交基上之后,完全可以用一个很小的 upper Hessenberg matrix Hj 来记录这些作用结果在基底中的坐标
这可以理解为:巨大的矩阵 A 被投影到 Krylov 子空间后,变成了小矩阵 Hj
在子空间里求最优系数
有了正交基 Qj 以后,近似解写成
xj=x0+Qjc
这是因为前面已经规定,当我们使用 Kj(A,r0) 作为 j 维搜索空间时,近似解只允许从下面这个仿射空间中选取
x0+Kj(A,r0)
也就是说,任何候选解都必须能写成
xj=x0+sj
其中
sj∈Kj(A,r0)
而现在 Qj=[q1,…,qj] 的列向量正好就是这个 Krylov 子空间的一组正交基,所以子空间里的任意向量都可以写成
sj=c1q1+⋯+cjqj=Qjc
因此
xj=x0+Qjc
这里的 c 并不是原问题中的解,而是“在 Krylov 基底坐标系下,这个近似解位于什么位置”的系数向量
这里 c∈Rj 是一个小向量
原始问题里 x 可能有几百万个分量,但如果我们只使用 Kj 这个 j 维搜索空间,那么 c 只有 j 个分量
所以问题从
在 Rn 中找 x
变成了
在 Rj 中找 c
接下来必须选择最好的 c,而不是构造完 Qj 就自动得到解
从多项式视角看,选择 c 就是在选择这些 Krylov 基向量的线性组合,也就是在当前低维空间里选出最合适的多项式近似
对 GMRES 来说,“最好” 的意思是让 residual 的 2-范数最小
cj=argcmin∥b−A(x0+Qjc)∥2
然后
xj=x0+Qjcj
如果 x0=0,这就变成
cj=argcmin∥b−AQjc∥2
也就是在 Krylov 子空间中寻找残差最小的那个向量
利用 Arnoldi 关系
AQj=Qj+1Hj
这个大问题还可以进一步化成一个小的 least squares 问题
关键点在于:我们虽然仍然在最小化一个很大的 residual 向量,但这个 residual 已经被限制在 Arnoldi 构造出的低维结构里,因此可以把它改写成一个小坐标向量的长度
先从 residual 本身开始。把
xj=x0+Qjc
代回去,就有
b−Axj=b−A(x0+Qjc)=(b−Ax0)−AQjc=r0−AQjc
所以我们真正要最小化的对象,其实就是
r0−AQjc
接下来要做的事情,是把这一项完全改写到 Arnoldi 基底里
因为
r0=βq1=Qj+1(βe1)
这里的 β=∥r0∥2,而
q1=βr0
所以自然有
r0=βq1
另一方面,Qj+1 的第一列就是 q1
Qj+1=[q1,q2,…,qj+1]
而标准基向量
e1=10⋮0
右乘之后只会取出第一列,因此
Qj+1e1=q1
于是
r0=βq1=Qj+1(βe1)
这一步的本质只是:把初始 residual 写成 Arnoldi 基底坐标的形式
所以 residual 可以写成
b−A(x0+Qjc)=r0−AQjc=Qj+1(βe1−Hjc)
其中第二步只是同时用了两件事:
r0=Qj+1(βe1)
以及
AQj=Qj+1Hj
于是整个 residual 被写成
Qj+1(βe1−Hjc)
也就是说,高维空间里的 residual 向量,现在等价地表示成了一个低维坐标向量
βe1−Hjc
由于 Qj+1 的列正交归一,最小化原 residual 等价于最小化
cmin∥βe1−Hjc∥2
原因是:对任意向量 y,只要 Qj+1 的列正交归一,就有
∥Qj+1y∥2=∥y∥2
所以左边那个大 residual 的长度
∥Qj+1(βe1−Hjc)∥2
和右边这个小向量的长度完全相同
∥βe1−Hjc∥2
因此,最小化高维 residual,等价于最小化一个维度只有 j+1 的小 least squares 问题
这就是 GMRES 的核心形式
大的线性系统没有被直接求逆,而是被投影成了一个低维 least squares 问题
子空间维度越大一定越好吗
Krylov 子空间是嵌套的
K1(A,r0)⊂K2(A,r0)⊂K3(A,r0)⊂⋯
因为从 Kj 扩展到 Kj+1,只是向原来的搜索空间里多加入一个方向
Ajr0
所以如果每次扩展子空间后都在当前子空间里做同一种意义下的最优近似,那么理论上的最佳误差不会变差
例如 GMRES 中
xj=argx∈x0+Kjmin∥b−Ax∥2
而
Kj⊂Kj+1
所以在更大的空间 Kj+1 中优化时,至少还可以选择原来 Kj 中的解
因此理论上有
∥b−Axj+1∥2≤∥b−Axj∥2
但是这不意味着每次增加子空间维度都会明显变好
收敛速度取决于很多因素,包括
- A 的特征值分布
- 特征值是否远离 0
- 条件数是否很大
- residual 在不同特征方向上的分量
- 数值正交化误差
- 是否使用了 preconditioner
从多项式逼近角度看,如果 A 的重要特征值集中在远离 0 的区域,那么 1/t 比较容易被低阶多项式近似,Krylov 方法通常收敛较快
如果特征值非常分散,或者有很多特征值接近 0,那么低阶多项式很难同时照顾所有重要方向,收敛就会变慢
和直接分解法的区别
直接分解法的思路是先对矩阵做一次比较昂贵的分解
A=LU
或者
A=QR
之后如果有很多个右端项
Ax1=b1,Ax2=b2,Ax3=b3
就可以重复使用同一套分解
因此直接分解法适合:
- 矩阵规模没有大到无法分解
- 需要求很多个右端项 RHS
- 需要较高精度的确定性求解
而 Krylov 方法更像是为当前的 b 构造一个专门的低维搜索空间
Kj(A,r0)
如果换一个右端项 b,初始 residual 通常也会变
r0=b−Ax0
于是 Krylov 子空间一般也要重新构造
所以 Krylov 方法适合:
- A 非常大
- A 很稀疏
- 矩阵分解太贵
- 只需要少数右端项 RHS
- 可以接受迭代近似解
- 能够快速计算 Av
这也是它常被称为 matrix-free 或 matvec-based 方法的原因
总结
Krylov 方法可以压缩成三层直觉
第一,从谱分解角度看,如果一个多项式在 A 的特征值上满足
p(λi)≈λi1
那么就可以期待
p(A)b≈A−1b
这说明 Krylov 方法背后是在用低阶多项式扮演 A−1 对当前 b 的作用
第二,Krylov 子空间正是这些低阶多项式自然生成的搜索空间
b,Ab,A2b,…
或者更一般地构造
r0,Ar0,A2r0,…
这些向量张成的 Krylov 子空间等价于一族多项式近似
pj−1(A)r0
第三,Gram-Schmidt / Arnoldi 负责给这个空间构造稳定的正交基,GMRES 这类方法再在这个低维空间里解一个小优化问题,选出最好的系数
所以最重要的分工是:
乘 A⇒扩展 Krylov 空间
Gram-Schmidt⇒得到稳定的正交基
优化 ⇒选择最好的系数并得到 xj
它不是显式求特征值、显式插值、再显式构造 A−1,而是通过矩阵-向量乘法、Krylov 投影和低维优化,隐式完成对 A−1b 或 A−1r0 的近似
这就是 Krylov 子空间方法为什么能用相对少的矩阵-向量乘法,去近似一个本来需要求逆才能得到的解