Main Content

本页对应的英文页面已更新,但尚未翻译。 若要查看最新内容,请点击此处访问英文页面。

gmres

求解线性方程组 - 广义最小残差法

说明

示例

x = gmres(A,b) 尝试使用广义最小残差法求解关于 x 的线性方程组 A*x = b。如果尝试成功,gmres 会显示一条消息来确认收敛。如果 gmres 无法在达到最大迭代次数后收敛或出于任何原因暂停,则会显示一条包含相对残差 norm(b-A*x)/norm(b) 以及该方法停止时的迭代次数的诊断消息。对于此语法,gmres 不会重新启动;最大迭代次数为 min(size(A,1),10)

示例

x = gmres(A,b,restart)restart内迭代重新启动该方法一次。最大外迭代次数为 outer = min(size(A,1)/restart,10)。最大总迭代次数为 restart*outer,因为 gmres 对每次外迭代执行 restart 次内迭代。如果 restartsize(A,1)[],则 gmres 不重新启动,最大总迭代次数为 min(size(A,1),10)

示例

x = gmres(A,b,restart,tol) 指定该方法的容差。默认容差是 1e-6

示例

x = gmres(A,b,restart,tol,maxit) 指定最大外迭代次数,使总迭代次数不超过 restart*maxit。如果 maxit[]gmres 使用默认值 min(size(A,1)/restart,10)。如果 restartsize(A,1)[],则最大总迭代次数为 maxit(而不是 restart*maxit)。如果 gmres 未能在最大迭代次数内收敛,将显示诊断消息。

示例

x = gmres(A,b,restart,tol,maxit,M) 指定预条件子矩阵 M 并通过有效求解关于 x 的方程组 M1Ax=M1b 来计算 x。使用预条件子矩阵可以改善问题的数值属性和计算的效率。

示例

x = gmres(A,b,restart,tol,maxit,M1,M2) 指定预条件子矩阵 M 的因子,使得 M = M1*M2

示例

x = gmres(A,b,restart,tol,maxit,M1,M2,x0) 指定解向量 x 的初始估计值。默认值为由零组成的向量。

示例

[x,flag] = gmres(___) 返回一个标志,指示算法是否成功收敛。当 flag = 0 时,收敛成功。您可以将此输出语法用于之前的任何输入参数组合。如果指定了 flag 输出,gmres 将不会显示任何诊断消息。

示例

[x,flag,relres] = gmres(___) 还返回相对残差 norm(M\(b-A*x))/norm(M\b),其中包括预条件子矩阵 M。如果 flag0,则 relres <= tol

示例

[x,flag,relres,iter] = gmres(___) 还以向量 [outer inner] 形式返回计算出 x 时的内迭代和外迭代次数。外迭代数在 0 <= iter(1) <= maxit 范围内,内迭代数在 0 <= iter(2) <= restart 范围内。

示例

[x,flag,relres,iter,resvec] = gmres(___) 还会返回每次内迭代中的残差范数向量(包括第一个残差 norm(M\(b-A*x0)))。这些是预条件方程组的残差范数。

示例

全部折叠

使用采用默认设置的 gmres 求解系数矩阵为方阵的线性方程组,然后在求解过程中调整使用的容差和迭代次数。

创建密度为 50% 的随机稀疏矩阵 A。另为 Ax=b 的右侧创建随机向量 b

rng default
A = sprand(400,400,.5);
A = A'*A;
b = rand(400,1);

使用 gmres 求解 Ax=b。输出显示包括相对残差 Ax-bb 的值。

x = gmres(A,b);
gmres stopped at iteration 10 without converging to the desired tolerance 1e-06
because the maximum number of iterations was reached.
The iterate returned (number 10) has relative residual 0.15.

默认情况下,gmres 使用 10 次迭代和容差 1e-6,对于此矩阵,算法无法在 10 次迭代后收敛。由于残差仍然很大,这说明需要更多的迭代(或预条件子矩阵)。您还可以减小容差,使算法更容易收敛。

使用容差 1e-4 和 100 次迭代再次求解方程组。

tol = 1e-4;
maxit = 100;
x = gmres(A,b,[],tol,maxit);
gmres stopped at iteration 100 without converging to the desired tolerance 0.0001
because the maximum number of iterations was reached.
The iterate returned (number 100) has relative residual 0.052.

即使采用更宽松的容差和更多迭代,残差也并未改进多少。当迭代算法以这种方式停滞时,显然需要预条件子矩阵。不过,gmres 也有控制内迭代次数的输入。通过为内迭代指定值,gmres 将针对每次外迭代做更多的工作。

使用 restart 值 100 和 maxit 值 250 再次求解方程组。gmres 不是一次执行 100 次迭代,而是在两次重启之间执行 100 次迭代,并重复 250 次。

restart = 100;
maxit = 250;
x = gmres(A,b,restart,tol,maxit);
gmres(100) converged at outer iteration 134 (inner iteration 39) to a solution with relative residual 0.0001.

在这种情况下,为 gmres 指定较大的重启值会使其能够在允许的迭代次数内收敛于某个解。但是,当 A 也很大时,大的重启值会消耗大量内存。

检查使用预条件子矩阵和非重启 gmres 求解线性方程组的效果。

加载 west0479,它是一个非对称的 479×479 实稀疏矩阵。

load west0479
A = west0479;

定义 b 以使实际解是全为 1 的向量。

b = sum(A,2);

设置容差和最大迭代次数。

tol = 1e-12;
maxit = 20;

使用 gmres 根据请求的容差和迭代次数求解。指定五个输出以返回有关求解过程的信息:

  • x0 是计算 A*x0 = b 所得的解。

  • fl0 是指示算法是否收敛的标志。

  • rr0 是计算的解 x0 的残差。

  • it0 是二元素向量 [inner outer],它表示计算 x0 时的内迭代和外迭代次数。

  • rv0Ax-b 的残差历史记录组成的向量。

[x0,fl0,rr0,it0,rv0] = gmres(A,b,[],tol,maxit);
fl0
fl0 = 1
rr0
rr0 = 0.7603
it0
it0 = 1×2

     1    20

gmres 未在请求的 20 次迭代内收敛至请求的容差 1e-12,因此 fl0 为 1。gmres 返回的最佳近似解是最后一个(如 it0(2) = 20 所示)。MATLAB 将残差历史记录存储于 rv0 中。

为了有助于缓慢收敛,您可以指定预条件子矩阵。由于 A 是非对称的,请使用 ilu 生成预条件子 M=LU。指定调降容差,以忽略值小于 1e-6 的非对角线元。通过指定 LU 作为 gmres 的输入,求解预条件方程组 M-1Ax=M-1b。请注意,当您指定预条件子时,gmres 会针对输出 rr1rv1 计算预条件方程组的残差范数。

[L,U] = ilu(A,struct('type','ilutp','droptol',1e-6));
[x1,fl1,rr1,it1,rv1] = gmres(A,b,[],tol,maxit,L,U);
fl1
fl1 = 0
rr1
rr1 = 6.9008e-14
it1
it1 = 1×2

     1     6

在第六次外迭代中,使用 ilu 预条件子产生的相对残差小于规定的容差 1e-12。第一个残差 rv1(1)norm(U\(L\b)),其中 M = L*U。最后一个残差 rv1(end)norm(U\(L\(b-A*x1)))

您可以通过绘制每次迭代的相对残差来跟踪 gmres 的进度。绘制每个解的残差历史记录图,并添加一条表示指定容差的线。

semilogy(0:length(rv0)-1,rv0/norm(b),'-o')
hold on
semilogy(0:length(rv1)-1,rv1/norm(U\(L\b)),'-o')
yline(tol,'r--');
legend('No preconditioner','ILU preconditioner','Tolerance','Location','East')
xlabel('Iteration number')
ylabel('Relative residual')

使用指定了预条件子的重启的 gmres

加载 west0479,它是一个非对称的 479×479 实稀疏矩阵。

load west0479
A = west0479;

定义 b 以使实际解是全为 1 的向量。

b = sum(A,2);

构造一个调降容差为 1e-6 的不完全 LU 预条件子。

[L,U] = ilu(A,struct('type','ilutp','droptol',1e-6));

使用重新启动的 gmres 的好处是限制执行该方法所需的内存量。如果不重新启动,gmres 需要存储 maxit 向量来保存基本 Krylov 子空间。此外,gmres 必须在每一步与以前的所有向量正交。重新启动可限制使用的工作区量以及每次外迭代执行的工作量。

使用不完全 LU 因子作为预条件子执行 gmres(3)gmres(4)gmres(5)。使用容差 1e-12 和最多 20 次外迭代。

tol = 1e-12;
maxit = 20;
[x3,fl3,rr3,it3,rv3] = gmres(A,b,3,tol,maxit,L,U);
[x4,fl4,rr4,it4,rv4] = gmres(A,b,4,tol,maxit,L,U);
[x5,fl5,rr5,it5,rv5] = gmres(A,b,5,tol,maxit,L,U);
fl3
fl3 = 0
fl4
fl4 = 0
fl5
fl5 = 0

fl3fl4fl5 均为 0,因为在每种情况下重新启动的 gmres 使相对残差趋向小于 1e-12 的规定公差。

以下绘图显示了每个重启的 gmres 方法的收敛历史记录。gmres(3) 收敛于外迭代 5、内迭代 3 (it3 = [5, 3]),这将与外迭代 6、内迭代 0 相同,因此最终刻度线上的标记是 6。

semilogy(1:1/3:6,rv3/norm(U\(L\b)),'-o');
h1 = gca;
h1.XTick = (1:6);
title('gmres(N) for N = 3, 4, 5')
xlabel('Outer iteration number');
ylabel('Relative residual');
hold on
semilogy(1:1/4:3,rv4/norm(U\(L\b)),'-o');
semilogy(1:1/5:2.8,rv5/norm(U\(L\b)),'-o');
yline(tol,'r--');
hold off
legend('gmres(3)','gmres(4)','gmres(5)','Tolerance')
grid on

一般情况下,内迭代次数越多,gmres 针对每个外迭代所做的工作会越多,收敛速度也会越快。

检查向 gmres 提供解的初始估计值的效果。

创建一个三对角稀疏矩阵。使用每行的总和作为 Ax=b 右侧的向量,以便 x 的预期解是由 1 组成的向量。

n = 900;
e = ones(n,1);
A = spdiags([e 2*e e],-1:1,n,n);
b = sum(A,2);

使用 gmres 求解 Ax=b 两次:一次是使用默认的初始估计值,一次是使用解的良好初始估计值。对这两个解都使用 200 次迭代,并将初始估计值指定为所有元素均等于 0.99 的向量。

maxit = 200;
x1 = gmres(A,b,[],[],maxit);
gmres converged at iteration 27 to a solution with relative residual 9.5e-07.
x0 = 0.99*ones(size(A,2),1);
x2 = gmres(A,b,[],[],maxit,[],[],x0);
gmres converged at iteration 7 to a solution with relative residual 6.7e-07.

在这种情况下,提供初始估计值可以使 gmres 更快地收敛。

返回中间结果

您还可以通过在 for 循环中调用 gmres 来使用初始估计值获得中间结果。每次调用求解器都会执行几次迭代,并存储计算出的解。然后,将该解用作下一批迭代的初始向量。

例如,以下代码会循环执行四次,每次执行 100 次迭代,并在 for 循环中每通过一次后均存储解向量:

x0 = zeros(size(A,2),1);
tol = 1e-8;
maxit = 100;
for k = 1:4
    [x,flag,relres] = gmres(A,b,[],tol,maxit,[],[],x0);
    X(:,k) = x;
    R(k) = relres;
    x0 = x;
end

X(:,k) 是在 for 循环的第 k 次迭代时计算的解向量,R(k) 是该解的相对残差。

通过为 gmres 提供函数句柄来求解线性方程组,该函数句柄计算 A*x 而不是系数矩阵 A

gallery 生成的 Wilkinson 测试矩阵之一是 21×21 三对角矩阵。预览该矩阵。

A = gallery('wilk',21)
A = 21×21

    10     1     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0
     1     9     1     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0
     0     1     8     1     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0
     0     0     1     7     1     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0
     0     0     0     1     6     1     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0
     0     0     0     0     1     5     1     0     0     0     0     0     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     1     4     1     0     0     0     0     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     1     3     1     0     0     0     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     1     2     1     0     0     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     1     1     1     0     0     0     0     0     0     0     0     0     0
      ⋮

Wilkinson 矩阵有特殊的结构,因此您可以用函数句柄来表示 A*x 运算。由于 A 的每行都乘以 x 中的元素,因此只有少数结果为非零值(对应于三对角线上的非零值)。此外,只有主对角线具有不等于 1 的非零值。表达式 Ax 变为:

[1010001910001810017100161001510014100130001000110][x1x2x3x4x5x21]=[10x1+x2x1+9x2+x3x2+8x3+x4x19+9x20+x21x20+10x21]

结果向量可以写为三个向量的和:

[0+10x1+x2x1+9x2+x3x2+8x3+x4x19+9x20+x21x20+10x21+0]=[0x1x20]+[10x19x210x21]+[x2x210]

在 MATLAB® 中,编写一个函数来创建这些向量并将它们相加,从而给出 A*x 的值:

function y = afun(x)
y = [0; x(1:20)] + ...
    [(10:-1:0)'; (1:10)'].*x + ...
    [x(2:21); 0];
end

(该函数作为局部函数保存在示例的末尾。)

现在,通过为 gmres 提供用于计算 A*x 的函数句柄,求解线性方程组 Ax=b。重启前,使用容差 1e-12、15 次外迭代和 10 次内迭代。

b = ones(21,1);
tol = 1e-12;  
maxit = 15;
restart = 10;
x1 = gmres(@afun,b,restart,tol,maxit)
gmres(10) converged at outer iteration 5 (inner iteration 10) to a solution with relative residual 5.3e-13.
x1 = 21×1

    0.0910
    0.0899
    0.0999
    0.1109
    0.1241
    0.1443
    0.1544
    0.2383
    0.1309
    0.5000
      ⋮

检查 afun(x1) 是否产生由 1 组成的向量。

afun(x1)
ans = 21×1

    1.0000
    1.0000
    1.0000
    1.0000
    1.0000
    1.0000
    1.0000
    1.0000
    1.0000
    1.0000
      ⋮

局部函数

function y = afun(x)
y = [0; x(1:20)] + ...
    [(10:-1:0)'; (1:10)'].*x + ...
    [x(2:21); 0];
end

输入参数

全部折叠

系数矩阵,指定为方阵或函数句柄。该矩阵是线性方程组 A*x = b 中的系数矩阵。通常,A 是大型稀疏矩阵或函数句柄,它返回大型稀疏矩阵和列向量的乘积。

A 指定为函数句柄

您可以将系数矩阵指定为函数句柄而不是矩阵,以节省计算中使用的内存。函数句柄返回矩阵向量乘积,而不是构建整个系数矩阵,从而使计算更加高效。

要使用函数句柄,请使用函数签名 function y = afun(x)参数化函数说明如何在必要时为函数 afun 提供附加参数。函数调用 afun(x) 必须返回 A*x 的值。

数据类型: double | function_handle
复数支持:

线性方程的右侧,指定为列向量。b 必须为长度等于 size(A,1) 的列向量。

数据类型: double
复数支持:

重启前的内迭代次数,指定为整数标量。使用此输入和 maxit 输入来控制最大迭代次数,即 restart*maxit。如果 restart[]size(A,1),则 gmres 不会重启,迭代总数为 maxit

通常,restart 值越大,收敛行为越好,但对时间和内存的要求也越高。

数据类型: double

方法容差,指定为正标量。计算中使用此输入可在准确度和运行时间之间进行权衡。gmres 必须在允许的迭代次数内满足容差才能成功。较小的 tol 值意味着,计算要成功,解必须更精确。

数据类型: double

最大外迭代次数,指定为正整数标量。增加 maxit 的值,以允许 gmres 进行更多迭代,从而满足容差 tol。通常,tol 的值越小,成功完成计算所需的迭代次数越多。

如果还指定了 restart 输入,则总迭代次数为 restart*maxit。否则,总迭代次数为 maxit

maxit 的默认值取决于是否指定了 restart

  • 如果未指定 restart,或者指定为 []size(A,1),则 maxit 的默认值为 min(size(A,1),10)

  • 如果 restart 指定为 1 <= restart < size(A,1) 范围内的值,则 maxit 的默认值为 min(ceil(size(A,1)/restart),10)

数据类型: double

预条件子矩阵,指定为由矩阵或函数句柄组成的单独参数。您可以指定预条件子矩阵 M 或其矩阵因子 M = M1*M2 来改进线性方程组的数值方面,使 gmres 更容易快速收敛。您可以使用不完全矩阵分解函数 iluichol 来生成预条件子矩阵。您还可以在分解之前使用 equilibrate 来改进系数矩阵的条件数。有关预条件子的详细信息,请参阅线性方程组的迭代方法

gmres 将未指定的预条件子视为单位矩阵。

M 指定为函数句柄

您可以将 MM1M2 中的任一个指定为函数句柄而不是矩阵,以节省计算中使用的内存。函数句柄执行矩阵向量运算,而不是构建整个预条件子矩阵,从而使计算更加高效。

要使用函数句柄,请使用函数签名 function y = mfun(x)参数化函数说明如何在必要时为函数 mfun 提供附加参数。函数调用 mfun(x) 必须返回 M\xM2\(M1\x) 的值。

数据类型: double | function_handle
复数支持:

初始估计值,指定为长度等于 size(A,2) 的列向量。如果您能为 gmres 提供比默认的零向量更合理的初始估计值 x0,则它可以节省计算时间并帮助算法更快地收敛。

数据类型: double
复数支持:

输出参数

全部折叠

线性方程组解,以向量形式返回。该输出给出线性方程组 A*x = b 的近似解。如果计算成功 (flag = 0),则 relres 小于或等于 tol

每当计算不成功 (flag ~= 0) 时,gmres 返回的解 x 是在所有迭代中计算出的残差范数最小的解。

收敛标志,返回下表中的标量值之一。收敛标志指示计算是否成功,并区分几种不同形式的失败。

标志值

收敛

0

成功 - gmresmaxit 次迭代内收敛至所需容差 tol

1

失败 - gmres 执行了 maxit 次迭代,但未收敛。

2

失败 - 预条件子矩阵 MM = M1*M2 为病态。

3

失败 - gmres 在经过两次相同的连续迭代后已停滞。

4

失败 - 由 gmres 算法计算的标量数量之一变得太小或太大,无法继续计算。

相对残差,以标量形式返回。相对残差 relres = norm(M\(b-A*x))/norm(M\b) 指示解的准确度。请注意,gmres 在相对残差计算中包括预条件子矩阵 M,而大多数其他迭代求解器不包括。如果计算在 maxit 次迭代内收敛于容差 tol,则 relres <= tol

数据类型: double

外迭代和内迭代次数,以二元素向量 [outer inner] 形式返回。此输出指示计算出 x 的解时的内迭代和外迭代次数:

  • 如果未指定 restart,或者指定为 []size(A,1),则 outer = 1 和所有迭代都被视为内迭代。

  • 如果 restart 指定为 1 <= restart < size(A,1) 范围内的值,则外迭代次数在 0 <= outer <= maxit 范围内,内迭代次数在 0 <= inner <= restart 范围内。

数据类型: double

残差,以向量形式返回。残差 norm(M\(b-A*x)) 揭示对于给定的 x 值,算法接近收敛的程度。请注意,gmres 在相对残差计算中包括预条件子矩阵 M,而大多数其他迭代求解器不包括。resvec 中的元素数等于总迭代次数(如果使用 restart,则最多为 restart*maxit 次)。您可以检查 resvec 的内容,以帮助决定是否更改 restarttolmaxit 的值。

数据类型: double

详细信息

全部折叠

广义最小残差法

开发广义最小残差 (GMRES) 算法旨在将最小残差 (MINRES) 算法扩展到非对称矩阵。

像共轭梯度 (CG) 方法一样,GMRES 算法计算正交序列,但 GMRES 需要在序列中存储所有先前的向量。如果不进行检查,这种存储先前向量的做法会消耗大量内存。算法的“重启”版本通过周期性清除中间序列并在另一次迭代中使用结果作为初始值来控制这些序列的存储。

选择合适的“重启”值对于实现良好的性能至关重要,但选择合适的值主要取决于经验。如果重启前的迭代次数太少,算法可能收敛很慢或无法完全收敛。但是,如果重启值太大,则该算法会增加存储要求,并且可能做不必要的工作 [1]

内迭代和外迭代

内迭代gmres 在重启之前完成的迭代。您可以使用 restart 参数指定内迭代的次数。

每次 gmres 重启时,外迭代数都会增加。您可以使用 maxit 参数指定外迭代的次数。默认的外迭代次数是 min(size(A,1)/restart,10)

最大总迭代次数为 restart*maxit

提示

  • 大多数迭代方法的收敛取决于系数矩阵的条件数 cond(A)。您可以使用 equilibrate 来改进 A 的条件数,它本身就能使大多数迭代求解器更容易收敛。但如果您随后会对经平衡处理的矩阵 B = R*P*A*C 进行因式分解,使用 equilibrate 还可以获得质量更好的预条件子矩阵。

  • 您可以使用矩阵重新排序函数(如 dissectsymrcm)来置换系数矩阵的行和列,并在系数矩阵被分解以生成预条件子时最小化非零值的数量。这可以减少后续求解预条件线性方程组所需的内存和时间。

参考

[1] Barrett, R., M. Berry, T. F. Chan, et al., Templates for the Solution of Linear Systems: Building Blocks for Iterative Methods, SIAM, Philadelphia, 1994.

[2] Saad, Yousef and Martin H. Schultz, “GMRES: A generalized minimal residual algorithm for solving nonsymmetric linear systems,” SIAM J. Sci. Stat. Comput., July 1986, Vol. 7, No. 3, pp. 856-869.

扩展功能

在 R2006a 之前推出