This question builds upon the one here
I have the following cython code that imports a file (cGslInteg.pxd
) containing the cython declarations for the relevant parts of the gsl/gsl_integration.h
and gsl/gsl_math.h
header files and then defines a class to compute an integral:
from libc.math cimport log
from libc.math cimport sqrt
from cGslInteg cimport *
ctypedef double * double_ptr
cdef double integrand(double x, void * params):
"""integrand implemented outside class """
cdef double alpha = (<double_ptr> params)[0]
cdef double f = log(alpha*x) / sqrt(x)
return f
cdef class CalcSomething(object):
def integrate(self, double a, double b, double alpha):
"""This does the integral"""
cdef double result, error
cdef gsl_integration_workspace * W
W = gsl_integration_workspace_alloc(1000)
cdef gsl_function F
F.function = &integrand # works
# F.function = &self._integrand # doesn't work
cdef double params[1]
params[0] = alpha
F.params = ¶ms
cdef double epsabs = 0.
cdef double epsrel = 1e-7
gsl_integration_qags(&F, a, b, epsabs, epsrel, 1000, W, &result, &error)
gsl_integration_workspace_free(W)
return result
cdef double _integrand(self, double x, void * params):
"""integrand implemented inside class """
cdef double alpha = (<double_ptr> params)[0]
cdef double f = log(alpha*x) / sqrt(x)
return f
The above code compiles and runs correctly as the integrand function outside the class is used (F.function = &integrand
). However, changing this line to the one commented out beneath (F.function = &self._integrand
) in order to use instead the integrand function inside the class, brings the following compilation error:
cython_class_gsl.pyx:31:21: Cannot assign type 'double (*)(CalcSomething, double, void *)' to 'double (*)(double, void *)'
Which makes sense because my declaration for gsl_function
in cGslInteg.pxd
is:
cdef extern from "gsl/gsl_math.h":
# Definition of an arbitrary function with parameters
ctypedef struct gsl_function:
double (* function) (double x, void * params)
void * params
My question is: can I re-declare gsl_function
so it expects something with type e.g. double (*)(PythonObject, double, void *)
or can I wrap self._integrand
so it appears to have type double (*)( double, void *)
?
EDIT: Some extra notes to make this closer to the real-life problem/issue:
- Any wrapper of
self._integrand
would have to be defined within theCalcSomething
class. - The integration parameter
alpha
cannot be a class variable (i.e. it must be passed within theparams
argument to the integrand)