• 解线性方程组——(Gauss-Seidel)高斯-赛德尔迭代法 | 北太天元


    一、Gauss-Seidel迭代法

    n = 3 n=3 n=3
    A = ( a 11 a 12 a 13 a 21 a 22 a 23 a 31 a 32 a 33 ) , b = ( b 1 b 2 b 3 ) , A=

    (a11a12a13a21a22a23a31a32a33)" role="presentation">(a11a12a13a21a22a23a31a32a33)
    ,\quad b=
    (b1b2b3)" role="presentation" style="position: relative;">(b1b2b3)
    , A= a11a21a31a12a22a32a13a23a33 ,b= b1b2b3 ,

    先看一下Jacobi公式的特点

    Jacobi公式为
    x 1 ( k + 1 ) = b 1 − a 12 x 2 ( k ) − a 13 x 3 ( k ) a 11 x 2 ( k + 1 ) = b 2 − a 21 x 1 ( k ) − a 23 x 3 ( k ) a 22 x 3 ( k + 1 ) = b 3 − a 31 x 1 ( k ) − a 32 x 2 ( k ) a 33

    x1(k+1)=b1a12x2(k)a13x3(k)a11x2(k+1)=b2a21x1(k)a23x3(k)a22x3(k+1)=b3a31x1(k)a32x2(k)a33" role="presentation">x1(k+1)=b1a12x2(k)a13x3(k)a11x2(k+1)=b2a21x1(k)a23x3(k)a22x3(k+1)=b3a31x1(k)a32x2(k)a33
    x1(k+1)=a11b1a12x2(k)a13x3(k)x2(k+1)=a22b2a21x1(k)a23x3(k)x3(k+1)=a33b3a31x1(k)a32x2(k)

    可以看出Jacobi方法每次迭代使用的是上一步的结果,每行全部独立计算完后才进入下一轮迭代。

    而实际上计算 x 2 x_2 x2时, 本次迭代产生的 x 1 x_1 x1已经更新, 使用 x 3 x_3 x3时, x 1 , x 2 x_1,x_2 x1,x2已经更新。由此想法(尽可能使用最新产生的结果),得到Gauss-Seidel方法

    Gauss-Seidel公式为
    x 1 ( k + 1 ) = b 1 − a 12 x 2 ( k ) − a 13 x 3 ( k ) a 11 x 2 ( k + 1 ) = b 2 − a 21 x 1 ( k + 1 ) − a 23 x 3 ( k ) a 22 x 3 ( k + 1 ) = b 3 − a 31 x 1 ( k + 1 ) − a 32 x 2 ( k + 1 ) a 33

    x1(k+1)=b1a12x2(k)a13x3(k)a11x2(k+1)=b2a21x1(k+1)a23x3(k)a22x3(k+1)=b3a31x1(k+1)a32x2(k+1)a33" role="presentation">x1(k+1)=b1a12x2(k)a13x3(k)a11x2(k+1)=b2a21x1(k+1)a23x3(k)a22x3(k+1)=b3a31x1(k+1)a32x2(k+1)a33
    x1(k+1)x2(k+1)x3(k+1)=a11b1a12x2(k)a13x3(k)=a22b2a21x1(k+1)a23x3(k)=a33b3a31x1(k+1)a32x2(k+1)

    或等价的,将 A A A 分解为 A = D − L − U A=D-L-U A=DLU,其中
    D = d i a g ( a 11 , a 22 , a 33 ) , D=diag(a_{11},a_{22},a_{33}), D=diag(a11,a22,a33), L = − [ 0 0 0 a 21 0 0 a 31 a 32 0 ] , U = − [ 0 a 12 a 13 0 0 a 23 0 0 0 ] . L=-

    [000a2100a31a320]" role="presentation">[000a2100a31a320]
    ,\quad U=-
    [0a12a1300a23000]" role="presentation">[0a12a1300a23000]
    . L= 0a21a3100a32000 ,U= 000a1200a13a230 . ( D − L − U ) x = b D x = b + ( L + U ) x D x ( k + 1 ) = b + L x ( k + 1 ) + U x ( k ) ( D − L ) x ( k + 1 ) = b + U x ( k ) x ( k + 1 ) = ( D − L ) − 1 ( b + U x ( k ) )
    (DLU)x=bDx=b+(L+U)xDx(k+1)=b+Lx(k+1)+Ux(k)(DL)x(k+1)=b+Ux(k)x(k+1)=(DL)1(b+Ux(k))" role="presentation">(DLU)x=bDx=b+(L+U)xDx(k+1)=b+Lx(k+1)+Ux(k)(DL)x(k+1)=b+Ux(k)x(k+1)=(DL)1(b+Ux(k))
    (DLU)xDxDx(k+1)(DL)x(k+1)x(k+1)=b=b+(L+U)x=b+Lx(k+1)+Ux(k)=b+Ux(k)=(DL)1(b+Ux(k))

    其中 x ( k + 1 ) = D − 1 ( b + L x ( k + 1 ) + U x ( k ) ) x^{(k+1)}=D^{-1}(b+Lx^{(k+1)}+Ux^{(k)}) x(k+1)=D1(b+Lx(k+1)+Ux(k))
    写成矩阵的形式
    [ x 1 ( k + 1 ) x 2 ( k + 1 ) x 3 ( k + 1 ) ] = [ 1 a 11 1 a 22 1 a 33 ] ( [ b 1 b 2 b 3 ] − [ a 21 a 31 a 32   ] [ x 1 ( k + 1 ) x 2 ( k + 1 ) x 3 ( k + 1 ) ] − [   a 12 a 13 a 23 ] [ x 1 ( k ) x 2 ( k ) x 3 ( k ) ] )

    [x1(k+1)x2(k+1)x3(k+1)]" role="presentation">[x1(k+1)x2(k+1)x3(k+1)]
    =
    [1a111a221a33]" role="presentation">[1a111a221a33]
    \left(
    [b1b2b3]" role="presentation">[b1b2b3]
    -
    [a21a31a32 ]" role="presentation">[a21a31a32 ]
    [x1(k+1)x2(k+1)x3(k+1)]" role="presentation">[x1(k+1)x2(k+1)x3(k+1)]
    -
    [ a12a13a23]" role="presentation">[ a12a13a23]
    [x1(k)x2(k)x3(k)]" role="presentation">[x1(k)x2(k)x3(k)]
    \right) x1(k+1)x2(k+1)x3(k+1) = a111a221a331 b1b2b3 a21a31a32  x1(k+1)x2(k+1)x3(k+1)  a12a13a23 x1(k)x2(k)x3(k)
    下面是其一般形式下的算法

    二、算法

    ♡ \heartsuit Gauss-Seidel迭代法

    主要思路

    输入 : A , b , x ( 0 ) A,b,x^{(0)} A,b,x(0)
    输出 : x x x
    x ( 0 ) =  initial vector  x ( k + 1 ) = ( D − L ) − 1 ( b + U x ( k ) )

    x(0)= initial vector x(k+1)=(DL)1(b+Ux(k))" role="presentation">x(0)= initial vector x(k+1)=(DL)1(b+Ux(k))
    x(0)x(k+1)= initial vector =(DL)1(b+Ux(k))

    添加一些限制

    • 容许误差 e_tol,
    • 最大迭代步 N N N.

    当 残差 ≥ N \geq N N 时,都会停止迭代,输出结果

    实现步骤

    • 步骤 1 1 1: k = 0 k=0 k=0, x = x ( 0 ) x=x^{(0)} x=x(0)

    • 步骤 2 2 2: 计算残差 r = ∥ b − A x ∥ r=\|b-Ax\| r=bAx

      • 如果残差 r r r >e_tol 且 k < N kk<N,转步骤 3 3 3;
      • 否则, 转步骤 5 5 5
    • 步骤 3 3 3: 更新解向量 x = ( D − L ) − 1 ( b + U x ( 0 ) ) x=(D-L)^{-1}(b+Ux^{(0)}) x=(DL)1(b+Ux(0))

    • 步骤 4 4 4 x 0 = x x0=x x0=x, k = k + 1 k=k+1 k=k+1,转步骤 2 2 2;

    • 步骤 5 5 5: 输出 x x x.

    在这里插入图片描述

    三、北太天元源程序

    Gauss-Seidel

    function [x,k,r] = myGS(A,b,x0,e_tol,N)
    % Gauss-Seidel迭代法解线性方程组
    % Input: A, b(列向量), x0(初始值)
    %        e_tol: error tolerant  
    %        N: 限制迭代次数小于 N 次
    % Output: x , k(迭代次数),r:残差
    %   Version:            1.0
    %   last modified:      01/29/2024
        n = length(b); k = 0; 
        x=zeros(n,N); % 记录每一次迭代的结果,方便后续作误差分析
        x(:,1)=x0; 
        L = -tril(A,-1); U = -triu(A,1); D = diag(diag(A));
        r = norm(b - A*x,2);
        while r > e_tol && k < N
            x(:,k+2) = inv(D-L)*(b+U*x(:,k+1)); % 不同之处
            r = norm(b - A*x(:,k+2),2); % 残差
            k = k+1;
        end
        x = x(:,2:k+1); % x取迭代时的结果
        
        if k>N
            fprintf('迭代超出最大迭代次数');
        else
            fprintf('迭代次数=%i\n',k);
        end
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    保存为 myGS.m 文件

    四、数值算例

    (此例子与 Jaboci迭代法 文章中的例子相同,可以对比着来看)

    A x = b Ax=b Ax=b,求 x x x
    A = ( 10 − 1 2 0 − 1 11 − 1 3 2 − 1 10 − 1 0 3 − 1 8 ) b = ( 6 25 − 11 15 ) A =

    (1012011113211010318)" role="presentation">(1012011113211010318)
    \quad b =
    (6251115)" role="presentation">(6251115)
    A= 1012011113211010318 b= 6251115

    用Gauss列主元消去法,得

    x = 
       1.000000000000000
       2.000000000000000
      -1.000000000000000
       1.000000000000000
    
    • 1
    • 2
    • 3
    • 4
    • 5

    下面我们用Gauss-Seidel 迭代法进行求解

    %% Gauss-Seidel test
    % time :      4/24/2024
    
    %% example 1
    clc;clear all,format long;
    N = 100; e_tol = 1e-8;
    A=[10 -1 2 0; -1 11 -1 3; 2 -1 10 -1; 0 3 -1 8];
    b=[6; 25; -11; 15];
    x0=[0; 0; 0; 0];
        [x11,k1] = myGS(A,b,x0,e_tol,N)
        [x12,k2] = myJacobi(A,b,x0,e_tol,N)
    % 作图查看误差变化
        x_exact=[1;2;-1;1]; %真解
        n = length(b);
        error=zeros(n,k1);% 每个分量的误差
            error = abs(x_exact - x11) 
        res =zeros(1,k1); % 残差
        res1 = res;
        res2 = res;
        for i=1:1:k1
            res1(i) = norm(b-A*x11(:,i),2);
            
        end 
        for i=1:1:k2
            res2(i) = norm(b-A*x12(:,i),2);
        end
        % 数值解
            figure(1);
            plot(1:k1,x11(1,:),'-*r',1:k1,x11(2,:),'-og', 1:k1,x11(3,:),'-+b',1:k1,x11(4,:),'-dk');
            legend('x_1','x_2','x_3','x_4');
            title('G-S下每个数值解的变化')
        % 残差变化
            figure(2);
            plot(1:k1,res1,'-*r');
            hold on
            plot(1:k2,res2,'-*b');
            legend('G-S','Jacobi');
            title('残差变化')
        % 误差
            figure(3);
            plot(1:k1,error(1,:),'-*r',1:k1,error(2,:),'-og', 1:k1,error(3,:),'-+b',1:k1,error(4,:),'-dk');
            legend('x_1','x_2','x_3','x_4');
            title('G-S下每个数值解的误差变化')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    运行后得到
    在这里插入图片描述
    在这里插入图片描述

    和Jacobi相比,其 达到相同精度 所需要得迭代步数更少,如下图
    在这里插入图片描述
    Gauss-Seidel 需进行 10次迭代

    而 Jacobi 需进行 26 次迭代

  • 相关阅读:
    记录一下在Ubuntu18.04下,程序窗口之间切换快捷键
    程序员自由创业周记#13:第一桶金
    Guava的缓存
    Java - 将TXT文本文件转换为PDF文件
    【流水线】FPGA中流水线的原因和方法
    牛客的课程订单分析[分组统计时如何取指定行字段?]
    Mybatis-Plus--update(), updateById()将字段更新为null
    Android开发笔记1:Android Studio 2021.3.1.17 Toolbar工具栏调整
    【我的前端】前端项目小练习:CSS创建3D圆柱旋转效果
    Dubbo3.0系列(6)- Dubbo3.0支持的RPC协议
  • 原文地址:https://blog.csdn.net/Math_Boy_W/article/details/138171722