質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

2007閲覧

scipy、sympyを使わずに積分近似をして誤差を計算したい

agg1234

総合スコア6

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2020/06/17 15:12

編集2020/06/17 15:17

現在sympyやscipyを使わずに台形法則、シンプソン法、ガウス=ルジャンドル法を使って積分の近似をし、ステップ数を増やすと誤差がどうなっていくのかをプロットしたいと思っています。
自分の作った関数では、単純な積分近似はできるのですが、誤差を計算する段階になるとSympifyErrorが出てしまいます。
どこがどのようにまずいのかもわからず困っています。
まだプログラミングを始めて日が浅いので優しく御教授いただけると助かります。

ガウス=ルジャンドルについてはわからないようなら先生の方からWikipediaのテーブルを移して良いとの回答を頂いたのでこのようになっていますので、あまり気にしなくても大丈夫なのですが、その他は質問しても教えられないとだけ言われてしまい、お手上げ状態です。

エラーメッセージ: SympifyError: Sympify of expression 'could not parse '<function <lambda> at 0x7fec74eba3b0>'' failed, because of exception being raised: SyntaxError: invalid syntax (<string>, line 1)

該当のソースコード

ソースコード def integral(f, a, b, N, method='trapezoid'): if method == 'trapezoid': s = (b - a) / N t = 0.5 * (f(a) + f(b)) for i in range(1, N): t = t + f(a + i * s) return s * t elif method == 'simpson': if N % 2 == 1: return ValueError("N must be an even integer.") h = (b - a)/ N x0 = f(a) + f(b) x1 = 0 x2 = 0 for i in np.arange(1, N): x = a + i * h if i % 2 == 0: x2 += f(x) else: x1 += f(x) X = h * (x0 + 2 * x2 + 4 * x1) / 3 return X elif method == 'gauss': s1 = (b - a) / 2 s2 = (b + a) / 2 if N == 1: x = [0] w = [2] elif N == 2: x = [-1/np.sqrt(3), 1/np.sqrt(3)] w = [1, 1] elif N == 3: x = [-np.sqrt(3/5), 0, np.sqrt(3/5)] w = [5/9, 8/9, 5/9] elif N == 4: x = [-np.sqrt(3/7+2/7*np.sqrt(6/5)), -np.sqrt(3/7-2/7*np.sqrt(6/5)), np.sqrt(3/7-2/7*np.sqrt(6/5)), np.sqrt(3/7+2/7*np.sqrt(6/5))] w = [(18-np.sqrt(30))/36, (18+np.sqrt(30))/36, (18+np.sqrt(30))/36, (18-np.sqrt(30))/36] elif N == 5: x = [-1/3*np.sqrt(5+2*np.sqrt(10/7)), -1/3*np.sqrt(5-2*np.sqrt(10/7)), 0, 1/3*np.sqrt(5-2*np.sqrt(10/7)), 1/3*np.sqrt(5+2*np.sqrt(10/7))] w = [(322-13*np.sqrt(70))/900, (322+13*np.sqrt(70))/900, 128/225, (322+13*np.sqrt(70))/900, (322-13*np.sqrt(70))/900] else: ValueError('N must be less than 6.') p = 0 for i in np.arange(N): p += w[i] * f(s1 * x[i] + s2) return s1 * p else: return ValueError('Not a valid method.') N = [2 ** (t) for t in np.arange(1, 7)] trap = np.zeros(len(N)) simp = np.zeros(len(N)) true_ = np.zeros(len(N)) f = lambda x: np.exp(-x) for index, i in enumerate(N): trap[index] = integrate(f, 0, 1, i, 'trapezoid') simp[index] = integrate(f, 0, 1, i, 'simpson') true_[index] = 1 / i * (sum(f(-(np.linspace(0, 1, i))))) et = abs((trap - true_) / true_) * 100 es = abs((simp - true_) / true_) * 100

試したこと

関数は台形とシンプソンはできているとは思うのですが、誤差を計算してプロットを描くためにループ処理しようとするとエラーになってしまいます。

補足情報(FW/ツールのバージョンなど)

Python 3.7

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

python

1trap[index] = integrate(f, 0, 1, i, 'trapezoid') 2simp[index] = integrate(f, 0, 1, i, 'simpson')

にあるintegrateintegralの間違いです。最初にそこを直しましょう。

プログラムを始めて日が浅いとのことですのでアドバイスします。

エラーメッセージを良く読む

エラーメッセージは情報の宝庫です。例えば今回のケースだと

  • SympifyErrorから、SymPyパッケージに関するエラーである
  • function <lambda>から、ラムダ式を用いている箇所に関係している
  • 'could not parse...'から、ラムダ式をSymPyに与えてエラーとなっている

ということがわかります。今、ラムダ式を使っているのは

python

1f = lambda x: np.exp(-x)

の部分です。このラムダ式fを渡しているのは

python

1trap[index] = integrate(f, 0, 1, i, 'trapezoid') 2simp[index] = integrate(f, 0, 1, i, 'simpson') 3true_[index] = 1 / i * (sum(f(-(np.linspace(0, 1, i)))))

しかありませんので、エラーはこの部分であろうと予想がつきます。じっくり眺めると、上で定義している関数はintegralにも関わらず、ここではintegrateが使われています。もしかしてこのintegrateはSymPyの関数ではないだろうかとインターネットで検索するとSymPy 1.6 Integralsに辿り着き、やはり間違いだったことが分かります。

ソースコードには動作に必要な記述のみ書く

今回問題となったのはSymPyを使う予定が無いにも関わらずSymPyの関数integrateが使えてしまったことです。おそらく上の方に

python

1from sympy import *

のような記述があるのではないでしょうか。SymPyを使わないのであれば思い切って削除しましょう。この部分を削除して入ればintegrateとミスをすることはなかったです。

関数は内容を理解して使用する

このソースコードを見て気になったのは、0~1の区間を分割する際に使っている二つの関数np.linspacenp.arangeです。np.arange()は整数を返すので、例えばN=4の場合は0.25を乗算して

python

1>>> np.arange(0, 4) 2array([0, 1, 2, 3]) 3>>> np.arange(0, 4)*0.25 4array([0. , 0.25, 0.5 , 0.75])

という刻み方をします。np.linspace()の場合は

python

1>>> np.linspace(0, 1, 4) 2array([0. , 0.33333333, 0.66666667, 1. ])

となります。同じ結果を得たいのであれば

python

1>>> np.linspace(0, 0.75, 4) 2array([0. , 0.25, 0.5 , 0.75])

とする必要があります。似た関数であってもその振る舞いは同じとは限らないため、必ず仕様を理解してから使いましょう。

投稿2020/06/17 17:49

yymmt

総合スコア1615

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

agg1234

2020/06/17 21:57

初歩的なミスで大変お恥ずかしい。。 なのにとても丁寧に回答してくださって本当にありがとうございます! おかげさまで上手く行きました! np.linspaceとnp.arangeの使い分けについても教えてくださってありがとうございます! 自分自身でだんだん訳が分からなくなってしまっていたのですが、yymmtさんのおかげで整理できました。 本当にありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問