问题描述
在此网站上有很多关于在cython中使用numpy的问题,其中一个特别有用的是.
There are lots of questions about using numpy in cython on this site, a particularly useful one being Simple wrapping of C code with cython.
但是,cython/numpy接口api 似乎已经改变了,尤其是在确保通过内存连续数组的情况下.
However, the cython/numpy interface api seems to have changed a bit, in particular with ensuring the passing of memory-contiguous arrays.
在cython中编写包装函数的最佳方法是:
What is the best way to write a wrapper function in cython that:
- 采用一个可能但不一定是连续的numpy数组
- 调用签名为
double* data_in, double* data_out
的C ++类方法 - 返回该方法写入的
double*
的numpy数组?
- takes a numpy array that is likely but not necessarily contiguous
- calls a C++ class method with the signature
double* data_in, double* data_out
- returns a numpy array of the
double*
that the method wrote to?
我的尝试如下:
cimport numpy as np
import numpy as np # as suggested by jorgeca
cdef extern from "myclass.h":
cdef cppclass MyClass:
MyClass() except +
void run(double* X, int N, int D, double* Y)
def run(np.ndarray[np.double_t, ndim=2] X):
cdef int N, D
N = X.shape[0]
D = X.shape[1]
cdef np.ndarray[np.double_t, ndim=1, mode="c"] X_c
X_c = np.ascontiguousarray(X, dtype=np.double)
cdef np.ndarray[np.double_t, ndim=1, mode="c"] Y_c
Y_c = np.ascontiguousarray(np.zeros((N*D,)), dtype=np.double)
cdef MyClass myclass
myclass = MyClass()
myclass.run(<double*> X_c.data, N, D, <double*> Y_c.data)
return Y_c.reshape(N, 2)
此代码可以编译,但不一定是最佳代码.您对改善以上代码段有什么建议吗?
This code compiles but is not necessarily optimal. Do you have any suggestions on improving the snippet above?
推荐答案
您基本上是正确的.首先,希望优化应该没什么大不了的.理想情况下,大多数时间都花在C ++内核中,而不是在cythnon包装器代码中.
You've basically got it right. First, hopefully optimization shouldn't be a big deal. Ideally, most of the time is spent inside your C++ kernel, not in the cythnon wrapper code.
您可以进行一些样式上的更改,以简化您的代码. (1)无需在1D和2D阵列之间重塑.当您知道数据的内存布局(C顺序与fortran顺序,跨度等)时,您可以看到数组只是要在C ++中建立索引的一部分内存,因此numpy的ndim不会在C ++方面无关紧要-只是看到了那个指针. (2)使用cython的地址运算符&
,您可以使用&X[0,0]
,以更简洁的方式获取指向数组开头的指针-无需显式强制转换.
There are a few stylistic changes you can make that will simplify your code. (1) Reshaping between 1D and 2D arrays is not necessary. When you know the memory layout of your data (C-order vs. fortran order, striding, etc), you can see the array as just a chunk of memory that you're going to index yourself in C++, so numpy's ndim doesn't matter on the C++ side -- it's just seeing that pointer. (2) Using cython's address-of operator &
, you can get the pointer to the start of the array in a little cleaner way -- no explicit cast necessary -- using &X[0,0]
.
这是我对原始代码段的修改后的版本:
So this is my edited version of your original snippet:
cimport numpy as np
import numpy as np
cdef extern from "myclass.h":
cdef cppclass MyClass:
MyClass() except +
void run(double* X, int N, int D, double* Y)
def run(np.ndarray[np.double_t, ndim=2] X):
X = np.ascontiguousarray(X)
cdef np.ndarray[np.double_t, ndim=2, mode="c"] Y = np.zeros_like(X)
cdef MyClass myclass
myclass = MyClass()
myclass.run(&X[0,0], X.shape[0], X.shape[1], &Y[0,0])
return Y
这篇关于通过Cython传递和返回numpy数组到C ++方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!