QUBO++ Library with QUBO Solver APIs
Author: Koji Nakano, License: Non-commercial research and evaluation purposes without any guarantees.
qbpp.hpp
Go to the documentation of this file.
1 
15 #ifndef QUBOPP_HPP
16 #define QUBOPP_HPP
17 
18 #define VERSION "2025-01-15"
19 
20 #include <tbb/blocked_range.h>
21 #include <tbb/parallel_for.h>
22 #include <tbb/parallel_reduce.h>
23 #include <tbb/parallel_sort.h>
24 
25 #include <algorithm>
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>
31 #include <chrono>
32 #include <cmath>
33 #include <initializer_list>
34 #include <iomanip>
35 #include <iostream>
36 #include <limits>
37 #include <list>
38 #include <memory>
39 #include <mutex>
40 #include <optional>
41 #include <sstream>
42 #include <string>
43 #include <thread>
44 #include <type_traits>
45 #include <unordered_map>
46 #include <unordered_set>
47 #include <utility>
48 #include <variant>
49 #include <vector>
50 
51 
52 
53 namespace qbpp {
54 
55 class Inf;
56 template <typename T>
57 class Vector;
58 class Var;
59 class Term;
60 class Expr;
61 class VarIntCore;
62 class VarInt;
63 class Sol;
64 class Model;
65 class QuadModel;
66 class SolHolder;
67 
68 namespace impl {
69 class VarSet;
70 class BitVector;
71 class IndexVarMapper;
72 struct var_hash;
73 struct vars_hash;
74 }
75 
76 
77 
78 template <typename... Args>
79 std::string file_line(const char *file, int line, Args... args) {
80  std::ostringstream oss;
81  oss << file << "(" << line << ") ";
82  (oss << ... << args);
83  return oss.str();
84 }
85 
86 #define THROW_MESSAGE(...) file_line(__FILE__, __LINE__, __VA_ARGS__)
87 
88 #define TERM_CAPACITY 4
89 
90 
91 #ifndef MAXDEG
92 #define MAXDEG 0
93 #endif
94 
95 #if MAXDEG == 0
96 using Vars = boost::container::small_vector<Var, 2>;
97 #else
98 
99 using Vars = boost::container::static_vector<Var, MAXDEG>;
100 #endif
101 
102 using Terms = std::vector<Term>;
103 
113 
114 #ifndef COEFF_TYPE
115 #define COEFF_TYPE int32_t
116 #endif
117 
118 #ifndef ENERGY_TYPE
119 #define ENERGY_TYPE int64_t
120 #endif
121 
122 using vindex_t = uint32_t;
123 
124 const vindex_t vindex_limit = std::numeric_limits<vindex_t>::max();
125 
126 using var_val_t = int8_t;
127 
129 
131 
132 
133 
134 using MapList = std::list<std::pair<std::variant<Var, VarInt>, Expr>>;
135 
136 using MapDict = std::unordered_map<Var, Expr, impl::var_hash>;
137 
138 using VarValMap = std::unordered_map<Var, var_val_t, impl::var_hash>;
139 
140 using VarIndexMap = std::unordered_map<Var, vindex_t, impl::var_hash>;
141 
142 using VarExprMap = std::unordered_map<Var, Expr, impl::var_hash>;
143 
144 using VarsCoeffMap = std::unordered_map<Vars, coeff_t, impl::vars_hash>;
145 
146 namespace impl {
147 
148 struct var_hash {
149  size_t operator()(const Var var) const;
150 };
151 
152 struct vars_hash {
153  size_t operator()(const Vars &vars) const;
154 };
155 
156 }
157 
158 
159 
160 
161 Var var(const std::string &var_str);
162 Var var();
163 
164 std::string str(Var var);
165 std::string str(const char *param);
166 std::string str(const Vars &vars);
167 std::string str(const Term &term);
168 std::string str(const Expr &expr, const std::string &prefix);
169 std::string str(const Model &model);
170 std::string str(const QuadModel &quad_model);
171 std::string str(const Sol &sol);
172 std::string str(const MapList &map_list);
173 std::string str_short(const Expr &expr);
174 
175 std::ostream &operator<<(std::ostream &os, Var var);
176 std::ostream &operator<<(std::ostream &os, const Term &term);
177 std::ostream &operator<<(std::ostream &os, const Expr &expr);
178 std::ostream &operator<<(std::ostream &os, const Model &model);
179 std::ostream &operator<<(std::ostream &os, const QuadModel &quad_model);
180 std::ostream &operator<<(std::ostream &os, const Sol &sol);
181 
182 void sort_vars_in_place(Vars &vars);
183 Vars sort_vars(const Vars &vars);
184 Vars sort_vars_as_binary(const Vars &vars);
185 Vars sort_vars_as_spin(const Vars &vars);
186 Expr simplify(const Expr &expr, Vars (*sort_vars_func)(const Vars &));
189 bool is_simplified(const Expr &expr);
190 bool is_binary(const Expr &expr);
191 
192 template <typename T>
193 Vector<Expr> sqr(const Vector<T> &arg);
194 template <typename T>
195 auto sqr(const Vector<Vector<T>> &arg) -> Vector<decltype(sqr(arg[0]))>;
196 
197 energy_t eval(const Expr &expr, const Sol &sol);
198 energy_t eval(const Expr &expr, const MapList &map_list);
199 Expr reduce(const Expr &expr);
200 
201 Expr binary_to_spin(const Expr &expr);
202 Expr spin_to_binary(const Expr &expr);
203 
204 template <typename T>
206 template <typename T>
207 auto binary_to_spin(const Vector<Vector<T>> &arg)
208  -> Vector<decltype(binary_to_spin(arg[0]))>;
209 
210 template <typename T>
212 template <typename T>
213 auto spin_to_binary(const Vector<Vector<T>> &arg)
214  -> Vector<decltype(spin_to_binary(arg[0]))>;
215 
216 Vector<Expr> get_row(const Vector<Vector<Expr>> &vec, vindex_t index);
217 Vector<Expr> get_col(const Vector<Vector<Expr>> &vec, size_t index);
218 
219 double get_time();
221 
222 template <typename T>
223 Expr sum(const Vector<T> &items);
224 
225 template <typename T>
227 
228 Expr operator-(const Expr &expr);
230 
231 energy_t toInt(const Expr &expr);
232 VarValMap list_to_var_val(const MapList &map_list);
233 
234 
235 inline std::string str(int8_t val) {
236  return std::to_string(static_cast<int32_t>(val));
237 }
238 
239 template <typename T>
240 auto str(const T &val) -> decltype(std::to_string(val)) {
241  return std::to_string(val);
242 }
243 
244 template <typename T>
245 auto str(T val) -> decltype(val.str()) {
246  return val.str();
247 }
248 
249 template <typename T>
250 T abs(T val) {
251  return val < 0 ? -val : val;
252 }
253 
255  a = abs(a);
256  b = abs(b);
257  if (a == 0) return b;
258  if (b == 0) return a;
259  while (b != 0) {
260  energy_t r = a % b;
261  a = b;
262  b = r;
263  }
264  return a;
265 }
266 
267 
268 class Inf {
269  bool positive_ = true;
270 
271  public:
272  Inf() = default;
273 
274  bool is_positive() const { return positive_; }
275 
276  bool is_negative() const { return !positive_; }
277 
278  Inf operator+() const { return *this; }
279 
280  Inf operator-() const {
281  Inf inf;
283  return inf;
284  }
285 };
286 
287 const Inf inf;
288 
289 template <typename T>
290 class Vector {
291  std::vector<T> data_;
292 
293  template <typename U, typename Op>
294  Vector<T> &vector_operation(const Vector<U> &rhs, Op operation) {
295  if (size() != rhs.size()) {
296  throw std::out_of_range(
297  THROW_MESSAGE("Vector size mismatch: ", size(), " != ", rhs.size()));
298  }
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]);
304  }
305  });
306  return *this;
307  }
308 
309  template <typename U, typename Op>
310  Vector<T> &vector_operation(Vector<U> &&rhs, Op operation) {
311  if (size() != rhs.size()) {
312  throw std::out_of_range(
313  THROW_MESSAGE("Vector size mismatch: ", size(), " != ", rhs.size()));
314  }
315 
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]);
321  }
322  });
323 
324  return *this;
325  }
326 
327  template <typename Op>
328  Vector<T> &vector_operation(const Expr &rhs, Op operation) {
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);
333  }
334  });
335 
336  return *this;
337  }
338 
339  public:
340  Vector() = default;
341 
342  Vector(const Vector<T> &) = default;
343 
344  Vector(Vector<T> &&) = default;
345 
346  Vector(std::initializer_list<T> init) : data_(init) {}
347 
348  Vector &operator=(const Vector<T> &) = default;
349 
350  Vector &operator=(Vector<T> &&) = default;
351 
352  explicit Vector(size_t size) : data_(size) {}
353 
354  template <typename U, typename = typename std::enable_if<
355  std::is_integral<U>::value>::type>
356  Vector(U size, const T &value) : data_(static_cast<size_t>(size), value) {}
357 
358  template <typename U, typename = typename std::enable_if<
359  !std::is_integral<U>::value>::type>
360  Vector(U begin, U end) : data_(begin, end) {}
361 
362  template <typename U>
363  Vector(const Vector<U> &rhs) {
364  data_.resize(rhs.size());
365  tbb::parallel_for(size_t(0), rhs.size(),
366  [&](size_t i) { data_[i] = rhs[i]; });
367  }
368 
369  const std::vector<T> get_data() const { return data_; }
370 
371  std::vector<T> get_data() { return data_; }
372 
373  void resize(size_t size) { data_.resize(size); }
374 
375  void push_back(const T &t) { data_.push_back(t); }
376 
377  void emplace_back(T &&t) { data_.emplace_back(std::forward<T>(t)); }
378 
379  void reserve(size_t size) { data_.reserve(size); }
380 
381  T &operator[](size_t i) { return data_[i]; }
382 
383  const T &operator[](size_t i) const { return data_[i]; }
384 
385  size_t size() const { return data_.size(); }
386 
387  auto begin() const { return data_.begin(); }
388 
389  auto end() const { return data_.end(); }
390 
391  auto begin() { return data_.begin(); }
392 
393  auto end() { return data_.end(); }
394 
395  typename std::vector<T>::iterator erase(
396  typename std::vector<T>::iterator pos) {
397  return data_.erase(pos);
398  }
399 
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);
404  }
405 
406 
407  Vector<T> &operator=(const Expr &rhs) {
408  tbb::parallel_for(size_t(0), size(), [&](size_t i) { (*this)[i] = rhs; });
409  return *this;
410  }
411 
413  tbb::parallel_for(size_t(0), size(), [&](size_t i) { (*this)[i] = rhs; });
414  return *this;
415  }
416 
417  template <typename U>
419  return vector_operation(rhs, [](T &larg, const U &rarg) { larg += rarg; });
420  }
421 
422  template <typename U>
424  return vector_operation(std::move(rhs),
425  [](T &lhs_elem, U rhs_elem) mutable {
426  lhs_elem += std::move(rhs_elem);
427  });
428  }
429 
430  template <typename U>
432  return vector_operation(rhs, [](T &larg, const U &rarg) { larg -= rarg; });
433  }
434 
435  template <typename U>
437  return vector_operation(std::move(rhs),
438  [](T &lhs_elem, U rhs_elem) mutable {
439  lhs_elem -= std::move(rhs_elem);
440  });
441  }
442 
443  template <typename U>
445  return vector_operation(rhs, [](T &larg, const U &rarg) { larg *= rarg; });
446  }
447 
448  template <typename U>
450  return vector_operation(std::move(rhs),
451  [](T &lhs_elem, U rhs_elem) mutable {
452  lhs_elem *= std::move(rhs_elem);
453  });
454  }
455 
457  return vector_operation(expr,
458  [](T &elem, const Expr &rhs) { elem += rhs; });
459  }
460 
462  return vector_operation(expr,
463  [](T &elem, const Expr &rhs) { elem -= rhs; });
464  }
465 
467  return vector_operation(expr,
468  [](T &elem, const Expr &rhs) { elem *= rhs; });
469  }
470 
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) {
475  (*this)[i] /= val;
476  }
477  });
478  return *this;
479  }
480 
482  *this *= *this;
483  return *this;
484  }
485 
486  Vector<T> &simplify(Vars (*sort_vars_func)(const Vars &) = sort_vars);
487 
489  *this = simplify(sort_vars_as_binary);
490  return *this;
491  }
492 
494  *this = simplify(sort_vars_as_spin);
495  return *this;
496  }
497 
499  *this = qbpp::binary_to_spin(*this);
500  return *this;
501  }
502 
504  *this = qbpp::spin_to_binary(*this);
505  return *this;
506  }
507 
508  Vector<T> &replace(const MapList &map_list);
509 
511 
513  *this = transpose(*this);
514  return *this;
515  }
516 };
517 
518 class Var {
520 
521  Var() = delete;
522 
523  public:
524  Var(const Var &var) = default;
525 
526  Var &operator=(const Var &var) = default;
527 
528  explicit Var(vindex_t index) : index_(index) {}
529  vindex_t get_index() const { return index_; }
530 
531  bool operator==(Var var) const { return index_ == var.index_; }
532 
533  bool operator!=(Var var) const { return index_ != var.index_; }
534  bool operator<(Var var) const { return index_ < var.index_; }
535 
536  bool operator>(Var var) const { return index_ > var.index_; }
537 
538  bool operator<=(Var var) const { return index_ <= var.index_; }
539 
540  size_t size() const { return 1; }
541 };
542 
543 namespace impl {
544 
545 
546 class VarSet {
547  std::vector<std::string> var_str_;
548 
550 
551  VarSet() {}
552 
553  VarSet(const impl::VarSet &) = delete;
554 
555  VarSet &operator=(const impl::VarSet &) = delete;
556 
557  public:
558  static VarSet &get_instance() {
559  static std::mutex mutex_;
560  static VarSet singleton_var_set;
561  std::lock_guard<std::mutex> lock(mutex_);
562  return singleton_var_set;
563  }
564 
566  return static_cast<vindex_t>(get_instance().var_str_.size());
567  }
568 
569  static Var var(const std::string &var_str) {
570  static std::mutex mutex_;
571  std::lock_guard<std::mutex> lock(mutex_);
572  vindex_t new_index = get_instance().all_var_count();
573  get_instance().var_str_.push_back(var_str);
574  return Var(new_index);
575  }
576 
577  static std::string new_unnamed_var_str() {
578  static std::mutex mutex_;
579  std::lock_guard<std::mutex> lock(mutex_);
580  return "{" + std::to_string(get_instance().unnamed_vars++) + "}";
581  }
582 
583  static std::string str(Var var) {
584  return get_instance().var_str_[var.get_index()];
585  }
586 };
587 
589  const std::vector<Var> index_var_;
590  const std::vector<vindex_t> var_index_;
591 
592  std::vector<Var> compute_index_var(const Expr &expr);
593 
594  std::vector<vindex_t> compute_var_index(const std::vector<Var> &index_var);
595 
596  IndexVarMapper() = delete;
597 
598  public:
599  explicit IndexVarMapper(const Expr &expr)
602 
603  const std::vector<Var> &get_index_var() const { return index_var_; }
604 
605  const std::vector<vindex_t> &get_var_index() const { return var_index_; }
606 
607  vindex_t var_count() const {
608  return static_cast<vindex_t>(index_var_.size());
609  }
610 
612  return static_cast<vindex_t>(var_index_[var.get_index()]);
613  }
614 
615  Var get_var(vindex_t index) const { return get_index_var()[index]; }
616 
617  bool has(Var var) const {
618  return var_index_[var.get_index()] != vindex_limit;
619  }
620 };
621 }
622 
623 class Term {
625 
627 
628  public:
629 
630  Term() = default;
631 
632  Term(const Term &) = default;
633 
634  Term(Term &&) noexcept = default;
635 
636  explicit Term(coeff_t coeff) : coeff_(coeff) {}
637 
638  explicit Term(Var var, coeff_t coeff = 1) : coeff_(coeff), vars_({var}) {}
639 
640 
641  explicit Term(const Vars &vars, coeff_t coeff = 1)
642  : coeff_(coeff), vars_(vars) {}
643 
644 
645  explicit Term(Vars &&vars, coeff_t coeff = 1) noexcept
646  : coeff_(coeff), vars_(std::move(vars)) {}
647 
648 
649  Term &operator=(const Term &) = default;
650 
651  Term &operator=(Term &&) noexcept = default;
652 
653  coeff_t get_coeff() const { return coeff_; }
654 
655  void set_coeff(coeff_t coeff) { coeff_ = coeff; }
656 
657  Vars &get_vars() { return vars_; }
658 
659  const Vars &get_vars() const { return vars_; }
660 
661  vindex_t var_count() const { return static_cast<vindex_t>(vars_.size()); }
662 
663  bool operator==(const Term &term) const {
664  return (coeff_ == term.coeff_) && (vars_ == term.vars_);
665  }
666 
667  bool operator!=(const Term &term) const { return !(*this == term); }
668 
669  bool operator<(const Term &term) const {
670  if (var_count() < term.var_count())
671  return true;
672  else if (var_count() > term.var_count())
673  return false;
674  return vars_ < term.vars_;
675  }
676 
677  bool operator<=(const Term &term) const {
678  return *this < term || *this == term;
679  }
680 
682  coeff_ *= val;
683  return *this;
684  }
685 
686 
687  Term &operator*=(const Term &term) {
688  coeff_ *= term.coeff_;
689  vars_.reserve(var_count() + term.var_count());
690  vars_.insert(vars_.end(), term.vars_.begin(), term.vars_.end());
691  return *this;
692  }
693 
695  if constexpr (std::is_integral<coeff_t>::value) {
696  if ((coeff_ / val) * val != coeff_) {
697  throw std::runtime_error(
698  THROW_MESSAGE("Indivisible division occurred."));
699  }
700  }
701  coeff_ /= static_cast<coeff_t>(val);
702  return *this;
703  }
704 
705  Term operator*(energy_t val) const {
706  Term result = *this;
707  result.coeff_ *= static_cast<coeff_t>(val);
708  return result;
709  }
710 
711  Term operator*(const Term &term) const {
712  Term result = *this;
713  result.coeff_ *= term.coeff_;
714  result.vars_.insert(result.vars_.end(), term.vars_.begin(),
715  term.vars_.end());
716  return result;
717  }
718 
719  Term &operator-() && {
720  coeff_ = -coeff_;
721  return *this;
722  }
723 
724  Term operator-() const & {
725  Term result = *this;
726  result.coeff_ = -result.coeff_;
727  return result;
728  }
729 };
730 
731 class Expr {
732 
734 
736 
737  Expr(bool b) = delete;
738 
739 
740  public:
741 
742  Expr() { terms_.reserve(TERM_CAPACITY); };
743 
744  Expr(const Expr &expr, size_t term_capacity = TERM_CAPACITY) {
746  terms_.reserve(term_capacity);
747  terms_ = expr.terms_;
748  };
749 
750  Expr(Expr &&expr) noexcept = default;
751 
752  template <typename T,
753  typename std::enable_if<std::is_convertible<T, energy_t>::value,
754  int>::type = 0>
755  Expr(T value, size_t term_capacity = TERM_CAPACITY) {
756  constant_ = static_cast<energy_t>(value);
757  terms_.reserve(term_capacity);
758  }
759 
760  Expr(Var var) : Expr() { terms_.emplace_back(Term(var)); }
761 
762  Expr(const Term &term, size_t term_capacity = TERM_CAPACITY) {
763  terms_.reserve(term_capacity);
764  terms_.push_back(term);
765  }
766 
767  Expr(Term &&term, size_t term_capacity = TERM_CAPACITY) noexcept {
768  terms_.reserve(term_capacity);
769  terms_.push_back(std::move(term));
770  }
771 
772  Expr(energy_t constant, Terms &&terms) noexcept
773  : constant_(constant), terms_(std::move(terms)) {}
774 
775  Expr(energy_t constant, const Terms &terms) noexcept
776  : constant_(constant), terms_(terms) {}
777 
778  Expr(const VarInt &var_int);
779 
780  Expr(VarInt &&var_int);
781 
782 
783  Expr &operator=(const Expr &expr) {
784  if (this != &expr) {
786  terms_ = expr.terms_;
787  }
788  return *this;
789  }
790 
791  Expr &operator=(Expr &&expr) noexcept {
792  if (this != &expr) {
794  terms_ = std::move(expr.terms_);
795  }
796  return *this;
797  }
798 
799 
800  template <typename T,
801  typename std::enable_if<std::is_convertible<T, energy_t>::value,
802  int>::type = 0>
803  Expr &operator*=(T val) {
804  if (val == 0) {
805  constant_ = 0;
806  terms_.clear();
807  } else {
808  constant_ *= val;
809  if (terms_.size() < 1000) {
810  for (auto &t : terms_) {
811  t *= static_cast<coeff_t>(val);
812  }
813  } else {
814  tbb::parallel_for(size_t(0), terms_.size(), [&](size_t i) {
815  terms_[i] *= static_cast<coeff_t>(val);
816  });
817  }
818  }
819  return *this;
820  }
821 
822  Expr &operator*=(const Term &term) {
823  if (term.var_count() == 0) {
824  return *this *= term.get_coeff();
825  }
826  if (terms_.size() < 1000) {
827  for (auto &t : terms_) {
828  t *= term;
829  }
830  } else {
831  tbb::parallel_for(size_t(0), terms_.size(),
832  [&](size_t i) { terms_[i] *= term; });
833  }
834  if (constant_ != 0) {
835  *this += term * constant_;
836  constant_ = 0;
837  }
838  return *this;
839  }
840 
841 
842 
844  if (expr.term_count() == 0) {
845  if (term_count() < 1000) {
846  return *this *= expr.constant_;
847  }
849  tbb::parallel_for(size_t(0), terms_.size(), [&](size_t i) {
850  terms_[i] *= static_cast<coeff_t>(expr.constant_);
851  });
852  return *this;
853  }
854 
855  if (expr.term_count() == 1 && expr.constant_ == 0) {
856  return *this *= expr.terms_[0];
857  }
858 
859  const Expr &expr_small =
860  this->term_count() <= expr.term_count() ? *this : expr;
861  const Expr &expr_large =
862  this->term_count() <= expr.term_count() ? expr : *this;
863 
864  Expr result(expr_small.constant_ * expr_large.constant_);
865 
866  size_t total_terms = expr_large.term_count() * expr_small.term_count();
867 
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);
873  }
874  }
875  if (expr_large.constant_ != 0) {
876  result.terms_.reserve(total_terms += expr_small.term_count());
877  for (const auto &term : expr_small.terms_) {
878  result.terms_.push_back(term * expr_large.constant_);
879  }
880  }
881 
882  if (expr_small.constant_ != 0) {
883  result.terms_.reserve(total_terms += expr_large.term_count());
884  for (const auto &term : expr_large.terms_) {
885  result.terms_.push_back(term * expr_small.constant_);
886  }
887  }
888  *this = std::move(result);
889  return *this;
890  }
891 
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];
897  }
898  });
899 
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_;
905  });
906  total_terms += expr_small.term_count();
907  }
908 
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_;
914  });
915  }
916 
917  *this = std::move(result);
918  return *this;
919  }
920 
922  constant_ += expr.constant_;
923  auto expr2 = expr;
924  terms_.insert(terms_.end(), expr2.terms_.begin(), expr2.terms_.end());
925  return *this;
926  }
927 
929  auto expr2 = -expr;
930  *this += std::move(expr2);
931  return *this;
932  }
933 
935  if (val == 0) {
936  throw std::runtime_error(THROW_MESSAGE("Division by zero."));
937  }
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."));
942  }
943  constant_ /= val;
944  return *this;
945  }
946 
947 
948 
949  Expr &sqr() {
950  *this *= *this;
951  return *this;
952  }
953 
954 
955  Expr &simplify(Vars (*sort_vars)(const Vars &));
956 
958 
960 
961 
962 
963 
964  energy_t get_constant() const { return constant_; }
965 
966  void set_constant(energy_t constant) { constant_ = constant; }
967 
968  const Terms &get_terms() const { return terms_; }
969 
970  Terms &get_terms() { return terms_; }
971 
972  size_t term_count() const { return terms_.size(); }
973 
974  size_t size() const { return term_count(); }
975 
976 
977 
978  Expr &replace(const MapList &map_list);
979 
980  Expr operator()(const MapList &map_list) const {
981  auto result = *this;
982  return result.replace(map_list);
983  }
984 
985 
986 
987 
988  Expr &reduce() { return *this = qbpp::reduce(*this); }
989 
990 
991 
992  Expr &binary_to_spin() { return *this = qbpp::binary_to_spin(*this); }
993 
994  Expr &spin_to_binary() { return *this = qbpp::spin_to_binary(*this); }
995 
996  energy_t pos_sum() const {
997  Expr temp = qbpp::simplify_as_binary(*this);
998  energy_t sum = temp.constant_;
999  for (const auto &term : temp.terms_) {
1000  if (term.get_coeff() > 0) {
1001  sum += term.get_coeff();
1002  }
1003  }
1004  return sum;
1005  }
1006 
1007  energy_t neg_sum() const {
1008  Expr temp = qbpp::simplify_as_binary(*this);
1009  energy_t sum = temp.constant_;
1010  for (const auto &term : temp.terms_) {
1011  if (term.get_coeff() < 0) {
1012  sum += term.get_coeff();
1013  }
1014  }
1015  return sum;
1016  }
1017 };
1018 
1019 class VarIntCore {
1020  public:
1021  const std::string var_str_;
1022 
1023  explicit VarIntCore(const std::string &var_str) : var_str_(var_str) {}
1024 
1025  VarIntCore() : var_str_(impl::VarSet::new_unnamed_var_str()) {}
1026 };
1027 
1028 class VarInt {
1029 
1030  const std::string var_str_;
1031 
1034  const std::shared_ptr<std::vector<coeff_t>> coeffs_ptr_;
1036  const Expr expr_;
1037 
1038  const Vector<Var> new_vars() const {
1039  Vector<Var> vars;
1040  if (coeffs_ptr_->size() == 1) {
1041  vars.push_back(var(var_str_));
1042  } else {
1043  for (size_t i = 0; i < coeffs_ptr_->size(); i++) {
1044  vars.push_back(var(var_str_ + "[" + std::to_string(i) + "]"));
1045  }
1046  }
1047  return vars;
1048  }
1049 
1050  const Expr new_expr() const {
1051  Expr result = min_val_;
1052  for (size_t i = 0; i < coeffs_ptr_->size(); i++) {
1053  result += Term(vars_[i], (*coeffs_ptr_)[i]);
1054  }
1055  return result;
1056  }
1057 
1058  public:
1059  VarInt(const std::string &var_str, energy_t min_val, energy_t max_val,
1060  std::shared_ptr<std::vector<coeff_t>> coeffs_ptr)
1061  : var_str_(var_str),
1062  min_val_(min_val),
1063  max_val_(max_val),
1064  coeffs_ptr_(coeffs_ptr),
1065  vars_(new_vars()),
1066  expr_(new_expr()) {}
1067 
1068  VarInt(const VarInt &) = default;
1069 
1070  std::string get_name() const { return var_str_; }
1071 
1072  vindex_t var_count() const { return static_cast<vindex_t>(vars_.size()); }
1073 
1074  energy_t min_val() const { return min_val_; }
1075 
1076  energy_t max_val() const { return max_val_; }
1077 
1078  coeff_t get_coeff(vindex_t i) const { return (*coeffs_ptr_)[i]; }
1079 
1080  Var get_var(vindex_t i) const { return vars_[i]; }
1081 
1082  Var operator[](vindex_t i) const { return vars_[i]; }
1083 
1084  const Expr &get_expr() const { return expr_; }
1085 
1087  if (val < min_val_ || val > max_val_) {
1088  throw std::out_of_range(
1089  THROW_MESSAGE("Value (", str(val), " out of range."));
1090  }
1091  val -= min_val_;
1092  VarValMap result;
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];
1097  } else {
1098  result[vars_[i - 1]] = 0;
1099  }
1100  }
1101  return result;
1102  }
1103 };
1104 
1105 class Model {
1106  protected:
1107  const std::shared_ptr<const Expr> expr_ptr_;
1108 
1109  const std::shared_ptr<const impl::IndexVarMapper> index_var_ptr_;
1110 
1111  static const Expr &check_expr(const Expr &expr) {
1112  if (is_simplified(expr)) {
1113  return expr;
1114  } else {
1115  throw std::runtime_error(THROW_MESSAGE(
1116  "The expression must be simplified to be a QUBO expression."));
1117  }
1118  }
1119 
1120  static Expr check_expr(Expr &&expr) {
1121  if (is_simplified(expr)) {
1122  return std::move(expr);
1123  } else {
1124  throw std::runtime_error(THROW_MESSAGE(
1125  "The expression must be simplified to be a QUBO expression."));
1126  }
1127  }
1128 
1129  Model() = delete;
1130 
1131  Model &operator=(const Model &) = delete;
1132 
1133  Model &operator=(Model &&) = delete;
1134 
1135  public:
1136  Model(const Model &model)
1137  : expr_ptr_(model.expr_ptr_), index_var_ptr_(model.index_var_ptr_) {}
1138 
1139 
1140  Model(const Expr &expr)
1141  : expr_ptr_(std::make_shared<const Expr>(expr)),
1142  index_var_ptr_(
1143  std::make_shared<const impl::IndexVarMapper>(*expr_ptr_)) {}
1144 
1145  Model(Model &&) = default;
1146 
1147  Model(Expr &&expr) noexcept
1148  : expr_ptr_(std::make_shared<const Expr>(std::move(expr))),
1149  index_var_ptr_(
1150  std::make_shared<const impl::IndexVarMapper>(*expr_ptr_)) {}
1151 
1152  virtual ~Model() = default;
1153 
1154  vindex_t var_count() const { return index_var_ptr_->var_count(); }
1155 
1156  Var get_var(vindex_t index) const { return index_var_ptr_->get_var(index); }
1157 
1158  vindex_t get_index(Var var) const { return index_var_ptr_->get_index(var); }
1159 
1160  bool has(Var var) const { return index_var_ptr_->has(var); }
1161 
1162  virtual size_t term_count() const { return expr_ptr_->term_count(); }
1163 
1164  const Expr &get_expr() const { return *expr_ptr_; }
1165 
1166  operator const Expr &() const { return *expr_ptr_; }
1167 
1168  energy_t get_constant() const { return expr_ptr_->get_constant(); }
1169 
1170  const Terms &get_terms() const { return expr_ptr_->get_terms(); }
1171 
1172  std::vector<Var> get_index_var() const {
1173  return index_var_ptr_->get_index_var();
1174  }
1175 
1176 };
1177 
1178 class QuadModel : public Model {
1179  private:
1180 
1181  struct Impl {
1182  std::vector<coeff_t> linear_;
1183 
1184  std::vector<vindex_t> degree_;
1185 
1186  std::vector<std::vector<std::pair<vindex_t, coeff_t>>> quadratic_;
1187 
1189 
1191 
1192  explicit Impl(const qbpp::Model &model);
1193  };
1194 
1195  const std::shared_ptr<const Impl> pimpl_;
1196 
1197  const std::vector<coeff_t> &linear_;
1198 
1199  const std::vector<vindex_t> &degree_;
1200 
1201  const std::vector<std::vector<std::pair<vindex_t, coeff_t>>> &quadratic_;
1202 
1204 
1205  QuadModel &operator=(const QuadModel &) = delete;
1206 
1207  public:
1208 
1209  QuadModel(const QuadModel &) = default;
1210 
1211  QuadModel(QuadModel &&) noexcept = default;
1212 
1213  QuadModel(const Model &model)
1214  : Model(model),
1215  pimpl_(std::make_shared<Impl>(model)),
1216  linear_(pimpl_->linear_),
1217  degree_(pimpl_->degree_),
1218  quadratic_(pimpl_->quadratic_) {}
1219 
1220  QuadModel(Model &&model)
1221  : Model(std::move(model)),
1222  pimpl_(std::make_shared<Impl>(*this)),
1223  linear_(pimpl_->linear_),
1224  degree_(pimpl_->degree_),
1225  quadratic_(pimpl_->quadratic_) {}
1226 
1228  : Model(expr),
1229  pimpl_(std::make_shared<Impl>(Impl(*this))),
1230  linear_(pimpl_->linear_),
1231  degree_(pimpl_->degree_),
1232  quadratic_(pimpl_->quadratic_) {}
1233 
1235  : Model(std::move(expr)),
1236  pimpl_(std::make_shared<Impl>(Impl(*this))),
1237  linear_(pimpl_->linear_),
1238  degree_(pimpl_->degree_),
1239  quadratic_(pimpl_->quadratic_) {}
1240 
1241  const std::vector<coeff_t> &get_linear() const { return linear_; }
1242 
1243  const std::vector<vindex_t> &get_degree() const { return degree_; }
1244 
1245  const std::vector<std::vector<std::pair<vindex_t, coeff_t>>> &get_quadratic()
1246  const {
1247  return quadratic_;
1248  }
1249 
1250  coeff_t get_linear(vindex_t index) const { return linear_[index]; }
1251 
1252  vindex_t get_degree(vindex_t index) const { return degree_[index]; }
1253 
1254  std::pair<vindex_t, coeff_t> get_quadratic(vindex_t i, vindex_t j) const {
1255  return quadratic_[i][j];
1256  }
1257 
1258  size_t term_count(vindex_t deg) const {
1259  if (deg == 1) {
1260  return linear_.size();
1261  } else if (deg == 2) {
1262  return std::accumulate(degree_.begin(), degree_.end(), 0UL);
1263  } else {
1264  return 0;
1265  }
1266  }
1267 
1268  size_t term_count() const override { return term_count(1) + term_count(2); }
1269 
1270  coeff_t get_min_coeff() const { return pimpl_->min_coeff_; }
1271 
1272  coeff_t get_max_coeff() const { return pimpl_->max_coeff_; }
1273 
1274 };
1275 
1276 namespace impl {
1277 class BitVector {
1279 
1281 
1282  std::unique_ptr<uint64_t[]> bits_;
1283 
1284  public:
1285  explicit BitVector(vindex_t bit_count)
1286  : bit_count_(bit_count),
1287  size64_((bit_count + 63) / 64),
1288  bits_(std::make_unique<uint64_t[]>(size64_)) {}
1289 
1290  explicit BitVector(const BitVector &bit_vector)
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_,
1295  bits_.get());
1296  }
1297 
1298  BitVector(BitVector &&bit_vector)
1299  : bit_count_(bit_vector.bit_count_),
1300  size64_(bit_vector.size64_),
1301  bits_(std::move(bit_vector.bits_)) {};
1302 
1303  BitVector &operator=(const BitVector &bit_vector) {
1304  if (this == &bit_vector) {
1305  return *this;
1306  }
1307  if (size64_ != bit_vector.size64_) {
1308  throw std::runtime_error(
1309  THROW_MESSAGE("BitVector: Different size of bit vector."));
1310  }
1311  std::copy(bit_vector.bits_.get(), bit_vector.bits_.get() + size64_,
1312  bits_.get());
1313  return *this;
1314  }
1315 
1317  if (this == &bit_vector) {
1318  return *this;
1319  }
1320  if (size64_ != bit_vector.size64_) {
1321  throw std::runtime_error(
1322  THROW_MESSAGE("BitVector: Different size of bit vector."));
1323  }
1324  bits_ = std::move(bit_vector.bits_);
1325  return *this;
1326  }
1327 
1328  BitVector &operator=(BitVector &&bit_vector) {
1329  if (this == &bit_vector) {
1330  return *this;
1331  }
1332  if (bit_count_ != bit_vector.bit_count_) {
1333  throw std::runtime_error(
1334  THROW_MESSAGE("BitVector: Different size of bit vector."));
1335  }
1336  bits_ = std::move(bit_vector.bits_);
1337  return *this;
1338  };
1339 
1340  bool operator==(const BitVector &bit_vector) const {
1341  if (bit_count_ != bit_vector.bit_count_) {
1342  throw std::runtime_error(
1343  THROW_MESSAGE("BitVector: Different size of bit vector."));
1344  }
1345  return std::equal(bits_.get(), bits_.get() + size64_,
1346  bit_vector.bits_.get());
1347  }
1348 
1349  bool operator!=(const BitVector &bit_vector) const {
1350  return !this->operator==(bit_vector);
1351  }
1352 
1353  bool operator<(const BitVector &bit_vector) const {
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);
1358 #endif
1359 #endif
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);
1366  return n;
1367  };
1368  for (vindex_t i = 0; i < size64_; i++) {
1369  if (reverse_bits(bits_[i]) < reverse_bits(bit_vector.bits_[i]))
1370  return true;
1371  if (reverse_bits(bits_[i]) > reverse_bits(bit_vector.bits_[i]))
1372  return false;
1373  }
1374  return false;
1375  }
1376 
1377  vindex_t size() const { return bit_count_; }
1378 
1379  vindex_t size64() const { return size64_; }
1380 
1381  bool get(vindex_t index) const {
1382  if (index >= bit_count_) {
1383  throw std::out_of_range(THROW_MESSAGE("Index out of range."));
1384  }
1385  return bits_[index / 64] & (1ULL << (index % 64));
1386  }
1387 
1388  void set(vindex_t index, bool value) {
1389  if (index >= bit_count_) {
1390  throw std::out_of_range(THROW_MESSAGE("Index out of range."));
1391  }
1392  if (value)
1393  bits_[index / 64] |= 1ULL << (index % 64);
1394  else
1395  bits_[index / 64] &= ~(1ULL << (index % 64));
1396  }
1397 
1398  void flip(vindex_t index) {
1399  if (index >= bit_count_) {
1400  throw std::out_of_range(THROW_MESSAGE("Index out of range."));
1401  }
1402  bits_[index / 64] ^= 1ULL << (index % 64);
1403  }
1404 
1405  uint64_t get64(vindex_t index64) const {
1406  if (index64 >= size64_) {
1407  throw std::out_of_range(THROW_MESSAGE("Index out of range."));
1408  }
1409  return bits_[index64];
1410  }
1411 
1412  uint64_t set64(vindex_t index64, uint64_t value) {
1413  if (index64 >= size64_) {
1414  throw std::out_of_range(THROW_MESSAGE("Index out of range."));
1415  }
1416  if (index64 < size64_ - 1 || index64 * 64 == bit_count_)
1417  return bits_[index64] = value;
1418  else
1419  return bits_[index64] = value & ((1ULL << (bit_count_ % 64)) - 1);
1420  }
1421 
1422  void clear() { std::fill(bits_.get(), bits_.get() + size64_, 0); }
1423 
1424  vindex_t popcount() const {
1425  vindex_t count = 0;
1426  for (vindex_t i = 0; i < size64_; i++) {
1427  count += static_cast<vindex_t>(__builtin_popcountll(bits_[i]));
1428  }
1429  return count;
1430  }
1431 
1432  std::string str() const {
1433  std::string result;
1434  for (vindex_t i = 0; i < bit_count_; i++) {
1435  result += get(i) ? "1" : "0";
1436  }
1437  return result;
1438  }
1439 };
1440 }
1441 
1442 class Sol {
1443  protected:
1445 
1447 
1448  mutable std::optional<energy_t> energy_ = std::nullopt;
1449 
1450  Sol() = delete;
1451 
1452  energy_t comp_energy() const;
1453 
1454  MapList get_map_list() const;
1455 
1456  public:
1457 
1458  Sol(const Sol &sol) = default;
1459 
1460  Sol(Sol &&sol) = default;
1461 
1462  Sol(const QuadModel &quad_model)
1463  : quad_model_(quad_model),
1464  bit_vector_(quad_model.var_count()),
1465  energy_(quad_model.get_constant()) {}
1466 
1467  virtual ~Sol() = default;
1468 
1469  Sol &operator=(const Sol &sol) {
1470  if (this == &sol) {
1471  return *this;
1472  }
1473  bit_vector_ = sol.bit_vector_;
1474  energy_ = sol.energy_;
1475  return *this;
1476  }
1477 
1478  Sol &operator=(Sol &&sol) {
1479  if (this == &sol) {
1480  return *this;
1481  }
1482  bit_vector_ = std::move(sol.bit_vector_);
1483  energy_ = std::move(sol.energy_);
1484  return *this;
1485  }
1486 
1487  bool operator==(const Sol &sol) const {
1488  if (get_energy() != sol.get_energy()) return false;
1489  return bit_vector_ == sol.bit_vector_;
1490  }
1491  bool operator<(const Sol &sol) const {
1492  if (get_energy() < sol.get_energy()) return true;
1493  if (get_energy() == sol.get_energy())
1494  return bit_vector_ < sol.bit_vector_;
1495  else
1496  return false;
1497  }
1498 
1499 
1500  var_val_t get(vindex_t index) const { return bit_vector_.get(index); }
1501 
1502  var_val_t get(Var var) const { return get(quad_model_.get_index(var)); }
1503 
1504  energy_t get(const Expr &expr) const { return eval(expr, *this); }
1505 
1506  bool has(Var var) const { return quad_model_.has(var); }
1507 
1508  void clear() {
1509  bit_vector_.clear();
1510  energy_ = quad_model_.get_constant();
1511  }
1512 
1513  template <typename T>
1514  auto get(const Vector<T> &vec) const {
1516  result.reserve(vec.size());
1517  for (const auto &elem : vec) {
1518  result.push_back(get(elem));
1519  }
1520  return result;
1521  }
1522 
1523  void set(vindex_t index, bool value) {
1524  energy_.reset();
1525  bit_vector_.set(index, value);
1526  }
1527 
1528  void set(Var var, bool value) {
1529  energy_.reset();
1530  set(quad_model_.get_index(var), value);
1531  }
1532 
1533  virtual void flip(vindex_t index) {
1534  energy_.reset();
1535  bit_vector_.flip(index);
1536  }
1537 
1538  void flip(Var var) {
1539  energy_.reset();
1540  bit_vector_.flip(quad_model_.get_index(var));
1541  }
1542 
1543  vindex_t popcount() const { return bit_vector_.popcount(); }
1544 
1546  if (!energy_) energy_ = comp_energy();
1547  return *energy_;
1548  }
1549 
1550  void set_energy(energy_t energy) { energy_ = energy; }
1551 
1552  const impl::BitVector &get_bit_vector() const { return bit_vector_; }
1553 
1554 
1555 
1556  vindex_t var_count() const { return quad_model_.var_count(); }
1557 
1558  energy_t get_constant() const { return quad_model_.get_constant(); }
1559 
1560  Var get_var(vindex_t index) const { return quad_model_.get_var(index); }
1561 
1562  vindex_t get_index(Var var) const { return quad_model_.get_index(var); }
1563 
1564  operator MapList() const { return get_map_list(); }
1565 
1566  Sol set(const Sol &sol) {
1567  for (auto var : sol.quad_model_.get_index_var()) {
1568  set(var, sol.get(var));
1569  }
1570  return *this;
1571  }
1572 
1573  Sol set(const MapList &map_list) {
1574  VarValMap var_val_map = list_to_var_val(map_list);
1575  for (const auto &[var, val] : var_val_map) {
1576  set(var, val);
1577  }
1578  return *this;
1579  }
1580 };
1581 
1582 class SolHolder {
1583  protected:
1585  std::optional<energy_t> bound_ = std::nullopt;
1586  double startx_ = get_time();
1587  double tts_{0.0};
1588  std::string solver_ = "N/A";
1589  mutable std::mutex mtx_;
1590 
1591  public:
1592  explicit SolHolder(const QuadModel &quad_model) : sol_(quad_model) {}
1593 
1594  SolHolder(const SolHolder &other) = delete;
1595 
1596 
1597  virtual ~SolHolder() = default;
1598 
1599 
1600  virtual std::optional<double> set_if_better(const qbpp::Sol &new_sol,
1601  const std::string &solver = "") {
1602  if (new_sol.get_energy() >= sol_.get_energy()) {
1603  return std::nullopt;
1604  }
1605  std::lock_guard<std::mutex> lock(mtx_);
1606  if (new_sol.get_energy() < sol_.get_energy()) {
1607  tts_ = get_time() - startx_;
1608  sol_ = new_sol;
1609  solver_ = solver;
1610  return std::make_optional(tts_);
1611  } else {
1612  return std::nullopt;
1613  }
1614  }
1615 
1616  virtual std::optional<qbpp::Sol> get_if_better(energy_t my_energy) {
1617  if (sol_.get_energy() >= my_energy) return std::nullopt;
1618  std::lock_guard<std::mutex> lock(mtx_);
1619  if (sol_.get_energy() < my_energy) {
1620  return sol_;
1621  } else {
1622  return std::nullopt;
1623  }
1624  }
1625 
1626  std::optional<qbpp::Sol> get_if_better(const Sol &my_sol) {
1627  return get_if_better(my_sol.get_energy());
1628  }
1629 
1630  std::tuple<Sol, double, std::string> get_sol_tts_solver() const {
1631  std::lock_guard<std::mutex> lock(mtx_);
1632  return std::make_tuple(sol_, tts_, solver_);
1633  }
1634 
1635  vindex_t var_count() const { return sol_.var_count(); }
1636 
1637  energy_t get_energy() const { return sol_.get_energy(); }
1638 
1639  const Sol &get_sol() const { return sol_; }
1640 
1641  Sol copy_sol() const {
1642  std::lock_guard<std::mutex> lock(mtx_);
1643  return sol_;
1644  }
1645 
1646  void clear() {
1647  std::lock_guard<std::mutex> lock(mtx_);
1648  sol_.clear();
1649  tts_ = 0;
1650  solver_ = "N/A";
1651  }
1652 
1653  double get_tts() const { return tts_; }
1654 
1655  std::string get_solver() const { return solver_; }
1656 
1657  void set_bound(energy_t bound) { bound_ = bound; }
1658 
1659  std::optional<energy_t> get_bound() const { return bound_; }
1660 
1661  operator Sol() const { return sol_; }
1662 
1663 };
1664 
1665 
1666 inline std::string str_impl(const Vars &vars,
1667  std::function<std::string(Var)> str) {
1668  std::string result;
1669  for (const auto &item : vars) {
1670  if (!result.empty()) {
1671  result += "*";
1672  }
1673  result += str(item);
1674  }
1675  return result;
1676 }
1677 
1678 inline std::string str_impl(const Term &term,
1679  std::function<std::string(Var)> str) {
1680  std::string result;
1681  if (term.var_count() == 0) return qbpp::str(term.get_coeff());
1682  if (term.get_coeff() == -1)
1683  result += "-";
1684  else if (term.get_coeff() != 1)
1685  result += qbpp::str(term.get_coeff()) + "*";
1686  result += str_impl(term.get_vars(), str);
1687  return result;
1688 }
1689 
1690 inline std::string str_impl(const Expr &expr,
1691  std::function<std::string(Var)> str) {
1692  bool first = true;
1693  std::string result;
1694  if (expr.get_constant() != 0) {
1695  result += qbpp::str(expr.get_constant());
1696  first = false;
1697  } else if (expr.term_count() == 0)
1698  return "0";
1699  for (const auto &term : expr.get_terms()) {
1700  if (first) {
1701  result += str_impl(term, str);
1702  first = false;
1703  } else {
1704  if (term.get_coeff() < 0)
1705  result += " " + str_impl(term, str);
1706  else
1707  result += " +" + str_impl(term, str);
1708  }
1709  }
1710  return result;
1711 }
1712 
1713 
1714 
1715 inline std::string str(Var var) { return impl::VarSet::str(var); }
1716 
1717 inline std::string str(const Vars &vars) {
1718  return str_impl(vars, static_cast<std::string (*)(Var)>(str));
1719 }
1720 
1721 inline std::string str(const impl::BitVector &bit_vector) {
1722  std::string result;
1723  for (vindex_t i = 0; i < bit_vector.size(); i++) {
1724  result += bit_vector.get(i) ? "1" : "0";
1725  }
1726  return result;
1727 }
1728 
1729 
1730 inline std::string str(const char *param) {
1731  std::string param_str(param);
1732  if (param_str == "compilation_date") {
1733  return __DATE__;
1734  } else if (param_str == "author") {
1735  return "Koji Nakano";
1736  } else if (param_str == "version") {
1737  return 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 "
1741  "prohibited.";
1742  } else if (param_str == "all_vars") {
1743  std::string result;
1744  for (vindex_t i = 0; i < impl::VarSet::get_instance().all_var_count();
1745  i++) {
1746  result += "{" + std::to_string(i) + "," + str(Var(i)) + "}";
1747  }
1748  return result;
1749  } else
1750  throw std::runtime_error(
1751  THROW_MESSAGE("Unknown parameter (", param, ") for str()."));
1752 }
1753 
1754 inline std::string str(const Term &term) {
1755  return str_impl(term, static_cast<std::string (*)(Var)>(str));
1756 }
1757 
1758 inline std::string str(const Expr &expr) {
1759  return str_impl(expr, static_cast<std::string (*)(Var)>(str));
1760 }
1761 
1762 inline std::string str(const Expr &expr, const std::string &prefix,
1763  const std::string &separator [[maybe_unused]] = ",") {
1764  if (prefix == "") {
1765  return "{" + str_impl(expr, static_cast<std::string (*)(Var)>(str)) + "}";
1766  } else {
1767  return "{" + prefix + "," +
1768  str_impl(expr, static_cast<std::string (*)(Var)>(str)) + "}";
1769  }
1770 }
1771 
1772 inline std::string str(const Model &model) {
1773  auto str = [&model](Var var) -> std::string {
1774  return "<" + std::to_string(model.get_index(var)) + ">";
1775  };
1776  return str_impl(model.get_expr(), str);
1777 }
1778 
1779 inline std::string str(const QuadModel &quad_model) {
1780  auto str = [&quad_model](Var var) -> std::string {
1781  return "<" + qbpp::str(quad_model.get_index(var)) + ">";
1782  };
1783  std::string result = qbpp::str(quad_model.get_constant());
1784  for (vindex_t i = 0; i < quad_model.var_count(); i++) {
1785  result += " +" + str_impl(quad_model.get_var(i), str) + "*(" +
1786  qbpp::str(quad_model.get_linear(i));
1787  for (vindex_t j = 0; j < quad_model.get_degree(i); j++) {
1788  auto [index, coeff] = quad_model.get_quadratic(i, j);
1789  if (coeff == 1)
1790  result += " +";
1791  else if (coeff == -1)
1792  result += " -";
1793  else if (coeff > 1)
1794  result += " +" + qbpp::str(coeff) + "*";
1795  else
1796  result += " " + qbpp::str(coeff) + "*";
1797  result += str_impl(quad_model.get_var(index), str) + "/2";
1798  }
1799  result += ")";
1800  }
1801  return result;
1802 }
1803 
1804 inline std::string str(const MapList &map_list) {
1805  std::ostringstream oss;
1806  oss << "{";
1807  bool first = true;
1808 
1809  for (const auto &[key, val] : map_list) {
1810  if (!first) {
1811  oss << ",";
1812  }
1813  first = false;
1814 
1815  auto str_val = str(val);
1816  std::visit(
1817  [&](const auto &arg) {
1818  using T = std::decay_t<decltype(arg)>;
1819  oss << "{";
1820  if constexpr (std::is_same_v<T, VarInt>) {
1821  oss << arg.get_name();
1822  } else {
1823  oss << str(arg);
1824  }
1825  oss << "," << str_val << "}";
1826  },
1827  key);
1828  }
1829 
1830  oss << "}";
1831  return oss.str();
1832 }
1833 
1834 inline std::string str(const Sol &sol) {
1835  return qbpp::str(sol.get_energy()) + ":" + str(static_cast<MapList>(sol));
1836 }
1837 
1838 template <typename T>
1839 std::string str(const Vector<T> &vec, const std::string &prefix = "",
1840  const std::string &separator = ",") {
1841  std::string result;
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;
1845  }
1846  return result;
1847 }
1848 
1849 inline std::ostream &operator<<(std::ostream &os, Var var) {
1850  return os << str(var);
1851 }
1852 
1853 inline std::ostream &operator<<(std::ostream &os, const VarInt &var_int) {
1854  return os << qbpp::Expr(var_int);
1855 }
1856 
1857 inline std::ostream &operator<<(std::ostream &os, const Term &term) {
1858  return os << str(term);
1859 }
1860 
1861 inline std::ostream &operator<<(std::ostream &os, const Expr &expr) {
1862  return os << str(expr);
1863 }
1864 
1865 inline std::ostream &operator<<(std::ostream &os, const Model &model) {
1866  return os << str(model);
1867 }
1868 
1869 inline std::ostream &operator<<(std::ostream &os, const QuadModel &quad_model) {
1870  return os << str(quad_model);
1871 }
1872 
1873 inline std::ostream &operator<<(std::ostream &os, const MapList &map_list) {
1874  return os << str(map_list);
1875 }
1876 
1877 inline std::ostream &operator<<(std::ostream &os, const Sol &sol) {
1878  return os << str(sol);
1879 }
1880 
1881 template <typename T>
1882 std::ostream &operator<<(std::ostream &os, const Vector<T> &vec) {
1883  os << str(vec);
1884  return os;
1885 }
1886 
1887 template <typename T>
1888 std::ostream &operator<<(std::ostream &os,
1889  const std::pair<std::string, Vector<T>> &vec) {
1890  os << str(vec.second, vec.first);
1891  return os;
1892 }
1893 
1894 inline std::string str_short(const Expr &expr) {
1895  if (expr.term_count() <= 5) return str(expr);
1896  std::string result;
1897  if (expr.get_constant() != 0)
1898  result += qbpp::str(expr.get_constant()) + " + ";
1899  auto it = expr.get_terms().begin();
1900  result += str(*it) + " + ";
1901  ++it;
1902  result += str(*it) + " + ... + ";
1903  it = expr.get_terms().end();
1904  --it;
1905  --it;
1906  result += str(*it) + " + ";
1907  ++it;
1908  result += str(*it);
1909  result += " (" + qbpp::str(expr.term_count()) + " terms)";
1910  return result;
1911 }
1912 
1913 
1914 namespace impl {
1915 inline size_t var_hash::operator()(const Var var) const {
1916  std::hash<vindex_t> hasher;
1917  return hasher(var.get_index());
1918 }
1919 
1920 inline size_t vars_hash::operator()(const Vars &vars) const {
1921  std::hash<vindex_t> hasher;
1922  size_t seed = 0;
1923  for (const auto &item : vars) {
1924  seed ^= hasher(item.get_index()) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
1925  }
1926  return seed;
1927 }
1928 }
1929 
1930 
1931 namespace impl {
1932 template <typename T>
1933 Expr equal(const T &lhs, const T &rhs) {
1934  return lhs - rhs == 0;
1935 }
1936 
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"));
1941  }
1942  Expr result = 0;
1943  for (size_t i = 0; i < lhs.size(); i++) {
1944  result += equal(lhs[i], rhs[i]);
1945  }
1946  return result;
1947 }
1948 
1949 }
1950 
1951 
1952 inline Expr &Expr::simplify(Vars (*sort_vars_func)(const Vars &) = sort_vars) {
1953  return *this = qbpp::simplify(*this, sort_vars_func);
1954 }
1955 
1957  return *this = qbpp::simplify_as_binary(*this);
1958 }
1959 
1961  return *this = qbpp::simplify_as_spin(*this);
1962 }
1963 
1964 inline Expr::Expr(const VarInt &var_int)
1965  : constant_(var_int.get_expr().get_constant()),
1966  terms_(var_int.get_expr().get_terms()) {
1967  if (var_int.max_val() == 0) {
1968  throw std::runtime_error(
1969  THROW_MESSAGE("Wrong VarInt object. Max value is not specified."));
1970  }
1971 }
1972 
1974  : constant_(var_int.get_expr().get_constant()),
1975  terms_(std::move(var_int.get_expr().get_terms())) {
1976  if (var_int.max_val() == 0) {
1977  throw std::runtime_error(
1978  THROW_MESSAGE("Wrong VarInt object. Max value is not specified."));
1979  }
1980 }
1981 
1982 
1983 inline VarValMap list_to_var_val(const MapList &map_list) {
1984  VarValMap var_int_map;
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."));
1988  }
1989  auto constant = val.get_constant();
1990  std::visit(
1991  [&](auto &&arg) {
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;
1997  }
1998  } else {
1999  var_int_map[arg] = static_cast<var_val_t>(constant);
2000  }
2001  },
2002  key);
2003  }
2004  return var_int_map;
2005 }
2006 
2007 inline MapDict list_to_dict(const MapList &map_list) {
2008  MapDict map_dict;
2009  for (const auto &[key, val] : map_list) {
2010  auto val_local = val;
2011  std::visit(
2012  [&](auto &&arg) {
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(
2017  THROW_MESSAGE("VarInt must have a constant."));
2018  }
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;
2022  }
2023  } else {
2024  map_dict[arg] = val_local;
2025  }
2026  },
2027  key);
2028  }
2029  return map_dict;
2030 }
2031 
2032 inline Expr replace(const Term &term, const MapDict &map_dict) {
2033  Expr result = term.get_coeff();
2034  for (auto item : term.get_vars()) {
2035  auto it = map_dict.find(item);
2036  if (it == map_dict.end()) {
2037  result *= item;
2038  } else {
2039  result *= it->second;
2040  }
2041  }
2042  return result;
2043 }
2044 
2045 inline Expr &Expr::replace(const MapList &map_list) {
2046  MapDict map_dict = list_to_dict(map_list);
2047  Vector<Expr> exprs;
2048  exprs.resize(terms_.size());
2049  tbb::parallel_for(size_t(0), terms_.size(), [&](size_t i) {
2050  exprs[i] = qbpp::replace(terms_[i], map_dict);
2051  });
2052  Expr result = qbpp::sum(exprs);
2053  result += constant_;
2054  *this = std::move(result);
2055  return *this;
2056 }
2057 
2058 
2059 inline energy_t eval(const Term &term, const VarValMap &var_val_map) {
2060  energy_t result = term.get_coeff();
2061  for (const auto &item : term.get_vars()) {
2062  try {
2063  result *= var_val_map.at(item);
2064  } catch (const std::out_of_range &e) {
2065  throw std::runtime_error(THROW_MESSAGE("Variable ", qbpp::str(item),
2066  " is not found in the map."));
2067  }
2068  }
2069  return result;
2070 }
2071 
2072 inline energy_t eval(const Term &term, const Sol &sol) {
2073  energy_t result = term.get_coeff();
2074  for (const auto &item : term.get_vars()) {
2075  result *= sol.get(item);
2076  }
2077  return result;
2078 }
2079 
2080 
2081 inline Expr replace(const Expr &expr, const MapList &map_list) {
2082  auto result = expr;
2083  return result.replace(map_list);
2084 }
2085 
2087  const VarValMap &var_val_map) {
2088  energy_t result = expr.get_constant();
2089 
2090  result += tbb::parallel_reduce(
2091  tbb::blocked_range<size_t>(0, expr.get_terms().size()),
2092  static_cast<energy_t>(0),
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);
2096  }
2097  return local_result;
2098  },
2099  [](energy_t lhs, energy_t rhs) { return lhs + rhs; });
2100 
2101  return result;
2102 }
2103 
2104 inline energy_t eval(const Expr &expr, const MapList &map_list) {
2105  VarValMap var_val_map = list_to_var_val(map_list);
2106  return eval_var_val_map(expr, var_val_map);
2107 }
2108 
2109 inline energy_t eval(const Expr &expr, const Sol &sol) {
2110  energy_t result = expr.get_constant();
2111  result += tbb::parallel_reduce(
2112  tbb::blocked_range<size_t>(0, expr.get_terms().size()),
2113  static_cast<energy_t>(0),
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);
2117  }
2118  return local_result;
2119  },
2120  [](energy_t lhs, energy_t rhs) { return lhs + rhs; });
2121 
2122  return result;
2123 }
2124 
2125 
2126 
2128  const Expr &expr) {
2129  std::vector<std::pair<int8_t, vindex_t>> var_set(all_var_count(), {1, 0});
2130  if (expr.term_count() == 0) return {};
2131 
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()};
2136  }
2137  });
2138 
2139  tbb::parallel_sort(var_set.begin(), var_set.end());
2140 
2141  vindex_t non_zero_count = all_var_count();
2142  for (vindex_t i = 1; i < all_var_count(); ++i) {
2143  if (var_set[i - 1].first == 0 && var_set[i].first == 1) {
2144  non_zero_count = i;
2145  break;
2146  }
2147  }
2148 
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);
2152  }
2153 
2154  return index_var;
2155 }
2156 
2157 inline std::vector<vindex_t> impl::IndexVarMapper::compute_var_index(
2158  const std::vector<Var> &index_var) {
2159  std::vector<vindex_t> var_index(all_var_count(), vindex_limit);
2160 
2161  if (index_var.empty()) return var_index;
2162 
2163  tbb::parallel_for(
2164  static_cast<vindex_t>(0), static_cast<vindex_t>(index_var.size()),
2165  [&](vindex_t i) { var_index[index_var[i].get_index()] = i; });
2166 
2167  return var_index;
2168 }
2169 
2170 
2171 
2172 inline Var var(const std::string &var_str) {
2173  auto name = var_str;
2174  return impl::VarSet::var(name);
2175 }
2176 
2178 
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) {
2183  Vector<Var> vars;
2184  if (size == 1) {
2185  vars.emplace_back(var(var_str));
2186  } else {
2187  for (vindex_t i = 0; i < static_cast<size_t>(size); ++i) {
2188  vars.emplace_back(var(var_str + "[" + qbpp::str(i) + "]"));
2189  }
2190  }
2191  return vars;
2192  } else {
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) {
2196  vars.emplace_back(var(var_str + "[" + qbpp::str(i) + "]",
2197  static_cast<size_t>(args)...));
2198  }
2199  return vars;
2200  }
2201 }
2202 
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) {
2206  return var(impl::VarSet::new_unnamed_var_str(), size, args...);
2207 }
2208 
2211 }
2212 
2213 
2214 
2215 
2216 
2217 inline VarIntCore var_int(const std::string &var_str) {
2218  return VarIntCore(var_str);
2219 }
2220 
2223 }
2224 
2225 
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) {
2229  Vector<VarIntCore> vars;
2230  vars.reserve(static_cast<size_t>(size));
2231  for (size_t i = 0; i < static_cast<size_t>(size); ++i) {
2232  vars.emplace_back(VarIntCore(var_str + "[" + qbpp::str(i) + "]"));
2233  }
2234  return vars;
2235  } else {
2236  Vector<decltype(var_int(var_str, args...))> vars;
2237  vars.reserve(static_cast<size_t>(size));
2238  for (size_t i = 0; i < static_cast<size_t>(size); ++i) {
2239  vars.emplace_back(var_int(var_str + "[" + qbpp::str(i) + "]",
2240  static_cast<size_t>(args)...));
2241  }
2242  return vars;
2243  }
2244 }
2245 
2246 
2247 
2248 
2249 inline std::vector<coeff_t> comp_coeffs(energy_t min_val, energy_t max_val,
2250  energy_t base_coeff = 1) {
2251  std::vector<coeff_t> coeffs;
2252  coeff_t val = static_cast<coeff_t>(max_val - min_val);
2253  if (val <= 0) {
2254  throw std::invalid_argument(THROW_MESSAGE(
2255  "max_val(", max_val, ") must be greater than min_val(", min_val, ")"));
2256  }
2257  coeff_t current_coeff = static_cast<coeff_t>(base_coeff);
2258  while (val > 0) {
2259  if (current_coeff < val) {
2260  coeffs.push_back(current_coeff);
2261  } else {
2262  coeffs.push_back(val);
2263  }
2264  val -= current_coeff;
2265  current_coeff *= 2;
2266  }
2267  return coeffs;
2268 }
2269 
2270 inline VarInt new_var_int(const std::string &var_str, energy_t min_val,
2271  energy_t max_val, energy_t base_coeff = 1) {
2272  std::shared_ptr<std::vector<coeff_t>> coeffs_ptr =
2273  std::make_shared<std::vector<coeff_t>>(
2274  comp_coeffs(min_val, max_val, base_coeff));
2275  return VarInt(var_str, min_val, max_val, coeffs_ptr);
2276 }
2277 
2278 inline VarInt new_var_int(const VarIntCore &var_int_core, energy_t min_val,
2279  energy_t max_val, energy_t base_coeff = 1) {
2280  return new_var_int(var_int_core.var_str_, min_val, max_val, base_coeff);
2281 }
2282 
2283 inline auto operator<=(energy_t lhs, VarIntCore &&rhs) {
2284  return std::make_pair(lhs, std::move(rhs));
2285 }
2286 
2287 template <typename T>
2288 auto operator<=(energy_t lhs, Vector<T> &&rhs) {
2289  return std::make_pair(lhs, std::forward<Vector<T>>(rhs));
2290 }
2291 
2292 template <typename T>
2293 auto operator<=(const std::pair<energy_t, T> lhs, energy_t rhs) {
2294  return new_var_int(lhs.second.var_str_, lhs.first, rhs);
2295 }
2296 
2297 inline std::pair<energy_t, Vector<VarIntCore>> operator<=(
2298  energy_t lhs, const Vector<VarIntCore> &rhs) {
2299  return std::make_pair(lhs, rhs);
2300 }
2301 
2302 inline auto operator<=(const std::pair<energy_t, Vector<VarIntCore>> lhs,
2303  energy_t rhs) {
2304  Vector<VarInt> result;
2305  result.reserve(lhs.second.size());
2306  for (const auto &item : lhs.second) {
2307  result.push_back(new_var_int(item, lhs.first, rhs));
2308  }
2309  return result;
2310 }
2311 
2312 void operator<=(energy_t , Var ) = delete;
2313 
2314 void operator<=(Var , energy_t ) = delete;
2315 
2316 
2317 
2318 inline Expr expr() { return Expr(); }
2319 
2320 inline Vector<Expr> expr(vindex_t size) { return Vector<Expr>(size); }
2321 
2322 template <typename T, typename... Args>
2323 auto expr(T size, Args... args) {
2324  if constexpr (sizeof...(Args) == 0) {
2325  return Vector<Expr>(static_cast<size_t>(size));
2326  } else {
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)...);
2330  return result;
2331  }
2332 }
2333 
2334 template <typename T>
2335 Expr toExpr(const T &arg) {
2336  return Expr(arg);
2337 }
2338 
2339 inline Expr toExpr(const Expr &arg) { return arg; }
2340 
2341 inline Vector<Expr> toExpr(const Vector<Expr> &arg) { return arg; }
2342 
2343 template <typename T>
2344 auto toExpr(const Vector<T> &arg) {
2345  Vector<decltype(toExpr(arg[0]))> result;
2346  result.reserve(arg.size());
2347  for (const auto &item : arg) {
2348  result.push_back(toExpr(item));
2349  }
2350  return result;
2351 }
2352 
2353 template <typename T>
2354 auto toExpr(const std::vector<T> &arg) {
2355  Vector<decltype(toExpr(arg[0]))> result;
2356  result.reserve(arg.size());
2357  for (const auto &item : arg) {
2358  result.push_back(toExpr(item));
2359  }
2360  return result;
2361 }
2362 
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,
2366  Vector<T>>::type {
2367  return arg;
2368 }
2369 
2370 inline Vector<Expr> toExpr(const std::initializer_list<Expr> &list) {
2371  return Vector<Expr>(list);
2372 }
2373 
2374 template <typename T>
2375 auto toExpr(const std::initializer_list<T> &list) {
2377  result.reserve(list.size());
2378  for (const auto &item : list) {
2379  result.push_back(toExpr(item));
2380  }
2381  return result;
2382 }
2383 
2385  const std::initializer_list<std::initializer_list<Expr>> &list) {
2386  Vector<Vector<Expr>> result;
2387  result.reserve(list.size());
2388  for (const auto &item : list) {
2389  result.push_back(toExpr(item));
2390  }
2391  return result;
2392 }
2393 
2395  const std::initializer_list<
2396  std::initializer_list<std::initializer_list<Expr>>> &list) {
2397  Vector<Vector<Vector<Expr>>> result;
2398  result.reserve(list.size());
2399  for (const auto &item : list) {
2400  result.push_back(toExpr(item));
2401  }
2402  return result;
2403 }
2404 
2406  const std::initializer_list<std::initializer_list<
2407  std::initializer_list<std::initializer_list<Expr>>>> &list) {
2409  result.reserve(list.size());
2410  for (const auto &item : list) {
2411  result.push_back(toExpr(item));
2412  }
2413  return result;
2414 }
2415 
2416 
2417 
2418 
2419 inline Expr &&operator*(Expr &&lhs, Expr &&rhs) {
2420  if (lhs.term_count() >= rhs.term_count()) {
2421  lhs *= rhs;
2422  return std::move(lhs);
2423  } else {
2424  rhs *= lhs;
2425  return std::move(rhs);
2426  }
2427 }
2428 
2429 inline Expr &&operator*(Expr &&lhs, const Expr &rhs) {
2430  lhs *= rhs;
2431  return std::move(lhs);
2432 }
2433 
2434 inline Expr &&operator*(const Expr &lhs, Expr &&rhs) {
2435  rhs *= lhs;
2436  return std::move(rhs);
2437 }
2438 
2439 inline Expr operator*(const Expr &lhs, const Expr &rhs) {
2440  auto result = lhs;
2441  result *= rhs;
2442  return result;
2443 }
2444 
2445 inline Expr &&operator+(Expr &&lhs, Expr &&rhs) {
2446  lhs += rhs;
2447  return std::move(lhs);
2448 }
2449 
2450 inline Expr &&operator+(Expr &&lhs, const Expr &rhs) {
2451  lhs += rhs;
2452  return std::move(lhs);
2453 }
2454 
2455 inline Expr &&operator+(const Expr &lhs, Expr &&rhs) {
2456  rhs += lhs;
2457  return std::move(rhs);
2458 }
2459 
2460 inline Expr operator+(const Expr &lhs, const Expr &rhs) {
2461  auto result = lhs;
2462  return result += rhs;
2463 }
2464 
2465 inline Expr &&operator-(Expr &&lhs, Expr &&rhs) {
2466  lhs -= rhs;
2467  return std::move(lhs);
2468 }
2469 
2470 inline Expr &&operator-(Expr &&lhs, const Expr &rhs) {
2471  lhs -= rhs;
2472  return std::move(lhs);
2473 }
2474 
2475 inline Expr &&operator-(const Expr &lhs, Expr &&rhs) {
2476  rhs *= -1;
2477  rhs += lhs;
2478  return std::move(rhs);
2479 }
2480 
2481 inline Expr operator-(const Expr &lhs, const Expr &rhs) {
2482  auto result = lhs;
2483  return result -= rhs;
2484 }
2485 
2486 inline Expr &&operator/(Expr &&expr, energy_t val) {
2487  expr /= val;
2488  return std::move(expr);
2489 }
2490 
2491 inline Expr operator/(const Expr &expr, energy_t val) {
2492  auto temp = expr;
2493  return temp /= val;
2494 }
2495 
2496 
2497 inline Expr operator+(Expr &&expr) { return std::move(expr); }
2498 
2499 inline const Expr &operator+(const Expr &expr) { return expr; }
2500 
2503  for (auto &term : expr.get_terms()) {
2504  term = -std::move(term);
2505  }
2506  return std::move(expr);
2507 }
2508 
2509 inline Expr operator-(const Expr &expr) {
2510  Expr result{-expr.get_constant()};
2511  for (const auto &term : expr.get_terms()) {
2512  result += -term;
2513  }
2514  return result;
2515 }
2516 
2517 
2518 
2519 
2520 inline Expr sqr(const Expr &expr) { return expr * expr; }
2521 
2522 inline energy_t gcd(const Expr &expr) {
2523  const auto &terms = expr.get_terms();
2524  energy_t result = tbb::parallel_reduce(
2525  tbb::blocked_range<size_t>(0, terms.size()),
2526  expr.get_constant(),
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());
2531  }
2532  return local_result;
2533  },
2534  [](energy_t a, energy_t b) {
2535  return gcd(a, b);
2536  }
2537  );
2538  return abs(result);
2539 }
2540 
2541 
2542 
2543 inline Expr operator==(const Expr &expr, energy_t val) {
2544  return sqr(expr - val);
2545 }
2546 
2547 inline Expr comparison(const Expr &expr, energy_t minimum, energy_t maximum) {
2548  energy_t val = maximum - minimum;
2549  Expr result;
2550  if (val < 0) {
2551  throw std::runtime_error(THROW_MESSAGE("RHS (", maximum,
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);
2558  } else {
2559  VarInt slack_var = new_var_int(impl::VarSet::new_unnamed_var_str(), minimum,
2560  maximum - 1, 2);
2561  result = (expr - slack_var) * (expr - (slack_var + 1));
2562  }
2563  return result;
2564 }
2565 
2566 inline std::pair<energy_t, Expr> operator<=(energy_t min_val,
2567  const Expr &expr) {
2568  return std::make_pair(min_val, expr);
2569 }
2570 
2571 inline Expr operator<=(const std::pair<energy_t, Expr> &pair,
2572  energy_t max_val) {
2573  energy_t min_val = pair.first;
2574  const Expr &result = pair.second;
2575  return comparison(result, min_val, max_val);
2576 }
2577 
2578 inline Expr operator<=(const std::pair<energy_t, Expr> &pair, Inf val) {
2579  energy_t min_val = pair.first;
2580  const Expr &result = pair.second;
2581  if (val.is_negative()) {
2582  throw std::runtime_error(
2583  THROW_MESSAGE("RHS of operator <= must not be -inf."));
2584  }
2585  return comparison(result, min_val, result.pos_sum());
2586 }
2587 
2588 inline std::pair<energy_t, Expr> operator<=(Inf val, const Expr &expr) {
2589  if (val.is_positive()) {
2590  throw std::runtime_error(
2591  THROW_MESSAGE("LHS of operator <= must not be inf."));
2592  }
2593  return std::make_pair(expr.neg_sum(), expr);
2594 }
2595 
2596 
2597 
2598 inline void sort_vars_in_place(Vars &vars) {
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());
2603 }
2604 
2605 inline Vars sort_vars(const Vars &vars) {
2606  auto result = vars;
2607  sort_vars_in_place(result);
2608  return result;
2609 }
2610 
2611 inline Vars sort_vars_as_binary(const Vars &vars) {
2612  auto result = vars;
2613  sort_vars_in_place(result);
2614  if (result.size() >= 2)
2615  result.erase(std::unique(result.begin(), result.end()), result.end());
2616  return result;
2617 }
2618 
2619 inline Vars sort_vars_as_spin(const Vars &vars) {
2620  auto result = vars;
2621  sort_vars_in_place(result);
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);
2627  } else {
2628  ++it;
2629  }
2630  }
2631  }
2632  return result;
2633 }
2634 
2635 
2636 inline Expr simplify_seq(const Expr &expr,
2637  Vars (*sort_vars_func)(const Vars &) = sort_vars) {
2638  VarsCoeffMap vars_val_map;
2639  Expr result = expr.get_constant();
2640  for (const auto &term : expr.get_terms()) {
2641  auto new_vars = (*sort_vars_func)(term.get_vars());
2642  if (new_vars.size() == 0) {
2643  result += term.get_coeff();
2644  } else {
2645  vars_val_map[new_vars] += term.get_coeff();
2646  }
2647  }
2648  for (const auto &[vars, val] : vars_val_map) {
2649  if (val != 0) {
2650  result += Term(vars, val);
2651  }
2652  }
2653  std::sort(result.get_terms().begin(), result.get_terms().end());
2654  return result;
2655 }
2656 
2657 inline Expr simplify(const Expr &expr,
2658  Vars (*sort_vars_func)(const Vars &) = sort_vars) {
2659  if (expr.size() <= 1000) return simplify_seq(expr, sort_vars_func);
2660 
2661  Terms simplified_terms;
2662  simplified_terms.resize(expr.get_terms().size());
2663 
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());
2667  });
2668 
2669  tbb::parallel_sort(simplified_terms.begin(), simplified_terms.end());
2670 
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;
2677 
2678  std::vector<Terms> chunk(chunk_count);
2679  std::vector<energy_t> constant(chunk_count, 0);
2680  std::vector<size_t> indices(chunk_count);
2681 
2682  tbb::parallel_for(
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);
2688 
2689  for (size_t j = start; j < end; ++j) {
2690  if (simplified_terms[j].get_coeff() == 0) {
2691  continue;
2692  }
2693  if (simplified_terms[j].var_count() == 0) {
2694  constant[i] += simplified_terms[j].get_coeff();
2695  continue;
2696  }
2697  if (chunk[i].empty()) {
2698  chunk[i].push_back(std::move(simplified_terms[j]));
2699  continue;
2700  }
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();
2706  }
2707  continue;
2708  }
2709  chunk[i].emplace_back(std::move(simplified_terms[j]));
2710  }
2711  }
2712  });
2713 
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();
2719  continue;
2720  }
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());
2727  }
2728  }
2729  }
2730  }
2731 
2732  std::vector<size_t> prefix(chunk_count + 1, 0);
2733  energy_t result_constant = expr.get_constant();
2734  for (size_t i = 0; i < chunk_count; ++i) {
2735  prefix[i + 1] = prefix[i] + chunk[i].size();
2736  result_constant += constant[i];
2737  }
2738 
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]));
2744  });
2745 
2746  return Expr(result_constant, std::move(result_terms));
2747 }
2748 
2749 template <typename T>
2751  Vars (*sort_vars_func)(const Vars &) = sort_vars) {
2752  Vector<T> result(vec.size());
2753  tbb::parallel_for(size_t(0), vec.size(), [&](size_t i) {
2754  result[i] = simplify(vec[i], sort_vars_func);
2755  });
2756  return result;
2757 }
2758 
2761 }
2762 
2763 template <typename T>
2764 auto simplify_as_binary(const Vector<T> &arg) {
2765  return simplify(arg, sort_vars_as_binary);
2766 }
2767 
2768 inline Expr simplify_as_spin(const Expr &expr) {
2769  return simplify(expr, sort_vars_as_spin);
2770 }
2771 
2772 template <typename T>
2773 auto simplify_as_spin(const Vector<T> &arg) {
2774  return simplify(arg, sort_vars_as_spin);
2775 }
2776 
2777 inline bool is_simplified(const Expr &expr) {
2778  for (auto it = expr.get_terms().begin(); it != expr.get_terms().end(); ++it) {
2779  if (it->get_coeff() == 0) {
2780  return false;
2781  }
2782  for (auto it_var = it->get_vars().begin(); it_var != it->get_vars().end();
2783  ++it_var) {
2784  if (it_var != it->get_vars().begin() && *it_var < *(std::prev(it_var))) {
2785  return false;
2786  }
2787  }
2788  if (it != expr.get_terms().begin() && *it < *(std::prev(it))) {
2789  return false;
2790  }
2791  }
2792  return true;
2793 }
2794 
2795 inline bool is_binary(const Expr &expr) {
2796  for (const auto &term : expr.get_terms()) {
2797  if (term.var_count() > 2) {
2798  return false;
2799  }
2800  if (term.var_count() == 2 && term.get_vars()[0] == term.get_vars()[1]) {
2801  return false;
2802  }
2803  }
2804  return true;
2805 }
2806 
2807 
2808 
2809 inline energy_t Sol::comp_energy() const {
2810  const auto &terms = quad_model_.get_expr().get_terms();
2811  energy_t constant = quad_model_.get_constant();
2812 
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) {
2821  term_energy = 0;
2822  break;
2823  }
2824  }
2825  acc += term_energy;
2826  }
2827  return acc;
2828  },
2829  std::plus<energy_t>());
2830 
2831  return term_sum + constant;
2832 }
2833 
2834 inline MapList Sol::get_map_list() const {
2835  MapList result;
2836  for (Var var : quad_model_.get_index_var()) {
2837  result.push_back({var, static_cast<var_val_t>(get(var))});
2838  }
2839  return result;
2840 }
2841 
2842 
2843 inline Expr reduce_sum(const Term &term) {
2844  coeff_t num_var = static_cast<coeff_t>(term.var_count());
2845  if (num_var <= 2) {
2846  return term;
2847  }
2848  Expr sum_vars =
2849  std::accumulate(term.get_vars().begin(), term.get_vars().end(), Expr(0));
2850  if (term.get_coeff() < 0) {
2851  return term.get_coeff() * qbpp::var() * (sum_vars - (num_var - 1));
2852  }
2853  VarInt aux_var =
2854  new_var_int(impl::VarSet::new_unnamed_var_str(), 0, num_var - 2, 2);
2855  Expr result =
2856  term.get_coeff() * (sum_vars - aux_var) * (sum_vars - (aux_var + 1));
2857  return simplify_as_binary(result) / 2;
2858 }
2859 
2860 inline Expr reduce_cascade(const Term &term) {
2861  coeff_t var_count = static_cast<coeff_t>(term.var_count());
2862  if (var_count <= 2) {
2863  return term;
2864  }
2865  Term temp = term;
2866  auto aux_var = qbpp::var();
2867  auto tail1 = temp.get_vars().back();
2868  temp.get_vars().pop_back();
2869  auto tail0 = temp.get_vars().back();
2870  temp.get_vars().pop_back();
2871  temp.get_vars().push_back(aux_var);
2872  return reduce_cascade(temp) +
2873  abs(term.get_coeff()) *
2874  (tail0 * tail1 - 2 * (tail0 + tail1) * aux_var + 3 * aux_var);
2875 }
2876 
2877 
2878 inline Expr reduce(const Expr &expr) {
2879  Expr result = expr.get_constant();
2880  for (const auto &term : expr.get_terms()) {
2881  if (term.get_coeff() < 0 || term.var_count() <= 4) {
2882  result += reduce_sum(term);
2883  } else
2884  result += reduce_cascade(term);
2885  }
2886  return result;
2887 }
2888 
2889 
2890 
2891 
2892 inline Expr binary_to_spin(const Expr &expr) {
2893  Expr result = 4 * expr.get_constant();
2894  for (const auto &term : expr.get_terms()) {
2895  if (term.var_count() == 0) {
2896  result += term.get_coeff();
2897  } else if (term.var_count() == 1) {
2898  result += 2 * term.get_coeff() * (term.get_vars()[0] + 1);
2899  } else if (term.var_count() == 2) {
2900  result += term.get_coeff() * (term.get_vars()[0] + 1) *
2901  (term.get_vars()[1] + 1);
2902  } else {
2903  throw std::runtime_error(
2904  THROW_MESSAGE("The term must be linear or quadratic, but degree is ",
2905  term.var_count(), "."));
2906  }
2907  }
2908  return result.simplify_as_spin();
2909 }
2910 
2911 inline Expr spin_to_binary(const Expr &expr) {
2912  Expr result = expr.get_constant();
2913  for (const auto &term : expr.get_terms()) {
2914  if (term.var_count() == 0) {
2915  result += term.get_coeff();
2916  } else if (term.var_count() == 1) {
2917  result += term.get_coeff() * (2 * term.get_vars()[0] - 1);
2918  } else if (term.var_count() == 2) {
2919  result += term.get_coeff() * (2 * term.get_vars()[0] - 1) *
2920  (2 * term.get_vars()[1] - 1);
2921  } else {
2922  throw std::runtime_error(
2923  THROW_MESSAGE("The term must be linear or quadratic, but degree is ",
2924  term.var_count(), "."));
2925  }
2926  }
2927  return result.simplify_as_binary();
2928 }
2929 
2930 
2931 
2932 
2933 
2934 template <typename T, typename U>
2935 Vector<Expr> operator+(const Vector<T> &lhs, const Vector<U> &rhs) {
2936  Vector<Expr> result = lhs;
2937  result += rhs;
2938  return result;
2939 }
2940 
2941 template <typename T, typename U>
2942 auto operator+(const Vector<Vector<T>> &lhs, const Vector<Vector<U>> &rhs) {
2943  Vector<decltype(lhs[0] + rhs[0])> result = lhs;
2944  result += rhs;
2945  return result;
2946 }
2947 
2948 template <typename T>
2949 Vector<Expr> operator+(const Vector<T> &lhs, const Expr &rhs) {
2950  Vector<Expr> result = lhs;
2951  result += rhs;
2952  return result;
2953 }
2954 
2955 template <typename T>
2956 Vector<Expr> operator+(Vector<T> &&lhs, const Expr &rhs) {
2957  lhs += rhs;
2958  return std::move(lhs);
2959 }
2960 
2961 template <typename T>
2962 auto operator+(const Vector<Vector<T>> &lhs, const Expr &rhs) {
2963  Vector<decltype(lhs[0] + rhs)> result = lhs;
2964  result += rhs;
2965  return result;
2966 }
2967 
2968 template <typename T>
2969 auto operator+(Vector<Vector<T>> &&lhs, const Expr &rhs) {
2970  lhs += rhs;
2971  return std::move(lhs);
2972 }
2973 
2974 template <typename T>
2975 auto operator+(const Expr &lhs, const Vector<T> &rhs) {
2976  return rhs + lhs;
2977 }
2978 
2979 template <typename T>
2980 auto operator+(const Expr &lhs, Vector<T> &&rhs) {
2981  rhs += lhs;
2982  return std::move(rhs);
2983 }
2984 
2985 
2986 
2987 template <typename T, typename U>
2988 Vector<Expr> operator*(const Vector<T> &lhs, const Vector<U> &rhs) {
2989  Vector<Expr> result = lhs;
2990  result *= rhs;
2991  return result;
2992 }
2993 
2994 template <typename T, typename U>
2995 auto operator*(const Vector<Vector<T>> &lhs, const Vector<Vector<U>> &rhs) {
2996  Vector<decltype(lhs[0] * rhs[0])> result = lhs;
2997  result *= rhs;
2998  return result;
2999 }
3000 
3001 template <typename T>
3002 Vector<Expr> operator*(const Vector<T> &lhs, const Expr &rhs) {
3003  Vector<Expr> result = lhs;
3004  result *= rhs;
3005  return result;
3006 }
3007 
3008 template <typename T>
3009 Vector<Expr> operator*(Vector<T> &&lhs, const Expr &rhs) {
3010  lhs *= rhs;
3011  return std::move(lhs);
3012 }
3013 
3014 template <typename T>
3015 auto operator*(const Vector<Vector<T>> &lhs, const Expr &rhs) {
3016  Vector<decltype(lhs[0] * rhs)> result = lhs;
3017  result *= rhs;
3018  return result;
3019 }
3020 
3021 template <typename T>
3022 auto operator*(Vector<Vector<T>> &&lhs, const Expr &rhs) {
3023  lhs *= rhs;
3024  return lhs;
3025 }
3026 
3027 template <typename T>
3028 auto operator*(const Expr &lhs, const Vector<T> &rhs) {
3029  return rhs * lhs;
3030 }
3031 
3032 template <typename T>
3033 auto operator*(const Expr &lhs, Vector<T> &&rhs) {
3034  return std::move(rhs) * lhs;
3035 }
3036 
3037 
3038 
3039 template <typename T, typename U>
3040 Vector<Expr> operator-(const Vector<T> &lhs, const Vector<U> &rhs) {
3041  Vector<Expr> result = lhs;
3042  result -= rhs;
3043  return result;
3044 }
3045 
3046 template <typename T, typename U>
3047 auto operator-(const Vector<Vector<T>> &lhs, const Vector<Vector<U>> &rhs) {
3048  Vector<decltype(lhs[0] - rhs[0])> result = lhs;
3049  result -= rhs;
3050  return result;
3051 }
3052 
3053 template <typename T>
3054 Vector<Expr> operator-(const Vector<T> &lhs, const Expr &rhs) {
3055  Vector<Expr> result = lhs;
3056  result -= rhs;
3057  return result;
3058 }
3059 
3060 template <typename T>
3061 Vector<Expr> operator-(Vector<T> &&lhs, const Expr &rhs) {
3062  lhs -= rhs;
3063  return std::move(lhs);
3064 }
3065 
3066 template <typename T>
3067 auto operator-(const Vector<Vector<T>> &lhs, const Expr &rhs) {
3068  Vector<decltype(lhs[0] - rhs)> result = lhs;
3069  result -= rhs;
3070  return result;
3071 }
3072 
3073 template <typename T>
3074 auto operator-(Vector<Vector<T>> &&lhs, const Expr &rhs) {
3075  lhs -= rhs;
3076  return std::move(lhs);
3077 }
3078 
3079 template <typename T>
3080 auto operator-(const Expr &lhs, const Vector<T> &rhs) {
3081  return -(rhs - lhs);
3082 }
3083 
3084 
3085 
3086 template <typename T>
3087 auto operator/(const Vector<T> &lhs, energy_t rhs) {
3088  Vector<decltype(lhs[0] / rhs)> result = lhs;
3089  result /= rhs;
3090  return result;
3091 }
3092 
3093 
3094 
3095 template <typename T>
3096 auto operator+(const Vector<T> &lhs) {
3097  return qbpp::toExpr(lhs);
3098 }
3099 
3100 template <typename T>
3101 auto operator-(const Vector<T> &lhs) {
3102  return lhs * (-1);
3103 }
3104 
3105 
3106 
3107 template <typename T>
3108 auto operator==(const Vector<T> &lhs, energy_t rhs) {
3109  Vector<decltype(lhs[0] == rhs)> result = qbpp::sqr(lhs - rhs);
3110  return result;
3111 }
3112 
3113 template <typename T>
3114 auto operator<=(energy_t lhs, const Vector<T> &rhs) {
3115  return std::make_pair(lhs, rhs);
3116 }
3117 
3118 template <typename T>
3119 auto operator<=(Inf lhs, const Vector<T> &rhs) {
3120  return std::make_pair(lhs, rhs);
3121 }
3122 
3123 template <typename T>
3124 auto operator<=(const std::pair<energy_t, Vector<T>> &lhs, energy_t rhs) {
3125  Vector<Expr> result;
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);
3129  });
3130  return result;
3131 }
3132 
3133 template <typename T>
3134 auto operator<=(const std::pair<energy_t, Vector<T>> &lhs, Inf rhs) {
3135  Vector<Expr> result;
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);
3139  });
3140  return result;
3141 }
3142 
3143 template <typename T>
3144 auto operator<=(const std::pair<Inf, Vector<T>> &lhs, energy_t rhs) {
3145  Vector<Expr> result;
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);
3149  });
3150  return result;
3151 }
3152 
3153 template <typename T>
3154 auto operator<=(energy_t lhs, const Vector<Vector<T>> &rhs) {
3155  return std::make_pair(lhs, rhs);
3156 }
3157 
3158 template <typename T>
3159 auto operator<=(const std::pair<energy_t, Vector<Vector<T>>> &lhs,
3160  energy_t rhs) {
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);
3165  });
3166  return result;
3167 }
3168 
3169 template <typename T>
3170 auto operator<=(const std::pair<energy_t, Vector<Vector<T>>> &lhs, Inf rhs) {
3171  Vector<Vector<T>> result;
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);
3175  });
3176  return result;
3177 }
3178 
3179 template <typename T>
3180 auto operator<=(const std::pair<Inf, Vector<Vector<T>>> &lhs, energy_t rhs) {
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);
3185  });
3186  return result;
3187 }
3188 
3189 
3190 
3191 template <typename T>
3192 Expr sum(const T &arg [[maybe_unused]]) {
3193  throw std::runtime_error(
3194  "qbpp::sum cannot have a scalar argment. It must be a vector.");
3195  return toExpr(0);
3196 }
3197 
3198 template <typename T>
3199 Expr sum(const Vector<Vector<T>> &arg [[maybe_unused]]) {
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 "
3203  "or "
3204  "qbpp::vector_sum.");
3205  return toExpr(0);
3206 }
3207 
3208 template <typename T>
3209 Expr sum(const Vector<T> &items) {
3210  std::vector<Expr> result;
3211  result.reserve(items.size());
3212  for (const auto &item : items) {
3213  result.push_back(toExpr(item));
3214  }
3215  std::vector<size_t> indices(result.size() + 1);
3216  energy_t constant = 0;
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();
3220  }
3221  Terms terms;
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]));
3226  });
3227  return Expr(constant, std::move(terms));
3228 }
3229 
3230 template <typename T>
3231 Expr total_sum_impl(const T &item) {
3232  return toExpr(item);
3233 }
3234 
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);
3242  energy_t constant = 0;
3243 
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();
3247  }
3248  Terms terms;
3249  terms.resize(indices.back());
3250  tbb::parallel_for(
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]));
3256  }
3257  });
3258  return Expr(constant, std::move(terms));
3259 }
3260 
3261 template <typename T>
3262 qbpp::Expr total_sum(const T &arg [[maybe_unused]]) {
3263  throw std::runtime_error(
3264  "qbpp::total_sum cannot have a scalar argment. It must be a vector.");
3265  return toExpr(0);
3266 }
3267 
3268 template <typename T>
3269 qbpp::Expr total_sum(const Vector<T> &arg [[maybe_unused]]) {
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.");
3273  return toExpr(0);
3274 }
3275 
3276 template <typename T>
3277 Expr total_sum(const Vector<Vector<T>> &items) {
3278  return total_sum_impl(items);
3279 }
3280 
3281 template <typename T>
3282 Expr vector_sum(const T &items [[maybe_unused]]) {
3283  throw std::runtime_error(
3284  "qbpp::vector_sum function does not support scalar values.");
3285  return toExpr(0);
3286 }
3287 
3288 template <typename T>
3289 Expr vector_sum(const Vector<T> &items [[maybe_unused]]) {
3290  throw std::runtime_error(
3291  "qbpp::vector_sum function does not support 1-d vectors. Use "
3292  "qbpp::sum instead.");
3293  return toExpr(0);
3294 }
3295 
3296 template <typename T>
3297 auto vector_sum_impl(const T &items) {
3298  return toExpr(items);
3299 }
3300 
3301 template <typename T>
3302 auto vector_sum_impl(const Vector<T> &items) {
3303  return sum(items);
3304 }
3305 
3306 template <typename T>
3307 auto vector_sum_impl(const Vector<Vector<T>> &items) {
3308  using SubResultType = decltype(vector_sum_impl(std::declval<Vector<T>>()));
3309  Vector<SubResultType> result(items.size());
3310  tbb::parallel_for(size_t(0), items.size(),
3311  [&](size_t i) { result[i] = vector_sum_impl(items[i]); });
3312  return result;
3313 }
3314 
3315 template <typename T>
3316 auto vector_sum(const Vector<Vector<T>> &items) {
3317  return vector_sum_impl(items);
3318 }
3319 
3320 template <typename T>
3321 Expr product(const T &arg [[maybe_unused]]) {
3322  throw std::runtime_error(
3323  "qbpp::product cannot have a scalar argment. It must be a vector.");
3324  return toExpr(0);
3325 }
3326 
3327 template <typename T>
3328 Expr product(const Vector<Vector<T>> &arg [[maybe_unused]]) {
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 "
3333  "or "
3334  "qbpp::vector_product.");
3335  return toExpr(0);
3336 }
3337 
3338 template <typename T>
3339 Expr product(const Vector<T> &items) {
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) {
3344  acc *= items[i];
3345  }
3346  return acc;
3347  },
3348  [](const Expr &a, const Expr &b) { return a * b; });
3349 }
3350 
3351 template <typename T>
3352 Expr total_product_impl(const T &item) {
3353  return toExpr(item);
3354 }
3355 
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]);
3363  }
3364  return acc;
3365  },
3366  [](const Expr &a, const Expr &b) { return a * b; });
3367  return result;
3368 }
3369 
3370 template <typename T>
3372  return total_product_impl(items);
3373 }
3374 
3375 template <typename T>
3376 Expr total_product(const T &arg [[maybe_unused]]) {
3377  throw std::runtime_error(
3378  "qbpp::total_product cannot have a scalar argment. It must be a "
3379  "vector.");
3380  return toExpr(0);
3381 }
3382 
3383 template <typename T>
3384 Expr total_product(const Vector<T> &arg [[maybe_unused]]) {
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.");
3388  return toExpr(0);
3389 }
3390 
3391 template <typename T>
3392 Expr vector_product(const T &items [[maybe_unused]]) {
3393  throw std::runtime_error(
3394  "qbpp::vector_product function does not support scalar values.");
3395  return toExpr(0);
3396 }
3397 
3398 template <typename T>
3399 Expr vector_product(const Vector<T> &items [[maybe_unused]]) {
3400  throw std::runtime_error(
3401  "qbpp::vector_product function does not support 1-d vectors. Use "
3402  "qbpp::product instead.");
3403  return toExpr(0);
3404 }
3405 
3406 template <typename T>
3407 auto vector_product_impl(const T &items) {
3408  return toExpr(items);
3409 }
3410 
3411 template <typename T>
3412 auto vector_product_impl(const Vector<T> &items) {
3413  return product(items);
3414 }
3415 
3416 template <typename T>
3417 auto vector_product_impl(const Vector<Vector<T>> &items) {
3418  using SubResultType = decltype(vector_product(std::declval<Vector<T>>()));
3419  Vector<SubResultType> result(items.size());
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]);
3424  }
3425  });
3426 
3427  return result;
3428 }
3429 
3430 template <typename T>
3431 auto vector_product(const Vector<Vector<T>> &items) {
3432  return vector_product_impl(items);
3433 }
3434 
3435 
3436 
3437 inline energy_t toInt(const Expr &expr) {
3438  if (expr.term_count() == 0) {
3439  return static_cast<energy_t>(expr.get_constant());
3440  } else
3441  throw std::runtime_error(
3442  THROW_MESSAGE("The expression is not a constant."));
3443 }
3444 
3445 template <typename T>
3446 auto toInt(const Vector<T> &arg) {
3447  using ResultType = decltype(toInt(arg[0]));
3448  Vector<ResultType> result(arg.size());
3449 
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]);
3454  }
3455  });
3456 
3457  return result;
3458 }
3459 
3460 template <typename T>
3462  const VarValMap &var_val_map) {
3463  Vector<energy_t> result(arg.size());
3464 
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);
3469  }
3470  });
3471 
3472  return result;
3473 }
3474 
3475 template <typename T>
3476 Vector<energy_t> eval(const Vector<T> &arg, const MapList &map_list) {
3477  VarValMap var_val_map = list_to_var_val(map_list);
3478  return eval_var_val_map(arg, var_val_map);
3479 }
3480 
3481 template <typename T>
3483  const VarValMap &var_val_map) {
3484  using ResultType = decltype(eval_var_val_map(arg[0], var_val_map));
3485  Vector<ResultType> result(arg.size());
3486 
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);
3491  }
3492  });
3493 
3494  return result;
3495 }
3496 
3497 template <typename T>
3498 auto eval(const Vector<Vector<T>> &arg, const MapList &map_list) {
3499  VarValMap var_val_map = list_to_var_val(map_list);
3500  return eval_var_val_map(arg, var_val_map);
3501 }
3502 
3503 template <typename T>
3504 Vector<Expr> replace(const Vector<T> &arg, const MapList &map_list) {
3505  Vector<Expr> result(arg.size());
3506 
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);
3511  }
3512  });
3513 
3514  return result;
3515 }
3516 
3517 template <typename T>
3518 auto replace(const Vector<Vector<T>> &arg, const MapList &map_list) {
3519  using ResultType = decltype(replace(arg[0], map_list));
3520  Vector<ResultType> result(arg.size());
3521 
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);
3526  }
3527  });
3528 
3529  return result;
3530 }
3531 
3532 template <typename T, typename F>
3533 auto element_wise(const Vector<T> &arg, F func) {
3534  Vector<decltype(func(arg[0]))> result(arg.size());
3535 
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]);
3540  }
3541  });
3542 
3543  return result;
3544 }
3545 
3546 template <typename T>
3548  return element_wise(arg, [](const T &item) { return sqr(item); });
3549 }
3550 
3551 template <typename T>
3552 auto sqr(const Vector<Vector<T>> &arg) -> Vector<decltype(sqr(arg[0]))> {
3553  return element_wise(arg, [](const Vector<T> &item) { return sqr(item); });
3554 }
3555 
3556 template <typename T>
3558  return element_wise(arg, [](const T &item) { return reduce(item); });
3559 }
3560 
3561 template <typename T>
3562 auto reduce(const Vector<Vector<T>> &arg) {
3563  return element_wise(arg, [](const Vector<T> &item) { return reduce(item); });
3564 }
3565 
3566 template <typename T>
3568  return element_wise(arg, [](const T &item) { return binary_to_spin(item); });
3569 }
3570 
3571 template <typename T>
3573  -> Vector<decltype(binary_to_spin(arg[0]))> {
3574  return element_wise(
3575  arg, [](const Vector<T> &item) { return binary_to_spin(item); });
3576 }
3577 
3578 template <typename T>
3580  return element_wise(arg, [](const T &item) { return spin_to_binary(item); });
3581 }
3582 
3583 template <typename T>
3585  -> Vector<decltype(spin_to_binary(arg[0]))> {
3586  return element_wise(
3587  arg, [](const Vector<T> &item) { return spin_to_binary(item); });
3588 }
3589 
3590 inline Vector<Expr> get_row(const Vector<Vector<Expr>> &vec, vindex_t index) {
3591  Vector<Expr> result = vec[index];
3592  return result;
3593 }
3594 
3595 inline Vector<Expr> get_col(const Vector<Vector<Expr>> &vec, size_t index) {
3596  Vector<Expr> result(vec.size());
3597 
3598  tbb::parallel_for(size_t(0), vec.size(),
3599  [&](size_t i) { result[i] = vec[i][index]; });
3600 
3601  return result;
3602 }
3603 
3604 template <typename T>
3605 energy_t gcd(const Vector<T> &vec) {
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]));
3611  }
3612  return acc;
3613  },
3614  [](energy_t a, energy_t b) { return gcd(a, b); });
3615 }
3616 
3617 template <typename T>
3619  Vector<Vector<Expr>> result(vec[0].size());
3620 
3621  tbb::parallel_for(size_t(0), vec[0].size(),
3622  [&](size_t j) { result[j] = get_col(vec, j); });
3623 
3624  return result;
3625 }
3626 
3627 inline int32_t onehot_to_int(const Vector<var_val_t> &vec) {
3628  int32_t total = 0;
3629  int32_t result = -1;
3630  for (vindex_t i = 0; i < vec.size(); i++) {
3631  if (vec[i] == 1) {
3632  result = static_cast<int32_t>(i);
3633  }
3634  total += vec[i];
3635  }
3636  if (total != 0) {
3637  return result;
3638  } else {
3639  return -1;
3640  }
3641 }
3642 
3643 template <typename T>
3644 auto onehot_to_int(const Vector<Vector<T>> &vec) {
3645  using ResultType = decltype(onehot_to_int(vec[0]));
3646  Vector<ResultType> result(vec.size());
3647 
3648  tbb::parallel_for(size_t(0), vec.size(),
3649  [&](size_t i) { result[i] = onehot_to_int(vec[i]); });
3650 
3651  return result;
3652 }
3653 
3654 
3655 
3656 template <typename T>
3657 Vector<T> &Vector<T>::simplify(Vars (*sort_vars_func)(const Vars &)) {
3658  *this = qbpp::simplify(*this, sort_vars_func);
3659  return *this;
3660 }
3661 
3662 template <typename T>
3664  *this = qbpp::replace(*this, map_list);
3665  return *this;
3666 }
3667 
3668 template <typename T>
3670  *this = qbpp::reduce(*this);
3671  return *this;
3672 }
3673 
3674 
3675 inline std::tuple<bool, size_t, size_t, coeff_t, coeff_t>
3677  if (expr.term_count() == 0) {
3678  return {false, 0, 0, 0, 0};
3679  }
3680  const auto &terms = expr.get_terms();
3681  bool error = false;
3682  size_t linear_count = 0;
3683  coeff_t min_coeff = terms[0].get_coeff();
3684  coeff_t max_coeff = terms[0].get_coeff();
3685  std::mutex mtx;
3686 
3687  tbb::parallel_for(
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];
3694 
3695  if (local_min > term.get_coeff()) local_min = term.get_coeff();
3696  if (local_max < term.get_coeff()) local_max = term.get_coeff();
3697 
3698  if (term.var_count() == 0 || term.var_count() >= 3) {
3699  error = true;
3700  return;
3701  }
3702  if (term.var_count() == 2 &&
3703  term.get_vars()[1] <= term.get_vars()[0]) {
3704  error = true;
3705  return;
3706  }
3707 
3708  if (i > 0) {
3709  if (term <= terms[i - 1]) {
3710  error = true;
3711  return;
3712  }
3713  if (terms[i - 1].var_count() == 1 && term.var_count() == 2) {
3714  linear_count = i;
3715  }
3716  }
3717  }
3718 
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;
3722  });
3723 
3724  if (terms.back().var_count() == 1) {
3725  linear_count = terms.size();
3726  }
3727  return {error, linear_count, terms.size() - linear_count, min_coeff,
3728  max_coeff};
3729 }
3730 
3732  : linear_(model.var_count(), 0),
3733  degree_(model.var_count(), 0),
3734  quadratic_(model.var_count()) {
3735  const auto var_count = model.var_count();
3736  const Expr &expr = model.get_expr();
3737  const Terms &terms = expr.get_terms();
3738  auto [error, linear_count, quadratic_count, min_coeff, max_coeff] =
3740  if (error) {
3741  throw std::runtime_error(
3742  THROW_MESSAGE("The expression must be simplified as binary or spin."));
3743  }
3744  min_coeff_ = min_coeff;
3745  max_coeff_ = max_coeff;
3746 
3747  if (model.get_expr().get_terms().size() == 0) {
3748  return;
3749  }
3750 
3751  if (linear_count > 0) {
3752  tbb::parallel_for(size_t(0), linear_count, [&](size_t i) {
3753  linear_[model.get_index(terms[i].get_vars()[0])] = terms[i].get_coeff();
3754  });
3755  }
3756 
3757  if (quadratic_count == 0) {
3758  return;
3759  }
3760 
3761  std::vector<Term> quadratic(quadratic_count * 2);
3762 
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]);
3771  });
3772 
3773  tbb::parallel_sort(quadratic.begin(), quadratic.end());
3774 
3775  std::vector<size_t> quadratic_index(var_count + 1, 0);
3776  tbb::parallel_for(
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;
3783 
3784  for (size_t j = start; j < end; ++j) {
3785  quadratic_index[j] = i;
3786  }
3787  }
3788  }
3789  });
3790 
3791  quadratic_index[model.get_index(
3792  quadratic[quadratic_count * 2 - 1].get_vars()[0]) +
3793  1] = quadratic_count * 2;
3794 
3795  tbb::parallel_for(static_cast<vindex_t>(0), var_count, [&](size_t i) {
3796  degree_[i] =
3797  static_cast<vindex_t>(quadratic_index[i + 1] - quadratic_index[i]);
3798  });
3799 
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()});
3809  }
3810  }
3811  });
3812 }
3813 
3814 
3815 inline double get_time() {
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();
3819 }
3820 
3821 }
3822 #endif
Expr(energy_t constant, Terms &&terms) noexcept
Definition: qbpp.hpp:772
Expr(energy_t constant, const Terms &terms) noexcept
Definition: qbpp.hpp:775
Expr(Expr &&expr) noexcept=default
Expr & operator+=(const Expr &expr)
Definition: qbpp.hpp:921
Expr operator()(const MapList &map_list) const
Definition: qbpp.hpp:980
energy_t constant_
Definition: qbpp.hpp:733
Expr & simplify_as_binary()
Definition: qbpp.hpp:1956
Expr(Var var)
Definition: qbpp.hpp:760
Expr(T value, size_t term_capacity=TERM_CAPACITY)
Definition: qbpp.hpp:755
Expr & operator*=(T val)
Definition: qbpp.hpp:803
size_t term_count() const
Definition: qbpp.hpp:972
Expr & operator*=(const Term &term)
Definition: qbpp.hpp:822
Expr & operator=(Expr &&expr) noexcept
Definition: qbpp.hpp:791
Expr & operator/=(energy_t val)
Definition: qbpp.hpp:934
energy_t pos_sum() const
Definition: qbpp.hpp:996
energy_t get_constant() const
Definition: qbpp.hpp:964
Terms terms_
Definition: qbpp.hpp:735
Terms & get_terms()
Definition: qbpp.hpp:970
Expr & operator=(const Expr &expr)
Definition: qbpp.hpp:783
Expr & replace(const MapList &map_list)
Definition: qbpp.hpp:2045
size_t size() const
Definition: qbpp.hpp:974
Expr(const Expr &expr, size_t term_capacity=TERM_CAPACITY)
Definition: qbpp.hpp:744
Expr & operator*=(const Expr &expr)
Definition: qbpp.hpp:843
energy_t neg_sum() const
Definition: qbpp.hpp:1007
Expr & sqr()
Definition: qbpp.hpp:949
Expr(Term &&term, size_t term_capacity=TERM_CAPACITY) noexcept
Definition: qbpp.hpp:767
const Terms & get_terms() const
Definition: qbpp.hpp:968
Expr & simplify_as_spin()
Definition: qbpp.hpp:1960
Expr & binary_to_spin()
Definition: qbpp.hpp:992
Expr & reduce()
Definition: qbpp.hpp:988
Expr & operator-=(const Expr &expr)
Definition: qbpp.hpp:928
Expr & spin_to_binary()
Definition: qbpp.hpp:994
Expr(bool b)=delete
Expr(const Term &term, size_t term_capacity=TERM_CAPACITY)
Definition: qbpp.hpp:762
void set_constant(energy_t constant)
Definition: qbpp.hpp:966
bool positive_
Definition: qbpp.hpp:269
bool is_positive() const
Definition: qbpp.hpp:274
bool is_negative() const
Definition: qbpp.hpp:276
Inf operator-() const
Definition: qbpp.hpp:280
Inf operator+() const
Definition: qbpp.hpp:278
Inf()=default
Var get_var(vindex_t index) const
Definition: qbpp.hpp:1156
const Expr & get_expr() const
Definition: qbpp.hpp:1164
const std::shared_ptr< const Expr > expr_ptr_
Definition: qbpp.hpp:1107
const Terms & get_terms() const
Definition: qbpp.hpp:1170
energy_t get_constant() const
Definition: qbpp.hpp:1168
Model & operator=(const Model &)=delete
vindex_t var_count() const
Definition: qbpp.hpp:1154
Model()=delete
static const Expr & check_expr(const Expr &expr)
Definition: qbpp.hpp:1111
virtual size_t term_count() const
Definition: qbpp.hpp:1162
Model & operator=(Model &&)=delete
virtual ~Model()=default
Model(const Model &model)
Definition: qbpp.hpp:1136
const std::shared_ptr< const impl::IndexVarMapper > index_var_ptr_
Definition: qbpp.hpp:1109
vindex_t get_index(Var var) const
Definition: qbpp.hpp:1158
std::vector< Var > get_index_var() const
Definition: qbpp.hpp:1172
Model(const Expr &expr)
Definition: qbpp.hpp:1140
Model(Expr &&expr) noexcept
Definition: qbpp.hpp:1147
static Expr check_expr(Expr &&expr)
Definition: qbpp.hpp:1120
bool has(Var var) const
Definition: qbpp.hpp:1160
Model(Model &&)=default
QuadModel(Expr &&expr)
Definition: qbpp.hpp:1234
size_t term_count(vindex_t deg) const
Definition: qbpp.hpp:1258
coeff_t get_max_coeff() const
Definition: qbpp.hpp:1272
std::pair< vindex_t, coeff_t > get_quadratic(vindex_t i, vindex_t j) const
Definition: qbpp.hpp:1254
const std::vector< std::vector< std::pair< vindex_t, coeff_t > > > & quadratic_
Definition: qbpp.hpp:1201
QuadModel & operator=(QuadModel &&)=delete
QuadModel & operator=(const QuadModel &)=delete
const std::vector< std::vector< std::pair< vindex_t, coeff_t > > > & get_quadratic() const
Definition: qbpp.hpp:1245
coeff_t get_linear(vindex_t index) const
Definition: qbpp.hpp:1250
size_t term_count() const override
Definition: qbpp.hpp:1268
QuadModel(QuadModel &&) noexcept=default
QuadModel(const Expr &expr)
Definition: qbpp.hpp:1227
vindex_t get_degree(vindex_t index) const
Definition: qbpp.hpp:1252
const std::vector< coeff_t > & get_linear() const
Definition: qbpp.hpp:1241
const std::shared_ptr< const Impl > pimpl_
Definition: qbpp.hpp:1195
QuadModel(const QuadModel &)=default
const std::vector< vindex_t > & get_degree() const
Definition: qbpp.hpp:1243
coeff_t get_min_coeff() const
Definition: qbpp.hpp:1270
QuadModel(Model &&model)
Definition: qbpp.hpp:1220
const std::vector< vindex_t > & degree_
Definition: qbpp.hpp:1199
const std::vector< coeff_t > & linear_
Definition: qbpp.hpp:1197
Sol copy_sol() const
Definition: qbpp.hpp:1641
void set_bound(energy_t bound)
Definition: qbpp.hpp:1657
energy_t get_energy() const
Definition: qbpp.hpp:1637
std::tuple< Sol, double, std::string > get_sol_tts_solver() const
Definition: qbpp.hpp:1630
std::optional< qbpp::Sol > get_if_better(const Sol &my_sol)
Definition: qbpp.hpp:1626
vindex_t var_count() const
Definition: qbpp.hpp:1635
SolHolder(const SolHolder &other)=delete
std::mutex mtx_
Definition: qbpp.hpp:1589
SolHolder(const QuadModel &quad_model)
Definition: qbpp.hpp:1592
std::optional< energy_t > get_bound() const
Definition: qbpp.hpp:1659
double get_tts() const
Definition: qbpp.hpp:1653
virtual std::optional< double > set_if_better(const qbpp::Sol &new_sol, const std::string &solver="")
Definition: qbpp.hpp:1600
void clear()
Definition: qbpp.hpp:1646
const Sol & get_sol() const
Definition: qbpp.hpp:1639
std::string get_solver() const
Definition: qbpp.hpp:1655
virtual ~SolHolder()=default
virtual std::optional< qbpp::Sol > get_if_better(energy_t my_energy)
Definition: qbpp.hpp:1616
energy_t get_constant() const
Definition: qbpp.hpp:1558
vindex_t var_count() const
Definition: qbpp.hpp:1556
Sol set(const Sol &sol)
Definition: qbpp.hpp:1566
const QuadModel quad_model_
Definition: qbpp.hpp:1444
vindex_t popcount() const
Definition: qbpp.hpp:1543
bool operator<(const Sol &sol) const
Definition: qbpp.hpp:1491
void set_energy(energy_t energy)
Definition: qbpp.hpp:1550
void set(Var var, bool value)
Definition: qbpp.hpp:1528
void set(vindex_t index, bool value)
Definition: qbpp.hpp:1523
energy_t get_energy() const
Definition: qbpp.hpp:1545
Sol & operator=(Sol &&sol)
Definition: qbpp.hpp:1478
Var get_var(vindex_t index) const
Definition: qbpp.hpp:1560
Sol(const Sol &sol)=default
energy_t get(const Expr &expr) const
Definition: qbpp.hpp:1504
Sol(const QuadModel &quad_model)
Definition: qbpp.hpp:1462
virtual void flip(vindex_t index)
Definition: qbpp.hpp:1533
vindex_t get_index(Var var) const
Definition: qbpp.hpp:1562
Sol & operator=(const Sol &sol)
Definition: qbpp.hpp:1469
std::optional< energy_t > energy_
Definition: qbpp.hpp:1448
bool has(Var var) const
Definition: qbpp.hpp:1506
const impl::BitVector & get_bit_vector() const
Definition: qbpp.hpp:1552
var_val_t get(Var var) const
Definition: qbpp.hpp:1502
Sol(Sol &&sol)=default
void flip(Var var)
Definition: qbpp.hpp:1538
MapList get_map_list() const
Definition: qbpp.hpp:2834
void clear()
Definition: qbpp.hpp:1508
energy_t comp_energy() const
Definition: qbpp.hpp:2809
impl::BitVector bit_vector_
Definition: qbpp.hpp:1446
auto get(const Vector< T > &vec) const
Definition: qbpp.hpp:1514
virtual ~Sol()=default
var_val_t get(vindex_t index) const
Definition: qbpp.hpp:1500
bool operator==(const Sol &sol) const
Definition: qbpp.hpp:1487
Sol set(const MapList &map_list)
Definition: qbpp.hpp:1573
Sol()=delete
bool operator==(const Term &term) const
Definition: qbpp.hpp:663
Term(const Term &)=default
void set_coeff(coeff_t coeff)
Definition: qbpp.hpp:655
bool operator<=(const Term &term) const
Definition: qbpp.hpp:677
const Vars & get_vars() const
Definition: qbpp.hpp:659
bool operator<(const Term &term) const
Definition: qbpp.hpp:669
Term operator*(const Term &term) const
Definition: qbpp.hpp:711
Term & operator/=(energy_t val)
Definition: qbpp.hpp:694
bool operator!=(const Term &term) const
Definition: qbpp.hpp:667
coeff_t coeff_
Definition: qbpp.hpp:624
vindex_t var_count() const
Definition: qbpp.hpp:661
Vars & get_vars()
Definition: qbpp.hpp:657
Vars vars_
Definition: qbpp.hpp:626
Term(const Vars &vars, coeff_t coeff=1)
Definition: qbpp.hpp:641
Term(Term &&) noexcept=default
Term operator-() const &
Definition: qbpp.hpp:724
Term & operator*=(coeff_t val)
Definition: qbpp.hpp:681
Term()=default
Term operator*(energy_t val) const
Definition: qbpp.hpp:705
Term(Vars &&vars, coeff_t coeff=1) noexcept
Definition: qbpp.hpp:645
Term & operator-() &&
Definition: qbpp.hpp:719
Term & operator=(Term &&) noexcept=default
Term & operator=(const Term &)=default
Term(Var var, coeff_t coeff=1)
Definition: qbpp.hpp:638
coeff_t get_coeff() const
Definition: qbpp.hpp:653
Term & operator*=(const Term &term)
Definition: qbpp.hpp:687
VarIntCore(const std::string &var_str)
Definition: qbpp.hpp:1023
const std::string var_str_
Definition: qbpp.hpp:1021
vindex_t var_count() const
Definition: qbpp.hpp:1072
std::string get_name() const
Definition: qbpp.hpp:1070
const Vector< Var > new_vars() const
Definition: qbpp.hpp:1038
Var get_var(vindex_t i) const
Definition: qbpp.hpp:1080
const std::string var_str_
Definition: qbpp.hpp:1030
energy_t max_val() const
Definition: qbpp.hpp:1076
energy_t min_val() const
Definition: qbpp.hpp:1074
const Expr & get_expr() const
Definition: qbpp.hpp:1084
const energy_t max_val_
Definition: qbpp.hpp:1033
VarInt(const VarInt &)=default
const energy_t min_val_
Definition: qbpp.hpp:1032
VarValMap get_val_map(energy_t val) const
Definition: qbpp.hpp:1086
Var operator[](vindex_t i) const
Definition: qbpp.hpp:1082
const Expr new_expr() const
Definition: qbpp.hpp:1050
const Vector< Var > vars_
Definition: qbpp.hpp:1035
VarInt(const std::string &var_str, energy_t min_val, energy_t max_val, std::shared_ptr< std::vector< coeff_t >> coeffs_ptr)
Definition: qbpp.hpp:1059
coeff_t get_coeff(vindex_t i) const
Definition: qbpp.hpp:1078
const std::shared_ptr< std::vector< coeff_t > > coeffs_ptr_
Definition: qbpp.hpp:1034
const Expr expr_
Definition: qbpp.hpp:1036
size_t size() const
Definition: qbpp.hpp:540
bool operator!=(Var var) const
Definition: qbpp.hpp:533
vindex_t get_index() const
Definition: qbpp.hpp:529
Var(const Var &var)=default
bool operator>(Var var) const
Definition: qbpp.hpp:536
Var(vindex_t index)
Definition: qbpp.hpp:528
bool operator<=(Var var) const
Definition: qbpp.hpp:538
bool operator==(Var var) const
Definition: qbpp.hpp:531
Var & operator=(const Var &var)=default
bool operator<(Var var) const
Definition: qbpp.hpp:534
vindex_t index_
Definition: qbpp.hpp:519
Var()=delete
void emplace_back(T &&t)
Definition: qbpp.hpp:377
Vector< T > & operator-=(const Vector< U > &rhs)
Definition: qbpp.hpp:431
T & operator[](size_t i)
Definition: qbpp.hpp:381
Vector< T > & operator/=(energy_t val)
Definition: qbpp.hpp:471
Vector< T > & transpose()
Definition: qbpp.hpp:512
Vector< T > & operator*=(const Vector< U > &rhs)
Definition: qbpp.hpp:444
Vector< T > & vector_operation(Vector< U > &&rhs, Op operation)
Definition: qbpp.hpp:310
Vector(std::initializer_list< T > init)
Definition: qbpp.hpp:346
void push_back(const T &t)
Definition: qbpp.hpp:375
Vector< T > & vector_operation(const Expr &rhs, Op operation)
Definition: qbpp.hpp:328
Vector< T > & simplify(Vars(*sort_vars_func)(const Vars &)=sort_vars)
Definition: qbpp.hpp:3657
Vector< T > & operator*=(const Expr &expr)
Definition: qbpp.hpp:466
Vector< T > & operator+=(const Expr &expr)
Definition: qbpp.hpp:456
Vector< T > & operator-=(Vector< U > &&rhs)
Definition: qbpp.hpp:436
const T & operator[](size_t i) const
Definition: qbpp.hpp:383
auto begin()
Definition: qbpp.hpp:391
auto end()
Definition: qbpp.hpp:393
const std::vector< T > get_data() const
Definition: qbpp.hpp:369
Vector(size_t size)
Definition: qbpp.hpp:352
std::vector< T > get_data()
Definition: qbpp.hpp:371
void reserve(size_t size)
Definition: qbpp.hpp:379
Vector< T > & operator+=(const Vector< U > &rhs)
Definition: qbpp.hpp:418
Vector(const Vector< U > &rhs)
Definition: qbpp.hpp:363
Vector< T > & binary_to_spin()
Definition: qbpp.hpp:498
Vector()=default
Vector< T > & operator=(energy_t rhs)
Definition: qbpp.hpp:412
Vector & operator=(Vector< T > &&)=default
Vector< T > & simplify_as_spin()
Definition: qbpp.hpp:493
Vector< T > & operator+=(Vector< U > &&rhs)
Definition: qbpp.hpp:423
void resize(size_t size)
Definition: qbpp.hpp:373
std::vector< T >::iterator erase(typename std::vector< T >::iterator first, typename std::vector< T >::iterator last)
Definition: qbpp.hpp:400
Vector< T > & operator=(const Expr &rhs)
Definition: qbpp.hpp:407
Vector(U begin, U end)
Definition: qbpp.hpp:360
Vector< T > & vector_operation(const Vector< U > &rhs, Op operation)
Definition: qbpp.hpp:294
Vector< T > & operator-=(const Expr &expr)
Definition: qbpp.hpp:461
Vector(U size, const T &value)
Definition: qbpp.hpp:356
Vector(Vector< T > &&)=default
Vector< T > & simplify_as_binary()
Definition: qbpp.hpp:488
Vector< T > & reduce()
Definition: qbpp.hpp:3669
Vector< T > & operator*=(Vector< U > &&rhs)
Definition: qbpp.hpp:449
Vector(const Vector< T > &)=default
auto begin() const
Definition: qbpp.hpp:387
std::vector< T >::iterator erase(typename std::vector< T >::iterator pos)
Definition: qbpp.hpp:395
Vector & operator=(const Vector< T > &)=default
Vector< T > & replace(const MapList &map_list)
Definition: qbpp.hpp:3663
std::vector< T > data_
Definition: qbpp.hpp:291
Vector< T > & sqr()
Definition: qbpp.hpp:481
size_t size() const
Definition: qbpp.hpp:385
auto end() const
Definition: qbpp.hpp:389
Vector< T > & spin_to_binary()
Definition: qbpp.hpp:503
uint64_t get64(vindex_t index64) const
Definition: qbpp.hpp:1405
BitVector & operator=(BitVector &bit_vector)
Definition: qbpp.hpp:1316
vindex_t popcount() const
Definition: qbpp.hpp:1424
std::string str() const
Definition: qbpp.hpp:1432
bool get(vindex_t index) const
Definition: qbpp.hpp:1381
void flip(vindex_t index)
Definition: qbpp.hpp:1398
vindex_t size() const
Definition: qbpp.hpp:1377
void set(vindex_t index, bool value)
Definition: qbpp.hpp:1388
const vindex_t size64_
Definition: qbpp.hpp:1280
std::unique_ptr< uint64_t[]> bits_
Definition: qbpp.hpp:1282
const vindex_t bit_count_
Definition: qbpp.hpp:1278
vindex_t size64() const
Definition: qbpp.hpp:1379
BitVector & operator=(const BitVector &bit_vector)
Definition: qbpp.hpp:1303
BitVector(vindex_t bit_count)
Definition: qbpp.hpp:1285
BitVector(const BitVector &bit_vector)
Definition: qbpp.hpp:1290
bool operator!=(const BitVector &bit_vector) const
Definition: qbpp.hpp:1349
BitVector & operator=(BitVector &&bit_vector)
Definition: qbpp.hpp:1328
BitVector(BitVector &&bit_vector)
Definition: qbpp.hpp:1298
bool operator==(const BitVector &bit_vector) const
Definition: qbpp.hpp:1340
bool operator<(const BitVector &bit_vector) const
Definition: qbpp.hpp:1353
uint64_t set64(vindex_t index64, uint64_t value)
Definition: qbpp.hpp:1412
const std::vector< vindex_t > & get_var_index() const
Definition: qbpp.hpp:605
const std::vector< vindex_t > var_index_
Definition: qbpp.hpp:590
bool has(Var var) const
Definition: qbpp.hpp:617
std::vector< Var > compute_index_var(const Expr &expr)
Definition: qbpp.hpp:2127
const std::vector< Var > & get_index_var() const
Definition: qbpp.hpp:603
std::vector< vindex_t > compute_var_index(const std::vector< Var > &index_var)
Definition: qbpp.hpp:2157
const std::vector< Var > index_var_
Definition: qbpp.hpp:589
IndexVarMapper(const Expr &expr)
Definition: qbpp.hpp:599
vindex_t get_index(Var var) const
Definition: qbpp.hpp:611
Var get_var(vindex_t index) const
Definition: qbpp.hpp:615
vindex_t var_count() const
Definition: qbpp.hpp:607
VarSet & operator=(const impl::VarSet &)=delete
static std::string new_unnamed_var_str()
Definition: qbpp.hpp:577
VarSet(const impl::VarSet &)=delete
std::vector< std::string > var_str_
Definition: qbpp.hpp:547
static vindex_t all_var_count()
Definition: qbpp.hpp:565
vindex_t unnamed_vars
Definition: qbpp.hpp:549
static std::string str(Var var)
Definition: qbpp.hpp:583
static VarSet & get_instance()
Definition: qbpp.hpp:558
static Var var(const std::string &var_str)
Definition: qbpp.hpp:569
Expr equal(const std::vector< T > &lhs, const std::vector< T > &rhs)
Definition: qbpp.hpp:1938
Generates a QUBO Expression for the Graph Coloring Problem using QUBO++ library.
Definition: qbpp.hpp:53
Expr vector_sum(const T &items[[maybe_unused]])
Definition: qbpp.hpp:3282
energy_t gcd(energy_t a, energy_t b)
Definition: qbpp.hpp:254
COEFF_TYPE coeff_t
Definition: qbpp.hpp:128
const Inf inf
Definition: qbpp.hpp:287
VarValMap list_to_var_val(const MapList &map_list)
Definition: qbpp.hpp:1983
Expr binary_to_spin(const Expr &expr)
Definition: qbpp.hpp:2892
Expr simplify_as_spin(const Expr &expr)
Definition: qbpp.hpp:2768
std::ostream & operator<<(std::ostream &os, const std::pair< std::string, Vector< T >> &vec)
Definition: qbpp.hpp:1888
Expr spin_to_binary(const Expr &expr)
Definition: qbpp.hpp:2911
std::string str(const Vector< T > &vec, const std::string &prefix="", const std::string &separator=",")
Definition: qbpp.hpp:1839
Var var(const std::string &var_str)
Definition: qbpp.hpp:2172
std::unordered_map< Var, vindex_t, impl::var_hash > VarIndexMap
Definition: qbpp.hpp:140
auto operator<=(energy_t lhs, VarIntCore &&rhs)
Definition: qbpp.hpp:2283
std::unordered_map< Var, var_val_t, impl::var_hash > VarValMap
Definition: qbpp.hpp:138
qbpp::Expr total_sum(const T &arg[[maybe_unused]])
Definition: qbpp.hpp:3262
std::string file_line(const char *file, int line, Args... args)
Definition: qbpp.hpp:79
Expr operator==(const Expr &expr, energy_t val)
Definition: qbpp.hpp:2543
VarInt new_var_int(const std::string &var_str, energy_t min_val, energy_t max_val, energy_t base_coeff=1)
Definition: qbpp.hpp:2270
auto simplify_as_binary(const Vector< T > &arg)
Definition: qbpp.hpp:2764
auto vector_product_impl(const T &items)
Definition: qbpp.hpp:3407
std::vector< Term > Terms
Definition: qbpp.hpp:102
boost::multiprecision::int128_t int128_t
Definition: qbpp.hpp:104
VarIntCore var_int(const std::string &var_str)
Definition: qbpp.hpp:2217
boost::multiprecision::uint128_t uint128_t
Definition: qbpp.hpp:105
std::string str_impl(const Expr &expr, std::function< std::string(Var)> str)
Definition: qbpp.hpp:1690
boost::multiprecision::uint512_t uint512_t
Definition: qbpp.hpp:109
auto element_wise(const Vector< T > &arg, F func)
Definition: qbpp.hpp:3533
Expr operator-(const Expr &expr)
Definition: qbpp.hpp:2509
double get_time()
Definition: qbpp.hpp:3815
std::string str(Var var)
Definition: qbpp.hpp:1715
auto operator==(const Vector< T > &lhs, energy_t rhs)
Definition: qbpp.hpp:3108
Vector< Vector< Expr > > transpose(const Vector< Vector< T >> &vec)
Definition: qbpp.hpp:3618
Vector< Expr > get_col(const Vector< Vector< Expr >> &vec, size_t index)
Definition: qbpp.hpp:3595
auto eval(const Vector< Vector< T >> &arg, const MapList &map_list)
Definition: qbpp.hpp:3498
energy_t eval_var_val_map(const Expr &expr, const VarValMap &var_val_map)
Definition: qbpp.hpp:2086
auto vector_sum_impl(const T &items)
Definition: qbpp.hpp:3297
MapDict list_to_dict(const MapList &map_list)
Definition: qbpp.hpp:2007
Expr toExpr(const T &arg)
Definition: qbpp.hpp:2335
Expr && operator*(Expr &&lhs, Expr &&rhs)
Definition: qbpp.hpp:2419
uint32_t vindex_t
Definition: qbpp.hpp:122
Expr vector_product(const T &items[[maybe_unused]])
Definition: qbpp.hpp:3392
void sort_vars_in_place(Vars &vars)
Definition: qbpp.hpp:2598
Vars sort_vars_as_binary(const Vars &vars)
Definition: qbpp.hpp:2611
Vars sort_vars_as_spin(const Vars &vars)
Definition: qbpp.hpp:2619
Expr replace(const Term &term, const MapDict &map_dict)
Definition: qbpp.hpp:2032
vindex_t all_var_count()
Definition: qbpp.hpp:2209
auto var_int(const std::string &var_str, T size, Args... args)
Definition: qbpp.hpp:2227
std::string str_short(const Expr &expr)
Definition: qbpp.hpp:1894
bool is_simplified(const Expr &expr)
Definition: qbpp.hpp:2777
auto var(T size, Args... args)
Definition: qbpp.hpp:2205
boost::multiprecision::int1024_t int1024_t
Definition: qbpp.hpp:110
Expr sum(const Vector< T > &items)
Definition: qbpp.hpp:3209
Expr simplify(const Expr &expr, Vars(*sort_vars_func)(const Vars &))
Definition: qbpp.hpp:2657
T abs(T val)
Definition: qbpp.hpp:250
bool is_binary(const Expr &expr)
Definition: qbpp.hpp:2795
ENERGY_TYPE energy_t
Definition: qbpp.hpp:130
Expr simplify_as_binary(const Expr &expr)
Definition: qbpp.hpp:2759
Vector< T > simplify(const Vector< T > &vec, Vars(*sort_vars_func)(const Vars &)=sort_vars)
Definition: qbpp.hpp:2750
boost::container::small_vector< Var, 2 > Vars
Definition: qbpp.hpp:96
boost::multiprecision::uint256_t uint256_t
Definition: qbpp.hpp:107
energy_t eval(const Expr &expr, const Sol &sol)
Definition: qbpp.hpp:2109
boost::multiprecision::int512_t int512_t
Definition: qbpp.hpp:108
Expr total_product(const Vector< Vector< T >> &items)
Definition: qbpp.hpp:3371
Expr reduce_cascade(const Term &term)
Definition: qbpp.hpp:2860
Expr simplify_seq(const Expr &expr, Vars(*sort_vars_func)(const Vars &)=sort_vars)
Definition: qbpp.hpp:2636
Vector< Expr > get_row(const Vector< Vector< Expr >> &vec, vindex_t index)
Definition: qbpp.hpp:3590
Vector< Expr > sqr(const Vector< T > &arg)
Definition: qbpp.hpp:3547
std::ostream & operator<<(std::ostream &os, Var var)
Definition: qbpp.hpp:1849
Expr reduce(const Expr &expr)
Definition: qbpp.hpp:2878
const vindex_t vindex_limit
Definition: qbpp.hpp:124
Expr expr()
Definition: qbpp.hpp:2318
std::unordered_map< Var, Expr, impl::var_hash > MapDict
Definition: qbpp.hpp:136
Expr comparison(const Expr &expr, energy_t minimum, energy_t maximum)
Definition: qbpp.hpp:2547
std::vector< coeff_t > comp_coeffs(energy_t min_val, energy_t max_val, energy_t base_coeff=1)
Definition: qbpp.hpp:2249
Expr && operator+(Expr &&lhs, Expr &&rhs)
Definition: qbpp.hpp:2445
std::tuple< bool, size_t, size_t, coeff_t, coeff_t > check_if_simplified_as_binary(const Expr &expr)
Definition: qbpp.hpp:3676
Expr product(const T &arg[[maybe_unused]])
Definition: qbpp.hpp:3321
boost::multiprecision::uint1024_t uint1024_t
Definition: qbpp.hpp:111
int8_t var_val_t
Definition: qbpp.hpp:126
std::unordered_map< Var, Expr, impl::var_hash > VarExprMap
Definition: qbpp.hpp:142
energy_t toInt(const Expr &expr)
Definition: qbpp.hpp:3437
Expr && operator/(Expr &&expr, energy_t val)
Definition: qbpp.hpp:2486
Expr total_product_impl(const T &item)
Definition: qbpp.hpp:3352
auto expr(T size, Args... args)
Definition: qbpp.hpp:2323
Vars sort_vars(const Vars &vars)
Definition: qbpp.hpp:2605
boost::multiprecision::int256_t int256_t
Definition: qbpp.hpp:106
std::unordered_map< Vars, coeff_t, impl::vars_hash > VarsCoeffMap
Definition: qbpp.hpp:144
Expr total_sum_impl(const T &item)
Definition: qbpp.hpp:3231
boost::multiprecision::cpp_int cpp_int
Definition: qbpp.hpp:112
Expr reduce_sum(const Term &term)
Definition: qbpp.hpp:2843
std::list< std::pair< std::variant< Var, VarInt >, Expr > > MapList
Definition: qbpp.hpp:134
auto simplify_as_spin(const Vector< T > &arg)
Definition: qbpp.hpp:2773
int32_t onehot_to_int(const Vector< var_val_t > &vec)
Definition: qbpp.hpp:3627
#define VERSION
Definition: qbpp.hpp:18
#define THROW_MESSAGE(...)
Definition: qbpp.hpp:86
#define COEFF_TYPE
Definition: qbpp.hpp:115
#define ENERGY_TYPE
Definition: qbpp.hpp:119
#define TERM_CAPACITY
Definition: qbpp.hpp:88
std::vector< vindex_t > degree_
Definition: qbpp.hpp:1184
Impl(const qbpp::Model &model)
Definition: qbpp.hpp:3731
std::vector< coeff_t > linear_
Definition: qbpp.hpp:1182
std::vector< std::vector< std::pair< vindex_t, coeff_t > > > quadratic_
Definition: qbpp.hpp:1186
size_t operator()(const Var var) const
Definition: qbpp.hpp:1915
size_t operator()(const Vars &vars) const
Definition: qbpp.hpp:1920