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

Passing a cython function vs a cython method to scipy.integrate

我正在尝试研究如何使用 cython 来加速涉及在我定义的 class 中完成的积分的计算。我试图更好地理解 cython 如何与用户定义的 python classes 一起工作。我想详细了解为什么会出现下面描述的错误。

我在名为 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

它显示了从 class

中调用 scipy.integrate.quad 的三种方法
  1. 使用在 class 之外定义的 cython 被积函数:integrate_other(好的!)
  2. 使用 class 中定义的 cython 被积函数:integrate_self(产生错误)
  3. 将 class 中定义的 cython 被积函数包装在 class 中定义的 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)

这是我的问题:

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

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