【问题标题】:indexing Cython memoryview using memoryview of ints使用整数的 memoryview 索引 Cython memoryview
【发布时间】:2019-05-18 19:12:46
【问题描述】:
使用 Cython,我尝试这样做:
cpdef myFun(double[:] array):
cdef int[:] sortIndices = np.argsort(array, kind='mergesort')
array = array[sortIndices]
编译器报错:
指定的内存视图索引无效,键入 int[:]
如何使用某种整数数组索引此内存视图?是否只允许切片?我可以轻松地使用基于“数组”的索引和旧的 NumPy 数组缓冲区支持。 (我刚刚调整了我的代码以使用 memoryviews 来查看它是否会提高性能,但它实际上会中断......)
【问题讨论】:
标签:
python-3.x
indexing
cython
typed-memory-views
【解决方案1】:
@ead 关于自己展开循环的建议是一个不错的建议,但是我很想对底层 Numpy 数组进行这种类型的索引,您可以使用 memoryview 的 base 属性访问它:
array = array.base[sortIndices]
或者
array = np.asarray(array)[sortIndices]
这具有快速编码的优点,并且只需要对您的工作 ndarray 代码进行最少的修改。它有一些小缺点:
没有 Cython 加速,因为它基本上是一个 Python 对象调用 - 我希望这无关紧要,因为 Numpy 索引通常非常快,并且假设 sortIndices 的长度足以否定 Python 对象调用。
如果底层对象实际上不是 Numpy 数组,则第一个版本会中断(因此,与最初出现的 memoryview 接口相比,该函数在它可以采用的类型方面受到更多限制。您可以通过使用来解决这个问题第二个版本,它应该创建一个包裹在 memoryview 内存周围的 Numpy 数组。
【解决方案2】:
恐怕不可能像 numpy 使用 int-arrays 那样使用类型化的内存视图作为索引。
Cython 的文档states that
内存视图使用 Python 切片语法的方式与 NumPy 类似。
“相似”意味着它对于整数、切片 (:)、省略号 (...) 和 None(对应于 numpy.newaxis('None'))是相同的,但对于整数 不是-数组或布尔数组,可以在numpy中用作索引。
负责生成对类型化内存视图的访问的 Cython 代码是 generate_buffer_slice_code,您需要知道的全部内容都在文档字符串中:
"""
Slice a memoryviewslice.
indices - list of index nodes.
If not a SliceNode, or NoneNode, then it must be coercible to Py_ssize_t
....
"""
所以array 既不是 SliceNode(即:、... 或例如0:33),也不是None,也不能强制转换为Py_ssize_t,因此不能由 Cython 处理.
我的第一个想法是,将功能添加到 Cython 的类型化内存视图不会太难。但这可能并不容易以一致的方式完成:操作的结果必须是一个新的类型化内存视图(因为我们无法就地更改手头的数组 - 结果数组可能具有完全不同的维度) - 但是哪种类型应该是底层缓冲区?在 numpy-world 中更容易,所有东西都是 numpy 数组,但类型化内存视图的底层缓冲区可以是 numpy-array、array.array、堆栈上的 c-array 等等。
您现在最好的选择可能是手动推出这种重新排序(这样您就可以明确选择底层缓冲区的类型)并通过它替换损坏的代码,或者为此操作回退到 numpy 功能,如@DavidWs 回答。