# ABS3 Solverの使い方 :::{container} prog-cpp ABS3 Solverを使用して式 `f` を解くには,以下の2つのステップで行います: 1. 式 `f` に対してABS3 Solver(**`qbpp::ABS3Solver`**)オブジェクトを作成します. 2. **`search()`**メンバ関数を呼び出します.パラメータは初期化子リストとして渡します.得られた解が返されます. ## ABS3 SolverによるLABS問題の求解 以下のHi-QUBOプログラムは,ABS3 Solverを使用して**Low Autocorrelation Binary Sequence (LABS)**問題を解きます: ```{literalinclude} /../programFiles/cppPrograms/solver/abs3-solver-usage-program1.cpp :language: cpp :caption: abs3-solver-usage-program1.cpp ``` このプログラムでは,まず式 `f` に対してABS3 Solverオブジェクト**`solver`**を作成します. 次に,**`search()`**メンバ関数にパラメータを初期化子リストとして渡して呼び出します. `time_limit` オプションは最大探索時間を秒単位で指定し,`enable_default_callback` は探索中に新たに見つかった最良解のエネルギーとTTSを出力する組み込みコールバック関数を有効にします. この関数は指定された制限時間内に見つかった最良解を返し,`sol` に格納されます. プログラムは解のエネルギーと対応するバイナリ列を出力します."+"は1を,"-"は0を表します. このプログラムは以下の出力を生成します: ```{include} /../programFiles/markDown/solver/abs3-solver-usage.md :start-after: :end-before: ``` ## ABS3 Solverオブジェクト ABS3 Solver(`qbpp::ABS3Solver`)オブジェクトは与えられた式に対して作成されます. ソルバーオブジェクトが構築されると,式は内部データフォーマットに変換され,GPUメモリにロードされます. オプションの第2引数 `gpu` でGPUの使用を制御します: - **`qbpp::ABS3Solver(expression)`**: 利用可能なすべてのGPUを自動的に使用します.GPUが利用できない場合はCPUのみモードにフォールバックします. - **`qbpp::ABS3Solver(expression, 0)`**: CPUのみモードを強制します(GPUは使用されません). - **`qbpp::ABS3Solver(expression, n)`**: `n` 個のGPUを使用します. 探索パラメータは `search()` に初期化子リストとして直接渡します. 上記の例では: - **`"time_limit", 10.0`**: 制限時間を10.0秒に設定します. - **`"enable_default_callback", 1`**: 新たに得られた解のエネルギーを出力する組み込みコールバック関数を有効にします. ## ABS3パラメータ パラメータは `search()` メソッドに初期化子リストとして直接渡します. 上記のプログラムでは,`"time_limit", 10.0` で制限時間を10.0秒に設定し,`"enable_default_callback", 1` で新たに得られた解のエネルギーを出力する組み込みコールバック関数を有効にしています. ### 基本オプション | キー | 値 | 説明 | |----|----|----| | **`time_limit`** | 制限時間(秒) | 制限時間に達すると探索を終了します | | **`target_energy`** | ターゲットエネルギー値 | ターゲットエネルギーが達成されると探索を終了します | ### 詳細オプション | キー | 値 | 説明 | |----|----|----| | **`enable_default_callback`** | "1" | エネルギーとTTSを出力する組み込みコールバックを有効にします | | **`cpu_enable`** | "0" または "1" | GPUと並行して動作するCPUソルバーの有効/無効(デフォルト: "1") | | **`cpu_thread_count`** | CPUスレッド数 | CPUソルバーのスレッド数(デフォルト: 自動) | | **`block_count`** | GPU当たりのCUDAブロック数 | ソルバーカーネルが起動するCUDAブロック数 | | **`thread_count`** | CUDAブロック当たりのスレッド数 | CUDAブロック当たりのスレッド数 | | **`topk_sols`** | 解の数 | 最良エネルギーのtop-K解を返します | | **`best_energy_sols`** | 最大数("0" = 無制限) | 見つかった最良エネルギーを持つすべての解を返します | | **`seed`** | 乱数シード("0" = 未指定) | 初期解や提案に使う乱数列を固定します(既定は非決定).完全な実行再現は直列構成(例: `cpu_thread_count=1` かつ GPU なし)でのみ保証され,多スレッドや GPU ではタイミングの非決定性が残ります | ## 複数解の収集 ABS3 Solverは探索中に複数の解を収集できます. 2つのモードが利用可能です: ### Top-K解 (`topk_sols`) `topk_sols` パラメータはエネルギーの昇順にソートされたtop-K解を収集します. ```{include} /../programFiles/markDown/solver/abs3-solver-usage.md :start-after: :end-before: ``` ### 最良エネルギー解 (`best_energy_sols`) `best_energy_sols` パラメータは見つかった最良エネルギーを共有するすべての解を収集します. より良いエネルギーが発見されると,プールがクリアされ,新しい最良エネルギーの解のみが保持されます. ```{include} /../programFiles/markDown/solver/abs3-solver-usage.md :start-after: :end-before: ``` または,`best_energy_sols` を最大数付きで設定することもできます: ```{include} /../programFiles/markDown/solver/abs3-solver-usage.md :start-after: :end-before: ``` `topk_sols` と `best_energy_sols` は同じ内部プールを共有することに注意してください. 両方が指定された場合,最後に指定されたものが有効になります. ### 収集された解へのアクセス `search()` メソッドは `ABS3SolverSol` オブジェクトを返し,収集された解へのアクセスを提供します: ```{include} /../programFiles/markDown/solver/abs3-solver-usage.md :start-after: :end-before: ``` `ABS3SolverSol` オブジェクトは以下をサポートします: - **`size()`** — 収集された解の数 - **`sols`** — 解ベクトルへのアクセス - **`operator[](i)`** — i番目の解へのアクセス - 範囲ベースforループによるイテレーション ## カスタムコールバック 組み込みコールバック(`enable_default_callback` で有効化)は,新しい最良解が見つかるたびにエネルギーとTTSを出力するだけです. より細かい制御が必要な場合は,`ABS3Solver` をサブクラス化して `callback()` 仮想メソッドをオーバーライドできます. コールバックは以下のイベントのいずれかで呼び出されます: | イベント | 説明 | |-------|-------------| | `CallbackEvent::Start` | `search()` の開始時に1回呼び出されます | | `CallbackEvent::BestUpdated` | 新しい最良解が見つかるたびに呼び出されます | | `CallbackEvent::Timer` | 設定可能な間隔で定期的に呼び出されます | コールバック内では,以下のメソッドが利用可能です: - **`best_sol()`** — 現在の最良解への `const qbpp::Sol&` を返します.`.energy()`,`.tts()`,`.get(var)` などが使用できます. - **`event()`** — このコールバックをトリガーしたイベントを返します - **`hint(sol)`** — 探索中にソルバーにヒント解を提供します([Solution Hint](#solution-hint)を参照) - **`terminate()`** — 現在の探索を協調的に中断します(下記[探索の中断](#探索の中断)を参照) ### タイマー制御 `Timer` イベントはデフォルトでは有効になっていません. 定期的なタイマーコールバックを有効にするには,`callback()` メソッド内で `timer(seconds)` を呼び出します: - **`timer(1.0)`** — 1秒ごとに `Timer` コールバックを発火します - **`timer(0)`** — タイマーを無効にします - `timer()` が呼ばれない場合,タイマー間隔は変更されません. 通常,`timer()` は `Start` コールバック中に1回呼び出されて間隔を設定します. `BestUpdated` や `Timer` コールバック中にも呼び出して,タイマーを動的に調整または無効にすることができます. ### 例: カスタムコールバック ```{literalinclude} /../programFiles/cppPrograms/solver/abs3-solver-usage-program2.cpp :language: cpp :caption: abs3-solver-usage-program2.cpp ``` ## 探索の中断 `terminate()` を呼び出すと,実行中の `search()` を協調的に中断させ,これまでに発見した最良解を保持したまま即座に return させることができます. 呼び出せる場所: - **`callback()` の内部** — `best_sol().energy()` などを観察して停止を判断 - **別スレッド** — 外部からのキャンセル,シグナルハンドラ,ウォッチドッグなど `terminate()` の利点は,**現在の最良解を見て柔軟に停止条件を組み立てられる** ことです.`target_energy` は事前に閾値を1つ固定する必要がありますが,`terminate()` なら: - 任意の `energy` 条件(例:`energy <= 0`, `energy < prev_best * 0.99`) - 経過時間と組み合わせた条件(例:「5秒以内に改善が無ければ停止」) - 制約違反量と目的関数の重み付け(例:`onehot_violation == 0 && objective <= threshold`) - 外部要因(GUI のキャンセルボタン,別ソルバーの完了通知など) など,**実行時に評価できる任意の条件**で停止を制御できます. 同じインスタンスで再度 `search()` を呼び出すと,停止フラグは自動的にクリアされます. ### 例: energy が 0 になったら停止 `target_energy` を使わず,コールバックで `energy == 0` を観測した瞬間に `terminate()` を呼び出します. ```{literalinclude} /../programFiles/cppPrograms/solver/abs3-solver-usage-program3.cpp :language: cpp :caption: abs3-solver-usage-program3.cpp ``` ## Solution Hint ヒント解を使用すると,以前に見つかった解で探索をウォームスタートできます. 最も簡単な方法は,`search()` の前に**`params.hint(sol)`**を呼び出すことです: ```{include} /../programFiles/markDown/solver/abs3-solver-usage.md :start-after: :end-before: ``` 解は探索開始前にソルバーの内部データ構造に直接書き込まれます. 外部ソルバーを並行して実行するような高度なユースケースでは,コールバック中に**`hint(sol)`**を呼び出して動的に解を供給することもできます. このシナリオでは,コールバックが定期的に呼び出されて新しい外部解をチェックできるように,定期的なタイマー(例:`timer(1.0)`)を設定することを推奨します. ### 例: ヒント解の提供 以下の例は素因数分解問題を2回解きます. 1回目の実行では通常通り最適解を見つけます. 2回目の実行では `params.hint(sol)` を介して最初の解をヒントとして提供し,ソルバーの収束を大幅に高速化します. ```{literalinclude} /../programFiles/cppPrograms/solver/abs3-solver-usage-program4.cpp :language: cpp :caption: abs3-solver-usage-program4.cpp ``` ヒント解は探索開始前にソルバーの内部データ構造に直接書き込まれます. ソルバーはそのエネルギーを評価し,初期状態として使用した上で,より良い解の探索を続けます. ::: :::{container} prog-python ABS3 Solverを使用して式 `f` を解くには,以下の2つのステップで行います: 1. 式 `f` に対して **`ABS3Solver`** オブジェクトを作成する. 2. キーワード引数を指定して **`search()`** メソッドを呼び出し,得られた解を取得する. ## ABS3 Solverを使用したLABS問題の求解 以下のプログラムは,ABS3 Solverを使用して **Low Autocorrelation Binary Sequence (LABS)** 問題を解きます: ```{literalinclude} /../programFiles/pythonPrograms/solver/abs3-solver-usage-program1.py :language: python :caption: abs3-solver-usage-program1.py ``` このプログラムでは,まず式 `f` に対して `ABS3Solver` オブジェクト `solver` を作成します. 次に,`search()` メソッドにパラメータをキーワード引数として渡して呼び出します. `time_limit` は最大探索時間を秒単位で指定し,`enable_default_callback=1` は探索中に新たに見つかった最良解のエネルギーとTTSを出力する組み込みコールバックを有効にします. このメソッドは指定された制限時間内に見つかった最良解を返し,`sol` に格納されます. プログラムは解のエネルギーと対応するバイナリ列を出力します."+"は1を,"-"は0を表します. このプログラムは以下のような出力を生成します: ```{include} /../programFiles/markDown/solver/abs3-solver-usage.md :start-after: :end-before: ``` ## ABS3 Solverオブジェクト `ABS3Solver` オブジェクトは,与えられた式に対して作成されます. コンストラクタは式を内部データフォーマットに変換してホストメモリにロードし,GPUが利用可能な場合はデバイスメモリにも転送します. 以降 `search()` を複数回呼び出してもこのロードは1度きりなので,同じ式に対して繰り返し探索する際のオーバーヘッドがありません. 省略可能な第2引数 `gpu` でGPUの使用を制御します: - **`ABS3Solver(f)`**: 利用可能なすべてのGPUを自動的に使用します.GPUが利用できない場合はCPUのみモードにフォールバックします. - **`ABS3Solver(f, 0)`**: CPUのみモードを強制します(GPUは使用されません). - **`ABS3Solver(f, n)`**: `n` 個のGPUを使用します.式は `n` 個のGPUすべてにロードされます. 探索パラメータは `search()` にキーワード引数として直接渡します. 上記の例では: - **`time_limit=10.0`**: 制限時間を10.0秒に設定します. - **`enable_default_callback=1`**: 新たに得られた解のエネルギーとTTSを出力する組み込みコールバック関数を有効にします. ## ABS3パラメータ パラメータは `search()` メソッドにキーワード引数として直接渡します. 上記のプログラムでは,`time_limit=10.0` で制限時間を10.0秒に設定し,`enable_default_callback=1` で新たに得られた解のエネルギーを出力する組み込みコールバック関数を有効にしています. 戻り値は解で,`sol.energy`(エネルギー値),`sol(x)`(変数値の取得),`sol.info`(ソルバー情報の辞書)などを提供します.詳細は [QR_SOLUTION](../quickReference/qr-solution.md) を参照してください. ### 基本オプション | キー | 型 | 説明 | |----|----|----| | **`time_limit`** | float | 制限時間(秒).制限時間に達すると探索を終了します | | **`target_energy`** | int | ターゲットエネルギーが達成されると探索を終了します | ### 詳細オプション | キー | 型 | 説明 | |----|----|----| | **`enable_default_callback`** | int (0 または 1) | エネルギーとTTSを出力する組み込みコールバックを有効にします | | **`cpu_enable`** | int (0 または 1) | GPUと並行して動作するCPUソルバーの有効/無効(デフォルト: 1) | | **`cpu_thread_count`** | int | CPUソルバーのスレッド数(デフォルト: 自動) | | **`block_count`** | int | GPU当たりのCUDAブロック数 | | **`thread_count`** | int | CUDAブロック当たりのスレッド数 | | **`topk_sols`** | int | 最良エネルギーのtop-K解を返します | | **`best_energy_sols`** | int | 最大数(`0` = 無制限).見つかった最良エネルギーを持つすべての解を返します | | **`seed`** | int | 乱数シード(`0` = 未指定,既定は非決定).初期解や提案に使う乱数列を固定します.注: 完全な実行再現は直列構成(例: `cpu_thread_count=1` かつ GPU なし)でのみ保証されます — 多スレッドや GPU ではタイミングの非決定性が残ります | ## 複数解の収集 ABS3 Solverは探索中に複数の解を収集できます. 2つのモードが利用可能です: ### Top-K解 (`topk_sols`) `topk_sols` パラメータはエネルギーの昇順にソートされたtop-K解を収集します. ```{include} /../programFiles/markDown/solver/abs3-solver-usage.md :start-after: :end-before: ``` ### 最良エネルギー解 (`best_energy_sols`) `best_energy_sols` パラメータは見つかった最良エネルギーを共有するすべての解を収集します. より良いエネルギーが発見されると,プールがクリアされ,新しい最良エネルギーの解のみが保持されます. ```{include} /../programFiles/markDown/solver/abs3-solver-usage.md :start-after: :end-before: ``` または,`best_energy_sols` を最大数付きで設定することもできます: ```{include} /../programFiles/markDown/solver/abs3-solver-usage.md :start-after: :end-before: ``` `topk_sols` と `best_energy_sols` は同じ内部プールを共有することに注意してください. 両方が指定された場合,最後に指定されたものが有効になります. ### 収集された解へのアクセス `search()` の戻り値は解で,`sol.sols` プロパティを介して収集された解のリストにアクセスできます: ```{include} /../programFiles/markDown/solver/abs3-solver-usage.md :start-after: :end-before: ``` 戻り値オブジェクトは以下をサポートします: - **`sol.energy`** — 最良解のエネルギー - **`sol.tts`** — 最良解が見つかるまでの時間(秒) - **`sol.sols`** — 収集された解のリスト(エネルギーの昇順) - **`sol.sols[i]`** — i番目の解へのアクセス - **`len(sol.sols)`** — 収集された解の数 - **`sol.info`** — ソルバー情報の辞書 ## カスタムコールバック 組み込みコールバック(`enable_default_callback=1` で有効化)は,新しい最良解が見つかるたびにエネルギーとTTSを出力するだけです. より細かい制御が必要な場合は,**`ABS3Solver` をサブクラス化**して `callback()` メソッド(引数なし)をオーバーライドします. コールバックは以下のイベントのいずれかで呼び出されます: | イベント値 | 名前 | 説明 | |:-:|----|----| | `0` | `Start` | `search()` の開始時に1回呼び出されます | | `1` | `BestUpdated` | 新しい最良解が見つかるたびに呼び出されます | | `2` | `Timer` | 設定可能な間隔で定期的に呼び出されます | `callback()` 内では,以下のメソッドが利用可能です: - **`self.event()`** — コールバックを発火したイベント.`EVENT_*` 定数(`EVENT_START`=0, `EVENT_BEST_UPDATED`=1, `EVENT_TIMER`=2)と比較できる整数を返します.これらの定数と比較してください(例: `if self.event() == self.EVENT_BEST_UPDATED:`) - **`self.best_sol()`** — 現在の最良解を返します.`.energy`, `.tts`, `.get(var)` などが使用できます - **`self.timer(seconds)`** — 定期的な `Timer` コールバックの間隔を秒単位で設定.`0` でタイマーを無効化(下記参照) - **`self.hint(sol)`** — 探索中にソルバーにヒント解を提供([Solution Hint](#solution-hint) を参照) - **`self.terminate()`** — 現在の探索を協調的に中断します(下記[探索の中断](#探索の中断)を参照) ### タイマー制御 `Timer` イベントはデフォルトでは有効になっていません. 定期的なタイマーコールバックを有効にするには,`callback()` メソッド内で `self.timer(seconds)` を呼び出します: - **`self.timer(1.0)`** — 1秒ごとに `Timer` コールバックを発火します - **`self.timer(0)`** — タイマーを無効にします - `self.timer()` が呼ばれない場合,タイマー間隔は変更されません 通常,`self.timer()` は `Start` コールバック中に1回呼び出されて間隔を設定します. `BestUpdated` や `Timer` コールバック中にも呼び出して,タイマーを動的に調整または無効にすることができます. ### 例: カスタムコールバック ```{literalinclude} /../programFiles/pythonPrograms/solver/abs3-solver-usage-program2.py :language: python :caption: abs3-solver-usage-program2.py ``` ## 探索の中断 `self.terminate()` を呼び出すと,実行中の `search()` を協調的に中断させ,これまでに発見した最良解を保持したまま即座に return させることができます. 呼び出せる場所: - **`callback()` の内部** — `self.best_sol().energy` などを観察して停止を判断 - **別スレッド** — 外部からのキャンセル,シグナルハンドラ,ウォッチドッグなど `terminate()` の利点は,**現在の最良解を見て柔軟に停止条件を組み立てられる** ことです.`target_energy` は事前に閾値を1つ固定する必要がありますが,`terminate()` なら: - 任意の `energy` 条件(例: `energy <= 0`,`energy < prev_best * 0.99`) - 経過時間と組み合わせた条件(例:「5秒以内に改善が無ければ停止」) - 制約違反量と目的関数の重み付け(例: `onehot_violation == 0 and objective <= threshold`) - 外部要因(GUI のキャンセルボタン,別ソルバーの完了通知など) など,**実行時に評価できる任意の条件**で停止を制御できます. 同じインスタンスで再度 `search()` を呼び出すと,停止フラグは自動的にクリアされます. ### 例: energy が 0 になったら停止 `target_energy` を使わず,コールバックで `energy == 0` を観測した瞬間に `self.terminate()` を呼び出します. ```{literalinclude} /../programFiles/pythonPrograms/solver/abs3-solver-usage-program3.py :language: python :caption: abs3-solver-usage-program3.py ``` ## Solution Hint ヒント解を使用すると,以前に見つかった解で探索をウォームスタートできます. 最も簡単な方法は,`search()` の前に `solver.hint(sol)` を呼び出すことです: ```{include} /../programFiles/markDown/solver/abs3-solver-usage.md :start-after: :end-before: ``` 解は探索開始前にソルバーの内部データ構造に直接書き込まれます. 外部ソルバーを並行して実行するような高度なユースケースでは,コールバック内で `self.hint(sol)` を呼び出して動的に解を供給することもできます. このシナリオでは,コールバックが定期的に呼び出されて新しい外部解をチェックできるように,定期的なタイマー(例: `self.timer(1.0)`)を設定することを推奨します. ### 例: ヒント解の提供 以下の例は素因数分解問題を2回解きます. 1回目の実行では通常通り最適解を見つけます. 2回目の実行では `solver.hint(sol1)` を介して最初の解をヒントとして提供し,ソルバーの収束を大幅に高速化します. ```{literalinclude} /../programFiles/pythonPrograms/solver/abs3-solver-usage-program4.py :language: python :caption: abs3-solver-usage-program4.py ``` ヒント解は探索開始前にソルバーの内部データ構造に直接書き込まれます. ソルバーはそのエネルギーを評価し,初期状態として使用した上で,より良い解の探索を続けます. :::