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?