web-dev-qa-db-ja.com

solve_ivpの引数を渡す(新しいSciPy ODE API)

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では、odeおよびodeint関数が置き換えられたようです新しい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

18
sharkmas

新しい関数にargsパラメータがあるようには見えません。回避策として、次のようなラッパーを作成できます

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

それを渡します。

9
rlee827

比較的最近、同様の質問が scipy's github に出てきました。彼らの解決策はlambdaを使うことです:

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

そして、彼らはこれが問題にならないためにすでに十分なオーバーヘッドがあると主張します。

12
Lev K.

最近 'args'オプションがsolve_ivpに追加されました。ここを参照してください https://github.com/scipy/scipy/issues/8352#issuecomment-535689344

4
Javier-Acuna

Javier-Acunaの非常に簡潔で非常に便利な回答 によると、あなた(そして私も)が望む機能が最近追加されました。これは Githubで発表された 偉大なウォーレンウェッケサー(彼の GithubStackOverflow を参照)自身によるものでした。とにかく、 docstring of solve_ivp 以外のジョークには、それを ` Lotka-Volterra方程式 に使用する例があります。

solve_ivp(fun、t_span、y0、method = 'RK45'、t_eval = None、density_output = False、events = None、vectorized = False、args = None、** options、)

したがって、タプルとしてargsを含めるだけです。あなたの場合

args = (arg1, arg2)

あなたのscipyバージョン> = 1.4でない限り、私の答えを使用しないでください。その下のバージョンのsolve_ivpにはargsパラメーターはありません。私は個人的にバージョン1.2.1で失敗した私の答えを経験しました。

zahabaz による実装は、scipyバージョンが1.4未満の場合でもおそらく正常に動作します

2
Tejas Shetty

クレブの答えに加えて、これがlambda t,y: fun(t,y,args)メソッドの使用例です。 2つのパラメーターを持つ2次同次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')
1
zahbaz

完全を期すために、これも可能だと思いますが、ここに掲載されている他の2つのオプションが問題なく動作する理由を理解できません。

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)
1
Bill