# 整数変数と制約に関する演算と関数 :::{container} prog-cpp `qbpp::Expr` は通常の式・整数変数・制約式を **統一的に表現する型** です.3 つとも同じ型で,持つメタデータが違うだけです. `Expr` は 3 つの「顔」を持ちます: - **通常の式** (多項式): `x + 2*y*z` などの算術式 - **整数変数**: `l <= qbpp::var_int("x") <= u` などで作った `Expr`.範囲・ビット分解のメタデータを保持 - **制約式**: `e == 5` / `lo <= e <= hi` などで作った `Expr`.penalty + body のメタデータを保持 > **基本原則** > - `qbpp::Expr` の演算・関数はすべて,どの「顔」の Expr にも適用できる > - **固有 accessor** (`min_val()`, `body` 等) は対応する「顔」の Expr でのみ有効.合わない Expr で呼ぶと **runtime abort**(エラーメッセージ付き) > - **式を変更するメンバ関数** (`+=`, `-=`, `*=`, `/=`, `sqr()`, `replace()`) を呼ぶと,内部表現は通常の式に戻る(固有メタデータは破棄され,固有 accessor は以後呼べなくなる) > - **例外: `simplify*()`** は固有メタデータを保ったまま,保持している式のみを簡約する.「顔」は維持される > - `is_varint()` / `is_exprexpr()` で現在の「顔」を実行時に確認できる --- ## 1. 整数変数 このページの整数変数は,複数のバイナリ変数に展開されるものです. 整数値をそのまま保持する[ネイティブ整数変数](../basic/integer-variables-and-linear-systems.md)(`qbpp::IntVar`)は `qbpp::Expr` とは別の型で,リファレンスは[変数と式](../quickReference/qr_variable.md)にあります. `cons()` の制約式には,どちらの整数変数も使えます. ### 生成 | 構文 | 戻り値 | |---|---| | `l <= qbpp::var_int("x") <= u` | `Expr` (範囲 `[l, u]` の整数変数) | | `l <= qbpp::var_int("x", s1, s2, ...) <= u` | 整数変数の多次元配列 `Array` | ### 使える演算・関数 | カテゴリ | 例 | 戻り値 | 備考 | |---|---|---|---| | 単項 | `-vi` | `Expr` | | | 算術 (右辺 Expr) | `vi + 1`, `vi * 2`, `vi - x` | `Expr` | | | 算術 (右辺 整数変数) | `vi1 + vi2`, `vi1 * vi2` | `Expr` | | | 比較 (== int) | `vi == 5` | `Expr` (制約式) | 制約生成 | | 比較 (範囲) | `2 <= vi <= 5` | `Expr` (制約式) | between 制約 | | グローバル関数 | `qbpp::sqr(vi)`, `qbpp::simplify(vi)`, `qbpp::sqr(vi - 3)` | `Expr` | | | 整数変数固有メタ情報 | `vi.min_val()`, `vi.max_val()` | `energy_t` | read-only | | 整数変数固有構造メンバ | `vi.var_count()`, `vi.coeff(i)`, `vi.get_var(i)`, `vi[i]` | 各種 | read-only | | 配列アクセス | `vi.vars()`, `vi.coeffs()` | `Array<1, ...>` | read-only | | **複合代入** | `vi += 1`, `vi -= 1`, `vi *= 2`, `vi /= 2` | `Expr&` | **以後は通常の式相当**(固有メタは破棄) | | **二乗** | `vi.sqr()` | `Expr&` | **以後は通常の式相当** | | **置換** | `vi.replace(ml)` | `Expr&` | **以後は通常の式相当** | | in-place 簡約 | `vi.simplify()`, `vi.simplify_as_binary()`, `vi.simplify_as_spin()` | `Expr&` | 保持式のみ簡約,**整数変数のメタは保たれる** | | 代入 | `vi = other` | `Expr&` | 同じ型 | > **注意**: `vi += 1` 等の式変更系を呼んだ後,静的な型は引き続き `qbpp::Expr` ですが内部状態は通常の式相当です.`vi.min_val()` 等の整数変数固有 accessor は **runtime error** になります. --- ## 2. 制約式 ### 生成 | 構文 | 戻り値 | 意味 (penalty / body) | |---|---|---| | `f == n` | `Expr` (制約式) | penalty = `sqr(f - n)`, body = `f` | | `l <= f <= u` | `Expr` (制約式) | penalty = `(f-a)(f-(a+1))` (a は slack), body = `f` | ここで `f` は整数変数以外の式 (`Var`, `Term`, `Expr`, 整数変数 `Expr`). ### 使える演算・関数 | カテゴリ | 例 | 戻り値 | 備考 | |---|---|---|---| | 単項 | `-ee` | `Expr` | penalty を反転 | | 算術 (右辺 Expr) | `ee + 1`, `ee * 2`, `ee + x` | `Expr` | | | 算術 (右辺 制約式) | `ee1 + ee2`, `ee * ee` | `Expr` | penalty 同士 | | グローバル関数 | `qbpp::sqr(ee)`, `qbpp::simplify_as_binary(ee)`, `qbpp::replace(ee, ml)` | `Expr` | penalty に適用 | | body 取得 | `ee.body()` | `Expr` | clone | | 解での評価 | `sol(ee)` (penalty を評価), `ee.body(sol)` (body を評価) | `energy_t` | 制約満足度の検証に使用 | | **複合代入** | `ee += 1`, `ee -= 1`, `ee *= 2`, `ee /= 2` | `Expr&` | **以後は通常の式相当**(body 参照不可に) | | **二乗** | `ee.sqr()` | `Expr&` | **以後は通常の式相当** | | **置換** | `ee.replace(ml)` | `Expr&` | **以後は通常の式相当** | | in-place 簡約 | `ee.simplify()`, `ee.simplify_as_binary()`, `ee.simplify_as_spin()` | `Expr&` | penalty と body を同時に簡約,**制約式のまま** | | 代入 | `ee = other` | `Expr&` | 同じ型 | > **注意**: `ee += 1` 等の式変更系を呼ぶと penalty のみが更新され body は参照できなくなります.一方 `ee.simplify*()` は penalty と body 両方に同じ rule を適用するため,制約式の整合性が保たれます. > **Python との挙動の違い**: Python では `+=` 等の複合代入は silent rebind (新しい `Expr` に再束縛).一方 C++ は同じ object の内部状態が通常の式相当に変わります.詳細は [Hi-QUBO (C++) と PyQBPP (Python) の違い](../cppVsPy/cpp-vs-python.md) を参照. --- ## 3. ネイティブ制約 (`cons`) 比較や制約式を `qbpp::cons()` で囲むと,**ネイティブ制約として宣言**された式になります. 宣言された制約は制約として特別に処理され,バンドルされたソルバーは制約を満たすように効率よく探索します. 詳細は[ネイティブ制約](../basic/constraints.md)を参照してください. ### 生成 | 構文 | 意味 | |---|---| | `qbpp::cons(f == n)` | 等式制約 `f == n` | | `qbpp::cons(f <= n)` | 片側制約 | | `qbpp::cons(l <= f <= u)` | 両側の範囲制約 | | `qbpp::cons(f == qbpp::equal{a, b, ...})` | 離散許容値集合(`f` が `a`, `b`, ... のいずれか) | | `qbpp::cons(arr == n)` (配列の比較) | **要素ごとに1本**の制約 | | `P * qbpp::cons(...)` | 重み `P`(正の整数)を付与 | | `obj + qbpp::cons(...) + qbpp::cons(...)` | `+` で目的関数・他の制約と自由に結合 | ### 演算・関数 制約宣言を含む式 `f` に対して: | 例 | 戻り値 | 説明 | |---|---|---| | `f.is_declared_cons()` | `bool` | 制約宣言を含むか | | `f(sol)` | `energy_t` | ソルバーが報告する Energy と一致(目的関数+ペナルティ) | | `f.cons(sol)` | `size_t` | 解 `sol` で違反している制約の本数(0 なら全充足) | | `f.cons()` | 表示用ビュー | `std::cout << f.cons()` で宣言済み制約リストを表示 | | `f.violations(sol)` | リスト | 各制約の値・境界・違反量・重みを報告 | | `f.is_feasible(sol)` | `bool` | 全制約を充足しているか | | `f.simplify_as_binary()` | `Expr&` | 目的関数と制約の両方を簡約,**宣言は維持** | | `qbpp::replace(f, ml)` | `Expr` | 変数置換,宣言は維持 | | `qbpp::expand_cons(f)` / `f.expand_cons()` | `Expr` / `Expr&` | 従来のペナルティ式に展開(宣言は消える) | | `sqr()`, 式同士の乗算, 0 以下のスカラー倍, 制約式を引く減算, `reduce()` 等 | — | 宣言を壊す演算は**明示的に runtime error** | --- ## 4. グローバル関数: 新しい `Expr` を返す 整数変数・制約式を引数に取れる主要なグローバル関数.**いずれも引数を変更せず,新しい `qbpp::Expr` を返します**: | 関数 | 戻り値 | 説明 | |---|---|---| | `qbpp::sqr(x)` | `Expr` | `x * x` | | `qbpp::simplify(x)` | `Expr` | 同類項マージ | | `qbpp::simplify_as_binary(x)` | `Expr` | binary (0/1) ルールで簡約 | | `qbpp::simplify_as_spin(x)` | `Expr` | spin (±1) ルールで簡約 | | `qbpp::replace(x, ml)` | `Expr` | 変数置換 | | `qbpp::cons(x)` | `Expr` (制約宣言) | ネイティブ制約として宣言 | | `qbpp::expand_cons(x)` | `Expr` | 宣言された制約をペナルティ式に展開 | 引数 `x` は `Var`, `Term`, 任意の顔の `Expr` のいずれでも OK (内部では `Expr` として扱われる). --- ## 5. 配列版 整数変数の配列および制約式の配列も同じ性質: - **算術では各要素が `Expr` として扱われる** → 結果は `Array` - **in-place mutator (`+=`, `*=` 等)** は使えるが,要素ごとに上記と同じく通常の式相当に戻る ```{include} /../programFiles/markDown/quickReference/qr-intconstraint.md :start-after: :end-before: ``` 要素ごとの `body` アクセスは `qbpp::Expr(arr[i]).body()`. --- ## 関連ページ - [整数変数](../basic/integer-variables-and-linear-systems.md) — 整数変数を使った方程式の解き方 - [比較演算子](../advanced/comparison-operators.md) — `==`, `<= <=` の詳細 - [ネイティブ制約](../basic/constraints.md) — `qbpp::cons()` の詳細な使い方とソルバーごとの意味論 - [置換関数](../advanced/replace-functions.md) — `replace()` の使用例 ::: :::{container} prog-python `pyqbpp.Expr` は通常の式・整数変数・制約式を **統一的に表現する型** です.3 つとも同じ型で,持つメタデータが違うだけです. `Expr` は 3 つの「顔」を持ちます: - **通常の式** (多項式): `x + 2*y*z` などの算術式 - **整数変数**: `qbpp.var("x", between=(0, 10))` で作った `Expr` - **制約式**: `qbpp.constrain(e, equal=5)` などで作った `Expr` > **基本原則** > - `pyqbpp.Expr` の演算・関数はすべて,どの「顔」の Expr にも適用できる > - **固有 accessor** (`min_val`, `body` 等) は対応する「顔」の Expr でのみ有効.合わない Expr で呼ぶと **runtime abort** > - **式を変更するメソッド** (`+=`, `-=`, `*=`, `/=`, `//=`, `sqr()`, `replace()`) を呼ぶと,内部表現は通常の式に戻る(固有メタデータは破棄) > - **例外: `simplify*()`** は固有メタデータを保ったまま簡約 > - `e.is_varint()` / `e.is_exprexpr()` で現在の「顔」を実行時に確認できる --- ## 1. 整数変数 このページの整数変数は,複数のバイナリ変数に展開されるものです. 整数値をそのまま保持する[ネイティブ整数変数](../basic/integer-variables-and-linear-systems.md)(`IntVar`)は `Expr` とは別の型で,リファレンスは[変数と式](../quickReference/qr_variable.md)にあります. `cons()` の制約式には,どちらの整数変数も使えます. ### 生成 | 構文 | 戻り値 | |---|---| | `qbpp.var("x", between=(l, u))` | `Expr` (範囲 `[l, u]` の整数変数) | | `qbpp.var("x", shape=N, between=(l, u))` | 整数変数 `Expr` 要素の配列 | | `qbpp.var("x", shape=(s1, s2, ...), between=(l, u))` | 多次元の整数変数配列 | | `qbpp.var("x", shape=N, equal=0)` | placeholder の整数変数配列 (各要素を後から代入) | ### 演算・関数 | カテゴリ | 例 | 戻り値 | 備考 | |---|---|---|---| | 単項 | `-vi` | `Expr` | | | 算術 (右辺 Expr 系) | `vi + 1`, `vi * 2`, `vi - x` | `Expr` | | | 算術 (右辺 整数変数) | `vi1 + vi2`, `vi1 * vi2` | `Expr` | | | 制約 (等値) | `qbpp.constrain(vi, equal=5)` | `Expr` (制約式) | 制約生成 | | 制約 (範囲) | `qbpp.constrain(vi, between=(l, u))` | `Expr` (制約式) | 範囲制約 | | グローバル関数 | `qbpp.sqr(vi)`, `qbpp.simplify(vi)`, `qbpp.simplify_as_binary(vi)` | `Expr` | | | 整数変数固有メタ情報 | `vi.min_val`, `vi.max_val` | 各種 | read-only | | 整数変数固有構造 | `vi.var_count`, `vi.coeff(i)`, `vi.get_var(i)`, `vi[i]` | 各種 | read-only | | 配列プロパティ | `vi.vars`, `vi.coeffs` | `list` | read-only | | Expr 取得 | `str(vi)` | `str` | | | **複合代入** | `vi += 1`, `vi -= 1`, `vi *= 2`, `vi //= 2`, `vi /= 2` | (`vi` が通常の式相当に) | **以後整数変数固有 accessor は使えなくなる** | | **二乗** | `vi.sqr()` | (`vi` が通常の式相当に) | | | **置換** | `vi.replace(ml)` | (`vi` が通常の式相当に) | | | in-place 簡約 | `vi.simplify()`, `vi.simplify_as_binary()`, `vi.simplify_as_spin()` | `Expr` | 保持式のみ簡約,**整数変数のメタは保たれる** | | 代入 | `vi = other` | (再束縛) | Python の通常の代入 | > **注意**: `vi += 1` 等を呼んだ後,Python の型は引き続き `Expr` ですが内部状態は通常の式相当です.`vi.min_val` 等の整数変数固有 accessor は **runtime error** になります. --- ## 2. 制約式 ### 生成 | 構文 | 戻り値 | 意味 (penalty / body) | |---|---|---| | `qbpp.constrain(f, equal=n)` | `Expr` (制約式) | penalty = `sqr(f - n)`, body = `f` | | `qbpp.constrain(f, between=(l, u))` | `Expr` (制約式) | penalty = between, body = `f` | | `qbpp.constrain(f, between=(l, None))` | `Expr` (制約式) | `f >= l` (無上限) | | `qbpp.constrain(f, between=(None, u))` | `Expr` (制約式) | `f <= u` (無下限) | `f` は整数変数以外の式 (`Var`, `Term`, `Expr`, 整数変数 `Expr`),`n`, `l`, `u` は整数. ### 演算・関数 | カテゴリ | 例 | 戻り値 | 備考 | |---|---|---|---| | 単項 | `-ee` | `Expr` | penalty を反転 | | 算術 (右辺 Expr 系) | `ee + 1`, `ee * 2`, `ee + x` | `Expr` | | | 算術 (右辺 制約式) | `ee1 + ee2` | `Expr` | penalty 同士 | | グローバル関数 | `qbpp.sqr(ee)`, `qbpp.simplify_as_binary(ee)`, `qbpp.replace(ee, ml)` | `Expr` | penalty に適用 | | プロパティ | `ee.body`, `str(ee)` | `Expr` / `str` | clone | | 解での評価 | `sol(ee)` (penalty を評価), `sol(ee.body)` (body を評価) | `int` | 制約満足度の検証 | | **複合代入** | `ee += 1`, `ee -= 1`, `ee *= 2`, `ee //= 2`, `ee /= 2` | (`ee` が通常の式相当に) | **body は参照不可に** | | **二乗** | `ee.sqr()` | (`ee` が通常の式相当に) | | | **置換** | `ee.replace(ml)` | (`ee` が通常の式相当に) | | | in-place 簡約 | `ee.simplify()`, `ee.simplify_as_binary()`, `ee.simplify_as_spin()` | `Expr` | penalty と body を同時に簡約,**制約式のまま** | | 代入 | `ee = other` | (再束縛) | Python の通常の代入 | > **注意**: `ee += 1` 等の式変更系を呼ぶと penalty のみが更新され body は参照できなくなります.`ee.simplify*()` は penalty と body 両方に同じ rule を適用するため,制約式の整合性が保たれます. --- ## 3. ネイティブ制約 (`cons`) 制約を `qbpp.cons()` で作成すると,**ネイティブ制約として宣言**された式になります. 宣言された制約は制約として特別に処理され,バンドルされたソルバーは制約を満たすように効率よく探索します. 詳細は[ネイティブ制約](../basic/constraints.md)を参照してください. ### 生成 | 構文 | 意味 | |---|---| | `qbpp.cons(f, equal=n)` | 等式制約 `f == n` | | `qbpp.cons(f, equal=[a, b, ...])` | 離散許容値集合(`f` が `a`, `b`, ... のいずれか) | | `qbpp.cons(f, between=(l, u))` | 範囲制約(片側は `None` で無制限) | | `qbpp.cons(制約式)` | `==` で作った制約式をネイティブ制約として宣言 | | `qbpp.cons(配列の比較)` | **要素ごとに1本**の制約 | | `P * qbpp.cons(...)` | 重み `P`(正の整数)を付与 | | `obj + qbpp.cons(...) + qbpp.cons(...)` | `+` で目的関数・他の制約と自由に結合 | ### 演算・関数 制約宣言を含む式 `f` に対して: | 例 | 戻り値 | 説明 | |---|---|---| | `f.is_declared_cons()` | `bool` | 制約宣言を含むか | | `sol(f)` | `int` | ソルバーが報告する Energy と一致(目的関数+ペナルティ) | | `f.cons(sol)` | `int` | 解 `sol` で違反している制約の本数(0 なら全充足) | | `f.cons()` | `str` | 宣言済み制約リストの文字列(`print(f.cons())` で表示) | | `f.violations(sol)` | `list` | 各制約の値・境界・違反量・重みを報告 | | `f.is_feasible(sol)` | `bool` | 全制約を充足しているか | | `f.simplify_as_binary()` | `Expr` | 目的関数と制約の両方を簡約,**宣言は維持** | | `qbpp.replace(f, ml)` | `Expr` | 変数置換,宣言は維持 | | `qbpp.expand_cons(f)` / `f.expand_cons()` | `Expr` | 従来のペナルティ式に展開(宣言は消える) | | `sqr()`, 式同士の乗算, 0 以下のスカラー倍, 制約式を引く減算, `reduce()` 等 | — | 宣言を壊す演算は**明示的に runtime error** | --- ## 4. グローバル関数: 新しい `Expr` を返す 整数変数・制約式を引数に取れる主要なグローバル関数.**いずれも引数を変更せず,新しい `pyqbpp.Expr` を返します**: | 関数 | 戻り値 | 説明 | |---|---|---| | `qbpp.sqr(x)` | `Expr` | `x * x` | | `qbpp.simplify(x)` | `Expr` | 同類項マージ | | `qbpp.simplify_as_binary(x)` | `Expr` | binary (0/1) ルールで簡約 | | `qbpp.simplify_as_spin(x)` | `Expr` | spin (±1) ルールで簡約 | | `qbpp.replace(x, ml)` | `Expr` | 変数置換 | | `qbpp.constrain(f, equal=n)` | `Expr` (制約式) | 等値制約 | | `qbpp.constrain(f, between=(l, u))` | `Expr` (制約式) | 範囲制約 | | `qbpp.cons(...)` | `Expr` (制約宣言) | ネイティブ制約として宣言 | | `qbpp.expand_cons(f)` | `Expr` | 宣言された制約をペナルティ式に展開 | 引数 `x` は `Var`, `Term`, 任意の顔の `Expr` のいずれでも OK (内部では `Expr` として扱われる). --- ## 5. 配列版 整数変数・制約式の配列も同じ規則: - **算術では各要素が `Expr` として扱われる** → 結果は `Expr` 配列 - **in-place mutator (`+=`, `*=` 等) も使える**が,要素ごとに上記と同じく通常の式相当に戻る ```{include} /../programFiles/markDown/quickReference/qr-intconstraint.md :start-after: :end-before: ``` 要素ごとの `body` アクセスは `arr[i].body`. --- ## 6. C++ 版との差異 C++ / Python とも `+=` 等の式変更操作は許可されますが,その後の挙動が異なります: - **C++**: 同じ object の内部状態が通常の式相当に変わる.固有 accessor 呼出は runtime error - **Python**: 同じオブジェクトの中身が変わる.Python の object identity は保たれるが,固有 accessor は同じく runtime error --- ## 関連ページ - [整数変数と連立方程式の求解](../basic/integer-variables-and-linear-systems.md) — `qbpp.var(..., between=...)` と `qbpp.constrain(...)` を使った例 - [比較制約](../advanced/comparison-operators.md) — `qbpp.constrain(f, equal=n)` による制約生成 - [ネイティブ制約](../basic/constraints.md) — `qbpp.cons()` の詳細な使い方とソルバーごとの意味論 - [置換関数](../advanced/replace-functions.md) — `qbpp.replace(...)` の使用例 :::