18 #define VERSION "2025-01-15" 
   20 #include <tbb/blocked_range.h> 
   21 #include <tbb/parallel_for.h> 
   22 #include <tbb/parallel_reduce.h> 
   23 #include <tbb/parallel_sort.h> 
   26 #include <boost/container/small_vector.hpp> 
   27 #include <boost/container/static_vector.hpp> 
   28 #include <boost/endian/conversion.hpp> 
   29 #include <boost/multi_array.hpp> 
   30 #include <boost/multiprecision/cpp_int.hpp> 
   33 #include <initializer_list> 
   44 #include <type_traits> 
   45 #include <unordered_map> 
   46 #include <unordered_set> 
   78 template <
typename... Args>
 
   79 std::string 
file_line(
const char *file, 
int line, Args... args) {
 
   80   std::ostringstream oss;
 
   81   oss << file << 
"(" << line << 
") ";
 
   86 #define THROW_MESSAGE(...) file_line(__FILE__, __LINE__, __VA_ARGS__) 
   88 #define TERM_CAPACITY 4 
   96 using Vars = boost::container::small_vector<Var, 2>;
 
   99 using Vars = boost::container::static_vector<Var, MAXDEG>;
 
  115 #define COEFF_TYPE int32_t 
  119 #define ENERGY_TYPE int64_t 
  134 using MapList = std::list<std::pair<std::variant<Var, VarInt>, 
Expr>>;
 
  136 using MapDict = std::unordered_map<Var, Expr, impl::var_hash>;
 
  138 using VarValMap = std::unordered_map<Var, var_val_t, impl::var_hash>;
 
  140 using VarIndexMap = std::unordered_map<Var, vindex_t, impl::var_hash>;
 
  142 using VarExprMap = std::unordered_map<Var, Expr, impl::var_hash>;
 
  144 using VarsCoeffMap = std::unordered_map<Vars, coeff_t, impl::vars_hash>;
 
  161 Var var(
const std::string &var_str);
 
  165 std::string 
str(
const char *param);
 
  166 std::string 
str(
const Vars &vars);
 
  167 std::string 
str(
const Term &term);
 
  169 std::string 
str(
const Model &model);
 
  171 std::string 
str(
const Sol &sol);
 
  192 template <
typename T>
 
  194 template <
typename T>
 
  204 template <
typename T>
 
  206 template <
typename T>
 
  210 template <
typename T>
 
  212 template <
typename T>
 
  222 template <
typename T>
 
  225 template <
typename T>
 
  235 inline std::string 
str(int8_t val) {
 
  236   return std::to_string(
static_cast<int32_t
>(val));
 
  239 template <
typename T>
 
  240 auto str(
const T &val) -> decltype(std::to_string(val)) {
 
  241   return std::to_string(val);
 
  244 template <
typename T>
 
  245 auto str(T val) -> decltype(val.str()) {
 
  249 template <
typename T>
 
  251   return val < 0 ? -val : val;
 
  257   if (a == 0) 
return b;
 
  258   if (b == 0) 
return a;
 
  289 template <
typename T>
 
  293   template <
typename U, 
typename Op>
 
  296       throw std::out_of_range(
 
  299     tbb::parallel_for(tbb::blocked_range<size_t>(0, 
size()),
 
  300                       [&](
const tbb::blocked_range<size_t> &range) {
 
  301                         for (
size_t i = range.begin(); i < range.end(); ++i) {
 
  302                           operation((*this)[i], rhs[i]);
 
  303                           (*this)[i] = static_cast<T>((*this)[i]);
 
  309   template <
typename U, 
typename Op>
 
  311     if (
size() != rhs.size()) {
 
  312       throw std::out_of_range(
 
  316     tbb::parallel_for(tbb::blocked_range<size_t>(0, 
size()),
 
  317                       [&](
const tbb::blocked_range<size_t> &range) {
 
  318                         for (
size_t i = range.begin(); i < range.end(); ++i) {
 
  319                           operation((*this)[i], std::move(rhs[i]));
 
  320                           (*this)[i] = static_cast<T>((*this)[i]);
 
  327   template <
typename Op>
 
  329     tbb::parallel_for(tbb::blocked_range<size_t>(0, 
size()),
 
  330                       [&](
const tbb::blocked_range<size_t> &range) {
 
  331                         for (
size_t i = range.begin(); i < range.end(); ++i) {
 
  332                           operation((*this)[i], rhs);
 
  354   template <
typename U, 
typename = 
typename std::enable_if<
 
  355                             std::is_integral<U>::value>::type>
 
  358   template <
typename U, 
typename = 
typename std::enable_if<
 
  359                             !std::is_integral<U>::value>::type>
 
  362   template <
typename U>
 
  365     tbb::parallel_for(
size_t(0), rhs.
size(),
 
  366                       [&](
size_t i) { data_[i] = rhs[i]; });
 
  395   typename std::vector<T>::iterator 
erase(
 
  396       typename std::vector<T>::iterator pos) {
 
  397     return data_.erase(pos);
 
  400   typename std::vector<T>::iterator 
erase(
 
  401       typename std::vector<T>::iterator first,
 
  402       typename std::vector<T>::iterator last) {
 
  403     return data_.erase(first, last);
 
  408     tbb::parallel_for(
size_t(0), 
size(), [&](
size_t i) { (*this)[i] = rhs; });
 
  413     tbb::parallel_for(
size_t(0), 
size(), [&](
size_t i) { (*this)[i] = rhs; });
 
  417   template <
typename U>
 
  422   template <
typename U>
 
  425                             [](T &lhs_elem, U rhs_elem) 
mutable {
 
  426                               lhs_elem += std::move(rhs_elem);
 
  430   template <
typename U>
 
  435   template <
typename U>
 
  438                             [](T &lhs_elem, U rhs_elem) 
mutable {
 
  439                               lhs_elem -= std::move(rhs_elem);
 
  443   template <
typename U>
 
  448   template <
typename U>
 
  451                             [](T &lhs_elem, U rhs_elem) 
mutable {
 
  452                               lhs_elem *= std::move(rhs_elem);
 
  458                             [](T &elem, 
const Expr &rhs) { elem += rhs; });
 
  463                             [](T &elem, 
const Expr &rhs) { elem -= rhs; });
 
  468                             [](T &elem, 
const Expr &rhs) { elem *= rhs; });
 
  472     tbb::parallel_for(tbb::blocked_range<size_t>(0, 
size()),
 
  473                       [&](
const tbb::blocked_range<size_t> &range) {
 
  474                         for (
size_t i = range.begin(); i < range.end(); ++i) {
 
  540   size_t size()
 const { 
return 1; }
 
  559     static std::mutex mutex_;
 
  560     static VarSet singleton_var_set;
 
  561     std::lock_guard<std::mutex> lock(mutex_);
 
  562     return singleton_var_set;
 
  569   static Var var(
const std::string &var_str) {
 
  570     static std::mutex mutex_;
 
  571     std::lock_guard<std::mutex> lock(mutex_);
 
  574     return Var(new_index);
 
  578     static std::mutex mutex_;
 
  579     std::lock_guard<std::mutex> lock(mutex_);
 
  678     return *
this < term || *
this == term;
 
  695     if constexpr (std::is_integral<coeff_t>::value) {
 
  697         throw std::runtime_error(
 
  746     terms_.reserve(term_capacity);
 
  752   template <
typename T,
 
  753             typename std::enable_if<std::is_convertible<T, energy_t>::value,
 
  757     terms_.reserve(term_capacity);
 
  763     terms_.reserve(term_capacity);
 
  768     terms_.reserve(term_capacity);
 
  769     terms_.push_back(std::move(term));
 
  800   template <
typename T,
 
  801             typename std::enable_if<std::is_convertible<T, energy_t>::value,
 
  809       if (
terms_.size() < 1000) {
 
  811           t *= 
static_cast<coeff_t>(val);
 
  814         tbb::parallel_for(
size_t(0), 
terms_.size(), [&](
size_t i) {
 
  815           terms_[i] *= static_cast<coeff_t>(val);
 
  826     if (
terms_.size() < 1000) {
 
  831       tbb::parallel_for(
size_t(0), 
terms_.size(),
 
  832                         [&](
size_t i) { terms_[i] *= term; });
 
  849       tbb::parallel_for(
size_t(0), 
terms_.size(), [&](
size_t i) {
 
  850         terms_[i] *= static_cast<coeff_t>(expr.constant_);
 
  859     const Expr &expr_small =
 
  861     const Expr &expr_large =
 
  868     if (total_terms < 1000) {
 
  869       result.
terms_.reserve(total_terms);
 
  870       for (
const auto &term1 : expr_large.
terms_) {
 
  871         for (
const auto &term2 : expr_small.
terms_) {
 
  872           result.
terms_.push_back(term1 * term2);
 
  877         for (
const auto &term : expr_small.
terms_) {
 
  884         for (
const auto &term : expr_large.
terms_) {
 
  888       *
this = std::move(result);
 
  892     result.
terms_.resize(total_terms);
 
  893     tbb::parallel_for(
size_t(0), expr_large.
term_count(), [&](
size_t i) {
 
  894       for (size_t j = 0; j < expr_small.term_count(); ++j) {
 
  895         result.terms_[i * expr_small.term_count() + j] =
 
  896             expr_large.terms_[i] * expr_small.terms_[j];
 
  900     if (expr_large.constant_ != 0) {
 
  901       result.terms_.resize(total_terms + expr_small.term_count());
 
  902       tbb::parallel_for(
size_t(0), expr_small.term_count(), [&](
size_t i) {
 
  903         result.terms_[total_terms + i] =
 
  904             expr_small.terms_[i] * expr_large.constant_;
 
  906       total_terms += expr_small.term_count();
 
  909     if (expr_small.constant_ != 0) {
 
  910       result.terms_.resize(total_terms + expr_large.term_count());
 
  911       tbb::parallel_for(
size_t(0), expr_large.term_count(), [&](
size_t i) {
 
  912         result.terms_[total_terms + i] =
 
  913             expr_large.terms_[i] * expr_small.constant_;
 
  917     *
this = std::move(result);
 
  924     terms_.insert(terms_.end(), expr2.terms_.begin(), expr2.terms_.end());
 
  930     *
this += std::move(expr2);
 
  936       throw std::runtime_error(
THROW_MESSAGE(
"Division by zero."));
 
  938     tbb::parallel_for(
size_t(0), terms_.size(),
 
  939                       [&](
size_t i) { terms_[i] /= val; });
 
  940     if ((constant_ / val) * val != constant_) {
 
  941       throw std::runtime_error(
THROW_MESSAGE(
"Indivisible division occurred."));
 
  974   size_t size()
 const { 
return term_count(); }
 
  982     return result.
replace(map_list);
 
  999     for (
const auto &term : temp.
terms_) {
 
 1000       if (term.get_coeff() > 0) {
 
 1001         sum += term.get_coeff();
 
 1010     for (
const auto &term : temp.
terms_) {
 
 1011       if (term.get_coeff() < 0) {
 
 1012         sum += term.get_coeff();
 
 1023   explicit VarIntCore(
const std::string &var_str) : var_str_(var_str) {}
 
 1040     if (coeffs_ptr_->size() == 1) {
 
 1043       for (
size_t i = 0; i < coeffs_ptr_->size(); i++) {
 
 1044         vars.
push_back(
var(var_str_ + 
"[" + std::to_string(i) + 
"]"));
 
 1051     Expr result = min_val_;
 
 1052     for (
size_t i = 0; i < coeffs_ptr_->size(); i++) {
 
 1053       result += 
Term(vars_[i], (*coeffs_ptr_)[i]);
 
 1060          std::shared_ptr<std::vector<coeff_t>> coeffs_ptr)
 
 1061       : var_str_(var_str),
 
 1064         coeffs_ptr_(coeffs_ptr),
 
 1066         expr_(new_expr()) {}
 
 1087     if (val < min_val_ || val > max_val_) {
 
 1088       throw std::out_of_range(
 
 1093     for (
size_t i = var_count(); i >= 1; i--) {
 
 1094       if (val >= (*coeffs_ptr_)[
static_cast<size_t>(i) - 1]) {
 
 1095         result[vars_[i - 1]] = 1;
 
 1096         val -= (*coeffs_ptr_)[i - 1];
 
 1098         result[vars_[i - 1]] = 0;
 
 1116           "The expression must be simplified to be a QUBO expression."));
 
 1122       return std::move(
expr);
 
 1125           "The expression must be simplified to be a QUBO expression."));
 
 1137       : expr_ptr_(model.expr_ptr_), index_var_ptr_(model.index_var_ptr_) {}
 
 1141       : expr_ptr_(std::make_shared<const 
Expr>(
expr)),
 
 1143             std::make_shared<const impl::IndexVarMapper>(*expr_ptr_)) {}
 
 1148       : expr_ptr_(std::make_shared<const Expr>(std::move(
expr))),
 
 1150             std::make_shared<const impl::IndexVarMapper>(*expr_ptr_)) {}
 
 1162   virtual size_t term_count()
 const { 
return expr_ptr_->term_count(); }
 
 1166   operator const Expr &() 
const { 
return *expr_ptr_; }
 
 1173     return index_var_ptr_->get_index_var();
 
 1186     std::vector<std::vector<std::pair<vindex_t, coeff_t>>> 
quadratic_;
 
 1201   const std::vector<std::vector<std::pair<vindex_t, coeff_t>>> &
quadratic_;
 
 1215         pimpl_(std::make_shared<
Impl>(model)),
 
 1216         linear_(pimpl_->linear_),
 
 1217         degree_(pimpl_->degree_),
 
 1218         quadratic_(pimpl_->quadratic_) {}
 
 1221       : 
Model(std::move(model)),
 
 1222         pimpl_(std::make_shared<
Impl>(*this)),
 
 1223         linear_(pimpl_->linear_),
 
 1224         degree_(pimpl_->degree_),
 
 1225         quadratic_(pimpl_->quadratic_) {}
 
 1229         pimpl_(std::make_shared<
Impl>(
Impl(*this))),
 
 1230         linear_(pimpl_->linear_),
 
 1231         degree_(pimpl_->degree_),
 
 1232         quadratic_(pimpl_->quadratic_) {}
 
 1236         pimpl_(std::make_shared<
Impl>(
Impl(*this))),
 
 1237         linear_(pimpl_->linear_),
 
 1238         degree_(pimpl_->degree_),
 
 1239         quadratic_(pimpl_->quadratic_) {}
 
 1241   const std::vector<coeff_t> &
get_linear()
 const { 
return linear_; }
 
 1243   const std::vector<vindex_t> &
get_degree()
 const { 
return degree_; }
 
 1255     return quadratic_[i][j];
 
 1260       return linear_.size();
 
 1261     } 
else if (deg == 2) {
 
 1262       return std::accumulate(degree_.begin(), degree_.end(), 0UL);
 
 1286       : bit_count_(bit_count),
 
 1287         size64_((bit_count + 63) / 64),
 
 1288         bits_(std::make_unique<uint64_t[]>(size64_)) {}
 
 1291       : bit_count_(bit_vector.bit_count_),
 
 1292         size64_(bit_vector.size64_),
 
 1293         bits_(std::make_unique<uint64_t[]>(size64_)) {
 
 1294     std::copy(bit_vector.
bits_.get(), bit_vector.
bits_.get() + size64_,
 
 1299       : bit_count_(bit_vector.bit_count_),
 
 1300         size64_(bit_vector.size64_),
 
 1301         bits_(std::move(bit_vector.bits_)) {};
 
 1304     if (
this == &bit_vector) {
 
 1307     if (size64_ != bit_vector.
size64_) {
 
 1308       throw std::runtime_error(
 
 1311     std::copy(bit_vector.
bits_.get(), bit_vector.
bits_.get() + size64_,
 
 1317     if (
this == &bit_vector) {
 
 1320     if (size64_ != bit_vector.
size64_) {
 
 1321       throw std::runtime_error(
 
 1324     bits_ = std::move(bit_vector.
bits_);
 
 1329     if (
this == &bit_vector) {
 
 1332     if (bit_count_ != bit_vector.bit_count_) {
 
 1333       throw std::runtime_error(
 
 1336     bits_ = std::move(bit_vector.bits_);
 
 1342       throw std::runtime_error(
 
 1345     return std::equal(bits_.get(), bits_.get() + size64_,
 
 1346                       bit_vector.
bits_.get());
 
 1354     auto reverse_bits = [](uint64_t n) -> uint64_t {
 
 1355 #if defined(__has_builtin) 
 1356 #if __has_builtin(__builtin_bitreverse64) 
 1357       return __builtin_bitreverse64(n);
 
 1360       n = ((n >> 1) & 0x5555555555555555) | ((n & 0x5555555555555555) << 1);
 
 1361       n = ((n >> 2) & 0x3333333333333333) | ((n & 0x3333333333333333) << 2);
 
 1362       n = ((n >> 4) & 0x0f0f0f0f0f0f0f0f) | ((n & 0x0f0f0f0f0f0f0f0f) << 4);
 
 1363       n = ((n >> 8) & 0x00ff00ff00ff00ff) | ((n & 0x00ff00ff00ff00ff) << 8);
 
 1364       n = ((n >> 16) & 0x0000ffff0000ffff) | ((n & 0x0000ffff0000ffff) << 16);
 
 1365       n = ((n >> 32) & 0x00000000ffffffff) | ((n & 0x00000000ffffffff) << 32);
 
 1368     for (
vindex_t i = 0; i < size64_; i++) {
 
 1369       if (reverse_bits(bits_[i]) < reverse_bits(bit_vector.
bits_[i]))
 
 1371       if (reverse_bits(bits_[i]) > reverse_bits(bit_vector.
bits_[i]))
 
 1382     if (index >= bit_count_) {
 
 1383       throw std::out_of_range(
THROW_MESSAGE(
"Index out of range."));
 
 1385     return bits_[index / 64] & (1ULL << (index % 64));
 
 1389     if (index >= bit_count_) {
 
 1390       throw std::out_of_range(
THROW_MESSAGE(
"Index out of range."));
 
 1393       bits_[index / 64] |= 1ULL << (index % 64);
 
 1395       bits_[index / 64] &= ~(1ULL << (index % 64));
 
 1399     if (index >= bit_count_) {
 
 1400       throw std::out_of_range(
THROW_MESSAGE(
"Index out of range."));
 
 1402     bits_[index / 64] ^= 1ULL << (index % 64);
 
 1406     if (index64 >= size64_) {
 
 1407       throw std::out_of_range(
THROW_MESSAGE(
"Index out of range."));
 
 1409     return bits_[index64];
 
 1413     if (index64 >= size64_) {
 
 1414       throw std::out_of_range(
THROW_MESSAGE(
"Index out of range."));
 
 1416     if (index64 < size64_ - 1 || index64 * 64 == bit_count_)
 
 1417       return bits_[index64] = value;
 
 1419       return bits_[index64] = value & ((1ULL << (bit_count_ % 64)) - 1);
 
 1422   void clear() { std::fill(bits_.get(), bits_.get() + size64_, 0); }
 
 1426     for (
vindex_t i = 0; i < size64_; i++) {
 
 1427       count += 
static_cast<vindex_t>(__builtin_popcountll(bits_[i]));
 
 1434     for (
vindex_t i = 0; i < bit_count_; i++) {
 
 1435       result += get(i) ? 
"1" : 
"0";
 
 1448   mutable std::optional<energy_t> energy_ = std::nullopt;
 
 1463       : quad_model_(quad_model),
 
 1464         bit_vector_(quad_model.var_count()),
 
 1465         energy_(quad_model.get_constant()) {}
 
 1482     bit_vector_ = std::move(sol.bit_vector_);
 
 1483     energy_ = std::move(sol.energy_);
 
 1488     if (get_energy() != sol.
get_energy()) 
return false;
 
 1492     if (get_energy() < sol.
get_energy()) 
return true;
 
 1509     bit_vector_.
clear();
 
 1513   template <
typename T>
 
 1517     for (
const auto &elem : vec) {
 
 1518       result.push_back(get(elem));
 
 1525     bit_vector_.
set(index, value);
 
 1535     bit_vector_.
flip(index);
 
 1546     if (!energy_) energy_ = comp_energy();
 
 1564   operator MapList()
 const { 
return get_map_list(); }
 
 1575     for (
const auto &[
var, val] : var_val_map) {
 
 1585   std::optional<energy_t> bound_ = std::nullopt;
 
 1588   std::string solver_ = 
"N/A";
 
 1601                                               const std::string &solver = 
"") {
 
 1603       return std::nullopt;
 
 1605     std::lock_guard<std::mutex> lock(mtx_);
 
 1610       return std::make_optional(tts_);
 
 1612       return std::nullopt;
 
 1617     if (sol_.
get_energy() >= my_energy) 
return std::nullopt;
 
 1618     std::lock_guard<std::mutex> lock(mtx_);
 
 1622       return std::nullopt;
 
 1631     std::lock_guard<std::mutex> lock(mtx_);
 
 1632     return std::make_tuple(sol_, tts_, solver_);
 
 1642     std::lock_guard<std::mutex> lock(mtx_);
 
 1647     std::lock_guard<std::mutex> lock(mtx_);
 
 1659   std::optional<energy_t> 
get_bound()
 const { 
return bound_; }
 
 1661   operator Sol()
 const { 
return sol_; }
 
 1667                             std::function<std::string(
Var)> 
str) {
 
 1669   for (
const auto &item : vars) {
 
 1670     if (!result.empty()) {
 
 1673     result += 
str(item);
 
 1679                             std::function<std::string(
Var)> 
str) {
 
 1691                             std::function<std::string(
Var)> 
str) {
 
 1694   if (
expr.get_constant() != 0) {
 
 1697   } 
else if (
expr.term_count() == 0)
 
 1699   for (
const auto &term : 
expr.get_terms()) {
 
 1724     result += bit_vector.
get(i) ? 
"1" : 
"0";
 
 1730 inline std::string 
str(
const char *param) {
 
 1731   std::string param_str(param);
 
 1732   if (param_str == 
"compilation_date") {
 
 1734   } 
else if (param_str == 
"author") {
 
 1735     return "Koji Nakano";
 
 1736   } 
else if (param_str == 
"version") {
 
 1738   } 
else if (param_str == 
"license") {
 
 1739     return "QUBO++: Only for non-commercial use, evaluation, and research " 
 1740            "purposes with no warranties. Redistribution is strictly " 
 1742   } 
else if (param_str == 
"all_vars") {
 
 1744     for (
vindex_t i = 0; i < impl::VarSet::get_instance().all_var_count();
 
 1746       result += 
"{" + std::to_string(i) + 
"," + 
str(
Var(i)) + 
"}";
 
 1750     throw std::runtime_error(
 
 1751         THROW_MESSAGE(
"Unknown parameter (", param, 
") for str()."));
 
 1763                        const std::string &separator [[maybe_unused]] = 
",") {
 
 1767     return "{" + prefix + 
"," +
 
 1773   auto str = [&model](
Var var) -> std::string {
 
 1774     return "<" + std::to_string(model.
get_index(
var)) + 
">";
 
 1780   auto str = [&quad_model](
Var var) -> std::string {
 
 1791       else if (coeff == -1)
 
 1794         result += 
" +" + 
qbpp::str(coeff) + 
"*";
 
 1805   std::ostringstream oss;
 
 1809   for (
const auto &[key, val] : map_list) {
 
 1815     auto str_val = 
str(val);
 
 1817         [&](
const auto &arg) {
 
 1818           using T = std::decay_t<decltype(arg)>;
 
 1820           if constexpr (std::is_same_v<T, VarInt>) {
 
 1821             oss << arg.get_name();
 
 1825           oss << 
"," << str_val << 
"}";
 
 1838 template <
typename T>
 
 1840                 const std::string &separator = 
",") {
 
 1842   for (
size_t i = 0; i < vec.
size(); i++) {
 
 1843     result += 
str(vec[i], prefix + 
"[" + 
qbpp::str(i) + 
"]", separator);
 
 1844     if (i < vec.
size() - 1) result += separator;
 
 1858   return os << 
str(term);
 
 1866   return os << 
str(model);
 
 1870   return os << 
str(quad_model);
 
 1874   return os << 
str(map_list);
 
 1878   return os << 
str(sol);
 
 1881 template <
typename T>
 
 1887 template <
typename T>
 
 1889                          const std::pair<std::string, 
Vector<T>> &vec) {
 
 1890   os << 
str(vec.second, vec.first);
 
 1897   if (
expr.get_constant() != 0)
 
 1899   auto it = 
expr.get_terms().begin();
 
 1900   result += 
str(*it) + 
" + ";
 
 1902   result += 
str(*it) + 
" + ... + ";
 
 1903   it = 
expr.get_terms().end();
 
 1906   result += 
str(*it) + 
" + ";
 
 1915 inline size_t var_hash::operator()(
const Var var)
 const {
 
 1916   std::hash<vindex_t> hasher;
 
 1917   return hasher(
var.get_index());
 
 1920 inline size_t vars_hash::operator()(
const Vars &vars)
 const {
 
 1921   std::hash<vindex_t> hasher;
 
 1923   for (
const auto &item : vars) {
 
 1924     seed ^= hasher(item.get_index()) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
 
 1932 template <
typename T>
 
 1934   return lhs - rhs == 0;
 
 1937 template <
typename T>
 
 1938 Expr equal(
const std::vector<T> &lhs, 
const std::vector<T> &rhs) {
 
 1939   if (lhs.size() != rhs.size()) {
 
 1940     throw std::runtime_error(
THROW_MESSAGE(
"Vector dimension mismatch"));
 
 1943   for (
size_t i = 0; i < lhs.size(); i++) {
 
 1944     result += 
equal(lhs[i], rhs[i]);
 
 1965     : constant_(
var_int.get_expr().get_constant()),
 
 1966       terms_(
var_int.get_expr().get_terms()) {
 
 1968     throw std::runtime_error(
 
 1969         THROW_MESSAGE(
"Wrong VarInt object. Max value is not specified."));
 
 1974     : constant_(
var_int.get_expr().get_constant()),
 
 1975       terms_(std::move(
var_int.get_expr().get_terms())) {
 
 1977     throw std::runtime_error(
 
 1978         THROW_MESSAGE(
"Wrong VarInt object. Max value is not specified."));
 
 1985   for (
const auto &[key, val] : map_list) {
 
 1986     if (val.term_count() >= 1) {
 
 1987       throw std::runtime_error(
THROW_MESSAGE(
"Value must be an integer."));
 
 1989     auto constant = val.get_constant();
 
 1992           using T = std::decay_t<decltype(arg)>;
 
 1993           if constexpr (std::is_same_v<T, VarInt>) {
 
 1994             for (
const auto &[
var, bin_val] :
 
 1995                  arg.get_val_map(
static_cast<coeff_t>(constant))) {
 
 1996               var_int_map[
var] = bin_val;
 
 1999             var_int_map[arg] = 
static_cast<var_val_t>(constant);
 
 2009   for (
const auto &[key, val] : map_list) {
 
 2010     auto val_local = val;
 
 2013           using T = std::decay_t<decltype(arg)>;
 
 2014           if constexpr (std::is_same_v<T, VarInt>) {
 
 2015             if (val_local.term_count() >= 1) {
 
 2016               throw std::runtime_error(
 
 2019             for (
const auto &[
var, bin_val] : arg.get_val_map(
 
 2020                      static_cast<coeff_t>(val_local.get_constant()))) {
 
 2021               map_dict[
var] = bin_val;
 
 2024             map_dict[arg] = val_local;
 
 2034   for (
auto item : term.
get_vars()) {
 
 2035     auto it = map_dict.find(item);
 
 2036     if (it == map_dict.end()) {
 
 2039       result *= it->second;
 
 2049   tbb::parallel_for(
size_t(0), 
terms_.size(), [&](
size_t i) {
 
 2050     exprs[i] = qbpp::replace(terms_[i], map_dict);
 
 2054   *
this = std::move(result);
 
 2061   for (
const auto &item : term.
get_vars()) {
 
 2063       result *= var_val_map.at(item);
 
 2064     } 
catch (
const std::out_of_range &e) {
 
 2066                                              " is not found in the map."));
 
 2074   for (
const auto &item : term.
get_vars()) {
 
 2075     result *= sol.
get(item);
 
 2083   return result.
replace(map_list);
 
 2090   result += tbb::parallel_reduce(
 
 2093       [&](
const tbb::blocked_range<size_t> &range, 
energy_t local_result) {
 
 2094         for (size_t i = range.begin(); i < range.end(); ++i) {
 
 2095           local_result += eval(expr.get_terms()[i], var_val_map);
 
 2097         return local_result;
 
 2111   result += tbb::parallel_reduce(
 
 2114       [&](
const tbb::blocked_range<size_t> &range, 
energy_t local_result) {
 
 2115         for (size_t i = range.begin(); i < range.end(); ++i) {
 
 2116           local_result += eval(expr.get_terms()[i], sol);
 
 2118         return local_result;
 
 2129   std::vector<std::pair<int8_t, vindex_t>> var_set(
all_var_count(), {1, 0});
 
 2132   tbb::parallel_for(
size_t(0), 
expr.
get_terms().size(), [&](
size_t i) {
 
 2133     const auto &term = expr.get_terms()[i];
 
 2134     for (const auto &var : term.get_vars()) {
 
 2135       var_set[var.get_index()] = {0, var.get_index()};
 
 2139   tbb::parallel_sort(var_set.begin(), var_set.end());
 
 2143     if (var_set[i - 1].first == 0 && var_set[i].first == 1) {
 
 2149   std::vector<Var> index_var(non_zero_count, Var(
vindex_limit));
 
 2150   for (
vindex_t i = 0; i < non_zero_count; ++i) {
 
 2151     index_var[i] = Var(var_set[i].second);
 
 2158     const std::vector<Var> &index_var) {
 
 2161   if (index_var.empty()) 
return var_index;
 
 2165       [&](
vindex_t i) { var_index[index_var[i].get_index()] = i; });
 
 2173   auto name = var_str;
 
 2179 template <
typename T, 
typename... Args,
 
 2180           typename = 
typename std::enable_if<std::is_integral<T>::value>::type>
 
 2181 auto var(
const std::string &var_str, T size, Args... args) {
 
 2182   if constexpr (
sizeof...(Args) == 0) {
 
 2187       for (
vindex_t i = 0; i < static_cast<size_t>(size); ++i) {
 
 2193     Vector<decltype(
var(var_str, args...))> vars;
 
 2194     vars.
reserve(
static_cast<size_t>(size));
 
 2195     for (
size_t i = 0; i < static_cast<size_t>(size); ++i) {
 
 2197                             static_cast<size_t>(args)...));
 
 2203 template <
typename T, 
typename... Args,
 
 2204           typename = 
typename std::enable_if<std::is_integral<T>::value>::type>
 
 2205 auto var(T size, Args... args) {
 
 2226 template <
typename T, 
typename... Args>
 
 2227 auto var_int(
const std::string &var_str, T size, Args... args) {
 
 2228   if constexpr (
sizeof...(args) == 0) {
 
 2230     vars.
reserve(
static_cast<size_t>(size));
 
 2231     for (
size_t i = 0; i < static_cast<size_t>(size); ++i) {
 
 2237     vars.
reserve(
static_cast<size_t>(size));
 
 2238     for (
size_t i = 0; i < static_cast<size_t>(size); ++i) {
 
 2240                                 static_cast<size_t>(args)...));
 
 2251   std::vector<coeff_t> coeffs;
 
 2255         "max_val(", max_val, 
") must be greater than min_val(", min_val, 
")"));
 
 2259     if (current_coeff < val) {
 
 2260       coeffs.push_back(current_coeff);
 
 2262       coeffs.push_back(val);
 
 2264     val -= current_coeff;
 
 2272   std::shared_ptr<std::vector<coeff_t>> coeffs_ptr =
 
 2273       std::make_shared<std::vector<coeff_t>>(
 
 2275   return VarInt(var_str, min_val, max_val, coeffs_ptr);
 
 2284   return std::make_pair(lhs, std::move(rhs));
 
 2287 template <
typename T>
 
 2289   return std::make_pair(lhs, std::forward<
Vector<T>>(rhs));
 
 2292 template <
typename T>
 
 2294   return new_var_int(lhs.second.var_str_, lhs.first, rhs);
 
 2297 inline std::pair<energy_t, Vector<VarIntCore>> 
operator<=(
 
 2298     energy_t lhs, 
const Vector<VarIntCore> &rhs) {
 
 2299   return std::make_pair(lhs, rhs);
 
 2305   result.
reserve(lhs.second.size());
 
 2306   for (
const auto &item : lhs.second) {
 
 2322 template <
typename T, 
typename... Args>
 
 2324   if constexpr (
sizeof...(Args) == 0) {
 
 2327     Vector<decltype(
expr(args...))> result(
static_cast<size_t>(size));
 
 2328     for (
size_t i = 0; i < static_cast<size_t>(size); ++i)
 
 2329       result[i] = 
expr(
static_cast<size_t>(args)...);
 
 2334 template <
typename T>
 
 2343 template <
typename T>
 
 2347   for (
const auto &item : arg) {
 
 2353 template <
typename T>
 
 2357   for (
const auto &item : arg) {
 
 2363 template <
typename T>
 
 2364 auto toExpr(
const Vector<T> &arg) ->
 
 2365     typename std::enable_if<std::is_same<T, decltype(
toExpr(arg[0]))>::value,
 
 2374 template <
typename T>
 
 2375 auto toExpr(
const std::initializer_list<T> &list) {
 
 2378   for (
const auto &item : list) {
 
 2379     result.push_back(
toExpr(item));
 
 2385     const std::initializer_list<std::initializer_list<Expr>> &list) {
 
 2388   for (
const auto &item : list) {
 
 2395     const std::initializer_list<
 
 2396         std::initializer_list<std::initializer_list<Expr>>> &list) {
 
 2399   for (
const auto &item : list) {
 
 2406     const std::initializer_list<std::initializer_list<
 
 2407         std::initializer_list<std::initializer_list<Expr>>>> &list) {
 
 2410   for (
const auto &item : list) {
 
 2420   if (lhs.term_count() >= rhs.term_count()) {
 
 2422     return std::move(lhs);
 
 2425     return std::move(rhs);
 
 2431   return std::move(lhs);
 
 2436   return std::move(rhs);
 
 2447   return std::move(lhs);
 
 2452   return std::move(lhs);
 
 2457   return std::move(rhs);
 
 2462   return result += rhs;
 
 2467   return std::move(lhs);
 
 2472   return std::move(lhs);
 
 2478   return std::move(rhs);
 
 2483   return result -= rhs;
 
 2488   return std::move(
expr);
 
 2504     term = -std::move(term);  
 
 2506   return std::move(
expr);  
 
 2524   energy_t result = tbb::parallel_reduce(
 
 2525         tbb::blocked_range<size_t>(0, terms.size()), 
 
 2527         [&](
const tbb::blocked_range<size_t> &range, 
energy_t local_result) {
 
 2528         for (size_t i = range.begin(); i < range.end(); ++i) {
 
 2529             const auto &term = terms[i];
 
 2530             local_result = gcd(local_result, term.get_coeff());
 
 2532         return local_result;
 
 2552                                            ") must be greater than LHS (",
 
 2553                                            minimum, 
") in operator <=."));
 
 2554   } 
else if (val == 0) {
 
 2555     result = (
expr - minimum) == 0;
 
 2556   } 
else if (val == 1) {
 
 2557     result = (
expr - minimum) * (
expr - maximum);
 
 2561     result = (
expr - slack_var) * (
expr - (slack_var + 1));
 
 2568   return std::make_pair(min_val, 
expr);
 
 2574   const Expr &result = pair.second;
 
 2580   const Expr &result = pair.second;
 
 2582     throw std::runtime_error(
 
 2588 inline std::pair<energy_t, Expr> 
operator<=(Inf val, 
const Expr &
expr) {
 
 2589   if (val.is_positive()) {
 
 2590     throw std::runtime_error(
 
 2599   if (vars.size() <= 1) 
return;
 
 2600   if (vars.size() == 2)
 
 2601     if (vars[0] > vars[1]) std::swap(vars[0], vars[1]);
 
 2602   std::sort(vars.begin(), vars.end());
 
 2614   if (result.size() >= 2)
 
 2615     result.erase(std::unique(result.begin(), result.end()), result.end());
 
 2622   if (result.size() >= 2) {
 
 2623     for (
auto it = result.begin();
 
 2624          it != result.end() && it + 1 != result.end();) {
 
 2625       if (*it == *(it + 1)) {
 
 2626         it = result.erase(it, it + 2);
 
 2641     auto new_vars = (*sort_vars_func)(term.
get_vars());
 
 2642     if (new_vars.size() == 0) {
 
 2645       vars_val_map[new_vars] += term.
get_coeff();
 
 2648   for (
const auto &[vars, val] : vars_val_map) {
 
 2650       result += 
Term(vars, val);
 
 2661   Terms simplified_terms;
 
 2664   tbb::parallel_for(
size_t(0), 
expr.
get_terms().size(), [&](
size_t i) {
 
 2665     simplified_terms[i] = Term(sort_vars_func(expr.get_terms()[i].get_vars()),
 
 2666                                expr.get_terms()[i].get_coeff());
 
 2669   tbb::parallel_sort(simplified_terms.begin(), simplified_terms.end());
 
 2671   const size_t size = simplified_terms.size();
 
 2672   constexpr 
size_t min_chunk_size = 32;
 
 2673   size_t max_chunk_count = std::thread::hardware_concurrency();
 
 2674   size_t chunk_count =
 
 2675       std::min((size + min_chunk_size - 1) / min_chunk_size, max_chunk_count);
 
 2676   size_t chunk_size = (size + chunk_count - 1) / chunk_count;
 
 2678   std::vector<Terms> chunk(chunk_count);
 
 2679   std::vector<energy_t> constant(chunk_count, 0);
 
 2680   std::vector<size_t> indices(chunk_count);
 
 2683       tbb::blocked_range<size_t>(0, chunk_count),
 
 2684       [&](
const tbb::blocked_range<size_t> &range) {
 
 2685         for (
size_t i = range.begin(); i < range.end(); ++i) {
 
 2686           size_t start = i * chunk_size;
 
 2687           size_t end = std::min(start + chunk_size, size);
 
 2689           for (size_t j = start; j < end; ++j) {
 
 2690             if (simplified_terms[j].get_coeff() == 0) {
 
 2693             if (simplified_terms[j].var_count() == 0) {
 
 2694               constant[i] += simplified_terms[j].get_coeff();
 
 2697             if (chunk[i].empty()) {
 
 2698               chunk[i].push_back(std::move(simplified_terms[j]));
 
 2701             if (chunk[i].back().get_vars() == simplified_terms[j].get_vars()) {
 
 2702               chunk[i].back().set_coeff(chunk[i].back().get_coeff() +
 
 2703                                         simplified_terms[j].get_coeff());
 
 2704               if (chunk[i].back().get_coeff() == 0) {
 
 2705                 chunk[i].pop_back();
 
 2709             chunk[i].emplace_back(std::move(simplified_terms[j]));
 
 2714   for (
size_t i = 1; i < chunk_count; ++i) {
 
 2715     if (!chunk[i - 1].empty()) {
 
 2716       if (chunk[i].empty()) {
 
 2717         chunk[i].push_back(std::move(chunk[i - 1].back()));
 
 2718         chunk[i - 1].pop_back();
 
 2721       if (chunk[i - 1].back().get_vars() == chunk[i].front().get_vars()) {
 
 2722         chunk[i].front().set_coeff(chunk[i].front().get_coeff() +
 
 2723                                    chunk[i - 1].back().get_coeff());
 
 2724         chunk[i - 1].pop_back();
 
 2725         if (chunk[i].front().get_coeff() == 0) {
 
 2726           chunk[i].erase(chunk[i].begin());
 
 2732   std::vector<size_t> prefix(chunk_count + 1, 0);
 
 2734   for (
size_t i = 0; i < chunk_count; ++i) {
 
 2735     prefix[i + 1] = prefix[i] + chunk[i].size();
 
 2736     result_constant += constant[i];
 
 2739   std::vector<Term> result_terms;
 
 2740   result_terms.resize(prefix.back());
 
 2741   tbb::parallel_for(
size_t(0), 
size_t(chunk_count), [&](
size_t i) {
 
 2742     std::copy(chunk[i].begin(), chunk[i].end(),
 
 2743               result_terms.begin() + 
static_cast<std::ptrdiff_t
>(prefix[i]));
 
 2746   return Expr(result_constant, std::move(result_terms));
 
 2749 template <
typename T>
 
 2753   tbb::parallel_for(
size_t(0), vec.
size(), [&](
size_t i) {
 
 2754     result[i] = simplify(vec[i], sort_vars_func);
 
 2763 template <
typename T>
 
 2772 template <
typename T>
 
 2779     if (it->get_coeff() == 0) {
 
 2782     for (
auto it_var = it->get_vars().begin(); it_var != it->get_vars().end();
 
 2784       if (it_var != it->get_vars().begin() && *it_var < *(std::prev(it_var))) {
 
 2788     if (it != 
expr.
get_terms().begin() && *it < *(std::prev(it))) {
 
 2810   const auto &terms = quad_model_.get_expr().get_terms();
 
 2811   energy_t constant = quad_model_.get_constant();
 
 2813   energy_t term_sum = tbb::parallel_reduce(
 
 2814       tbb::blocked_range<size_t>(0, terms.size()), 
static_cast<energy_t>(0),
 
 2815       [&](
const tbb::blocked_range<size_t> &range, 
energy_t acc) {
 
 2816         for (size_t i = range.begin(); i < range.end(); ++i) {
 
 2817           const auto &term = terms[i];
 
 2818           energy_t term_energy = term.get_coeff();
 
 2819           for (auto item : term.get_vars()) {
 
 2820             if (get(item) == 0) {
 
 2829       std::plus<energy_t>());
 
 2831   return term_sum + constant;
 
 2836   for (
Var var : quad_model_.get_index_var()) {
 
 2856       term.
get_coeff() * (sum_vars - aux_var) * (sum_vars - (aux_var + 1));
 
 2862   if (var_count <= 2) {  
 
 2867   auto tail1 = temp.
get_vars().back();
 
 2869   auto tail0 = temp.
get_vars().back();
 
 2871   temp.
get_vars().push_back(aux_var);
 
 2874              (tail0 * tail1 - 2 * (tail0 + tail1) * aux_var + 3 * aux_var);
 
 2903       throw std::runtime_error(
 
 2904           THROW_MESSAGE(
"The term must be linear or quadratic, but degree is ",
 
 2922       throw std::runtime_error(
 
 2923           THROW_MESSAGE(
"The term must be linear or quadratic, but degree is ",
 
 2934 template <
typename T, 
typename U>
 
 2941 template <
typename T, 
typename U>
 
 2943   Vector<decltype(lhs[0] + rhs[0])> result = lhs;
 
 2948 template <
typename T>
 
 2955 template <
typename T>
 
 2958   return std::move(lhs);
 
 2961 template <
typename T>
 
 2963   Vector<decltype(lhs[0] + rhs)> result = lhs;
 
 2968 template <
typename T>
 
 2971   return std::move(lhs);
 
 2974 template <
typename T>
 
 2979 template <
typename T>
 
 2982   return std::move(rhs);
 
 2987 template <
typename T, 
typename U>
 
 2994 template <
typename T, 
typename U>
 
 2996   Vector<decltype(lhs[0] * rhs[0])> result = lhs;
 
 3001 template <
typename T>
 
 3008 template <
typename T>
 
 3011   return std::move(lhs);
 
 3014 template <
typename T>
 
 3016   Vector<decltype(lhs[0] * rhs)> result = lhs;
 
 3021 template <
typename T>
 
 3027 template <
typename T>
 
 3032 template <
typename T>
 
 3034   return std::move(rhs) * lhs;
 
 3039 template <
typename T, 
typename U>
 
 3046 template <
typename T, 
typename U>
 
 3048   Vector<decltype(lhs[0] - rhs[0])> result = lhs;
 
 3053 template <
typename T>
 
 3060 template <
typename T>
 
 3063   return std::move(lhs);
 
 3066 template <
typename T>
 
 3068   Vector<decltype(lhs[0] - rhs)> result = lhs;
 
 3073 template <
typename T>
 
 3076   return std::move(lhs);
 
 3079 template <
typename T>
 
 3081   return -(rhs - lhs);
 
 3086 template <
typename T>
 
 3088   Vector<decltype(lhs[0] / rhs)> result = lhs;
 
 3095 template <
typename T>
 
 3100 template <
typename T>
 
 3107 template <
typename T>
 
 3113 template <
typename T>
 
 3115   return std::make_pair(lhs, rhs);
 
 3118 template <
typename T>
 
 3120   return std::make_pair(lhs, rhs);
 
 3123 template <
typename T>
 
 3126   result.
resize(lhs.second.size());
 
 3127   tbb::parallel_for(
size_t(0), lhs.second.size(), [&](
size_t i) {
 
 3128     result[i] = (lhs.first <= lhs.second[i] <= rhs);
 
 3133 template <
typename T>
 
 3136   result.
resize(lhs.second.size());
 
 3137   tbb::parallel_for(
size_t(0), lhs.second.size(), [&](
size_t i) {
 
 3138     result[i] = (lhs.first <= lhs.second[i] <= rhs);
 
 3143 template <
typename T>
 
 3146   result.
resize(lhs.second.size());
 
 3147   tbb::parallel_for(
size_t(0), lhs.second.size(), [&](
size_t i) {
 
 3148     result[i] = (lhs.first <= lhs.second[i] <= rhs);
 
 3153 template <
typename T>
 
 3155   return std::make_pair(lhs, rhs);
 
 3158 template <
typename T>
 
 3161   Vector<decltype(lhs.first <= lhs.second[0] <= rhs)> result;
 
 3162   result.
resize(lhs.second.size());
 
 3163   tbb::parallel_for(
size_t(0), lhs.second.size(), [&](
size_t i) {
 
 3164     result[i] = (lhs.first <= lhs.second[i] <= rhs);
 
 3169 template <
typename T>
 
 3172   result.
resize(lhs.second.size());
 
 3173   tbb::parallel_for(
size_t(0), lhs.second.size(), [&](
size_t i) {
 
 3174     result[i] = (lhs.first <= lhs.second[i] <= rhs);
 
 3179 template <
typename T>
 
 3181   Vector<decltype(lhs.second[0] <= rhs)> result;
 
 3182   result.
resize(lhs.second.size());
 
 3183   tbb::parallel_for(
size_t(0), lhs.second.size(), [&](
size_t i) {
 
 3184     result[i] = (lhs.first <= lhs.second[i] <= rhs);
 
 3191 template <
typename T>
 
 3193   throw std::runtime_error(
 
 3194       "qbpp::sum cannot have a scalar argment. It must be a vector.");
 
 3198 template <
typename T>
 
 3200   throw std::runtime_error(
 
 3201       "qbpp::sum cannot have a 2-d or higher array as an argument. It " 
 3202       "must be a 1-d vector. For 2-d or higher arrays, use qbpp::total_sum " 
 3204       "qbpp::vector_sum.");
 
 3208 template <
typename T>
 
 3210   std::vector<Expr> result;
 
 3211   result.reserve(items.
size());
 
 3212   for (
const auto &item : items) {
 
 3213     result.push_back(
toExpr(item));
 
 3215   std::vector<size_t> indices(result.size() + 1);
 
 3217   for (
size_t i = 0; i < result.size(); ++i) {
 
 3218     indices[i + 1] = indices[i] + result[i].term_count();
 
 3219     constant += result[i].get_constant();
 
 3222   terms.resize(indices.back());
 
 3223   tbb::parallel_for(
size_t(0), result.size(), [&](
size_t i) {
 
 3224     std::copy(result[i].get_terms().begin(), result[i].get_terms().end(),
 
 3225               terms.begin() + static_cast<std::ptrdiff_t>(indices[i]));
 
 3227   return Expr(constant, std::move(terms));
 
 3230 template <
typename T>
 
 3235 template <
typename T>
 
 3237   std::vector<Expr> result;
 
 3238   result.resize(items.
size());
 
 3239   tbb::parallel_for(
size_t(0), items.
size(),
 
 3240                     [&](
size_t i) { result[i] = total_sum_impl(items[i]); });
 
 3241   std::vector<size_t> indices(result.size() + 1);
 
 3244   for (
size_t i = 0; i < result.size(); ++i) {
 
 3245     indices[i + 1] = indices[i] + result[i].term_count();
 
 3246     constant += result[i].get_constant();
 
 3249   terms.resize(indices.back());
 
 3251       tbb::blocked_range<size_t>(0, result.size()),
 
 3252       [&](
const tbb::blocked_range<size_t> &range) {
 
 3253         for (size_t i = range.begin(); i < range.end(); ++i) {
 
 3254           std::copy(result[i].get_terms().begin(), result[i].get_terms().end(),
 
 3255                     terms.begin() + static_cast<std::ptrdiff_t>(indices[i]));
 
 3258   return Expr(constant, std::move(terms));
 
 3261 template <
typename T>
 
 3263   throw std::runtime_error(
 
 3264       "qbpp::total_sum cannot have a scalar argment. It must be a vector.");
 
 3268 template <
typename T>
 
 3270   throw std::runtime_error(
 
 3271       "qbpp::total_sum cannot have a 1-d vector as an argument. For " 
 3272       "1-d vector, use qbpp::sum.");
 
 3276 template <
typename T>
 
 3281 template <
typename T>
 
 3283   throw std::runtime_error(
 
 3284       "qbpp::vector_sum function does not support scalar values.");
 
 3288 template <
typename T>
 
 3290   throw std::runtime_error(
 
 3291       "qbpp::vector_sum function does not support 1-d vectors. Use " 
 3292       "qbpp::sum instead.");
 
 3296 template <
typename T>
 
 3301 template <
typename T>
 
 3306 template <
typename T>
 
 3310   tbb::parallel_for(
size_t(0), items.size(),
 
 3311                     [&](
size_t i) { result[i] = vector_sum_impl(items[i]); });
 
 3315 template <
typename T>
 
 3320 template <
typename T>
 
 3322   throw std::runtime_error(
 
 3323       "qbpp::product cannot have a scalar argment. It must be a vector.");
 
 3327 template <
typename T>
 
 3329   throw std::runtime_error(
 
 3330       "qbpp::product cannot have a 2-d or higher array as an argument. It " 
 3331       "must be a 1-d vector. For 2-d or higher arrays, use " 
 3332       "qbpp::total_product " 
 3334       "qbpp::vector_product.");
 
 3338 template <
typename T>
 
 3340   return tbb::parallel_reduce(
 
 3341       tbb::blocked_range<size_t>(0, items.
size()), 
Expr{1},
 
 3342       [&](
const tbb::blocked_range<size_t> &range, 
Expr acc) {
 
 3343         for (size_t i = range.begin(); i < range.end(); ++i) {
 
 3348       [](
const Expr &a, 
const Expr &b) { 
return a * b; });
 
 3351 template <
typename T>
 
 3356 template <
typename T>
 
 3358   Expr result = tbb::parallel_reduce(
 
 3359       tbb::blocked_range<size_t>(0, items.
size()), 
Expr{1},
 
 3360       [&](
const tbb::blocked_range<size_t> &range, 
Expr acc) {
 
 3361         for (size_t i = range.begin(); i < range.end(); ++i) {
 
 3362           acc *= total_product_impl(items[i]);
 
 3366       [](
const Expr &a, 
const Expr &b) { 
return a * b; });
 
 3370 template <
typename T>
 
 3375 template <
typename T>
 
 3377   throw std::runtime_error(
 
 3378       "qbpp::total_product cannot have a scalar argment. It must be a " 
 3383 template <
typename T>
 
 3385   throw std::runtime_error(
 
 3386       "qbpp::total_product cannot have a 1-d vector as an argument. For " 
 3387       "1-d vector, use qbpp::product.");
 
 3391 template <
typename T>
 
 3393   throw std::runtime_error(
 
 3394       "qbpp::vector_product function does not support scalar values.");
 
 3398 template <
typename T>
 
 3400   throw std::runtime_error(
 
 3401       "qbpp::vector_product function does not support 1-d vectors. Use " 
 3402       "qbpp::product instead.");
 
 3406 template <
typename T>
 
 3411 template <
typename T>
 
 3416 template <
typename T>
 
 3420   tbb::parallel_for(tbb::blocked_range<size_t>(0, items.size()),
 
 3421                     [&](
const tbb::blocked_range<size_t> &range) {
 
 3422                       for (size_t i = range.begin(); i < range.end(); ++i) {
 
 3423                         result[i] = vector_product_impl(items[i]);
 
 3430 template <
typename T>
 
 3441     throw std::runtime_error(
 
 3445 template <
typename T>
 
 3447   using ResultType = decltype(
toInt(arg[0]));
 
 3450   tbb::parallel_for(tbb::blocked_range<size_t>(0, arg.
size()),
 
 3451                     [&](
const tbb::blocked_range<size_t> &range) {
 
 3452                       for (size_t i = range.begin(); i < range.end(); ++i) {
 
 3453                         result[i] = toInt(arg[i]);
 
 3460 template <
typename T>
 
 3465   tbb::parallel_for(tbb::blocked_range<size_t>(0, arg.
size()),
 
 3466                     [&](
const tbb::blocked_range<size_t> &range) {
 
 3467                       for (size_t i = range.begin(); i < range.end(); ++i) {
 
 3468                         result[i] = eval_var_val_map(arg[i], var_val_map);
 
 3475 template <
typename T>
 
 3481 template <
typename T>
 
 3487   tbb::parallel_for(tbb::blocked_range<size_t>(0, arg.size()),
 
 3488                     [&](
const tbb::blocked_range<size_t> &range) {
 
 3489                       for (size_t i = range.begin(); i < range.end(); ++i) {
 
 3490                         result[i] = eval_var_val_map(arg[i], var_val_map);
 
 3497 template <
typename T>
 
 3503 template <
typename T>
 
 3507   tbb::parallel_for(tbb::blocked_range<size_t>(0, arg.
size()),
 
 3508                     [&](
const tbb::blocked_range<size_t> &range) {
 
 3509                       for (size_t i = range.begin(); i < range.end(); ++i) {
 
 3510                         result[i] = replace(arg[i], map_list);
 
 3517 template <
typename T>
 
 3519   using ResultType = decltype(
replace(arg[0], map_list));
 
 3522   tbb::parallel_for(tbb::blocked_range<size_t>(0, arg.size()),
 
 3523                     [&](
const tbb::blocked_range<size_t> &range) {
 
 3524                       for (size_t i = range.begin(); i < range.end(); ++i) {
 
 3525                         result[i] = replace(arg[i], map_list);
 
 3532 template <
typename T, 
typename F>
 
 3534   Vector<decltype(func(arg[0]))> result(arg.
size());
 
 3536   tbb::parallel_for(tbb::blocked_range<size_t>(0, arg.
size()),
 
 3537                     [&](
const tbb::blocked_range<size_t> &range) {
 
 3538                       for (size_t i = range.begin(); i < range.end(); ++i) {
 
 3539                         result[i] = func(arg[i]);
 
 3546 template <
typename T>
 
 3551 template <
typename T>
 
 3556 template <
typename T>
 
 3561 template <
typename T>
 
 3566 template <
typename T>
 
 3571 template <
typename T>
 
 3578 template <
typename T>
 
 3583 template <
typename T>
 
 3598   tbb::parallel_for(
size_t(0), vec.size(),
 
 3599                     [&](
size_t i) { result[i] = vec[i][index]; });
 
 3604 template <
typename T>
 
 3606   return tbb::parallel_reduce(
 
 3607       tbb::blocked_range<size_t>(0, vec.
size()), 
static_cast<energy_t>(0),
 
 3608       [&](
const tbb::blocked_range<size_t> &range, 
energy_t acc) {
 
 3609         for (size_t i = range.begin(); i < range.end(); ++i) {
 
 3610           acc = gcd(acc, gcd(vec[i]));
 
 3617 template <
typename T>
 
 3621   tbb::parallel_for(
size_t(0), vec[0].size(),
 
 3622                     [&](
size_t j) { result[j] = 
get_col(vec, j); });
 
 3629   int32_t result = -1;
 
 3632       result = 
static_cast<int32_t
>(i);
 
 3643 template <
typename T>
 
 3648   tbb::parallel_for(
size_t(0), vec.size(),
 
 3649                     [&](
size_t i) { result[i] = onehot_to_int(vec[i]); });
 
 3656 template <
typename T>
 
 3662 template <
typename T>
 
 3668 template <
typename T>
 
 3675 inline std::tuple<bool, size_t, size_t, coeff_t, coeff_t>
 
 3678     return {
false, 0, 0, 0, 0};
 
 3682   size_t linear_count = 0;
 
 3683   coeff_t min_coeff = terms[0].get_coeff();
 
 3684   coeff_t max_coeff = terms[0].get_coeff();
 
 3688       tbb::blocked_range<size_t>(0, terms.size()),
 
 3689       [&](
const tbb::blocked_range<size_t> &range) {
 
 3690         coeff_t local_min = min_coeff;
 
 3691         coeff_t local_max = max_coeff;
 
 3692         for (size_t i = range.begin(); i < range.end(); ++i) {
 
 3693           const auto &term = terms[i];
 
 3695           if (local_min > term.get_coeff()) local_min = term.get_coeff();
 
 3696           if (local_max < term.get_coeff()) local_max = term.get_coeff();
 
 3698           if (term.var_count() == 0 || term.var_count() >= 3) {
 
 3702           if (term.var_count() == 2 &&
 
 3703               term.get_vars()[1] <= term.get_vars()[0]) {
 
 3709             if (term <= terms[i - 1]) {
 
 3713             if (terms[i - 1].var_count() == 1 && term.var_count() == 2) {
 
 3719         std::lock_guard<std::mutex> lock(mtx);
 
 3720         if (local_min < min_coeff) min_coeff = local_min;
 
 3721         if (local_max > max_coeff) max_coeff = local_max;
 
 3724   if (terms.back().var_count() == 1) {
 
 3725     linear_count = terms.size();
 
 3727   return {error, linear_count, terms.size() - linear_count, min_coeff,
 
 3732     : linear_(model.var_count(), 0),
 
 3733       degree_(model.var_count(), 0),
 
 3734       quadratic_(model.var_count()) {
 
 3738   auto [error, linear_count, quadratic_count, min_coeff, max_coeff] =
 
 3741     throw std::runtime_error(
 
 3742         THROW_MESSAGE(
"The expression must be simplified as binary or spin."));
 
 3751   if (linear_count > 0) {
 
 3752     tbb::parallel_for(
size_t(0), linear_count, [&](
size_t i) {
 
 3757   if (quadratic_count == 0) {
 
 3761   std::vector<Term> quadratic(quadratic_count * 2);
 
 3763   auto linear_count_local = linear_count;  
 
 3764   tbb::parallel_for(
size_t(0), quadratic_count, [&](
size_t i) {
 
 3765     quadratic[2 * i] = terms[i + linear_count_local];
 
 3766     quadratic[2 * i + 1].set_coeff(terms[i + linear_count_local].get_coeff());
 
 3767     quadratic[2 * i + 1].get_vars().push_back(
 
 3768         terms[i + linear_count_local].get_vars()[1]);
 
 3769     quadratic[2 * i + 1].get_vars().push_back(
 
 3770         terms[i + linear_count_local].get_vars()[0]);
 
 3773   tbb::parallel_sort(quadratic.begin(), quadratic.end());
 
 3775   std::vector<size_t> quadratic_index(
var_count + 1, 0);
 
 3777       tbb::blocked_range<size_t>(1, quadratic_count * 2),
 
 3778       [&](
const tbb::blocked_range<size_t> &range) {
 
 3779         for (
size_t i = range.begin(); i < range.end(); ++i) {
 
 3780           if (quadratic[i - 1].get_vars()[0] != quadratic[i].get_vars()[0]) {
 
 3781             size_t start = model.get_index(quadratic[i - 1].get_vars()[0]) + 1;
 
 3782             size_t end = model.get_index(quadratic[i].get_vars()[0]) + 1;
 
 3784             for (size_t j = start; j < end; ++j) {
 
 3785               quadratic_index[j] = i;
 
 3791   quadratic_index[model.get_index(
 
 3792                       quadratic[quadratic_count * 2 - 1].get_vars()[0]) +
 
 3793                   1] = quadratic_count * 2;
 
 3797         static_cast<vindex_t>(quadratic_index[i + 1] - quadratic_index[i]);
 
 3800   tbb::parallel_for(tbb::blocked_range<size_t>(0, 
var_count),
 
 3801                     [&](
const tbb::blocked_range<size_t> &range) {
 
 3802                       for (
size_t i = range.begin(); i < range.end(); ++i) {
 
 3803                         quadratic_[i].reserve(degree_[i]);
 
 3804                         for (size_t j = quadratic_index[i];
 
 3805                              j < quadratic_index[i + 1]; ++j) {
 
 3806                           quadratic_[i].push_back(
 
 3807                               {model.get_index(quadratic[j].get_vars()[1]),
 
 3808                                quadratic[j].get_coeff()});
 
 3816   static const auto start_ = std::chrono::high_resolution_clock::now();
 
 3817   auto elapsed = std::chrono::high_resolution_clock::now() - start_;
 
 3818   return std::chrono::duration<double>(elapsed).count();
 
Expr(energy_t constant, Terms &&terms) noexcept
 
Expr(energy_t constant, const Terms &terms) noexcept
 
Expr(Expr &&expr) noexcept=default
 
Expr & operator+=(const Expr &expr)
 
Expr operator()(const MapList &map_list) const
 
Expr & simplify_as_binary()
 
Expr(T value, size_t term_capacity=TERM_CAPACITY)
 
size_t term_count() const
 
Expr & operator*=(const Term &term)
 
Expr & operator=(Expr &&expr) noexcept
 
Expr & operator/=(energy_t val)
 
energy_t get_constant() const
 
Expr & operator=(const Expr &expr)
 
Expr & replace(const MapList &map_list)
 
Expr(const Expr &expr, size_t term_capacity=TERM_CAPACITY)
 
Expr & operator*=(const Expr &expr)
 
Expr(Term &&term, size_t term_capacity=TERM_CAPACITY) noexcept
 
const Terms & get_terms() const
 
Expr & simplify_as_spin()
 
Expr & operator-=(const Expr &expr)
 
Expr(const Term &term, size_t term_capacity=TERM_CAPACITY)
 
void set_constant(energy_t constant)
 
Var get_var(vindex_t index) const
 
const Expr & get_expr() const
 
const std::shared_ptr< const Expr > expr_ptr_
 
const Terms & get_terms() const
 
energy_t get_constant() const
 
Model & operator=(const Model &)=delete
 
vindex_t var_count() const
 
static const Expr & check_expr(const Expr &expr)
 
virtual size_t term_count() const
 
Model & operator=(Model &&)=delete
 
Model(const Model &model)
 
const std::shared_ptr< const impl::IndexVarMapper > index_var_ptr_
 
vindex_t get_index(Var var) const
 
std::vector< Var > get_index_var() const
 
Model(Expr &&expr) noexcept
 
static Expr check_expr(Expr &&expr)
 
size_t term_count(vindex_t deg) const
 
coeff_t get_max_coeff() const
 
std::pair< vindex_t, coeff_t > get_quadratic(vindex_t i, vindex_t j) const
 
const std::vector< std::vector< std::pair< vindex_t, coeff_t > > > & quadratic_
 
QuadModel & operator=(QuadModel &&)=delete
 
QuadModel & operator=(const QuadModel &)=delete
 
const std::vector< std::vector< std::pair< vindex_t, coeff_t > > > & get_quadratic() const
 
coeff_t get_linear(vindex_t index) const
 
size_t term_count() const override
 
QuadModel(QuadModel &&) noexcept=default
 
QuadModel(const Expr &expr)
 
vindex_t get_degree(vindex_t index) const
 
const std::vector< coeff_t > & get_linear() const
 
const std::shared_ptr< const Impl > pimpl_
 
QuadModel(const QuadModel &)=default
 
const std::vector< vindex_t > & get_degree() const
 
coeff_t get_min_coeff() const
 
const std::vector< vindex_t > & degree_
 
const std::vector< coeff_t > & linear_
 
void set_bound(energy_t bound)
 
energy_t get_energy() const
 
std::tuple< Sol, double, std::string > get_sol_tts_solver() const
 
std::optional< qbpp::Sol > get_if_better(const Sol &my_sol)
 
vindex_t var_count() const
 
SolHolder(const SolHolder &other)=delete
 
SolHolder(const QuadModel &quad_model)
 
std::optional< energy_t > get_bound() const
 
virtual std::optional< double > set_if_better(const qbpp::Sol &new_sol, const std::string &solver="")
 
const Sol & get_sol() const
 
std::string get_solver() const
 
virtual ~SolHolder()=default
 
virtual std::optional< qbpp::Sol > get_if_better(energy_t my_energy)
 
energy_t get_constant() const
 
vindex_t var_count() const
 
const QuadModel quad_model_
 
vindex_t popcount() const
 
bool operator<(const Sol &sol) const
 
void set_energy(energy_t energy)
 
void set(Var var, bool value)
 
void set(vindex_t index, bool value)
 
energy_t get_energy() const
 
Sol & operator=(Sol &&sol)
 
Var get_var(vindex_t index) const
 
Sol(const Sol &sol)=default
 
energy_t get(const Expr &expr) const
 
Sol(const QuadModel &quad_model)
 
virtual void flip(vindex_t index)
 
vindex_t get_index(Var var) const
 
Sol & operator=(const Sol &sol)
 
std::optional< energy_t > energy_
 
const impl::BitVector & get_bit_vector() const
 
var_val_t get(Var var) const
 
MapList get_map_list() const
 
energy_t comp_energy() const
 
impl::BitVector bit_vector_
 
auto get(const Vector< T > &vec) const
 
var_val_t get(vindex_t index) const
 
bool operator==(const Sol &sol) const
 
Sol set(const MapList &map_list)
 
bool operator==(const Term &term) const
 
Term(const Term &)=default
 
void set_coeff(coeff_t coeff)
 
bool operator<=(const Term &term) const
 
const Vars & get_vars() const
 
bool operator<(const Term &term) const
 
Term operator*(const Term &term) const
 
Term & operator/=(energy_t val)
 
bool operator!=(const Term &term) const
 
vindex_t var_count() const
 
Term(const Vars &vars, coeff_t coeff=1)
 
Term(Term &&) noexcept=default
 
Term & operator*=(coeff_t val)
 
Term operator*(energy_t val) const
 
Term(Vars &&vars, coeff_t coeff=1) noexcept
 
Term & operator=(Term &&) noexcept=default
 
Term & operator=(const Term &)=default
 
Term(Var var, coeff_t coeff=1)
 
coeff_t get_coeff() const
 
Term & operator*=(const Term &term)
 
VarIntCore(const std::string &var_str)
 
const std::string var_str_
 
vindex_t var_count() const
 
std::string get_name() const
 
const Vector< Var > new_vars() const
 
Var get_var(vindex_t i) const
 
const std::string var_str_
 
const Expr & get_expr() const
 
VarInt(const VarInt &)=default
 
VarValMap get_val_map(energy_t val) const
 
Var operator[](vindex_t i) const
 
const Expr new_expr() const
 
const Vector< Var > vars_
 
VarInt(const std::string &var_str, energy_t min_val, energy_t max_val, std::shared_ptr< std::vector< coeff_t >> coeffs_ptr)
 
coeff_t get_coeff(vindex_t i) const
 
const std::shared_ptr< std::vector< coeff_t > > coeffs_ptr_
 
bool operator!=(Var var) const
 
vindex_t get_index() const
 
Var(const Var &var)=default
 
bool operator>(Var var) const
 
bool operator<=(Var var) const
 
bool operator==(Var var) const
 
Var & operator=(const Var &var)=default
 
bool operator<(Var var) const
 
Vector< T > & operator-=(const Vector< U > &rhs)
 
Vector< T > & operator/=(energy_t val)
 
Vector< T > & transpose()
 
Vector< T > & operator*=(const Vector< U > &rhs)
 
Vector< T > & vector_operation(Vector< U > &&rhs, Op operation)
 
Vector(std::initializer_list< T > init)
 
void push_back(const T &t)
 
Vector< T > & vector_operation(const Expr &rhs, Op operation)
 
Vector< T > & simplify(Vars(*sort_vars_func)(const Vars &)=sort_vars)
 
Vector< T > & operator*=(const Expr &expr)
 
Vector< T > & operator+=(const Expr &expr)
 
Vector< T > & operator-=(Vector< U > &&rhs)
 
const T & operator[](size_t i) const
 
const std::vector< T > get_data() const
 
std::vector< T > get_data()
 
void reserve(size_t size)
 
Vector< T > & operator+=(const Vector< U > &rhs)
 
Vector(const Vector< U > &rhs)
 
Vector< T > & binary_to_spin()
 
Vector< T > & operator=(energy_t rhs)
 
Vector & operator=(Vector< T > &&)=default
 
Vector< T > & simplify_as_spin()
 
Vector< T > & operator+=(Vector< U > &&rhs)
 
std::vector< T >::iterator erase(typename std::vector< T >::iterator first, typename std::vector< T >::iterator last)
 
Vector< T > & operator=(const Expr &rhs)
 
Vector< T > & vector_operation(const Vector< U > &rhs, Op operation)
 
Vector< T > & operator-=(const Expr &expr)
 
Vector(U size, const T &value)
 
Vector(Vector< T > &&)=default
 
Vector< T > & simplify_as_binary()
 
Vector< T > & operator*=(Vector< U > &&rhs)
 
Vector(const Vector< T > &)=default
 
std::vector< T >::iterator erase(typename std::vector< T >::iterator pos)
 
Vector & operator=(const Vector< T > &)=default
 
Vector< T > & replace(const MapList &map_list)
 
Vector< T > & spin_to_binary()
 
uint64_t get64(vindex_t index64) const
 
BitVector & operator=(BitVector &bit_vector)
 
vindex_t popcount() const
 
bool get(vindex_t index) const
 
void flip(vindex_t index)
 
void set(vindex_t index, bool value)
 
std::unique_ptr< uint64_t[]> bits_
 
const vindex_t bit_count_
 
BitVector & operator=(const BitVector &bit_vector)
 
BitVector(vindex_t bit_count)
 
BitVector(const BitVector &bit_vector)
 
bool operator!=(const BitVector &bit_vector) const
 
BitVector & operator=(BitVector &&bit_vector)
 
BitVector(BitVector &&bit_vector)
 
bool operator==(const BitVector &bit_vector) const
 
bool operator<(const BitVector &bit_vector) const
 
uint64_t set64(vindex_t index64, uint64_t value)
 
const std::vector< vindex_t > & get_var_index() const
 
const std::vector< vindex_t > var_index_
 
std::vector< Var > compute_index_var(const Expr &expr)
 
const std::vector< Var > & get_index_var() const
 
std::vector< vindex_t > compute_var_index(const std::vector< Var > &index_var)
 
const std::vector< Var > index_var_
 
IndexVarMapper(const Expr &expr)
 
vindex_t get_index(Var var) const
 
Var get_var(vindex_t index) const
 
vindex_t var_count() const
 
VarSet & operator=(const impl::VarSet &)=delete
 
static std::string new_unnamed_var_str()
 
VarSet(const impl::VarSet &)=delete
 
std::vector< std::string > var_str_
 
static vindex_t all_var_count()
 
static std::string str(Var var)
 
static VarSet & get_instance()
 
static Var var(const std::string &var_str)
 
Expr equal(const std::vector< T > &lhs, const std::vector< T > &rhs)
 
Generates a QUBO Expression for the Graph Coloring Problem using QUBO++ library.
 
Expr vector_sum(const T &items[[maybe_unused]])
 
energy_t gcd(energy_t a, energy_t b)
 
VarValMap list_to_var_val(const MapList &map_list)
 
Expr binary_to_spin(const Expr &expr)
 
Expr simplify_as_spin(const Expr &expr)
 
std::ostream & operator<<(std::ostream &os, const std::pair< std::string, Vector< T >> &vec)
 
Expr spin_to_binary(const Expr &expr)
 
std::string str(const Vector< T > &vec, const std::string &prefix="", const std::string &separator=",")
 
Var var(const std::string &var_str)
 
std::unordered_map< Var, vindex_t, impl::var_hash > VarIndexMap
 
auto operator<=(energy_t lhs, VarIntCore &&rhs)
 
std::unordered_map< Var, var_val_t, impl::var_hash > VarValMap
 
qbpp::Expr total_sum(const T &arg[[maybe_unused]])
 
std::string file_line(const char *file, int line, Args... args)
 
Expr operator==(const Expr &expr, energy_t val)
 
VarInt new_var_int(const std::string &var_str, energy_t min_val, energy_t max_val, energy_t base_coeff=1)
 
auto simplify_as_binary(const Vector< T > &arg)
 
auto vector_product_impl(const T &items)
 
std::vector< Term > Terms
 
boost::multiprecision::int128_t int128_t
 
VarIntCore var_int(const std::string &var_str)
 
boost::multiprecision::uint128_t uint128_t
 
std::string str_impl(const Expr &expr, std::function< std::string(Var)> str)
 
boost::multiprecision::uint512_t uint512_t
 
auto element_wise(const Vector< T > &arg, F func)
 
Expr operator-(const Expr &expr)
 
auto operator==(const Vector< T > &lhs, energy_t rhs)
 
Vector< Vector< Expr > > transpose(const Vector< Vector< T >> &vec)
 
Vector< Expr > get_col(const Vector< Vector< Expr >> &vec, size_t index)
 
auto eval(const Vector< Vector< T >> &arg, const MapList &map_list)
 
energy_t eval_var_val_map(const Expr &expr, const VarValMap &var_val_map)
 
auto vector_sum_impl(const T &items)
 
MapDict list_to_dict(const MapList &map_list)
 
Expr toExpr(const T &arg)
 
Expr && operator*(Expr &&lhs, Expr &&rhs)
 
Expr vector_product(const T &items[[maybe_unused]])
 
void sort_vars_in_place(Vars &vars)
 
Vars sort_vars_as_binary(const Vars &vars)
 
Vars sort_vars_as_spin(const Vars &vars)
 
Expr replace(const Term &term, const MapDict &map_dict)
 
auto var_int(const std::string &var_str, T size, Args... args)
 
std::string str_short(const Expr &expr)
 
bool is_simplified(const Expr &expr)
 
auto var(T size, Args... args)
 
boost::multiprecision::int1024_t int1024_t
 
Expr sum(const Vector< T > &items)
 
Expr simplify(const Expr &expr, Vars(*sort_vars_func)(const Vars &))
 
bool is_binary(const Expr &expr)
 
Expr simplify_as_binary(const Expr &expr)
 
Vector< T > simplify(const Vector< T > &vec, Vars(*sort_vars_func)(const Vars &)=sort_vars)
 
boost::container::small_vector< Var, 2 > Vars
 
boost::multiprecision::uint256_t uint256_t
 
energy_t eval(const Expr &expr, const Sol &sol)
 
boost::multiprecision::int512_t int512_t
 
Expr total_product(const Vector< Vector< T >> &items)
 
Expr reduce_cascade(const Term &term)
 
Expr simplify_seq(const Expr &expr, Vars(*sort_vars_func)(const Vars &)=sort_vars)
 
Vector< Expr > get_row(const Vector< Vector< Expr >> &vec, vindex_t index)
 
Vector< Expr > sqr(const Vector< T > &arg)
 
std::ostream & operator<<(std::ostream &os, Var var)
 
Expr reduce(const Expr &expr)
 
const vindex_t vindex_limit
 
std::unordered_map< Var, Expr, impl::var_hash > MapDict
 
Expr comparison(const Expr &expr, energy_t minimum, energy_t maximum)
 
std::vector< coeff_t > comp_coeffs(energy_t min_val, energy_t max_val, energy_t base_coeff=1)
 
Expr && operator+(Expr &&lhs, Expr &&rhs)
 
std::tuple< bool, size_t, size_t, coeff_t, coeff_t > check_if_simplified_as_binary(const Expr &expr)
 
Expr product(const T &arg[[maybe_unused]])
 
boost::multiprecision::uint1024_t uint1024_t
 
std::unordered_map< Var, Expr, impl::var_hash > VarExprMap
 
energy_t toInt(const Expr &expr)
 
Expr && operator/(Expr &&expr, energy_t val)
 
Expr total_product_impl(const T &item)
 
auto expr(T size, Args... args)
 
Vars sort_vars(const Vars &vars)
 
boost::multiprecision::int256_t int256_t
 
std::unordered_map< Vars, coeff_t, impl::vars_hash > VarsCoeffMap
 
Expr total_sum_impl(const T &item)
 
boost::multiprecision::cpp_int cpp_int
 
Expr reduce_sum(const Term &term)
 
std::list< std::pair< std::variant< Var, VarInt >, Expr > > MapList
 
auto simplify_as_spin(const Vector< T > &arg)
 
int32_t onehot_to_int(const Vector< var_val_t > &vec)
 
#define THROW_MESSAGE(...)
 
std::vector< vindex_t > degree_
 
Impl(const qbpp::Model &model)
 
std::vector< coeff_t > linear_
 
std::vector< std::vector< std::pair< vindex_t, coeff_t > > > quadratic_
 
size_t operator()(const Var var) const
 
size_t operator()(const Vars &vars) const