用于编写与`scipy.integrate.odeint'交互的Python类的设计启发法? [英] Design heuristics for writing Python classes that interact with `scipy.integrate.odeint`?

查看:105
本文介绍了用于编写与`scipy.integrate.odeint'交互的Python类的设计启发法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简介



scipy.integrate.odeint 要求作为其第一个参数,该函数计算我们要变量的导数集成(从现在开始,我将其称为 d_func ,用于微分函数)。



d_func 必须由用户使用Python代码编写。使用Numba提升性能的一种好方法是 @jit d_func (因为 d_func 在集成过程中被称为很多次。



我对如何在 d_func 非常复杂,它后面需要一个Python类对象。



代码设置



这里是我代码的卡通:




  • 在此模块内部有一个名为 DynamicBox.py

  • 的模块一个Python类, DynamicBox

  • DynamicBox 有很多属性

  • 其中一些属性是相位变量,即它们是我要积分的数量

  • 其中一些属性是参数,也就是说,我用它们来
    计算相位变量的导数



我将有一堆函数,这些函数将使用 DynamixBox 相位变量或参数属性,以便计算导数中的相关项。那就是:




  • 我将有一个 d_func

  • d_func 本身将使用 DynamixBox 计算导数中的相关项$ c>
    属性



设计选择



我有选择以下选项:


  1. 我可以使 d_func 以及
    DynamicBox 的所有辅助函数方法;

  2. 或者我只能使用 DynamicBox ,$ b的方法制作 d_func $ b及其所有辅助功能与
    DynamicBox 在同一模块中,但不是 DynamicBox ;

  3. 或仅辅助函数是 DynamicBox 的方法,而
    d_func 只是在同一模块( DynamicBox.py )中,而不是 DynamicBox 方法$ c>;

  4. 或辅助功能或d_func都不是
    DynamicBox的方法。



问题



我对Python不够了解,无法确定哪种选择是最好的。我认为需要回答以下问题。




  • 进行实例属性调用以获取属性是否昂贵?仅当您使用的不是类的方法
    时,它才昂贵吗?


  • 如果Numba怎么办?在玩吗?例如,如果我使用 @jit -ting普通函数而不是类方法,Numba会更喜欢吗?



解决方案

我可以对此问题的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 参数,w如果函数必须依靠任何(慢速)Python代码,则hich将导致Numba引发错误。此 nopython 参数是确保Numba函数尽可能高效的好方法。


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?

解决方案

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.

这篇关于用于编写与`scipy.integrate.odeint'交互的Python类的设计启发法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆