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

巧了我就是萌 提交于 2019-12-24 02:39:14

问题


Introduction

scipy.integrate.odeint requires as its first argument, a function that computes the derivatives of the variables we want to integrate over (which I'll refer to as d_func, for "derivative function" from now on).

d_func has to be written by the user, in Python code. A great way to get a boost of performance using Numba is to @jit the d_func (because d_func is called many times during integration).

I have questions about how to write performant code when d_func is complicated enough that it needs a Python class object behind it.

Code setup

Here is a "cartoon" of my code:

  • there is a module called DynamicBox.py
  • inside this module is a Python class, DynamicBox
  • DynamicBox has a bunch of attributes
  • some of these attributes are "phase variables" -- that is, they are the quantities I am interested in integrating
  • some of these attributes are "parameters" -- that is, I use them to calculate the derivatives of the phase variables

I will have a bunch of functions that will take DynamixBox phase variable or parameter attributes, in order to calculate relevant terms in the derivatives. That is:

  • I will have a d_func
  • d_func itself will call lots of little helper functions to calculate relevant terms in the derivative, using DynamixBox attributes

Design choices

I have to make a choice, with the following options:

  1. either I can make d_func and all its helper functions methods of DynamicBox;
  2. or I can make only d_func a method of DynamicBox, and all of its helper functions are in the same module as DynamicBox, but not methods of DynamicBox;
  3. or only the helper functions are methods of DynamicBox, but d_func is just in the same module (DynamicBox.py), and not a method of DynamicBox;
  4. or neither the helper functions, nor d_func, are methods of DynamicBox.

Question

I do not know enough about Python to figure out which choice is best. The following questions I think would need answering.

  • Is it expensive to make instance attribute calls to get attributes or is it expensive only if you are in a function that is not a method of the class?

  • What if Numba is in play? For instance, will Numba like it better if I am @jit-ting normal functions instead of class methods?


回答1:


I can comment on the Numba portion of this question.

As other users have mentioned, attribute access in Numba leads to some overhead. For example, you might be tempted to write code like this:

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]

This will be slow, because Numba has to call into the Python layer for attribute access each time it encounters self.x.

A better way to do the same thing would be this:

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]

Here there is no attribute access within the loop, and additionally we're able to add the nopython=True argument, which will cause Numba to raise an error if the function has to fall back on any (slow) Python code. This nopython argument is a great way to make sure that your Numba functions are as efficient as possible.



来源:https://stackoverflow.com/questions/30016845/design-heuristics-for-writing-python-classes-that-interact-with-scipy-integrate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!