
前面我们已经知道对于线性方程组,一般有两种数值解法:直接法和迭代法。直接法前面已经写过了,没看的同学可以移步阅读:直接法。本次主要讲述迭代法及其相应的MATLAB代码。
考虑线性方程组
当
本文主要介绍迭代法的基本思路和雅可比(Jacobi)迭代法、高斯-塞德尔(Gauss-Seidel)迭代法、(逐次)超松弛(SOR, Successie over Relaxation)迭代法、共轭梯度(CG, Conjugate Gradient)法。
1. 迭代法的基本思路
对于线性方程组
为了使用迭代法对其进行求解,我们首先需要构造迭代序列,我们将上式改写为
其中
对向量序列
这就是我们构造迭代法的基本思路。MATLAB代码为
function [x,t,it] = Iteration(A,b,I,eps)
% 输入:
% A: 系数矩阵
% b: 载荷矩阵
% I: 最大迭代次数
% 输出:
% x: 解矩阵
% t: 时间
% it: 迭代次数
% 迭代初值默认为 0if nargin < 4eps = 1e-6;
endtic
[n,~] = size(A);
B = zeros(size(A));
x = zeros(n,1);
f = zeros(n,1);for r = 1:nfor l = 1:nif l == rB(r,r) = 0;elseB(r,l) = -A(r,l)/A(r,r);endendf(r) = b(r)/A(r,r);
endx_exact = Ab;
it = 1;
for k = 1:I-1x = B*x+f;if norm(x-x_exact)>epsit = it+1;end
end
t = toc;
end
示例:
clear
A = [8 -3 2; 4 11 -1; 6 3 12]; b = [20; 33; 36];
I = 1000;
[x,t,it] = Iteration(A,b,I)
运行结果
x =321t =0.016490086000000it =16
可见只是迭代
2. 雅可比(Jacobi)迭代法
其实上面第1节的代码使用的方法就是最原始的雅可比迭代法,只是在形式上看起来不那么规范。下面我们来看规范的解
其中
其分量计算公式为
但实际编程计算一般采取简洁且高效的矩阵形式,其MATLAB代码为
function [x,t,it] = Jacobi(A,b,I,eps)
% 雅可比迭代法
% 输入:
% A: 系数矩阵
% b: 载荷矩阵
% I: 最大迭代次数
% 输出:
% x: 解矩阵
% t: 时间
% it: 迭代次数
% 迭代初值默认为 0if nargin < 4eps = 1e-6;
endtic
[n,~] = size(A);
x = zeros(n,1);D = diag(diag(A)); %求 A 的对角矩阵
L = -tril(A,-1); %求 A 的下三角矩阵,不带对角线
U = -triu(A,1); %求 A 的上三角矩阵
J = D(L+U);
f = Db;x_exact = Ab;
it = 1;
for k = 1:I-1x = J*x+f;if norm(x-x_exact)>epsit = it+1;end
endt = toc;
end
仍然计算第一节的例子,只需把函数名改一下:
clear
A = [8 -3 2; 4 11 -1; 6 3 12]; b = [20; 33; 36];
I = 1000;
[x,t,it] = Jacobi(A,b,I)
运行结果也与第1节一致:
x =321t =0.037686548000000it =16
3. 高斯-塞德尔(Gauss-Seidel)迭代法
高斯-塞德尔迭代法与雅可比迭代法很相似,可以看成是其的一种改进。其形式为:
其中
其分量计算公式为
其MATLAB代码亦采取矩阵形式:
function [x,t,it] = GaussSeidel(A,b,I,eps)
% 高斯-赛德尔(Gauss-Seidel)迭代法
% 输入:
% A: 系数矩阵
% b: 载荷矩阵
% I: 最大迭代次数
% 输出:
% x: 解矩阵
% t: 时间
% it: 迭代次数
% 迭代初值默认为 0if nargin < 4eps = 1e-6;
endtic
[n,~] = size(A);
x = zeros(n,1);D = diag(diag(A)); %求 A 的对角矩阵
L = -tril(A,-1); %求 A 的下三角矩阵,不带对角线
U = -triu(A,1); %求 A 的上三角矩阵
G = (D-L)U;
f = (D-L)b;x_exact = Ab;
it = 1;
for k = 1:I-1x = G*x+f;if norm(x_exact-x)>epsit = it+1;end
endt = toc;
end
同样计算前面的例子,其结果为:
x =321t =0.054796674000000it =8
从结果可以看出,对于同样的精度要求,高斯-塞德尔迭代法只需要
3. (逐次)超松弛(SOR)迭代法
简单来说,逐次超松弛迭代法就是在前面高斯-塞德尔迭代法的基础上加了松弛因子
其中
其分量计算公式为
显然,当
其MATLAB代码为
function [x,t,it,w] = SOR(A,b,I,eps,w)
% 逐次超松驰迭代法(successive over relaxation method)迭代法
% 输入:
% A: 系数矩阵
% b: 载荷矩阵
% I: 最大迭代次数
% w: 松弛因子(w=1 时即为 Gauss-Seidel 迭代法)
% 输出:
% x: 解矩阵
% t: 时间
% it: 迭代次数
% w: 松弛因子
% 迭代初值默认为 0tic
[n,~] = size(A);
x = zeros(n,1);D = diag(diag(A)); %求 A 的对角矩阵
L = -tril(A,-1); %求 A 的下三角矩阵,不带对角线
U = -triu(A,1); %求 A 的上三角矩阵
w_opt = 2/(1+sqrt(1-(vrho(D(L+U)))^2)); % 最佳松弛因子
if nargin < 4eps = 1e-6;w = w_opt;
end
if nargin < 5w = w_opt;
end
Lw = (D-w*L)((1-w)*D+w*U);
f = w*((D-w*L)b);x_exact = Ab;
it = 1;
for k = 1:I-1x = Lw*x+f;if norm(x-x_exact)>epsit = it+1;end
endt = toc;
end
还是计算前面那个例子,选择精度为
clear
A = [8 -3 2; 4 11 -1; 6 3 12]; b = [20; 33; 36];
I = 1000;
[x,t,it,w] = SOR(A,b,I,1e-6,1.2)
运行结果为
x =3.0000000000000002.0000000000000001.000000000000000t =0.003814113000000it =13w =1.200000000000000
如果采取默认松弛因子(自动选择最佳松弛因子):
clear
A = [8 -3 2; 4 11 -1; 6 3 12]; b = [20; 33; 36];
I = 1000;
[x,t,it,w] = SOR(A,b,I)
其结果为
x =3.0000000000000002.0000000000000001.000000000000000t =0.009697537000000it =8w =1.034531942537068
此时迭代次数减少为
4. 共轭梯度(CG)法
也称共轭斜量法,它是一种变分方法,对应于求一个二次函数的极值。CG方法是一种求解大型稀疏对称正定方程组十分有效的方法。
其算法描述为:
(1)任取
(2)对
(3)若
写成MATLAB代码为
function [x,t,it] = CG(A,b)
% 共轭梯度法 CG(conjugate gradient)
% 针对大型稀疏对称正定矩阵方程组
% 输入:
% A: 系数矩阵
% b: 载荷矩阵
% 输出:
% x: 解矩阵
% t: 时间
% it: 迭代次数tic
[n,~] = size(A);
x = zeros(n,1);
r = b - A*x;
p = r;
it = 0;while (sum(r.*r) ~= 0) && (sum(p.*(A*p)) ~= 0)it = it+1;rr = sum(r.*r);alpha = rr/sum(p.*(A*p));x = x + alpha*p;r = r - alpha*A*p;beta = sum(r.*r)/rr;p = r + beta*p;
end
t = toc;
end
用此CG方法求解一个
clear
n = 6; A = zeros(n,n);
% Hilbert 矩阵
for i = 1:nfor j = 1:nA(i,j) = 1/(i+j-1);end
end
x_star = ones(n,1); b = A*x_star;
[x,t,it] = CG(A,b)
运行结果为:
x =0.9999999999998971.0000000000040020.9999999999680481.0000000000921610.9999999998907641.000000000045352t =0.006673698000000it =350
而如果采用Gauss-Seidel迭代法,精度要求为
x =0.9999999999998711.0000000000043290.9999999999676931.0000000000897200.9999999998961901.000000000042388t =2.914480589000000it =5438741
对比结果可以发现,达到类似精度,G-S迭代法需要迭代