我想找到如何使用cython来加速涉及集成的计算,这些计算是在我定义的类中进行的。我正在尝试更好地理解cython如何与用户自定义的Python类一起使用。我想更多地了解下面描述的错误发生的原因。
我在名为ex.pyx
的文件中编写了以下cython代码。
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
这段文字展示了在类内部调用scipy.integrate.quad
的三种方式:
- 使用在类外定义的cython积分函数:
integrate_other
(可行!) - 使用在类内定义的cython积分函数:
integrate_self
(会产生错误) - 将在类内定义的cython积分函数封装在一个在类内定义的python函数中:
integrate_wrap_self
(可行!)
上述的cython代码编译正常。现在我调用每个积分方法,例如:
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
以下是追溯信息:
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)
以下是我的问题:
为什么可以将
scipy.integrate
作为cython函数或python方法传递(因此现在实例是第一个参数),但不能将其作为cython方法传递?错误:TypeError: wrap() takes exactly 2 positional arguments (1 given)
表明问题出在传递给cython方法的实例参数上吗?这个错误是来自我对如何使用cython的误解,还是来自
scipy
的限制?如果我想通过cython加速,那么在类中计算积分(通过调用类内部的积分函数)是一个不好的解决方案吗?披露:真正的代码将调用GSL积分函数,而不是
scipy
。
calcSomething._integrand(.5)
和calcSomething.wrap_integrand(.5)
有什么区别?calcSomething._integrand(None, .5)
呢?我在想,尝试从类外调用函数是否是问题所在。 - hpauljcalcSomething._wrap_integrand(0.5)
是可以工作的,但是calcSomething._integrand(0.5)
不行,会抛出AttributeError: 'ex.CalcSomething' object has no attribute '_integrand'
的错误。然而,调用ex.integrand_outside(double x)
会产生AttributeError: 'module' object has no attribute 'integrand_outside'
的错误。 - alexabatecpdef
来定义那些你想从Python中调用的函数。 - hpauljcdef
函数传递给期望Python函数的位置时,自动生成一个wrap
函数是一个相对较新的功能,但仍存在一些问题。他们可能会欣赏一个错误报告。 - DavidW