クイックリファレンス: 整数変数と制約に関する演算と関数
整数変数 (qbpp::VarInt) と制約 (qbpp::ExprExpr) は、qbpp::Expr を補う 2 つの専用オブジェクト型 で、共に immutable です。
基本原則
- in-place 変更は不可 (
vi += 1,ee.simplify_as_binary()などはエラー)- 上書きできるのは同じ型の代入のみ (
vi = other_vi,ee = other_ee)- 算術文脈では
Exprに decay する (暗黙変換)。一旦Exprになれば in-place 変更も自由- 関数を適用したい時は グローバル関数 を使う (
qbpp::simplify_as_binary(ee)等は新しいExprを返す。元のVarInt/ExprExprは変更されない)
1. qbpp::VarInt
生成
| 構文 | 戻り値 |
|---|---|
l <= qbpp::var_int("x") <= u | VarInt (範囲 [l, u]) |
l <= qbpp::var_int("x", s1, s2, ...) <= u | Array<Dim, VarInt> |
qbpp::between(qbpp::var_int("x"), l, u) | VarInt (関数形式) |
使える演算・関数
| カテゴリ | 例 | 戻り値 | 備考 |
|---|---|---|---|
| 単項 | -vi, vi (Expr decay) | Expr | Expr への暗黙変換 |
| 算術 (右辺 Expr) | vi + 1, vi * 2, vi - x | Expr | 暗黙変換 → Expr 演算 |
| 算術 (右辺 VarInt) | vi1 + vi2, vi1 * vi2 | Expr | 両辺 decay |
| 比較 (== int) | vi == 5 | ExprExpr | 制約生成 |
| 比較 (範囲) | 2 <= vi <= 5 | ExprExpr | between 制約 |
| グローバル関数 | qbpp::sqr(vi), qbpp::simplify(vi), qbpp::sqr(vi - 3) | Expr | decay → Expr に適用 |
| メタ情報メンバ | vi.name(), 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() | Array<1, ...> | read-only |
| Expr 取得 | vi.expr(), vi.str() | Expr / string | clone |
| 代入 | vi = other_vi | VarInt& | 同じ型のみ |
使えない演算・関数
| カテゴリ | 例 | 結果 |
|---|---|---|
| 複合代入 | vi += 1, vi -= 1, vi *= 2, vi /= 2 | コンパイルエラー (= delete) |
| in-place mutator メソッド | vi.simplify(), vi.simplify_as_binary(), vi.simplify_as_spin(), vi.sqr() | コンパイルエラー (= delete) |
| 置換 | vi.replace(ml) | エラー |
| Expr の代入 | vi = some_expr | コンパイルエラー (型不一致) |
→ いずれも グローバル関数 (qbpp::simplify_as_binary(vi) など) で代用してください。
2. qbpp::ExprExpr
生成
| 構文 | 戻り値 | 意味 (penalty / body) |
|---|---|---|
f == n | ExprExpr | penalty = sqr(f - n), body = f |
l <= f <= u | ExprExpr | penalty = (f-a)(f-(a+1)) (a は slack), body = f |
qbpp::between(f, l, u) | ExprExpr | 上と同じ (関数形式) |
ここで f は非整数の ExprType (Var, Term, Expr, VarInt)。
使える演算・関数
| カテゴリ | 例 | 戻り値 | 備考 |
|---|---|---|---|
| 単項 | -ee | Expr | Expr への暗黙変換 (penalty) |
| 算術 (右辺 Expr) | ee + 1, ee * 2, ee + x | Expr | decay → Expr 演算 |
| 算術 (右辺 ExprExpr) | ee1 + ee2, ee * ee | Expr | 両辺 decay (penalty 同士) |
| グローバル関数 | qbpp::sqr(ee), qbpp::simplify_as_binary(ee), qbpp::replace(ee, ml) | Expr | penalty に適用、新 Expr を返す |
| メンバ取得 | ee.penalty(), ee.body(), ee.str() | Expr / string | clone |
| 解での評価 | sol(ee) (penalty を評価), sol(ee.body()) (body を評価) | coeff_t | 制約満足度の検証に使用 |
| 代入 | ee = other_ee | ExprExpr& | 同じ型のみ |
使えない演算・関数
| カテゴリ | 例 | 結果 |
|---|---|---|
| 複合代入 | ee += 1, ee -= 1, ee *= 2, ee /= 2 | コンパイルエラー (= delete) |
| in-place mutator メソッド | ee.simplify(), ee.simplify_as_binary(), ee.simplify_as_spin(), ee.sqr() | コンパイルエラー (= delete) |
| 置換 | ee.replace(ml) | コンパイルエラー (= delete) |
| Expr の代入 | ee = some_expr | コンパイルエラー (型不一致) |
→ いずれも グローバル関数で代用してください (qbpp::simplify_as_binary(ee) 等は Expr を返し、元の ee は変更されません)。
Python との挙動の違い: Python では
+=等の複合代入は silent rebind (新しいExprに再束縛)、メソッド呼出はTypeError。詳細は QUBO++ (C++) と PyQBPP (Python) の違い を参照。
3. グローバル関数: 新しい Expr を返す
VarInt / ExprExpr を引数に取れる主要なグローバル関数。いずれも引数を変更せず、新しい 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::between(x, l, u) | ExprExpr | 範囲制約 (l <= x <= u と同じ) |
引数 x は Var, Term, Expr, VarInt, ExprExpr のいずれでも OK (内部で Expr に decay)。
4. 配列版
qbpp::Array<Dim, VarInt> および qbpp::Array<Dim, ExprExpr> も同じ性質:
- 要素ごとに immutable
- 算術では各要素が
Exprに decay → 結果はArray<Dim, Expr> - in-place mutator は不可、グローバル関数で代用
// VarInt 配列
auto x = 0 <= qbpp::var_int("x", 3) <= 7; // Array<1, VarInt>
auto sum = qbpp::sum(x); // Expr (各要素を decay して合計)
// ExprExpr 配列 (要素ごとの制約)
auto m = qbpp::var("m", 3, 4); // Array<2, Var>
auto rows = qbpp::vector_sum(m, 0); // Array<1, Expr> (各行の和)
auto onehot = (rows == 1); // Array<1, ExprExpr>
auto penalty = qbpp::sum(onehot); // Expr (全制約の合計)
要素ごとの body アクセスは arr[i].body()。