在numba jitted函数中动态增长的数组

时间:2017-05-09 12:21:54

标签: python numpy dynamic-arrays numba

似乎numba不支持numpy.resize

在nopython模式下使用numba.jit动态增长数组的最佳方法是什么?

到目前为止,我能做的最好的事情是在jitted函数之外定义和调整数组,是否有更好的(更整洁)选项?

3 个答案:

答案 0 :(得分:5)

numpy.resizepure python function

import numpy as np

def resize(a, new_shape):
    """I did some minor changes so it all works with just `import numpy as np`."""
    if isinstance(new_shape, (int, np.core.numerictypes.integer)):
        new_shape = (new_shape,)
    a = np.ravel(a)
    Na = len(a)
    if not Na:
        return np.zeros(new_shape, a.dtype)
    total_size = np.multiply.reduce(new_shape)
    n_copies = int(total_size / Na)
    extra = total_size % Na

    if total_size == 0:
        return a[:0]

    if extra != 0:
        n_copies = n_copies+1
        extra = Na-extra

    a = np.concatenate((a,)*n_copies)
    if extra > 0:
        a = a[:-extra]

    return np.reshape(a, new_shape)

对于1D阵列,这可以直接实现自己。不幸的是,它对于ND阵列来说要复杂得多,因为在nopython numba函数中不支持某些操作:isinstancereshape和元组乘法。这是1D等价物:

import numpy as np
import numba as nb

@nb.njit
def resize(a, new_size):
    new = np.zeros(new_size, a.dtype)
    idx = 0
    while True:
        newidx = idx + a.size
        if newidx > new_size:
            new[idx:] = a[:new_size-newidx]
            break
        new[idx:newidx] = a
        idx = newidx
    return new

当你不想要"重复输入"行为只用于增加大小它更容易:

@nb.njit
def resize(a, new_size):
    new = np.zeros(new_size, a.dtype)
    new[:a.size] = a
    return new

这些函数用numba.njit修饰,因此可以在nopython模式下的任何numba函数中调用。

但请注意:一般情况下,您不想调整大小 - 或者如果您这样做,请确保选择具有amoritzed O(1) cost (Wikipedia link)的方法。如果您可以估计最大长度,那么最好立即预先分配正确大小(或稍微过度分配)的阵列。

答案 1 :(得分:1)

通常我采用的策略是分配足够多的数组存储以适应计算,然后跟踪所使用的最终索引/索引,然后在返回之前将数组切割为实际大小。这假设您事先知道阵列可能增大的最大大小。我的想法是,在我自己的大多数应用程序中,内存很便宜但是调整大小并在python和jitted函数之间切换很多都很昂贵。

答案 2 :(得分:0)

要动态增加现有数组的大小(因此就地进行),必须使用 numpy.ndarray.resize 而不是 numpy.resize。此方法未在 Python 中实现,在 Numba 中不可用,因此无法完成。