迭代法简介
迭代法也称辗转法,是一种不断用变量的旧值递推新值的过程,跟迭代法相对应的是直接法(或者称为一次解法),即一次性解决问题。迭代算法是用计算机解决问题的一种基本方法,它利用计算机运算速度快、适合做重复性操作的特点,让计算机对一组指令(或一定步骤)进行重复执行,在每次执行这组指令(或这些步骤)时,都从变量的原值推出它的一个新值,迭代法又分为精确迭代和近似迭代。比较典型的迭代法如“二分法”和"牛顿迭代法”属于近似迭代法。
Jacobi迭代
以如下方程组为例:
10
x
1
−
2
x
2
−
x
3
=
3
10x{_1}-2x{_2}-x{_3}=3
10x1−2x2−x3=3
−
2
x
1
+
10
x
2
−
x
3
=
15
-2x{_1}+10x{_2}-x{_3}=15
−2x1+10x2−x3=15
−
1
x
1
−
2
x
2
−
5
x
3
=
10
-1x{_1}-2x{_2}-5x{_3}=10
−1x1−2x2−5x3=10
高斯消元法(高中用的那种)可以算出结果分别为1,2,3
Jacobi的计算过程:
先对每行分别进行变换,左边分别只留下
x
1
、
x
2
、
x
3
x{_1}、x{_2}、x{_3}
x1、x2、x3:
x
1
=
0.2
x
2
+
0.1
x
3
+
0.3
x{_1}=0.2x{_2}+0.1x{_3}+0.3
x1=0.2x2+0.1x3+0.3
x
2
=
0.2
x
1
+
0.1
x
3
+
1.5
x{_2}=0.2x{_1}+0.1x{_3}+1.5
x2=0.2x1+0.1x3+1.5
x
3
=
0.2
x
1
+
0.4
x
2
+
2
x{_3}=0.2x{_1}+0.4x{_2}+2
x3=0.2x1+0.4x2+2
相信大家到这一步都会,那么我们就开始分别计算
x
1
、
x
2
、
x
3
x{_1}、x{_2}、x{_3}
x1、x2、x3的值吧。
先设 x 1 、 x 2 、 x 3 x{_1}、x{_2}、x{_3} x1、x2、x3都为0,第一次迭代,他们的结果分别为: 0.3 、 1.5 、 2 0.3、1.5、2 0.3、1.5、2
然后把
0.3
、
1.5
、
2
0.3、1.5、2
0.3、1.5、2分别带入
x
1
、
x
2
、
x
3
x{_1}、x{_2}、x{_3}
x1、x2、x3计算,则:
x
1
=
0.2
x
2
+
0.1
x
3
+
0.3
=
0.2
∗
1.5
+
0.1
∗
2
+
0.3
=
0.8
x{_1}=0.2x{_2}+0.1x{_3}+0.3=0.2*1.5+0.1*2+0.3=0.8
x1=0.2x2+0.1x3+0.3=0.2∗1.5+0.1∗2+0.3=0.8
x
2
=
0.2
x
1
+
0.1
x
3
+
1.5
=
0.2
∗
0.3
+
0.1
∗
0.2
+
1.5
=
1.76
x{_2}=0.2x{_1}+0.1x{_3}+1.5=0.2*0.3+0.1*0.2+1.5=1.76
x2=0.2x1+0.1x3+1.5=0.2∗0.3+0.1∗0.2+1.5=1.76
x
3
=
0.2
x
1
+
0.4
x
2
+
2
=
0.2
∗
0.3
+
0.4
∗
1.5
+
2
=
2.66
x{_3}=0.2x{_1}+0.4x{_2}+2=0.2*0.3+0.4*1.5+2=2.66
x3=0.2x1+0.4x2+2=0.2∗0.3+0.4∗1.5+2=2.66
迭代10次可得结果如下:
次数 | x 1 x{_1} x1 | x 2 x{_2} x2 | x 3 x{_3} x3 |
---|---|---|---|
1 | 0.3 | 1.5 | 2.0 |
2 | 0.8 | 1.76 | 2.66 |
3 | 0.918 | 1.926 | 2.864 |
4 | 0.972 | 1.97 | 2.954 |
5 | 0.989 | 1.99 | 2.982 |
6 | 0.996 | 1.996 | 2.994 |
7 | 0.999 | 1.999 | 2.998 |
8 | 1.0 | 2.0 | 2.999 |
9 | 1.0 | 2.0 | 3.0 |
10 | 1.0 | 2.0 | 3.0 |
其python代码如下:
x1=0
x2=0
x3=0
print('Jacobi')
for i in range(10):
x11=round(0.2*x2+0.1*x3+0.3,3)
x22=round(0.2*x1+0.1*x3+1.5,3)
x33=round(0.2*x1+0.4*x2+2,3)
print('|',i+1,'|',x11,'|',x22,'|',x33,'|')
x1=x11
x2=x22
x3=x33
其中round是将结果保留3位小数。
上面这个过程叫Jacobi迭代。
Gauss-Seidel迭代
高斯迭代唯一的区别在于,在每次迭代的过程中,都使用最新的值,直接上代码大家应该也可以看明白:
x1=0
x2=0
x3=0
print('Gauss-Seidel')
for i in range(10):
x1=round(0.2*x2+0.1*x3+0.3,3)
x2=round(0.2*x1+0.1*x3+1.5,3)
x3=round(0.2*x1+0.4*x2+2,3)
print('|',i+1,'|',x1,'|',x2,'|',x3,'|')
其10次迭代的结果如下:
次数 | x 1 x{_1} x1 | x 2 x{_2} x2 | x 3 x{_3} x3 |
---|---|---|---|
1 | 0.3 | 1.56 | 2.684 |
2 | 0.88 | 1.944 | 2.954 |
3 | 0.984 | 1.992 | 2.994 |
4 | 0.998 | 1.999 | 2.999 |
5 | 1.0 | 2.0 | 3.0 |
6 | 1.0 | 2.0 | 3.0 |
7 | 1.0 | 2.0 | 3.0 |
8 | 1.0 | 2.0 | 3.0 |
9 | 1.0 | 2.0 | 3.0 |
10 | 1.0 | 2.0 | 3.0 |
可以看到,只用5次就得到了正确的结果。
所以这里可以发现,高斯迭代法使用的空间小,并且计算速度快。
例2
为了计算复用,可以将函数封装一下:
#1.(1)
data=[
[10,-2,-1,3],
[-2,10,-1,15],
[-1,-2,5,10]
]
x=zeros(3)
xx=zeros(3)
print('Jacobi')
for i in range(10):
xx[0]=round((-data[0][1]*x[1]-data[0][2]*x[2]+data[0][3])/data[0][0],3)
xx[1]=round((-data[1][0]*x[0]-data[1][2]*x[2]+data[1][3])/data[1][1],3)
xx[2]=round((-data[2][0]*x[0]-data[2][1]*x[1]+data[2][3])/data[2][2],3)
x[0]=xx[0];x[1]=xx[1];x[2]=xx[2]
print('|',i+1,'|',x[0],'|',x[1],'|',x[2],'|')
#print(i+1,x[0],x[1],x[2])
x=zeros(3)
print('Gauss-Seidel')
for i in range(10):
x[0]=round((-data[0][1]*x[1]-data[0][2]*x[2]+data[0][3])/data[0][0],3)
x[1]=round((-data[1][0]*x[0]-data[1][2]*x[2]+data[1][3])/data[1][1],3)
x[2]=round((-data[2][0]*x[0]-data[2][1]*x[1]+data[2][3])/data[2][2],3)
print('|',i+1,'|',x[0],'|',x[1],'|',x[2],'|')
#print(i+1,x[0],x[1],x[2])
得到的结果和上面一致:
Jacobi:
次数 | x 1 x{_1} x1 | x 2 x{_2} x2 | x 3 x{_3} x3 |
---|---|---|---|
1 | 0.3 | 1.5 | 2.0 |
2 | 0.8 | 1.76 | 2.66 |
3 | 0.918 | 1.926 | 2.864 |
4 | 0.972 | 1.97 | 2.954 |
5 | 0.989 | 1.99 | 2.982 |
6 | 0.996 | 1.996 | 2.994 |
7 | 0.999 | 1.999 | 2.998 |
8 | 1.0 | 2.0 | 2.999 |
9 | 1.0 | 2.0 | 3.0 |
10 | 1.0 | 2.0 | 3.0 |
Gauss-Seidel:
次数 | x 1 x{_1} x1 | x 2 x{_2} x2 | x 3 x{_3} x3 |
---|---|---|---|
1 | 0.3 | 1.56 | 2.684 |
2 | 0.88 | 1.944 | 2.954 |
3 | 0.984 | 1.992 | 2.994 |
4 | 0.998 | 1.999 | 2.999 |
5 | 1.0 | 2.0 | 3.0 |
6 | 1.0 | 2.0 | 3.0 |
7 | 1.0 | 2.0 | 3.0 |
8 | 1.0 | 2.0 | 3.0 |
9 | 1.0 | 2.0 | 3.0 |
10 | 1.0 | 2.0 | 3.0 |
上面这个例子是《数值计算方法》第二版 北京理工大学出版社 习题三的1(1),下面计算1(1)。
只需要修改数据:
#1.(2)
data=[
[8,-3,2,20],
[4,11,-1,33],
[2,1,4,12]
]
运行结果如下:
Jacobi:
次数 | x 1 x{_1} x1 | x 2 x{_2} x2 | x 3 x{_3} x3 |
---|---|---|---|
1 | 2.5 | 3.0 | 3.0 |
2 | 2.875 | 2.364 | 1.0 |
3 | 3.136 | 2.045 | 0.971 |
4 | 3.024 | 1.948 | 0.921 |
5 | 3.0 | 1.984 | 1.001 |
6 | 2.994 | 2.0 | 1.004 |
7 | 2.999 | 2.003 | 1.003 |
8 | 3.0 | 2.001 | 1.0 |
9 | 3.0 | 2.0 | 1.0 |
10 | 3.0 | 2.0 | 1.0 |
Gauss-Seidel:
次数 | x 1 x{_1} x1 | x 2 x{_2} x2 | x 3 x{_3} x3 |
---|---|---|---|
1 | 2.5 | 2.091 | 1.227 |
2 | 2.977 | 2.029 | 1.004 |
3 | 3.01 | 1.997 | 0.996 |
4 | 3.0 | 2.0 | 1.0 |
5 | 3.0 | 2.0 | 1.0 |
6 | 3.0 | 2.0 | 1.0 |
7 | 3.0 | 2.0 | 1.0 |
8 | 3.0 | 2.0 | 1.0 |
9 | 3.0 | 2.0 | 1.0 |
10 | 3.0 | 2.0 | 1.0 |
可以看出高斯法只需要4次就有结果了。
例3
以习题三的3题为例:
data=[
[1,2,-2,1],
[1,1,1,1],
[2,2,1,1]
]
其结果如下:
Jacobi:
次数 | x 1 x{_1} x1 | x 2 x{_2} x2 | x 3 x{_3} x3 |
---|---|---|---|
1 | 1.0 | 1.0 | 1.0 |
2 | 1.0 | -1.0 | -3.0 |
3 | -3.0 | 3.0 | 1.0 |
4 | -3.0 | 3.0 | 1.0 |
5 | -3.0 | 3.0 | 1.0 |
6 | -3.0 | 3.0 | 1.0 |
7 | -3.0 | 3.0 | 1.0 |
8 | -3.0 | 3.0 | 1.0 |
9 | -3.0 | 3.0 | 1.0 |
10 | -3.0 | 3.0 | 1.0 |
Gauss-Seidel:
次数 | x 1 x{_1} x1 | x 2 x{_2} x2 | x 3 x{_3} x3 |
---|---|---|---|
1 | 1.0 | 0.0 | -1.0 |
2 | -1.0 | 3.0 | -3.0 |
3 | -11.0 | 15.0 | -7.0 |
4 | -43.0 | 51.0 | -15.0 |
5 | -131.0 | 147.0 | -31.0 |
6 | -355.0 | 387.0 | -63.0 |
7 | -899.0 | 963.0 | -127.0 |
8 | -2179.0 | 2307.0 | -255.0 |
9 | -5123.0 | 5379.0 | -511.0 |
10 | -11779.0 | 12291.0 | -1023.0 |
可以看出Jacobi迭代法迭代3次就能计算出答案,而Gauss-Seidel法得到的结果却发散了,可见Gauss-Seidel在使用时还有一定的要求。
上述内容是本人课程学习随笔,如有错误欢迎指出,共同学习。