我可以通过包装或 cython 重新声明 gsl_function 将 cython class 方法分配给 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.h
和 gsl/gsl_math.h
头文件相关部分的 cython 声明,然后定义一个 class 计算积分:
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
以上代码编译并正确运行,因为使用 class 之外的被积函数 (F.function = &integrand
)。但是,将此行更改为下面注释掉的行 (F.function = &self._integrand
) 以便使用 class 中的被积函数 会带来以下编译错误:
cython_class_gsl.pyx:31:21: Cannot assign type 'double (*)(CalcSomething, double, void *)' to 'double (*)(double, void *)'
这是有道理的,因为我在 cGslInteg.pxd
中对 gsl_function
的声明是:
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 *)
?
编辑:
一些额外的注释,使它更接近现实生活 problem/issue:
self._integrand
的任何包装器 都有 在 CalcSomething
class 中定义。
- 积分参数
alpha
不能是 class 变量(即它必须在 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_ptr
.
,您就必须确保 o
保持活动状态
更新(以匹配稍微编辑过的问题):
The integration parameter alpha cannot be a class variable (i.e. it must be passed within the params argument to the integrand)
这很容易做到。在我的原始代码中,我使用了一个 class 变量,但我现在将它们作为元组分别传递。
这个问题建立在
我有以下 cython 代码,它导入一个文件 (cGslInteg.pxd
),其中包含 gsl/gsl_integration.h
和 gsl/gsl_math.h
头文件相关部分的 cython 声明,然后定义一个 class 计算积分:
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
以上代码编译并正确运行,因为使用 class 之外的被积函数 (F.function = &integrand
)。但是,将此行更改为下面注释掉的行 (F.function = &self._integrand
) 以便使用 class 中的被积函数 会带来以下编译错误:
cython_class_gsl.pyx:31:21: Cannot assign type 'double (*)(CalcSomething, double, void *)' to 'double (*)(double, void *)'
这是有道理的,因为我在 cGslInteg.pxd
中对 gsl_function
的声明是:
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 *)
?
编辑: 一些额外的注释,使它更接近现实生活 problem/issue:
self._integrand
的任何包装器 都有 在CalcSomething
class 中定义。- 积分参数
alpha
不能是 class 变量(即它必须在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_ptr
.
o
保持活动状态
更新(以匹配稍微编辑过的问题):
The integration parameter alpha cannot be a class variable (i.e. it must be passed within the params argument to the integrand)
这很容易做到。在我的原始代码中,我使用了一个 class 变量,但我现在将它们作为元组分别传递。