简体   繁体   中英

Cython memoryviews: wrapping c function with array parameter to pass numpy array

I am trying to use Cython to wrap c function with an array parameter ( quick_sort() ), so I can pass a numpy array to it. I've searched the documentation, SO and web for a working, minimal example but didn't find it. I've tried several possibilities but without any progress, so please help me to figure it out. Here are my files:

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"),
)

When I'm running python setup.py build_ext --inplace command, it returns the following error:

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);

What I want to achieve is to compile this and be able to run for example:

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

Thanks in advance for Your time!


Edit:

After changes suggested by DavidW in quicksort.pxd , cy_quicksort.pyx and changing the setup.py file into the following form, it's working as intended.

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)
)

The problem is mainly in "quicksort.pxd" - the definition needs to match that in quicksort.h:

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

( [:] defines it as a memoryview instead, which is a Cythony invention and can't be cast directly to a pointer, as your error says).

You then need to get a pointer from the memoryview in "cy_quicksort.pyx"

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

I've changed the input parameter to [::1] to specify that the elements must be continuous in memory, which I think is what quicksort expects.

(Note - untested, but reasonably simple so should work!)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM