クイックリファレンス: 整数変数と制約に関する演算と関数

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. 整数変数

生成

構文 戻り値
l <= qbpp::var_int("x") <= u Expr (範囲 [l, u] の整数変数)
l <= qbpp::var_int("x", s1, s2, ...) <= u 整数変数の多次元配列 Array<Dim, Expr>

使える演算・関数

カテゴリ 戻り値 備考
単項 -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 の内部状態が通常の式相当に変わります。詳細は QUBO++ (C++) と PyQBPP (Python) の違い を参照。


3. ネイティブ制約 (cons)

比較や制約式を qbpp::cons() で囲むと、ネイティブ制約として宣言された式になります。 宣言された制約は制約として特別に処理され、バンドルされたソルバーは制約を満たすように効率よく探索します。 詳細はネイティブ制約を参照してください。

生成

構文 意味
qbpp::cons(f == n) 等式制約 f == n
qbpp::cons(f <= n) 片側制約
qbpp::cons(l <= f <= u) 両側の範囲制約
qbpp::cons(f == qbpp::equal{a, b, ...}) 離散許容値集合(fa, 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 宣言された制約をペナルティ式に展開

引数 xVar, Term, 任意の顔の Expr のいずれでも OK (内部では Expr として扱われる)。


5. 配列版

整数変数の配列および制約式の配列も同じ性質:

  • 算術では各要素が Expr として扱われる → 結果は Array<Dim, Expr>
  • in-place mutator (+=, *= 等) は使えるが、要素ごとに上記と同じく通常の式相当に戻る
// 整数変数の配列
auto x = 0 <= qbpp::var_int("x", 3) <= 7;     // Array<1, Expr> の整数変数配列
auto sum = qbpp::sum(x);                       // Expr (各要素を Expr として合計)

// 制約式の配列 (要素ごとの制約)
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, Expr> の制約式
auto penalty = qbpp::sum(onehot);              // Expr (全制約の合計)

要素ごとの body アクセスは qbpp::Expr(arr[i]).body()


関連ページ


Back to top

Page last modified: 2026.07.12.