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