3次元離散ランダムウォーク
暇を持てあましたhat-tunの遊び。
3次元離散ランダムウォークの到達地点距離のシミュレーションプログラムを書いてみた。
あとそのスケーリング。
3次元離散ランダムウォークってのは、
時間0の時に原点にいるヒトが、
各単位時間ごとにそれぞれ6分の1の確立で、x,y,zの軸の正負の方向に動き続けるというシンプルなもの。
それで、原点にわしゃわしゃいっぱいヒトがいた時に、何時間後にみんなだいたいどこにいるやろか。
って話ですね。
たとえば、実用例としては、
物理現象の、ブラウン運動などは3次元ランダムウォークですねー◎
#include <stdlib.h> #include <stdio.h> #include <time.h> #include <math.h> #define N_SUM 100000 //試行回数 #define N_TOTAL 1000 //ステップ数上限 int main(void); double frand(void); void random_walk(void); int main(){ random_walk(); return 0; } double frand(){ return (double)rand()/RAND_MAX; } void random_walk(void){ int i,j,k; int x,y,z; double r=0.0; //各試行での2乗和を累計 double r_ave=0.0; //2乗和の平均 FILE* fp; fp = fopen("test.dat","w+"); for(i=1;i<=N_TOTAL;i=i*10){ for(j=0;j<N_SUM;j++){ x=0; y=0; z=0; srand((unsigned)time( NULL ));//乱数系列の更新 for(k=0;k<i;k++){ double val = frand()*6;//0<=val<=6の乱数 if(val>5.0){ x++; }else if(5.0>= val && val > 4.0){ x--; }else if(4.0>= val && val > 3.0){ y++; }else if(3.0>= val && val > 2.0){ y--; }else if(2.0>= val && val > 1.0){ z++; }else{ z--; } } r = r+ pow(abs(x),2)+pow(abs(y),2)+pow(abs(z),2); } r_ave= (double)r/N_SUM; printf("%4dstep | R average = %f\n",i,r_ave); fprintf(fp,"%f %f\n",pow(i,0.5),pow(r_ave,0.5)); } fclose(fp); }
テキトーに書きました。上の例で言うと、N_SUMが人の数で、N_TOTALが時間ですね。
それにしてもステップ数のオーダーがO(N_SUM*N_TOTAL^2)というひどいプログラムですねw
まともに計算したら10^11となって、理論上1000秒もかかるみたいですw
ここでは、計算時間を1秒ぐらい(=約1億ステップ)に抑えるため、
N_TOTALが1,10,100,1000の時の値を出してます。
それと乱数を2つ使ったほうが高精度という話を聞いたんですが、
よくわかりませぬ><
教えて賢いヒト。
まぁそれはさておき、こっからが新しい。俺の中で。
gnuplotを使って、スケーリングを確かめまする。
上のプログラムで、
ステップ数、末端間距離の2乗平均=r_ave
の各1/2乗をファイルにアウトプットする。
test.datのoutput例
1.000000 1.000000 3.162278 3.710881 10.000000 16.904752 31.622777 28.647591
やりたいことは、この2つの変数が、大体比例してるやん!(スケーリングしてる)
ということを確認したいわけです。
そのためにgnuplotのfit関数というものを使うのですが、
こいつは、ある指定した(予想した)関数とデータから、その関数の係数を割り出してくれるものです。
さらにグラフにプロットすることもできます。
これで、データが予想した関数に近いかどうかを判定できるというスンポー。
論より証拠、やってみましょう。
とりあえずおもむろにgnuplotを起動する。
fittingする関数を定義する。 → 机で計算して予想。
そしてデータファイルを読ませる。→ だいたいの係数がわかる
plotしてみる。 → わっほい!
という流れ。
$ gnuplot gnuplot> f(x)=a*x gnuplot> fit f(x) 'test.dat' using 1:2 via a gnuplot> plot f(x),'test.dat' using 1:2
ここでは、線形になるとの予想があるので、f(x)=a*xと定義。
そして、fit!
using 1:2というのはおまじない。いや、意味知らないだけですが。
via aで対象変数を設定しましょう。
せっかくなので、プロットしたグラフをファイルに。
gnuplot> set term png gnuplot> set output "scaling.png" gnuplot> plot f(x),'test.dat' using 1:2
と、ここではscaling.pngというファイルに出力してみます!
できたできた♪ どれどれどれ。。。
ん?
比例してねえwww
すいません。多分コードの精度の問題ですww
理論上は比例するはずです・・・w
ダメ過ぎるw
ああ、乱数まわりちょっと勉強せんとなー。orz
まぁこういう使い方があるってことだけでも、理解してくれたら幸い。