簡體   English   中英

是否可以通過包裝或cython重新聲明gsl_function將cython類方法分配給gsl_function結構?

[英]Can I assign a cython class method to a gsl_function structure via wrapping or cython re-declaration of gsl_function?

這個問題是基於這里的問題

我有以下cython代碼,該代碼導入一個文件( cGslInteg.pxd ),其中包含gsl/gsl_integration.hgsl/gsl_math.h頭文件的相關部分的cython聲明,然后定義一個用於計算積分的類:

from libc.math cimport log
from libc.math cimport sqrt
from cGslInteg cimport *

ctypedef double * double_ptr

cdef double integrand(double x, void * params):
    """integrand implemented outside class """

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


cdef class CalcSomething(object):

    def integrate(self, double a, double b, double alpha):
        """This does the integral"""

        cdef double result, error

        cdef gsl_integration_workspace * W
        W = gsl_integration_workspace_alloc(1000)

        cdef gsl_function F

        F.function = &integrand          # works 
        # F.function = &self._integrand  # doesn't work

        cdef double params[1]
        params[0] = alpha
        F.params = &params

        cdef double epsabs = 0.
        cdef double epsrel = 1e-7
        gsl_integration_qags(&F, a, b, epsabs, epsrel, 1000, W, &result, &error)
        gsl_integration_workspace_free(W)

        return result


    cdef double _integrand(self, double x, void * params):
        """integrand implemented inside class """

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

上面的代碼在使用該類之外的 F.function = &integrand函數時可以編譯並正確運行( F.function = &integrand )。 但是,將這一行更改為下面注釋掉的那一行( F.function = &self._integrand ),以代替使用類內部的 F.function = &self._integrand函數,會導致以下編譯錯誤:

cython_class_gsl.pyx:31:21: Cannot assign type 'double (*)(CalcSomething, double, void *)' to 'double (*)(double, void *)'

這是有道理的,因為我在cGslInteg.pxdgsl_functioncGslInteg.pxd是:

cdef extern from "gsl/gsl_math.h":

    # Definition of an arbitrary function with parameters
    ctypedef struct gsl_function:
        double (* function) (double x, void * params)
        void * params

我的問題是:我可以重新聲明gsl_function以便它期望使用double (*)(PythonObject, double, void *)類型的東西,還是可以包裝self._integrand使其看起來像double (*)( double, void *)

編輯:一些額外的說明,以使其更接近於現實生活中的問題/問題:

  1. self._integrand任何包裝必須在CalcSomething類中定義。
  2. 積分參數alpha不能是類變量(即必須在params參數中傳遞給被積分數)

這就是params目的。 你會做這樣的事情(大大削減了例子...)

from libc.math cimport log,sqrt

cdef class CalcSomething:   
    cdef double integrand(self, double x, double alpha):
        return log(alpha*x)/sqrt(x)

cdef double wrapped_integrand_func(double x, void* params):
    cdef object params_as_object = <object>params
    cdef CalcSomething instance = params_as_object[0] # we need to know the type to use cdef functions
    alpha = params_as_object[1]
    return instance.integrand(x,alpha)

def test(alpha):
    cdef object o = (CalcSomething(),alpha) # store Calc something and alpha as a tuple
    cdef void* o_ptr = <void*>o # be careful with reference counts here - o_ptr doesn't keep o alive!
    print(wrapped_integrand_func(4.3,o_ptr))

這顯然不是包裝綁定方法的通用解決方案,但是在這種情況下,這正是gsl允許您傳遞void*

一個警告是,您必須確保o保持生存狀態, o_ptr您想使用o_ptr

更新 (以匹配稍作修改的問題):

積分參數alpha不能是類變量(即必須在params參數中傳遞給被積分數)

這很容易做到。 在我的原始代碼中,我使用了一個類變量,但是現在我將它們分別作為一個元組傳遞給了它們。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM