设计与 `scipy.integrate.odeint` 交互的 Python 类 的启发式方法?

Design heuristics for writing Python classes that interact with `scipy.integrate.odeint`?

简介

scipy.integrate.odeint 需要一个函数作为其第一个参数,该函数计算我们要积分的变量的导数(我将其称为 d_func,因为 "derivative function"今后)。

d_func 必须由用户在 Python 代码中编写。使用 Numba 提高性能的一个好方法是 @jit d_func(因为 d_func 在集成期间被调用 很多 次)。

我对如何在 d_func 复杂到需要 Python class 对象的情况下编写高性能代码有疑问。

代码设置

这是我的代码 "cartoon":

我将有一堆函数将采用 DynamixBox 相变量或参数属性,以便计算导数中的相关项。即:

设计选择

我必须做出选择,有以下选项:

  1. 要么我可以制作 d_func 及其所有辅助函数方法 DynamicBox;
  2. 或者我只能d_func一个DynamicBox的方法, 并且它的所有辅助函数都在同一个模块中 DynamicBox,但不是 DynamicBox;
  3. 的方法
  4. 或者只有辅助函数是DynamicBox的方法,但是 d_func 只是在同一个模块 (DynamicBox.py) 中,而不是 DynamicBox;
  5. 的方法
  6. 或者辅助函数和d_func都不是 动态框.

问题

我对 Python 的了解还不够,无法找出最佳选择。我认为需要回答以下问题。

我可以评论这个问题的 Numba 部分。

正如其他用户所提到的,Numba 中的属性访问会导致一些开销。例如,您可能想编写如下代码:

class Foo(object):
    def __init__(self, x):
        self.x = x

    @numba.jit
    def dosomething(self, y):
        for i in range(len(self.x)):
            self.x[i] += y[i]

这样会很慢,因为Numba每次遇到self.x.

都要调用Python层进行属性访问

做同样事情的更好方法是:

class Foo(object):
    def __init__(self, x):
        self.x = x

    def dosomething(self, y):
        _dosomething(self.x, y)

@numba.jit(nopython=True)
def _dosomething(x, y):
    for i in range(len(x)):
        x[i] += y[i]

这里在循环中没有属性访问,另外我们可以添加 nopython=True 参数,如果函数必须回退到任何(慢速),这将导致 Numba 引发错误) Python 代码。这个 nopython 参数是确保您的 Numba 函数尽可能高效的好方法。