将cython函数与cython方法传递给scipy.integrate

时间:2015-10-01 19:38:36

标签: python oop scipy cython

我正在尝试研究如何使用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的三种方法
  1. 使用在课外定义的cython integrand函数:integrate_other(ok!)
  2. 使用在类中定义的cython integrand函数:integrate_self(产生错误)
  3. 在类中定义的python函数中包装类中定义的cython integrand函数:integrate_wrap_self(ok!)
  4. 上面的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

1 个答案:

答案 0 :(得分:1)

从上面的hpaulj的帮助:答案是_integrand方法需要声明cpdef而不是cdef

cpdef double _integrand(self, double x):
    """Cython: integrand inside the class"""
    cdef double f = log(x) / sqrt(x)
    return f