変数と式¶
qbpp::Exprで使用されるデータ型
coeff_t:qbpp::Termオブジェクトの係数に使用される整数データ型.デフォルトはint32_t.energy_t:qbpp::Exprオブジェクトのエネルギー値の計算,およびqbpp::Expr内の整数定数項に使用される整数データ型.デフォルトはint64_t.energy_tのビット幅はcoeff_tのビット幅以上であることが保証されています.
これらの型はプリビルド済みの共有ライブラリとセットで提供されており,
ヘッダをインクルードする前に次の INTEGER_TYPE_* マクロのいずれかを定義して切り替えます
(コンパイラフラグ -D... でも指定可能):
マクロ |
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
注意 — オーバーフロー.
coeff_tは各係数を,energy_tは累積エネルギー(有効な項の総和)を制限します.固定幅の型はオーバーフローを検出しません.累積エネルギーがenergy_tを超えると,C++ の組み込み整数演算と同じく黙って折り返します.最悪ケースのエネルギーを収められるenergy_tを持つバリアントを選んでください.INTEGER_TYPE_CPP_INT(任意精度)はオーバーフローしません.
実数(double)係数
係数は double(実数)にもできます.INTEGER_TYPE_* の代わりに次の DOUBLE_TYPE* マクロの
いずれかを定義すると,coeff_t と energy_t はともに double になります:
マクロ |
|
|
求解に使うソルバー |
|---|---|---|---|
|
|
|
64ビット整数ソルバー |
|
|
|
128ビット整数ソルバー(高精度) |
#define DOUBLE_TYPE
#include <qbpp/qbpp.hpp>
auto x = qbpp::var("x");
auto y = qbpp::var("y");
qbpp::Expr f = -1.5 * x - 2.5 * y + 4.0 * x * y; // 実数(double)係数
式の構築・簡約・評価はすべて
doubleで行われ,sol.energy()もdoubleを返します.求解時には係数が自動的に整数へスケーリングされ,上記の整数ソルバーに渡されます — 手動の量子化は不要です.
2進小数の係数(1, 1/2, 1/4, ...)は厳密に表現されます.最大係数よりはるかに小さい係数は スケーリング精度を下回ると通知付きでドロップされます.
DOUBLE_TYPE_C128E128を使うと ダイナミックレンジが大幅に広がります.除算(
/,/=)は実数除算です — 整数バリアントの割り切れ要件は適用されません.MAXDEG*は整数バリアントと同様に組み合わせ可能です(例:DOUBLE_TYPE+MAXDEG2).
詳しくは 実数(double)係数 を参照してください.
さらに,各 qbpp::Term が変数をどう格納するかを制御する MAXDEG* マクロも指定できます.
最大次数が事前に分かっている場合,固定長モードを使うとヒープ確保が不要になり性能が向上します:
マクロ |
最大次数 |
説明 |
|---|---|---|
|
無制限 |
可変長(3次以上でヒープ確保) |
|
2 |
固定長,QUBO専用(ヒープ確保なし,最速) |
|
4 |
固定長,4次まで(ヒープ確保なし) |
INTEGER_TYPE_* と MAXDEG* は独立に組み合わせ可能です.詳細は VAREXPR を参照してください.
WARNING パフォーマンスを最大化するため,Hi-QUBOは算術オーバーフローのチェックを行いません. 開発およびテスト中は,
coeff_tとenergy_tにはより広いビット幅を使用することを推奨します. 必要なビット幅が不明な場合は,qbpp::cpp_intを使用して正確性を確保し, 検証後に固定幅の整数型に切り替えてください.
クラスオブジェクトの出力
Hi-QUBOのほとんどのクラスは,std::ostreamの<<演算子を使用して出力でき,
デバッグに便利です.
例えば,Hi-QUBOのオブジェクトobjは次のようにstd::coutに出力できます:
std::cout << obj << std::endl;
この設計により,デバッガに頼ることなく内部状態を簡単に確認できます.
変数クラス
qbpp::Var: 一意な32ビット整数IDを保持するクラス. 変数名はグローバルレジストリに格納され,std::cout << xで確認できます.
注意
qbpp::Varオブジェクトは変数をシンボリックに表現します. 特定のデータ型は関連付けられていません. バイナリ,スピン,その他の型の変数を表現するために使用できます.
変数作成関数
変数を作成するために以下の関数が提供されています:
qbpp::var("name"): 指定された名前"name"を持つqbpp::Varオブジェクトを作成します.qbpp::var("name", s1): ベース名"name"を持つqbpp::Varオブジェクトの1次元配列を作成します. 各要素はname[i]として表現されます. 結果は1次元の変数の配列です.qbpp::var("name", s1, s2): ベース名"name"を持つqbpp::Varオブジェクトの2次元配列(行列)を作成します. 各要素はname[i][j]として表現されます. 結果は2次元の変数の配列です.qbpp::var("name", s1, s2, ...): ベース名"name"を持つqbpp::Varオブジェクトの高次元配列を作成します. 各要素はname[i][j]...として表現されます. 結果はN次元の変数の配列です(Nは次元数).
注意
"name"が省略された場合,"{0}","{1}",...のような番号付きの名前が作成順に自動的に割り当てられます.
qbpp::Varメンバ関数
qbpp::Varのインスタンスxに対して,以下のメンバ関数が利用できます:
uint32_t x.index():xの一意な整数IDを返します.
通常,Hi-QUBOプログラムでこれらのメンバ関数を明示的に呼び出す必要はありません.
整数変数
Hi-QUBO には 2 種類の整数変数があります.
種類 |
生成 |
内部表現 |
使いどころ |
|---|---|---|---|
整数変数 |
|
複数のバイナリ変数に展開 |
外部のバイナリ専用ソルバーにも渡せる |
|
整数値をそのまま保持 |
同梱ソルバー・MIP ソルバーで数量を扱う |
整数変数は,範囲とビット分解のメタデータを保持する qbpp::Expr であり,指定された範囲の整数値を表現します.
整数変数作成関数
整数変数を作成するために以下の関数が提供されています:
qbpp::var_int("name"): 内部的に使用されるヘルパーオブジェクトを返し,単体では整数変数を作成しません. 整数変数を定義するには,以下に示すように<=演算子を使用して範囲を指定する必要があります.l <= qbpp::var_int("name") <= u: ここでlとuは整数でなければなりません. この式は名前"name"を持つ整数変数のqbpp::Exprオブジェクトを作成し, 保持する式が範囲[l, u]のすべての整数を表現します. 内部的には,基礎となる式で使用されるqbpp::Varオブジェクトも作成されます.l <= qbpp::var_int("name", s1) <= u: ベース名"name"と同じ範囲[l, u]を持つ整数変数qbpp::Exprの1次元配列を作成します. 各要素はname[i]として表現されます. 結果は1次元の整数変数の配列です. 整数変数の高次元配列はqbpp::Varオブジェクトと同じ方法で作成できます.
整数変数メンバ関数
整数変数 x(qbpp::Expr)に対して,以下のメンバ関数が利用できます:
energy_t x.min_val():xの最小値lを返します.energy_t x.max_val():xの最大値uを返します.Array<1, Var> x.vars(): 整数変数を表現するために使用されるqbpp::Varオブジェクト配列を返します.Array<1, coeff_t> x.coeffs(): 整数係数配列を返します.
以下の式はxに格納されている式と等価です:
qbpp::sum(x.coeffs() * x.vars()) + x.min_val()
ネイティブ整数変数
ネイティブ整数変数は,整数値をそのまま保持する qbpp::IntVar 型です.
qbpp::Expr ではなく独立した型ですが,式の中で使うと自動的に qbpp::Expr に
変換されるため,通常の変数と同じように書けます.詳しくは
ネイティブ整数変数を参照してください.
ネイティブ整数変数作成関数
l <= qbpp::int_var("name") <= u: 名前"name"・範囲[l, u]のネイティブ整数変数qbpp::IntVarを作成します. 範囲の指定は必須で,l < uでなければなりません.l <= qbpp::int_var("name", s1, s2, ...) <= u: 同じ範囲[l, u]を持つネイティブ整数変数の配列qbpp::Array<Dim, IntVar>を 作成します.各要素はname[i]・name[i][j]として表現され,x[i]・x[i][j]でアクセスします(x(i)・x(i, j)の呼び出し形も使えます).
ネイティブ整数変数メンバ関数
ネイティブ整数変数 x(qbpp::IntVar)に対して,以下のメンバ関数が利用できます:
energy_t x.lo():xの最小値lを返します.energy_t x.hi():xの最大値uを返します.
解 sol における値は sol(x)(または sol.get(x))で取得し,
sol.set(x, v) で設定します.
変換
qbpp::binarize(f): 式fに含まれるネイティブ整数変数をバイナリエンコーディングに展開した 新しいqbpp::Exprを返します.MIP ソルバーは整数変数を直接扱えるため, バイナリ変数専用の外部 QUBO ソルバーに渡すときに使います.
PyQBPP のデータ型
PyQBPPでは係数・エネルギー値・定数をPythonのネイティブな int 型で扱うため,
ユーザーコード上で coeff_t や energy_t を気にする必要はありません.
ただし,内部で使用する共有ライブラリは複数の型バリアントを備えており,
インポート時にサブモジュールを選択することで切り替えます
(デフォルトの import pyqbpp は c32e64,つまり32ビット係数・64ビットエネルギー).
import pyqbpp as qbpp # デフォルト: c32e64
# import pyqbpp.cppint as qbpp # 任意精度 (cpp_int)
# import pyqbpp.c32e64m4 as qbpp # c32e64 + 4次まで固定長
利用可能な型バリアント:
インポート |
係数 |
エネルギー |
用途 |
|---|---|---|---|
|
32ビット |
64ビット |
デフォルト,最も一般的 |
|
32ビット |
32ビット |
小規模問題 |
|
64ビット |
64ビット |
大きな係数 |
|
64ビット |
128ビット |
大きなエネルギー範囲 |
|
128ビット |
128ビット |
非常に大規模な問題 |
|
無制限 |
無制限 |
任意精度 ( |
注意 — オーバーフロー. 係数の幅は各係数を,エネルギーの幅は累積エネルギー(有効な項の総和)を制限します.固定幅のバリアントはオーバーフローを検出しません.累積エネルギーがエネルギー幅を超えると黙って折り返します.エネルギーが大きくなり得る場合は,より広いバリアント(または任意精度の
pyqbpp.cppint)を使ってください.
実数(double)係数
係数は double(Python の float)にもできます.整数バリアントの代わりに
次のサブモジュールをインポートします:
インポート |
係数 |
エネルギー |
求解に使うソルバー |
|---|---|---|---|
|
|
|
64ビット整数ソルバー |
|
|
|
128ビット整数ソルバー(高精度) |
import pyqbpp.d as qbpp
x = qbpp.var("x")
y = qbpp.var("y")
f = -1.5 * x - 2.5 * y + 4.0 * x * y # 実数(float)係数
式の構築・簡約・評価はすべて
floatで行われ,sol.energyもfloatになります.求解時には係数が自動的に整数へスケーリングされ,上記の整数ソルバーに渡されます — 手動の量子化は不要です.
2進小数の係数(1, 1/2, 1/4, ...)は厳密に表現されます.最大係数よりはるかに小さい係数は スケーリング精度を下回ると通知付きでドロップされます.
pyqbpp.dc128e128を使うと ダイナミックレンジが大幅に広がります.除算(
/,/=)は実数除算です — 整数バリアントの割り切れ要件は適用されません.VarArray モード接尾辞も通常どおり組み合わせ可能です(例:
import pyqbpp.dc64e64m2).qbpp.array()・qbpp.einsum()・配列の要素ごと演算子にはfloatのリストや numpy の ndarray を直接渡せます(MULTIDIM / EINSUM 参照).
詳しくは 実数(double)係数 を参照してください.
さらに各バリアントに VarArray モード接尾辞 m0 / m2 / m4 を付けて,
qbpp::Term の変数格納方式を選択できます
(例: import pyqbpp.c32e64m4 as qbpp):
接尾辞 |
最大次数 |
説明 |
|---|---|---|
(なし)/ |
無制限 |
可変長(デフォルト,3次以上でヒープ確保) |
|
2 |
固定長,QUBO専用(ヒープ確保なし,最速) |
|
4 |
固定長,4次まで(ヒープ確保なし) |
型バリアントはインポート時に選択し,プログラム実行中に切り替えることはできません. 詳細は VAREXPR を参照してください.
オブジェクトの表示
すべてのPyQBPPオブジェクトは print() で表示するか,str() で文字列に変換できます.
print(obj)
s = str(obj)
変数クラス
pyqbpp.Var: 一意な32ビット整数IDを保持するクラスです. 変数名はstr(x)で取得できます.
注釈
pyqbpp.Varオブジェクトは変数をシンボリックに表現します. 特定のデータ型は関連付けられていません. バイナリ変数,スピン変数,その他の種類の変数を表現するために使用できます.
変数作成関数
変数を作成するために以下の関数が提供されています.
pyqbpp.var("name"): 指定された名前"name"を持つpyqbpp.Varオブジェクトを作成します.pyqbpp.var("name", shape=s1): 基本名"name"を持つバイナリ変数の1次元配列を作成します. 各要素はname[i]として表されます.pyqbpp.var("name", shape=(s1, s2)): 基本名"name"を持つバイナリ変数の2次元配列(行列)を作成します. 各要素はname[i][j]として表されます.pyqbpp.var("name", shape=(s1, s2, ...)): 基本名"name"を持つバイナリ変数の高次元配列を作成します. 各要素はname[i][j]...として表されます.
注釈
"name"を省略すると,作成順に"{0}","{1}"などの番号付き名前が自動的に割り当てられます.
例
import pyqbpp as qbpp
x = qbpp.var("x") # Single variable named "x"
y = qbpp.var("y", shape=3) # Array: y[0], y[1], y[2]
z = qbpp.var("z", shape=(2, 3)) # 2x3 matrix: z[0][0], ..., z[1][2]
a = qbpp.var() # Single unnamed variable
b = qbpp.var(shape=5) # Array of 5 unnamed variables
pyqbpp.Var のプロパティとメソッド
pyqbpp.Var のインスタンス x に対して,以下が利用可能です.
str(x):xの名前を文字列として返します.
整数変数
Hi-QUBO には 2 種類の整数変数があります.
種類 |
生成 |
内部表現 |
使いどころ |
|---|---|---|---|
整数変数 |
|
複数のバイナリ変数に展開 |
外部のバイナリ専用ソルバーにも渡せる |
|
整数値をそのまま保持 |
同梱ソルバー・MIP ソルバーで数量を扱う |
整数変数は,範囲とビット分解のメタデータを保持する pyqbpp.Expr であり,指定された範囲の整数値を表現します.
整数変数作成関数
整数変数を作成するために以下の関数が提供されています.
pyqbpp.var("name", between=(l, u)): ここでlとuは整数でなければなりません. この式は名前"name"を持つ整数変数のpyqbpp.Exprオブジェクトを作成し, 保持する式が範囲[l, u]のすべての整数を表します. 内部的に,基礎となる式で使用されるpyqbpp.Varオブジェクトも作成します.pyqbpp.var("name", shape=s1, between=(l, u)): 基本名"name"と同じ範囲[l, u]を持つ整数変数の1次元配列を作成します. 各要素はname[i]として表されます. 整数変数の高次元配列は,バイナリ変数と同じ方法で作成できます.
例
import pyqbpp as qbpp
x = qbpp.var("x", between=(0, 10)) # Integer variable x in [0, 10]
y = qbpp.var("y", shape=3, between=(-5, 5)) # Array of 3 integer variables in [-5, 5]
z = qbpp.var("z", shape=(2, 3), between=(1, 8)) # 2x3 matrix of integer variables in [1, 8]
整数変数のプロパティ
整数変数 x(pyqbpp.Expr)に対して,以下が利用可能です.
x.min_val(プロパティ):xの最小値lを返します.x.max_val(プロパティ):xの最大値uを返します.x.vars(プロパティ): 整数変数を表現するために使用されるpyqbpp.Varオブジェクトのリストを返します.x.coeffs(プロパティ): 整数係数のリストを返します.
以下の式は x に格納されている式と等価です.
x.min_val + sum(v * c for v, c in zip(x.vars, x.coeffs))
ネイティブ整数変数
ネイティブ整数変数は,整数値をそのまま保持する IntVar オブジェクトです.
Expr ではなく独立した型ですが,式の中で使うと自動的に Expr に変換されるため,
通常の変数と同じように書けます.詳しくは
ネイティブ整数変数を参照してください.
ネイティブ整数変数作成関数
qbpp.var("name", integer=(l, u)): 名前"name"・範囲[l, u]のネイティブ整数変数を作成します. 範囲の指定は必須で,l < uでなければなりません.qbpp.var("name", s1, s2, ..., integer=(l, u)): 同じ範囲[l, u]を持つネイティブ整数変数の配列を作成します. 各要素はname[i]・name[i][j]として表現され,x[i]・x[i, j](x(i, j)も可)でアクセスします.shape=キーワードも使えます.
ネイティブ整数変数のプロパティ
x.lo(プロパティ):xの最小値lを返します.x.hi(プロパティ):xの最大値uを返します.
配列 s には s.shape / s.ndim / s.total と,全要素の和を返す
s.sum() があります.
解 sol における値は sol(x) で取得し,sol.set(x, v) で設定します.
変換
qbpp.binarize(f): 式fに含まれるネイティブ整数変数をバイナリエンコーディングに展開した 新しいExprを返します.MIP ソルバーは整数変数を直接扱えるため, バイナリ変数専用の外部 QUBO ソルバーに渡すときに使います.