openjij
Framework for the Ising model and QUBO.
Loading...
Searching...
No Matches
chimera.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 <cstddef>
18#include <cstdint>
19#include <tuple>
20#include <type_traits>
21
23
24namespace openjij {
25namespace graph {
26
41using ChimeraIndex = std::tuple<std::size_t, std::size_t, std::size_t>;
42
46enum class ChimeraDir {
47
51 PLUS_R,
52
56 MINUS_R,
57
61 PLUS_C,
62
66 MINUS_C,
67
71 IN_0or4,
72
76 IN_1or5,
77
81 IN_2or6,
82
86 IN_3or7,
87};
88
94template <typename FloatType = double>
95class Chimera : public Sparse<FloatType> {
96 static_assert(std::is_arithmetic<FloatType>::value,
97 "argument must be an arithmetic type");
98
99private:
104
108 std::size_t _num_row;
109
113 std::size_t _num_column;
114
118 constexpr static std::size_t _num_in_chimera = 8;
119
127 inline std::size_t mod_r(std::int64_t a) const {
128 // a -> [-1:num_row]
129 return (a + _num_row) % _num_row;
130 }
131
139 inline std::size_t mod_c(std::int64_t a) const {
140 // a -> [-1:num_column]
141 return (a + _num_column) % _num_column;
142 }
143
151 inline void _checkpair(Index idx1, Index idx2) const {
152 std::int64_t r1, c1, i1, r2, c2, i2;
153 std::tie(r1, c1, i1) = to_rci(idx1);
154 std::tie(r2, c2, i2) = to_rci(idx2);
155 if (!((r1 == r2 && std::abs(c1 - c2) == 1 && i1 == i2 &&
156 i1 >= 4) || // horizontal connect
157 (c1 == c2 && std::abs(r1 - r2) == 1 && i1 == i2 &&
158 4 < i1) || // vertical connect
159 (r1 == r2 && c1 == c2 && i1 < 4 && 4 <= i2) || // in-site connect
160 (r1 == r2 && c1 == c2 && i2 < 4 && 4 <= i1) || // in-site connect
161 (r1 == r2 && c1 == c2 && i1 == i2)) // local field
162 ) {
163 throw std::runtime_error("invalid index pair " + std::to_string(idx1) +
164 " " + std::to_string(idx2) +
165 " inserted in Chimera");
166 }
167 }
168
169public:
179 Index to_ind(std::int64_t r, std::int64_t c, std::int64_t i) const {
180 // row-major matrix
181
182 if (!(-1 <= r && r <= static_cast<std::int64_t>(_num_row))) {
183 throw std::runtime_error("invalid value r=" + std::to_string(r) +
184 " inserted in Chimera");
185 }
186
187 if (!(-1 <= c && c <= static_cast<std::int64_t>(_num_column))) {
188 throw std::runtime_error("invalid value c=" + std::to_string(c) +
189 " inserted in Chimera");
190 }
191
192 if (!(0 <= i && i < static_cast<std::int64_t>(_num_in_chimera))) {
193 throw std::runtime_error("invalid value i=" + std::to_string(i) +
194 " inserted in Chimera");
195 }
196
197 return _num_column * _num_in_chimera * mod_r(r) +
198 _num_in_chimera * mod_c(c) + i;
199 }
200
209 if (!(ind < this->get_num_spins())) {
210 throw std::runtime_error("invalid value index=" + std::to_string(ind) +
211 " inserted in Chimera");
212 }
213
214 std::int64_t r = ind / (_num_column * _num_in_chimera);
215 ind -= (_num_column * _num_in_chimera) * r;
216 std::int64_t c = ind / _num_in_chimera;
217 ind -= (_num_in_chimera)*c;
218 std::int64_t i = ind;
219 return std::make_tuple(r, c, i);
220 }
221
229 Chimera(std::size_t num_row, std::size_t num_column, FloatType init_val = 0)
230 : Sparse<FloatType>(num_row * num_column * _num_in_chimera, 6 + 1),
231 _init_val(init_val), _num_row(num_row), _num_column(num_column) {
232 // generate sparse graph
233 assert(_num_row >= 1);
234 assert(_num_column >= 1);
235
236 for (std::size_t r = 0; r < _num_row; r++) {
237 for (std::size_t c = 0; c < _num_column; c++) {
238 for (std::size_t i = 0; i < _num_in_chimera; i++) {
239 // open boundary
240 if (r > 0 && i < 4) {
241 // MINUS_R (0<=i<4)
242 this->Sparse<FloatType>::J(to_ind(r, c, i), to_ind(r - 1, c, i)) =
243 _init_val;
244 }
245 if (c > 0 && 4 <= i) {
246 // MINUS_C (4<=i<8)
247 this->Sparse<FloatType>::J(to_ind(r, c, i), to_ind(r, c - 1, i)) =
248 _init_val;
249 }
250 if (r < num_row - 1 && i < 4) {
251 // PLUS_R (0<=i<4)
252 this->Sparse<FloatType>::J(to_ind(r, c, i), to_ind(r + 1, c, i)) =
253 _init_val;
254 }
255 if (c < num_column - 1 && 4 <= i) {
256 // PLUS_C (4<=i<8)
257 this->Sparse<FloatType>::J(to_ind(r, c, i), to_ind(r, c + 1, i)) =
258 _init_val;
259 }
260
261 // inside chimera unit
262
263 this->Sparse<FloatType>::J(to_ind(r, c, i),
264 to_ind(r, c, (i < 4) ? 4 : 0)) = _init_val;
265 this->Sparse<FloatType>::J(to_ind(r, c, i),
266 to_ind(r, c, (i < 4) ? 5 : 1)) = _init_val;
267 this->Sparse<FloatType>::J(to_ind(r, c, i),
268 to_ind(r, c, (i < 4) ? 6 : 2)) = _init_val;
269 this->Sparse<FloatType>::J(to_ind(r, c, i),
270 to_ind(r, c, (i < 4) ? 7 : 3)) = _init_val;
271
272 // local field
273 this->Sparse<FloatType>::J(to_ind(r, c, i), to_ind(r, c, i)) =
274 _init_val;
275 }
276 }
277 }
278 }
279
288 Chimera(const json &j, std::size_t num_row, std::size_t num_column,
289 FloatType init_val = 0)
290 : Chimera<FloatType>(num_row, num_column, init_val) {
291 if (!(j["num_variables"] <= num_row * num_column * _num_in_chimera)) {
292 throw std::runtime_error("number of system size does not match");
293 }
294 // define bqm with ising variables
295 auto bqm = json_parse<FloatType, cimod::Sparse>(j, false);
296 // interactions
297 for (auto &&elem : bqm.get_quadratic()) {
298 const auto &key = elem.first;
299 const auto &val = elem.second;
300 _checkpair(key.first, key.second);
301 this->Sparse<FloatType>::J(key.first, key.second) += val;
302 }
303 // local field
304 for (auto &&elem : bqm.get_linear()) {
305 const auto &key = elem.first;
306 const auto &val = elem.second;
307 this->Sparse<FloatType>::h(key) += val;
308 }
309 }
310
315 Chimera(const Chimera<FloatType> &) = default;
316
322
328 std::size_t get_num_row() const { return _num_row; }
329
335 std::size_t get_num_column() const { return _num_column; }
336
342 std::size_t get_num_in_chimera() const { return _num_in_chimera; }
343
354 FloatType &J(std::size_t r, std::size_t c, std::size_t i, ChimeraDir dir) {
355 assert(r < _num_row);
358
359 switch (dir) {
361 assert(i < 4);
362 return this->Sparse<FloatType>::J(
363 to_ind(r, c, i), to_ind(static_cast<std::int64_t>(r) - 1, c, i));
365 assert(4 <= i);
366 return this->Sparse<FloatType>::J(
367 to_ind(r, c, i), to_ind(r, static_cast<std::int64_t>(c) - 1, i));
369 assert(i < 4);
370 return this->Sparse<FloatType>::J(
371 to_ind(r, c, i), to_ind(static_cast<std::int64_t>(r) + 1, c, i));
373 assert(4 <= i);
374 return this->Sparse<FloatType>::J(
375 to_ind(r, c, i), to_ind(r, static_cast<std::int64_t>(c) + 1, i));
376
378 return this->Sparse<FloatType>::J(to_ind(r, c, i),
379 to_ind(r, c, (i < 4) ? 4 : 0));
381 return this->Sparse<FloatType>::J(to_ind(r, c, i),
382 to_ind(r, c, (i < 4) ? 5 : 1));
384 return this->Sparse<FloatType>::J(to_ind(r, c, i),
385 to_ind(r, c, (i < 4) ? 6 : 2));
387 return this->Sparse<FloatType>::J(to_ind(r, c, i),
388 to_ind(r, c, (i < 4) ? 7 : 3));
389
390 default:
391 assert(false);
392 return _init_val;
393 }
394 }
395
406 const FloatType &J(std::size_t r, std::size_t c, std::size_t i,
407 ChimeraDir dir) const {
408 assert(r < _num_row);
411
412 switch (dir) {
414 assert(i < 4);
415 return this->Sparse<FloatType>::J(
416 to_ind(r, c, i), to_ind(static_cast<std::int64_t>(r) - 1, c, i));
418 assert(4 <= i);
419 return this->Sparse<FloatType>::J(
420 to_ind(r, c, i), to_ind(r, static_cast<std::int64_t>(c) - 1, i));
422 assert(i < 4);
423 return this->Sparse<FloatType>::J(
424 to_ind(r, c, i), to_ind(static_cast<std::int64_t>(r) + 1, c, i));
426 assert(4 <= i);
427 return this->Sparse<FloatType>::J(
428 to_ind(r, c, i), to_ind(r, static_cast<std::int64_t>(c) + 1, i));
429
431 return this->Sparse<FloatType>::J(to_ind(r, c, i),
432 to_ind(r, c, (i < 4) ? 4 : 0));
434 return this->Sparse<FloatType>::J(to_ind(r, c, i),
435 to_ind(r, c, (i < 4) ? 5 : 1));
437 return this->Sparse<FloatType>::J(to_ind(r, c, i),
438 to_ind(r, c, (i < 4) ? 6 : 2));
440 return this->Sparse<FloatType>::J(to_ind(r, c, i),
441 to_ind(r, c, (i < 4) ? 7 : 3));
442
443 default:
444 assert(false);
445 return _init_val;
446 }
447 }
448
458 FloatType &h(std::size_t r, std::size_t c, std::size_t i) {
459 assert(r < _num_row);
462
463 return this->Sparse<FloatType>::h(to_ind(r, c, i));
464 }
465
475 const FloatType &h(std::size_t r, std::size_t c, std::size_t i) const {
476 assert(r < _num_row);
479
480 return this->Sparse<FloatType>::h(to_ind(r, c, i));
481 }
482
493 Spin &spin(Spins &spins, std::size_t r, std::size_t c, std::size_t i) const {
494 return spins[to_ind(r, c, i)];
495 }
496
507 const Spin &spin(const Spins &spins, std::size_t r, std::size_t c,
508 std::size_t i) const {
509 return spins[to_ind(r, c, i)];
510 }
511};
512} // namespace graph
513} // namespace openjij
chimera lattice graph
Definition chimera.hpp:95
std::size_t mod_r(std::int64_t a) const
mod function (a mod num_row)
Definition chimera.hpp:127
static constexpr std::size_t _num_in_chimera
number of spins in each chimera units (8)
Definition chimera.hpp:118
const Spin & spin(const Spins &spins, std::size_t r, std::size_t c, std::size_t i) const
derive spin value at the index (row x column)
Definition chimera.hpp:507
FloatType _init_val
initial value to be set to inreactions
Definition chimera.hpp:103
Chimera(std::size_t num_row, std::size_t num_column, FloatType init_val=0)
chimera lattice graph constructor
Definition chimera.hpp:229
Chimera(const json &j, std::size_t num_row, std::size_t num_column, FloatType init_val=0)
Square constructor (from nlohmann::json)
Definition chimera.hpp:288
std::size_t get_num_column() const
get number of columns
Definition chimera.hpp:335
ChimeraIndex to_rci(Index ind) const
convert from global index to (row x column x in-chimera) index
Definition chimera.hpp:208
std::size_t mod_c(std::int64_t a) const
mod function (a mod num_column)
Definition chimera.hpp:139
void _checkpair(Index idx1, Index idx2) const
check if the pair has a valid connection
Definition chimera.hpp:151
FloatType & h(std::size_t r, std::size_t c, std::size_t i)
access h(row, colum, in-chimera) (local field)
Definition chimera.hpp:458
Chimera(Chimera< FloatType > &&)=default
chimera lattice graph move constructor
std::size_t get_num_in_chimera() const
get number of spins in each chimera unit
Definition chimera.hpp:342
std::size_t _num_row
number of rows
Definition chimera.hpp:108
std::size_t _num_column
number of columns
Definition chimera.hpp:113
FloatType & J(std::size_t r, std::size_t c, std::size_t i, ChimeraDir dir)
access J(row, colum, in-chimera, direction)
Definition chimera.hpp:354
const FloatType & J(std::size_t r, std::size_t c, std::size_t i, ChimeraDir dir) const
access J(row, colum, in-chimera, direction)
Definition chimera.hpp:406
const FloatType & h(std::size_t r, std::size_t c, std::size_t i) const
access h(row, colum, in-chimera) (local field)
Definition chimera.hpp:475
Chimera(const Chimera< FloatType > &)=default
chimera lattice graph copy constructor
std::size_t get_num_row() const
get number of rows
Definition chimera.hpp:328
Index to_ind(std::int64_t r, std::int64_t c, std::int64_t i) const
convert from (row x column x in-chimera) index to global index
Definition chimera.hpp:179
Spin & spin(Spins &spins, std::size_t r, std::size_t c, std::size_t i) const
derive spin value at the index (row x column)
Definition chimera.hpp:493
std::size_t get_num_spins() const noexcept
get number of spins
Definition graph.hpp:89
Sparse graph: two-body intereactions with O(1) connectivity The Hamiltonian is like.
Definition sparse.hpp:40
FloatType & h(Index i)
access h_{i} (local field)
Definition sparse.hpp:300
FloatType & J(Index i, Index j)
access J_{ij}
Definition sparse.hpp:269
auto json_parse(const json &obj, bool relabel=true)
parse json object from bqm.to_serializable
Definition parse.hpp:50
std::tuple< std::size_t, std::size_t, std::size_t > ChimeraIndex
Chimera index (row, column, in-chimera) The structure of in-chimera is as follows in-chimera index.
Definition chimera.hpp:41
ChimeraDir
direction in chimera graph
Definition chimera.hpp:46
@ MINUS_C
minus-column direction: (r, c, ind) -> (r, c-1, ind)
@ IN_0or4
inside-chimera 0or4 direction: (r, c, ind) -> (r, c, 0or4)
@ IN_2or6
inside-chimera 2or6 direction: (r, c, ind) -> (r, c, 2or6)
@ MINUS_R
minus-row direction: (r, c, ind) -> (r-1, c, ind)
@ IN_1or5
inside-chimera 1or5 direction: (r, c, ind) -> (r, c, 1or5)
@ IN_3or7
inside-chimera 3or7 direction: (r, c, ind) -> (r, c, 3or7)
@ PLUS_C
plus-column direction: (r, c, ind) -> (r, c+1, ind)
@ PLUS_R
plus-row direction: (r, c, ind) -> (r+1, c, ind)
std::vector< Spin > Spins
Definition graph.hpp:27
int Spin
Definition graph.hpp:26
nlohmann::json json
Definition parse.hpp:33
std::size_t Index
Definition graph.hpp:30
Definition algorithm.hpp:24
double FloatType
Note:
Definition compile_config.hpp:37