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

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

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

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

Q&A

解決済

3回答

742閲覧

pythonで関数の逐次更新をしたい

_hh

総合スコア79

Python 3.x

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

1グッド

1クリップ

投稿2022/08/25 11:13

前提

Windows10でjupyter notebookでpythonのコードを書いております。
少し前にも類似の質問をさせて頂いたのですが、やはり目的のことができずにおりご相談させて頂きます。

実現したいこと

ある変分問題を解く上で、例えば以下のような「関数の逐次更新」をしたいと考えています。

u_{n+1}(t) = u_n(t)*(1-\int_0^1 |u_n(s)|^2 ds) (n=0,1,2,...N, 0≦t≦1)

簡単のため、ここでは3回目ほどで終了して、u_3(t)の関数が得たいと考えております。

発生している問題・エラーメッセージ

関数の一般表現は得られないことを前提として、上の漸化式の形のまま実装したいのですが、、以下の様になってしまいます。

RecursionError Traceback (most recent call last) <ipython-input-6-474c6340d013> in <module> ----> 1 u(0.1) <ipython-input-4-eab238bb6b57> in u(t) 7 j=j+1 8 def u(t): ----> 9 ans = u(t) * (1- (integrate.quad(u, 0, 1))**2 ) 10 return ans ... last 1 frames repeated, from the frame below ... <ipython-input-4-eab238bb6b57> in u(t) 7 j=j+1 8 def u(t): ----> 9 ans = u(t) * (1- (integrate.quad(u, 0, 1))**2 ) 10 return ans RecursionError: maximum recursion depth exceeded

該当のソースコード

python

1#初期値 2def u(t): 3 ans = 2*t 4 return ans 5 6j=0 7while j<3: 8 j=j+1 9 def u(t): 10 ans = u(t) * (1- (integrate.quad(u, 0, 1))**2 ) 11 return ans 12 13u(0.1)

試したこと

上記以外に、どのようにして書いてよいのか分からずにおります。。ご教示のほど、宜しくお願い致します。

TakaiY👍を押しています

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

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

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

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

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

_hh

2022/08/25 23:42

有難うございます。上記は、一般項が表現できる場合でしたが、漸化式が前提の場合には適用できないことが分かり、再度こちらで質問をさせて頂いてしまいました。。以下の通り何とか自己解決しましたので、そちらを記載して本件クローズさせて頂きます。
guest

回答3

0

プログラミング FAQ ループの中で異なる値で定義されたラムダ式が、同じ値を返すのはなぜですか?

これは、x がラムダにとってのローカル変数ではなく外側のスコープで定義されていて、ラムダが定義されたときでなく呼び出されたときにアクセスされるために起こります。
(略)
これを避けるためには、グローバルの x の値に依存しないために、ラムダにとってのローカル変数に値を保存する必要があります

>>> squares = [] >>> for x in range(5): ... squares.append(lambda n=x: n**2)

ここで、n=x は新しいラムダにとってのローカル変数 n を作成し、ラムダが定義されるときに計算されるので、ループのその時点での x と同じ値を持っています。

プログラミング FAQ なぜオブジェクト間でデフォルト値が共有されるのですか?

関数の呼び出しによって、デフォルトの値に対する新しいオブジェクトが作られるのだと予想しがちです。実はそうなりません。デフォルト値は、関数が定義されたときに一度だけ生成されます。

(個人的には、「一度だけ生成されます」じゃなくて「一度だけ評価されます」と書いてあって欲しいと思いますが、一応原文ママで引用しました)


これらを使って、

python

1from scipy import integrate 2 3 4#初期値 5def u(t): 6 ans = 2*t 7 return ans 8 9j=0 10j=j+1 11def u(t, previous=u): 12 ans = previous(t) * (1 - integrate.quad(lambda x: abs(previous(x))**2, 0, 1)[0]) 13 return ans 14 15print(u(0.1))

とすると、無限の再帰を避けつつ漸化式に近い関数定義ができると思います。

キーワード引数とデフォルト値 previous=u によって

  1. 新しいuは1引数の関数っぽく呼び出せる
  2. 古いuへの参照はdef文実行時だけ評価されてローカル変数previousに束縛される
  3. 新しいuの中ではローカル変数previousを使って1つ前のuにアクセスする

を実現しています。


提示された式は

式

なので、新しいuはこんな形なのでは? と思った実装に変えています。勘違いだったらすみません。


そして、式の後ろ (1 - \int (略) ds) の部分は"新しい関数"の変数tを含んでいないので、要は定数項です。
"新しい関数"の呼び出し時に計算する理由はありません。

from scipy import integrate #初期値 def u(t): ans = 2*t return ans j=0 j=j+1 def u(t, previous=u, constant=(1 - integrate.quad(lambda x: abs(u(x))**2, 0, 1)[0])): ans = previous(t) * constant return ans print(u(0.1))

でもいいと思います。

投稿2022/08/26 18:19

編集2022/08/26 19:17
quickquip

総合スコア11038

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

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

_hh

2022/09/01 05:04

気づくのが遅くなってしまい済みません。クローズ後にも関わらずご教示下さり有難うございました。 お蔭様で思っていたことができました。有難うございます。
guest

0

自己解決のような方法であれば、以下の方法がよいのではないかと思います。この質問見たときに思いついた方法ですが、もっとスマートな方法があるんじゃないかと思って出さずにいたものです。

★ 下によりよい処理を追記しています。

この方法も、すべて事前に定義しておかなければならないのでいまひとつだと思っています。
高階関数を使ってうまく再帰定義できる方法があるといいんですが。
だれかわかるひといませんかー。

★ 以下のコードはこちらで検証できるように、簡略化した式を使っています。

関数定義を使う方法

python

1u = [] 2 3def u0(t): 4 ans = t 5 return ans 6 7u.append(u0) # u[0] = u0 8 9fun_max_count = 4 10 11for i in range(1, fun_max_count): 12 def tmpfn(t, j=i): 13 ans = u[j - 1](t) + 1 14 return ans 15 u.append(tmpfn)

これで、u[2](5) -> 7 となります。

lambda式を使うと少しすっきりします。

python

1u = [] 2 3def u0(t): 4 ans = t 5 return ans 6 7u.append(u0) # u[0] = u0 8 9fun_max = 3 10 11for i in range(1, fun_max): 12 u.append(lambda t, j=i: u[j - 1](t) + 1)

いずれの場合も、定義のところでiをjに置き換えているところがポイントです。iのまま使うと、定義の中のiがすべてループの最終値になってしまいます。


漸化式で関数生成できないかと思って考えてみました。たぶん できています。

python

1from functools import lru_cache 2 3@lru_cache(maxsize=1000) 4def gen_u(n): 5 if n == 0: 6 return lambda t: 2 * t 7 else: 8 return lambda t: gen_u(n - 1)(t) * (1- (integrate.quad(gen_u(n - 1), 0, 1)[0])**2 ) 9 10# 引数に数値を与えると、質問の関数相当のものを生成して返します 11u3 = gen_u(3)

lru_cacheはなんとなく付けたおまけです。
この関数はテストできませんでしたが、以下の簡略したもので確認しています。

python

1from functools import lru_cache 2 3@lru_cache(maxsize=1000) 4def gen_u(n): 5 if n == 0: 6 return lambda t: 2 * t 7 else: 8 return lambda t: gen_u(n - 1)(t) + 1 9 10u3 = gen_u(3) 11 12print(u3(5)) 13 14print(gen_u(7)(5))

ついでですが、もともとの要望であった「今ある関数を更新する」ということであれば、 こんな感じでしょうか。
これも高階関数です。

python

1def u(t): 2 ans = t 3 return ans 4 5for i in range(10): 6 print(u(5)) 7 u = lambda t, c_f=u: c_f(t) + 1 8 print(u(5))

ここでも、lambdaの引数に現行の関数(c_f)として渡しているところがポイントです。
これをやらないと、成立しません。

投稿2022/08/26 01:58

編集2022/08/26 10:21
TakaiY

総合スコア12743

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

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

TakaiY

2022/08/26 10:05

よさそうな方法みつけたので追記します。
_hh

2022/09/01 05:07

気づくのが遅くなってしまい済みません。クローズ後にも関わらずご教示下さり有難うございました。 from scipy import integrate from functools import lru_cache @lru_cache(maxsize=1000) def gen_u(n): if n == 0: return lambda t: 2 * t else: return lambda t: gen_u(n - 1)(t) * (1- (integrate.quad(gen_u(n - 1), 0, 1)[0])**2 ) # 引数に数値を与えると、質問の関数相当のものを生成して返します u3 = gen_u(1) print(u3(1)) としますと、0.0となり、手計算の結果(-1/3)とは異なってしまいました。私にはちょっと理由は分かりませんが、ともかく御礼申し上げます。有難うございます。
guest

0

自己解決

以下のように、添え字を陽に書いて、別の関数として一つ一つ定義することで
解決致しました。必要な回数だけ、手書きで書いていきたいと思います。
考えて下さった皆様大変有難うございました。

python3.7

1#初期値 2def u(t): 3 ans = 2*t 4 return ans 5 6j=0 7def u1(t): 8 ans = u(t) * (1- (integrate.quad(u, 0, 1)[0])**2 ) 9 return ans 10 11def u2(t): 12 ans = u1(t) * (1- (integrate.quad(u1, 0, 1)[0])**2 ) 13 return ans 14 15def u3(t): 16 ans = u2(t) * (1- (integrate.quad(u2, 0, 1)[0])**2 ) 17 return ans 18 19u3(0.1)

投稿2022/08/25 23:43

_hh

総合スコア79

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問