2012年5月21日月曜日

Life Game

Life Gameはuniversalであるといわれる. つまり計算機を構築する部品がいろいろ考案され, それを組合せればよいという議論らしい. ただ, von Neumannの自己増殖機械みたいに, 縦何セル, 横何セル, 遺伝子のセル何個で出来るというような具体的な数値がないので, これで時間さえかければ解けるよね, といわれている程度にしか納得できない.

さて, そういう部品の一つに希薄銃(thin gun)というのがある. Life Gameで作る計算機の情報(信号)は, 2次元世界を飛び回わるグライダーだが, グライダー銃は30クロックごとにグライダー1個を発射し, これでは濃すぎる(多すぎる)ので, もっと間引いたグライダー列を作りたい. その機構が希薄銃である. 本当に出来るかなと思いやってみた.

次の図が希薄銃の様子を示す. これはProcessingのシミュレータで動いているもののある時点でのスナップショット(をPostScriptで書き直したもの)である.



赤い丸で数字を囲ったのが3個所あり, それぞれグライダー銃がグライダーを発射する場所だ. 左上のグライダー銃0は, 右下へグライダーを出し続ける. 図に見えるグライダーに先頭からa, b, c,...と標識を付ける.

(グライダー銃はもっと複雑な形だが, こんな大きなものをシミュレータに書き込むと, 広い面積が必要になるので, このシミュレーションでは, シミュレータがどのタイミングにどの位置でどの方向へグライダーを発射するかのシナリオに従ってグライダーを発生する.)

右端の中ほどに1番のグライダー銃があり, これは左上へグライダーを送る. こちらのグライダーをf, g, h,...とする.

これらグライダーの2列の間で, eというグライダーが右上に向っている. これはConwayのいうキックバックで, eは2つのグライダー列の間を右上と左下で往復する. eは間もなくfと接触し, eとfは消滅し, eと逆向きのグライダーが出現する.

そうして戻ってくるキックバックのグライダーは, タイミング的には0番のグライダー列のdと接触し, dを消し, また右上へキックバックする.

eが前回右上に向う前に, 左下へ向っていたグライダーはaの1機前のグライダーに衝突し, 右上へキックバックしていたのである. 0番のグライダー列は, したがって, a, b, cとキックバック地点を通過した後, dは消滅し, その後また3個通過し, 1個消滅する,...  を繰り返す.

左上へ進んでいる1番のグライダー列も, 4個に1個はキックバックで消えるが, 3個はキックバックされずに通過する. しかしキックバック後のグライダーは要らないから, Eと書いたイーターで吸い込む.

上の図には中央あたりに2番のグライダー銃があり, グライダーを左下へ発射している. そこへキックバックを回避してきた0番のグライダー列が近づく. この衝突は, 両者が消滅する位相であって右下へ通過するグライダーはないが, すでにキックバックで消えた0番グライダーに対応するホールでは, 2番のグライダーは衝突を免れ, 左下へ進む. 図の左下のグライダーiは, そのように抜けてきたものである. その後3機の2番のグライダーは, キックバックを免れた0番のグライダーのために消滅してホールになる. jはaの前のグライダーがホールだったため, 抜けてきたのである.

このようにして, キックバックで3/4になった0番のグライダー列により, 1/4に希薄になったグライダー列が発生出来る.

次は, キックバックの起こし方だ. グライダーの位置決めのため, ある方向に進むグライダーの4位相パターンのそれぞれに, 注目点を決めよう.



この右下へ移動するグライダーの図で, 左上, 右上, 左下, 右下が赤字のようにそれぞれ位相0,1,2,3で, 一番進行方向に近い場所を注目点とする. 位相0はいわゆるハッカーエンブレムの形で, 4クロック後には右へも下へも1セル分移動する.

Conwayの示すキックバック機構の図は以下の通り.



白黒を問わず, 丸が生きているセルである. 下の数字0から8は相対クロックだ. クロック0では上に左下へ進むグライダー, 下に右下へ進むグライダーが見える. 黒丸は次のクロックでも生き残るセル. 白丸は次には消えるセル, 点は今は死んでいるが, 次のクロックで生まれるセルだ.

この反応を経て, クロック6,7,8では右上へキックバックされるグライダーが形成され, 8が丁度0と180度逆転している. つまり, ターンで8クロックかかるわけだ.

グライダーの列は30クロック間隔なので, 向こうでもう一度キックバックされ, 30の倍数で戻ってくれば, 後続のグライダーとうまく衝突出来る. こちらのターンで8, 向こうで8かかると, 16クロック. 1歩進むのに4クロックかかるから, その距離往路と復路で8クロック. 16足す何倍かの8クロックの和で30の倍数になるのは,

30=16+8*1.75
60=16+8*5.5
90=16+8*9.25
120=16+8*13

だから, 最後のが解で13ステップの距離を往復し, 片側で120クロック毎にキックバックを起すことになる. 120はグライダー間隔30クロックも4倍なので, 4機に1機が犠牲になる.

この計算から分かるように, 240クロックでもグライダー間隔を28にすればキックバック出来る. Conwayの記述には, 1/Nに希釈出来るが, Nは4の倍数でなければならないとある.

先ほどの図で, グライダー0とキックバックしたとして, 次のグライダー1とのキックバックはどこだろうか. タイミング0の下のグライダーの注目点(下の3x3の正方形の右下)をx=0,y=0とすると, タイミング8の右上に出発しようとするグライダーの注目点はx=0,y=5である(yは上向きに測る.)

次の衝突のタイミング0は13セル間隔離れているから, x=13, y=18, つまりタイミング0の上のグライダーの注目点がそこである. 従って, その時点で1番のグライダーの注目点は, 0の下のグライダーと180度回転した形で, xが1少なく、yが4多い. x=12, y=22にグライダーがあれば良い. そのタイミングでグライダーを発射するように1番のグライダー銃を配置する. または, xとyを1ずつ遠ざけると, 発射の位相を4早める.

キックバックの図を描くプログラムを利用して, 2個のグライダー消滅の様子も描いてみよう.



この図のように, 左上から来るグライダー(下)と右上から来るの(上)とが, この位置で出会うと4クロック後に消滅する. 右上の2番から出続けるグライダーは, 左上のグライダーがあると消滅し, ないと飛び続けるから, これをNot回路という.

シミュレータを使うノウハウも結構たまったので, またいろいろ遊べそうだ.

2012年5月9日水曜日

PC-1シミュレータ

パラメトロン計算機 PC-1のシミュレータは何回も書いたことがある. 数年前にC言語とxlibで実装したのは, 計算機のインディケータの点滅も再現していて, 見ていると楽しい. それを公開したいと思っていたが, うまい方法が見つからず, 延び延びになっていた.

しかし, 情報処理学会コンピュータ博物館のウェブページで, 「PC-1 パラメトロン式計算機」を見ると, 「現在PC-1の現物は存在しないが, 和田英一によりノートPC上でPC-1シミュレータが実現され, 当時のプログラムが動作している.」と書いてあるので, 早く公開しなければと少しずつ公開用の実装を進めていた.

今回, やっとProcessingで実装した同様のシミュレータが完成したので, お目にかけたい. ただ, 私の新しい4CPUのMacBook Airでは順調に走るのだが, 古い方のMacBookAirでは, インディケータが高速には点滅せず, 臨場感がいまいちだ. また私のウェブページパラメトロン計算機 PC-1も参考にされたい.

さて, 今回のシミュレータである.

http://playground.iijlab.net/~ew/pc1sim/pc1sim.html

にアクセスすると, 下のような画面が現れる. これがシミュレータのインターフェースだ.



中央左よりの緑の小箱の列は, インディケータで, 最上段の左18ビットが命令レジスタ, その右11ビットがSCC(シーケンスコントロールカウンタ), その下で36個並ぶのは, 上からメモリーレジスタ, アキュムレータ, Rレジスタである. PC-1は1語が18ビットだが, 2語つなげて36ビットを長語として演算が出来た.

各レジスタの内容の0(白で)と1(オレンジ色で)が表示される.

情報処理学会のコンピュータ博物館にパラメトロン計算機PC-1のウェブページがあり, 後藤さんと高橋先生がPC-1の前にいる写真がある. そのPC-1の上の方にネオン管が並んでいるが, それがこのインディケータである.

インディケータの右で3行3列に並ぶ枠がスイッチである. 上の3個は左からクリアスタート(Clear Start), イニシアルスタート(Init Start), リスタート(Restart).  リスタートは中断したプログラムを再開する. PC-1では, 停止したとき, 次の命令が命令レジスタに読み出されているから, それを棄て, SCCの示す場所の命令からスタートするのがイニシアルスタートである. さらにSCCを0にした上でイニシアルスタートするのがクリアスタートである.

このシミュレータは先読みしないので, 中と右のスタートは同じである.

中段の3個は左からイニシアルロード(Init Load), フリーラン(Free Run), ストップ(Stop)で, フリーランは連続実行モードをオンにし, ストップはオフにする. オフの時のスタートスイッチは, 命令のステップ実行になる. 左端のイニシアルロードは, イニシアルオーダーのテープを読込む.

下段は左からイニシアルオーダーテープを用意する(Place R0); e1000桁のテープを用意する(Place e1000)スイッチである. 右端は, 他のデモテープを選択する(Place Tape)スイッチで, 現れたメニューから選ぶ.

テープ選択スイッチを押すと,



のように右上にメニューが出るので, 使いたいデモプログラムをクリックする.

デモテープは次の4つが用意してある.

a. factorize32 2^31-1, 2^31-3, ..., 2^31-19 を素因数分解する (5分55秒)
b. eratosthenes 篩を使い256から11327までの素数の表を作る (7分)
c. lucaslehmer 3から199までの素数pについてMpの素数性を調べる
d. e1000 自然対数の底eの値を1000桁計算する (6分15秒)

lucas lehmer以外のそれぞれの最後は私が最近ウェブでテストしたの終了までの時間である.

シミュレータを使うには, まず左下のLoad R0スイッチで, イニシアルオーダーR0 のテープを用意する. 次にその上のInit Loadスイッチで, R0を読込む. テープの6列分がメモリーレジスタに読込まれ, 長語(36ビット)として, SCCの表示する0番地, 2番地, ..., に読込まれ, 同時にアキュムレータの各ビットとXORをとってアキュムレータに戻す. 読み終わったとき, アキュムレータが0になるようにパリティビットがテープに入っている.

e1000桁は当時ポピュラーだったデモプログラムである. フリーランにして, クリアスタートでテープ読込みと計算が始まる.

このプログラムは460の階乗分の1までで計算するが, 4回分を一度にまとめて計算するので, インディケータの規則的な繰り返しが115回で計算は終了. その後は結果の二進十進変換になる. このプログラムはR0を壊さないから, 次のデモはR0の再読込みなしで始められる.

factorize31は 231-1, 231-3, 231-5,...231-19を素因数分解するデモプログラムである. このテープは入力サブルーチンのテープを読込んだ後, 停止するから, フリーランをクリックし, リスタートしなければならない. 結果は以下のようになる.

2147483647.=2147483647.
2147483645.=5.19.22605091.
2147483643.=3.715827881.
2147483641.=2699.795659.
2147483639.=7.17.18046081.
2147483637.=3.3.3..13.6118187
2147483635.=5.11.337.115861.
2147483633.=5843.367531.
2147483631.=3.137.263.19867.
2147483629.=2147483629.


最初と最後が素数であり, 特に最初はMersenne素数である. 231の平方根 46340までの疑似素数で割ってみる. 割る値がRレジスタに見えている. 46340は八進法では132404なので, Rレジスタの中央より右が132000くらいになると素数でも計算は終了する.

このデモプログラムはR0を破壊するので, 次のデモの前にはR0を再読込みする必要がある.

eratosthenesの篩 256から11327までの素数を篩で探す. 篩には36ビット長語の32ビットを使い, 残りの4ビットには疑似素数の差を保持する.

最初3で篩い, 次に5で篩い, ..., 11327の平方根106で篩うまで篩えばよいのだが, このプログラムは, 疑似素数の差の循環時に終了テストをするから, 231(八進で347)になるまで篩う. 篩う数はRレジスタに見え, 篩う数が大きくなると, 篩うのに要する時間短くなるのが分かる.

篩終わると, 出力ルーチンが読込まれ, 結果の1315個の素数を持つ素数表257. 263. ... . 11321.  が印字される. このデモプログラムはR0を破壊しない.

Lucas Lehmerテスト ある素数pについて, Mp=2p-1が素数の時, MpをMersenne素数という. この素数性を調べるLucas Lehmerテストというのがある. s0=0, sn=sn-12-2(mod Mp)を計算し, sp-2=0(mod Mp)ならMpは素数である.

デモプログラムlucas lehmerはp=2,3,...,199の素数について, Mpの素数性をしらべ, 素数ならpを, 合成数ならcを印字する.

最後まで実行すると相当時間がかかるので, 適当なところで中断しよう. PC-1が活動していた頃, 分かっていたMersenne素数はM3217くらいまでであった.

デモプログラムはplayground.iijlab.net/~ew/pc1sim/{e1000, factorize31, eratosthenes, llt}で見られる.

これらのシミュレーションは50年前の実機より格段に速い. しかしネオン管の明滅は当時を彷彿とさせる. 最近のCPUはブラックボックスになって, なにがどうなっているか分からないが, 当時はこのようなインディケータを眺めて計算の進行状況を知り, 一喜一憂していたものだ. 出力も印刷電信機で, 大きな音をたて, 机をゆさゆさ揺らしながら, 文字を出力していた. あれから半世紀が過ぎた.