具有Numba-nopython模式的三对角矩阵算法

具有Numba-nopython模式的三对角矩阵算法,python,python-3.x,performance,numpy,numba,Python,Python 3.x,Performance,Numpy,Numba,我正试着用nopython模式和numba写一篇文章。这是我的密码: @jit(nopython=True) def TDMA(a、b、c、d): n=len(d) x=np.零(n) w=np.零(n) #ac,bc,cc,dc=map(np.copy,(a,b,c,d))#复制数组 ac=np.副本(a) bc=np.副本(b) cc=np.copy(c) dc=np.副本(d) 对于范围(1,n)内的i: w[i]=ac[i-1]/bc[i-1] bc[i]=bc[i]-w[i]*cc[i

我正试着用nopython模式和numba写一篇文章。这是我的密码:

@jit(nopython=True)
def TDMA(a、b、c、d):
n=len(d)
x=np.零(n)
w=np.零(n)
#ac,bc,cc,dc=map(np.copy,(a,b,c,d))#复制数组
ac=np.副本(a)
bc=np.副本(b)
cc=np.copy(c)
dc=np.副本(d)
对于范围(1,n)内的i:
w[i]=ac[i-1]/bc[i-1]
bc[i]=bc[i]-w[i]*cc[i-1]
dc[i]=dc[i]-w[i]*dc[i-1]
x[n-1]=dc[n-1]/bc[n-1]
对于范围(n-2,-1,-1)内的k:
x[k]=(dc[k]-cc[k]*x[k+1])/bc[k]
返回np.array(x)
然后测试该解算器:

A=np.array([[5,2,0,0],[1,5,2,0],[0,1,5,2],[0,0,1,5]],float)
B=np.数组([[15]、[2]、[7]、[20]、浮点)
a=a.对角线(-1)
b=A.对角线()
c=A.对角线(1)
x1=np.linalg.solve(A,B)
x2=TDMA(a、b、c、b)
打印('默认情况下解算器,x1=',x1)
打印('按TDMA,x2=',x2)
但是,我的TDMA功能失败,出现
打字机错误

TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Cannot resolve setitem: array(float64, 1d, C)[int64] = array(float64, 1d, C)

File "<ipython-input-20-e25cda7246bd>", line 16:
def TDMA(a,b,c,d):
    <source elided>

  x[n-1] = dc[n-1]/bc[n-1]
  ^
nopython
也不兼容。是否可以在
nopython
模式下使用
map
功能


我知道我的TDMA可能仍然很慢。那么,有没有一种使用python 3语言实现三对角矩阵算法的最快代码?

问题是,您有2D数组,但索引和分配它们就像是1D数组一样。因此,在将它们传递给numba函数之前,您可以只
ravel()
它们。我不确定这是否真的是正确的——但为了这个答案,我假设它是正确的

另外,您不需要复制
a
c
,因为您不修改它们,实际上只需要复制
b
d
的第一个元素

因此,工作函数可能如下所示:

import numba as nb
import numpy as np

@nb.njit
def TDMA(a,b,c,d):
    n = len(d)
    x = np.zeros(n)
    bc = np.zeros(len(b))
    bc[0] = b[0]
    dc = np.zeros(len(d))
    dc[0] = d[0]
    
    for i in range(1, n):
        w = a[i - 1] / bc[i - 1]
        bc[i] = b[i] - w * c[i - 1]
        dc[i] = d[i] - w * dc[i - 1]

    x[n - 1] = dc[n - 1] / bc[n - 1]
    for k in range(n - 2, -1, -1):
        x[k] = (dc[k] - c[k] * x[k + 1]) / bc[k]
    return x
TDMA(a.ravel(), b.ravel(), c.ravel(), B.ravel())
你这样称呼它:

import numba as nb
import numpy as np

@nb.njit
def TDMA(a,b,c,d):
    n = len(d)
    x = np.zeros(n)
    bc = np.zeros(len(b))
    bc[0] = b[0]
    dc = np.zeros(len(d))
    dc[0] = d[0]
    
    for i in range(1, n):
        w = a[i - 1] / bc[i - 1]
        bc[i] = b[i] - w * c[i - 1]
        dc[i] = d[i] - w * dc[i - 1]

    x[n - 1] = dc[n - 1] / bc[n - 1]
    for k in range(n - 2, -1, -1):
        x[k] = (dc[k] - c[k] * x[k + 1]) / bc[k]
    return x
TDMA(a.ravel(), b.ravel(), c.ravel(), B.ravel())
因为我使用了
ravel()
结果与
np.linalg.solve
的形状不同:

by default solver, x1 =  [[ 3.05427975]
 [-0.13569937]
 [-0.18789144]
 [ 4.03757829]]
by TDMA, x2 =  [ 3.05427975 -0.13569937 -0.18789144  4.03757829]
然而,我真的不会重新实现NumPy函数,除非您可以利用NumPy函数不知道的数据结构。NumPy是一个高性能的库,它已经使用了非常精细的实现,因此,对于非常小的数据集,或者如果您可以利用数据的某些事实(允许使用非常高性能的算法),临时重新实现可能会更快

我必须承认,我不知道“三对角矩阵算法”,但我知道一些(通常难以置信的快速数学库)实现了它。NumPy使用BLAS

但是,SciPy为特殊矩阵类型提供了一些(非常快速的)特殊线性代数解算器:

  • inv(a[,overwrite\u a,check\u finite])
    计算矩阵的逆
  • solve(a,b[,sym_pos,lower,overwrite_a,…])
    为方阵的未知x求解线性方程组a*x=b
  • solve_banded(l_和_,ab,b[,overwrite_ab,…])
    假设a是带状矩阵,求解x的方程a x=b
  • solveh_banded(ab,b[,overwrite_ab,…])
    求解方程a x=b
  • solve_循环(c,b[,奇异,tol,…])
    solve cx=b for x,其中c是循环矩阵
  • 求解_三角形(a,b[,trans,lower,…])
    假设a是三角形矩阵,求解方程a x=b for x
  • 使用Levinson递归求解toeplitz系统
[……]

关于
map
的问题:现任官员不包括
map
。因此,您不能在Numbas nopython模式下使用
map