nopython模式下Numba的递归函数出错
我想在Numba中运行一个递归函数,使用nopython模式。到现在为止,我只会犯错误。这是一个非常简单的代码,用户给出一个少于五个元素的元组,然后函数创建另一个元组,并在元组中添加一个新值(在本例中为数字3)。重复此操作,直到最后一个元组的长度为5。由于某种原因,这不起作用,不知道为什么nopython模式下Numba的递归函数出错,python,python-3.x,recursion,tuples,numba,Python,Python 3.x,Recursion,Tuples,Numba,我想在Numba中运行一个递归函数,使用nopython模式。到现在为止,我只会犯错误。这是一个非常简单的代码,用户给出一个少于五个元素的元组,然后函数创建另一个元组,并在元组中添加一个新值(在本例中为数字3)。重复此操作,直到最后一个元组的长度为5。由于某种原因,这不起作用,不知道为什么 @njit def tup(a): 如果len(a)==5: 归还 其他: b=a+(3,) b=tup(b) 返回b 例如,如果a=(0,1),我希望最终结果是tuple(0,1,3,3) 编辑:我使用的
@njit
def tup(a):
如果len(a)==5:
归还
其他:
b=a+(3,)
b=tup(b)
返回b
例如,如果a=(0,1)
,我希望最终结果是tuple(0,1,3,3)
编辑:我使用的是Numba 0.41.0,我得到的错误是内核正在死亡,“内核似乎已经死亡。”。它将自动重新启动。根据当前版本:
numba中的递归支持目前仅限于使用
函数的显式类型注释。这个限制来自于
无法确定递归调用的返回类型
因此,不妨尝试:
from numba import jit
@jit()
def tup(a:tuple) -> tuple:
if len(a) == 5:
return a
return tup(a + (3,))
print(tup((0, 1)))
看看这是否对你有好处。你不应该这么做有几个原因:
- 这通常是一种在纯Python中可能比在numba修饰函数中更快的方法
- 迭代将更简单,可能更快,但是要注意,连元组通常是一个
操作,即使在numba中也是如此。因此,该函数的总体性能将是O(n)
。这可以通过使用支持O(n**2)
附录的数据结构或支持预分配大小的数据结构来改进。或者干脆不使用“循环”或“递归”方法O(1)
- 您是否尝试过如果省略
decorator并传入包含6个元素的元组会发生什么情况?(提示:它将达到递归限制,因为它永远不会满足递归的结束条件)njit
元组(int64 x 2)
,但是递归调用尝试传入一个不同类型的元组(int64 x 3)
。奇怪的是,它在我的电脑上遇到了一个StackOverflow
,这看起来像是numba中的一个bug
我的建议是使用这个(无numba,无递归):
请不要忘记显示您会遇到什么样的错误。包括numba版本也可能有帮助,因为numba仍在积极开发中,并且支持的功能集正在快速发展。运行它时,这真的有效吗?我只是试着运行代码,至少是在我的机器上,它只会产生堆栈溢出。你的numba版本是什么?@MSeifert,我刚刚访问了numba网站和他们的“在线试用”jupyter页面。在那里,有注释对我很有效,但没有注释就不行。我所知道的都很有趣谢谢你的解释。但是它在nopython模式下也会失败。非常感谢你的回答。事实上,这段代码并不完全是我想要运行的,它只是我试图做的有问题的部分。最初的问题是在多维数组的条目上运行任意嵌套循环。由于循环的数量可能不同,我在进行递归调用,每个调用进入下一个循环,并相应地构造(多)索引。如果我只传递具有最终大小的元组,一切都会变得更简单,我可以在开始循环之前知道它的大小,问题是元组是不可变的,所以我不能将索引的值赋给它们。我可以使用数组而不是元组,并且可以分配新值,但我不能使用索引数组,比如[1,2,0,0,1]来访问多维M的值M[1,2,0,0,1]。numba也不允许我将数组转换为元组。。。我也找不出一个列表解决方案…似乎每种方法都有一些细节阻止我去做我想做的事情。无论如何,我已经看到纯python在递归方面实际上比numba更快,正如你所说的。这有点令人失望,我希望获得性能,因为numba对循环的性能更好。@Integral不是每个循环都可以用numba进行优化,它实际上取决于您在循环内执行的操作。@Integral numba中数组-元组转换的问题是因为元组需要有一个固定的编译时大小。数组没有那个大小(列表也没有),所以不能从数组创建元组。我还发现在numba中使用多维数组和自定义索引相当复杂。
def tup(a):
if len(a) < 5:
a += (3, ) * (5 - len(a))
return a
>>> tup((1,))
(1, 3, 3, 3, 3)
>>> tup((1, 2))
(1, 2, 3, 3, 3)