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

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

このページの整数変数は,複数のバイナリ変数に展開されるものです. 整数値をそのまま保持するネイティブ整数変数(qbpp::IntVar)は qbpp::Expr とは別の型で,リファレンスは変数と式にあります. cons() の制約式には,どちらの整数変数も使えます.

生成

構文

戻り値

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 の内部状態が通常の式相当に変わります.詳細は Hi-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, ...})

離散許容値集合(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<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().


関連ページ

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

このページの整数変数は,複数のバイナリ変数に展開されるものです. 整数値をそのまま保持するネイティブ整数変数(IntVar)は Expr とは別の型で,リファレンスは変数と式にあります. 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() で作成すると,ネイティブ制約として宣言された式になります. 宣言された制約は制約として特別に処理され,バンドルされたソルバーは制約を満たすように効率よく探索します. 詳細はネイティブ制約を参照してください.

生成

構文

意味

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 (+=, *= 等) も使えるが,要素ごとに上記と同じく通常の式相当に戻る

# 整数変数の配列
x = qbpp.var("x", shape=3, between=(0, 7))      # 整数変数 Expr の配列
sum_expr = qbpp.sum(x)                           # Expr
f = qbpp.sqr(sum_expr - 5)                       # Expr

# 制約式の配列 (要素ごとの制約)
m = qbpp.var("m", shape=(3, 4))                  # 2D Var 配列
rows = qbpp.vector_sum(m, axis=0)                # 各行の和 (Expr 配列)
onehot = qbpp.constrain(rows, equal=1)           # 制約式 Expr の配列
penalty = qbpp.sum(onehot)                       # Expr (全制約の合計)

要素ごとの body アクセスは arr[i].body.


6. C++ 版との差異

C++ / Python とも += 等の式変更操作は許可されますが,その後の挙動が異なります:

  • C++: 同じ object の内部状態が通常の式相当に変わる.固有 accessor 呼出は runtime error

  • Python: 同じオブジェクトの中身が変わる.Python の object identity は保たれるが,固有 accessor は同じく runtime error


関連ページ