将 NumPy 数组作为参数传递给 numba.cfunc

mos*_*gui 7 c python scipy python-3.x numba

我一直在与一个我无法解决的问题作斗争,因此不太知道如何开始解决它。我在C语言编程方面的经验非常有限,我认为这就是我无法取得进步的原因。

\n\n

我有一些函数使用numpy.interpscipy.integrate.quad来执行一定的积分。自从我使用quad集成,并且根据其文档:

\n\n
\n

要集成的 Python 函数或方法。如果func采用多个参数,则沿第一个参数对应的轴进行积分。

\n\n

如果用户希望提高集成性能,则f可能是\n scipy.LowLevelCallable之一:

\n\n
double func(double x)\ndouble func(double x, void *user_data) \ndouble func(int n, double *xx) \ndouble func(int n, double *xx, void *user_data) \n
Run Code Online (Sandbox Code Playgroud)\n\n

user_data 是包含在scipy.LowLevelCallable. 在 的调用形式中xx,是包含的数组n的长度xxxx[0] == x,其余项是quad 的 args 参数中包含的数字。

\n\n

此外,还支持某些 ctypes 调用签名以实现向后兼容,但这些签名不应在新代码中使用。

\n
\n\n

我需要使用这些scipy.LowLevelCallable对象来加速我的代码,并且我需要将我的函数设计坚持上述签名之一。此外,由于我不想使用 C 库和编译器使整个事情变得复杂,所以我想使用 中提供的工具“即时”解决这个问题numba,特别是numba.cfunc,这允许我绕过 Python C API。

\n\n

我已经能够解决这个被积函数的问题,该被积函数将积分变量和任意数量的标量参数作为输入:

\n\n
double func(double x)\ndouble func(double x, void *user_data) \ndouble func(int n, double *xx) \ndouble func(int n, double *xx, void *user_data) \n
Run Code Online (Sandbox Code Playgroud)\n\n

这段代码工作得很好。我能够 jit 被积函数并将 jitted 函数作为LowLevelCallable对象返回。然而,我实际上需要传递给我的被积函数 2 numpy.array,并且上述构造中断:

\n\n
    from scipy import integrate, LowLevelCallable\n    from numba import njit, cfunc\n    from numba.types import intc, float64, CPointer\n\n\n    def jit_integrand_function(integrand_function):\n        jitted_function = njit(integrand_function)\n\n        @cfunc(float64(intc, CPointer(float64)))\n        def wrapped(n, xx):\n            return jitted_function(xx[0], xx[1], xx[2], xx[3])\n        return LowLevelCallable(wrapped.ctypes)\n\n    @jit_integrand_function\n    def regular_function(x1, x2, x3, x4):\n        return x1 + x2 + x3 + x4\n\n    def do_integrate_wo_arrays(a, b, c, lolim=0, hilim=1):\n        return integrate.quad(regular_function, lolim, hilim, (a, b, c))\n\n    >>> print(do_integrate_wo_arrays(1,2,3,lolim=2, hilim=10))\n    (96.0, 1.0658141036401503e-12)\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在好了,显然这不起作用,因为在这个例子中我没有修改装饰器的设计。但这正是我问题的核心:我不完全理解这种情况,因此不知道如何修改参数cfunc以将数组作为参数传递并仍然遵守scipy.integrate.quad签名要求。在numba介绍的文档中CPointers有一个如何将数组传递给 a 的示例numba.cfunc

\n\n
\n

C 或 C++ 使用的本机平台 ABI don\xe2\x80\x99t 具有 Numpy 中的 n 形数组的概念。一种常见的解决方案是传递原始数据指针和一个或多个大小参数(取决于维数)。Numba 必须提供一种在回调内重建此数据的数组视图的方法。

\n\n
    from scipy import integrate, LowLevelCallable\n    from numba import njit, cfunc\n    from numba.types import intc, float64, CPointer\n\n\n    def jit_integrand_function(integrand_function):\n        jitted_function = njit(integrand_function)\n\n        @cfunc(float64(intc, CPointer(float64)))\n        def wrapped(n, xx):\n            return jitted_function(xx[0], xx[1], xx[2], xx[3])\n        return LowLevelCallable(wrapped.ctypes)\n\n    @jit_integrand_function\n    def function_using_arrays(x1, x2, array1, array2):\n        res1 = np.interp(x1, array1[0], array1[1])\n        res2 = np.interp(x2, array2[0], array2[1])\n\n        return res1 + res2\n\n    def do_integrate_w_arrays(a, lolim=0, hilim=1):\n        foo = np.arange(20, dtype=np.float).reshape(2, -1)\n        bar = np.arange(60, dtype=np.float).reshape(2, -1)\n\n        return integrate.quad(function_using_arrays, lolim, hilim, (a, foo, bar))\n\n\n    >>> print(do_integrate_w_arrays(3, lolim=2, hilim=10))\n    Traceback (most recent call last):\n      File "C:\\ProgramData\\Miniconda3\\lib\\site-packages\\IPython\\core\\interactiveshell.py", line 3267, in run_code\n        exec(code_obj, self.user_global_ns, self.user_ns)\n      File "<ipython-input-63-69c0074d4936>", line 1, in <module>\n        runfile(\'C:/Users/mosegui/Desktop/fos4x_pkg_develop/python-packages/fos4x_tec/fos4x_tec/test_scipy_numba.py\', wdir=\'C:/Users/mosegui/Desktop/fos4x_pkg_develop/python-packages/fos4x_tec/fos4x_tec\')\n      File "C:\\Program Files\\JetBrains\\PyCharm Community Edition 2018.3.4\\helpers\\pydev\\_pydev_bundle\\pydev_umd.py", line 197, in runfile\n        pydev_imports.execfile(filename, global_vars, local_vars)  # execute the script\n      File "C:\\Program Files\\JetBrains\\PyCharm Community Edition 2018.3.4\\helpers\\pydev\\_pydev_imps\\_pydev_execfile.py", line 18, in execfile\n        exec(compile(contents+"\\n", file, \'exec\'), glob, loc)\n      File "C:/Users/mosegui/Desktop/fos4x_pkg_develop/python-packages/fos4x_tec/fos4x_tec/test_scipy_numba.py", line 29, in <module>\n        @jit_integrand_function\n      File "C:/Users/mosegui/Desktop/fos4x_pkg_develop/python-packages/fos4x_tec/fos4x_tec/test_scipy_numba.py", line 13, in jit_integrand_function\n        @cfunc(float64(intc, CPointer(float64)))\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\decorators.py", line 260, in wrapper\n        res.compile()\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\compiler_lock.py", line 32, in _acquire_compile_lock\n        return func(*args, **kwargs)\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\ccallback.py", line 69, in compile\n        cres = self._compile_uncached()\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\ccallback.py", line 82, in _compile_uncached\n        cres = self._compiler.compile(sig.args, sig.return_type)\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\dispatcher.py", line 81, in compile\n        raise retval\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\dispatcher.py", line 91, in _compile_cached\n        retval = self._compile_core(args, return_type)\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\dispatcher.py", line 109, in _compile_core\n        pipeline_class=self.pipeline_class)\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\compiler.py", line 528, in compile_extra\n        return pipeline.compile_extra(func)\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\compiler.py", line 326, in compile_extra\n        return self._compile_bytecode()\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\compiler.py", line 385, in _compile_bytecode\n        return self._compile_core()\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\compiler.py", line 365, in _compile_core\n        raise e\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\compiler.py", line 356, in _compile_core\n        pm.run(self.state)\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\compiler_machinery.py", line 328, in run\n        raise patched_exception\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\compiler_machinery.py", line 319, in run\n        self._runPass(idx, pass_inst, state)\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\compiler_lock.py", line 32, in _acquire_compile_lock\n        return func(*args, **kwargs)\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\compiler_machinery.py", line 281, in _runPass\n        mutated |= check(pss.run_pass, internal_state)\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\compiler_machinery.py", line 268, in check\n        mangled = func(compiler_state)\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\typed_passes.py", line 94, in run_pass\n        state.locals)\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\typed_passes.py", line 66, in type_inference_stage\n        infer.propagate()\n      File "C:\\Users\\mosegui\\AppData\\Roaming\\Python\\Python36\\site-packages\\numba\\typeinfer.py", line 951, in propagate\n        raise errors[0]\n    numba.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)\n    Failed in nopython mode pipeline (step: nopython frontend)\n    Invalid use of Function(<built-in function getitem>) with argument(s) of type(s): (float64, Literal[int](0))\n     * parameterized\n    In definition 0:\n        All templates rejected with literals.\n    In definition 1:\n        All templates rejected without literals.\n    In definition 2:\n        All templates rejected with literals.\n    In definition 3:\n        All templates rejected without literals.\n    In definition 4:\n        All templates rejected with literals.\n    In definition 5:\n        All templates rejected without literals.\n    In definition 6:\n        All templates rejected with literals.\n    In definition 7:\n        All templates rejected without literals.\n    In definition 8:\n        All templates rejected with literals.\n    In definition 9:\n        All templates rejected without literals.\n    In definition 10:\n        All templates rejected with literals.\n    In definition 11:\n        All templates rejected without literals.\n    In definition 12:\n        All templates rejected with literals.\n    In definition 13:\n        All templates rejected without literals.\n    This error is usually caused by passing an argument of a type that is unsupported by the named function.\n    [1] During: typing of intrinsic-call at C:/Users/mosegui/Desktop/fos4x_pkg_develop/python-packages/fos4x_tec/fos4x_tec/test_scipy_numba.py (32)\n    [2] During: typing of static-get-item at C:/Users/mosegui/Desktop/fos4x_pkg_develop/python-packages/fos4x_tec/fos4x_tec/test_scipy_numba.py (32)\n    File "test_scipy_numba.py", line 32:\n    def diff_moment_edge(radius, alpha, chord_df, aerodyn_df):\n        <source elided>\n        # # calculate blade twist for radius\n        # sensor_twist = np.arctan((2 * rated_wind_speed) / (3 * rated_rotor_speed * (sensor_radius / 30.0) * radius)) * (180.0 / np.pi)\n        ^\n    [1] During: resolving callee type: type(CPUDispatcher(<function function_using_arrays at 0x0000020C811827B8>))\n    [2] During: typing of call at C:/Users/mosegui/Desktop/fos4x_pkg_develop/python-packages/fos4x_tec/fos4x_tec/test_scipy_numba.py (15)\n    [3] During: resolving callee type: type(CPUDispatcher(<function function_using_arrays at 0x0000020C811827B8>))\n    [4] During: typing of call at C:/Users/mosegui/Desktop/fos4x_pkg_develop/python-packages/fos4x_tec/fos4x_tec/test_scipy_numba.py (15)\n    File "test_scipy_numba.py", line 15:\n    def jit_integrand_function(integrand_function):\n        <source elided>\n        jitted_function = njit(integrand_function)\n     ^\n\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

我以某种方式理解它CPointer用于在 C 中构建数组,就像在我的装饰器示例的签名中CPointer(float64)收集作为参数传递的所有浮点数并将它们放入数组中一样。但是,我仍然无法将它放在一起,看看如何使用它来传递数组,而不是从集合中创建数组float我传递的参数集合中创建一个数组。

\n\n

编辑:

\n\n

答案是@max9111有效的,从某种意义上说,它能够传递给scipy.integrate.quadaLowLevelCallable从而提高了计算的时间效率。这是非常有价值的,因为现在 C 中内存地址的管理方式更加清晰。尽管原生 C 中不存在结构化数组的概念,但我可以使用 C 将要存储的数据在 Python 中创建一个结构化数组在连续的内存区域中并通过唯一的内存地址访问它/指向它。结构化数组提供的映射允许识别该存储区域的不同组件。

\n\n

尽管该解决方案有效并解决了我最初发布的问题,但从 Python 的角度来看,这种方法会带来一定的开销,在某些条件下,可能比现在通过调用集成函数@max9111所获得的时间更耗时。scipy.integrate.quadLowLevelCallable.

\n\n

在我的实际案例中,我将积分用作二维优化问题的一个步骤。优化的每一步都需要积分两次,积分需要九个标量参数和两个数组。只要我无法通过 a 解决集成问题LowLevelCallable,我唯一能做的就是加快代码速度njit被积函数。即使集成仍然是通过 Python API 触发的,它也能正常工作。

\n\n

就我而言,实施@max9111\ 的解决方案极大地提高了积分时间的效率(从每步约 0.0009 秒到约 0.0005 秒)。尽管如此,创建结构化数组、对数据进行 C 解包、将其传递给抖动被积函数并返回 a 的步骤LowLevelCallable平均每次迭代增加了 0.3 秒,从而使我的情况变得更糟。

\n\n

这里有一些玩具代码,用于展示LowLevelCallable迭代过程越多,该方法如何变得越糟糕:

\n\n
    from numba import cfunc, carray\n    from numba.types import float64, CPointer, void, intp\n\n    # A callback with the C signature `void(double *, double *, size_t)`\n\n    @cfunc(void(CPointer(float64), CPointer(float64), intp))\n    def invert(in_ptr, out_ptr, n):\n        in_ = carray(in_ptr, (n,))\n        out = carray(out_ptr, (n,))\n        for i in range(n):\n            out[i] = 1 / in_[i] ```\n
Run Code Online (Sandbox Code Playgroud)\n\n

这里比较了两个选项(仅抖动被积函数与@max9111\ 的解)。@max9111在\ 解决方案的修改版本中,我永久地调整了被积函数 ( function_using_arrays) 并从 中删除了该步骤create_jit_integrand_function,这将“开销”时间减少了 20%。此外,也是为了速度,我抑制了该jit_with_dummy_data函数并将其功能包含在 的主体中process_lowlev_callable,基本上是为了避免不必要的函数调用。在下面查找两个解决方案对于最多 100 个周期的系列的计算时间:

\n\n

仅抖动被积函数与构建 LowLevelCallable 所花费的计算时间

\n\n

正如您所看到的,如果您处于迭代过程中,则每次计算中节省的时间 (30+ %!!) 并不能抵消构建 LowLevelCallable 所需实现的几个额外函数所带来的开销(函数它们也被迭代调用并通过 Python C API 运行)。

\n\n

底线:该解决方案非常适合减少单个非常重的积分的计算时间,但是在迭代过程中求解平均积分时,仅抖动被积数似乎会更好,因为 LowlevelCallable 需要额外的函数,需要与集成本身一样频繁地被调用,这会造成损失。

\n\n

不管怎样,非常感谢。尽管这个解决方案对我不起作用,但我学到了有价值的东西,并且我认为我的问题得到了解决。

\n\n

编辑2:

\n\n

我误解了@max9111\ 的解决方案的一部分以及函数所扮演的角色create_jit_integrand_function,并且我LowLevelCallable在优化的每个步骤中都错误地编译了(我不需要这样做,因为即使传递给积分的参数和数组每个都发生变化)迭代,它们的形状,因此 C 结构体的形状保持不变)。

\n\n

上面编辑的代码的重构版本是有意义的:

\n\n
\n    import ctypes\n    import timeit\n\n    from tqdm import tqdm\n    import numpy as np\n    from scipy import integrate, LowLevelCallable\n    import numba as nb\n    from numba import types\n    import matplotlib.pyplot as plt\n\n\n    ##################################################\n    # creating some sample data and parameters\n    a = 3\n    foo = np.arange(200, dtype=np.float64).reshape(2, -1)\n    bar = np.arange(600, dtype=np.float64).reshape(2, -1)\n\n    lim1 = 0\n    lim2 = 1\n\n\n    def function_using_arrays(x1, x2, array1, array2):\n        res1 = np.interp(x1, array1[0], array1[1])\n        res2 = np.interp(x2, array2[0], array2[1])\n\n        return res1 + res2\n\n\n    ##################################################\n    # JIT INTEGRAND\n\n    def do_integrate_w_arrays_jit(a, array1, array2, lolim=0, hilim=1):\n        return integrate.quad(nb.njit(function_using_arrays), lolim, hilim, (a, array1, array2))\n\n    def process_jit_integrand():\n        do_integrate_w_arrays_jit(a, foo, bar, lolim=lim1, hilim=lim2)\n\n\n    ##################################################\n    # LOWLEV CALLABLE\n\n    def create_jit_integrand_function(integrand_function, args_dtype):\n        jitted_function = nb.njit(integrand_function)\n\n        @nb.cfunc(types.float64(types.float64,types.CPointer(args_dtype)))\n        def wrapped(x1,user_data_p):\n            #Array of structs\n            user_data = nb.carray(user_data_p, 1)\n\n            #Extract the data\n            x2=user_data[0].a\n            array1=user_data[0].foo\n            array2=user_data[0].bar\n\n            return jitted_function(x1, x2, array1, array2)\n        return wrapped\n\n\n    def do_integrate_w_arrays_lowlev(func,args,lolim=0, hilim=1):\n        integrand_func=LowLevelCallable(func.ctypes,user_data=args.ctypes.data_as(ctypes.c_void_p))\n        return integrate.quad(integrand_func, lolim, hilim)\n\n\n    def process_lowlev_callable():\n        do_integrate_w_arrays_lowlev(func, np.array((a, foo, bar), dtype=args_dtype), lolim=0, hilim=1)\n\n\n    ##################################################\n\n    repetitions = range(100)\n\n    jit_integrand_delays = [timeit.timeit(stmt=process_jit_integrand, number=repetition) for repetition in tqdm(repetitions)]\n\n\n    args_dtype = types.Record.make_c_struct([\n            (\'a\', types.float64),\n            (\'foo\', types.NestedArray(dtype=types.float64, shape=foo.shape)),\n            (\'bar\', types.NestedArray(dtype=types.float64, shape=bar.shape)),])\n    func = create_jit_integrand_function(function_using_arrays, args_dtype)\n\n\n    lowlev_callable_delays = [timeit.timeit(stmt=process_lowlev_callable, number=repetition) for repetition in tqdm(repetitions)]\n\n    fig, ax = plt.subplots()\n    ax.plot(repetitions, jit_integrand_delays, label="jit_integrand")\n    ax.plot(repetitions, lowlev_callable_delays, label="lowlev_callable")\n    ax.set_xlabel(\'number of repetitions\')\n   

max*_*111 3

您可以使用 user_data 输入来传递数组

据我了解scipy.integrate.quad的文档,args在使用scipy.LowLevelCallable时不可能通过参数传递数组,但您可以传递任意 user_data 。

在下面的例子中我使用了这个签名。

double func(double x, void *user_data)

无需重新编译即可编辑任意形状的数组

使用这个答案,还可以为任意数组形状编译一次函数(仅维数是固定的)。

import numpy as np
import numba as nb
from numba import types
from scipy import integrate, LowLevelCallable
import ctypes

#Void Pointer from Int64
@nb.extending.intrinsic
def address_as_void_pointer(typingctx, src):
    """ returns a void pointer from a given memory address """
    from numba import types 
    from numba.core import cgutils
    sig = types.voidptr(src)

    def codegen(cgctx, builder, sig, args):
        return builder.inttoptr(args[0], cgutils.voidptr_t)
    return sig, codegen

def create_jit_integrand_function(integrand_function,args_dtype):
    jitted_function = nb.njit(integrand_function)

    #double func(double x, void *user_data)
    @nb.cfunc(types.float64(types.float64,types.CPointer(args_dtype)))
    def wrapped(x1,user_data_p):
        #Array of structs
        user_data = nb.carray(user_data_p, 1)

        #Extract the data
        x2=user_data[0].a
        array1=nb.carray(address_as_void_pointer(user_data[0].foo_p),(user_data[0].foo_s1,user_data[0].foo_s2),dtype=np.float64)
        array2=nb.carray(address_as_void_pointer(user_data[0].bar_p),(user_data[0].bar_s1,user_data[0].bar_s2),dtype=np.float64)

        return jitted_function(x1, x2, array1, array2)
    return wrapped

def function_using_arrays(x1, x2, array1, array2):
    res1 = np.interp(x1, array1[0], array1[1])
    res2 = np.interp(x2, array2[0], array2[1])

    return res1 + res2

def do_integrate_w_arrays(func,args,lolim=0, hilim=1):
    integrand_func=LowLevelCallable(func.ctypes,user_data=args.ctypes.data_as(ctypes.c_void_p))
    return integrate.quad(integrand_func, lolim, hilim)

#Define the datatype of the struct array
#Pointers are not allowed, therefore we use int64
args_dtype = types.Record.make_c_struct([
    ('a', types.float64),
    ('foo_p',  types.int64),
    ('foo_s1', types.int64),
    ('foo_s2', types.int64),
    ('bar_p',  types.int64),
    ('bar_s1', types.int64),
    ('bar_s2', types.int64),])

#creating some sample data
#The arrays must be c-contigous
#To ensure that you can use np.ascontiguousarray

a=3
foo = np.ascontiguousarray(np.arange(200, dtype=np.float64).reshape(2, -1))
bar = np.ascontiguousarray(np.arange(600, dtype=np.float64).reshape(2, -1))


args=np.array((a,foo.ctypes.data,foo.shape[0],foo.shape[1],
                 bar.ctypes.data,bar.shape[0],bar.shape[1]),dtype=args_dtype)

#compile the integration function (array-shapes are fixed)
#There is only a structured array like args allowed
func=create_jit_integrand_function(function_using_arrays,args_dtype)


print(do_integrate_w_arrays(func,args, lolim=0, hilim=1))
Run Code Online (Sandbox Code Playgroud)

旧版

当我传递结构化数组时,如果数组形状或数据类型发生变化,则需要重新编译。这不是 API 本身的限制。必须有一种方法可以更简单地做到这一点(也许使用元组?)

执行

import numpy as np
import numba as nb
from numba import types
from scipy import integrate, LowLevelCallable
import ctypes

def create_jit_integrand_function(integrand_function,args,args_dtype):
    jitted_function = nb.njit(integrand_function)

    @nb.cfunc(types.float64(types.float64,types.CPointer(args_dtype)))
    def wrapped(x1,user_data_p):
        #Array of structs
        user_data = nb.carray(user_data_p, 1)

        #Extract the data
        x2=user_data[0].a
        array1=user_data[0].foo
        array2=user_data[0].bar

        return jitted_function(x1, x2, array1, array2)
    return wrapped

def function_using_arrays(x1, x2, array1, array2):
    res1 = np.interp(x1, array1[0], array1[1])
    res2 = np.interp(x2, array2[0], array2[1])

    return res1 + res2

def jit_with_dummy_data(args,args_dtype):
    func=create_jit_integrand_function(function_using_arrays,args,args_dtype)
    return func

def do_integrate_w_arrays(func,args,lolim=0, hilim=1):
    integrand_func=LowLevelCallable(func.ctypes,user_data=args.ctypes.data_as(ctypes.c_void_p))
    return integrate.quad(integrand_func, lolim, hilim)
Run Code Online (Sandbox Code Playgroud)

使用实施

#creating some sample data
a=3
foo = np.arange(200, dtype=np.float64).reshape(2, -1)
bar = np.arange(600, dtype=np.float64).reshape(2, -1)

args_dtype = types.Record.make_c_struct([
    ('a', types.float64),
    ('foo', types.NestedArray(dtype=types.float64, shape=foo.shape)),
    ('bar', types.NestedArray(dtype=types.float64, shape=bar.shape)),])

args=np.array((a,foo,bar),dtype=args_dtype)

#compile the integration function (array-shapes are fixed)
#There is only a structured array like args allowed
func=jit_with_dummy_data(args,args_dtype)


print(do_integrate_w_arrays(func,args, lolim=0, hilim=1))
Run Code Online (Sandbox Code Playgroud)