2

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

1 Answer 1

5

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

Sign up to request clarification or add additional context in comments.

5 Comments

Thank You for Your answer. With Your fixes it compiles, however when I try to import cy_quicksort it returns ImportError: dlopen(./cy_quicksort.so, 2): Symbol not found: _quick_sort Referenced from: ./cy_quicksort.so Expected in: flat namespace in ./cy_quicksort.so. Do You know what can be the issue?
You need to make sure quicksort.c is compiled and linked when the module is generated. Have a look at docs.cython.org/src/reference/… (the bottom example). I think you need to do sourcefiles = ['cy_quicksort.pyx', 'quicksort.c'] and then follow the rest of the example given in the link. link
Thank You very much, now it's working! I would spend hours trying to figure that out by myself... I've edited my question to add working setup.py for any potential reader.
Talking about complicated syntax... :D But it works. It took me quite a while to find this information. Thanks for the great answer and explanation.
@Azerila you probably haven't told Cython about the C function you're trying to use (so it's assuming the function is a Python function that takes Python objects)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.