【问题标题】:Casting Cython fused types to C++ pointers将 Cython 融合类型转换为 C++ 指针
【发布时间】:2015-02-13 19:48:10
【问题描述】:

这是一个关于从 Cython 融合类型转换为 C++ 类型的一般问题,我将用一个最小的例子来描述。考虑肤浅的 C++ 函数模板:

template <typename T>
void scale_impl(const T * x, T * y, const T a, const size_t N) {
    for (size_t n = 0; n < N; ++n) {
        y[n] = a*x[n];
    }
}

我希望能够在任何类型和形状的任何 numpy ndarray 上调用此函数。使用 Cython,我们首先声明函数模板:

cdef extern:
    void scale_impl[T](const T * x, T * y, const T a, const size_t N)

然后声明我们希望操作的有效标量类型:

ctypedef fused Scalar:
    float
    double
    ...

最后实现实际的 Cython shim:

def scale(ndarray[Scalar] x, Scalar a):
    """Scale an array x by the value a"""
    cdef ndarray[Scalar] y = np.empty_like(x)
    scale_impl(<Scalar *>x.data, <Scalar *>y.data, a, x.size)
    return y

这不起作用有两个原因:

  • x 只能是一维的,不能是任意的(或至少是多维的)
  • 转换为 &lt;Scalar *&gt; 会引发错误,因为 Scalar 实际上是一个 Python 对象

显然可以明确地推断出专业化:

    if Scalar is float:
        scale_impl(<float *>x.data, <float *>y.data, a, x.size)
    if Scalar is double:
        scale_impl(<double *>x.data, <double *>y.data, a, x.size)
    if Scalar is ...

但这会导致我必须为具有多种融合类型的函数手动编写组合数量的代码路径,并造成引入融合类型以避免的情况(我假设)。

有没有办法将任意维度(在合理范围内)数组传递给 Cython 函数并让它推断出标量数据的指针类型?或者,实现此类功能的最合理折衷方案是什么?

【问题讨论】:

    标签: python c++ templates casting cython


    【解决方案1】:

    (另请参阅Using Cython to wrap a c++ template to accept any numpy array 中给出的答案,这是一个非常相似的问题。)

    使用&amp;x[0] 形式而不是尝试强制转换x.data 解决了选择正确模板专业化的问题。二维数组的问题有点复杂,因为不能保证数组是连续的还是有序的。

    我将创建一个对一维数组执行实际工作的函数,并包装在一个根据需要展平的简单函数中:

    def _scale_impl(Scalar[::1] x, Scalar a):
      # the "::1" syntax ensures the array is actually continuous
      cdef np.ndarray[Scalar,ndim=1] y = np.empty_like(x)
      cdef size_t N = x.shape[0] # this seems to be necessary to avoid throwing off Cython's template deduction
      scale_impl(&x[0],&y[0],a,N)
      return y
    
    
    def scale(x, a):
      """Scale an array x by the value a"""
    
      y = _scale_impl(np.ravel(x),a)
      return y.reshape(x.shape) # reshape needs to be kept out of Cython
    

    【讨论】:

    • 这或多或少是我最终解决的问题
    猜你喜欢
    • 2021-09-20
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 2021-08-03
    • 1970-01-01
    • 2013-09-23
    相关资源
    最近更新 更多