基于python实现的Jacobi迭代法和Gauss-Seidel迭代法

之前的文章介绍过Gauss消元法、Doolittle和Crout分解等解线性方程组的直接方法。但是直接法不是在任何时候都可用的,它有以下缺点:

  • 在有舍入误差的情况下,直接法只能得到方程的近似解。
  • 如果待求解问题规模很大,直接法求解的计算量是很大的,更糟的是随着计算量的增大舍入误差积累也会越多,从而得到的解误差更大。所以直接法适合小规模稠密型方程组的求解。
  • 另外,直接法的程序设计也比较复杂。

迭代法解线性方程组

对于方程组 A x = b Ax=b Ax=b 一般可以将其写成如下形式
x = M x + g x=Mx+g x=Mx+g建立上述方程组的迭代公式:
x ( k + 1 ) = M x ( k ) + g , k = 0 , 1 , 2 , … x^{(k+1)}=Mx^{(k)}+g,k=0,1,2,\dots x(k+1)=Mx(k)+g,k=0,1,2,这个迭代公式有什么用呢?

当向量序列 x ( k ) x^{(k)} x(k) 收敛于 x ∗ x^* x 时,有
x ∗ = M x ∗ + g x^*=Mx^*+g x=Mx+g可以发现 x ∗ x^* x 即为方程组 x = M x + g x=Mx+g x=Mx+g 的解,也就是说,当 x ( k ) x^{(k)} x(k) 收敛时, x ( k ) x^{(k)} x(k) 即为方程组的解。

以上就是迭代法解方程组的基本原理,只要 x ( k ) x^{(k)} x(k)收敛,就可以通过k步迭代得到方程组的近似解。

下面介绍两种经典的迭代法:Jacobi迭代法和Gauss-Seidel迭代法。


Jacobi迭代法

假设有下列线性方程组
{ a 11 x 1 + a 12 x 2 + a 13 x 3 = b 1 a 21 x 1 + a 22 x 2 + a 23 x 3 = b 2 a 31 x 1 + a 32 x 2 + a 33 x 3 = b 3 \left\{\begin{array}{l}a_{11}x_1+a_{12}x_2+a_{13}x_3=b_1\\a_{21}x_1+a_{22}x_2+a_{23}x_3=b_2\\a_{31}x_1+a_{32}x_2+a_{33}x_3=b_3\end{array}\right. a11x1+a12x2+a13x3=b1a21x1+a22x2+a23x3=b2a31x1+a32x2+a33x3=b3
将其写成下面形式
{ x 1 = 1 a 11 ( b 1 − a 12 x 2 − a 13 x 3 ) x 2 = 1 a 22 ( b 2 − a 21 x 1 − a 23 x 3 ) x 3 = 1 a 33 ( b 3 − a 31 x 1 − a 32 x 2 ) \left\{\begin{array}{l}x_1=\frac1{a_{11}}(b_1-a_{12}x_2-a_{13}x_3)\\x_2=\frac1{a_{22}}(b_2-a_{21}x_1-a_{23}x_3)\\x_3=\frac1{a_{33}}(b_3-a_{31}x_1-a_{32}x_2)\end{array}\right. x1=a111(b1a12x2a13x3)x2=a221(b2a21x1a23x3)x3=a331(b3a31x1a32x2)
建立迭代公式
{ x 1 ( k + 1 ) = 1 a 11 ( b 1 − a 12 x 2 ( k ) − a 13 x 3 ( k ) ) x 2 ( k + 1 ) = 1 a 22 ( b 2 − a 21 x 1 ( k ) − a 23 x 3 ( k ) ) x 3 ( k + 1 ) = 1 a 33 ( b 3 − a 31 x 1 ( k ) − a 32 x 2 ( k ) ) \left\{\begin{array}{l}x_1^{(k+1)}=\frac1{a_{11}}(b_1-a_{12}x_2^{(k)}-a_{13}x_3^{(k)})\\x_2^{(k+1)}=\frac1{a_{22}}(b_2-a_{21}x_1^{(k)}-a_{23}x_3^{(k)})\\x_3^{(k+1)}=\frac1{a_{33}}(b_3-a_{31}x_1^{(k)}-a_{32}x_2^{(k)})\end{array}\right. x1(k+1)=a111(b1a12x2(k)a13x3(k))x2(k+1)=a221(b2a21x1(k)a23x3(k))x3(k+1)=a331(b3a31x1(k)a32x2(k))
对于每一个 x i ( k + 1 ) x_i^{(k+1)} xi(k+1) ,有如下公式
x i ( k + 1 ) = 1 a i i ( b i − ∑ j = 1 i − 1 a i j x j ( k ) − ∑ j = i + 1 n a i j x j ( k ) ) i = 1 , 2 , ⋯   , n , k = 0 , 1 , ⋯ x_i^{(k+1)}=\frac1{a_{ii}}(b_i-\sum_{j=1}^{i-1}a_{ij}x_j^{(k)}-\sum_{j=i+1}^na_{ij}x_j^{(k)})\\i=1,2,\cdots,n,k=0,1,\cdots xi(k+1)=aii1(bij=1i1aijxj(k)j=i+1naijxj(k))i=1,2,,n,k=0,1,然后我们就可根据这个公式解线性方程组了。

但是为了便于理论分析,我们把它写成矩阵的形式。
假设方程组为 A x = b Ax=b Ax=b,将 A A A 分裂为
A = D − L − U A = D - L - U A=DLU其中 D D D 为对角矩阵 d i a g ( a 11 , a 22 , … , a n n ) diag(a_{11},a_{22},\dots,a_{nn}) diag(a11,a22,,ann) − L -L L − U -U U 分别如下
− L = ( 0 a 21 0 a 31 a 32 0 ⋮ ⋮ ⋱ ⋱ a n 1 a n 2 … a n n − 1 0 )    − U = ( 0 a 12 a 13 … a 1 n 0 a 23 … a 2 n ⋱ ⋱ ⋮ ⋱ a n − 1 n 0 ) -L=\begin{pmatrix}0&&&&\\a_{21}&0&&&\\a_{31}&a_{32}&0&&\\\vdots&\vdots&\ddots&\ddots&\\a_{n1}&a_{n2}&\dots&a_{nn-1}&0\end{pmatrix}\\ \;\\ -U=\begin{pmatrix}0&a_{12}&a_{13}&\dots&a_{1n}\\&0&a_{23}&\dots&a_{2n}\\&&\ddots&\ddots&\vdots\\&&&\ddots&a_{n-1n}\\&&&&0\end{pmatrix} L=0a21a31an10a32an20ann10U=0a120a13a23a1na2nan1n0则方程组和迭代公式可写为
( D − L − U ) x = b    x = D − 1 ( L + U ) x + D − 1 b    x ( k + 1 ) = D − 1 ( L + U ) x ( k ) + D − 1 b ( 迭 代 公 式 )    k = 0 , 1 , ⋯ (D - L - U)x=b\\ \;\\ x = D^{-1}(L+U)x + D^{-1}b\\ \;\\ x^{(k+1)} = D^{-1}(L+U)x^{(k)} + D^{-1}b(迭代公式)\\ \;\\ k=0,1,\cdots (DLU)x=bx=D1(L+U)x+D1bx(k+1)=D1(L+U)x(k)+D1b()k=0,1,
可以验证矩阵形式的迭代公式和上面大括号方程组表示的迭代公式一致的。


下面根据公式 x ( k + 1 ) = D − 1 ( L + U ) x ( k ) + D − 1 b x^{(k+1)} = D^{-1}(L+U)x^{(k)} + D^{-1}b x(k+1)=D1(L+U)x(k)+D1b 编写代码

算法代码

def Jfunction(A,b,k):
    n = A.shape[1]
    D = np.eye(n)
    D[np.arange(n),np.arange(n)] = A[np.arange(n),np.arange(n)]
    LU = D - A
    X = np.zeros(n)
    for i in range(k):
        D_inv = np.linalg.inv(D)
        X =  np.dot(np.dot(D_inv,LU),X) + np.dot(D_inv,b)
    return X

实验
解下列方程组
在这里插入图片描述
方程组的精确解为 x = ( 1 , 1 , 1 ) x = (1,1,1) x=(1,1,1)

A = np.array([
    [10,3,1],
    [2,-10,3],
    [1,3,10]
])
b = np.array([14,-5,14])
k = 6
X = Jfunction(A,b,k);

实验结果
在这里插入图片描述


Gauss-Seidel迭代法

在J迭代法中在计算 x i ( k + 1 ) x_i^{(k+1)} xi(k+1)时,前 i − 1 i-1 i1 个分量已经计算完成了,如果可以利用这些信息,可能加速迭代法的收敛。因此我们对迭代公式做如下修改
{ x 1 ( k + 1 ) = 1 a 11 ( b 1 − a 12 x 2 ( k ) − a 13 x 3 ( k ) ) x 2 ( k + 1 ) = 1 a 22 ( b 2 − a 21 x 1 ( k + 1 ) − a 23 x 3 ( k ) ) x 3 ( k + 1 ) = 1 a 33 ( b 3 − a 31 x 1 ( k + 1 ) − a 32 x 2 ( k + 1 ) ) \left\{\begin{array}{l}x_1^{(k+1)}=\frac1{a_{11}}(b_1-a_{12}x_2^{(k)}-a_{13}x_3^{(k)})\\x_2^{(k+1)}=\frac1{a_{22}}(b_2-a_{21}x_1^{(k+1)}-a_{23}x_3^{(k)})\\x_3^{(k+1)}=\frac1{a_{33}}(b_3-a_{31}x_1^{(k+1)}-a_{32}x_2^{(k+1)})\end{array}\right. x1(k+1)=a111(b1a12x2(k)a13x3(k))x2(k+1)=a221(b2a21x1(k+1)a23x3(k))x3(k+1)=a331(b3a31x1(k+1)a32x2(k+1))这就是Gauss-Seidel迭代法的迭代公式
对于每一个 x i ( k + 1 ) x_i^{(k+1)} xi(k+1) ,有如下公式
x i ( k + 1 ) = 1 a i i ( b i − ∑ j = 1 i − 1 a i j x j ( k + 1 ) − ∑ j = i + 1 n a i j x j ( k ) ) i = 1 , 2 , ⋯   , n , k = 0 , 1 , ⋯ x_i^{(k+1)}=\frac1{a_{ii}}(b_i-\sum_{j=1}^{i-1}a_{ij}x_j^{(k+1)}-\sum_{j=i+1}^na_{ij}x_j^{(k)})\\i=1,2,\cdots,n,k=0,1,\cdots xi(k+1)=aii1(bij=1i1aijxj(k+1)j=i+1naijxj(k))i=1,2,,n,k=0,1,上述公式也可以写成矩阵形式,我们可以从J迭代法的矩阵形式推出G-S迭代法的矩阵形式

按照J迭代法的迭代公式有
x ( k + 1 ) = D − 1 ( L + U ) x ( k ) + D − 1 b    D x ( k + 1 ) = L x ( k ) + U x ( k ) + b x^{(k+1)} = D^{-1}(L+U)x^{(k)} + D^{-1}b\\ \;\\ Dx^{(k+1)} =Lx^{(k)}+Ux^{(k)}+b x(k+1)=D1(L+U)x(k)+D1bDx(k+1)=Lx(k)+Ux(k)+b不难发现 L x ( k ) Lx^{(k)} Lx(k) 对应了G-S迭代公式中的 ∑ j = 1 i − 1 a i j x j ( k + 1 ) \sum_{j=1}^{i-1}a_{ij}x_j^{(k+1)} j=1i1aijxj(k+1) 部分,因此按照G-S迭代法的迭代公式,上面迭代公式应该写成
D x ( k + 1 ) = L x ( k + 1 ) + U x ( k ) + b Dx^{(k+1)} =Lx^{(k+1)}+Ux^{(k)}+b Dx(k+1)=Lx(k+1)+Ux(k)+b整理,得
x ( k + 1 ) = ( D − L ) − 1 U x ( k ) + ( D − L ) − 1 b x^{(k+1)} =(D-L)^{-1}Ux^{(k)}+(D-L)^{-1}b x(k+1)=(DL)1Ux(k)+(DL)1b


下面根据公式 x ( k + 1 ) = ( D − L ) − 1 U x ( k ) + ( D − L ) − 1 b x^{(k+1)} =(D-L)^{-1}Ux^{(k)}+(D-L)^{-1}b x(k+1)=(DL)1Ux(k)+(DL)1b 编写代码

算法代码

def G_Sfunction(A,b,k):
    n = A.shape[1]
    D = np.eye(n)
    D[np.arange(n),np.arange(n)] = A[np.arange(n),np.arange(n)]
    LU = D - A
    L = np.tril(LU)
    U = np.triu(LU)
    D_L = D - L
    X = np.zeros(n)
    for i in range(k):
        D_L_inv = np.linalg.inv(D_L)
        X =  np.dot(np.dot(D_L_inv,U),X) + np.dot(D_L_inv,b)
    return X

实验
解下列方程组(一样的例题)
在这里插入图片描述
方程组的精确解为 x = ( 1 , 1 , 1 ) x = (1,1,1) x=(1,1,1)

A = np.array([
    [10,3,1],
    [2,-10,3],
    [1,3,10]
])
b = np.array([14,-5,14])
k = 6
X = G_Sfunction(A,b,k);

实验结果
在这里插入图片描述
可以发现G-S迭代法在第4次迭代完成的时候就已经达到了J迭代法第六次迭代完成的效果了。


迭代法的特点

  • 只能求的近似解
  • 可以在迭代的过程中对误差进行矫正
  • 如果系数矩阵是稀疏的,即使面对大规模的问题,也可能通过较小的计算量得到方程组的解
  • 原理简单方便实现
  • 7
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
JacobiGauss-Seidel均是解线性方程组的代方。下面分别介绍它们的实现Jacobi Jacobi的公式为: $$x_i^{(k+1)}=\frac{1}{a_{ii}}\left(b_i-\sum_{j=1,j\neq i}^na_{ij}x_j^{(k)}\right),\quad i=1,2,\cdots,n$$ 其中,$a_{ij}$是系数矩阵,$b_i$是常数向量,$x_i^{(k)}$是第$k$次代中$x_i$的近似值。 下面是Python实现Jacobi的代码: ```python import numpy as np def jacobi(A, b, x0, tol=1e-6, max_iter=100): n = len(A) x = x0.copy() for k in range(max_iter): x_new = np.zeros(n) for i in range(n): s = 0 for j in range(n): if j != i: s += A[i, j] * x[j] x_new[i] = (b[i] - s) / A[i, i] if np.linalg.norm(x_new - x) < tol: return x_new x = x_new return x ``` 其中,`A`和`b`分别是系数矩阵和常数向量,`x0`是初始解,`tol`是代收敛的容许误差,`max_iter`是最大代次数。函数返回代得到的近似解。 Gauss-Seidel Gauss-Seidel的公式为: $$x_i^{(k+1)}=\frac{1}{a_{ii}}\left(b_i-\sum_{j=1}^{i-1}a_{ij}x_j^{(k+1)}-\sum_{j=i+1}^na_{ij}x_j^{(k)}\right),\quad i=1,2,\cdots,n$$ 其中,$a_{ij}$是系数矩阵,$b_i$是常数向量,$x_i^{(k)}$是第$k$次代中$x_i$的近似值。 下面是Python实现Gauss-Seidel的代码: ```python import numpy as np def gauss_seidel(A, b, x0, tol=1e-6, max_iter=100): n = len(A) x = x0.copy() for k in range(max_iter): for i in range(n): s1 = sum(A[i, j] * x[j] for j in range(i)) s2 = sum(A[i, j] * x[j] for j in range(i+1, n)) x[i] = (b[i] - s1 - s2) / A[i, i] if np.linalg.norm(A @ x - b) < tol: return x return x ``` 其中,`A`和`b`分别是系数矩阵和常数向量,`x0`是初始解,`tol`是代收敛的容许误差,`max_iter`是最大代次数。函数返回代得到的近似解。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值