用Cython扩展numpy

4 投票
2 回答
1476 浏览
提问于 2025-04-15 17:16

我正在尝试把一个包含很多函数的头文件包装起来,像这样:

test.h

void test(int N, int* data_in, int* data_out);

这样我就可以在numpy中使用这些函数。

现在我有以下的cython代码:

test.pyx

import numpy as np
cimport numpy as np

ctypedef np.int_t itype_t

cdef extern from 'VolumeForm.h':
    void _test 'test' (int, int*, int*)

def wrap_test(np.ndarray[itype_t, ndim=2] data):
    cdef np.ndarray[dtype_t, ndim=1] out
    out = np.zeros((data.shape[0],1), dtype=np.double)
    _test(
        data.shape[0],
        <itype_t*> data.data,
        <itype_t*> out.data
    )
    return out

但是,当我尝试编译它时,我遇到了这个错误:

Error converting Pyrex file to C:
(...)
Cannot assign type 'test.itype_t *' to 'int *'

我该如何解决这个问题呢?

2 个回答

2

还有一种解决办法,不需要你把 int 改成 long。你只需要在 cdef extern from '...' 这个块里修改函数的定义。Cython 在生成 .c 文件的时候,只是用 cdef extern 块里的声明来检查类型,但生成的 C 代码只是简单地做了一个 #include "VolumeForm.h",所以你可以这样做而不会出问题。

import numpy as np
cimport numpy as np

ctypedef np.int_t itype_t

cdef extern from 'VolumeForm.h':
    # NOTE: We changed the int* declarations to itype_t*
    void _test 'test' (int, itype_t*, itype_t*)

def wrap_test(np.ndarray[itype_t, ndim=2] data):
    cdef np.ndarray[dtype_t, ndim=1] out
    out = np.zeros((data.shape[0],1), dtype=np.double)
    _test(
        data.shape[0],
        <itype_t*> data.data,
        <itype_t*> out.data
    )
    return out

Cython 对上述内容不会报错。

4

这个问题目前正在Cython的邮件列表上讨论;看起来是因为Cython库中的一个小错误引起的:

http://codespeak.net/mailman/listinfo/cython-dev

现在,有一个可能的解决办法是使用NumPy数组,类型设置为np.long,然后把'ctypedef np.long_t itype_t'写成这样。接下来,你只需要让C代码使用长整型(long ints)而不是整型(ints)就可以了。

撰写回答