倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

物理系 & 初期化パラメータ in シミュレーション設計図

前回までで、シミュレーション設計図内で反復条件を設定する仕方を見てきました。 今回は反復条件に替わり、物理系と初期化パラメータの設定の仕方を見ていきます。 前回までと同様、何も観測せず、何も出力しないシミュレーションを考えましょう。

サンプル


シミュレーション設計図の記事で見た例をもう一度見てみましょう(<iteration-condition> 要素は少し修正。 import 文も省略しました。):

public class RandomWalk1D implements PhysicalSystem{
    
    /**
     * この物理系に設定できる初期パラメータの名前。 初期位置。
     */
    public static final String INITIAL_POSITION  = "Initial Position";
    
    // その他の実装は省略
}
<?xml version="1.0" encoding="UTF-8"?>

<simulation-schema xmlns="http://xmlns.org.waman/simulation/0.1">
	
  <system class="RandomWalk1D"/>
	
  <init-params>
    <param name="Initial Position">100</param>
  </init-params>
    
  <iteration>
    <iteration-condition type="count" total="10"/>
  </iteration>
</simulation-schema>

プロパティ


反復条件では、<iteration-condition> 要素に属性をつけて IterationCondition オブジェクトにプロパティを設定できるようにしました。 同様に、<system> 要素にも属性をつけてプロパティを設定できるようにしましょう。 反復条件の時と同様に、class 属性と type 属性はプロパティとして認識されないとします。

初期化パラメータを外部から知る


初期化パラメータの設定は <init-params> 要素の子要素として <param> 要素に

<param name="《初期化パラメータの名前》">《初期化パラメータの値》</param>

という形で設定します。 複数のパラメータを指定する場合は、<init-params> 要素下に複数の <param> 要素を書きます。

ここで、name 属性に指定する初期化パラメータの名前は PhysicalSystem の初期化メソッド initialize() でパラメータの値を取得する際に用いる文字列と一致させなければなりません。 手でシミュレーション設計図を書く人には頑張ってもらうことにして、設計図用のエディタを作る際には、自作の PhysicalSystem のサブクラスから初期化パラメータのエントリを取得できるようにしておいた方が良いでしょう。 インスタンスからではなくクラスからです。

このような文字列リテラルは、上記の RandomWalk1D クラスの例のように "public static final" な String フィールドとして宣言するのが普通かと思います。 しかし、"public static final" な String フィールドというのは必ずしも初期化パラメータのエントリとは限らないので、この区別をどうやってするかが少々問題です。

あまり新たなプログラミング規約を設けるのは気が引けますが、アノテーションを使って区別をすることにしましょう。 まず、以下のように InitParamEntry アノテーションを作成します(実際には PhysicalSystem インターフェースのネストクラスとして定義します):

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface InitParamEntry{
    Class<?> value();
}

value の値は初期化パラメータの型です。 このアノテーションを使って、上記の例を以下のように書き換えます:

public class RandomWalk1D implements PhysicalSystem{
    
    /**
     * この物理系に設定できる初期パラメータの名前。 初期位置。
     */
    @InitParamEntry(Integer.class)
    public static final String INITIAL_POSITION  = "Initial Position";
    
    // その他の実装は省略
}

外部から InitParamEntry アノテーションが指定されている String フィールドを取得するために、ユーティリティ・クラスを作成しておきましょう:

public final class SimulationUtils{

    private SimulationUtils(){}

    public static List<String> getInitParamEntries(
            final Class<? extends PhysicalSystem> targetType){
        // 実装は省略
    }

    public static boolean supportsInitParam(
            final Class<? extends PhysicalSystem> targetType, 
            final String name){
        // 実装は省略
    }

    public static Class<?> getInitParamType(
            final Class<? extends PhysicalSystem> targetType, 
            final String name){
        // 実装は省略
    }
}

てな感じです。

プロパティと初期条件


さて、上では「プロパティ」と「初期化パラメータ」を説明しましたが、プログラミング的にはどちらもフィールドの値を設定するのに用いるので、どういった場合にどちらを使うべきかを考えましょう。 先に行っておきますが、今のところ、どちらかでなければ使えないというものはありません。

プログラミング的な観点
シミュレーション実行中(PhysicalSystem#evolveState() を呼び出したとき)に値が変化するものは初期化パラメータ、そうでないものはプロパティで設定します。
物理的な観点
Hamilton 系での正準変数、Lagrange 系での一般化座標・一般化運動量、量子力学での波動関数などは初期化パラメータ、そうでないものはプロパティで設定します。