2016-12-11 2 views
0

私はPythonでAdams-Bashforthメソッド(https://en.wikipedia.org/wiki/Linear_multistep_method#Two-step_Adams.E2.80.93Bashforth)を書こうとしています。実際、私のコードはオイラー法より遅く、最悪の結果を出しました。コードをアップグレードする手助けはできますか?PythonのAdams-Bashforthメソッド

s1 = [1] 
s2 = [-0.5, 1.5] 
s3 = [5./12, -4./3, 23./12] 
s4 = [-3./8, 37/24, -59./24, 55./24] 
s5 = [251./720, -637./360, 109./30, -1387./360, 1901./720] 


def adams_bashforth(f, ta, tb, xa, n, sn=s5): 
    last_n = [] 
    h = (tb - ta)/float(n) 
    t = ta 
    x = xa 
    # first n steps made by Euler method 
    for i in range(len(sn)): 
     last_n.append(h * f(t, x)) 
     x += last_n[-1] 
     t += h 
    # Adams-Bashforth method 
    for i in range(n): 
     x += h * sum([last_n[i] * sn[i] for i in range(len(sn))]) 
     last_n = last_n[1:] 
     last_n.append(f(t, x)) 
     t += h 
    return x 

def f(t, x): 
    return t * sqrt(x) 

print adams_bashforth(f, 0, 1, 10, 1000, s5) 

答えて

0

免責事項:私はAdams-Bashforthに精通していません。あなたが提供したPythonコードをリファクタリングしています。アルゴリズム自体を変更することで、より良い結果が得られる可能性があります。

リストコピー(last_n = last_n[1:])を削除し、プログラムから追加することで、かなりのスピードアップ(私のマシンでは30-40%、n=1M)を得ることができます。以下は同じで、循環方式でちょうどSN=len(sn))要素のリストを使用しています。

def adams_bashforth(f, ta, tb, xa, n, sn=s5): 
    h = (tb - ta)/float(n) 
    t = ta 
    x = xa 
    SN = len(sn) 
    # first n steps made by Euler method 
    last_n = [] 
    for i in range(SN): 
     y = h * f(t, x) 
     last_n.append(y) 
     x += y 
     t += h 
    # Adams-Bashforth method 
    j = 0 
    for i in range(n): 
     ss = 0 
     for s in sn: 
      ss += last_n[j] * s 
      j += 1 
      if j >= SN: j = 0 
     x += h * ss   
     last_n[j] = f(t, x) 
     t += h 
     j += 1 
     if j >= SN: j = 0 
    return x 
+0

ありがとう!私のバージョンよりはるかに高速です。残念ながら、私はまだ私の結果で大きなエラーに問題があります。 – Poia