我需要编写一个实现Thomas算法的程序。我的程序编译得很好,但当我与numpy中的np.linalg.solve函数进行比较时我得到了同一系统的不同结果
这是我的代码
import numpy as np
## Tri Diagonal Matrix Algorithm(a.k.a Thomas algorithm) solver
def TDMAsolver(a, b, c, d):
nf = len(d) # number of equations
ac, bc, cc, dc = map(np.array, (a, b, c, d)) # copy arrays
for it in range(1, nf):
mc = ac[it-1]/bc[it-1]
bc[it] = bc[it] - mc*cc[it-1]
dc[it] = dc[it] - mc*dc[it-1]
xc = bc
xc[-1] = dc[-1]/bc[-1]
for il in range(nf-2, -1, -1):
xc[il] = (dc[il]-cc[il]*xc[il+1])/bc[il]
return xc
这就是我测试它的方式
a = np.array([3,3,3,3])
c = np.array([2,2,2,2])
d = np.array([2,2,2,2])
b = np.array([12,17,14,7])
x = TDMAsolver(a,d,c,b)
print(x)
输出
[5 1 0 2]
当我做的时候
a = np.array([3,3,3,3])
c = np.array([2,2,2,2])
d = np.array([2,2,2,2])
b = np.array([12,17,14,7])
A = np.diag(a,0) + np.diag(c[1:],-1) + np.diag(d[1:],1)
x = np.linalg.solve(A,b)
print(x)
输出
[ 2. 3. 2. 1.]
任何猜测为什么会这样?
谢谢
答案 0 :(得分:0)
似乎你纠结于对角线和右列数组目的地(命名,赋值?)。
如果b是主对角线,a是底部对,c是上部,d是右列
b c 0 0 d
a b c 0 d
0 a b c d
0 0 a b d
然后你的代码看起来正确。但是对于linalg.solve的矩阵A收缩呢?你能打印出准备好的矩阵并检查元素位置吗?
答案 1 :(得分:0)
np.linalg.solve
来电的结果是你需要得到的。
您的功能有两个问题:
当使用类型为int
的numpy数组调用它时,对它们(它们的副本)的所有赋值也将导致int
,这意味着中间部分丢失了小数部分计算
它使用第二个参数作为主对角线(即[2,2,2,2]
),同时向np.linalg.solve
传递一个矩阵,其中[3,3,3,3]
是主对角线。
我还建议在全局范围内使用与函数相同的命名约定,因为正如您现在所拥有的那样,在全局范围内调用等式 b 的右侧范围,但在函数中它被称为 d 。全局范围内的 d 在函数中是 b 。这无助于掌握您的代码。
当您查看此作业时,第一个问题变得明显:
bc[it] = bc[it] - mc*cc[it-1]
在第一次迭代中,此计算结果为
bc[it] = 3 - 0.6666666667 * 2
应该是1.6666666667,但是如果你在赋值后检查bc[it]
的值,你会看到它得到值1.这是因为numpy数组保存整数类型的值。
这可以通过替换它来解决:
ac, bc, cc, dc = map(np.array, (a, b, c, d))
使用:
ac, bc, cc, dc = (x.astype(float) for x in (a, b, c, d))
您要解决的等式如下所示:
( 3 2 0 0 ) ( x0 ) ( 12 )
( 2 3 2 0 ) . ( x1 ) = ( 17 )
( 0 2 3 2 ) ( x2 ) ( 14 )
( 0 0 2 3 ) ( x3 ) ( 7 )
您的函数希望这些值出现在参数中,如下所示
( b0 c0 0 0 ) ( x0 ) ( d0 )
( a0 b1 c1 0 ) . ( x1 ) = ( d1 )
( 0 a1 b2 c2 ) ( x2 ) ( d2 )
( 0 0 a2 b3 ) ( x3 ) ( d3 )
协调全局名称,并为数组提供正确的大小 - 有两个数组应该少一个元素:
a = np.array([2,2,2])
b = np.array([3,3,3,3]) # main diagonal
c = np.array([2,2,2])
d = np.array([12,17,14,7]) # right side of equation
x = TDMAsolver(a,b,c,d) # pass in same order
print(x)
为了匹配命名约定和更短的数组,请按如下方式调整代码的验证部分:
A = np.diag(b,0) + np.diag(a,-1) + np.diag(c,1)
x = np.linalg.solve(A,b)
print(x)
两种情况下的解决方案现在都是:
x == [ 2. 3. 2. 1.]
上查看它