1

ODE ソルバーを作成して Python の学習を始めています。1 変数または多変数の入力関数の両方を透過的に処理したいと考えています。オイラーの方法の 1 ステップのコードは次のとおりです。

def euler(h, t, y, f):
    return (y + h*f for y,f in zip(y,f(t,y)))

f1ここで、次のf2ように 2 つの関数を定義します。

def f1(t,y):
    return -2*t*y

def f2(t,y):
    x, y = y #is rebinding usually ok, or confusing?
    return (x - t*y, y + x/t)

私がそれらをテストすると、それが(明らかに)起こることです

>>> list(euler(0.01, 1, (1,2), f2))
[0.99, 2.03]
>>> list(euler(0.01, 1, 1, f1))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in euler
TypeError: zip argument #1 must support iteration

与えられた関数が 1 つ以上の変数で機能する場合、ソルバーが透過的に処理することを望みますが、それを行うクールな方法が見つかりません。私が見つけた方法は

import operator as op
def euler(h, t, y, f):
    if op.isNumberType(y):
        return (y + h*f(t,y),)
    return (y + h*f for y,f in zip(y,f(t,y)))

しかし、フロートを渡してlist(euler(...))イテラブルを返したので、成功することができます。ただし、たとえばf(t,euler(...)).

シングルトン シーケンスをプリミティブ型として処理する方法、またはプリミティブをシングルトン シーケンスとしてエンドレス チェックなしで処理する方法はありますか? 「無限のチェック」とは、コード全体ではなく、いくつかの場所だけをチェックする必要があることを意味します。それとも、それを吸い上げてf(t,y)、数値ではなくシーケンスを期待する必要がありますか?

助けてくれてありがとう、そして私のコーディングに関するヒントも大歓迎です!

4

3 に答える 3

1

f(t、y)にシーケンスのみを使用させるのは非常に簡単です。

def euler(h, t, y, f):
    return (y + h*v for y,v in zip(y,f(t,y)))

def f1(t,status):
    x, = status
    return -2*t*x,

def f2(t,status):
    x, y = status
    return x - t*y, y + x/t


print list(euler(0.01, 1, (1,2), f2))
print list(euler(0.01, 1, (1,), f1))
于 2012-04-29T22:12:51.367 に答える
1

オイラー関数では、TypeError をキャッチし、リストにカプセル化して再試行することで回復できます。

于 2012-04-29T21:45:10.217 に答える
1

考えられる解決策の 1 つは、オイラー関数を次のように記述することです。

def euler(h, t, y, f):
    if isinstance(y,collections.Iterable):
        return (y + h*f for y,f in zip(y,f(t,y)))
    else:
        return (y+h*f(t,y),)

別の解決策は、1 次元関数を次のように記述することです。

def f1(t,y):
    return (-2*t*y[0],)

次に、次の方法で euler を呼び出します

list(euler(0.01, 1, (1,), f1))
于 2012-04-29T21:57:55.550 に答える