# 整数変数と制約に関する演算と関数
:::{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(...)` の使用例
:::