自己平方フラクタル
それぞれの違いを簡単なスクリプトを書いて確かめましょう。
(1) グリッドにスナップするツール(磁石アイコン)を選んで、座標軸と方眼を表示しておきます。
(2) 点を2つとります。A,Bとなるでしょう。
(3) インスペクタを開いて、Aのラベルをz0 , Bのラベルをc とします。
(4) スクリプトメニューからCindyScriptを開き、左側のDrawスロットをクリックします。
右側のスクリプトウィンドウをクリックして、次のスクリプトを書いて実行します。
z0=complex(A);
c=complex(B);
f(z):=z^2+c;
z=z0;
repeat(3,k,
z=f(z);
draw(gauss(z));
drawtext(gauss(z)+[0.1,0],"z"+k);
);
スクリプトの説明をしましょう。
1行目と2行目で、点A,Bの座標を複素数に変換してz0とcに代入します。点A,Bは画面上ではz0,cと表示されていますが、これはインスペクタでラベルをつけたためで、元の識別名はA,Bで変わりません。
3行目は関数の定義です。
4行目から、f(z)によって点を作っていきます。
repeat(3,k, で3回繰り返します。
draw(gauss(z)); で、複素数zを複素数平面上に表示します。実際は gauss(z) によって、直交座標系の座標にしています。
drawtext(gauss(z)+[0.1,0],"z"+k); で表示した点のすぐ横に、zに続いて番号kを書きます。
点A(z0)とB(c)をドラッグして動かしてみましょう。両方が原点近くにないとz2 , z3は画面からはみ出してしまうでしょう。
さらにこまかく位置を動かせるように、「矩形領域を画面サイズに拡大」ツールを使って拡大しましょう。
さて、(A) マンデルブロ集合では初期値を0にします。点A(z0) を原点に移動します。そこで点Cをドラッグして動かしてみましょう。
さらに点を増やしてその動きを見ることにします。repeatの値を3から10くらいに増やします。
点B(c)を動かしてみると、発散しないのが単に原点に近いだけではないことがわかるでしょう。たとえば、-0.5+0.5i くらいなら発散しませんが0.4+0.1iくらいでは発散します。また、発散するものについても、あっというまに遠ざかってしまう点とそうでない点があることもわかるでしょう。
つぎは(B)ジュリア集合です。ジュリア集合では、点cの方を固定します。−0.5+0,5i くらいのところに点B(c)を置き、点A(z0)をドラッグして動かしてみましょう。
点A(z0)が点B(c)の左上にあるときはすく近くでも発散してしまうのに、右下ならばかなり遠くても発散しませんね。
いろいろ動かしてみると、発散するかどうかにまったく規則性(何かの線分上にあるとか)はないように思われるでしょう。
また、点Bを他に移してみると、まったく様相が変わってしまいますね。たとえば、先ほどの点を虚軸(y軸)に対称な点 0.5+0.5i に移すと先ほどとはずいぶん違ってしまいます。かなり近い点でも発散してしまいます。
どの点なら発散するのか、またその速さはどうちがうか(すぐに遠ざかる、しばらくは原点付近にとどまるがいずれ発散する)、それをはっきりさせるために、発散速度で色分けすることにします。色分けの方法はいくつかありますが、たいていは次のようにしています。
(ア) 何回まで調べるかその上限を決めます。たとえば100回
(イ) 原点からの距離に限界を設けて、それより外に出たら発散とみなします。たとえば距離2、つまり |z|>2 となったら発散。
(ウ) (イ)になるまでの回数を、色コードにする。このとき、RGB値(赤・緑・青の混色)を使うか HUE値(色相環での位置)を使うかで色合いは変わります。また、Cinderellaの場合は、透明度も指定できますのでこれを利用することもできます。
問題は、「すべての点」をどうやって調べるかです。実際には「すべての点」を調べることは不可能なので、0.01ごとの格子点で調べる、というようになるでしょう。C言語やJAVAなどのプログラミング言語では、この格子点をすべて調べるプログラムを書くことになります。しかし、CindyScriptには「すべての(といっても格子点ですが)点に色を割り当てる」という便利な関数があるのです。colorplotという関数です。ちなみに、MathematicaにもDensityPlotという同様の関数があります。
colorplot関数の書式は次の通りです。
colorplot([R,G,B],点Aの座標,点Bの座標)
colorplotでは、色の指定にRGB値を使います。この値を上記(イ)になるまでの回数にすればよいのです。ただし、それぞれ0以上1以下の値に換算します。点Aと点Bは矩形領域の左下と右上です。この矩形領域内の点について計算したものをRGB値とするのです。したがって、ここには、点の座標を使った式を書くことになりますが、それを変数#として計算式を作ります。このあとの実際の式をみてください。
また、色指定には、色相をRGB値に換算する hue(t)という関数を使うこともできます。この t も0以上1以下です。さらに、色の指定をひとつの実数にするとモノクロになります。
さらに、colorplotには、修飾子と呼ばれるオプションをつけることができます。
pxlres->n は解像度指定です。nは対象とするピクセルの大きさで初期値はn=2です。n=1にすると細かくきれいな図ができますが時間がかかります。
alpha->p は透明度です。pは0以上1以下です。
では、まずマンデルブロ集合からスクリプトを書きましょう。
その前に、2点A,Bをとっておきます。(前のものは消去して新たに作ります)
========================================================
f(pt):=(
c=complex(pt);
z=0;
k=0;
while(abs(z)<2.0 & k<N,
z=z^2+c;
k=k+1;
);
col=k/N;
);
N=100;
colorplot(hue(f(#)),A,B,pxlres->1);
========================================================
まず、colorplotのための関数を用意しました。
ptはある点の座標です。
cは点ptが表す複素数になります。
z=0 は初期値
k=0 は回数
while(|z|<2.0 & k<N は z の絶対値が2未満で、回数が上限のNより小さいあいだ繰り返すという関数(命令)です。
z=z^2+c で計算し、 k=k+1 で回数をカウントします。速く発散すればkは小さな値、そうでなければ大きな値になります。
col=k/N でカラーコードを決めます。0.01から1までの値になります。
N=100 は繰り返しの上限です。
colorplot(hue(f(#)),A,B,pxlres->1); で、点A,Bを対角とする領域の各点について調べ、色分けをします。
さて、このスクリプトですが、実行に少し時間がかかります。Draw スロットにおくと、点A,Bをちょっと動かしただけで実行するので、動作がとまったようになってしまいます。そこで、Mouse up スロットに置きます。このスロットのスクリプトは、マウスボタンがあがったときだけ実行されますので、点AやBをドラッグしている間は実行されません。
スクリプトの実行ボタン(歯車アイコン)を押したら、点A,Bのいずれかを動かしてみましょう。マウスボタンを離すと実行されます。
次はジュリア集合です。マンデルブロ集合とほとんど同じなので、マンデルブロ集合のファイルを保存し、複製をとって必要なところだけ書き換えればよいでしょう。
ジュリア集合では、点Cを固定しますので、点A,Bの他に点Cをとっておきます。
スクリプトは次のようになります。マンデルブロ集合と比較してください。
========================================================================================
f(pt):=(
z=complex(pt);
c=complex(C);
k=0;
while(abs(z)<2.0 & k<N,
z=z^2+c;
k=k+1;
);
col=k/N;
);
N=100;
colorplot(hue(f(#)+0.5),A,B,pxlres->1);
========================================================================================
colorplotで、hue値に0.5を足しています。こうすると全体の色合いが変わります。
さて、この画面コピーではわかりませんが、指定されている矩形領域は、A(-2,-1.5) , B(1.5,1.5) を対角とする領域です。これより外はすぐに発散してしまうので領域を広げてもあまり意味はありません。点Cの位置を変えると図はさまざまに変化します。
上図はCのあたりにいろいろ変化があるようです。このような場合、すぐには発散しない点が増えるので、計算にかなり時間がかかるようになります。そして、点Cの位置をほんのわずか変えるだけで図柄はがらっと変わってしまいます。
では、Cをこの位置にしてCの近くの領域を拡大してみましょう。点A,Bを点Cに近づけ、画面も拡大します。
すると次のようになります。さらに、回数の上限も変えてみましょう。
上限 N=80
上限 N=100
上限 N=200
Nを200にすると、それだけ実行時間がかかりますが、そのかわり精細な図が得られます。ブロッコリーのような図が現れましたね。
さらに領域を狭めて拡大し、微細な世界に分け入ってみましょう。AとBをCにぐっと近づけてみました。