Thomas Solver算法Python 3

时间:2017-01-22 06:44:31

标签: python algorithm python-3.x numpy

我需要编写一个实现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.]

任何猜测为什么会这样?

谢谢

2 个答案:

答案 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 。这无助于掌握您的代码。

1。避免截断为整数

当您查看此作业时,第一个问题变得明显:

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))

2。命名并传递变量

您要解决的等式如下所示:

( 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.]

ideone.com

上查看它