0
点赞
收藏
分享

微信扫一扫

Python实现Gauss-Seidel迭代法

钎探穗 2022-03-26 阅读 68

在雅可比(Jacobi)迭代法的基础上,通过修改其中逻辑使其成为Gauss-seidel迭代法。通过输入系数矩阵mx,值矩阵mr,最大迭代次数n,目标误差e即可得到答案。

代码如下:

import numpy as np


def Astringency(mx):  # 判断系数矩阵的收敛性
    L, D, U = [], [], []  # 初始化L,D,U矩阵
    for i in range(len(mx)):
        L.append([]), D.append([]), U.append([])
        for j in range(len(mx)):
            if i > j:
                L[i].append(mx[i][j]), D[i].append(0), U[i].append(0)
            if i == j:
                L[i].append(0), D[i].append(mx[i][j]), U[i].append(0)
            if i < j:
                L[i].append(0), D[i].append(0), U[i].append(mx[i][j])
    # print(L)
    # print(D)
    # print(U)
    ld = L  # 计算D+L矩阵
    for i in range(len(mx)):
        for k in range(len(mx)):
            ld[i][k] = L[i][k] + D[i][k]
    # print(ld)
    # print(-np.linalg.inv(ld))
    # print(D)
    G = np.dot(-np.linalg.inv(ld), U)  # 得到G矩阵
    # print(G)
    e, v = np.linalg.eig(G)
    # print(e)
    for i in range(len(e)):
        count = 0  # 计算不小于一的特征值的数量
        if abs(e[i]) < 1:
            continue
        else:
            count = count + 1
            print(abs(e[i]))
    # print(count)
    if count == 0:
        return True
    else:
        print("迭代法不收敛")
        return False


def Gauss_seidel(mx, mr, n=100, e=0.0001):  # mx为系数矩阵,mr为值矩阵,n为默认迭代次数,e为默认误差返回
    if len(mx) == len(mr):  # 若mx与mr长度相等则开始迭代,否则方程无解
        if Astringency(mx) == 1:  # 判断系数矩阵mx是否收敛
            x = []
            for i in range(len(mr)):
                x.append([0])  # 得到长度与mr相等的初值,并且把初值设定为零
            count = 0  # 迭代次数计数
            while count < n:  # 没有达到迭代次数时继续迭代
                tempx = np.copy(x)  # tempx用于存储迭代前的x值,但又不指向同一对象,用于后面的误差计算
                for i in range(len(x)):
                    ri = mr[i][0]
                    for k in range(len(mx[i])):
                        if k != i:
                            ri = ri - mx[i][k] * x[k][0]
                    ri = ri / mx[i][i]
                    x[i][0] = ri  # 每次计算存储单个x值
                print("第{}次迭代的值为:{}".format(count + 1, x))
                ee = []  # 存储每两次迭代结果之间的误差
                for i in range(len(x)):
                    # print(x[i][0])
                    # print(tempx[i][0])
                    ee.append(abs(x[i][0] - tempx[i][0]))
                em = max(ee)  # 取最大误差值
                print("第{}、{}次迭代间误差值为:{}".format(count, count + 1, em))
                if em < e:
                    return x  # 当两次迭代的x的最大误差满足要求时,直接返回计算结果
                count += 1
            return False  # 当运行到最大迭代次数时精度仍不满足要求则返回错误

        else:
            print("使用迭代法不收敛")
    else:
        print("此方程无解")


mx = [[5, 2, 1], [-1, 4, 2], [2, -5, 10]]
# # print(len(mx))

mr = [[-12], [10], [1]]
# print(len(mr))
print(Gauss_seidel(mx, mr, 100, 0.0001))

注意点:存储前一次迭代解时,若采用tempx=x,tempx与x将指向同一对象,会使迭代无法往下进行。解决方法:采用tempx=np.copy(x)创建唯一副本。

实现结果:

1次迭代的值为:[[-2.4], [1.9], [1.53]]01次迭代间误差值为:2.42次迭代的值为:[[-3.466], [0.8684999999999999], [1.22745]]12次迭代间误差值为:1.06600000000000033次迭代的值为:[[-2.99289], [1.1380525000000001], [1.2676042500000002]]23次迭代间误差值为:0.473110000000000144次迭代的值为:[[-3.1087418500000004], [1.0890124124999998], [1.26625457625]]34次迭代间误差值为:0.115851850000000315次迭代的值为:[[-3.08885588025], [1.0946587418125002], [1.2651005469562502]]45次迭代间误差值为:0.0198859697500002326次迭代的值为:[[-3.09088360611625], [1.0947288249928122], [1.265541133719656]]56次迭代间误差值为:0.00202772586624977447次迭代的值为:[[-3.090999756741056], [1.094479493954908], [1.2654396983256653]]67次迭代间误差值为:0.000249331037904143578次迭代的值为:[[-3.090879737247096], [1.0945602165253931], [1.2654560557121157]]78次迭代间误差值为:0.000120019493960121799次迭代的值为:[[-3.0909152977525802], [1.094543147705797], [1.2654546334034145]]89次迭代间误差值为:3.55605054842556e-05
[[-3.0909152977525802], [1.094543147705797], [1.2654546334034145]]

Jacobi迭代法与Gauss-Seidel迭代法比较:
仅此例子比较,Jacobi迭代法进行二十次迭代后达到目标精度,而Gauss-Seidel迭代法仅经过十次迭代后就到达了目标精度。从该例子比较Gauss-Seidel迭代法迭代速度更加快,可能的原因是Gauss-Seidel迭代法的计算数值处于一直更新迭代状态,因此迭代速度较快。

举报

相关推荐

0 条评论