Python 我是否可以通过包装或cython重新声明gsl_函数,将cython类方法分配给gsl_函数结构?
这个问题建立在这个问题之上 我有以下cython代码,它导入一个文件(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
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 = ¶ms
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))