線性方程組的迭代法 python代碼實現


第一次寫博客,時間不多,所以原理什麼的就不寫了。
直接貼代碼和實例演示,以下代碼基於python和numpy。
解釋就一張圖。
設有線性方程組 Ax = b,其中A非奇異, 且 aii不等於0, (i = 1, 2, …, n )。
設有線性方程組 Ax = b,其中A非奇異, 且 aii不等於0, (i = 1, 2, …, n )。

這裏十分詳細的講解了“迭代法求解線性方程組”。

Jacobi迭代法

首先

import numpy as np

以下便是我定義的函數:

def jacobi(a,b,c=0.0001,d=30):
    x1=np.zeros(a.shape[1])
    x2=np.zeros(a.shape[1])
    k=0
    while k<d:
        k=k+1
        print('k=',k)
        for i in range(a.shape[1]):
            x2[i]=(-a[i].dot(x1)+b[i]+a[i,i]*x1[i])/a[i,i]
        if np.max(np.abs(x2-x1))<=c:
            print("x%d=" % k,x2)
            print(np.max(np.abs(x2-x1)))
            break
        print("x%d=" % k,x2)
        x1=x2.copy()
	return x2

參數說明

“a”就是“A”,“b”就是“b”,和上圖對應。

c是一個跳出循環的限定值。

d是最大迭代次數。

實例運行

拿個實例運行一下。

a=np.array([[2,-1,0,0],
          [-1,2.5,-1,0],
           [0,-1,2.5,-1],
           [0,0,-1,2]])
b=np.array([-4,4,4,-4])
jacobi(a,b)

得出以下結果:

k= 1
x1= [-2. 1.6 1.6 -2. ]
k= 2
x2= [-1.2 1.44 1.44 -1.2 ]
k= 3
x3= [-1.28 1.696 1.696 -1.28 ]
k= 4
x4= [-1.152 1.7664 1.7664 -1.152 ]
k= 5
x5= [-1.1168 1.84576 1.84576 -1.1168 ]
k= 6
x6= [-1.07712 1.891584 1.891584 -1.07712 ]
k= 7
x7= [-1.054208 1.9257856 1.9257856 -1.054208 ]
k= 8
x8= [-1.0371072 1.94863104 1.94863104 -1.0371072 ]
k= 9
x9= [-1.02568448 1.96460954 1.96460954 -1.02568448]
k= 10
x10= [-1.01769523 1.97557002 1.97557002 -1.01769523]
k= 11
x11= [-1.01221499 1.98314992 1.98314992 -1.01221499]
k= 12
x12= [-1.00842504 1.98837397 1.98837397 -1.00842504]
k= 13
x13= [-1.00581301 1.99197957 1.99197957 -1.00581301]
k= 14
x14= [-1.00401021 1.99446662 1.99446662 -1.00401021]
k= 15
x15= [-1.00276669 1.99618256 1.99618256 -1.00276669]
k= 16
x16= [-1.00190872 1.99736635 1.99736635 -1.00190872]
k= 17
x17= [-1.00131683 1.99818305 1.99818305 -1.00131683]
k= 18
x18= [-1.00090847 1.99874649 1.99874649 -1.00090847]
k= 19
x19= [-1.00062675 1.99913521 1.99913521 -1.00062675]
k= 20
x20= [-1.0004324 1.99940338 1.99940338 -1.0004324 ]
k= 21
x21= [-1.00029831 1.99958839 1.99958839 -1.00029831]
k= 22
x22= [-1.0002058 1.99971603 1.99971603 -1.0002058 ]
k= 23
x23= [-1.00014198 1.99980409 1.99980409 -1.00014198]
8.805852909499201e-05

Gauss-Seidel迭代法

定義的函數如下:

def Gauss_Seidel(a,b,c=0.0001,d=30):
    x1=np.zeros(a.shape[1])
    x2=np.zeros(a.shape[1])
    k=0
    while k<d:
        k=k+1
        print('k=',k)
        for i in range(a.shape[1]):
            x2[i]=(-a[i].dot(x2)+b[i]+a[i,i]*x2[i])/a[i,i]
        if np.max(np.abs(x2-x1))<=c:
            print("x%d=" % k,x2)
            print(np.max(np.abs(x2-x1)))
            break
        print("x%d=" % k,x2)
        x1=x2.copy()
	return x2

實例運行

拿同一個實例運行一下。

a=np.array([[2,-1,0,0],
          [-1,2.5,-1,0],
           [0,-1,2.5,-1],
           [0,0,-1,2]])
b=np.array([-4,4,4,-4])
Gauss_Seidel(a,b)

得到如下結果:

k= 1
x1= [-2. 0.8 1.92 -1.04]
k= 2
x2= [-1.6 1.728 1.8752 -1.0624]
k= 3
x3= [-1.136 1.89568 1.933312 -1.033344]
k= 4
x4= [-1.05216 1.9524608 1.96764672 -1.01617664]
k= 5
x5= [-1.0237696 1.97755085 1.98454968 -1.00772516]
k= 6
x6= [-1.01122458 1.98933004 1.99264195 -1.00367902]
k= 7
x7= [-1.00533498 1.99492279 1.99649751 -1.00175125]
k= 8
x8= [-1.0025386 1.99758356 1.99833293 -1.00083354]
k= 9
x9= [-1.00120822 1.99884988 1.99920654 -1.00039673]
k= 10
x10= [-1.00057506 1.99945259 1.99962234 -1.00018883]
k= 11
x11= [-1.0002737 1.99973946 1.99982025 -1.00008987]
k= 12
x12= [-1.00013027 1.99987599 1.99991445 -1.00004278]
k= 13
x13= [-1.000062 1.99994098 1.99995928 -1.00002036]
6.826783096514077e-05

SOR迭代法

定義的函數如下:

def SOR(a,b,w=1,c=0.0001,d=30):
    x1=np.zeros(a.shape[1])
    x2=np.zeros(a.shape[1])
    k=0
    while k<d:
        k=k+1
        print('k=',k)
        for i in range(a.shape[1]):
            x2[i]=(-a[i].dot(x2)+b[i])*w/a[i,i]+x2[i]
        if np.max(np.abs(x2-x1))<=c:
            print("x%d=" % k,x2)
            print(np.max(np.abs(x2-x1)))
            break
        print("x%d=" % k,x2)
        x1=x2.copy()
	return x2

參數說明

w是鬆弛因子。

實例運行

拿同一個實例運行一下。

a=np.array([[2,-1,0,0],
          [-1,2.5,-1,0],
           [0,-1,2.5,-1],
           [0,0,-1,2]])
b=np.array([-4,4,4,-4])
w=1.16
SOR(a,b,w)

得到如下結果:

k= 1
x1= [-2.32 0.77952 2.21769728 -1.03373558]
k= 2
x2= [-1.4966784 2.06582956 1.98006004 -1.00616748]
k= 3
x3= [-0.88235031 2.03480459 2.01647801 -0.98945596]
k= 4
x4= [-0.99863729 2.00270936 2.0035131 -0.99964945]
k= 5
x5= [-0.9986466 2.00182455 2.00044715 -0.99979674]
k= 6
x6= [-0.9991583 2.0003061 2.0001648 -0.99993694]
k= 7
x7= [-0.99995713 2.00004738 2.00002488 -0.99999566]
k= 8
x8= [-0.99997938 2.00001353 2.00000431 -0.99999819]
3.3849332815805155e-05

總結

綜上可知,同一個實例,在速度上,SOR迭代法>Gauss-Seidel迭代法>Jacobi迭代法。當然,前提是三者均需滿足收斂條件。

迭代法收斂的充要條件如下圖所示。
迭代法收斂的充要條件

以上便是我(爲了不用一步一步按計算器來寫作業)寫的三種迭代方法的定義函數,可能會有更簡單,可以評論一番,多多加交流。

本來是爲了補數學作業,想GKD,沒想到出了點bug(根本就沒幾行代碼,還出了bug。。。),吃了箇中午飯才大概想到了“x1=x2”應該有問題。

不過塞翁司馬,焉知禍福,填補了空白也不錯。

可謂是前人栽樹,後人乘涼。

擴展

2020.3.27

不少同學注意到了我在函數中,默認的初始值爲0向量,問我能不能自己定義初始值,怎麼定義初始值。所以我對Jacobi函數做了如下修改。

def jacobi_pro(a,b,x0=np.zeros(a.shape[1]),c=0.0001,d=30):
    print('x0=',x0)
    x1=np.zeros(a.shape[1])
    k=0
    while k<d:
        k+=1
        print('k=',k)
        for i in range(a.shape[1]):
            x1[i]=(-a[i].dot(x0)+b[i]+a[i,i]*x0[i])/a[i,i]
        if np.max(np.abs(x0-x1))<=c:
            print("x%d=" % k,x1)
            print(np.max(np.abs(x0-x1)))
            break
        print("x%d=" % k,x1)
        x0=x1.copy()
    return x1

拿同一個實例運行一下,將初始值設爲單位向量。

a=np.array([[2,-1,0,0],
          [-1,2.5,-1,0],
           [0,-1,2.5,-1],
           [0,0,-1,2]])
b=np.array([-4,4,4,-4])
x=np.ones(a.shape[1])
jacobi_pro(a,b,x)

得到如下結果:

x0= [1. 1. 1. 1.]
k= 1
x1= [-1.5 2.4 2.4 -1.5]
k= 2
x2= [-0.8 1.96 1.96 -0.8 ]
k= 3
x3= [-1.02 2.064 2.064 -1.02 ]
k= 4
x4= [-0.968 2.0176 2.0176 -0.968 ]
k= 5
x5= [-0.9912 2.01984 2.01984 -0.9912 ]
k= 6
x6= [-0.99008 2.011456 2.011456 -0.99008 ]
k= 7
x7= [-0.994272 2.0085504 2.0085504 -0.994272 ]
k= 8
x8= [-0.9957248 2.00571136 2.00571136 -0.9957248 ]
k= 9
x9= [-0.99714432 2.00399462 2.00399462 -0.99714432]
k= 10
x10= [-0.99800269 2.00274012 2.00274012 -0.99800269]
k= 11
x11= [-0.99862994 2.00189497 2.00189497 -0.99862994]
k= 12
x12= [-0.99905251 2.00130601 2.00130601 -0.99905251]
k= 13
x13= [-0.99934699 2.0009014 2.0009014 -0.99934699]
k= 14
x14= [-0.9995493 2.00062176 2.00062176 -0.9995493 ]
k= 15
x15= [-0.99968912 2.00042899 2.00042899 -0.99968912]
k= 16
x16= [-0.99978551 2.00029595 2.00029595 -0.99978551]
k= 17
x17= [-0.99985203 2.00020418 2.00020418 -0.99985203]
9.17709429146818e-05

這個結果與最初的結果相比,迭代次數少了26.1%,所以初始值對迭代次數的影響也是蠻大的。

其它兩種迭代法的修改方式和Jacobi是一樣,在此我就不再贅述了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章