openjij
Framework for the Ising model and QUBO.
Loading...
Searching...
No Matches
single_spin_flip.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#include <type_traits>
18
23
24#ifdef USE_OMP
25#include <omp.h>
26#endif
27
28namespace openjij {
29namespace updater {
30
36template <typename System> struct SingleSpinFlip;
37
43template <typename GraphType>
44struct SingleSpinFlip<system::ClassicalIsing<GraphType>> {
45
50
54 using FloatType = typename GraphType::value_type;
55
66 template <typename RandomNumberEngine>
67 inline static void
68 update(ClIsing &system, RandomNumberEngine &random_number_engine,
69 const utility::ClassicalUpdaterParameter &parameter) {
70 // set probability distribution object
71 // to do Metroopolis
72 auto urd = std::uniform_real_distribution<>(0, 1.0);
73
74 Eigen::setNbThreads(1);
75 Eigen::initParallel();
76
77 // do a iteraction except for the auxiliary spin
78 for (std::size_t index = 0; index < system.num_spins; ++index) {
79
80 if (system.dE(index) <= 0 ||
81 std::exp(-parameter.beta * system.dE(index)) >
82 urd(random_number_engine)) {
83 // update dE
84 system.dE += 4 * system.spin(index) *
85 (system.interaction.row(index).transpose().cwiseProduct(
86 system.spin));
87
88 system.dE(index) *= -1;
89 system.spin(index) *= -1;
90 }
91
92 // assure that the dummy spin is not changed.
93 system.spin(system.num_spins) = 1;
94 }
95 }
96};
97
104template <typename GraphType>
105struct SingleSpinFlip<system::TransverseIsing<GraphType>> {
106
111
115 using FloatType = typename GraphType::value_type;
116
127 template <typename RandomNumberEngine>
128 inline static void
129 update(QIsing &system, RandomNumberEngine &random_number_engine,
131
132 // get number of classical spins
133 std::size_t num_classical_spins = system.num_classical_spins;
134 // get number of trotter slices
135 std::size_t num_trotter_slices = system.trotter_spins.cols();
136
137 // do metropolis
138 auto urd = std::uniform_real_distribution<>(0, 1.0);
139
140 // aliases
141 // const auto& spins = system.trotter_spins;
142 const auto &gamma = system.gamma;
143 const auto &beta = parameter.beta;
144 const auto &s = parameter.s;
145
146 // transverse factor
147 FloatType B =
148 (1 / 2.) * log(tanh(beta * gamma * (1.0 - s) / num_trotter_slices));
149
150 Eigen::setNbThreads(1);
151 Eigen::initParallel();
152
153 // generate random number (col major)
154 for (std::size_t t = 0; t < num_trotter_slices; t++) {
155 for (std::size_t i = 0; i < num_classical_spins; i++) {
156 system.rand_pool(i, t) = urd(random_number_engine);
157 }
158 }
159
160 // using OpenMP
161
162 // we have to consider the case num_trotter_slices is odd.
163 std::size_t upper_limit = num_trotter_slices % 2 != 0
164 ? num_trotter_slices - 1
165 : num_trotter_slices;
166
167 // NOTE: only signed integer is allowed for OpenMP
168#pragma omp parallel for
169 for (int64_t t = 0; t < (int64_t)upper_limit; t += 2) {
170 for (int64_t i = 0; i < (int64_t)num_classical_spins; i++) {
171 // calculate matrix dot product
172 do_calc(system, parameter, i, t, B);
173 }
174 }
175
176 // using OpenMP
177#pragma omp parallel for
178 for (int64_t t = 1; t < (int64_t)num_trotter_slices; t += 2) {
179 for (int64_t i = 0; i < (int64_t)num_classical_spins; i++) {
180 // calculate matrix dot product
181 do_calc(system, parameter, i, t, B);
182 }
183 }
184
185 // for the case num_trotter_slices is odd.
186 if (num_trotter_slices % 2 != 0) {
187 int64_t t = (int64_t)(num_trotter_slices - 1);
188 for (int64_t i = 0; i < (int64_t)num_classical_spins; i++) {
189 // calculate matrix dot product
190 do_calc(system, parameter, i, t, B);
191 }
192 }
193 }
194
195private:
196 inline static void
198 const utility::TransverseFieldUpdaterParameter &parameter, size_t i,
199 size_t t, FloatType B) {
200
201 // get number of trotter slices
202 std::size_t num_trotter_slices = system.trotter_spins.cols();
203
204 // aliases
205 auto &spins = system.trotter_spins;
206 // const auto& gamma = system.gamma;
207 const auto &beta = parameter.beta;
208 const auto &s = parameter.s;
209
210 // calculate dE for trotter direction
211 FloatType dEtrot = -2 * spins(i, t) *
212 (spins(i, mod_t((int64_t)t + 1, num_trotter_slices)) +
213 spins(i, mod_t((int64_t)t - 1, num_trotter_slices)));
214
215 // calculate total dE
216 FloatType dE =
217 s * (beta / num_trotter_slices) * system.dE(i, t) + B * dEtrot;
218
219 // for debugging
220
221 // FloatType testdE = 0;
222
224 // testdE += -2 * s * (beta/num_trotter_slices) * spins(i,
225 // t)*(system.interaction.row(i).dot(spins.col(t)));
226
228 // testdE += -2 * (1/2.) * log(tanh(beta* gamma * (1.0-s)
229 // /num_trotter_slices)) * spins(i, t) *
230 // ( spins(i, mod_t((int64_t)t+1, num_trotter_slices))
231 // + spins(i, mod_t((int64_t)t-1, num_trotter_slices)));
232
233 // std::cout << "s=" << s << std::endl;
234 // std::cout << "dE=" << dE << std::endl;
235 // std::cout << "testdE=" << testdE << std::endl;
236 // assert((std::isinf(dE) && std::isinf(testdE)) || abs(dE-testdE) < 1e-5);
237
238 // metropolis
239
240 if (dE < 0 || exp(-dE) > system.rand_pool(i, t)) {
241
242 // update dE (spatial direction)
243 system.dE.col(t) +=
244 4 * spins(i, t) *
245 (system.interaction.row(i).transpose().cwiseProduct(spins.col(t)));
246 system.dE(i, t) *= -1;
247
248 // update spins
249 spins(i, t) *= -1;
250 }
251 }
252
253 inline static std::size_t mod_t(std::int64_t a,
254 std::size_t num_trotter_slices) {
255 // a -> [-1:num_trotter_slices]
256 // return a%num_trotter_slices (a>0), num_trotter_slices-1 (a==-1)
257 return (a + num_trotter_slices) % num_trotter_slices;
258 }
259};
260
264template <typename GraphType>
265struct SingleSpinFlip<system::ClassicalIsingPolynomial<GraphType>> {
266
269
271 using FloatType = typename GraphType::value_type;
272
279 template <typename RandomNumberEngine>
280 inline static void
281 update(ClPIsing &system, RandomNumberEngine &random_number_engine,
282 const utility::ClassicalUpdaterParameter &parameter) {
283
284 if (system.vartype == cimod::Vartype::SPIN) {
285 update_spin<RandomNumberEngine>(system, random_number_engine, parameter);
286 } else if (system.vartype == cimod::Vartype::BINARY) {
287 update_binary<RandomNumberEngine>(system, random_number_engine,
288 parameter);
289 } else {
290 std::stringstream ss;
291 ss << "Unknown vartype detected in " << __func__ << std::endl;
292 throw std::runtime_error(ss.str());
293 }
294 }
295
302 template <typename RandomNumberEngine>
303 inline static void
304 update_spin(ClPIsing &system, RandomNumberEngine &random_number_engine,
305 const utility::ClassicalUpdaterParameter &parameter) {
306
307 auto urd = std::uniform_real_distribution<>(0, 1.0);
308 for (const auto &index_spin : system.get_active_variables()) {
309 if (system.dE(index_spin) <= 0.0 ||
310 std::exp(-parameter.beta * system.dE(index_spin)) >
311 urd(random_number_engine)) {
312 system.update_spin_system(index_spin);
313 }
314 }
315 }
316
323 template <typename RandomNumberEngine>
324 inline static void
325 update_binary(ClPIsing &system, RandomNumberEngine &random_number_engine,
326 const utility::ClassicalUpdaterParameter &parameter) {
327
328 auto urd = std::uniform_real_distribution<>(0, 1.0);
329 for (const auto &index_binary : system.get_active_variables()) {
330 if (system.dE(index_binary) <= 0.0 ||
331 std::exp(-parameter.beta * system.dE(index_binary)) >
332 urd(random_number_engine)) {
333 system.update_binary_system(index_binary);
334 }
335 }
336 }
337};
338
339
340template<class SystemType, typename RandType>
341void SingleFlipUpdater(SystemType *system,
342 const std::int32_t num_sweeps,
343 const std::vector<typename SystemType::ValueType> &beta_list,
344 const typename RandType::result_type seed,
345 const algorithm::UpdateMethod update_metod) {
346
347 const std::int32_t system_size = system->GetSystemSize();
348
349 // Set random number engine
350 RandType random_number_engine(seed);
351 std::uniform_real_distribution<typename SystemType::ValueType> dist_real(0, 1);
352
353 if (update_metod == algorithm::UpdateMethod::METROPOLIS) {
354 // Do sequential update
355 for (std::int32_t sweep_count = 0; sweep_count < num_sweeps; sweep_count++) {
356 const auto beta = beta_list[sweep_count];
357 for (std::int32_t i = 0; i < system_size; i++) {
358 const auto delta_energy = system->GetEnergyDifference(i);
359 if (delta_energy <= 0 || std::exp(-beta*delta_energy) > dist_real(random_number_engine)) {
360 system->Flip(i);
361 }
362 }
363 }
364 }
365 else if (update_metod == algorithm::UpdateMethod::HEAT_BATH) {
366 // Do sequential update
367 for (std::int32_t sweep_count = 0; sweep_count < num_sweeps; sweep_count++) {
368 const auto beta = beta_list[sweep_count];
369 for (std::int32_t i = 0; i < system_size; i++) {
370 const auto delta_energy = system->GetEnergyDifference(i);
371 if (1/(1 + std::exp(beta*delta_energy)) > dist_real(random_number_engine)) {
372 system->Flip(i);
373 }
374 }
375 }
376 }
377 else {
378 throw std::runtime_error("Unknown UpdateMethod");
379 }
380}
381
382} // namespace updater
383} // namespace openjij
ClassicalIsingPolynomial class, which is a system to solve higher order unconstrained binary optimiza...
Definition classical_ising_polynomial.hpp:36
UpdateMethod
Definition algorithm.hpp:63
@ METROPOLIS
Metropolis update.
void SingleFlipUpdater(SystemType *system, const std::int32_t num_sweeps, const std::vector< typename SystemType::ValueType > &beta_list, const typename RandType::result_type seed, const algorithm::UpdateMethod update_metod)
Definition single_spin_flip.hpp:341
Definition algorithm.hpp:24
ClassicalIsing structure (system for classical Ising model)
Definition classical_ising.hpp:38
TransverseIsing structure with discrete-time trotter spins.
Definition transverse_ising.hpp:39
typename GraphType::value_type FloatType
floating point type
Definition single_spin_flip.hpp:271
static void update_binary(ClPIsing &system, RandomNumberEngine &random_number_engine, const utility::ClassicalUpdaterParameter &parameter)
Operate single spin flip when the system is composed of binary variables.
Definition single_spin_flip.hpp:325
static void update(ClPIsing &system, RandomNumberEngine &random_number_engine, const utility::ClassicalUpdaterParameter &parameter)
Operate single spin flip for Ising models with polynomial interactions and polynomial unconstrained b...
Definition single_spin_flip.hpp:281
static void update_spin(ClPIsing &system, RandomNumberEngine &random_number_engine, const utility::ClassicalUpdaterParameter &parameter)
Operate single spin flip when the system is composed of spin variables.
Definition single_spin_flip.hpp:304
typename GraphType::value_type FloatType
float type
Definition single_spin_flip.hpp:54
static void update(ClIsing &system, RandomNumberEngine &random_number_engine, const utility::ClassicalUpdaterParameter &parameter)
operate single spin flip in a classical ising system
Definition single_spin_flip.hpp:68
static void do_calc(QIsing &system, const utility::TransverseFieldUpdaterParameter &parameter, size_t i, size_t t, FloatType B)
Definition single_spin_flip.hpp:197
static void update(QIsing &system, RandomNumberEngine &random_number_engine, const utility::TransverseFieldUpdaterParameter &parameter)
operate single spin flip in a transverse ising system
Definition single_spin_flip.hpp:129
static std::size_t mod_t(std::int64_t a, std::size_t num_trotter_slices)
Definition single_spin_flip.hpp:253
typename GraphType::value_type FloatType
float type
Definition single_spin_flip.hpp:115
naive single spin flip updater
Definition single_spin_flip.hpp:36
updater parameter for classical ising system
Definition schedule_list.hpp:37
double beta
inverse temperature
Definition schedule_list.hpp:46
updater paramter for transverse ising model
Definition schedule_list.hpp:74
double beta
inverse temperature
Definition schedule_list.hpp:85
double s
annealing schedule (from 0 (only transverse field) to 1 (only classical Hamiltonian))
Definition schedule_list.hpp:91