式の評価
qbpp::Maplist を使用した評価
式の評価は、変数とその値のペアのリストとして、すべての要素に値を割り当てることで簡単に実行できます。
リストqbpp::MapListはオブジェクトとして定義できます。
たとえば、次のプログラムは $(x,y,z)=(0,1,1)$ に対する関数 $f(x,y,z)$ を計算します。
#include "qbpp.hpp"
int main() {
auto x = qbpp::var("x");
auto y = qbpp::var("y");
auto z = qbpp::var("z");
auto f = qbpp::sqr(x + 2 * y + 3 * z - 3);
qbpp::MapList ml;
ml.push_back({x, 0});
ml.push_back({y, 1});
ml.push_back({z, 1});
std::cout << ml << std::endl;
std::cout << "f(0,1,1) = " << f(ml) << std::endl;
}
このプログラムでは、 qbpp::MapList オブジェクト ml が定義され、
値の割り当て {x, 0}, {y, 1} と {z, 1} が追加されます。 ml。
次に f(ml) $f(0,1,1)$の値を返す。
このプログラムは以下の出力を表示する:
{{x,0},{y,1},{z,1}}
f(0,1,1) = 4
あるいは、次のように直接代入を指定することもできます:
#include "qbpp.hpp"
int main() {
auto x = qbpp::var("x");
auto y = qbpp::var("y");
auto z = qbpp::var("z");
auto f = qbpp::sqr(x + 2 * y + 3 * z - 3);
std::cout << "f(0,1,1) = " << f({{x, 0}, {y, 1}, {z, 1}}) << std::endl;
}
qbpp::Sol を使用した評価
ソリューションオブジェクト (qbpp::Sol) を使用して式 (qbpp::Expr) の値を評価できます。
これを行うには、まず qbpp::Sol オブジェクト sol を構築します f。
新しく作成されたqbpp::Sol オブジェクトは、すべてゼロの代入で初期化されます。
sol のset()メンバ関数 qbpp::Solを使用すると、個々の変数に値を代入できます。
その後、solに格納された代入条件のもとで、f式の評価値をsol(f)f(sol)solおよびsolが返します。
さらに、solcomp_energy()のメンバ関数は同じ値を計算して返します。
#include "qbpp.hpp"
int main() {
auto x = qbpp::var("x");
auto y = qbpp::var("y");
auto z = qbpp::var("z");
auto f = qbpp::sqr(x + 2 * y + 3 * z - 3);
qbpp::Sol sol(f);
sol.set(y, 1);
sol.set(z, 1);
std::cout << "f(0,1,1) = " << f(sol) << std::endl;
std::cout << "f(0,1,1) = " << sol(f) << std::endl;
std::cout << "f(0,1,1) = " << sol.comp_energy() << std::endl;
}
なお、ソリューションオブジェクトのメンバcomp_energy()関数 sol はエネルギー値を計算し内部でキャッシュします。
また、ソルバーから返される解オブジェクトは既にエネルギー値が計算・キャッシュ済みです。
再計算せずにエネルギーを取得するには、以下に示すメンバー関数を使用できますenergy():
#include "qbpp.hpp"
#include "qbpp_easy_solver.hpp"
int main() {
auto x = qbpp::var("x");
auto y = qbpp::var("y");
auto z = qbpp::var("z");
auto f = qbpp::sqr(x + 2 * y + 3 * z - 4);
f.simplify_as_binary();
auto solver = qbpp::easy_solver::EasySolver(f);
solver.target_energy(0);
auto sol = solver.search();
std::cout << "sol = " << sol << std::endl;
std::cout << "energy = " << sol.energy() << std::endl;
sol.flip(z);
std::cout << "flipped sol = " << sol << std::endl;
std::cout << "flipped energy = " << sol.energy() << std::endl;
}
このプログラムでは、 sol.energy() は正しく 0 を返します。
しかし、変数 zを反転させた後、キャッシュされたエネルギー値は無効になります。
エネルギーを再計算せずに sol.energy() を呼び出すと、以下に示すようにランタイムエラーが発生します:
sol = 0:{{x,1},{y,0},{z,1}}
energy = 0
terminate called after throwing an instance of 'std::runtime_error'
この問題を解決するには、ソリューションを変更した後、sol.comp_energy()以下のように明示的にエネルギーを再計算する必要があります:
std::cout << "sol = " << sol << std::endl;
std::cout << "energy = " << sol.energy() << std::endl;
sol.flip(z);
std::cout << "sol.comp_energy() = " << sol.comp_energy() << std::endl;
std::cout << "flipped sol = " << sol << std::endl;
std::cout << "flipped energy = " << sol.energy() << std::endl;
このプログラムは次の出力を生成します:
sol = 0:{{x,1},{y,0},{z,1}}
energy = 0
sol.comp_energy() = 9
flipped sol = 9:{{x,1},{y,0},{z,0}}
flipped energy = 9