openjij
Framework for the Ising model and QUBO.
Loading...
Searching...
No Matches
single_integer_move.hpp
Go to the documentation of this file.
1// Copyright 2023 Jij Inc.
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5
6// http://www.apache.org/licenses/LICENSE-2.0
7
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14#pragma once
15
16#include <random>
17
18namespace openjij {
19namespace updater {
20
22 template <typename SystemType>
23 std::int64_t GenerateNewValue(SystemType &sa_system, const std::int64_t index,
24 const double T, const double _progress) {
25 const auto candidate_value = sa_system.GenerateCandidateValue(index);
26 const double dE = sa_system.GetEnergyDifference(index, candidate_value);
27 if (dE <= 0.0 || dist(sa_system.random_number_engine) < std::exp(-dE / T)) {
28 return candidate_value;
29 } else {
30 return sa_system.GetState()[index].value;
31 }
32 }
33
34 std::uniform_real_distribution<double> dist{0.0, 1.0};
35};
36
38 template <typename SystemType>
39 std::int64_t GenerateNewValue(SystemType &sa_system, const std::int64_t index,
40 const double T, const double progress) {
41 // Metropolis Optimal Transition if possible
42 // This is used for systems with up to 4th power coefficients
43 if (sa_system.CanOptMove(index) && dist(sa_system.random_number_engine) < progress) {
44 const auto [min_val, min_dE] = sa_system.GetMinEnergyDifference(index);
45 if (min_dE <= 0.0 ||
46 dist(sa_system.random_number_engine) < std::exp(-min_dE / T)) {
47 return min_val;
48 } else {
49 return sa_system.GetState()[index].value;
50 }
51 } else {
52 const auto candidate_value = sa_system.GenerateCandidateValue(index);
53 const double dE = sa_system.GetEnergyDifference(index, candidate_value);
54 if (dE <= 0.0 ||
55 dist(sa_system.random_number_engine) < std::exp(-dE / T)) {
56 return candidate_value;
57 } else {
58 return sa_system.GetState()[index].value;
59 }
60 }
61 }
62
63 std::uniform_real_distribution<double> dist{0.0, 1.0};
64};
65
67 template <typename SystemType>
68 std::int64_t GenerateNewValue(SystemType &sa_system, const std::int64_t index,
69 const double T, const double _progress) {
70 if (sa_system.IsLinearCoeff(index)) {
71 return ForBilinear(sa_system, index, T, _progress);
72 } else {
73 return ForAll(sa_system, index, T, _progress);
74 }
75 }
76
77 template <typename SystemType>
78 std::int64_t ForAll(SystemType &sa_system, const std::int64_t index,
79 const double T, const double _progress) {
80 const auto &var = sa_system.GetState()[index];
81 const double beta = 1.0 / T;
82 std::int64_t selected_state_number = -1;
83 double max_z = -std::numeric_limits<double>::infinity();
84
85 for (std::int64_t i = 0; i < var.num_states; ++i) {
86 const double g =
87 -std::log(-std::log(dist(sa_system.random_number_engine)));
88 const double z = -beta * sa_system.GetEnergyDifference(
89 index, var.GetValueFromState(i)) + g;
90 if (z > max_z) {
91 max_z = z;
92 selected_state_number = i;
93 }
94 }
95 if (selected_state_number == -1) {
96 throw std::runtime_error("No state selected.");
97 }
98 return var.GetValueFromState(selected_state_number);
99 }
100
101 template <typename SystemType>
102 std::int64_t ForBilinear(SystemType &sa_system,
103 const std::int64_t index, const double T,
104 const double _progress) {
105 const auto &state = sa_system.GetState()[index];
106 const double linear_coeff = sa_system.GetLinearCoeff(index);
107
108 if (std::abs(linear_coeff) < 1e-10) {
109 return state.GenerateRandomValue(sa_system.random_number_engine);
110 }
111
112 const double b = -linear_coeff * (1.0 / T);
113 const double dxl = static_cast<double>(state.lower_bound - state.value);
114 const double dxu = static_cast<double>(state.upper_bound - state.value);
115
116 const double u = this->dist(sa_system.random_number_engine);
117
118 double selected_dz = 0.0;
119 if (b > 0) {
120 selected_dz = dxu + std::log(u + (1.0 - u) * std::exp(-b * (dxu - dxl + 1))) / b;
121 } else {
122 selected_dz = dxl - 1.0 + std::log(1.0 - u * (1.0 - std::exp(b * (dxu - dxl + 1)))) / b;
123 }
124
125 selected_dz = static_cast<std::int64_t>(std::ceil(std::max(dxl, std::min(selected_dz, dxu))));
126
127 return state.value + selected_dz;
128 }
129
130 std::uniform_real_distribution<double> dist{0.0, 1.0};
131};
132
134 template <typename SystemType>
135 std::int64_t GenerateNewValue(SystemType &sa_system, const std::int64_t index,
136 const double T, const double _progress) {
137 const auto &var = sa_system.GetState()[index];
138 const std::int64_t max_num_state = var.num_states;
139 std::vector<double> weight_list(max_num_state, 0.0);
140 std::vector<double> sum_weight_list(max_num_state, 0.0);
141
142 const auto [max_weight_state_value, min_dE] = sa_system.GetMinEnergyDifference(index);
143 const auto max_weight_state = var.GetStateFromValue(max_weight_state_value);
144
145 for (std::int64_t i = 0; i < max_num_state; ++i) {
146 const std::int64_t state = (i == 0) ? max_weight_state : ((i == max_weight_state) ? 0 : i);
147 const double dE = sa_system.GetEnergyDifference(index, var.GetValueFromState(state)) - min_dE;
148 weight_list[i] = std::exp(-dE / T);
149 sum_weight_list[i] = (i == 0) ? weight_list[i] : sum_weight_list[i - 1] + weight_list[i];
150 }
151
152 std::int64_t current_state = var.GetStateFromValue(var.value);
153 if (current_state == 0) {
154 current_state = max_weight_state;
155 } else if (current_state == max_weight_state) {
156 current_state = 0;
157 }
158
159 const double w_0 = weight_list[0];
160 const double w_c = weight_list[current_state];
161 const double sum_w_c = sum_weight_list[current_state];
162 const double rand = dist(sa_system.random_number_engine) * w_c;
163 std::int64_t selected_state = -1;
164 double prob_sum = 0.0;
165
166 for (std::int64_t j = 0; j < max_num_state; ++j) {
167 const double d_ij = sum_w_c - sum_weight_list[(j - 1 + max_num_state) % max_num_state] + w_0;
168 prob_sum += std::max(0.0, std::min({d_ij, w_c + (weight_list[j] - d_ij), w_c, weight_list[j]}));
169 if (rand <= prob_sum) {
170 if (j == 0) {
171 selected_state = max_weight_state;
172 } else if (j == max_weight_state) {
173 selected_state = 0;
174 } else {
175 selected_state = j;
176 }
177 break;
178 }
179 }
180
181 if (selected_state == -1) {
182 throw std::runtime_error("No state selected.");
183 }
184
185 return var.GetValueFromState(selected_state);
186 }
187
188 std::uniform_real_distribution<double> dist{0.0, 1.0};
189};
190
191} // namespace updater
192} // namespace openjij
Definition algorithm.hpp:24
Definition single_integer_move.hpp:66
std::int64_t ForBilinear(SystemType &sa_system, const std::int64_t index, const double T, const double _progress)
Definition single_integer_move.hpp:102
std::int64_t GenerateNewValue(SystemType &sa_system, const std::int64_t index, const double T, const double _progress)
Definition single_integer_move.hpp:68
std::int64_t ForAll(SystemType &sa_system, const std::int64_t index, const double T, const double _progress)
Definition single_integer_move.hpp:78
std::uniform_real_distribution< double > dist
Definition single_integer_move.hpp:130
Definition single_integer_move.hpp:21
std::int64_t GenerateNewValue(SystemType &sa_system, const std::int64_t index, const double T, const double _progress)
Definition single_integer_move.hpp:23
std::uniform_real_distribution< double > dist
Definition single_integer_move.hpp:34
Definition single_integer_move.hpp:37
std::uniform_real_distribution< double > dist
Definition single_integer_move.hpp:63
std::int64_t GenerateNewValue(SystemType &sa_system, const std::int64_t index, const double T, const double progress)
Definition single_integer_move.hpp:39
Definition single_integer_move.hpp:133
std::int64_t GenerateNewValue(SystemType &sa_system, const std::int64_t index, const double T, const double _progress)
Definition single_integer_move.hpp:135
std::uniform_real_distribution< double > dist
Definition single_integer_move.hpp:188