19#include <nlohmann/json.hpp>
35template <
typename FloatType>
46 int rate_call_k_local = 10;
49 int64_t count_call_updater = 0;
55 const cimod::Vartype vartype = cimod::Vartype::BINARY;
64 : num_binaries(init_binaries.size()), binaries(init_binaries),
65 binaries_v_(init_binaries) {
67 cimod::CheckVariables(binaries, vartype);
69 const auto &poly_key_list = poly_graph.
get_keys();
70 const auto &poly_value_list = poly_graph.
get_values();
72 if (poly_key_list.size() != poly_value_list.size()) {
73 throw std::runtime_error(
74 "The sizes of key_list and value_list must match each other");
76 if (poly_key_list.size() == 0) {
77 throw std::runtime_error(
"The interaction is empty.");
80 std::unordered_set<graph::Index> active_binary_set;
82 poly_key_list_.clear();
83 poly_value_list_.clear();
85 for (std::size_t i = 0; i < poly_key_list.size(); ++i) {
86 if (poly_value_list[i] != 0.0) {
87 poly_key_list_.push_back(poly_key_list[i]);
88 poly_value_list_.push_back(poly_value_list[i]);
89 for (
const auto &it : poly_key_list[i]) {
90 active_binary_set.emplace(it);
94 num_interactions_ =
static_cast<int64_t
>(poly_key_list_.size());
96 active_binaries_ = std::vector<graph::Index>(active_binary_set.begin(),
97 active_binary_set.end());
98 std::sort(active_binaries_.begin(), active_binaries_.end());
103 std::abs(FindMaxInteraction().second * utility::THRESHOLD<FloatType>);
104 min_effective_dE_ = std::abs(FindMinInteraction(thres_hold).second);
112 const nlohmann::json &j)
113 : num_binaries(init_binaries.size()), binaries(init_binaries),
114 binaries_v_(init_binaries) {
116 cimod::CheckVariables(binaries, vartype);
118 if (j.at(
"vartype") !=
"BINARY") {
119 throw std::runtime_error(
"Only binary variables are supported");
123 const auto &poly_key_list = std::get<0>(v_k_v);
124 const auto &poly_value_list = std::get<1>(v_k_v);
126 if (poly_key_list.size() != poly_value_list.size()) {
127 throw std::runtime_error(
128 "The sizes of key_list and value_list must match each other");
130 if (poly_key_list.size() == 0) {
131 throw std::runtime_error(
"The interaction is empty.");
134 num_interactions_ =
static_cast<int64_t
>(poly_key_list.size());
136 poly_key_list_.resize(num_interactions_);
137 poly_value_list_.resize(num_interactions_);
139#pragma omp parallel for
140 for (int64_t i = 0; i < num_interactions_; ++i) {
141 poly_key_list_[i] = poly_key_list[i];
142 poly_value_list_[i] = poly_value_list[i];
146 active_binaries_.resize(num_binaries);
147 std::iota(active_binaries_.begin(), active_binaries_.end(), 0);
153 std::abs(FindMaxInteraction().second * utility::THRESHOLD<FloatType>);
154 min_effective_dE_ = std::abs(FindMinInteraction(thres_hold).second);
161 cimod::CheckVariables(init_binaries, vartype);
163 if (init_binaries.size() != binaries.size()) {
164 throw std::runtime_error(
165 "The size of initial binaries does not equal to system size");
167 for (
const auto &index_binary : active_binaries_) {
168 if (binaries[index_binary] != init_binaries[index_binary]) {
169 update_system_single(index_binary);
171 if (binaries[index_binary] != init_binaries[index_binary]) {
172 std::stringstream ss;
173 ss <<
"Unknown error detected in " << __func__;
174 throw std::runtime_error(ss.str());
184 dE_.resize(num_binaries);
185 dE_v_.resize(num_binaries);
188 max_effective_dE_ = std::abs(poly_value_list_.front());
190 for (
const auto &index_binary : active_binaries_) {
195 for (
const auto &index_key : adj_[index_binary]) {
196 if (zero_count_[index_key] + binary == 1) {
197 val += poly_value_list_[index_key];
200 abs_val += std::abs(poly_value_list_[index_key]);
202 dE_[index_binary] = (-2 * binary + 1) * val;
203 dE_v_[index_binary] = dE_[index_binary];
205 if (flag && max_effective_dE_ < abs_val) {
206 max_effective_dE_ = abs_val;
215 return dE_[index_binary];
226 for (
const auto &index_binary : poly_key_list_[index_key]) {
227 if (binaries_v_[index_binary] == 0) {
228 dE += dE_v_[index_binary];
229 virtual_update_system_single(index_binary);
240 for (
const auto &index_binary : update_index_binaries_v_) {
241 binaries[index_binary] = binaries_v_[index_binary];
243 for (
const auto &index_zero_count : update_index_zero_count_v_) {
244 zero_count_[index_zero_count] = zero_count_v_[index_zero_count];
246 for (
const auto &index_dE : update_index_dE_v_) {
247 dE_[index_dE] = dE_v_[index_dE];
249 update_index_binaries_v_.clear();
250 update_index_zero_count_v_.clear();
251 update_index_dE_v_.clear();
257 const graph::Binary update_binary = binaries[index_update_binary];
258 const int coeef = -2 * update_binary + 1;
259 const int count = +2 * update_binary - 1;
260 for (
const auto &index_key : adj_[index_update_binary]) {
261 const FloatType val = poly_value_list_[index_key];
262 for (
const auto &index_binary : poly_key_list_[index_key]) {
264 if (zero_count_[index_key] + update_binary + binary == 2 &&
265 index_binary != index_update_binary) {
266 dE_[index_binary] += coeef * (-2 * binary + 1) * val;
267 dE_v_[index_binary] = dE_[index_binary];
270 zero_count_[index_key] += count;
271 zero_count_v_[index_key] = zero_count_[index_key];
273 dE_[index_update_binary] *= -1;
274 dE_v_[index_update_binary] = dE_[index_update_binary];
275 binaries[index_update_binary] = 1 - binaries[index_update_binary];
276 binaries_v_[index_update_binary] = binaries[index_update_binary];
282 const graph::Binary update_binary = binaries_v_[index_update_binary];
283 const int coeef = -2 * update_binary + 1;
284 const int count = +2 * update_binary - 1;
285 for (
const auto &index_key : adj_[index_update_binary]) {
286 const FloatType val = poly_value_list_[index_key];
287 for (
const auto &index_binary : poly_key_list_[index_key]) {
289 if (zero_count_v_[index_key] + update_binary + binary == 2 &&
290 index_binary != index_update_binary) {
291 dE_v_[index_binary] += coeef * (-2 * binary + 1) * val;
292 update_index_dE_v_.emplace(index_binary);
295 zero_count_v_[index_key] += count;
296 update_index_zero_count_v_.push_back(index_key);
298 dE_v_[index_update_binary] *= -1;
299 update_index_dE_v_.emplace(index_update_binary);
300 binaries_v_[index_update_binary] = 1 - binaries_v_[index_update_binary];
301 update_index_binaries_v_.push_back(index_update_binary);
306 for (
const auto &index_binary : update_index_binaries_v_) {
307 binaries_v_[index_binary] = binaries[index_binary];
309 for (
const auto &index_zero_count : update_index_zero_count_v_) {
310 zero_count_v_[index_zero_count] = zero_count_[index_zero_count];
312 for (
const auto &index_dE : update_index_dE_v_) {
313 dE_v_[index_dE] = dE_[index_dE];
315 update_index_binaries_v_.clear();
316 update_index_zero_count_v_.clear();
317 update_index_dE_v_.clear();
324 if (rate_k_local <= 0) {
325 throw std::runtime_error(
"rate_k_local must be larger than zero");
327 rate_call_k_local = rate_k_local;
338 return zero_count_[index_key];
345 return poly_value_list_[index_key];
352 inline const std::vector<graph::Index> &
353 get_adj(
const std::size_t index_binary)
const {
354 return adj_[index_binary];
361 return active_binaries_;
376 const cimod::PolynomialValueList<FloatType> &
get_values()
const {
377 return poly_value_list_;
383 const cimod::PolynomialKeyList<graph::Index> &
get_keys()
const {
384 return poly_key_list_;
390 const std::vector<std::vector<graph::Index>> &
get_adj()
const {
return adj_; }
448 std::vector<FloatType>
dE_;
455 std::vector<std::vector<graph::Index>>
adj_;
507 std::vector<graph::Index> index(num_interactions_);
508#pragma omp parallel for
509 for (int64_t i = 0; i < num_interactions_; ++i) {
513 auto compare_value = [
this](
const std::size_t i1,
const std::size_t i2) {
514 return poly_value_list_[i1] < poly_value_list_[i2];
516 auto compare_size = [
this](
const std::size_t i1,
const std::size_t i2) {
517 return poly_key_list_[i1].size() < poly_key_list_[i2].size();
520 std::stable_sort(index.begin(), index.end(), compare_size);
521 std::stable_sort(index.begin(), index.end(), compare_value);
523 cimod::PolynomialValueList<FloatType> vv = poly_value_list_;
525#pragma omp parallel for
526 for (int64_t i = 0; i < num_interactions_; ++i) {
527 poly_value_list_[i] = vv[index[i]];
530 cimod::PolynomialValueList<FloatType>().swap(vv);
532 cimod::PolynomialKeyList<graph::Index> ii = poly_key_list_;
534#pragma omp parallel for
535 for (int64_t i = 0; i < num_interactions_; ++i) {
536 poly_key_list_[i] = ii[index[i]];
544 adj_.resize(num_binaries);
545 for (int64_t i = 0; i < num_interactions_; ++i) {
546 for (
const auto &index : poly_key_list_[i]) {
547 adj_[index].push_back(i);
552 auto compare_size = [
this](
const int64_t i1,
const int64_t i2) {
553 return poly_key_list_[i1].size() < poly_key_list_[i2].size();
555 auto compare_value = [
this](
const int64_t i1,
const int64_t i2) {
556 return poly_value_list_[i1] < poly_value_list_[i2];
559 int64_t adj_size =
static_cast<int64_t
>(adj_.size());
560#pragma omp parallel for
561 for (int64_t i = 0; i < adj_size; ++i) {
562 std::stable_sort(adj_[i].begin(), adj_[i].end(), compare_size);
563 std::stable_sort(adj_[i].begin(), adj_[i].end(), compare_value);
569 zero_count_.resize(num_interactions_);
570 zero_count_v_.resize(num_interactions_);
571#pragma omp parallel for
572 for (int64_t i = 0; i < num_interactions_; ++i) {
573 int64_t zero_count = 0;
574 for (
const auto &index : poly_key_list_[i]) {
575 if (binaries[index] == 0) {
579 zero_count_[i] = zero_count;
580 zero_count_v_[i] = zero_count;
588 if (poly_key_list_.size() == 0) {
589 throw std::runtime_error(
"Interactions are empty.");
592 std::vector<graph::Index> max_key = {};
593 for (std::size_t i = 0; i < poly_key_list_.size(); ++i) {
594 if (std::abs(max_val) < std::abs(poly_value_list_[i])) {
595 max_val = poly_value_list_[i];
596 max_key = poly_key_list_[i];
599 return std::pair<std::vector<graph::Index>,
FloatType>(max_key, max_val);
605 std::pair<std::vector<graph::Index>,
FloatType>
607 if (poly_key_list_.size() == 0) {
608 throw std::runtime_error(
"Interactions are empty.");
611 std::vector<graph::Index> min_key = poly_key_list_[0];
612 for (std::size_t i = 0; i < poly_key_list_.size(); ++i) {
613 if (poly_value_list_[i] != 0.0 &&
614 std::abs(poly_value_list_[i]) < std::abs(min_val) &&
615 threshold < std::abs(poly_value_list_[i])) {
616 min_val = poly_value_list_[i];
617 min_key = poly_key_list_[i];
621 if (std::abs(min_val) <= threshold) {
622 throw std::runtime_error(
"No minimum value in interactions");
624 return std::pair<std::vector<graph::Index>,
FloatType>(min_key, min_val);
632template <
typename GraphType>
634 const GraphType &init_interaction) {
644 const nlohmann::json &init_obj) {
Polynomial graph class, which can treat many-body interactions.
Definition polynomial.hpp:47
const cimod::PolynomialKeyList< Index > & get_keys() const
Get the PolynomialKeyList object (all the keys of polynomial interactions).
Definition polynomial.hpp:180
const cimod::PolynomialValueList< FloatType > & get_values() const
Get the PolynomialValueList object (all the values of polynomial interactions).
Definition polynomial.hpp:187
const std::vector< graph::Index > & get_adj(const std::size_t index_binary) const
Get the adjacency list (the index of interactions) of the binary specified by "index_binary".
Definition k_local_polynomial.hpp:353
int64_t GetNumInteractions() const
Get the number of interactions.
Definition k_local_polynomial.hpp:331
FloatType dE_single(const graph::Index index_binary) const
Return the energy difference of single spin flip update.
Definition k_local_polynomial.hpp:214
graph::Binaries binaries_v_
Virtually updated binary configulations, which is used to implement k-local update.
Definition k_local_polynomial.hpp:484
void virtual_update_system_single(const graph::Index index_update_binary)
Virtually flip specified binary by single spin flip.
Definition k_local_polynomial.hpp:281
cimod::PolynomialValueList< FloatType > poly_value_list_
The list of the values of the polynomial interactions as std::vector<FloatType>.
Definition k_local_polynomial.hpp:463
void ResetZeroCount()
Set zero_count_ and zero_count_v_.
Definition k_local_polynomial.hpp:568
std::vector< graph::Index > active_binaries_
The list of the binaries connected by at least one interaction.
Definition k_local_polynomial.hpp:466
const cimod::PolynomialKeyList< graph::Index > & get_keys() const
Get the PolynomialKeyList object, which is the list of the indices of the polynomial interactions as ...
Definition k_local_polynomial.hpp:383
KLocalPolynomial(const graph::Binaries &init_binaries, const nlohmann::json &j)
Constructor of KLocalPolynomial system class.
Definition k_local_polynomial.hpp:111
KLocalPolynomial(const graph::Binaries &init_binaries, const graph::Polynomial< FloatType > &poly_graph)
Constructor of KLocalPolynomial system class.
Definition k_local_polynomial.hpp:62
FloatType get_min_effective_dE() const
Get "min_effective_dE_", which is a rough lower bound of energy gap.
Definition k_local_polynomial.hpp:371
int64_t GetZeroCount(const std::size_t index_key) const
Return the number of variables taking the zero in the interaction specified by "index_key".
Definition k_local_polynomial.hpp:337
std::vector< int64_t > zero_count_
The number of variables taking the zero in each interaction.
Definition k_local_polynomial.hpp:451
void SortInteractions()
Sort interactions in accordance with its value and the degree of interactions (ascending order).
Definition k_local_polynomial.hpp:505
const cimod::PolynomialValueList< FloatType > & get_values() const
Get the PolynomialValueList object, which is the list of the values of the polynomial interactions as...
Definition k_local_polynomial.hpp:376
FloatType dE_k_local(const std::size_t index_key)
Return the energy difference of k-local update.
Definition k_local_polynomial.hpp:224
FloatType min_effective_dE_
Rough lower bound of energy gap.
Definition k_local_polynomial.hpp:472
void reset_dE()
Reset energy differences (dE), which is used to determine whether to flip the binary or not.
Definition k_local_polynomial.hpp:181
std::vector< std::size_t > update_index_zero_count_v_
The list of virtually updated index of zero_count_v_, which is used to implement k-local update.
Definition k_local_polynomial.hpp:492
std::vector< std::size_t > update_index_binaries_v_
The list of virtually updated index of binaries_v_, which is used to implement k-local update.
Definition k_local_polynomial.hpp:496
std::vector< FloatType > dE_v_
The energy differences when flipping a binary, which is used to implement k-local update.
Definition k_local_polynomial.hpp:480
std::unordered_set< std::size_t > update_index_dE_v_
The list of virtually updated delta E's, which is used to implement k-local update.
Definition k_local_polynomial.hpp:488
void update_system_single(const graph::Index index_update_binary)
Flip specified binary by single spin flip.
Definition k_local_polynomial.hpp:256
std::vector< FloatType > dE_
The energy differences when flipping a binary.
Definition k_local_polynomial.hpp:448
const int64_t num_binaries
The number of binaries.
Definition k_local_polynomial.hpp:43
void SetAdj()
Set adjacency list.
Definition k_local_polynomial.hpp:542
void reset_virtual_system()
Reset binary configurations virtually updated by k-local update.
Definition k_local_polynomial.hpp:305
graph::Binaries binaries
Binary configurations.
Definition k_local_polynomial.hpp:52
void set_rate_call_k_local(int rate_k_local)
Set "rate_call_k_local".
Definition k_local_polynomial.hpp:323
std::pair< std::vector< graph::Index >, FloatType > FindMinInteraction(const FloatType threshold=0.0) const
Return the key and value of the absolute minimum interaction.
Definition k_local_polynomial.hpp:606
const std::vector< std::vector< graph::Index > > & get_adj() const
Get the adjacency list, which is the list of the indices of polynomial interactions including specifi...
Definition k_local_polynomial.hpp:390
const std::vector< graph::Index > & get_active_binaries() const
Get "active_binaries_", which is the list of the binaries connected by at least one interaction.
Definition k_local_polynomial.hpp:360
void reset_binaries(const graph::Binaries &init_binaries)
Reset KLocalPolynomial system with new binary configurations.
Definition k_local_polynomial.hpp:159
cimod::PolynomialKeyList< graph::Index > poly_key_list_
The list of the indices of the polynomial interactions as std::vector<std::vector<graph::Index>>.
Definition k_local_polynomial.hpp:459
std::vector< std::vector< graph::Index > > adj_
Adjacency list, which is the list of the indices of polynomial interactions including specific binary...
Definition k_local_polynomial.hpp:455
std::string get_vartype_string() const
Get the vartype as std::string, which must be "BINARY".
Definition k_local_polynomial.hpp:394
void update_system_k_local()
Update binary configurations by k-local update.
Definition k_local_polynomial.hpp:239
FloatType get_max_effective_dE() const
Get "max_effective_dE_", which is a upper bound of energy gap.
Definition k_local_polynomial.hpp:366
FloatType GetPolyValue(const std::size_t index_key) const
Get the value of the interaction specified by "index_key".
Definition k_local_polynomial.hpp:344
std::vector< int64_t > zero_count_v_
The list of virtually updated the number of variables taking the zero in each interaction,...
Definition k_local_polynomial.hpp:500
FloatType max_effective_dE_
Upper bound of energy gap.
Definition k_local_polynomial.hpp:469
std::pair< std::vector< graph::Index >, FloatType > FindMaxInteraction() const
Return the key and value of the absolute maximum interaction.
Definition k_local_polynomial.hpp:587
int64_t num_interactions_
The number of the interactions.
Definition k_local_polynomial.hpp:445
KLocalPolynomial class, which is a system to solve higher order unconstrained binary optimization (HU...
Definition k_local_polynomial.hpp:32
std::vector< Binary > Binaries
Definition graph.hpp:29
auto json_parse(const json &obj, bool relabel=true)
parse json object from bqm.to_serializable
Definition parse.hpp:50
int Binary
Definition graph.hpp:28
std::size_t Index
Definition graph.hpp:30
auto make_k_local_polynomial(const graph::Binaries &init_binaries, const GraphType &init_interaction)
Helper function for ClassicalIsingPolynomial constructor.
Definition k_local_polynomial.hpp:633
Definition algorithm.hpp:24
double FloatType
Note:
Definition compile_config.hpp:37
classical monte carlo system (using beta (inverse temperature) for annealing parameter)
Definition system.hpp:31