Python 如何将附加参数传递给numba cfunc,作为低级别可调用传递给scipy.integrate.quad

Python 如何将附加参数传递给numba cfunc,作为低级别可调用传递给scipy.integrate.quad,python,scipy,numba,Python,Scipy,Numba,使用numba的cfuncs作为scipy.integrate.quad的lovelcallable参数的文档。我需要同样的东西和额外的参数 我基本上是想做这样的事情: import numpy as np from numba import cfunc import numba.types voidp = numba.types.voidptr def integrand(t, params): a = params[0] # this is additional parameter

使用numba的
cfunc
s作为
scipy.integrate.quad
lovelcallable
参数的文档。我需要同样的东西和额外的参数

我基本上是想做这样的事情:

import numpy as np
from numba import cfunc
import numba.types
voidp = numba.types.voidptr
def integrand(t, params):
    a = params[0] # this is additional parameter
    return np.exp(-t/a) / t**2
nb_integrand = cfunc(numba.float32(numba.float32, voidp))(integrand)
但是,它不起作用,因为
参数
应该是
voidptr
/
void*
,并且它们不能转换为
double
。我收到以下错误消息:

TypingError: Failed at nopython (nopython frontend)
Invalid usage of getitem with parameters (void*, int64)
 * parameterized

我在Numba中没有找到关于如何从
void*
提取值的任何信息。在C中,它应该类似于
a=*((双*)参数)
-在Numba中也可以做同样的事情吗?

1。通过scipy.integrate.quad传递额外参数

他们说:

如果用户希望提高集成性能,则
f
可以是具有以下签名之一的
scipy.lovelCallable

double func(双x)

double func(双x,无效*用户数据)

double func(int n,double*xx)

double func(int n,double*xx,void*user\u数据)

user\u数据
是包含在
scipy.lovelCallable
中的数据。在具有
xx
的调用表单中,
n
xx
数组的长度,该数组包含
xx[0]==x
其余项是
四元组的
args
参数中包含的数字

因此,要通过
quad
向被积函数传递额外的参数,最好使用
double func(int n,double*xx)
签名

您可以为被积函数编写一个decorator,将其转换为
低层可调用的
,如下所示:

import numpy as np
import scipy.integrate as si
import numba
from numba import cfunc
from numba.types import intc, CPointer, float64
from scipy import LowLevelCallable


def jit_integrand_function(integrand_function):
    jitted_function = numba.jit(integrand_function, nopython=True)
    
    @cfunc(float64(intc, CPointer(float64)))
    def wrapped(n, xx):
        return jitted_function(xx[0], xx[1])
    return LowLevelCallable(wrapped.ctypes)

@jit_integrand_function
def integrand(t, *args):
    a = args[0]
    return np.exp(-t/a) / t**2

def do_integrate(func, a):
    """
    Integrate the given function from 1.0 to +inf with additional argument a.
    """
    return si.quad(func, 1, np.inf, args=(a,))

print(do_integrate(integrand, 2.))
>>>(0.326643862324553, 1.936891932288535e-10)
或者,如果您不需要装饰器,请手动创建
LowLevelCallable
,并将其传递给
quad

2。包装被积函数

我不确定以下各项是否满足您的要求,但您也可以包装您的
被积函数以实现相同的结果:

import numpy as np
from numba import cfunc
import numba.types

def get_integrand(*args):
    a = args[0]
    def integrand(t):
        return np.exp(-t/a) / t**2
    return integrand

nb_integrand = cfunc(numba.float64(numba.float64))(get_integrand(2.))

import scipy.integrate as si
def do_integrate(func):
    """
    Integrate the given function from 1.0 to +inf.
    """
    return si.quad(func, 1, np.inf)

print(do_integrate(get_integrand(2)))
>>>(0.326643862324553, 1.936891932288535e-10)
print(do_integrate(nb_integrand.ctypes))
>>>(0.326643862324553, 1.936891932288535e-10)
3。从
voidptr
转换为python类型

我认为这还不可能。从2016年开始,
voidptr
似乎只是在这里向C回调传递上下文

void*指针的情况适用于API,其中外部C代码并不每次都尝试取消对指针的引用,而只是将其传递回回调,作为回调在调用之间保持状态的方式。我认为目前这一点并不特别重要,但我想提出这个问题

并尝试以下方法:

numba.types.RawPointer('p').can_convert_to(
    numba.typing.context.Context(), CPointer(numba.types.Any)))
>>>None

这似乎也不令人鼓舞

这里的技巧与雅克·高丁(Jacques Gaudin)提出的第一点相同,但有几个论点

将numpy导入为np
导入scipy.integrate作为si
进口麻木
来自numba进口cfunc
从numba.types导入intc、CPointer和float64
从scipy导入低级可调用
def jit_被积函数(被积函数):
jitted_函数=numba.jit(被积函数,nopython=True)
@cfunc(float64(intc,CPointer(float64)))
def包装(n,xx):
值=carray(xx,n)
返回jitted_函数(值)
返回低级别可调用(wrapped.ctypes)
@jit_被积函数
def被积函数(args):
t=args[0]
a=args[1]
b=args[2]
返回b*np.exp(-t/a)/t**2
def do_集成(func,a):
"""
将给定函数从1.0集成到+inf,并使用附加参数a。
"""
返回si.quad(func,1,np.inf,args=(a,b,)

Hello,您能将其扩展到几个参数吗?在
def wrapped(n,XX)
中,n是参数的数量,XX是参数值的列表/数组。因此,您可以轻松地将上述内容调整为任意数量的参数。如果您在第三点中提到此内容,您可以使用
double func(double x,void*user_data)
签名来传递numpy数组(包括一些元数据,如shape)和其他内容。例子: