OptimizationState#
OptimizationStateは、Optimizerの実行コンテキストとチェックポイントを保持する値です。Stage互換経路では、Stageがこの状態を直接受け取り、replace()で更新したコピーを次のStageへ渡します。
構造化ランタイムでは、グラフネイティブコンポーネントがOptimizationState全体を受け取ることはありません。コンポーネントは宣言したStateKeyに限定されたStateViewを受け取り、変更をStatePatchとして返します。ランタイムはそのパッチをStateStoreへ適用し、次の実行境界を生成します。
OptimizationStateの役割#
OptimizationStateは、Stage互換経路が実行に使う値、利用者が確認する結果、再開に必要な値の3つをまとめます。コンポーネント契約、グラフ構造、コンパイラの規則を保持する場所ではありません。状態の所有者は、Stage互換経路ではOptimizerと状態自体、graph-native経路ではStateStoreです。
OptimizationStateはreplace()で新しい値を生成し、StateStoreはStatePatchを適用して新しい世代を生成します。コンポーネントがStateStoreやOptimizationStateを直接変更できると、コンパイラもランタイムも、契約外で行われた書き込みを追跡したり、もはや一致しない再開地点を検出したりできません。
二つの状態境界#
OptimizationState と StateView は、異なる実行境界を表します。
境界 |
受け取る値 |
返す値 |
主な利用者 |
|---|---|---|---|
Stage互換境界 |
|
|
既存Stage、sequential compatibility ランタイム |
graph-native境界 |
宣言済みの |
|
Component、Compiler、構造化ランタイム |
この二つの境界を混同すると、グラフネイティブコンポーネントが任意の状態を読み書きできるように見えます。構造化パイプラインでは、ComponentContractが読み書きするStateKeyを宣言し、ランタイムはその範囲だけをコンポーネントへ渡します。
OptimizationStateが保持する値#
OptimizationState は、利用者が結果を確認したり、実行を再開したりするための値を保持します。
値 |
内容 |
|---|---|
|
最適化対象の |
|
現在の |
|
評価済み解の |
|
非劣解集合への互換性用ショートカット |
|
乱数生成器 |
|
真の評価回数 |
|
世代数 |
|
Stage互換拡張用の追加データ |
population、archive、pareto_archiveは、内部で名前付きのコレクションを参照します。新しいグラフネイティブコンポーネントが任意の値をdataへ入れる設計にはせず、代わりにStateContractでStateKeyを宣言します。
StateStore、StateView、StatePatch#
StateStoreは、型付きのStateKeyを値に対応付ける状態ストアです。コンポーネントに渡されるStateViewは、ComponentContractが宣言した読み取りキーだけを公開します。
Componentが状態を変更するときは、直接Storeを変更せずに StatePatch を返します。 RuntimeはPatchを現在のStoreへ適用し、次の状態を生成します。 この方式によって、Componentが宣言していないStateを偶然に読み書きすることを防ぎます。
コンパイラは、StateContractのreads、writes、exportsがStateBindingと対応していることを確認します。ランタイムはStateViewを宣言済みの読み取りキーに限定し、StatePatchの書き込みをストアの型付きキーと世代へ適用します。同じキーで競合するパッチや、存在しないキーを削除するパッチは、ランタイムの診断規則に従って扱います。
from saealib.core import StatePatch, StateView
from saealib.core import RUNTIME_GENERATION
def execute(view: StateView) -> StatePatch:
current = view.get(RUNTIME_GENERATION)
return StatePatch(writes={RUNTIME_GENERATION: current + 1})
実際のStateKeyは文字列ではなく、saealib.core.stateが提供する型付きキーです。上のコードは、ビューから読み取り、パッチを返す境界だけを示すよう簡略化しています。
Stage互換経路での更新#
カスタムStageはOptimizationStateを受け取り、state.replace(...)で更新後の状態を返します。
from saealib import Stage
class LogGenerationStage(Stage):
name = "log_generation"
def execute(self, state):
print(state.gen)
return state
Stage互換経路で追加の値を持たせる場合は、state.dataをコピーしてからreplace()に渡します。グラフネイティブコンポーネントで同じ値を扱う場合は、StateKeyとStatePatchを使います。
更新とチェックポイント#
replace(**kwargs) -> OptimizationState は、Stage互換経路で値を更新するためのメソッドです。 archive は評価結果を蓄積するために変更され、rng は乱数を生成するたびに内部状態が進みます。 これらは、他の値を replace() で渡す設計と異なる、明示された例外です。
save(path)とload(path, problem)はOptimizationStateのnpzチェックポイントを扱います。自動チェックポイントについてはCheckpointingを参照してください。pickle形式ではOptimizer側の状態も必要なため、どの保存経路を使うかはCheckpointCallbackとOptimizerの組み合わせで決まります。
どの状態境界を使うか#
既存のStageを実装する:
OptimizationStateとreplace()を使う。新しいグラフネイティブComponentを実装する:
ComponentContract、StateView、StatePatchを使う。Optimizerの実行結果を確認する:
Optimizer.run()またはOptimizer.iterate()が返すOptimizationStateを使う。実行を再開する:
saealib.context.OptimizationState.load()とOptimizer.run_from()を使う。
代表的な失敗#
Stage互換経路で誤った対象にreplace()を呼ぶと、次のStageが期待する値を受け取れません。graph-native経路でStateContractにないキーを読み取り、書き込み、または公開すると、コンパイラの状態効果検証で診断になります。別のProblemや互換性のない計画にチェックポイントを適用すると、保存された状態と実行境界がずれます。
関連コンポーネント#
Stage:
OptimizationStateを直接受け取る互換性用の実行単位Framework:Component、Contract、Graph、Compilerの関係
Runtime:計画、ランタイム、
StatePatchが適用される境界Population:
Population、Archive、ParetoArchiveのデータ構造Checkpointing:チェックポイントの保存と再開
参照#
saealib.context.OptimizationStateFramework ComponentContract:状態宣言を含む契約
Framework Compiler:状態効果の検証と診断