Pythonでロジスティック写像 カオスをプログラム

f:id:wataru_boss:20180619205116p:plain
こんにちは。BOSSです。

非線形動力学という授業が大学院でありました。

そのなかで出てきたカオスという現象。

一番単純なのがロジスティック写像というものがカオス現象を表すことがよく知られています。

今回は面白そうだったのでそれを再現するようなプログラムを書いてみようと思います。

カオスってなに?

課題の意図はカオス現象を確認して見てねってことです。

ではカオスとはなにか?

すごーく砕いてカオスを説明するとしたら

ランダムじゃないんだけど、未来がどうなるか予想がつかないものをカオスと言います。

かたーくいうなら

非線形な決定論的力学系から発生する、初期値鋭敏性を持つ、有界な非周期軌道 カオス理論 - Wikipedia

初期値鋭敏性ってのは小さい値の誤差でも大きな影響というかブレが生じるって意味です。

バタフライ効果とかが有名ですよね。

そのカオスという現象が現れる、ロジスティック写像というものがあります。

\( x_{n}=ax_{n}(1-x_{n}) \)
という写像、つまり漸化式で与えられるものです。

これは、\(a\)が1までは\( x_{n} \)は0に収束し、\(a\)が3まではある一定の値に収束します。 \(a\)が3より大きいところでは収束する値が2つ、4つ、8つ、、、と次々に分岐していきカオスとなります。

難しいですね。 これがわかる図を描くというプログラムを書くことが本記事の趣旨になります。

例題

a\in[0,4]の範囲でロジスティック写像 \( x_{n}=ax_{n}(1-x_{n}) \) の分岐を描け。ただし、分岐図を各手順は以下とする。

  1. a=0を初めのパラメータ値として選ぶ

  2. 初期値 \( x_{1} \)を\( [0,1]\)の中からランダムに選ぶ

  3. 写像 \( x_{n}=ax_{n}(1-x_{n}) \) の下で、\( x_{n} \)の軌道を反復計算する。

  4. 初めの100会の反復を無視し、101回目の反復から軌道をプロットする(横軸:a, 横軸:x_{n})

  5. aを決められた増分だけ増やして、aが4を越えれば終了し、そうでなければ2.に戻る。

プログラム

方針

課題の内容が非常にわかりやすいですのでその通りに実装していこうかと思います。

まずはロジスティック写像の計算をしていく部分を作ります。

これは関数としましょう。

漸化式ですのでx_{n}を格納するリストを作り、ランダムに初期値x_{0}の値を決めます。 この時引数にaをとるような関数としておきました。

def logistic_map(a):
    # xの値をx1からxnまでリストで格納
    x = []
    # 初期値x1をランダムに0から1の範囲で選ぶ(float型)
    x1 = random.random()
    x.append(x1)

このリストに先ほどの漸化式をといたものを次々に追加していけば各aに対する\( x_{n} \)リストが出来上がります。

この時値が収束するまでの100個のデータは捨てるようにします。

    # n = 1000までxを格納
    for n in range(1000):
        x.append(a * x[-1] * (1 - x[-1]))

    return x[101:]  # 最初の100回は捨てて値を返す

なんでこの場合は各\( x_{n} \)リストは900個の要素を持つことになり、値が収束している範囲の場合は同じ値が900個並んだリストということです。

対してカオスとなる範囲の場合はこの900個の値がそれぞれ変わるはずです。

このデータ点をプロットすれば良いということになりますね。

最後はこの関数に渡す引数aですが、aを0から4を任意の増分で増加させていき関数に受け渡していきます。

これを今回はnumpyの関数であるnp.linspace()を用いて実現させました。

linspace()は等差数列を作成する関数で、ある範囲を任意の分割数に分ける時に便利です。

コーディング

さて上記の方針に則りコードをかきました。

ちなみに図を描くのはmatplotlibを用いています。

import numpy as np
import random
import matplotlib.pyplot as plt


# 引数にaをとる
def logistic_map(a):
    # xの値をx1からxnまでリストで格納
    x = []
    # 初期値x1をランダムに0から1の範囲で選ぶ(float型)
    x1 = random.random()
    x.append(x1)

    # n = 1000までxを格納
    for n in range(1000):
        x.append(a * x[-1] * (1 - x[-1]))

    return x[101:]  # 最初の100回は捨てて値を返す


# 0から4まで100分割した等差数列を作成。同一刻み幅でaの値を変えている。
for a in np.linspace(0, 4, 100):
    x = logistic_map(a)
    # データのサイズを合わせる。[a]*len(x)で、全く同じ数値が格納されたxとサイズが同じリストを作成
    plt.plot([a] * len(x), x, 'ro', markersize=1.0)

plt.xlabel("a")
plt.ylabel("$\it{x_{n}}$")
plt.show()

この結果がこちら。 f:id:wataru_boss:20180614004647p:plain

先ほど言った通り、最初は0に収束→途中からある値に収束→aが4を超えてからぐちゃぐちゃのカオスです。

まとめ

このようにしてPythonを用いてロジスティック写像の分岐図を描くことができました。

なんとなくカオスというものがどういう挙動を示すのか
目に見えるようなプログラムがかけたのではと思います。