Kaiwu モデリングと求解
まず、ターゲットインタプリタ、ディストリビューション、バージョンを確認します。問題が既に与えられており、ライセンスがインストールされている場合は、そのまま使用し、再インストールや質問は行いません。
インストールされていない場合は、ターゲット環境で python -m pip install kaiwu(Enterprise)または
python -m pip install kaiwu-community(モデリングのみ)を使用します。どちらもインポート名は kaiwu です。
ローカルEnterprise求解には既存のライセンスが必要です。クラウドCIMは、ユーザーが要求し、資格情報を提供した場合にのみ使用します。
このスキルを介して実機を呼び出す場合、task_name は kaiwu_skill で始まる必要があります(例:kaiwu_skill_tsp)。
最初にモデルの等価性を保証する
元のビジネス目標、実行可能領域、求解エネルギーを区別します。変数、目的、すべての制約を簡潔な式で説明し、コードは同じモデルを表現する必要があります。 元の目的が最大化の場合は、負を取ってQUBOを構築しますが、報告値は元の目的に従って計算します。 問題ファミリの識別と変種のモデリングは、必要に応じて 問題カタログ を参照してください。
| 元の要件 | 二次エンコーディング;P は正のハード制約ペナルティ係数 |
|---|---|
| 正確に1つ/等式 | P * (sum(x) - c)**2 |
| 最大1つ | P * sum(x[i]*x[j] for i<j) |
| aを選べばbを選ぶ/同時選択・同時非選択 | P*a*(1-b) / P*(a-b)**2 |
| 2リテラルのOR:少なくとも1つが真 | P * (1-a)*(1-b);(a+b-1)**2 ではない |
| 重み付きソフトOR | 違反指示子に重みを乗算;単一リテラルは 1-a、2リテラルは (1-a)*(1-b) |
整数リソース上限 load <= C | P*(load+s-C)**2、非負整数緩和変数 s は 0..C をカバー |
| 少なくとも1つ(多変数) | P*(sum(x)-1-s)**2、s は 0..n-1 をカバー |
ブール正リテラルの真理値は x、否定リテラルは 1-x です。ORの違反指示子は、すべてのリテラルが偽の場合にのみ1になります。
1-sum(literals)(負になる可能性がある)や sum(1-literals)**2(選好を変える)は使用できません。
3つ以上のリテラルの積は高次項であり、直接二次モデルとして扱えません。適切な補助変数と等価な次数削減が必要です。
緩和変数は直接 Integer('slack', min_value=0, max_value=C) を使用するか、バイナリ重みエンコーディングを使用できます。
例えば上限 C=5 の場合、重み [1,2,2] で 0..5 を正確に表現できます。C=0 の場合は緩和ビットを作成しません。
一般的に C>0 の場合は k=C.bit_length()-1 を取り、重みは [2**j for j in range(k)] + [C-(2**k-1)] とします。
容量に余裕を持たせることができるため、(load-C)**2 を上限制約として使用してはいけません。
ペナルティ係数は、元の目的が改善される可能性のある範囲をカバーする必要があります。ハードペナルティ項の最小非ゼロ値が1の場合、Pは元の目的の上限と下限の差よりも大きい値を取ります。
重み付きソフトルールの場合は、重みの総和より大きい値を取ることができます。非負の割り当てコストの場合は、各コストの上限の合計より大きい値を取ることができます。
係数が大きすぎるとダイナミックレンジが拡大し、サンプリングが困難になります。根拠を明示する必要があり、Pを無限に大きくすることで誤ったモデルを修正しようとしてはなりません。
証明可能な局所的な修正限界が存在する場合は、より厳しい限界を優先的に使用します。例えば、非負重み付き頂点カバーの場合、目的は
sum(w[i]*x[i])、ペナルティ項は P*sum((1-x[u])*(1-x[v])) です。P>max(w) とすることで対応できます。
重みが非負整数の場合、デフォルトで P=max(w)+1 を直接使用し、感覚的にペナルティ係数を大きくすることはしません。
なぜなら、どの未カバー辺も1つの端点を追加することでカバーでき、目的の増加は max(w) を超えず、ペナルティ項は少なくともP減少し、新たな違反も発生しないからです。
これはこの単調なカバー制約にのみ適用され、容量制約、排他制約、等式制約には適用できません。修正が他の制約を破らないことを説明する必要があります。
Enterprise 1.4.0:このAPIフローを直接採用する
以下は実行可能な3つの選択肢の例で、SDKの呼び出しとデコードのみを示しています。実際の問題を処理するには、ターゲット、ペナルティ項、および元のビジネス検証を置き換えてください。
kaiwu.seed、QuboModel.add_variable、vartype、iterations_per_temperature などのインターフェースを発明しないでください。
import numpy as np
from kaiwu.core import (ndarray, Binary, QuboModel, PenaltyMethodConstraint,
qubo_matrix_to_ising_matrix, qubo_model_to_ising_model,
get_sol_dict, get_val)
from kaiwu.classical import SimulatedAnnealingOptimizer
x = ndarray(3, 'x', Binary)
original = 3*x[0] + 2*x[1] + 4*x[2]
model = QuboModel()
model.set_objective(original + 10*(x.sum()-1)**2)
model.set_constraint_handler(PenaltyMethodConstraint) # クラスを渡し、インスタンス化しない
q = model.get_matrix()
h, offset = qubo_matrix_to_ising_matrix(q) # offset は定数であり、変数辞書ではない
variables = qubo_model_to_ising_model(model).get_variables()
solver = SimulatedAnnealingOptimizer(
initial_temperature=100, alpha=0.99, cutoff_temperature=0.001,
iterations_per_t=100, size_limit=32, rand_seed=20261001)
pool = np.asarray(solver.solve(h))
valid = []
for row in pool:
sol = get_sol_dict(row[:-1]*row[-1], variables)
bits = [int(round(get_val(x[i], sol))) for i in range(3)]
if sum(bits) == 1: # 実際の問題では、ここで全ての元のビジネス制約を再計算する必要がある
valid.append((int(round(get_val(original, sol))), bits))
if not valid:
raise RuntimeError('SDKの候補に実行可能解がありません')
cost, decision = min(valid)
print({'bits': decision, 'objective': cost, 'feasible': True})
確認済みのSAパラメータ:initial_temperature, alpha, cutoff_temperature, iterations_per_t, size_limit, flag_evolution_history, verbose, rand_seed, process_num。
seed、time_limit、num_reads を渡さないでください。実行時間の制御は外側でバッチを管理する必要があり、パラメータを偽造して構築してはいけません。
例のbitsはバイナリ決定であり、すべてのタスクのsolutionフィールドと等しいわけではありません。
出力フィールドと番号規則は現在のタスクに従います。JSONが要求された場合は json.dumps を使用し、例の出力方法をそのままコピーしないでください。
中小規模の制約付き問題では、iterations_per_t を増やすか、異なる rand_seed を持つ複数のバッチのSDK候補を使用できます。
同時に実際の所要時間を記録し、ユーザーの時間制限を遵守します。例のパラメータは出発点であり、各問題で最適解が得られるとは限りません。
ペナルティ係数によりIsing行列の振幅が例の温度よりはるかに大きい場合、初期温度100では探索が不十分になる可能性があります。
タスクのパラメータが固定されていない場合は、最初に initial_temperature=max(100, 2*np.max(np.abs(h))) を取ることができます。
数十変数のローカル制約付き問題では、iterations_per_t=200, size_limit=128 を出発点として使用し、
その後、実際の候補品質と時間制限に基づいて判断します。小さな例の温度と解プールサイズをそのままコピーして、最適解を保証すると主張しないでください。
100変数以上で、サンプリングパラメータが固定されていない最適化の納品の場合、小さな例の低サンプリング構成を実行しただけで終了してはいけません。
例えば、品質を目標とし、実行予算が約40秒の場合、128~512変数で結合が疎(非ゼロ比率が10%未満)のデフォルトバッチは
iterations_per_t=(200,800,2400)、size_limit=128 です。他のパラメータは一貫して保持し、常に指定されたシードを使用し、
元の行列は一度だけコンパイルします。変数がさらに多い、行列が密、または予算が短い場合は、(200,400,800) などの小さいバッチから実際にテストを開始します。
各バッチ後、実際の所要時間と次のバッチの反復数の比率に基づいてオーバーヘッドを見積もり、少なくとも20%の余裕と2秒のデコード出力時間を残します。
次のバッチが残り時間内に完了できると予測される場合は、デフォルトのバッチを続行します。続行するかどうかは、以下の候補品質と時間制限の判断に従います。
時間超過が予測される場合は、直ちにこれまでに見つかった最良の実行可能候補を返し、固定バッチ数を完了するために時間超過しないようにします。プログラム全体で統一された1つの締切時間のみを保持します。
ユーザーの実行制限時間内に、実際に返されたすべての候補に対して元のビジネス目標を再計算し、コストが最も低い実行可能候補を保持します。
これはプログラム内で予算化された求解戦略です。最初に見つかった実行可能候補を最良の結果として扱わないでください。
ソフトな選好はハード制約ではありません。ハード制約がない場合は、人為的に大きなペナルティ係数を導入したり、問題で要求されていないバランス制限を追加したりしないでください。
規模と複雑さに応じてデフォルトパラメータを調整します。 上記の数値は経験的な出発点であり、すべての問題に適用できる固定のレシピではありません。 まず、変数の数、非ゼロ結合の数、係数の範囲、ハード制約の強さを確認し、実行時間制限と組み合わせて各バッチの規模を計画します。 密な行列や多くの補助変数は、求解ごとのオーバーヘッドを増加させます。まず小さいバッチで実際にテストし、コンパイル、デコード、出力時間を確保します。 反復を増やしたり、冷却を遅くしたり、解プールを拡大しても、より良いビジネス結果が保証されるわけではありません。これまでに保持した最良のSDK実行可能候補を累積的に保持し、 候補の実行可能比率、元のビジネスコスト、実際の所要時間を比較して継続するかどうかを決定し、より良い古い候補を上書きしないでください。 まず、誤ったモデリングや大きすぎるペナルティ係数を修正し、その後パラメータを調整します。使用したパラメータと停止条件を記録し、最適解を保証すると主張しないでください。
まず、タスクで指定された実験パラメータに従います。 問題で乱数シードが固定されている場合は、ソルバーを作成するたびに同じ指定された rand_seed を明示的に使用し、
シードをインクリメントしたり、別のシードリストを作成したり、時間を使用してシードを生成したりしないでください。上記の複数シードの提案は、タスクで許可されている場合にのみ使用します。
固定シードの下では、問題で許可されている場合にのみ、温度や反復数などのパラメータを調整します。実際の構成を記録します。
solve はエネルギーでソートされていないスピンプールを返し、最後の列は参照スピンです。各行を反復処理し、まず参照スピンを乗算して正規化し、
次にIsingモデルの変数辞書を使用してデコードします。get_val を使用して変数にアクセスし、内部の文字列キーを推測しないでください。
実際の候補をデコードし、元の問題の検証を通過した決定のみを出力できます。総当たり、ハードコードされた答え、またはサードパーティのソルバーをSDKの代わりに使用してはいけません。
自分で目的に追加したペナルティ項は、登録された制約と等価ではありません。add_constraint がない場合、
verify_constraint が0を返しても、元の問題の実行可能性を証明できません。登録の有無にかかわらず、すべてのビジネス制約を決定から再計算します。
verify_constraint を呼び出す場合は、まず unsatisfied, details = model.verify_constraint(sol) をアンパックします。
ビジネスコストとQUBO/Isingエネルギーは別々に印刷し、ペナルティ項、定数オフセット、最大化の負号をビジネス指標として使用してはいけません。
係数を引き継ぐ場合は、変数の順序、定数、線形項、二次項、補助変数のマッピングを保存します。Pは実際に係数に乗算され、各項の貢献は累積されます。
SDK行列の順序は、必ずしも配列作成の順序と同じではありません。コンバータのオフセットには、式のコンパイル時に除去されたビジネス定数は含まれず、両者は別々に保存します。
同じ状態のコストは w*(1-x[i]-x[j]+2*x[i]*x[j])、異なる状態のコストは w*(x[i]+x[j]-2*x[i]*x[j]) であり、
00、01、10、11で方向を確認し、同一チャネル干渉と最大カット目標を混同しないようにします。
重み付きソフトルールの報告方法は問題に従います。「違反コストの最小化」が要求された場合は、
sum(weight for rule in soft if not satisfied(rule)) を報告し、この値が最小の合法な方案を候補として選択します。
「充足された重みの和」と「違反コスト」は合計するとソフト重みの総和に等しく、両者の最適化方向は逆であり、フィールド名 objective を混同してはいけません。
出力前に、最終的なbitsに基づいて元の目標を再計算します。決定が同じであっても、反対の口径の数値を報告することは納品エラーになります。
バージョンとトピック別資料:関連部分のみを読む
| API | Enterprise 1.3.1 | Enterprise 1.4.0 |
|---|---|---|
| QuboModel | kaiwu.qubo | kaiwu.core |
| 2つのQUBO/Isingコンバータ | kaiwu.conversion | kaiwu.core |
| ndarray/Binary/Integer/quicksum/get_val/get_sol_dict/PenaltyMethodConstraint | kaiwu.core | kaiwu.core |
| 配列の値取得 | 要素ごとに get_val または get_array_val | get_val は配列をサポート。get_array_val はなし |
| PrecisionReducer | kaiwu.cim | kaiwu.preprocess |
| ペナルティ関数法ソルバー | kaiwu.solver.PenaltyMethodSolver | kaiwu.hybrid.PenaltyMethodOptimizer |
バージョンが既知の場合は、対応するモジュールを直接インポートします。明示的にクロスバージョンが要求されている場合、または確認できない場合にのみ、実際に移行するインポートに対して互換性のある分岐を作成します。
quicksum はバージョン間でリストを渡します。ndarray((n,m), 'x', Binary) は位置引数を使用します。
Community はローカルな古典ソルバーがあると仮定できません。
- 1.3.x またはより完全なシグネチャ:Enterprise API、API概要。
- 1.3.x TSP 履歴例:SDKサンプル。1.4.x に移行する場合は、上記の表に従ってインポートを変更する必要があります。
- 精度処理:
PrecisionReducerはオプティマイザデコレータであり、バージョン間でデフォルト値が変わります。only_feasible_solutionを明示的に記述します。perform_precision_adaption_splitは(split_matrix, last_var_idx)を返し、マッピングに従って復元し、元の行列のエネルギーを検証します。 - 実機接続:フロー補足。タスクで実機が要求された場合のみ読み取ります。
- その他のインターフェース:モジュール索引、Community。
- 連続量と離散決定の両方を含む場合:最初に完全な結合制約を記述します。Kaiwu が離散候補を求め、離散量を固定した後、連続/フローサブ問題で判断します。 大量の連続量をまとめてバイナリ展開したり、「有効でない場合はフローがゼロ」などの結合制約を削除したりしないでください。
納品と検証
ゼロから生成する場合は完全なスクリプトを提供します。既存のコードを変更する場合は、必要な変更のみを提供します。問題のデータ、出力プロトコル、時間制限を遵守し、コードの完全性を最優先します。 実行条件が許せば、まずインポートを確認し、次に実際にコンパイル、求解、デコード、元のビジネスの検証を行います。タスクで実行が禁止されている場合は、実行したと主張しないでください。
数学的な自己チェックでは、以下の2点に注意します。すべての合法なビジネス状態に対して、ハードペナルティ項をゼロにする補助変数を取れるかどうか。その場合、エネルギーは元の目的に定数を加えたものと等しいかどうか。 独立した開発検証では、真理値表や小さなインスタンスの総当たりを使用してエンコーディングエラーをチェックできますが、その列挙結果をSDKの戻り値と混同してはいけません。 参照限界や独立した証明が得られた場合のみ、最適解を主張します。それ以外の場合は、見つかった実行可能解、実際の目標値、および最適性が証明されていないという制限を報告します。
補足:コード納品規範
以下のルールは、新規および変更されたSDKコードに適用されます。上記のモデリングとバージョン要件は保持されます。
- 単一責任を維持します。 モデリング、SDK求解、候補デコード、元のビジネス検証をそれぞれ明確なステップに整理します。規模が小さい場合は、1つのスクリプトと少数の関数で十分です。SDKを1回呼び出すために、汎用フレームワーク、プラグイン登録、多層継承、または多数の転送ラッパーを導入しないでください。今回の変更で生じたデッドコード、重複ブランチ、未使用の依存関係は削除します。
- 確認済みのインターフェースを使用します。 SDKバージョンが既知の場合は、対応するAPIを直接インポートし、パッケージ全体をスキャンしたり、推測したクラス名やパラメータを順番に試したりしないでください。既存の複数のバージョンとの互換性が本当に必要な場合のみ、実際に移行するインターフェースの周りに狭いブランチを記述し、ビジネスエラーをバージョン互換性の問題として偽装しないでください。
- 例外には明確な処理結果が必要です。 入力、認可、外部呼び出しなど、実際の境界でのみ、処理可能な具体的な例外をキャッチします。復元不可能な場合は、理由を保持して失敗終了します。
except Exception: pass、複数回の重複キャッチ、無限リトライ、およびエラー後に偽の実行可能解や「成功」デフォルト値を返すことは禁止です。固定された内部計算には、意味のないtry/exceptを追加しないでください。 - 実際の境界に従って検証します。 外部データには、必要な次元、値の範囲、制約の一貫性をチェックします。内部で既に検証されたデータは、層を重ねて繰り返しチェックせず、ローカルな小さなスクリプトにタスクと無関係なセキュリティフレームワークを追加しないでください。鍵は既存の環境または設定から読み取り、ハードコードしたり、ログに書き込んだりしないでください。データ解析に
eval、exec、またはシェルコマンドの連結を使用しないでください。インストール、ネットワーキング、クラウド送信は、現在のタスクの認可範囲に従います。 - 求解オーバーヘッドを制御可能にします。 変数の規模と時間制限に応じて、温度減衰、温度あたりの反復数、解プールサイズを設定し、最初から極端に大きなパラメータを設定しないでください。外側で締切時間をチェックしても、一度ブロックされた
solveを中断できないため、単一バッチも十分に小さくなければなりません。単調クロックを使用してバッチを管理し、実際の所要時間を記録します。呼び出し、時間、またはコストの上限に達したら停止し、繰り返しの再接続で遅延させないでください。 - 無効な計算を減らします。 不変の行列、データ、変数マッピングを再利用します。候補はバッチごとにデコードおよびフィルタリングし、重複解を無制限に蓄積したり、巨大な中間配列で明確な計算を置き換えたりしないでください。速度を追求するために、実際の制約を削除したり、元の目的を変更したり、SDK以外の答えで求解結果を置き換えたりしてはいけません。
- インデックスと単位を明確にします。 入力番号と配列添え字は、エントリポイントで統一して変換します。正負のリテラルは
idx = abs(literal) - 1で位置を特定し、反転するかどうかを決定します。ビジネス目標、ペナルティ項、エネルギーオフセットを区別し、意味を説明できる変数名を使用し、複数の関数でそれぞれ矛盾する換算を記述しないでください。 - 正当性を説明できる検証のみを行います。 代表的な実行可能/実行不可能な境界、元のビジネス目標、実際のSDK候補の出所をチェックします。実装テキストにのみ一致するテストを証明として扱わないでください。完全で実行可能な必要なコードを納品し、実際に何を検証したかを明確にします。実行できない場合は直接説明し、実行記録を偽造しないでください。