【问题标题】:Use a class method as an integrand to GSL QAGS使用类方法作为 GSL QAGS 的被积函数
【发布时间】:2014-06-11 12:24:13
【问题描述】:

我想将一个类的成员函数用于 gsl_function 的全局函数,但我不知道该怎么做。由于我现在只是非常了解 C,我知道我必须将作为被积函数的类实例发送到 void 参数,但从技术上讲,我无法在 cython 中对其进行编码,这是一个 cython 示例。

from cython_gsl cimport *

ctypedef double * double_ptr
ctypedef void * void_ptr

cdef double foo(double x, void * params) nogil:
    cdef double alpha, f
    alpha = (<double_ptr> params)[0]
    f = log(alpha*x) / sqrt(x)
    return f


def main():
    cdef gsl_integration_workspace * w
    cdef double result, error, expected, alpha
    w = gsl_integration_workspace_alloc (1000)

    expected = -4.0
    alpha = 1

    cdef gsl_function F
    F.function = &foo
    F.params = &alpha

    gsl_integration_qags (&F, 0, 1, 0, 1e-7, 1000, w, &result, &error)
    print "result          = % .18f\n" % result
    print "estimated error          = % .18f\n" % error

假设我有以下课程:

from math import *
cdef class Foo(object):
    def __init__(self, double a=1.2, double b=0.6):
        self.a = a
        self.b = b
    def _integrand(self,double x):
         cdef double self.a = (<double_ptr> params)[0]
         cdef double self.b = (<double_ptr> params)[1]
         return self.a*log(x)+self.b/x**3
    def whole(self, double upper_limit=10,double lower_limit=0):
        cdef gsl_integration_workspace * w
        cdef double result, error, expected, alpha
        w = gsl_integration_workspace_alloc (1000)

        expected = -4.0
        params[0] = self.a
        params[1] = self.b

        cdef gsl_function F
        F.function = &self._integrand
        F.params = params

        gsl_integration_qags (&F, lower_limit,upper_limit , 0, 1e-7, 1000, w, &result, &error)
        return result,error

如何将Foo._integrand 转换为gsl 可以使用的全局函数?

【问题讨论】:

  • 一个问题:最后一行不应该说return self.a*log(x)+self.b/x**3吗?
  • 你想要全局化的特定方法在它所绑定的类实例的上下文之外没有任何意义。它依赖于ab,它们都是实例类属性。你为什么要按照你的要求去做?
  • @aruisdante 因为这只是我更大问题的一个例子。我想在一个类中使用这个积分,我不知道应该怎么做。

标签: python function class methods cython


【解决方案1】:

在 Python 中,您可以使用 functools.partial 来传递方法,就像函数预定义 self 参数一样:

from functools import partial

foo = Foo()
integrand_func = partial(Foo._integrand, foo)

但是您不能在 C 中定义这样的偏函数。因此,我会将被积函数外部化并将其定义为您的类的一个参数,而不是一个额外的方法。请注意,这就像使用静态方法,但Cython does not support it yet。另一个重要提示是使用log 形式math.h。请参阅下面的原型:

#cython: wraparound=False
#cython: boundscheck=False
#cython: cdivision=True
#cython: nonecheck=False
cdef extern from "math.h":
    double log(double x) nogil

ctypedef double (*function)(double x, void *params)

cdef struct integrandFoo_p:
    double *a
    double *b

cdef struct gsl_function:
    function function
    void *params

cdef double integrandFoo(double x, void *params):
    cdef integrandFoo_p *p=<integrandFoo_p *>params
    cdef double a, b
    a = p.a[0]
    b = p.b[0]
    return a*log(x)+b/(x*x*x)

cdef void trapzd(gsl_function *F, double lower_limit, double upper_limit,
                 int num, double *result, double *error):
    cdef int i
    cdef double x
    f = F[0].function
    p = F[0].params
    result[0] = 0.
    for i in range(num+1):
        x = lower_limit + (upper_limit - lower_limit)*i/num
        if i==0 or i==num:
            result[0] += f(x, p)*0.5
        else:
            result[0] += f(x, p)

    error[0] = 0.

cdef class Foo(object):
    cdef double a
    cdef double b
    cdef double result
    cdef double error
    cdef function f
    def __init__(self):
        self.a = 1.2
        self.b = 0.6
        self.f = <function>integrandFoo
    cdef void integrate(self, double lower_limit=1, double upper_limit=10):
        #cdef gsl_integration_workspace * w
        cdef double result, error, expected, alpha
        cdef integrandFoo_p p
        cdef gsl_function F

        #w = gsl_integration_workspace_alloc(1000)
        p.a = &self.a
        p.b = &self.b
        expected = -4.0

        F.function = self.f
        F.params = &p

        trapzd(&F, lower_limit, upper_limit, 1000, &self.result, &self.error)
        #gsl_integration_qags(&F, lower_limit, upper_limit, 0, 1e-7,
                             #1000, w, &result, &error)
def main():
    foo = Foo()
    print 'HERE', foo.result, foo.error
    foo.integrate()
    print 'HERE', foo.result, foo.error

【讨论】:

  • @Saullo 如果我想在类中添加一个实例来计算给定函数的积分,我该怎么做?
  • 可以@staticmethod 帮助使被积函数独立于整个类,或者在类外部没有明确给定功能的情况下制作通用integrand 函数,并在类中调用以获得类参数为投入能解决问题吗? – 达莱克
  • 我的问题是我需要在类中定义被积函数,因为在这个例子中没有,但我需要在类中使用其他瞬间来构建我的被积函数。但是,仍然有几个问题我无法用cython 构建您的答案。例如,第一个错误Cannot assign type 'integrandFoo_p' to 'integrandFoo_p *' 和第二个错误self.f=integrandFoo 它引发Cannot assign type 'double (double, void *)' to 'function',然后对于p.a = &amp;self.a 我得到了这个错误Cannot take address of Python variable
  • 您将即时integrate 定义为无效,但最后您返回了resulterror
  • @Dalek 谢谢你,我已经用工作版本更新了答案...... :)
【解决方案2】:

只需取出 'self's 并在其调用签名中添加 a 和 b,然后删除代码即可。

    def _integrand(x, a, b):
        return a*log(x)+b/x**3

【讨论】:

    猜你喜欢
    • 2022-06-18
    • 1970-01-01
    • 1970-01-01
    • 2011-03-10
    • 2021-11-21
    • 2016-10-10
    • 2021-07-12
    • 2017-03-04
    • 1970-01-01
    相关资源
    最近更新 更多