前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >数值计算方法 Chapter6. 解线性方程组的迭代法

数值计算方法 Chapter6. 解线性方程组的迭代法

作者头像
codename_cys
发布2022-06-17 21:17:21
8060
发布2022-06-17 21:17:21
举报
文章被收录于专栏:我的充电站我的充电站

0. 问题描述

这一章节要解的问题和上一章是一样的,依然还是n 元线性方程组的求解问题。

\left\{ \begin{aligned} a_{11}x_1 + a_{12}x_2 + ... + a_{1n}x_n &= y_1 \\ a_{21}x_1 + a_{22}x_2 + ... + a_{2n}x_n &= y_2 \\ ... \\ a_{n1}x_1 + a_{n2}x_2 + ... + a_{nn}x_n &= y_n \end{aligned} \right.

但是,上一章主要是通过矩阵的线性变换转换成可以快速求解的三角阵或者对角阵的方式进行求解,其计算结果是精确的结果。

而本章则是的思路则是将问题Ax=y 转换成x = A'x 的迭代形式,从而,我们就可以给出迭代数组x_{k+1} = A'x_{k}

此时,如果x_k 满足收敛条件,那么x_{k} 就会收敛到x = A'x 的一组解当中,上述问题同样可以得到解答。

1. Jacobi迭代

1. Jacobi迭代方法

对原始方程进行线性变换,我们显然有:

\left\{ \begin{aligned} x_{1} = & &-\frac{a_{12}}{a_{11}}x_2 &-... &-\frac{a_{1n}}{a_{11}}x_n &+ \frac{y_1}{a_{11}} \\ x_{2} = &-\frac{a_{21}}{a_{22}}x_2 & &- ... &-\frac{a_{2n}}{a_{22}}x_n &+ \frac{y_2}{a_{22}} \\ ... \\ x_{n} = &-\frac{a_{n1}}{a_{nn}}x_1 &-\frac{a_{n2}}{a_{nn}}x_2 &- ... & &+ \frac{y_n}{a_{nn}} \end{aligned} \right.

我们将其写成矩阵形式即为:

\begin{pmatrix} x_1 \\ x_2 \\ ... \\ x_n \end{pmatrix} = \begin{pmatrix} 0 & -\frac{a_{12}}{a_{11}} & ... & -\frac{a_{1n}}{a_{11}} \\ -\frac{a_{21}}{a_{22}} & 0 & ... & -\frac{a_{2n}}{a_{22}} \\ ... & ... & ... & ... \\ -\frac{a_{n1}}{a_{nn}} & -\frac{a_{n2}}{a_{nn}} & ... & 0 \end{pmatrix} \begin{pmatrix} x_1 \\ x_2 \\ ... \\ x_n \end{pmatrix} + \begin{pmatrix} \frac{y_1}{a_{11}} \\ \frac{y_2}{a_{22}} \\ ... \\ \frac{y_n}{a_{nn}} \end{pmatrix}

我们将其简化为符号表达即为:

x = Bx + g

基于此,我们就可以给出Jacobi迭代公式如下:

x_{k+1} = Bx_{k} + g

2. Jacobi迭代矩阵

我们给出更加严格的数据表达如下,令:

D = \begin{pmatrix} a_{11} \\ & a_{22} \\ & & ... \\ & & & a_{nn} \end{pmatrix}

则有:

Ax = (D + A - D)x = y

进而可以导出:

Dx = (D-A)x + y

两边左乘D^{-1} 即有:

x = D^{-1}(D-A)x + D^{-1}y

B=D^{-1}(D-A)g=D^{-1}y ,即可得到上一小节中一模一样的内容。

迭代矩阵B 即为Jacobi迭代矩阵。

3. Jacobi迭代收敛条件

Jacobi迭代收敛的充要条件为:

迭代矩阵B 的谱半径\rho(B) < 1

亦即:

  • 对于迭代矩阵B 的所有本征值\lambda_i ,均有|\lambda_i| < 1 ,或者等价的max(|\lambda_i|) < 1 。不过,在一些特定的情况下,上述充要条件可以有适当的放宽。

具体而言,有如下定理:

定理 6.1 若方程组Ax=y 的系数矩阵A,满足下列条件之一,则其Jacobi迭代收敛: (1) A为行对角优阵,即|a_{ii}| > \sum_{j \neq i} |a_{ij}|i=1,2,...,n ; (2) A为列对角优阵,即

j=1,2,...,n

4. python伪代码实现

最后,我们给出Jacobi迭代的python伪代码如下:

代码语言:javascript
复制
def jacobi_iter(A, y, epsilon=1e-6):
    n = len(A)
    B = [[0 for _ in range(n)] for _ in range(n)]
    g = [0 for _ in range(n)]
    for i in range(n):
        for j in range(n):
            if j == i:
                continue
            B[i][j] = -A[i][j] / A[i][i]
        g[i] = y[i] / A[i][i]
    
    x = [0 for _ in range(n)]
    for _ in range(10**6):
        z = [0 for _ in range(n)]
        for i in range(n):
            z[i] += g[i]
            for j in range(n):
                z[i] += B[i][j] * x[j]
        if max(abs(z[i] - x[i]) for i in range(n)) < epsilon:
            break
        x = z
    return z

2. Gauss-Seidel迭代

1. Gauss-Seidel迭代方法

Gauss-Seidel迭代方程和上述Jacobi迭代事实上是非常相似的,唯一的区别在于说Jacobi迭代是以x^{(k)} 为整体每次一起进行迭代更新的,而Guass-Seidel迭代则是在计算每一个x^{(k)}_{i} 的时候就是用当前已经迭代计算完成的所有的x^{(k)}_{j} 的结果。

即是说,以每一个元素为单位不断进行迭代更新。

用公式表达即为:

\left\{ \begin{aligned} x^{(k+1)}_{1} = & &-\frac{a_{12}}{a_{11}}x^{(k)}_2 &-... &-\frac{a_{1n}}{a_{11}}x^{(k)}_n &+ \frac{y_1}{a_{11}} \\ x^{(k+1)}_{2} = &-\frac{a_{21}}{a_{22}}x^{(k+1)}_1 & &- ... &-\frac{a_{2n}}{a_{22}}x^{(k)}_n &+ \frac{y_2}{a_{22}} \\ ... \\ x^{(k+1)}_{n} = &-\frac{a_{n1}}{a_{nn}}x^{(k+1)}_1 &-\frac{a_{n2}}{a_{nn}}x^{(k+1)}_2 &- ... & &+ \frac{y_n}{a_{nn}} \end{aligned} \right.

2. Gauss-Seidel迭代矩阵

同样的,我们给出更加严格的数学推导如下:

\begin{aligned} A &= D + L + U \\ &= \begin{pmatrix} a_{11} \\ & a_{22} \\ & & ... \\ & & & a_{nn} \end{pmatrix} + \begin{pmatrix} 0 \\ a_{21} & 0 \\ ... \\ a_{n1} & a_{n2} & ... & 0 \end{pmatrix} \begin{pmatrix} 0 & a_{12} & ... & a_{1n} \\ & 0 & ... & a_{2n} \\ & & ... \\ & & & 0 \end{pmatrix} \end{aligned}

从而,我们有:

Ax = (D+L+U)x = y

亦即:

(D+L)x = -Ux + y

两边同乘以(D+l)^{-1} 即有:

x = -(D+L)^{-1}Ux + (D+L)^{-1}y

S = -(D+L)^{-1}Uf = (D+L)^{-1}y ,我们即可写出Gauss-Seidel迭代公式:

x^{(k+1)} = Sx^{(k)} + f

称迭代矩阵S 即为Gauss-Seidel迭代矩阵。

当然,如上一小节所述,实际在算法实现当中并没有必要计算出Sf ,只需要根据前面Jacobi 迭代矩阵进行实时参数更新即可。

3. Gauss-Seidel迭代收敛条件

同样的,我们给出书中关于Gauss-Seidel迭代的收敛条件如下:

定理6.2 若方程组系数矩阵为行或列对角优时,则Gauss-Seidel迭代收敛。 定理6.3 若方程组系数矩阵A 为对称正定阵,则Gauss-Seidel迭代收敛。

4. 伪代码实现

同样的,我们用python给出伪代码如下:

代码语言:javascript
复制
def gauss_seidel_iter(A, y, epsilon=1e-6):
    n = len(A)
    B = [[0 for _ in range(n)] for _ in range(n)]
    g = [0 for _ in range(n)]
    for i in range(n):
        for j in range(n):
            if j == i:
                continue
            B[i][j] = -A[i][j] / A[i][i]
        g[i] = y[i] / A[i][i]
    
    x = [0 for _ in range(n)]
    cnt = 0
    for _ in range(10**6):
        for i in range(n):
            z = g[i]
            for j in range(n):
                z += B[i][j] * x[j]
            if abs(z-x[i]) < epsilon:
                cnt += 1
            else:
                cnt = 0
            x[i] = z

            if cnt >= n:
                break
        if cnt >= n:
            break
    return x

3. 松弛迭代

1. 松弛迭代方法

松弛迭代的原型依然还是之前的Jacobi迭代,不过,和Gauss-Seidel迭代的实时参数更新不同,松弛迭代在这里是对Jacobi迭代式的批次更新以及Gauss-Seidel迭代式的实时更新取了一个折中,通过一个超参w 来进行参数更新速度的控制。

具体而言,即为:

\left\{ \begin{aligned} x^{(k+1)}_1 &= (1-w)x^{(k)}_1 + w(b_{12}x^{(k)}_2 + b_{13}x^{(k)}_3 + ... + b_{1n}x^{(k)}_n + g_1) \\ x^{(k+1)}_2 &= (1-w)x^{(k)}_2 + w(b_{21}x^{(k+1)}_1 + b_{23}x^{(k)}_3 + ... + b_{2n}x^{(k)}_n + g_2) \\ ... \\ x^{(k+1)}_n &= (1-w)x^{(k)}_n + w(b_{n1}x^{(k+1)}_1 + b_{n2}x^{(k+1)}_2 + ... + b_{n,n-1}x^{(k+1)}_{n-1} + g_n) \end{aligned} \right.

2. 松弛迭代矩阵

同样的,我们给出松弛迭代的数学表达如下:

x^{(k+1)} = (1-w)x^{(k)} + w(\tilde{L}x^{(k+1)} + \tilde{U}x^{(k)} + g)

仿照Gauss-Seidel迭代,我们同样可以给出其迭代矩阵格式如下:

x^{(k+1)} = S_w x^{(k)} + f

其中,

\left\{ \begin{aligned} S_w &= (I + wD^{-1}L)^{-1}[(1-w)I - wD^{-1}U] \\ f &= w(I + wD^{-1}L)^{-1}g \end{aligned} \right.

3. 松弛迭代的收敛条件

而松弛迭代的收敛判断存在如下两个定理:

定理 6.4 松弛迭代收敛的必要条件为0 < w < 2定理 6.5A 为对称正定矩阵,则当0 < w < 2 时,松弛迭代恒收敛; 特别的,当0 < w < 1 时,称其为亚松弛迭代;当1 < w < 2 时,称其为超松弛迭代;当w=1 时,迭代退化为Gauss-Seidel迭代。

4. 伪代码实现

最后,我们同样给出松弛迭代的伪代码实现如下:

代码语言:javascript
复制
def loose_iter(A, y, w=0.5, epsilon=1e-6):
    n = len(A)
    B = [[0 for _ in range(n)] for _ in range(n)]
    g = [0 for _ in range(n)]
    for i in range(n):
        for j in range(n):
            if j == i:
                continue
            B[i][j] = -A[i][j] / A[i][i]
        g[i] = y[i] / A[i][i]
    
    x = [0 for _ in range(n)]
    cnt = 0
    for _ in range(10**6):
        for i in range(n):
            z = (1-w) * x[i] + w * g[i]
            for j in range(n):
                z += w * B[i][j] * x[j]
            if abs(z-x[i]) < epsilon:
                cnt += 1
            else:
                cnt = 0
            x[i] = z

            if cnt >= n:
                break
        if cnt >= n:
            break
    return x

4. 逆矩阵计算

最后,我们来考察一下逆矩阵计算。

逆矩阵的计算原则上来说其实算是上述解线性方程组的一个特殊应用,事实上解n 个单元向量然后将其解拼接一下就能得到我们的逆矩阵了。

我们这里就不进行详述了,只给出python伪代码实现如下:

代码语言:javascript
复制
def cal_inverse_matrix(A):
    n = len(A)
    res = [[0 for _ in range(n)] for _ in range(n)]
    for j in range(n):
        y = [0 for _ in range(n)]
        y[j] = 1
        x = gauss_seidel_iter(A, y)
        for i in range(n):
            res[i][j] = x[i]
    return res
本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-06-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0. 问题描述
  • 1. Jacobi迭代
    • 1. Jacobi迭代方法
      • 2. Jacobi迭代矩阵
        • 3. Jacobi迭代收敛条件
          • 4. python伪代码实现
          • 2. Gauss-Seidel迭代
            • 1. Gauss-Seidel迭代方法
              • 2. Gauss-Seidel迭代矩阵
                • 3. Gauss-Seidel迭代收敛条件
                  • 4. 伪代码实现
                  • 3. 松弛迭代
                    • 1. 松弛迭代方法
                      • 2. 松弛迭代矩阵
                        • 3. 松弛迭代的收敛条件
                          • 4. 伪代码实现
                          • 4. 逆矩阵计算
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
                          http://www.vxiaotou.com