グモウスキー・ミラの写像(Gumowski-Mira attractor)をrust nannouで描いてみました。
カオスなふるまいをする話題のものです。詳しくは、いろいろ検索してみてください。
さてどんなものかって言うと
こんな式
\begin{eqnarray}
\begin{cases}
x_{n+1} = y_n +ay_n(1-by_n^2)+f(x_n)\\
y_{n+1} = -x_n+f(x_{n+1})
\end{cases}
\end{eqnarray}
$$f(x)=mx+\frac{2(1-m)x^2}{1+x^2}$$
で計算される集合を描画したもの
グモウスキー・ミラの写像を計算していく
先ほど紹介したもの以外にも式がありまして、それの組み合わせや定数項(a,b,m)によって様々な模様を描くことができます。
数値を変えるだけで、形が変化するので、かなり無限にあるよね(笑)
今回は最初に紹介した数式を使っていくつか描いていこうかともいます。
rust nannouでグモウスキー・ミラの写像を求める
漸化式が2本と関数が1本で構成されてます。漸化式なので、何度も再帰して呼び出すので、関数化しちゃいましょう。
それぞれのパラメーターの関数を作る
高い精度?を求めるならf64で定義したほうがいいんでしょうが、nannouの座標はf32を使ってるので、f32で計算してきます。
まずは\(f(x)=mx+\frac{2(1-m)x^2}{1+x^2}\)から
fn f(m: f32, x: f32) -> f32 {
m * x + (2.0 * (1.0 - m) * x * x) / (1.0 + x * x)
}
素直に式そのままで
次に\(x_{n+1} = y_n +ay_n(1-by_n^2)+f(x_n)\)
fn x(x: f32, y: f32, a: f32, b: f32, m: f32) -> f32 {
y + a * y * (1.0 - b * y * y) + f(m, x)
}
最後に\(y_{n+1} = -x_n+f(x_{n+1})\)
fn y(x: f32, xn: f32, m: f32) -> f32 {
-x + f(m, xn)
}
関数を計算して座標を求める
それぞれの式を計算する関数ができたので、これらを使って座標を計算していきましょう。
式は、それぞれ漸化式になっているので、再帰的に計算するようにします。
update関数の中で、ステップごとに計算していくか、もしくはforなどを使い決めた回数一気に計算するか主に2つの方法があります。
update関数を使う方法
update関数を使ってステップごとに計算する方法を解説します。
update関数を使う場合、Modelに座標px、pyを定義してそれを更新していくことを考えます。
ソースを書いていきましょう。
//モデルの定義
struct Model {
px: f32,
py: f32,
}
//Model初期化
fn model(app: &App) -> Model {
...
...
Model { px: 0.1, py: 0.1 }
}
//Modelの更新
fn update(_app: &App, model: &mut Model, _update: Update) {
let a = 0.001;
let b = 0.4986;
let m = -0.95;
let xn = x(model.px, model.py, a, b, m);
let yn = y(model.px, xn, m);
model.px = xn;
model.py = yn;
}
//描画
fn view(app: &App, model: &Model, frame: Frame)
let scale = 15.0;
draw.ellipse()
.x_y(model.px * scale, model.py * scale)
.radius(1.5)
.color(WHITE);
}
a,b,mは定数項
xn,ynは計算された次のそれぞれの値。
最後にそれをpx、pyに代入して値を更新
forを使う方法
forを使って計算していく方法は、Modelのupdateのやり方とほぼ一緒
ただ、Modelを定義せずにそれを行います。
ソースを書くとこんな感じ
fn view(app: &App, model: &Model, frame: Frame) {
let scale = 15.0;
let a = 0.001;
let b = 0.4986;
let m = -0.95;
let mut px = 0.1;
let mut py = 0.1;
for _i in 0..20000 {
let xn = x(px, py, a, b, m);
let yn = y(px, xn, m);
px = xn;
py = yn;
draw.ellipse()
.x_y(px * scale, py * scale)
.radius(1.0)
.color(WHITE);
}
}
やってることは全く一緒です
こんな感じで、グモウスキー・ミラの写像を描くことができました
まとめ
今回はrust nannouでグモウスキー・ミラの写像を描いてみました。
パラメーターを変えるだけで本当いろんな形になって
とまぁ色々できます。
あとはこれに色を付けたり他の関数や描画方法を変えたりと表現の可能性はたくさんありそうですね。
ではまた!
コメント