MATLAB中bicgstabl函数用法

目录

语法

说明

示例

线性系统的迭代解

[使用指定了预条件子的 bicgstabl](#使用指定了预条件子的 bicgstabl)

提供初始估计值

使用函数句柄代替数值矩阵


bicgstabl函数的功能是求解线性系统 - 稳定双共轭梯度 (l) 法。

语法

cs 复制代码
x = bicgstabl(A,b)
x = bicgstabl(A,b,tol)
x = bicgstabl(A,b,tol,maxit)
x = bicgstabl(A,b,tol,maxit,M)
x = bicgstabl(A,b,tol,maxit,M1,M2)
x = bicgstabl(A,b,tol,maxit,M1,M2,x0)
[x,flag] = bicgstabl(___)
[x,flag,relres] = bicgstabl(___)
[x,flag,relres,iter] = bicgstabl(___)
[x,flag,relres,iter,resvec] = bicgstabl(___)

说明

**x = bicgstabl(A,b)**尝试使用双共轭梯度稳定法 (l)求解关于 x 的线性系统 A*x = b。如果尝试成功,bicgstabl 会显示一条消息来确认收敛。如果 bicgstabl 无法在达到最大迭代次数后收敛或出于任何原因暂停,则会显示一条包含相对残差 norm(b-A*x)/norm(b) 以及该方法停止时的迭代次数的诊断消息。

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

**x = bicgstabl(A,b,tol,maxit)**指定要使用的最大迭代次数。如果 bicgstabl 无法在 maxit 次迭代内收敛,将显示诊断消息。

x = bicgstabl(A,b,tol,maxit,M) 指定预条件子矩阵 M 并通过有效求解关于 y 的方程组 AM^−1y=b 来计算 x,其中 y=Mx。使用预条件子矩阵可以改善问题的数值属性和计算的效率。

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

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

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

**[x,flag,relres] = bicgstabl(___)**还会返回相对残差 norm(b-A*x)/norm(b)。如果 flag 为 0,则 relres <= tol。

**[x,flag,relres,iter] = bicgstabl(___)**还会返回计算出 x 时的迭代次数 iter。

**[x,flag,relres,iter,resvec] = bicgstabl(___)**还会在每个四分之一迭代中返回残差范数向量(包括第一个残差 norm(b-A*x0))。

示例

线性系统的迭代解

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

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

cs 复制代码
rng default
A = sprand(400,400,.5);
A = A'*A;
b = rand(400,1);

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

cpp 复制代码
x = bicgstabl(A,b);

bicgstabl stopped at iteration 20 without converging to the desired tolerance 1e-06
because the maximum number of iterations was reached.
The iterate returned (number 20) has relative residual 0.095.

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

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

cs 复制代码
x = bicgstabl(A,b,1e-4,100);

bicgstabl 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.028.

即使采用更宽松的容差和更多迭代,残差也并未改进多少。当迭代算法以这种方式停滞时,显然需要预条件子矩阵。

计算 A 的不完全 Cholesky 分解,并使用 L' 因子作为 bicgstabl 的预条件子输入。

cs 复制代码
L = ichol(A);
x = bicgstabl(A,b,1e-4,100,L');
bicgstabl converged at iteration 15.5 to a solution with relative residual 2.5e-05.

使用预条件子可以充分改进问题的数值属性,使 bicgstabl 能够收敛。

使用指定了预条件子的 bicgstabl

检查使用指定了预条件子矩阵的 bicgstabl 来求解线性系统的效果。

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

cs 复制代码
load west0479
A = west0479;

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

cs 复制代码
b = sum(A,2);

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

cs 复制代码
tol = 1e-12;
maxit = 20;

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

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

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

  • rr0 是计算的解 x 的相对残差。

  • it0 是计算 x 时所用的迭代次数。

  • rv0 是 ‖b−Ax‖ 的残差历史记录组成的向量。

cs 复制代码
[x,fl0,rr0,it0,rv0] = bicgstabl(A,b,tol,maxit);
fl0
fl0 = 1
rr0
rr0 = 1
it0
it0 = 0

bicgstabl 未在请求的 20 次迭代内收敛至请求的容差 1e-12,因此 fl0 为 1。实际上,bicgstabl 的行为太差,因此初始估计值 x0 = zeros(size(A,2),1) 是最佳解,并会返回最佳解(如 it0 = 0 所示)。

为了有助于缓慢收敛,可以指定预条件子矩阵。由于 A 是非对称的,请使用 ilu 生成预条件子 M=L U。指定调降容差,以忽略值小于 1e-6 的非对角线元。通过指定 L 和 U 作为 bicgstabl 的输入,求解预条件方程组 A M^−1M x=b。

cs 复制代码
setup = struct('type','ilutp','droptol',1e-6);
[L,U] = ilu(A,setup);
[x1,fl1,rr1,it1,rv1] = bicgstabl(A,b,tol,maxit,L,U);
fl1
fl1 = 0
rr1
rr1 = 1.0652e-15
it1
it1 = 2

在第二次迭代中,使用 ilu 预条件子产生的相对残差小于规定的容差 1e-12。输出 rv1(1) 为 norm(b),输出 rv1(end) 为 norm(b-A*x1)。

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

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

如图所示:

提供初始估计值

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

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

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

使用 bicgstabl 求解 Ax=b 两次:一次是使用默认的初始估计值,一次是使用解的良好初始估计值。对两次求解均使用 20 次迭代和默认容差。将第二种求解中的初始估计值指定为所有元素都等于 0.99 的向量。

cs 复制代码
maxit = 20;
x1 = bicgstabl(A,b,[],maxit);
bicgstabl converged at iteration 9.2 to a solution with relative residual 9.5e-07.
x0 = 0.99*e;
x2 = bicgstabl(A,b,[],maxit,[],[],x0);
bicgstabl converged at iteration 2 to a solution with relative residual 5.4e-07.

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

返回中间结果

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

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

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

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

使用函数句柄代替数值矩阵

通过为 bicgstabl 提供用来计算 A*x 的函数句柄(而非系数矩阵 A)来求解线性系统。

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

cs 复制代码
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 乘以向量时,所得向量中的大多数元素为零。结果中的非零元素对应于 A 的非零三对角元素。此外,只有主对角线具有不等于 1 的非零值。

表达式 Ax 变为:

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

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

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

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

现在,通过为 bicgstabl 提供用于计算 A*x 的函数句柄,求解线性系统 Ax=b。使用容差 1e-12 和 50 次迭代。

cs 复制代码
b = ones(21,1);
tol = 1e-12;  
maxit = 50;
x1 = bicgstabl(@afun,b,tol,maxit)
bicgstabl converged at iteration 5.2 to a solution with relative residual 2e-15.
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 组成的向量。

cs 复制代码
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
      ⋮

局部函数

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

双共轭梯度稳定法 (l)

双共轭梯度稳定 l (BiCGSTABL) 算法是为了改进 BiCGSTAB 方法而开发的,后者本身是为了改进 BiCG 方法而开发的。

像 BiCGSTAB 一样,BiCGSTABL 算法使用 GMRES 步骤来减轻 BiCG 中引入的不规则收敛行为。然而,BiCGSTABL 使用 BiCGSTAB 的 GMRES(2) 步骤而不是 GMRES(1) 步骤,因此能够提供更好的校正,减少频繁停滞的情况 [1]

提示

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

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

参考

[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.

相关推荐
懒惰才能让科技进步21 分钟前
从零学习大模型(十二)-----基于梯度的重要性剪枝(Gradient-based Pruning)
人工智能·深度学习·学习·算法·chatgpt·transformer·剪枝
DARLING Zero two♡25 分钟前
关于我、重生到500年前凭借C语言改变世界科技vlog.16——万字详解指针概念及技巧
c语言·开发语言·科技
Gu Gu Study27 分钟前
【用Java学习数据结构系列】泛型上界与通配符上界
java·开发语言
Ni-Guvara34 分钟前
函数对象笔记
c++·算法
芊寻(嵌入式)1 小时前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
一颗松鼠1 小时前
JavaScript 闭包是什么?简单到看完就理解!
开发语言·前端·javascript·ecmascript
泉崎1 小时前
11.7比赛总结
数据结构·算法
有梦想的咸鱼_1 小时前
go实现并发安全hashtable 拉链法
开发语言·golang·哈希算法
你好helloworld1 小时前
滑动窗口最大值
数据结构·算法·leetcode
海阔天空_20131 小时前
Python pyautogui库:自动化操作的强大工具
运维·开发语言·python·青少年编程·自动化