2011/06/28

セルオートマトンのプログラム ソース

カオスでCG2(入門)で取り扱った、セルオートマトンのプログラムのソースコードを載せます。

載せたプログラムは『ca1.c』『coord.c』の2つです。前者は、セルオートマトンのプログラム、後者は前者で出力された1と0の羅列をグラフに描くために座標上の点に変換するプログラムです。

プログラムの実行手順、gnuplotを用いて図形を描く手順はソースコードの後に示します。
クリックでその部分まで移動

/******************************************************/
/* ca1.cプログラム   */
/******************************************************/

/* セルオートマトン(1次元)計算プログラム */
/* ルールと初期状態から、時間発展を計算します */
/* 使い方 $./ca1 (ルール番号) <(初期状態ファイル名)*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define N 250 /*セルの最大個数*/
#define R 8 /*ルール表の大きさ*/
#define MAXT 200 /*繰り返しの回数*/
#define BUFSIZE 256 /*入力バッファ用配列の長さ*/

/*関数のプロトタイプ宣言*/
void setrule(char *arg,int rule[]) ;/*ルール表の初期化*/
void initca(int ca[]) ; /*初期値の読み込み*/
int cvalue(char ch) ;/*1文字の0/1への変換*/
void putca(int ca[]) ;/*caの状態の出力*/
void nextt(int ca[],int rule[]) ;/*次の時刻に更新*/

/**********************/
/* main関数 */
/**********************/
int main(int argc,char *argv[])
{
int t ;/*時刻を表す、反復回数のカウンタ*/
int ca[N]={0} ;/*セルの並び*/
int rule[R] ;/*ルール表*/

/*ルール表の初期化*/
if(argc<2){/*ルールの指定がない*/
fprintf(stderr,
"使い方 $ ./ca1(ルール番号)<(初期状態ファイル名)\n") ;
exit(1) ;
}
setrule(argv[1],rule) ;/*ルール表をセット*/

/*ca[]への初期値の読み込み*/
initca(ca) ;
putca(ca) ;/*ca[]の状態の出力*/

/*時間発展の計算*/
for(t=0;t<MAXT;++t){
nextt(ca,rule) ;/*次の時刻に更新*/
putca(ca) ;/*ca[]の状態の出力*/
}
return 0 ;
}

/***************************/
/* nextt()関数 */
/* caの状態の更新 */
/***************************/

void nextt(int ca[],int rule[])
{
int nextca[N]={0} ;/*次世代のca[]*/
int i;

/*ルールの適用*/
for(i=1;i<N-1;i++)
nextca[i]=rule[ca[i+1]*4+ca[i]*2+ca[i-1]] ;

/*caの更新*/
for(i=0;i<N;++i)
ca[i]=nextca[i] ;
}


/**************************/
/*   putca()関数    */
/* caの状態の出力 */
/**************************/
void putca(int ca[])
{
int i ;
for(i=N-1;i>=0;--i)
printf("%1d",ca[i]) ;
printf("\n") ;
}

/**************************/
/* initca()関数 */
/* 初期値の読み込み */
/**************************/
void initca(int ca[])
{
char linebuf[BUFSIZE] ;/*1行入力用の文字配列*/
int i=0 ;

/*初期値を読み込む*/
if(fgets(linebuf,BUFSIZE,stdin)==NULL){/*読み取り失敗*/
fprintf(stderr,"初期値の読み取りに失敗しました\n") ;
exit(1) ;
}

/*初期値の設定*/
for(i=0;linebuf[i]!='\0';++i)
ca[N-1-i]=cvalue(linebuf[i]) ;/*左詰めで代入*/
}


/************************************/
/* cvalue()関数 */
/* 1文字の0/1への変換 */
/************************************/
int cvalue(char ch)
{
if(ch=='1') return 1;
else return 0;
}


/************************************/
/* setrule()関数 */
/* ルール表の初期化 */
/************************************/
void setrule(char *arg,int rule[])
{
int ruleno ;/*ルール番号*/
int i ;

/*ルール番号を取得*/
ruleno=atoi(arg) ;
if((ruleno<0)||(255<ruleno)){/*ルール番号が不正*/
fprintf(stderr,"ルール番号が正しくありません(%d) \n",ruleno) ;
exit(1) ;
}
printf("ルール番号 %d :",ruleno) ;
/*ルール表の書き込み*/
for(i=0;i<R;++i){
rule[i]=ruleno%2 ;/*2進数で1の位の値を取り出す*/
ruleno/=2 ;/*左シフト*/
}
/*ルールの出力*/
for(i=R-1;i>=0;--i) printf("%1d",rule[i]) ;
printf("\n") ;

}





/************************************************/
/* coord.cプログラム */
/************************************************/

/* 行列形式のデータを座標形式に変換します */

#include

#define BUFSIZE 1024 /*入力バッファ用配列の長さ*/

/***************************/
/* main関数 */
/***************************/
int main()
{
int lineno=0 ;/*行番号*/
char linebuf[BUFSIZE] ;/*1行入力用の文字配列*/
int i ;

/*初期値を読み込む*/
while(fgets(linebuf,BUFSIZE,stdin)!=NULL){
/*読み取れる間繰り返す*/
if(linebuf[0]=='0'){/*データ領域*/
for(i=0;linebuf[i]!='\0';++i)
if(linebuf[i]=='1') printf("%d %d\n",i,-lineno) ;
/*座標の出力*/
++lineno ;
}
}

return 0 ;
}


 

手順
では実際にプログラムを動かしてみましょう。(以下の手順は、Linux上で、gccコンパイラ、gnuplotがパソコンに入っていることを前提としています。他の環境でも微妙に操作を変えることでうまく動作すると思います。)

0) ca1.c、coord.cが置いてあるフォルダの中に『init.txt』という名前で、125番目だけ1で他はすべて0の合計250文字・1行のテキスト文を作成しておく。例) 000000000000000・・・0001000・・・0000000000000000

1) 端末を開いて、『ca1.c』『coord.c』が置いてある場所へ行き、以下のようにコマンドを打っていく(私が使用しているのはUbuntuなので、端末の初めに表示されるのは ・・・$ )。

$ cd (ca1.c、coord.cが置いてあるディレクトリ名)
$ gcc -o ./ca1 ca1.c
$ gcc -o ./coord coord.c
$./ca1 18 <init.txt | ./coord >fig12out.txt


ここで、2,3行目の gcc のあとの引数 -o はコンパイルして生成される実行ファイルの名前を任意に決めることができるオプションをつけます。使い方は次のようにします。
$ gcc -o ./(実行ファイル名) (プログラム名)

4行目の./ca1 のあとの18という数字は「ルール」で、自分で指定することができます。0から256まで好きな数字をいれてください。それによって描かれる図形が変わってきます。

この結果、座標のデータが入ったテキスト『fig12out.txt』ができあがります。

2) 端末上で

$ gnuplot

と打ちます。その後、端末上に表示されるgnuplotの画面で以下のように打ち込みます。するとグラフ上に図形が描かれます。

gnuplot> plot "fig12out.txt" with points pt 5 ps 0.2 lt 8
pt:点の種類 ps:点のサイズ lt:点、線の色

上にも書いていますが、オプションとして、pt(点の種類)、ps(点のサイズ)、lt(点、線の色)を指定することができます。
ptとltは整数値で指定できます。端末上でいろいろと値を変化させてみて、最も見やすいグラフを作りましょう。




以上です。ソースコードは「小高知宏 『Cによる 数値計算とシミュレーション』 第1版 オーム社」のpp.86ー100、pp.199ー201をほぼ完全に抜粋しました(若干書き換えたところもあります)。

読んでくださった方は、興味があればぜひプログラムを実行してみてください。


スポンサーサイト
2011/06/12

カオスでCG2(入門)

今回は、カオス理論の関連書には必ず載っている「フラクタル図形」を描いてみたいと思います。

「フラクタル図形」を描くのに「セルオートマトン」を用いるものがあり、参考図書、参考サイトをもとにプログラムを組んでみたいと思います。

では、その前にセルオートマトンについて説明します。以下①・②はセルオートマトンを用いて描かれた画像。

セルオートマトン2   セルオートマトンで作ったフラクタル図形
①                   ②


① http://members.jcom.home.ne.jp/tom3d/pov840/ilpov84j.htm 数想空間 / CELLULAR AUTOMATON 0
② http://www001.upp.so-net.ne.jp/suzudo/tutorial.html セルオートマトンと複雑系   より画像を引用。

セルオートマトンとは、「内部状態を持ったセルが他のセルとの相互作用によって時間的に変化してゆくというモデル」です。少し説明が足りないので付け加えていきます。以下③・④を参照。

セルオートマトンの世界には、複数のセル(細胞、小部屋)があります。図③では4つのセルを描きました。それぞれのセルはある時刻tにおいて個別の内部状態を持ち、時間の経過とともに他のセル同士と相互作用をして内部状態を変化させていきます。図では時刻tにおける各々の内部状態をA1(t)、A2(t)、A3(t)、A4(t)のように表記しました。


セルオートマトン模式図

dt後

セルオートマトン模式図2

さらにdt後…


時間dtが経過した時点でセルは一斉に状態を更新します。(④)その状態の変化は上に述べたように、隣り合うセルの影響を受けて生じます。つまり時刻tにおける近くのセルの状態により、自身の時刻t+dtにおける内部状態が決定されるのです。

こうやって更新されたセルたちは、またさらに時間が経ったときに更新されます。自分に影響を与えた他のセルへ、今度はその影響も含めて自分の内部状態を他のセルへ伝播していくのです。

これが、セルオートマトンの概略です。

他の影響を受け、それに従いまた他に影響をおよぼす。これはまさに、生物界のやりとりに似ています。
それもそのはず、セルオートマトンは生物の活動そのもの、また遺伝などの複雑な生命現象を、簡潔な理念的モデルとして表せるか?との試みから作られたものなのです。


簡単な説明を終えたので、実際に②のような図をプログラムを用いて描いてみたいと思います。ただ、自分にはまだ完全にプログラムを自作する能力がないので、「小高知宏『Cによる数値計算とシュミレーション』オーム社」からソースコードを抜粋します。


プログラムのソースコードや描画の流れなどは、次のリンクから見ることができます。
セルオートマトンのプログラム




以下に示す図が、私がセルオートマトンのプログラムを用いて作成したフラクタル図形です。

セルオートマトン


最初にはピラミッドの頂点にしか点がなかったものが、時間とともに下へ向かうにつれて、美しく構造化されていきます。

プログラムでは、各々の点が自分自身、右隣、左隣の3つの点が0か1かによって、次の時刻における自身のあり方を決める単純な「ルール」を定めました。 例)赤色が自身とする。 0 1 0ならば0、 1 0 1ならば1…など

ただそれだけのことで、時間とともに繰り返すような構造が生まれてきます。ルールを変えたり、初期位置を変えたりすることで、また複雑な図形が描かれることもありました。(以下の図は左からルール30、ルール60)

ルール30ルール60



簡単なルールから、複雑な構造が生まれて来る。このことは、カオス理論の一翼を担う概念です。

近代の科学は、複雑な現象を観測すれば、とかく要素に分解して、それぞれの性質を調べれば分かるとの信念のもとに進んできました。しかし、いくら分解した物の性質が分かったとしても、それらが寄り集まったときのふるまいは、ただの総和にはならないのです。要素同士が相互に作用するからです。


いかに複雑な現象といえども、実は根底に非常に簡単なルールが隠されているかもしれない。そんな期待をカオス理論は持たせてくれます。今回セルオートマトンを用いて図形を描いてみて、それをひしと実感しました。


最後まで読んで下さりありがとうございます。ではまた次の記事で。


2011/06/06

読書メモ1 数学は世界を解明できるか

先日、中公新書から出ている丹羽敏雄さんの「数学は世界を解明できるか カオスと予定調和」という本を読み終えた。

内容は、人間が天体の運行を予測することから始まって、各時代の数学者を含めながら様々なモデルによる未来予測について説明し、最終的にはカオス、フラクタルの説明をするというものだ。

この本の要約は大変なので、中に出てきた人名及びキーワードを列挙する。本の進行順にしたがって書いて行く。各人名やキーワードはほぼすべてWikipediaに載っているので、検索してみるといいかもしれない。自分は忘れた頃に振り返ってまた調べるつもりである。

<人名>
ヘラクレイトス、プラトン、プトレマイオス、ヒッパルコス、コペルニクス、ガリレイ、ケプラー、ニュートン、フック、ポープ、マクスウェル、フーリエ、アンペール、ファラデー、ヘルツ、アインシュタイン、ボルツマン、フェルミ、パスタ、ウーラム、プリゴジン、ハーケン、マルサス、メイ、ローレンツ、ラプラス、ポアンカレ、コルモゴロフ、アーノルド、マンデルブロート、フォン・ノイマン

<キーワード>
ダイナミカル・システム、天動説、システム(系)、閉鎖系、開放系、アノマリ、地動説、理想化、マクスウェルの方程式、特殊相対性理論、エントロピー増大法則、大数の法則、エルゴード性、パイコネ変換、エルゴード仮説、安定不動点、安定定常状態、吸引点(シンク)、不安定不動点、湧点(ソース)、安定周期解、不安定多様体、安定多様体、ホップ分岐、散逸構造、ハーケンの隷属化原理、マルサスのモデル、ロジスティックモデル、ロトカ・ヴォルテラのモデル(捕食者・被食者モデル)、自己相似性、ファイゲンバウムの普遍定数、メイの生態学モデル、ローレンツ方程式、ローレンツ・アトラクター、ストレンジ・アトラクター、バタフライ効果、ホワイトノイズ、フラクタル図形、フラクタル次元、コッホ曲線、カントール集合、アーノルド拡散、セルオートマトン、テューリングのモデル


ひまがあれば上のワードにリンクをはってみたいと思う。
2011/06/01

人間は宇宙の法則に逆らっている?

ある閉鎖系の中では常に系内のエントロピーは増大する方向に向かう。

ある水槽が板によって2つの領域に分けられているのを想像してもらいたい。

一方の領域にはただの水が、他方にはインクで色をつけた水が入っている。

ここで、2領域をへだてる板をとりはらうとどうなるかは容易に分かるだろう。
無論インクは時間とともに混ざり合い、いずれは全体として色のついた水になってしまうはずだ。

インクのついた水が自然と2層に分かれることはない。(インクが油性だったらわからないが(´・ω・`))

   インクと水  インクを投下 
        1.インクと水            2.インクを水に滴下
     インクと水は時間が経つにつれ混ざっていく     
      3.時間とともに混ざる        4.インクはもう取り出せない


これはエントロピーを説明する際によく使われる例なのである。

自然においては、最初の、二つに分かれた状態(=整った状態)から、最終的には混ざり合った状態(=乱雑な状態)へと必ず移行する。このことを「エントロピー(乱雑さ)が増大する」という。

これが「なぜ」なのか、明確な答を出している人はまだいない。


さて、ここで人間の営みについて考えてみよう。

人間は木材から家を組み立て、冷めていくはずの水を温め、たくさんの部品から精密なコンピュータをつくることができる。

すなわち、人間はばらばらのモノを組み合わせることで、自然のまま放置していては形成されないような整った構造をつくりだすことができる。

これは、人間が自然の法則に従った流れに反する動作をしていることにはならないだろうか。

自分が撮影に使ったデジカメ一つとってみても、到底自然発生的に組み上がるものではない。

では人間は自然の法則を乱しているのであろうか?

ここで最初に述べた一行「ある閉鎖系の中では常に系内のエントロピーは増大する方向に向かう。」の「ある閉鎖系の中では」に注目したい。

閉鎖系については、外部とのやりとりのない箱を想像してもらえばいい。
温度に差がある二つの水をその箱の中に入れると、しばらく経った後には二つの水は一つの同じ温度の水になる。これは、温度差がある、という整然とした状態から、温度差のない混ざりあった状態になったので、箱の中のエントロピーは増大している。

しかし、この箱が外部とのやりとりがないものではなく、底から常に加熱され、また外へと熱を逃がすことのできる箱だとすると事情が少し変わってくる。全体の水の温度が均一になってしまったとしても、底から熱が供給されて水は温められ、底以外の部分では外部へと熱を逃がすため水は冷める。つまり、箱の内部では底とそれ以外の部分で水に温度差がうまれ、エントロピーは減少している。

外部とのやりとりのある箱のような系を「開放系」と呼ぶ。開放系では、箱の中に整然とした構造が生まれることが知られている。

では我々の住む地球に目を向けてみよう。

地球はそれ一個で完結した閉じた箱(閉鎖系)のようにも見える。生命たちは地球というカプセルの中でぐるぐると循環を繰り返していると考えられそうだ。

しかし大事なことを見逃してはならない。地球は閉鎖系ではなく、常に宇宙から太陽の光を受け取って暖められ、また宇宙空間へと熱を逃がしている開放系である、ということを。

太陽から常に熱や光エネルギーを受け取っているからこそ、生命や人間といったとても整った存在が生まれたのだ。

先ほどの二つの温度の水の例は直感的に分かりやすいが、人間がモノを組み立てたりする行為も、太陽光によって整然とした
構造を生み出す挙動のひとつの表れである。

自分はこの事実を知って感動を覚えた。太陽光というただの形のないエネルギーが、人間という生命体を形作り、エネルギーの作用のひとつの表れとして、整った文明をつくりあげたのだ。

この事実はとても面白いと思うのだがどうだろうか。

久しぶりの更新で長々と書いてしまいましたが、ここまで読んでくださりありがとうございます。






上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。