クイックリファレンス: 表示
注意 このページの出力例は参考として示すものです。最新版では出力の形式が異なっている可能性があります。 表示は人が読んで確かめるためのものなので、出力された文字列を計算処理に利用しないでください。 値が必要なときは
sol(x)やf(sol)などの関数で取り出してください(クイックリファレンス: 解)。
QUBO++ のほとんどのオブジェクトは、<< 演算子で std::cout に出力できます。
std::cout << obj << std::endl;
一覧
| オブジェクト | 表示の例 |
|---|---|
変数 qbpp::Var | x、~x、a[1] |
項 qbpp::Term | 2*x*y |
式 qbpp::Expr | -4 +3*x -2*y*z +~x |
| バイナリエンコードの整数変数 | v[0] +2*v[1] +2*v[2] |
ネイティブ整数変数 qbpp::IntVar | n |
| 比較演算子で作った制約式 | ペナルティ式の多項式 |
qbpp::cons()・qbpp::abs()・qbpp::relu() を含む式 | 目的関数の多項式に続けて 1 行に 1 つ |
制約の一覧 f.cons() | 100 * (x +y +z <= 2) |
f.violations(sol) の要素 | {value: 2, lower: 1, upper: 1, violation: 1, weight: 1, satisfied: false} |
配列 qbpp::Array | {a[0],a[1],a[2]} |
解 qbpp::Sol(ソルバーが返す解を含む) | 0:{{x[0],0},{x[1],0},{x[2],1},{n,3}} |
qbpp::CallbackEvent | CallbackEvent::BestUpdated |
変数・項・式
#include <qbpp/qbpp.hpp>
int main() {
auto x = qbpp::var("x");
auto y = qbpp::var("y");
auto z = qbpp::var("z");
auto a = qbpp::var("a", 3);
auto u = qbpp::var();
std::cout << x << std::endl;
std::cout << ~x << std::endl;
std::cout << a[1] << std::endl;
std::cout << u << std::endl;
std::cout << 2 * x * y << std::endl;
qbpp::Expr f = 3 * x - 2 * y * z + ~x - 4;
std::cout << f << std::endl;
}
このプログラムの出力は次のとおりです。
x
~x
a[1]
{0}
2*x*y
-4 +3*x -2*y*z +~x
- 名前を省略した変数(
qbpp::var())は{0}、{1}、… と表示されます。 - 式は定数項を先頭にして、項を作った順に並べます。2 番目以降の項は、空白のあとに符号(
+または-)を付けて続けます。 - 係数 1 は省略します。否定リテラルは
~xと表示されます。
簡約前と簡約後
式は作ったときの形のまま表示され、自動では簡約されません。 同類項をまとめた形で見るには、qbpp::simplify() や qbpp::simplify_as_binary() で簡約してから出力します。
#include <qbpp/qbpp.hpp>
int main() {
auto x = qbpp::var("x");
auto y = qbpp::var("y");
qbpp::Expr g = x * x + x * y + y * x + 1;
std::cout << g << std::endl;
std::cout << qbpp::simplify(g) << std::endl;
std::cout << qbpp::simplify_as_binary(g) << std::endl;
}
このプログラムの出力は次のとおりです。
1 +x*x +x*y +y*x
1 +x*x +2*x*y
1 +x +2*x*y
qbpp::simplify() は同類項をまとめ、qbpp::simplify_as_binary() はさらにバイナリ変数の性質(x*x = x)を使います。
整数変数
#include <qbpp/qbpp.hpp>
int main() {
auto x = qbpp::var("x");
auto v = 0 <= qbpp::var_int("v") <= 5;
auto n = 0 <= qbpp::int_var("n") <= 5;
std::cout << v << std::endl;
std::cout << n << std::endl;
qbpp::Expr f = 2 * n + x;
std::cout << f << std::endl;
std::cout << qbpp::binarize(f) << std::endl;
}
このプログラムの出力は次のとおりです。
v[0] +2*v[1] +2*v[2]
n
2*n +x
2*n#0 +4*n#1 +4*n#2 +x
- バイナリエンコードの整数変数は、値を表すバイナリ変数(
v[0]、v[1]、…)の式として表示されます(バイナリエンコードの整数変数)。 - ネイティブ整数変数は名前で表示されます(整数変数と連立方程式の求解)。
qbpp::binarize()がネイティブ整数変数を置き換えたバイナリ変数は、n#0、n#1、… と表示されます。
補助変数
QUBO++ が式を変換するときに加える変数は、波括弧で囲んだ名前で表示されます。
#include <qbpp/qbpp.hpp>
int main() {
auto x = qbpp::var("x");
auto y = qbpp::var("y");
auto z = qbpp::var("z");
std::cout << qbpp::reduce(x * y * z) << std::endl;
std::cout << qbpp::simplify_as_binary(x + y + z <= 2) << std::endl;
}
このプログラムの出力は次のとおりです。
{r0} +x*y +x*z -x*{r0} +y*z -y*{r0} -z*{r0}
2*{s1} +2*x*y +2*x*z -2*x*{s1} +2*y*z -2*y*{s1} -2*z*{s1}
{r0}のようにrで始まる名前:qbpp::reduce()が次数を下げるために加えた変数(HUBO の QUBO への変換){s1}のようにsで始まる名前: 比較演算子の制約式が加えたスラック変数(比較演算子)
番号は、加えた順に振られる通し番号です。
制約と非線形関数
比較演算子で作った制約式
比較演算子(==、<=、>=、範囲)で作った制約式は、ペナルティ式を展開した多項式として表示されます。 簡約前の形なので、qbpp::simplify_as_binary() を使うと短くなります。
#include <qbpp/qbpp.hpp>
int main() {
auto x = qbpp::var("x");
auto y = qbpp::var("y");
std::cout << (x + y == 1) << std::endl;
std::cout << qbpp::simplify_as_binary(x + y == 1) << std::endl;
}
このプログラムの出力は次のとおりです。
1 +x*x -2*x +2*x*y +y*y -2*y
1 -x -y +2*x*y
cons()・abs()・relu() を含む式
qbpp::cons()、qbpp::abs()、qbpp::relu() を含む式は、目的関数の多項式に続けて、それぞれを書いたときの形で 1 行に 1 つずつ表示されます。
#include <qbpp/qbpp.hpp>
int main() {
auto x = qbpp::var("x");
auto y = qbpp::var("y");
auto z = qbpp::var("z");
auto f = 3 * x + 100 * qbpp::cons(x + y + z <= 2) + qbpp::cons(x + y == 1);
std::cout << f << std::endl;
std::cout << qbpp::abs(x - y) + qbpp::relu(x + y - 1, 2) << std::endl;
std::cout << qbpp::cons(x + y + z == qbpp::equal{0, 2}) << std::endl;
std::cout << qbpp::cons(1 <= x + y + z <= 2) << std::endl;
std::cout << -5 * qbpp::cons(x + y == 1) << std::endl;
std::cout << qbpp::max(x, y) << std::endl;
}
このプログラムの出力は次のとおりです。
3*x
+100*cons(x +y +z <= 2)
+cons(x +y == 1)
abs(x -y, 1)
+relu(-1 +x +y, 2)
cons(x +y +z == {0, 2})
cons(1 <= x +y +z <= 2)
-5*cons(x +y == 1)
y
+relu(x -y, 1)
- 重み 1 は省略し、負の重みは行頭の符号で表します。目的関数の多項式が 0 のときは、その行は表示されません。
abs(f, k)・relu(f, k)の 2 番目の数は指数です(qbpp::abs(f)はabs(f, 1)、qbpp::abs(f, 2)はabs(f, 2)と表示されます)。qbpp::max()・qbpp::min()は、relu()やabs()を使った等しい式として表示されます。
詳しくは 非線形関数とネイティブ制約 を参照してください。
制約の一覧と違反
f.cons() は式に含まれる制約の一覧を、f.violations(sol) は解 sol での制約ごとの値と違反量を返します。どちらも出力できます。
#include <qbpp/qbpp.hpp>
int main() {
auto x = qbpp::var("x");
auto y = qbpp::var("y");
auto z = qbpp::var("z");
auto f = 3 * x + 100 * qbpp::cons(x + y + z <= 2) + qbpp::cons(x + y == 1);
std::cout << f.cons() << std::endl;
qbpp::Sol sol(f);
sol.set(x, 1);
sol.set(y, 1);
for (const auto& v : f.violations(sol)) {
std::cout << v << std::endl;
}
}
このプログラムの出力は次のとおりです。
100 * (x +y +z <= 2)
(x +y == 1)
{value: 2, lower: 0, upper: 2, violation: 0, weight: 100, satisfied: true}
{value: 2, lower: 1, upper: 1, violation: 1, weight: 1, satisfied: false}
配列
#include <qbpp/qbpp.hpp>
int main() {
auto a = qbpp::var("a", 3);
auto b = qbpp::var("b", 2, 3);
auto c = qbpp::array({1, 2, 3});
std::cout << a << std::endl;
std::cout << b << std::endl;
std::cout << b[1] << std::endl;
std::cout << a + 1 << std::endl;
std::cout << c << std::endl;
std::cout << qbpp::vector_sum(b) << std::endl;
}
このプログラムの出力は次のとおりです。
{a[0],a[1],a[2]}
{{b[0][0],b[0][1],b[0][2]},{b[1][0],b[1][1],b[1][2]}}
{b[1][0],b[1][1],b[1][2]}
{1 +a[0],1 +a[1],1 +a[2]}
{1,2,3}
{b[0][0] +b[0][1] +b[0][2],b[1][0] +b[1][1] +b[1][2]}
- 配列は要素を
,で区切り、{と}で囲んで表示されます。多次元配列は入れ子になります。 b[1]のような部分配列も同じ形式で表示されます。
解
#include <qbpp/qbpp.hpp>
#include <qbpp/exhaustive_solver.hpp>
int main() {
auto x = qbpp::var("x", 3);
auto n = 0 <= qbpp::int_var("n") <= 5;
auto f = qbpp::sqr(qbpp::sum(x) - 1) + 3 * x[0] + 2 * x[1] + qbpp::sqr(n - 3);
f.simplify_as_binary();
auto sol = qbpp::ExhaustiveSolver(f).search();
std::cout << sol << std::endl;
std::cout << sol(x) << std::endl;
std::cout << sol(n) << std::endl;
qbpp::Sol s(sol);
s.set(x[0], 1);
s.set(n, 5);
std::cout << s << std::endl;
}
このプログラムの出力は次のとおりです。
0:{{x[0],0},{x[1],0},{x[2],1},{n,3}}
{0,0,1}
3
8:{{x[0],1},{x[1],0},{x[2],1},{n,5}}
- 解は
エネルギー:{{変数,値},...}の形式で表示されます。バイナリ変数のあとに、ネイティブ整数変数が並びます。 sol.set()で値を変えた解は、その割り当てのエネルギーを計算して表示します。- ソルバー情報
sol.info("var_count")などの値は文字列です(クイックリファレンス: 解)。
ソルバーが集めた複数の解(sol.sols)は、1 つずつ出力します。
#include <qbpp/qbpp.hpp>
#include <qbpp/exhaustive_solver.hpp>
int main() {
auto x = qbpp::var("x", 3);
auto f = qbpp::sqr(qbpp::sum(x) - 1) + 3 * x[0] + 2 * x[1];
f.simplify_as_binary();
auto sol = qbpp::ExhaustiveSolver(f).search({{"topk_sols", 3}});
for (const auto& s : sol.sols) {
std::cout << s << std::endl;
}
}
このプログラムの出力は次のとおりです。
0:{{x[0],0},{x[1],0},{x[2],1}}
1:{{x[0],0},{x[1],0},{x[2],0}}
2:{{x[0],0},{x[1],1},{x[2],0}}
実数係数
DOUBLE_TYPE などで実数(double)係数を使うと、係数は元の値を正確に表せる最短の 10 進数で表示されます。 10 の指数が −4 以上 16 未満なら小数表記(2500、1.5、0.1)、それ以外は指数表記(1e+20、1e-07)です。 整数の値には小数点を付けません。
#define DOUBLE_TYPE
#include <qbpp/qbpp.hpp>
int main() {
auto x = qbpp::var("x");
auto y = qbpp::var("y");
auto z = qbpp::var("z");
qbpp::Expr f = 100 * x + 2500 * y + 1.5 * z;
std::cout << f << std::endl;
qbpp::Expr g = 0.1 * x - 1e-7 * y + 1e20 * z;
std::cout << g << std::endl;
}
このプログラムの出力は次のとおりです。
100*x +2500*y +1.5*z
0.1*x -1e-07*y +1e+20*z
ソルバーが実際に解く整数係数の式は、qbpp::quantize() の結果を出力すると確かめられます(変数と式のデータ型)。
コールバックのイベント
ABS3 Solver のコールバックで使う qbpp::CallbackEvent も出力できます(ABS3 Solver の使い方)。
#include <qbpp/qbpp.hpp>
#include <qbpp/abs3_solver.hpp>
int main() {
std::cout << qbpp::CallbackEvent::BestUpdated << std::endl;
}
このプログラムの出力は次のとおりです。
CallbackEvent::BestUpdated
出力できないオブジェクト
- ソルバー(
qbpp::EasySolver、qbpp::ExhaustiveSolver、qbpp::ABS3Solver)と探索パラメータqbpp::Paramsは出力できません。 - ソルバーが集めた解のリスト
sol.sols(std::vector<qbpp::Sol>)はそのままでは出力できないので、上の例のようにループで 1 つずつ出力します。
Python 版との違い
C++ と Python では、それぞれの言語の慣習に合わせて一部の書式が異なります。
| オブジェクト | C++ | Python |
|---|---|---|
| 配列 | {a[0],a[1],a[2]} | [a[0], a[1], a[2]] |
| 解 | 0:{{x,0},{y,1}} | Sol(energy=0, {x: 0, y: 1}) |
violations() の要素 | {value: 2, ..., satisfied: false} | 辞書 {'value': 2, ..., 'satisfied': False} |
CallbackEvent | CallbackEvent::BestUpdated | CallbackEvent.BestUpdated |
| ソルバー | 出力できない | <... object at 0x...> |