2

我在 cython 中创建了一个类型化的内存视图,并想将它乘以一个标量:

import numpy as np
import math
cimport numpy as np

def foo():
    N = 10
    cdef np.double_t [:, :] A = np.ones(shape=(N,N),dtype=np.double_)
    cdef int i,j
    cdef double pi = math.pi
    for i in range(N):
        for j in range(N):
            A[i,j] *= pi
    return A

def bar():
    N = 10
    cdef np.double_t [:, :] A = np.ones(shape=(N,N),dtype=np.double_)
    cdef double pi = math.pi
    A *= pi
    return A

函数foo()执行此任务但不是很方便/可读。

A *= pi但是,函数中的行bar()无法编译:Invalid operand types for '*' (double_t[:, :]; double).

有没有办法在 cython memoryview 上执行这样的广播操作?

4

1 回答 1

2

不,内存视图不这样做。内存视图实际上只是一种快速访问数组中各个元素的方法。它没有可以在数组上执行的数学运算的真正概念。

在您的bar函数的情况下,任何键入它的尝试实际上可能会使它变得更糟(即它将花费额外的时间检查类型,但最终工作是在对 Numpy 函数的普通调用中完成的)。

从 memoryview 获取 Numpy 数组有很多(不是 100% 令人满意)的方法:

  1. np.asarray(memview)- 这应该在不复制的情况下完成(前提是您没有使用深奥的间接内存布局)。可能值得添加一个断言来检查是否没有复制。

  2. memview.base- 对此要稍微小心。如果内存视图是切片的结果,那么.base将是原始的未切片对象。

  3. 保持一个并行的 numpy 数组和 memoryview 变量:

     Anp = np.array(...)
     cdef double[:] Amview = Anp
    

    因为 memoryview 是一些内存的视图,所以对数组的修改将反映在 memoryview 中,反之亦然。Anp = something_else(但不会反映重新分配数组变量,例如)。


总之,内存视图是为一项主要工作而设计的:能够快速访问单个元素。如果那不是您正在做的事情,那么您可能不想使用内存视图。

于 2021-02-09T18:12:02.847 回答