通过Cython传递和返回numpy数组到C ++方法 [英] Passing and returning numpy arrays to C++ methods via Cython

查看:485
本文介绍了通过Cython传递和返回numpy数组到C ++方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在此网站上有很多关于在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?

,并且在运行时调用时,将引发(2)并抛出在行X_c = ...上未定义np". 确切的测试代码和错误消息如下:

and (2) throws and "np is not defined on line X_c = ...") when calling it at runtime. The exact testing code and error message are the following:

import numpy as np
import mywrapper
mywrapper.run(np.array([[1,2],[3,4]], dtype=np.double))

# NameError: name 'np' is not defined [at mywrapper.pyx":X_c = ...]
# fixed!

推荐答案

您基本上是正确的.首先,希望优化应该没什么大不了的.理想情况下,大多数时间都花在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 ++方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆