ロジスティック写像を理解する

# はじめに
シンプルな式でありながら
解が複雑な振る舞いをするロジスティック写像について説明します。

# ロジスティック写像
次の漸化式で与えられる写像をロジスティック写像といいます。
rはパラメータです。

```math
x_{n+1} = r x_n (1 - x_n)
```

$x_n / x_{n+1}$のグラフは次の通りです。r=4で値域が[0,1]になります。

```py3
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 1, 100);
plt.figure(0)
plt.gca().set_aspect('equal', adjustable='box')
plt.title('logistic map')
plt.grid(True)
plt.xlabel('$x_n$', fontsize=20)
plt.ylabel('$x_{n+1}$', fontsize=20)
plt.plot(x, 4*x*(1-x), "r-x")
plt.plot(x, x*(1-x), "g-x")
plt.legend(["r=4", "r=1"])
plt.show()
```

![figure_0.png](https://qiita-image-store.s3.amazonaws.com/0/84205/169854d7-a525-45e6-fc67-c05ae6f5d235.png)

# Processing
Processingを使って漸化式で得られる数列の挙動を確認しましょう。

初期値$x_0=0.5$を固定にしてrを0~4の範囲で変化させてみます。
nは100です。プログラムは以下の通りです。

```java:
float r = 0;
float dr = 0.002;
int n = 100;
float x0 = 0.5;
float p;

void setup() {
  size(800, 600);
  frameRate(30);  
  fill(255, 255, 255, 255);
  noStroke();
  background(0, 0, 0);
  p = width / (float)n;
}

void draw() {
  fill(0, 20);
  rect(0, 0, width, height);
  fill(255);
  float x = x0;
  for (int i=0; i<n; i++) {
    float xn1; /* xn+1 */
    xn1 = r * x * (1 - x);
    ellipse(i*p /* x */, xn1*height /* y */, 4 /* width */, 4 /* height */);
    x = xn1;
  }
  if (r<3) {
    r += dr*4;
  } else if (3<r && r<3.5) {
    r += dr/2;
  } else if (3.5<r && r<3.8) {
    r += dr/4;
  } else if (3.8<r && r<3.95) {
    r += dr/8;
  } else {
    r += dr/32;
  }
  if (4 <= r) {
    r = 0;
  }
  textAlign(CENTER);
  textSize(32);
  text(String.format("r=%.2f", r), width/2, height/2);
  //saveFrame("line-######.png");
}
```

座標系は左上が$(x, y) = (0,0)$です。x軸の方向は左から右でy軸の方向は上から下です。
左から右に向かって$x_0$から$x_{99}$を一定間隔でx座標を取ります。
y座標は$x_{n+1}$をプロットします。画面の縦幅が1になるようにします。
図で説明します。

![figure.png](https://qiita-image-store.s3.amazonaws.com/0/84205/cec2c240-0903-04ce-8b34-e6a9750fd9ad.png)

Processingの結果を動画にしました。
rの値によって数列の振る舞いが大きく変化することが分かります。
rが4に近づくにつれて複雑な振る舞いに変化します。

[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/ZZHWnURQ32c/0.jpg)](http://www.youtube.com/watch?v=ZZHWnURQ32c)

# 初期値鋭敏性
初期値を僅かに変化させたときの数列の振る舞いを見てみましょう。
x0_0 = 0.0000001;
x0_1 = 0.0000002;
とします。僅かに差は0.0000001です。
rを変化させます。n=30とします。
x0_0は緑の丸で、x0_1は白丸で表します。
プログラムは以下の通りです。


```java
float r = 0;
float dr = 0.002;
int n = 30;
float x0_0 = 0.0000001;
float x0_1 = 0.0000002;
float p;

void setup() {
  size(800, 600);
  frameRate(30);  
  fill(255);
  noStroke();
  background(0);
  p = width / (float)n;
}

void draw() {
  fill(0);
  rect(0, 0, width, height);
  fill(255);
  float x;
  x = x0_0;
  for (int i=0; i<n; i++) {
    float xn1; /* xn+1 */
    xn1 = r * x * (1 - x);
    ellipse(i*p /* x */, xn1*height /* y */, 10 /* width */, 10 /* height */);
    x = xn1;
  }
  x = x0_1;
  fill(0, 255, 0);
  for (int i=0; i<n; i++) {
    float xn1; /* xn+1 */
    xn1 = r * x * (1 - x);
    ellipse(i*p /* x */, xn1*height /* y */, 10 /* width */, 10 /* height */);
    x = xn1;
  }
  
  if (r<3) {
    r += dr*4;
  } else if (3<r && r<3.5) {
    r += dr/2;
  } else if (3.5<r && r<3.8) {
    r += dr/4;
  } else if (3.8<r && r<3.95) {
    r += dr/8;
  } else {
    r += dr/32;
  }
  if (4 <= r) {
    r = 0;
  }
  
  fill(255);
  textAlign(CENTER);
  textSize(32);
  text(String.format("r=%.2f", r), width/2, height/2);
  //saveFrame("line-######.png");
}
```

Processingの結果を動画にしました。

[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/ICc66Bm7yFY/0.jpg)](http://www.youtube.com/watch?v=ICc66Bm7yFY)

初期値の違いが僅かであるにもかかわらず
nが増えるにつれて差が増大していることが分かります。
このような特徴を初期値鋭敏性といいます。

# パイこね変換
r=4のロジスティック写像の解は以下の特徴をもっています。

- 初期値鋭敏性
- ランダムに見える複雑な振る舞い

なぜこのような振る舞いになるのでしょうか。
理由は次の処理を行っているからです。

1. 引き伸ばし
2. 折りたたんで混ぜ合わせる
3. 有界な領域に閉じ込めている

上記を持つ変換をパイこね変換といいます。

引き伸ばしの効果により、初期値鋭敏性が現れます。
折りたたみと混ぜ合わせ、有界な領域への閉じ込めにより、複雑な振る舞いになります。