I need to generate a sort comparator using a parameter I will only have at runtime in Cython.
Here is a minimal example:
from libcpp.algorithm cimport sort
import random
cpdef test_sort():
cdef int *a = [1,2,3,4]
cdef int z = random.randrange(5)
sort(&a[0], &a[3], lambda x,y: abs(x-z) < abs(y-z)) # doesn't compile
I have tried lots of different approaches, but I can't get anything to compile. Is there any way to do this in Cython for native arrays and the libcpp
sort
function?
Update:
I tried @DavidW's suggestion to write the comparator in C++ but I am getting exactly the same error.
test_sort.pyx:
from libcpp cimport bool
from libcpp.algorithm cimport sort
from libcpp.functional cimport function
import random
cdef extern from "cmp.cpp":
# I couldn't figure out how to declare the return type for this function
# I tried function[bool(int, int)] make_cmp(int z) but Cython complained
make_cmp(int z)
cpdef test_sort():
cdef int *a = [1,2,3,4]
cdef int z = random.randrange(5)
sort(&a[0], &a[3], make_cmp(z))
print(z)
for i in range(4):
print(a[i])
cmp.cpp:
#include <stdlib.h>
std::function<bool(int, int)> make_cmp(int z) {
return [&z](int x, int y) { return abs(x-z) < abs(y-z); };
setup.py:
from distutils.core import setup
from Cython.Build import cythonize
setup(
ext_modules = cythonize("*.pyx", language="c++")
)
run.py:
from test_sort import test_sort
test_sort()
$ python setup.py build_ext --inplace
Gives the following errors (among other output):
test_sort.cpp: In function ‘PyObject* __pyx_f_9test_sort_test_sort(int)’: test_sort.cpp:1069:33: error: cannot convert ‘std::function’ to ‘PyObject* {aka _object*}’ in assignment __pyx_t_2 = make_cmp(__pyx_v_z); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 13, __pyx_L1_error)
...
test_sort.cpp:1071:78: required from here /usr/include/c++/6/bits/predefined_ops.h:147:11: error: expression cannot be used as a function { return bool(_M_comp(*__it, __val)); }
error: expression cannot be used as a function
is exactly what I get if I try to pass the python lambda into sort.