【问题标题】:Cython memoryviews: wrapping c function with array parameter to pass numpy arrayCython memoryviews:用数组参数包装c函数以传递numpy数组
【发布时间】:2016-04-08 15:42:38
【问题描述】:

我正在尝试使用 Cython 用数组参数 (quick_sort()) 包装 c 函数,因此我可以将一个 numpy 数组传递给它。我已经在文档、SO 和网络上搜索了一个有效的、最小的示例,但没有找到。我已经尝试了几种可能性,但没有任何进展,所以请帮我弄清楚。这是我的文件:

quicksort.c

#include <stdio.h>

void quick_sort (int* a, int n) {
    int i, j, p, t;
    if (n < 2)
        return;
    p = a[n / 2];
    for (i = 0, j = n - 1;; i++, j--) {
        while (a[i] < p)
            i++;
        while (p < a[j])
            j--;
        if (i >= j)
            break;
        t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
    quick_sort(a, i);
    quick_sort(a + i, n - i);
}

quicksort.h

void quick_sort (int* a, int n);

quicksort.pxd

cdef extern from "quicksort.h":
    void quick_sort (int[:] a, int n)

cy_quicksort.pyx

cimport quicksort

def quicksort_c(int[:] a):
    quicksort.quick_sort(a, a.size)

setup.py

from distutils.core import setup
from Cython.Build import cythonize

setup(
    name='quicksort cython',
    ext_modules=cythonize("*.pyx"),
)

当我运行python setup.py build_ext --inplace 命令时,它返回以下错误:

cy_quicksort.c:1362:14: error: passing '__Pyx_memviewslice' to parameter of
      incompatible type 'int *'
  quick_sort(__pyx_v_a, __pyx_t_3);
             ^~~~~~~~~
./quicksort.h:1:23: note: passing argument to parameter 'a' here
void quick_sort (int* a, int n);

我想要实现的是编译它并能够运行例如:

import numpy as np
from cy_quicksort import quicksort_c
a = np.array(range(9, 0, -1), dtype=np.int32)
quicksort_c(a)

提前感谢您的宝贵时间!


编辑:

DavidW 在 quicksort.pxdcy_quicksort.pyx 中建议更改并将 setup.py 文件更改为以下形式后,它是按预期工作。

setup.py

from distutils.core import setup
from Cython.Build import cythonize
from distutils.extension import Extension

sourcefiles = ['cy_quicksort.pyx', 'quicksort.c']

extensions = [Extension("cy_quicksort", sourcefiles)]

setup(
    ext_modules = cythonize(extensions)
)

【问题讨论】:

    标签: python c numpy cython memoryview


    【解决方案1】:

    问题主要出在“quicksort.pxd”中——定义需要与quicksort.h中的匹配:

    cdef extern from "quicksort.h":
        void quick_sort (int* a, int n)
    

    [:] 将其定义为内存视图,这是 Cythony 的一项发明,不能直接转换为指针,正如您的错误所说)。

    然后你需要从“cy_quicksort.pyx”中的内存视图中获取一个指针

    def quicksort_c(int[::1] a):
        quicksort.quick_sort(&a[0], a.size) # get address of first element
    

    我已将输入参数更改为[::1],以指定元素在内存中必须是连续的,我认为这是快速排序所期望的。

    (注意 - 未经测试,但相当简单,应该可以工作!)

    【讨论】:

    • 感谢您的回答。通过您的修复,它可以编译,但是当我尝试import cy_quicksort 时,它返回ImportError: dlopen(./cy_quicksort.so, 2): Symbol not found: _quick_sort Referenced from: ./cy_quicksort.so Expected in: flat namespace in ./cy_quicksort.so。你知道可能是什么问题吗?
    • 你需要确保quicksort.c在生成模块时已经编译链接。查看docs.cython.org/src/reference/…(底部示例)。我认为您需要执行sourcefiles = ['cy_quicksort.pyx', 'quicksort.c'],然后按照链接中给出的其余示例进行操作。链接
    • 非常感谢,现在可以使用了!我会花几个小时试图自己解决这个问题......我已经编辑了我的问题,为任何潜在的读者添加了工作 setup.py。
    • 谈论复杂的语法... :D 但它有效。我花了很长时间才找到这些信息。感谢您的出色回答和解释。
    • @Azerila 您可能没有告诉 Cython 您尝试使用的 C 函数(因此假设该函数是一个接受 Python 对象的 Python 函数)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多