Apply a Python function to an std::vector via Cython (callback)
c++, callback, cython, python, stdvector
Solution
Thanks, Ian. Based on your suggestion, I changed the code to return a vector instead of trying to modify it in place. This works, although is admittedly not particularly efficient
callback.hpp
typedef double (*Callback)( void *apply, double x );
vector<double> function( Callback callback, void *apply,
const vector<double> &x );
callback.cpp
vector<double> function( Callback callback, void* apply,
const vector<double> &x ) {
int n = x.size();
vector<double> y(n);
for(int i=0;i<n;++i) {
y[i] = callback(apply,x[i]);
}
return y;
}
cy_callback.pxd
cdef extern from "callback.hpp":
ctypedef double (*Callback)( void *apply, const double &x )
vector[double] function( Callback callback, void* apply,
vector[double] &x )
cy_callback.pyx
from cy_callback cimport function
from libcpp.vector cimport vector
def pyfun(f,x):
return function( cb, <void*> f, <const vector[double]&> x )
cdef double cb(void* f, double x ):
return (<object>f)(x)
test.py
import numpy as np
from callback import pyfun
x = np.arange(11)
y = np.zeros(11)
def f(x):
return x*x
y = pyfun(f,x)
print(y)
Problem
I am trying to learn how to use callbacks between C and Python by way of Cython and have been looking at this demo. I would like a Python function applied to one std::vector/numpy.array and store the results in another. I can compile and run without errors, but ultimately the vector y is not being changed. C++ header ``` // callback.hpp #include<vector> typedef double (*Callback)( void *apply, double &x ); void function( Callback callback, void *apply, vector<double> &x, vector<double> &y ); ``` C++ source ``` // callback.cpp #include "callback.hpp" #include <iostream> using namespace std; void function( Callback callback, void* apply, vector<double> &x, vector<double> &y ) { int n = x.size(); for(int i=0;i<n;++i) { y[i] = callback(apply,x[i]); std::cout << y[i] << std::endl; } ``` Cython header ``` # cy_callback.pxd import cython from libcpp.vector cimport vector cdef extern from "callback.hpp": ctypedef double (*Callback)( void *apply, double &x ) void function( Callback callback, void* apply, vector[double] &x, vector[double] &y ) ``` Cython source ``` # cy_callback.pyx from cy_callback cimport function from libcpp.vector cimport vector def pyfun(f,x,y): function( cb, <void*> f, <vector[double]&> x, <vector[double]&> y ) cdef double cb(void* f, double &x): return (<object>f)(x) ``` I compile with fairly boilerplate setup: python setup.py build_ext -i ``` # setup.py from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext import numpy import os os.environ["CC"] = "g++" os.environ["CXX"] = "g++" setup( name = 'callback', ext_modules=[Extension("callback", sources=["cy_callback.pyx","callback.cpp"], language="c++", include_dirs=[numpy.get_include()])], cmdclass = {'build_ext': build_ext}, ) ``` And finally test with the Python script ``` # test.py import numpy as np from callback import pyfun x = np.arange(11) y = np.zeros(11) pyfun(lambda x:x**2,x,y) print(y) ``` When the elements of y are set in callback.cpp, the correct values are being printed to the screen, which means that pyfun is indeed being evaluated correctly, however, at the Python level, y remains all zeros. Any idea what I'm doing incorrectly?