Solver の定義#
順問題を記述する Solver は、入力変数に対して目的関数の値を返す evaluate メソッドを持つクラスとして以下のように定義します。
Solverクラスはodatse.solver.SolverBaseを継承するクラスとします。import odatse class Solver(odatse.solver.SolverBase): pass
コンストラクタ
コンストラクタは
Infoクラスのインスタンスを引数としてとります。def __init__(self, info: odatse.Info): super().__init__(info) ...
必ず
infoを引数として基底クラスのコンストラクタを呼び出してください。 基底クラスのコンストラクタでは、次のインスタンス変数が設定されます。self.root_dirはルートディレクトリです。info.base["root_dir"]から取得され、odatseを実行するディレクトリになります。外部プログラムやデータファイルなどを参照する際に起点として利用できます。self.output_dirは出力ファイルを書き出すディレクトリです。info.base["output_dir"]から取得されます。通例、MPI並列の場合は各ランクからのデータを集約した結果を出力します。self.proc_dirはプロセスごとの作業用ディレクトリです。output_dir / str(odatse.mpi.algrank())が設定されます。 ソルバーのevaluateメソッドはproc_dirをカレントディレクトリとして Runner から呼び出され、MPIプロセスごとの中間結果などを出力します。 MPIを使用しない場合もランク番号を0として扱います。self.work_dirはself.proc_dirの別名です。self.dimensionは入力変数の次元数です。info.solverにdimensionが指定されていればその値、なければinfo.base["dimension"]が設定されます。self.timerは実行時間を記録するための辞書で、"prepare","run","post"のキーを持ちます。self._nameはソルバー名(文字列)です。基底クラスでは空文字列に初期化されるため、コンストラクタで適切な名前を設定してください。nameプロパティを通して参照されます。
Solver 固有のパラメータは
infoのsolverフィールドから取得します。必要な設定を読み取って保存します。evaluateメソッドdef evaluate(self, x, args=()) -> float: pass
入力変数に対して目的関数の値を返すメソッドです。以下の引数を取ります。
x: np.ndarray入力変数を numpy.ndarray 型の \(N\) 次元ベクトルとして受け取ります。
args: Tuple = ()Algorithm から渡される追加の引数で、step数と set番号からなる Tuple です。step数は Monte Carlo のステップ数や、グリッド探索のグリッド点のインデックスです。set番号は n巡目を表します。
evaluateメソッドは、Float 型の目的関数の値を返します。注釈
evaluateがRuntimeErrorを送出した場合、[runner]セクションでignore_error = trueが指定されていると、Runner は例外を無視して目的関数値をnp.nanとして扱います。 また、探索点が制約条件 ([runner.limitation]) を満たさない場合はソルバーは呼び出されず、目的関数値はnp.infになります。注釈
ソルバー並列を使用する場合 (
--nsolveが 2 以上)、evaluateはソルバーグループ内の全 MPI ランクで同一のx,argsを引数として呼び出されます。 ランク間の役割分担はソルバー内で実装してください。詳細は ソルバーの二層 MPI 並列化 を参照してください。