GMRES 方法的数学推导及其算法表示
- GMRES 解为 Krylov 子空间 2 范数意义下的极小化残差的最小二乘解。
- 考虑 Arnoldi 过程中正交基和上 Hessenberg 系数矩阵的分解关系 A V m = V m + 1 H ˉ m AV_m = V_{m+1} \bar{H}_m AVm=Vm+1Hˉm,子空间最小二乘问题从 V m V_m Vm 转到了 H ˉ m \bar{H}_m Hˉm。
- 上 Hessenberg 方程通过上三角化进行处理,上三角化的方式可采用 Givens 变换。
- 耦合 Given 变换上三角化上 Hessenberg 矩阵的过程到 Arnoldi 过程中,即得到了实用 GMRES 算法。
文章目录
-
- [GMRES 方法的数学推导及其算法表示](#GMRES 方法的数学推导及其算法表示)
-
- [GMRES 方法推导](#GMRES 方法推导)
- [最小二乘问题的 Givens 变换求解](#最小二乘问题的 Givens 变换求解)
- 幸运中断
- [实用 GMRES 算法与 MATLAB 编程实现](#实用 GMRES 算法与 MATLAB 编程实现)
GMRES 方法推导
考虑一般线性方程组求解问题
A x = b Ax=b Ax=b
假定 V m V_m Vm 是 Krylov 子空间 K m ( A , r 0 / ∥ r 0 ∥ 2 ) \mathcal{K}_m(A, r_0 /\left\|r_0\right\|_2) Km(A,r0/∥r0∥2) 一组正交基, x 0 x_0 x0 表示给定的迭代初值, r 0 r_0 r0 为初始残差 r 0 = b − A x 0 r_0 = b-Ax_0 r0=b−Ax0。
我们用 V m V_m Vm 表示以 v 1 , ⋯ , v m v_1, \cdots, v_m v1,⋯,vm 为列的 n × m n \times m n×m 矩阵。
x 0 + K m x_0+\mathcal{K}_m x0+Km 中的任意向量 x x x 可写为
x = x 0 + V m y , x=x_0+V_m y, x=x0+Vmy,
我们可以在投影空间中寻求 2 范数最小的解,即最小化
J ( y ) = ∥ b − A x ∥ 2 = ∥ b − A ( x 0 + V m y ) ∥ 2 , J(y)=\|b-A x\|_2=\left\|b-A\left(x_0+V_m y\right)\right\|_2, J(y)=∥b−Ax∥2=∥b−A(x0+Vmy)∥2,
我们用 h i j h_{ij} hij 表示的是向量 w j = A v j w_j = Av_j wj=Avj 在 v j v_j vj 上的投影内积。
H ˉ m \bar{H}m Hˉm 表示元素为 h i j h{i j} hij 的 ( m + 1 ) × m (m+1) \times m (m+1)×m 的上 Hessenberg 矩阵, H m H_m Hm 表示在 H ˉ m \bar{H}_m Hˉm 中删去最后一行所得的矩阵。
由
A v j = ∑ i = 1 j + 1 h i j v i , j = 1 , 2 , ⋯ , m . A v_j=\sum_{i=1}^{j+1} h_{i j} v_i, \quad j=1,2, \cdots, m . Avj=i=1∑j+1hijvi,j=1,2,⋯,m.
写成矩阵形式,实际上是
A V m = V m + 1 H ˉ m AV_m = V_{m+1} \bar{H}_m AVm=Vm+1Hˉm
那么有
b − A x = b − A ( x 0 + V m y ) = r 0 − A V m y = β v 1 − V m + 1 H ˉ m y = V m + 1 ( β e 1 − H ˉ m y ) b-A x=b-A\left(x_0+V_m y\right)=r_0-A V_m y=\beta v_1-V_{m+1} \bar{H}m y=V{m+1}\left(\beta e_1-\bar{H}_m y\right) b−Ax=b−A(x0+Vmy)=r0−AVmy=βv1−Vm+1Hˉmy=Vm+1(βe1−Hˉmy)
其中 β = ∣ ∣ r 0 ∣ ∣ 2 \beta = ||r_0||_2 β=∣∣r0∣∣2。那么,问题就变为了极小化问题
y m = arg min y ∥ β e 1 − H ˉ m y ∥ 2 . y_m=\arg \min _y\left\|\beta e_1-\bar{H}_m y\right\|_2 . ym=argymin βe1−Hˉmy 2.
结合 Arnoldi 正交化过程,可得 GMRES 算法如下,

最小二乘问题的 Givens 变换求解
求解最小二乘问题 min ∥ β e 1 − H ˉ m y ∥ \min \left\|\beta e_1-\bar{H}_m y\right\| min βe1−Hˉmy 可以通过 Givens 变换,将规模为 m × ( m − 1 ) m\times{(m-1)} m×(m−1) 的上 Hessenberg 矩阵 H ˉ m \bar{H}_m Hˉm 变为最后一行为 0 的上三角矩阵。
定义 g ˉ 0 ≡ β e 1 \bar{g}0 \equiv \beta e_1 gˉ0≡βe1。以 m = 5 m=5 m=5 举例来说,
H ˉ 5 = ( h 11 h 12 h 13 h 14 h 15 h 21 h 22 h 23 h 24 h 25 h 32 h 33 h 34 h 35 h 43 h 44 h 45 h 54 h 55 h 65 ) , g ˉ 0 = ( β 0 0 0 0 0 ) . \bar{H}5=\left(\begin{array}{ccccc} h{11} & h{12} & h_{13} & h_{14} & h_{15} \\ h_{21} & h_{22} & h_{23} & h_{24} & h_{25} \\ & h_{32} & h_{33} & h_{34} & h_{35} \\ & & h_{43} & h_{44} & h_{45} \\ & & & h_{54} & h_{55} \\ & & & & h_{65} \end{array}\right), \quad \bar{g}_0=\left(\begin{array}{c} \beta \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \end{array}\right) . Hˉ5= h11h21h12h22h32h13h23h33h43h14h24h34h44h54h15h25h35h45h55h65 ,gˉ0= β00000 .
我们可以定义一系列的旋转矩阵 Ω i \Omega_i Ωi,举例来说,
Ω 1 = ( c 1 s 1 − s 1 c 1 1 1 1 ) \Omega_1=\left(\begin{array}{ccccc} c_1 & s_1 & & & \\ -s_1 & c_1 & & & \\ & & 1 & & \\ & & & 1 & \\ & & & & 1 \end{array}\right) Ω1= c1−s1s1c1111
s 1 = h 21 h 11 2 + h 21 2 , c 1 = h 11 h 11 2 + h 21 2 s_1=\frac{h_{21}}{\sqrt{h_{11}^2+h_{21}^2}}, \quad c_1=\frac{h_{11}}{\sqrt{h_{11}^2+h_{21}^2}} s1=h112+h212 h21,c1=h112+h212 h11
以此类推。
那么,通过定义 Q m = Ω m Ω m − 1 ⋯ Ω 1 Q_m=\Omega_m \Omega_{m-1} \cdots \Omega_1 Qm=ΩmΩm−1⋯Ω1,有
R ˉ m = H ˉ m ( m ) = Q m H ˉ m g ˉ m = Q m ( β e 1 ) = ( γ 1 , ⋯ , γ m + 1 ) T . \begin{aligned} \bar{R}_m & =\bar{H}_m^{(m)}=Q_m \bar{H}_m \\ \bar{g}m & =Q_m\left(\beta e_1\right)=\left(\gamma_1, \cdots, \gamma{m+1}\right)^{\mathrm{T}} . \end{aligned} Rˉmgˉm=Hˉm(m)=QmHˉm=Qm(βe1)=(γ1,⋯,γm+1)T.
则
min ∥ β e 1 − H ˉ m y ∥ 2 = min ∥ g ˉ m − R ˉ m y ∥ 2 . \min \left\|\beta e_1-\bar{H}_m y\right\|_2=\min \left\|\bar{g}_m-\bar{R}_m y\right\|_2 . min βe1−Hˉmy 2=min gˉm−Rˉmy 2.
因为 R ˉ m \bar{R}_m Rˉm 最后一行是 0,用 R m R_m Rm 和 g m g_m gm 分别表示从 R ˉ m \bar{R}_m Rˉm 和 g ˉ m \bar{g}_m gˉm 中删除最后一行所得的 m × m m \times m m×m 上三角矩阵和 m m m 维向量。可以知道上述问题的最小二乘解为
y m = R m − 1 g m y_m=R_m^{-1} g_m ym=Rm−1gm
且残差范数
∥ b − A x m ∥ 2 = ∣ γ m + 1 ∣ \left\|b-A x_m\right\|2=\left|\gamma{m+1}\right| ∥b−Axm∥2=∣γm+1∣
幸运中断
由 Ω i \Omega_i Ωi 的表达方式,可以知道
γ j + 1 = − s j γ j \gamma_{j+1}=-s_j \gamma_j γj+1=−sjγj
事实上,容易证明,在 Arnoldi 正交基生成过程中, h j + 1 , j = 0 h_{j+1, j}=0 hj+1,j=0,当且仅当提前求解问题最小二乘解且误差为 0,即 b − A x j = 0 b-A x_j=0 b−Axj=0,也就是说近似解 x j x_j xj 就是精确解。因此, h j + 1 , j = 0 h_{j+1, j}=0 hj+1,j=0 可以作为中断条件,行内称之为"幸运中断"。
实用 GMRES 算法与 MATLAB 编程实现
将上述 Givens 变换上三角化的过程,耦合到整个 Arnoldi 正交化过程中,就得到了标准的实用的 GMRES 算法了。

可以看得出来,这个算法需要把每次的 Givens 变换矩阵都存下来,还是比较耗费内存的,所以后面有了带重启的 GMRES 算法。当然,考虑内存有限,也可以实用 BICGSTAB 算法。
算法的一些细节处理,我写了一个简单的 MATLAB 编程实现如下,仅供参考:
% 生成一个随机的正定矩阵测试
n = 100;
A = gallery('compar', n);
b = rand(n, 1);
x0 = zeros(n, 1);
% 调用算法
[x, res] = gmres(A, b, x0, 1e-6, 50);
x_ref = A\b;
err = norm(x - x_ref)
function [x, resvec] = gmres(A, b, x0, tol, iter_max)
% 输入: A-矩阵, b-右端项, x0-初值, tol-容差, iter_max-最大迭代次数
% 输出: x-近似解, resvec-残差历史
n = length(b);
r0 = b - A * x0;
beta = norm(r0);
if beta < tol
x = x0; return;
end
% 初始化
V = zeros(n, iter_max + 1);
V(:, 1) = r0 / beta;
H = zeros(iter_max + 1, iter_max);
g = zeros(iter_max + 1, 1);
g(1) = beta;
cs = zeros(iter_max, 1); % 存储 Givens 余弦
sn = zeros(iter_max, 1); % 存储 Givens 正弦
resvec = [];
for j = 1:iter_max
% --- Arnoldi 过程 ---
w = A * V(:, j);
for i = 1:j
H(i, j) = V(:, i)' * w;
w = w - H(i, j) * V(:, i);
end
H(j+1, j) = norm(w);
V(:, j+1) = w / H(j+1, j);
% --- 应用之前的 Givens 旋转到当前列 ---
for i = 1:j-1
temp = cs(i) * H(i, j) + sn(i) * H(i+1, j);
H(i+1, j) = -sn(i) * H(i, j) + cs(i) * H(i+1, j);
H(i, j) = temp;
end
% --- 计算并应用当前的 Givens 旋转 ---
[cs(j), sn(j)] = col_rotation(H(j, j), H(j+1, j));
H(j, j) = cs(j) * H(j, j) + sn(j) * H(j+1, j);
H(j+1, j) = 0;
% --- 更新残差向量 g ---
g(j+1) = -sn(j) * g(j);
g(j) = cs(j) * g(j);
relres = abs(g(j+1)) / beta;
resvec = [resvec; relres];
% 检查收敛
if relres < tol
break;
end
end
% --- 回代求解 H*y = g ---
y = H(1:j, 1:j) \ g(1:j);
% --- 计算最终解 ---
x = x0 + V(:, 1:j) * y;
end
% 辅助函数:计算 Givens 旋转参数
function [c, s] = col_rotation(a, b)
if b == 0
c = 1; s = 0;
elseif abs(b) > abs(a)
tau = a / b;
s = 1 / sqrt(1 + tau^2);
c = s * tau;
else
tau = b / a;
c = 1 / sqrt(1 + tau^2);
s = c * tau;
end
end