3. シミュレーション
プログラムの解説の前に、シミュレーション全般について解説します。シミュレーションを一言で説明すると、物事の「ミクロ」な動きを記述することによって、「マクロ」的な状態を予測することです。今回の万華鏡のシミュレーションであれば、光の直進と鏡面での反射という(ミクロな)動きを繰り返すことで、スクリーンに映るオブジェクトの像というマクロな結果を得ることがあたります(*1)。個別の動きは単純でも、マクロな動きを直接記述する術がないときに、シミュレーションは威力を発揮します。
シミュレーションには、科学技術計算から経済モデルまで、さまざまなモデルがありますが、大枠の構造は似通っており、主に以下の3つの部分から構成されます:
- 初期化:シミュレーションの出発点を定義することです。今回の万華鏡のモデルでは、スクリーン(網膜)上の点と、そこからピンホールに向かう方向を与えることがあたります。
- 反復処理:シミュレーションでは、あらかじめ決めておいた手順に基づいて、状態の変化を記述していきます。今回のモデルでは、光がどの鏡面に当たるか、当たった後にどの方向に反射されるかを決定することがあたります。
- 停止条件のチェック/停止:反復を止めて、答えを計算することです。今回のモデルでは、スクリーンから発した光がオブジェクトに至ったかどうかを判断し、Yesであれば達した点の座標/色を求め、Noであれば2の反復処理を続けることがあたります。
シミュレーションの例としては、その他に以下のようなものがあげられます:
- 天文計算:太陽や惑星間に働く引力を記述し、短い時間の惑星の(ミクロな)動きを繰り返すことで、未来の惑星の配置や、日食などの天文現象を予測する。
- 天気予報:現時点までに観測された気象状況(気圧、湿度など)と、流体力学などの動学に基づき、短時間の大気変化を繰り返し計算することで、未来の天気を予測する。
- マクロ経済予測:所得/支出、投資額、為替レートなどのマクロ的な数値の関係を記述し、微小期間内の経済状況の変化を繰り返し計算することで、比較的長期の経済動向を予測する。
- ミクロ経済モデル/ゲーム理論:個々人の損得/効用などの価値基準を定義し、各人がそれぞれの価値観に従って行動するものとする。その上で、各種施策/マーケティング活動など、さまざまな刺激に対する反応を計算し、施策の効果を予測する。
以下、万華鏡のシミュレーションについて解説していきます。
4. プログラム
プログラムでは、以下のクラスを用意しました:
- Kaleidoscope(万華鏡):メインモジュール。ここで各クラスを呼び出し、シミュレーションを行います。
- KS_object(オブジェクト):オブジェクトをあらわすクラス。シミュレーションでは、ビーズ等の代わりに画像ファイル(jpeg)を使います。
- Mirror_set(鏡):万華鏡を構成する鏡をあらわすクラス。3つの鏡(mirrorクラス)をメンバーとして持ちます。シミュレーションの実質的な処理は、ここのsimulationメソッドで行われます。
- KS_image(像):カメラのスクリーンにあたるクラス。万華鏡を通してスクリーンに映し出された像は、ここで保持します。
また、補助的なクラスとして、以下を用意しました:
- ray(光線):像(KS_image)から出発した光線(<位置,方向>で表現する)を、このクラスで定義します。
- mirror(鏡):鏡(<位置,向き>で表現する)を、このクラスで定義します。反復処理では、Mirror_setクラスとの間で、インプットとして鏡に入射する光線を受け取り、アウトプットとして反射された光線を返します。
なお、本稿で扱うプログラムの全体像については、記事に付属しているサンプルファイルを併せて参照してください。
なお、プログラムはコンパイル後、DOSプロンプト上で以下のように実行します:
java Kaleidoscope [object.jpg] [image.jpg] [width] [height]
- object.jpg: オブジェクト用画像ファイル名(各自で用意してください)
- image.jpg: イメージ用画像ファイル名(万華鏡の像。プログラム内で生成される)
- width: イメージ用画像ファイルの幅(ピクセル値 (例: 300))
-
height: イメージ用画像ファイルの高さ(ピクセル値 (例: 300))
(4.1)メインモジュール
メインモジュール(Kaleidoscope.main)での大きな流れは、以下のとおりです:
(4.1.1) 各種インスタンスの生成(オブジェクト(obj), 像(img), 鏡(mrrs))
(4.1.2) 像(img)の各ドットに対応するオブジェクト(obj)の座標を取得する(シミュレーション本体)。
(4.1.3) 像(img)の色を決める。
(4.1.4) すべてのドットでシミュレーションが終わったら、像をjpegファイルに出力する。
// Usage: java Kaleidoscope object_filename image_filename image_width image_height class Kaleidoscope { public static void main(String[] args){ // オブジェクト画像(input)、イメージ画像(output)の取得 (jpg) String obj_fname = args[0]; String img_fname = args[1]; // イメージ画像のサイズ取得 int img_width = Integer.valueOf(args[2]).intValue(); int img_height = Integer.valueOf(args[3]).intValue();; // (4.1.1) インスタンスの生成 KS_object obj = new KS_object(obj_fname); KS_image img = new KS_image(img_fname, img_width, img_height); mirror_set mrrs = new mirror_set(); double[] pt_img = new double[3]; double[] pt_obj = new double[3]; // シミュレーション // スクリーン上の各点を取得(pt_img) while(img.get_xy(pt_img) == 0) { // (4.1.2) 反復処理(反射)、オブジェクト上の到達点(pt_obj)の取得 mrrs.simulation(pt_img, pt_obj); // (4.1.3) pt_objの色を取得し、対応するスクリーン上の色をセットする img.set_color(obj.get_color(pt_obj)); // スクリーン上の点を再設定 (increment) img.inc_xy(); } // (4.1.4) シミュレーション結果を、イメージ画像として出力 (img_fname) img.write_image(img_fname); } }
(4.2)万華鏡の定義
以下で、(4.1)の各ステップを詳しく解説していきます。
まず、(4.1.1)鏡(mrrs)の生成で、万華鏡の部品配置が決められます(プログラムの詳細は、mirror_set.mirror_set/initを参照)。具体的には、三次元座標(xyz)の中で、各部品が次のように配置されます:
- オブジェクト:xy平面上(z=0)に配置。
- 万華鏡(鏡):xy平面から垂直に(高さ5まで)置かれた三角柱。それぞれの鏡は内側を向いているものとする。
- ピンホール:(x,y,z) = (0,0,5)に配置。
- スクリーン(像):ピンホールから高さ1離れた平面(つまり、z=6で定義される平面)に配置。
(4.3)以降では、スクリーン上の各ドットについて、「初期化」→「反復処理」→「停止条件のチェック」の流れを追っていきます(数学的な表現については、本稿の趣旨とは外れるため、Appendixにまとめました。興味のある方は、こちらも参考にしてください)。