(非)線形微分方程式の数値解法 その1 | バディ〜のブログ

バディ〜のブログ

 バディ〜のブログ

こんばんは

 

 

 

またまた小難しいテーマになりますが、

興味のあるかたはお読みくださいませ。

 

 

 

解析的に解けないが、数値積分すれば解が求められるという

非線形微分方程式の解法には昔から興味がありました。

 

10年くらい前に、一度、表計算ソフトのエクセルを使って

解いてみようとトライしたことがあります。

計算式をチマチマとセルに入力して、コピペを繰り返して、

なんとか解らしきものはグラフの形になったのですが、

解の質=有効桁数・・・

要するに、

この答えはどれくらいの桁まで正しいのかわからない・・・

一桁?、二桁?、・・・・・?

とりあえず計算の条件を変えて違いを調べるとなにかわかるかも?

ということでやり始めたところ、

エクセルの使用セルの量が爆発的に増えて、

ファイルの容量も数100メガバイトに膨らんでしまい、

開くだけでも10分近くかかるような状態でした。

 

エクセルは、セルの中の計算式はファイルを開いたときに

実行するのですね。

計算式の量が少ないときには開いたとたんに終了するのですが、

(ふつうは問題ない時間です、)

その量が膨大になると開くだけでも時間が掛かってしまいます。

そんなこんなで、中途半端なまま、自主的に終了していました。

まあ、誰に言われたことでもなく、

興味本位で始めたことなので、大勢に影響はないのですが・・・・・

それでもときどきファイルを開いては、

これなんとかしたいなあ・・・と思いつつ、

気が付けば10年ほど月日が経っていました。 (´・ω・`)

 

 

最終的には非線形微分方程式を解くのが目標ですが、

まずは厳密解がわかtっている簡単な線形の方程式を解いて

その性質、

とくに推定残差(厳密解との差)を評価する計算式

(らしきものでもいいので)が見つかれば、

それを使って解析的な厳密解の残差を推定したいなあ

と思っています。 

 

 

 

さて、数値積分の計算結果は一般に次の式になります。

 

 

  計算結果の値 = 真値 + 残差

 

になるので、変形すると、

  残差 = 計算結果の値 ー 真値

両辺を真値で割って。

残差 / 真値= (計算結果の値 ー 真値) / 真値

になります。

 

具体的な数字では、

例えば 

計算結果の値=11、真値=10 とすると

残差 / 真値= (計算結果の値 ー 真値) / 真値

         = (11 ー 10) / 10

         = 0.1

です。

 

ここで、今、計算結果の値だけはわかっていて、

もし、

何らかの方法で 「残差 / 真値」 を知ることができれば

計算結果の値 x 「残差 / 真値」 

を計算すればおおよその残差を推定できます。

 

上の例では

   推定残差 

 = 計算結果の値 x 「残差 / 真値」

 = 11 x 0.1 = 1.1

です。

推定残差にも±の幅があると考えて、

計算結果は 11±1.1 程度の範囲内にあることになります。

かなりザックリ言えば、

二けた目が怪しいから信用できるのは一けただけ 

ということですね。

この 「残差 / 真値」に相当する式を探していきます。

 

実際に数値積分に使うツールは表計算ソフトのエクセルです。

とは言っても、セルに計算式を埋め込む普通の方法では、

あまりにも作業時間やファイルの容量が増えてしまうので、

やってられない・・・

 

これ過去に経験済みということで、

今回はエクセルのマクロ機能を使ってプログラムを組みました。

エクセルのマクロは2000年代くらいから10年ほど使っていましたが、

ここ10年くらいはとんとご無沙汰しています。

それで、復習の意味もあって、改めてプログラミングです。

 

とは言っても(この言葉多いですね。)、

 

セロから始めたわけではなく世の中に出回っている

数値積分のサンプルプログラムをベースに

アレンジしてみました

 

前置きが長くなりましたね。

 

 

 

 

では、ここからが本筋です。

 

 

まず、

サンプルプログラムにも入っている1階の線形微分方程式が

こちらです。

 

  dy/dx=-2xy

 

この微分方程式は変数分離すると簡単に解けてしまいます。

式を変形して

     dy/y=ー2xdx

これを積分して

  ∫(1/y)dy=-∫(2x)dx

 ∴  loge(y)=-x^2 +c1

  (c1は任意の定数)

さらに変形して

   y=c・exp(-x^2)

  (cは任意の定数で、c=exp(c1) )

ですね。

 

このように方程式の厳密解がわかっていますから、

数値積分で解いた結果と比較できますね。

 

積分にはサンプルプログラムに使っている

ルンゲクッタ法で行いました

 

計算するにあたって、決めないといけないのは、

xとyの初期値とxの範囲、それにxの刻み幅hですね。

特に刻み幅hの値は重要です。

hを決めれば、淡々と計算すればそれで終わりですが、

今回はhをあるひとつの値(これをhの初期値とします。)にして

決めたxの範囲の各々のyを計算します。

次にhを半分にして同じように計算し、さらにその半分・・・

というように複数回同じことを繰り返します。

 

つまり、刻み幅hを

h、h/2、h/4、・・・、h/(2のべき乗)  のように繰り返すわけです。

ケースバイケースですが、

今回は、1/(2の10乗)から1/(2の20乗)くらいで

様子をみながら試行錯誤でやってみました。

同じ計算範囲で刻み幅hを小さくするので、

当然計算量は増えます。

hを半分にすれば2倍、・・・・1/1024にすれば1024倍・・・

1/(2の20乗)にすればとてつもなく膨大な量になります。

まあ、私が計算するわけでもなく、

PCの解散が終わるまで

数時間程度待てばいいだけのことですが。

 

マクロ内で定義した繰り返し数の設定を変えるだけで済むように

プログラムを作ったので、

デバッグするときはこれを小さくしたりと

いろいろ工夫したつもりです。

 

同じ処理(計算)が何度でも簡単にできるのも

マクロの強みですね。

ただ、長時間(例えば数時間)マクロを走らせっぱなしだと

windowsから応答なしのメッセージが返ってきて

気持ち悪い状態になります。

マクロ自体は動作しているので問題はないのですが・・・

これを回避するためにマク処理のきりのいいところに

「Doevents」コマンドを入れて、

一旦windousに返すという処理を入れたりしています。

 

 

 

さて、出てきた計算結果の料理方法です。

 

刻み幅hを設定して変数xを変えながらyを計算していきます。

ひとつのhについて計算が終わると

さらにhを半分にして同じことを繰り返します。

 

このとき、

真値をy_ture=f(x)、積分結果をy_cal=g(x,h)とおくと、

積分結果は真値と残差ε(x,h)の和になるので

  y_cal = y_ture + ε(x,h)

  または

  g(x,h) = f(x) + ε(x,h)

と表すことができます。

残差ε(x,h)は未知数で、

真値f(x)も不明ならばこれも未知数になります。

刻み幅hを変えたときの計算結果について考えると

変数xが同じ値ならば

真値は変わらず残差だけが異なることになります。

つまり

x=x1、h=h1及びh=h2(h1≠h2)とおくと

  g(x1,h1) = f(x1) + ε(x1,h1)

及び

  g(x1,h2) = f(x1) + ε(x1,h2)

なので、辺々の差を取れば

 g(x1,h1) - g(x1,h2) = ε(x1,h1) - ε(x1,h2)

となります。

ただ、このままでは「残差 / 真値」の形にならないので、

若干発想を転換して、式を変形します。

  y_cal = y_ture + ε(x,h)

      = y_ture ・  { 1 + ε(x,h) / y_ture }

または

  g(x,h) = f(x) + ε(x,h)

      = f(x)  ・{ 1 + ε(x,h) / f(x) }

と変形しておいて、 先に計算した g(x1,h1) - g(x1,h2) を

y_cal またはg(x,h) で割り算します。

 

すると、一応「残差 / 真値」の形が出てきます。

まず、g(x1,h1) で割ると

 

{g(x1,h1) - g(x1,h2)} / { g(x1,h1) ]

= { ε(x1,h1) - ε(x1,h2) } 

      /    [ f(x1)  ・{ 1 + ε(x1,h1) / f(x1) } ]

= { ε(x1,h1) - ε(x1,h2) }  /  f(x1) 

      /   { 1 + ε(x1,h1) / f(x1) ]

≒ { ε(x1,h1) - ε(x1,h2) }  /  f(x1) 

      ・  { 1 - ε(x1,h1) / f(x1) }

 ただし、 

ε(x1,h1) / f(x1) << 1 が成立するものとします。

 

次に g(x1,h2) で割ると

{g(x1,h1) - g(x1,h2)} / { g(x1,h2) ]

= { ε(x1,h1) - ε(x1,h2) } 

      /    [ f(x1)  ・{ 1 + ε(x1,h2) / f(x1) } ]

= { ε(x1,h1) - ε(x1,h2) }  /  f(x1) 

      /   { 1 + ε(x1,h2) / f(x1) ]

≒ { ε(x1,h1) - ε(x1,h2) }  /  f(x1) 

      ・  { 1 - ε(x1,h2) / f(x1) }

 ただし、 

ε(x1,h2) / f(x1) << 1 が成立するものとします。

 

二つの式を辺々引き算すると

 

左辺 = {g(x1,h1) - g(x1,h2)}

 ・ [ {1 / g(x1,h1) } - {1 / g(x1,h2) } ]

 

 

右辺 = { ε(x1,h1) - ε(x1,h2) }  /  f(x1) 

・  [ 1 - ε(x1,h1)/f(x1)  - 1 + ε(x1,h2)/f(x1) ]

 = -1 ・ { { ε(x1,h1) - ε(x1,h2) }  /  f(x1)  }^2

 =-1・{ (ふたつの刻み幅の残差の差/ 真値)の2乗 }

 

となります。

右辺のマイナスは両辺に-1を掛けて正の値にしておきます。

 

左辺は

刻み幅の異なるふたつの数値積分した計算結果から求められ

これが「残差 / 真値」の形の2乗になることがわかります。

したがって。左辺のルート

(これを評価式と呼ぶことにします)

を計算すれば

「残差 / 真値」の形となります。

これを「推定残差(比率)」と呼ぶことにします。

 

問題は

この「ふたつの刻み幅の残差の差 { ε(x1,h1) - ε(x1,h2) } 」

と現実の残差の関係です。

直観的には何らかの関係がありそうに思えますが

この挙動が見えないので、

実際に計算して、「真値残差」と比較していきます。

 

 

 

 

 

ではまた  

部分方程式 dy/dx=-2xy に話題を戻します。

 

 

 

まず、図1がdy/dx=-2xyの厳密解のグラフです。

初期値はx=0のときy=1としました。

y=exp(-x^2)をxが0から10までプロットしました。

数値積分もこの範囲で行います。

 

普通に見るグラフですね。

 

 

                図 1

 

このままでは縦軸yの範囲が狭くて見ずらいので、

図2のように縦軸を対数表示に変えて

さらに数値積分した結果をふたつ重ねて比較します。

xが4より小さいときは3本のカーブはほぼ重なっていますが、

xがそれより大きくなると次第にずれが大きくなりますね。

 

 

               図 2

 

 

図2の丸印辺りを拡大したものが図3です。

拡大すると文字通り桁違いの差がみえてきます。

 

               図 3

 

 

もっとも、その大きさ自体十分小さくてほぼゼロになりますが・・・

 

 

では、数値積分した結果について。

まず、相対刻み幅と真値残差(比率)の関係が図4です。

ここで、横軸の刻み幅は初回を0.1として

これを1とした相対値で示しています、

右方向で刻み幅が小さくなります。

縦軸は真値残差(比率)を対数表示で表しています。

上方向で残差が大きくなります。

なお、青いカーブは残差の最大値を、

オレンジ色は最小値を示しています。

なお、真値残差(比率)は絶対値としています。

 

 

 

              図 4

 

 

 

直観的には刻み幅が小さくなれば残差も小さくなるはずで、

図4の赤色と緑色の矢印の刻み幅の位置までは

確かにそうなっています。

が、

さらに刻み幅が小さくなるとそれ以後は逆に増加に転じます。

これは数値積分が本質的に積算処理の連続であることに

起因していて、

積算回数は刻み幅に反比例して増加し、

わずかな残差が回数分積算された結果です。

刻み幅は

やみくもに小さくすればいいものではないということです。

まさに「塵も積もれば山となる」ですね。

 

 

次に、

評価式を使った推定残差(比率)と相対刻み幅の関係が図5です。

図4と同じ条件にしています。

二つの図を比べると同じ傾向なのがわかります。

 

 

             図 5

 

図6が刻み幅をパラメータにして

変数xと推定残差(比率)の関係です。

横軸がxで右方向で増加します。

また、縦軸は推定残差(比率)で対数表示しています。

パラメータは刻み幅で下方向で小さくなります。

 

 

             図 6

 

変数xが増加すると推定残差(比率)も増加していて、

数値積分の積算の結果ですね。

 

 

図7は、

図5に重ねて推定残差(比率)の漸近カーブを加えたもので、

緑色と水色の破線がそれぞれ減衰方向の最大値、最小値の

漸近カーブになります。

水色の矢印方向の傾きは刻み幅の4乗です。

また紫色とオレンジ色の破線は増加方向の漸近カーブで

色の矢印方向の傾きは刻み幅の-1乗になっています。

推定残差(比率)の最大値、最小値の極小点は

それぞれ赤色と緑色の矢印で示しています。

 

 

 

            図 7

 

 

 

では、図4と図5を重ねてみましょう。

図8になります。

対数表示ですが、ほぼ一致しているといえますね。

 

 

 

            図 8

 

 

 

次に、

変数xに対する二つの残差(比率)の違いを調べてみました。

刻み幅は図8の赤色の矢印に対応した値としました。

図9では

真値残差(比率)は絶対値ではないので、±の極性があります。

 

              図 9

 

 

xの増加とともに単調増加とおもいきや、

どちらも増加したり減少したりやや複雑な動きをしています。

 

 

次に、

図9の絶対値をとって、

最大値と最小値にマークしたものが図10です。

赤い丸印が最大値、緑色の丸印が最小値で、

オレンジ色の直線が推定残差(比率)の最大ラインです。

このラインより下なら問題無しです。

 

 

 

                図 10

 

 

 

図11では、

横軸に真値残差(比率)、縦軸には推定残差(比率)として

相関図としてみました。

赤と緑の丸印は図10と同じでオレンジ色も同じ意味です。

 

 

 

               図 11

 

 

 

というわけで

今回の例の結論は、

図8のように真値残差(比率)と評価式の相対残差(比率)が

ほぼ一致したというこどですね。

 

次は、

やはり厳密解がわかっている別の微分方程式について

調べてみます、

 

 

最後までお読みくださったかた、

大変お疲れ様でした。

& ありがとうございました。。