openjij
Framework for the Ising model and QUBO.
Loading...
Searching...
No Matches
classical_ising_polynomial.hpp
Go to the documentation of this file.
1// Copyright 2023 Jij Inc.
2
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6
7// http://www.apache.org/licenses/LICENSE-2.0
8
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma once
16
17#include <algorithm>
18#include <iomanip>
19#include <iostream>
20#include <limits>
21#include <vector>
22
23#include <nlohmann/json.hpp>
24
25#include "openjij/graph/all.hpp"
28
29namespace openjij {
30namespace system {
31
36template <typename GraphType> class ClassicalIsingPolynomial;
37
39template <typename FloatType>
40class ClassicalIsingPolynomial<graph::Polynomial<FloatType>> {
41
42public:
45
47 const int64_t num_variables;
48
51
53 const cimod::Vartype vartype;
54
63 const graph::Polynomial<FloatType> &poly_graph,
64 const cimod::Vartype init_vartype)
65 : num_variables(poly_graph.size()), variables(init_variables),
66 vartype(init_vartype) {
67 cimod::CheckVariables(variables, vartype);
68 SetInteractions(poly_graph);
69 SetAdj();
70 ResetZeroCount();
71 ResetSignKey();
72 reset_dE();
73 const FloatType thres_hold =
74 std::abs(FindMaxInteraction().second * utility::THRESHOLD<FloatType>);
75 min_effective_dE_ = std::abs(FindMinInteraction(thres_hold).second);
76 }
77
86 const graph::Polynomial<FloatType> &poly_graph,
87 const std::string init_vartype)
88 : num_variables(poly_graph.size()), variables(init_variables),
89 vartype(ConvertVartype(init_vartype)) {
90 cimod::CheckVariables(variables, vartype);
91 SetInteractions(poly_graph);
92 SetAdj();
93 ResetZeroCount();
94 ResetSignKey();
95 reset_dE();
96 const FloatType thres_hold =
97 std::abs(FindMaxInteraction().second * utility::THRESHOLD<FloatType>);
98 min_effective_dE_ = std::abs(FindMinInteraction(thres_hold).second);
99 }
100
106 const nlohmann::json &j)
107 : num_variables(init_variables.size()), variables(init_variables),
108 vartype(j.at("vartype") == "SPIN" ? cimod::Vartype::SPIN
109 : cimod::Vartype::BINARY) {
110 cimod::CheckVariables(variables, vartype);
111 const auto &v_k_v = graph::json_parse_polynomial<FloatType>(j);
112 const auto &poly_key_list = std::get<0>(v_k_v);
113 const auto &poly_value_list = std::get<1>(v_k_v);
114
115 if (poly_key_list.size() != poly_value_list.size()) {
116 throw std::runtime_error(
117 "The sizes of key_list and value_list must match each other");
118 }
119 if (poly_key_list.size() == 0) {
120 throw std::runtime_error("The interaction is empty.");
121 }
122 if (num_variables == 0) {
123 throw std::runtime_error("The number of variables is zero.");
124 }
125
126 num_interactions_ = static_cast<int64_t>(poly_key_list.size());
127
128 poly_key_list_.resize(num_interactions_);
129 poly_value_list_.resize(num_interactions_);
130
131#pragma omp parallel for
132 for (int64_t i = 0; i < num_interactions_; ++i) {
133 poly_key_list_[i] = poly_key_list[i];
134 poly_value_list_[i] = poly_value_list[i];
135 }
136
137 active_variables_.resize(num_variables);
138 std::iota(active_variables_.begin(), active_variables_.end(), 0);
139
140 SetAdj();
141 ResetZeroCount();
142 ResetSignKey();
143 reset_dE();
144 const FloatType thres_hold =
145 std::abs(FindMaxInteraction().second * utility::THRESHOLD<FloatType>);
146 min_effective_dE_ = std::abs(FindMinInteraction(thres_hold).second);
147 }
148
153 void reset_variables(const graph::Spins &init_variables) {
154 if (init_variables.size() != variables.size()) {
155 throw std::runtime_error(
156 "The size of initial spins/binaries does not equal to system size");
157 }
158 cimod::CheckVariables(init_variables, vartype);
159 if (vartype == cimod::Vartype::SPIN) {
160 for (const auto &index_variable : active_variables_) {
161 if (variables[index_variable] != init_variables[index_variable]) {
162 update_spin_system(index_variable);
163 }
164 if (variables[index_variable] != init_variables[index_variable]) {
165 std::stringstream ss;
166 ss << "Unknown error detected in " << __func__;
167 throw std::runtime_error(ss.str());
168 }
169 }
170 } else if (vartype == cimod::Vartype::BINARY) {
171 for (const auto &index_variable : active_variables_) {
172 if (variables[index_variable] != init_variables[index_variable]) {
173 update_binary_system(index_variable);
174 }
175 if (variables[index_variable] != init_variables[index_variable]) {
176 std::stringstream ss;
177 ss << "Unknown error detected in " << __func__;
178 throw std::runtime_error(ss.str());
179 }
180 }
181 } else {
182 throw std::runtime_error("Unknown vartype detected");
183 }
184 }
185
188 void reset_dE() {
189 dE_.clear();
190 dE_.resize(num_variables);
191
192 if (vartype == cimod::Vartype::SPIN) {
193 // Initialize
194 max_effective_dE_ = 2.0 * std::abs(poly_value_list_.front());
195 for (const auto &index_binary : active_variables_) {
196 FloatType val = 0.0;
197 FloatType abs_val = 0.0;
198 bool flag = false;
199 for (const auto &index_key : adj_[index_binary]) {
200 val += poly_value_list_[index_key] * sign_key_[index_key];
201 abs_val += std::abs(poly_value_list_[index_key]);
202 flag = true;
203 }
204 dE_[index_binary] = -2 * val;
205 if (flag && max_effective_dE_ < 2 * abs_val) {
206 max_effective_dE_ = 2 * abs_val;
207 }
208 }
209 } else if (vartype == cimod::Vartype::BINARY) {
210 // Initialize
211 max_effective_dE_ = std::abs(poly_value_list_.front());
212 for (const auto &index_binary : active_variables_) {
213 FloatType val = 0.0;
214 FloatType abs_val = 0.0;
215 bool flag = false;
216 const graph::Binary binary = variables[index_binary];
217 for (const auto &index_key : adj_[index_binary]) {
218 if (zero_count_[index_key] + binary == 1) {
219 val += poly_value_list_[index_key];
220 }
221 flag = true;
222 abs_val += std::abs(poly_value_list_[index_key]);
223 }
224 dE_[index_binary] = (-2 * binary + 1) * val;
225
226 if (flag && max_effective_dE_ < abs_val) {
227 max_effective_dE_ = abs_val;
228 }
229 }
230 } else {
231 throw std::runtime_error("Unknown vartype detected");
232 }
233 }
234
238 void update_spin_system(const graph::Index index_update_spin) {
239 for (const auto &index_key : adj_[index_update_spin]) {
240 const FloatType val = 4.0 * poly_value_list_[index_key];
241 const int8_t sign = sign_key_[index_key];
242 for (const auto &index_spin : poly_key_list_[index_key]) {
243 if (index_spin != index_update_spin) {
244 dE_[index_spin] += val * sign;
245 }
246 }
247 sign_key_[index_key] *= -1;
248 }
249 dE_[index_update_spin] *= -1;
250 variables[index_update_spin] *= -1;
251 }
252
256 void update_binary_system(const graph::Index index_update_binary) {
257 const graph::Binary update_binary = variables[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]) {
263 const graph::Binary binary = variables[index_binary];
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 }
268 }
269 zero_count_[index_key] += count;
270 }
271 dE_[index_update_binary] *= -1;
272 variables[index_update_binary] = 1 - variables[index_update_binary];
273 }
274
278 inline FloatType dE(const graph::Index index_variable) const {
279 return dE_[index_variable];
280 }
281
285 inline const std::vector<graph::Index> &get_active_variables() const {
286 return active_variables_;
287 }
288
292 const cimod::PolynomialValueList<FloatType> &get_values() const {
293 return poly_value_list_;
294 }
295
299 const cimod::PolynomialKeyList<graph::Index> &get_keys() const {
300 return poly_key_list_;
301 }
302
306 const std::vector<std::vector<graph::Index>> &get_adj() const { return adj_; }
307
310 FloatType get_max_effective_dE() const { return max_effective_dE_; }
311
314 FloatType get_min_effective_dE() const { return min_effective_dE_; }
315
318 std::string get_vartype_string() const {
319 if (vartype == cimod::Vartype::SPIN) {
320 return "SPIN";
321 } else if (vartype == cimod::Vartype::BINARY) {
322 return "BINARY";
323 } else {
324 throw std::runtime_error("Unknown vartype detected");
325 }
326 }
327
328private:
331
333 std::vector<FloatType> dE_;
334
337 std::vector<int64_t> zero_count_;
338
341 std::vector<int8_t> sign_key_;
342
345 std::vector<std::vector<graph::Index>> adj_;
346
349 cimod::PolynomialKeyList<graph::Index> poly_key_list_;
350
353 cimod::PolynomialValueList<FloatType> poly_value_list_;
354
356 std::vector<graph::Index> active_variables_;
357
360
363
365 void SetAdj() {
366 adj_.clear();
367 adj_.resize(num_variables);
368 for (int64_t i = 0; i < num_interactions_; ++i) {
369 for (const auto &index : poly_key_list_[i]) {
370 adj_[index].push_back(i);
371 }
372 }
373 }
374
378 const auto &poly_key_list = poly_graph.get_keys();
379 const auto &poly_value_list = poly_graph.get_values();
380
381 if (poly_key_list.size() != poly_value_list.size()) {
382 throw std::runtime_error(
383 "The sizes of key_list and value_list must match each other");
384 }
385
386 if (poly_key_list.size() == 0) {
387 throw std::runtime_error("The interaction is empty.");
388 }
389
390 std::unordered_set<graph::Index> active_variable_set;
391
392 poly_key_list_.clear();
393 poly_value_list_.clear();
394
395 for (std::size_t i = 0; i < poly_key_list.size(); ++i) {
396 if (poly_value_list[i] != 0.0) {
397 poly_key_list_.push_back(poly_key_list[i]);
398 poly_value_list_.push_back(poly_value_list[i]);
399 for (const auto &it : poly_key_list[i]) {
400 active_variable_set.emplace(it);
401 }
402 }
403 }
404 num_interactions_ = static_cast<int64_t>(poly_key_list_.size());
405 active_variables_ = std::vector<graph::Index>(active_variable_set.begin(),
406 active_variable_set.end());
407 std::sort(active_variables_.begin(), active_variables_.end());
408 }
409
412 if (vartype != cimod::Vartype::BINARY) {
413 return;
414 }
415 zero_count_.resize(num_interactions_);
416#pragma omp parallel for
417 for (int64_t i = 0; i < num_interactions_; ++i) {
418 int64_t zero_count = 0;
419 for (const auto &index : poly_key_list_[i]) {
420 if (variables[index] == 0) {
421 zero_count++;
422 }
423 }
424 zero_count_[i] = zero_count;
425 }
426 }
427
430 if (vartype != cimod::Vartype::SPIN) {
431 return;
432 }
433 sign_key_.resize(num_interactions_);
434#pragma omp parallel for
435 for (int64_t i = 0; i < num_interactions_; ++i) {
436 int8_t sign_key = 1;
437 for (const auto &index : poly_key_list_[i]) {
438 sign_key *= variables[index];
439 }
440 sign_key_[i] = sign_key;
441 }
442 }
443
446 cimod::Vartype ConvertVartype(const std::string vartype) const {
447 if (vartype == "SPIN") {
448 return cimod::Vartype::SPIN;
449 } else if (vartype == "BINARY") {
450 return cimod::Vartype::BINARY;
451 } else {
452 throw std::runtime_error("Unknown vartype detected");
453 }
454 }
455
459 std::pair<std::vector<graph::Index>, FloatType> FindMaxInteraction() const {
460 if (poly_key_list_.size() == 0) {
461 throw std::runtime_error("Interactions are empty.");
462 }
463 FloatType max_val = 0.0;
464 std::vector<graph::Index> max_key = {};
465 for (std::size_t i = 0; i < poly_key_list_.size(); ++i) {
466 if (std::abs(max_val) < std::abs(poly_value_list_[i])) {
467 max_val = poly_value_list_[i];
468 max_key = poly_key_list_[i];
469 }
470 }
471 return std::pair<std::vector<graph::Index>, FloatType>(max_key, max_val);
472 }
473
477 std::pair<std::vector<graph::Index>, FloatType>
478 FindMinInteraction(const FloatType threshold = 0.0) const {
479 if (poly_key_list_.size() == 0) {
480 throw std::runtime_error("Interactions are empty.");
481 }
482 FloatType min_val = 0.0;
483 std::vector<graph::Index> min_key;
484
485 // Set initial value larger than threshold.
486 bool flag_success_initialize = false;
487 for (std::size_t i = 0; i < poly_key_list_.size(); ++i) {
488 if (std::abs(threshold) < std::abs(poly_value_list_[i])) {
489 min_val = poly_value_list_[i];
490 min_key = poly_key_list_[i];
491 flag_success_initialize = true;
492 break;
493 }
494 }
495 if (!flag_success_initialize) {
496 std::stringstream ss;
497 ss << "No interactions larger than threshold=" << std::abs(threshold)
498 << std::endl;
499 throw std::runtime_error(ss.str());
500 }
501
502 for (std::size_t i = 0; i < poly_key_list_.size(); ++i) {
503 if (std::abs(threshold) < std::abs(poly_value_list_[i]) &&
504 std::abs(poly_value_list_[i]) < std::abs(min_val)) {
505 min_val = poly_value_list_[i];
506 min_key = poly_key_list_[i];
507 }
508 }
509
510 if (std::abs(min_val) <= std::abs(threshold)) {
511 std::stringstream ss;
512 ss << "Unknown error in " << __func__ << std::endl;
513 throw std::runtime_error(ss.str());
514 }
515 return std::pair<std::vector<graph::Index>, FloatType>(min_key, min_val);
516 }
517};
518
527template <typename GraphType>
529 const GraphType &poly_graph,
530 const cimod::Vartype init_vartype) {
531 return ClassicalIsingPolynomial<GraphType>(init_variables, poly_graph,
532 init_vartype);
533}
534
542template <typename GraphType>
544 const GraphType &poly_graph,
545 const std::string init_vartype) {
547 init_variables, poly_graph, init_vartype);
548}
549
556 const nlohmann::json &init_obj) {
558 init_obj);
559}
560
561} // namespace system
562} // namespace openjij
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
FloatType get_min_effective_dE() const
Get "min_effective_dE", which is a rough lower bound of energy gap.
Definition classical_ising_polynomial.hpp:314
void SetAdj()
Set adjacency list.
Definition classical_ising_polynomial.hpp:365
graph::Spins variables
Spin/binary configurations.
Definition classical_ising_polynomial.hpp:50
std::pair< std::vector< graph::Index >, FloatType > FindMaxInteraction() const
Return the key and value of the absolute maximum interaction.
Definition classical_ising_polynomial.hpp:459
ClassicalIsingPolynomial(const graph::Spins &init_variables, const graph::Polynomial< FloatType > &poly_graph, const cimod::Vartype init_vartype)
Constructor of ClassicalIsingPolynomial.
Definition classical_ising_polynomial.hpp:62
const cimod::PolynomialValueList< FloatType > & get_values() const
Get the PolynomialValueList object, which is the list of the values of the polynomial interactions as...
Definition classical_ising_polynomial.hpp:292
void update_spin_system(const graph::Index index_update_spin)
Flip specified spin by single spin flip.
Definition classical_ising_polynomial.hpp:238
void reset_dE()
Reset energy differences (dE), which is used to determine whether to flip the spin/binary or not.
Definition classical_ising_polynomial.hpp:188
cimod::PolynomialKeyList< graph::Index > poly_key_list_
The list of the indices of the polynomial interactions as std::vector<std::vector<graph::Index>>.
Definition classical_ising_polynomial.hpp:349
cimod::PolynomialValueList< FloatType > poly_value_list_
The list of the values of the polynomial interactions as std::vector<FloatType>.
Definition classical_ising_polynomial.hpp:353
FloatType get_max_effective_dE() const
Get "max_effective_dE", which is a upper bound of energy gap.
Definition classical_ising_polynomial.hpp:310
void ResetSignKey()
Set sign_key_.
Definition classical_ising_polynomial.hpp:429
void ResetZeroCount()
Set zero_count_.
Definition classical_ising_polynomial.hpp:411
ClassicalIsingPolynomial(const graph::Spins &init_variables, const nlohmann::json &j)
Constructor of ClassicalIsingPolynomial.
Definition classical_ising_polynomial.hpp:105
const std::vector< graph::Index > & get_active_variables() const
Get "active_binaries_", which is the list of the binaries connected by at least one interaction.
Definition classical_ising_polynomial.hpp:285
cimod::Vartype ConvertVartype(const std::string vartype) const
Convert vartype from std::string to cimod::Vartype.
Definition classical_ising_polynomial.hpp:446
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 classical_ising_polynomial.hpp:478
void SetInteractions(const graph::Polynomial< FloatType > &poly_graph)
Set interactions from Polynomial graph.
Definition classical_ising_polynomial.hpp:377
std::vector< graph::Index > active_variables_
The list of the binaries connected by at least one interaction.
Definition classical_ising_polynomial.hpp:356
FloatType dE(const graph::Index index_variable) const
Return the energy difference of single spin flip update.
Definition classical_ising_polynomial.hpp:278
void reset_variables(const graph::Spins &init_variables)
Reset ClassicalIsingPolynomial system with new spin/binary configurations.
Definition classical_ising_polynomial.hpp:153
std::vector< std::vector< graph::Index > > adj_
Adjacency list, which is the list of the indices of polynomial interactions including specific spin/b...
Definition classical_ising_polynomial.hpp:345
const cimod::Vartype vartype
The model's type. SPIN or BINARY.
Definition classical_ising_polynomial.hpp:53
FloatType min_effective_dE_
Rough lower bound of energy gap.
Definition classical_ising_polynomial.hpp:362
ClassicalIsingPolynomial(const graph::Spins &init_variables, const graph::Polynomial< FloatType > &poly_graph, const std::string init_vartype)
Constructor of ClassicalIsingPolynomial.
Definition classical_ising_polynomial.hpp:85
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 classical_ising_polynomial.hpp:306
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 classical_ising_polynomial.hpp:299
std::string get_vartype_string() const
Get the vartype as std::string.
Definition classical_ising_polynomial.hpp:318
int64_t num_interactions_
The number of the interactions.
Definition classical_ising_polynomial.hpp:330
std::vector< FloatType > dE_
The energy differences when flipping a spin/binary.
Definition classical_ising_polynomial.hpp:333
void update_binary_system(const graph::Index index_update_binary)
Flip specified binary by single spin flip.
Definition classical_ising_polynomial.hpp:256
const int64_t num_variables
The number of spins/binaries.
Definition classical_ising_polynomial.hpp:47
std::vector< int8_t > sign_key_
The sign of product of spin variables in each interaction.
Definition classical_ising_polynomial.hpp:341
FloatType max_effective_dE_
Upper bound of energy gap.
Definition classical_ising_polynomial.hpp:359
std::vector< int64_t > zero_count_
The number of variables taking the zero in each interaction.
Definition classical_ising_polynomial.hpp:337
ClassicalIsingPolynomial class, which is a system to solve higher order unconstrained binary optimiza...
Definition classical_ising_polynomial.hpp:36
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::vector< Spin > Spins
Definition graph.hpp:27
std::size_t Index
Definition graph.hpp:30
auto make_classical_ising_polynomial(const graph::Spins &init_variables, const GraphType &poly_graph, const cimod::Vartype init_vartype)
Helper function for ClassicalIsingPolynomial constructor.
Definition classical_ising_polynomial.hpp:528
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