I am trying work out how to use cython to speed up a calculation involving integration that is done within a class I have defined. I'm trying to understand better how cython works with user-defined python classes. I'd like to understand more about why the error described below occurs.
I have the following cython code in a file called ex.pyx
from libc.math cimport log
from libc.math cimport sqrt
import scipy.integrate as integ
cdef double integrand_outside(double x):
"""Cython: integrand outside the class"""
cdef double f = log(x) / sqrt(x)
return f
cdef class CalcSomething(object):
def integrate_other(self, double a, double b):
"""This does the integral with the integrand outside the class"""
return integ.quad(integrand_outside, a, b)[0]
def integrate_self(self, double a, double b):
"""This does the integral with the integrand inside the class"""
return integ.quad(self._integrand, a, b)[0]
def integrate_wrap_self(self, double a, double b):
"""This does the integral with the integrand inside the class"""
return integ.quad(self.wrap_integrand, a, b)[0]
def wrap_integrand(self, double x):
"""Python method that wraps _integrand"""
return self._integrand(x)
cdef double _integrand(self, double x):
"""Cython: integrand inside the class"""
cdef double f = log(x) / sqrt(x)
return f
It shows three ways of calling scipy.integrate.quad
from within a class
- Using a cython integrand function defined outside the class:
integrate_other
(ok!)
- Using a cython integrand function defined inside the class:
integrate_self
(produces error)
- Wrapping the cython integrand function defined inside the class in a python function defined inside the class:
integrate_wrap_self
(ok!)
The above cython code compiles fine. Now I call each of these integrate methods, e.g.
import ex
calcSomething = ex.CalcSomething()
a = 0.001
b = 0.1
calcSomething.integrate_other(a,b) # works
calcSomething.integrate_wrap_self(a,b) # works
calcSomething.integrate_self(a,b) # doesn't work
Here is the traceback:
Traceback (most recent call last):
File "../examples/example.py", line 10, in <module>
print "integrate self =", calcSomething.integrate_self(a,b) # doesn't work
File "ex.pyx", line 17, in ex.CalcSomething.integrate_self (ex.c:989)
return integ.quad(self._integrand, a, b)[0]
File "/home/alex/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/scipy/integrate/quadpack.py", line 281, in quad
retval = _quad(func,a,b,args,full_output,epsabs,epsrel,limit,points)
File "/home/alex/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/scipy/integrate/quadpack.py", line 345, in _quad
return _quadpack._qagse(func,a,b,args,full_output,epsabs,epsrel,limit)
File "stringsource", line 30, in cfunc.to_py.__Pyx_CFunc_double____CalcSomething____double___to_py.wrap (ex.c:1560)
TypeError: wrap() takes exactly 2 positional arguments (1 given)
Here are my questions:
Why can scipy.integrate
be passed as a cython function or a python method (so now with instance as first argument) but not as a cython method? The error:
TypeError: wrap() takes exactly 2 positional arguments (1 given)
implies the issue is with the instance argument that is passed with the cython method I think?
Is this error coming from my misunderstanding of how to do cython, or a limitation of scipy
?
Is my intended plan of calculating an integral within a class (by calling an integrand function also within the class) a poor solution if I want to speed up via cython? Disclosure: the real code will call GSL integration functions, not scipy
.
See Question&Answers more detail:
os