Instance Preparation と PreparationPolicy#
Instance Preparationは、Instanceに既存の変換操作を適用し、targetのInstanceClassに属する表現へ近づける仕組みです。変換先を表すclass、許可する操作を選ぶPolicy、実際に変換するInstance.prepare()を分けて考えます。
要素 |
役割 |
|---|---|
targetのInstanceClass |
満たしたい表現の条件 |
PreparationPolicy |
使ってよい変換操作と設定の選択 |
Instance.prepare |
そのInstanceへ変換を適用し、target membershipを検査する |
classの意味はInstanceClassとAdapterの入力条件、一連の操作例はInstanceを変換するHow-toを参照してください。後半では、この共通の仕組みをAdapterに適用します。
Policyを作ることと、変換することは別#
PreparationPolicyは、変換操作の選択を保持する値です。Policyを作成・編集しただけではInstanceは変わりません。
例えば「ちょうど一つを選ぶ」というOneHotの条件を、通常の等式へ置き換えるPolicyは次のように作ります。特殊制約を通常の制約へ書き換える操作をloweringと呼びます。ここでは変換するinstanceと、変換先のtargetが用意されているとします。
from ommx import (
PreparationPolicy, SpecialConstraintKind, SpecialConstraintPreparation,
)
policy = PreparationPolicy(
special_constraints=SpecialConstraintPreparation.lower_special_constraints(
kinds={SpecialConstraintKind.OneHot}
)
)
instance.prepare(target, policy)
assert target.contains(instance)
prepare()は呼び出したInstanceをin-placeに変更します。変換前のInstance自体を後でも使う必要がある場合だけ、事前にcopyを作ります。候補の評価結果を比較するだけなら、変換前に評価結果を保存しておけば十分です。Instanceとtargetの構築も含む実行例は変換How-toにあります。
Targetに入った時点で止まる#
PreparationはPolicyのすべての操作を必ず最後まで実行する仕組みではありません。実行前と、選択した変換段階(phase)の完了後にInstance全体のmembershipを調べ、targetに入った時点で停止します。最初からmemberならInstanceは変更されません。
成功時に成立する条件は、指定したtargetへのmembershipです。
assert target.contains(instance)
この条件だけでは、元の問題との数学的な等価性や最適性は保証されません。変換元の条件、使う操作、その操作が保存するものを個別に確認します。
変換後の候補は、そのInstanceが保持する変数・制約・目的の情報を使って解釈します。Instanceの変数の役割と変換後の問題とRemoved constraintsを参照してください。
PreparationPolicy が選ぶ phase#
PreparationPolicy の各 field は optional で、未指定の phase は実行されません。デフォルトではすべての phase が無効です。各 field は、Instanceの変換操作のうちどれを呼ぶかを選択します。各操作の入力条件やerrorは、対応するメソッドのAPI Referenceを参照してください。
prepare() は、選択された phase を高々1回ずつ次の固定順序で適用します。
順序 |
Policy field |
役割 |
|---|---|---|
1 |
|
選択した active な特殊制約を通常制約へ lowering |
2 |
|
active objectiveを指定したsenseへ変換 |
3 |
|
active な通常不等式への Integer slack 導入 |
4 |
|
使用中の Integer 変数を Binary 変数で encoding |
5 |
|
active な通常制約を固定 weight の penalty として目的関数へ移動 |
6 |
|
activeなBinary変数の冪を縮約 |
各fieldに設定する型とfactoryの全引数は、SpecialConstraintPreparation、ObjectivePreparation、IntegerSlackPreparation、FixedPenaltyPreparation、IntegerEncodingPreparation、BinaryPowerPreparationのAPI Referenceを参照してください。特殊制約loweringの数式と成立条件も、各変換メソッドのAPI Referenceが所有します。特殊制約そのものの意味は特殊制約型を参照してください。
固定penaltyの大きさのように、問題のscaleや求める解の性質に依存する選択があります。どの変換を許し、どの値を使うかはapplicationが判断します。
Adapterへの適用:推奨Policyと自動Preparation#
Adapterは、直接受け取れるInstanceの集合をINPUT_CLASSとして宣言します。このInstanceClassをtargetとして使うのがAdapter向けのPreparationです。
通常の求解・samplingには、まずsolve()またはsample()を使えます。標準のeasy APIは、入力のcopyを作り、Adapterの推奨Policyでprepareしてから厳格なmethodを呼びます。
# 呼び出し元のinstanceは変更されない。内部のcopyだけがPreparationされる。
result = Adapter.solve(instance)
recommended_preparation_policy()は、Adapterのexact inputへ到達する際に一般的に有用なPolicyを返します。この呼び出しは次の性質を持ちます。
呼び出すたびに、呼び出し側が編集できる新しいPolicyを返す
特定のInstanceを参照または変更せず、Preparationもしない
target membershipへの到達を保証しない
INPUT_CLASSと推奨Policyは独立した値です。固定penaltyの大きさなど、Adapterが安全な値を推奨できないapplication固有の選択がある場合は、自分でPolicyを編集し、明示的な経路を使います。
input_class = Adapter.INPUT_CLASS
policy = Adapter.recommended_preparation_policy()
# 必要なら、application固有の判断でpolicyを編集する。
instance.prepare(input_class, policy)
assert input_class.contains(instance)
result = Adapter.solve_without_preparation(instance)
*_without_preparation()とAdapter constructorはPreparationしません。上の経路では、編集したPolicyを自分で適用してから渡します。一連の実行例はPreparationで変換する制約族を選ぶを参照してください。
AdapterではINPUT_CLASS membershipがapplicabilityです。converterやBackendは、その後のsolver input構築や実行で別のerrorを返すことがあります。それらは追加のapplicability条件ではありません。
Solverの出力をSolutionやSampleSetに戻すときも、Adapterへ渡した同じ変換済みInstanceで評価します。そのInstanceが保持する変数間のdependencyとremoved constraintにより、encoding前の変数値や変換前の制約も評価できます。値の復元はInstanceの基本モデル、制約の評価規則はRemoved constraintsと実行可能性を参照してください。
詳細:到達できない場合と部分的な変更#
すべての configured phase を適用しても target に到達しない場合、PreparationTargetNotReachedError が送出されます。report 属性には、最終状態に対する InstanceClassMembershipReport が入ります。呼び出し側は report を見て Policy を追加・変更するか、異なる target を選べます。
Preparation全体が失敗しても、自動的に変更前の状態へ戻るわけではありません。後のphaseが失敗しても、それより前に完了した変更はInstanceに残ります。通常のsolve()とsample()ではこの変更も内部copyだけに残ります。明示的なprepare()で失敗後も変換前のInstance自体を使う必要がある場合だけ、事前にcopyを作ってください。個々の変換が失敗時にどこまで変更を残すかは、それぞれのAPI Referenceを参照してください。
初めてAdapterを使う場合はTutorialから始め、失敗時の処理が必要になった時点で本節と各変換のAPI Referenceを確認してください。