Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 我是否可以通过包装或cython重新声明gsl_函数,将cython类方法分配给gsl_函数结构?_Python_Oop_Wrapper_Cython_Gsl - Fatal编程技术网

Python 我是否可以通过包装或cython重新声明gsl_函数,将cython类方法分配给gsl_函数结构?

Python 我是否可以通过包装或cython重新声明gsl_函数,将cython类方法分配给gsl_函数结构?,python,oop,wrapper,cython,gsl,Python,Oop,Wrapper,Cython,Gsl,这个问题建立在这个问题之上 我有以下cython代码,它导入一个文件(cgslinke.pxd),其中包含gsl/gsl_integration.h和gsl/gsl_math.h头文件相关部分的cython声明,然后定义一个类来计算积分: from libc.math cimport log from libc.math cimport sqrt from cGslInteg cimport * ctypedef double * double_ptr cdef double integra

这个问题建立在这个问题之上

我有以下cython代码,它导入一个文件(
cgslinke.pxd
),其中包含
gsl/gsl_integration.h
gsl/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
这很有意义,因为我在
cgslink.pxd
中对
gsl\u函数的声明是:

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\u函数
,这样它就需要类型为
double(*)(PythonObject,double,void*)
的东西,或者我是否可以包装
self.\u被积函数
使它看起来有类型
double(*)(double,void*)

编辑: 一些额外的注意事项使其更接近现实生活中的问题:

  • self.\u被积函数的任何包装将
    CalcSomething
    类中定义
  • 积分参数
    alpha
    不能是类变量(即必须在
    params
    参数中传递给被积函数)

  • 这就是
    params
    的作用。你会做这样的事情(大幅减少示例…)

    来自libc.math cimport日志,sqrt
    cdef类计算方法:
    cdef双被积函数(自、双x、双α):
    返回日志(alpha*x)/sqrt(x)
    cdef双包裹被积函数(双x,void*params):
    cdef对象参数作为对象=参数
    cdef CalcSomething instance=params_as_object[0]#我们需要知道使用cdef函数的类型
    alpha=参数作为对象[1]
    return instance.integrand(x,alpha)
    def测试(α):
    cdef object o=(CalcSomething(),alpha)#将Calc something和alpha存储为元组
    cdef void*o_ptr=o#注意这里的引用计数-o_ptr不能使o保持活动状态!
    打印(包装的被积函数函数(4.3,o\U ptr))
    
    这显然不是包装绑定方法的一般解决方案,但在本例中,这正是gsl允许您传递
    void*
    的原因

    需要注意的一点是,只要您想使用
    o_ptr
    ,就必须确保
    o
    保持活动状态

    更新(与略加编辑的问题相匹配):

    积分参数alpha不能是类变量(即,它必须在params参数内传递给被积函数)


    这是相当容易做到的。在我的原始代码中,我使用了一个类变量,但现在我将它们作为元组分别传入。

    我编辑了地址注释2的答案。我不明白为什么注1“任何self.\u被积函数的包装器都必须在CalcSomething类中定义。”这是一个要求?是什么阻止您在类之外声明包装器函数?这可能只是一个实现选择,但我想了解这是否可能。正如在我的原始问题中所描述的(可能很差/不清楚),当被积函数在类之外时,代码确实可以正确编译和运行,因此在这种情况下不需要包装。我认为“不容易”。不知何故,ctypes找到了一种方法(请参阅)来实现非常类似的功能。(我认为cffi也能做到这一点)。它是如何做到这一点的,看起来非常复杂,但是你可能能够稍微混合Cython和ctypes,以通过一点努力来完成你想要的。我想我将把寻找解决方案留给注释1。现在:听起来比在一个类中包含所有内容更糟糕可能我做了一些愚蠢的事情,但是在传递
    alpha
    的情况下,我将
    integrate
    函数更改为具有以下行:
    cdef object o=(self,alpha);cdef void*p=o;cdef gsl_函数F;F.function=&wrapped\u被积函数\u func;F.params=p
    但是我得到了一个运行时错误,
    cython\u class\u gsl.CalcSomething'object没有属性'integrand'”在'cython\u class\u gsl.wrapped\u integrand\u func
    中,我无法理解为什么
    wrapped\u integrand\u func
    在这种情况下看不到
    integrand
    方法?(它们都是
    cdef
    )哦,将
    integrand
    定义为
    cpdef
    类型是可行的,但不确定为什么
    cdef
    wrapped\u integrand\u func
    的小更新后没有起作用,从而在
    void*参数中包含
    alpha
    ,这是我的错(我没有正确测试我的编辑…)。为了使用
    cdef
    函数,Cython需要被告知对象的类型(它找不到类似Python的运行时)。我现在已经解决了这个问题(
    cdef CalcSomething instance=params_as_object[0]
    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
    
    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))