【问题标题】:Pass args for solve_ivp (new SciPy ODE API)为solve_ivp 传递参数(新的SciPy ODE API)
【发布时间】:2018-06-23 01:36:49
【问题描述】:

为了使用 SciPy 解决简单的 ODE,我曾经使用 odeint 函数,形式为:

scipy.integrate.odeint(func, y0, t, args=(), Dfun=None, col_deriv=0, full_output=0, ml=None, mu=None, rtol=None, atol=None, tcrit=None, h0=0.0, hmax=0.0, hmin=0.0, ixpr=0, mxstep=0, mxhnil=0, mxordn=12, mxords=5, printmessg=0)[source]

要集成的简单函数可以包含以下形式的附加参数:

def dy_dt(t, y, arg1, arg2):
    # processing code here

在 SciPy 1.0 中,似乎 odeodeint 函数已被更新的 solve_ivp 方法取代。

scipy.integrate.solve_ivp(fun, t_span, y0, method='RK45', t_eval=None, dense_output=False, events=None, vectorized=False, **options)

但是,这似乎没有提供 args 参数,文档中也没有任何关于实现 args 传递的指示。

因此,我想知道新 API 是否可以传递参数,或者这是一个尚未添加的功能? (如果有意删除此功能,我会觉得这是一种疏忽?)

参考: https://docs.scipy.org/doc/scipy/reference/integrate.html

【问题讨论】:

    标签: python numpy scipy ode odeint


    【解决方案1】:

    最近scipy's github上出现了一个类似的问题。他们的解决方案是使用lambda

    solve_ivp(fun=lambda t, y: fun(t, y, *args), ...)
    

    他们认为已经有足够的开销,这无关紧要。

    【讨论】:

    • 我阅读了 cmets,与简单的 arg=() 相比,似乎很多人对 lambda 的使用并不满意。他们仍然有例子,因为我不使用 lambda 我仍然不确定该怎么做。您能否发布一个完整的示例,我认为很多人都会受益。
    【解决方案2】:

    新函数似乎没有args 参数。作为一种解决方法,您可以创建一个包装器,如

    def wrapper(t, y):
        orig_func(t,y,hardcoded_args)
    

    然后把它传进去。

    【讨论】:

    • 谢谢,虽然这似乎是 solve_ivp 的一个严重问题(包装器希望增加开销并在我的应用程序中变慢)。因此,我将回到旧 API。我想知道为什么开发人员会做出如此倒退的举动?
    • 同意,这对于新手和普通用户来说太复杂了。不知道开发人员在想什么。更糟糕的是,他们甚至没有在文档中为这种非常常见的情况提供示例。
    【解决方案3】:

    最近将“args”选项添加到solve_ivp,请参见此处:https://github.com/scipy/scipy/issues/8352#issuecomment-535689344

    【讨论】:

    • 欢迎提供解决方案链接,但请确保您的答案在没有它的情况下有用:add context around the link 这样您的其他用户就会知道它是什么以及为什么会出现,然后引用最相关的您链接到的页面的一部分,以防目标页面不可用。 Answers that are little more than a link may be deleted..
    • 您或许应该直接添加它预计将从 scipy 版本 1.4 开始提供。
    【解决方案4】:

    根据Javier-Acuna's ultra-brief, ultra-useful answer,最近添加了您(以及我)想要的功能。这就是伟大的 Warren Weckesser(见他的GithubStackOverflow)本人的announced on Github。 无论如何,除了docstring of solve_ivp 的笑话之外,还有一个将它用于`Lotka-Volterra equations 的示例

    解决_ivp( 乐趣, t_span, y0, 方法='RK45', t_eval=无, 密集输出=假, 事件=无, 矢量化=假, args=无, **选项, )

    因此,只需将 args 包含为元组即可。你的情况

    args = (arg1, arg2)
    

    请不要使用我的答案,除非您的 scipy 版本 >= 1.4 。 对于低于它的版本,solve_ivp 中没有 args 参数。我亲身经历了我对 1.2.1 版的回答失败。

    如果您的 scipy 版本 ,zahabaz 的实现可能仍然可以正常工作

    【讨论】:

      【解决方案5】:

      为了完整起见,我认为您也可以这样做,但我不确定您为什么要打扰,因为此处发布的其他两个选项都很好。

      from functools import partial
      fun = partial(dy_dt, arg1=arg1, arg2=arg2)
      scipy.integrate.solve_ivp(fun, t_span, y0, method='RK45', t_eval=None, dense_output=False, events=None, vectorized=False, **options)
      

      【讨论】:

        【解决方案6】:

        添加到 Cleb 的答案中,这是使用 lambda t,y: fun(t,y,args) 方法的示例。我们设置了函数句柄,它返回带有两个参数的二阶齐次 ODE 的 rhs。然后我们将它与几个选项一起提供给我们的求解器。

        import numpy as np
        from scipy import integrate
        import matplotlib.pyplot as plt
        
        
        def rhs_2nd_order_ode(t, y, a, b):
            """
            2nd order ODE function handle for use with scipy.integrate.solve_ivp
            Solves u'' + au'+ bu = 0 after reducing order with y[0]=u and y[1]=u'.
        
            :param t: dependent variable
            :param y: independent variables
            :param a: a
            :param b: b
            :return: Returns the rhs of y[0]' = y[1] and y[1]' = -a*y[1] - b*y[0]
            """
            return [y[1], -a*y[1] - b*y[0]]
        
        
        if __name__ == "__main__":
            t_span = (0, 10)
            t_eval = np.linspace(t_span[0], t_span[1], 100)
            y0 = [0, 1]
            a = 1
            b = 2
            sol = integrate.solve_ivp(lambda t,y: rhs_2nd_order_ode(t,y,a,b), t_span, y0, 
                                      method='RK45', t_eval=t_eval)
        
            fig, ax = plt.subplots(1, 1)
            ax.plot(sol.t, sol.y[0])
            ax.set(xlabel='t',ylabel='y')
        

        【讨论】:

          猜你喜欢
          • 2020-10-24
          • 2021-08-12
          • 2020-11-28
          • 2019-09-16
          • 2022-01-04
          • 2019-12-23
          • 1970-01-01
          • 2019-11-06
          • 2020-05-09
          相关资源
          最近更新 更多