Pass Cython Functions Via Python Interface
Solution 1:
The LowLevelCallable
is a class of functions that must be accepted by the underlying Python module. This work has been done for a few modules, including the quadrature routine scipy.integrate.quad
If you wish to use the same wrapping method, you must either go through the SciPy routines that make use of it, such as scipy.ndimage.generic_filter1d
or scipy.integrate.quad
. The code sits in compiled extensions, however.
The alternative, if your problem is reasonably well defined for the callback, is to implement this yourself. I have done this in one of my codes, so I post the link for simplicity:
- In a
.pxd
file, I define the interfacecyfunc_d_d
: https://github.com/pdebuyl/skl1/blob/master/skl1/core.pxd - I can re-use this interface in the "base" cython module https://github.com/pdebuyl/skl1/blob/master/skl1/euler.pyx and also in a "user-defined" module.
The final code makes plain "cython-cython" calls while allowing the passing of objects at the Cython level
I adapted the code to your problem:
test_interface.pxd
cdef classcyfunc: cpdef doublef(self, double x) cdef classpyfunc(cyfunc): cdef object py_f cpdef doublef(self, double x)
test_interface.pyx
cdefclass cyfunc: cpdefdouble f(self, double x): return0def__cinit__(self): pass cdefclass pyfunc(cyfunc): cpdefdouble f(self, double x): return self.py_f(x) def__init__(self, f): self.py_f = f
setup.py
from setuptools import setup, ExtensionfromCython.Buildimport cythonize setup( ext_modules=cythonize((Extension('test_interface', ["test_interface.pyx"]), Extension('test_module', ["test_module.pyx"])) ) )
test_module.pyx
from test_interface cimport cyfunc, pyfunc cpdefmin_arg(f, int N): cdefdouble x = 100000. cdefint best_i = -1 cdefint i cdefdouble current_value cdefcyfunc py_f ifisinstance(f, cyfunc): py_f = f print('cyfunc') elifcallable(f): py_f = pyfunc(f) print('no cyfunc') else: raise ValueError("f should be a callable or a cyfunc") for i inrange(N): current_value = py_f.f(i) if current_value < x: x = current_value best_i = i return best_i defpy_f(x): return (x-5)**2 cdefclass cy_f(cyfunc): cpdefdouble f(self, double x): return (x-5)**2
To use:
python3 setup.py build_ext --inplace
python3 -c 'import test_module ; print(test_module.min_arg(test_module.cy_f(), 10))'
python3 -c 'import test_module ; print(test_module.min_arg(test_module.py_f, 10))'
Post a Comment for "Pass Cython Functions Via Python Interface"