openjij
Framework for the Ising model and QUBO.
Loading...
Searching...
No Matches
chimera_gpu_transverse.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#ifndef OPENJIJ_SYSTEM_CHIMERA_GPU_TRANSVERSE_HPP__
16#define OPENJIJ_SYSTEM_CHIMERA_GPU_TRANSVERSE_HPP__
17
18#ifdef USE_CUDA
19
20#include <cstddef>
21#include <vector>
22
23#include "openjij/graph/all.hpp"
28
29namespace openjij {
30namespace system {
31
37template <typename FloatType> struct ChimeraInteractions {
38 using value_type = FloatType;
39 utility::cuda::unique_dev_ptr<FloatType[]> J_out_p; // previous
40 utility::cuda::unique_dev_ptr<FloatType[]> J_out_n; // next
41 utility::cuda::unique_dev_ptr<FloatType[]> J_in_04;
42 utility::cuda::unique_dev_ptr<FloatType[]> J_in_15;
43 utility::cuda::unique_dev_ptr<FloatType[]> J_in_26;
44 utility::cuda::unique_dev_ptr<FloatType[]> J_in_37;
45 utility::cuda::unique_dev_ptr<FloatType[]> h;
46
47 ChimeraInteractions(std::size_t n)
48 : J_out_p(utility::cuda::make_dev_unique<FloatType[]>(n)),
49 J_out_n(utility::cuda::make_dev_unique<FloatType[]>(n)),
50 J_in_04(utility::cuda::make_dev_unique<FloatType[]>(n)),
51 J_in_15(utility::cuda::make_dev_unique<FloatType[]>(n)),
52 J_in_26(utility::cuda::make_dev_unique<FloatType[]>(n)),
53 J_in_37(utility::cuda::make_dev_unique<FloatType[]>(n)),
54 h(utility::cuda::make_dev_unique<FloatType[]>(n)) {}
55};
56
65template <typename FloatType, std::size_t rows_per_block = 2,
66 std::size_t cols_per_block = 2, std::size_t trotters_per_block = 2>
67struct ChimeraTransverseGPU {
68 using system_type = transverse_field_system;
69
78 ChimeraTransverseGPU(const TrotterSpins &init_trotter_spins,
79 const graph::Chimera<FloatType> &init_interaction,
80 FloatType gamma, int device_num = 0)
81 : gamma(gamma),
82 info({init_interaction.get_num_row(), init_interaction.get_num_column(),
83 init_trotter_spins.size()}),
84 interaction(init_interaction.get_num_row() *
85 init_interaction.get_num_column() * info.chimera_unitsize),
86 spin(utility::cuda::make_dev_unique<std::int32_t[]>(
87 init_interaction.get_num_row() * init_interaction.get_num_column() *
88 info.chimera_unitsize * init_trotter_spins.size())),
89 grid(dim3(init_interaction.get_num_column() / cols_per_block,
90 init_interaction.get_num_row() / rows_per_block,
91 init_trotter_spins.size() / trotters_per_block)),
92 block(dim3(info.chimera_unitsize * cols_per_block, rows_per_block,
93 trotters_per_block)),
94 dev_random(utility::cuda::make_dev_unique<FloatType[]>(
95 init_interaction.get_num_row() * init_interaction.get_num_column() *
96 info.chimera_unitsize * init_trotter_spins.size())) {
97
98 if (!(info.rows % rows_per_block == 0 && info.cols % cols_per_block == 0 &&
99 info.trotters % trotters_per_block == 0)) {
100 throw std::invalid_argument("invalid number of rows, cols, or trotters");
101 }
102
103 // initialize
104 initialize_gpu(init_interaction, init_trotter_spins, device_num);
105 }
106
116 ChimeraTransverseGPU(const graph::Spins &classical_spins,
117 const graph::Chimera<FloatType> &init_interaction,
118 FloatType gamma, size_t num_trotter_slices,
119 int device_num = 0)
120 : gamma(gamma),
121 info({init_interaction.get_num_row(), init_interaction.get_num_column(),
122 num_trotter_slices}),
123 interaction(init_interaction.get_num_row() *
124 init_interaction.get_num_column() * info.chimera_unitsize),
125 spin(utility::cuda::make_dev_unique<std::int32_t[]>(
126 init_interaction.get_num_row() * init_interaction.get_num_column() *
127 info.chimera_unitsize * num_trotter_slices)),
128 grid(dim3(init_interaction.get_num_column() / cols_per_block,
129 init_interaction.get_num_row() / rows_per_block,
130 num_trotter_slices / trotters_per_block)),
131 block(dim3(info.chimera_unitsize * cols_per_block, rows_per_block,
132 trotters_per_block)),
133 dev_random(utility::cuda::make_dev_unique<FloatType[]>(
134 init_interaction.get_num_row() * init_interaction.get_num_column() *
135 info.chimera_unitsize * num_trotter_slices)) {
136 // initialize trotter_spins with classical_spins
137 if (!(info.rows % rows_per_block == 0 && info.cols % cols_per_block == 0 &&
138 info.trotters % trotters_per_block == 0)) {
139 throw std::invalid_argument("invalid number of rows, cols, or trotters");
140 }
141
142 TrotterSpins trotter_spins(num_trotter_slices);
143 for (auto &spins : trotter_spins) {
144 spins = classical_spins;
145 }
146
147 // initialize
148 initialize_gpu(init_interaction, trotter_spins, device_num);
149 }
150
156 void reset_spins(const TrotterSpins &init_trotter_spins) {
157 // generate temporary interaction and spin
158 const std::size_t localsize = info.rows * info.cols * info.chimera_unitsize;
159 auto temp_spin =
160 utility::cuda::make_host_unique<int32_t[]>(localsize * info.trotters);
161
162 using namespace chimera_cuda;
163 // copy spin info to std::vector variables
164 for (size_t t = 0; t < info.trotters; t++) {
165 for (size_t r = 0; r < info.rows; r++) {
166 for (size_t c = 0; c < info.cols; c++) {
167 for (size_t i = 0; i < info.chimera_unitsize; i++) {
168 temp_spin[glIdx(info, r, c, i, t)] =
169 init_trotter_spins[t][glIdx(info, r, c, i)];
170 }
171 }
172 }
173 }
174 // copy to gpu
175 HANDLE_ERROR_CUDA(cudaMemcpy(spin.get(), temp_spin.get(),
176 localsize * info.trotters * sizeof(int32_t),
177 cudaMemcpyHostToDevice));
178 }
179
185 void reset_spins(const graph::Spins &classical_spins) {
186 TrotterSpins init_trotter_spins(
187 info.trotters); // info.trotters -> num_trotter_slices
188
189 for (auto &spins : init_trotter_spins) {
190 spins = classical_spins;
191 }
192
193 // generate temporary interaction and spin
194 const std::size_t localsize = info.rows * info.cols * info.chimera_unitsize;
195 auto temp_spin =
196 utility::cuda::make_host_unique<int32_t[]>(localsize * info.trotters);
197
198 using namespace chimera_cuda;
199 // copy spin info to std::vector variables
200 for (size_t t = 0; t < info.trotters; t++) {
201 for (size_t r = 0; r < info.rows; r++) {
202 for (size_t c = 0; c < info.cols; c++) {
203 for (size_t i = 0; i < info.chimera_unitsize; i++) {
204 temp_spin[glIdx(info, r, c, i, t)] =
205 init_trotter_spins[t][glIdx(info, r, c, i)];
206 }
207 }
208 }
209 }
210 // copy to gpu
211 HANDLE_ERROR_CUDA(cudaMemcpy(spin.get(), temp_spin.get(),
212 localsize * info.trotters * sizeof(int32_t),
213 cudaMemcpyHostToDevice));
214 }
215
219 FloatType gamma;
220
224 const ChimeraInfo info;
225
229 ChimeraInteractions<FloatType> interaction;
230
234 utility::cuda::unique_dev_ptr<std::int32_t[]> spin;
235
239 const dim3 grid;
240
244 const dim3 block;
245
249 utility::cuda::unique_dev_ptr<FloatType[]> dev_random;
250
251private:
259 inline void initialize_gpu(const graph::Chimera<FloatType> &init_interaction,
260 const TrotterSpins &trotter_spins, int gpu_num) {
261
262 // specify gpu number
263 HANDLE_ERROR_CUDA(cudaSetDevice(gpu_num));
264
265 // generate temporary interaction and spin
266 const std::size_t localsize = info.rows * info.cols * info.chimera_unitsize;
267
268 auto J_out_p = utility::cuda::make_host_unique<FloatType[]>(localsize);
269 auto J_out_n = utility::cuda::make_host_unique<FloatType[]>(localsize);
270 auto J_in_04 = utility::cuda::make_host_unique<FloatType[]>(localsize);
271 auto J_in_15 = utility::cuda::make_host_unique<FloatType[]>(localsize);
272 auto J_in_26 = utility::cuda::make_host_unique<FloatType[]>(localsize);
273 auto J_in_37 = utility::cuda::make_host_unique<FloatType[]>(localsize);
274 auto h = utility::cuda::make_host_unique<FloatType[]>(localsize);
275 auto temp_spin =
276 utility::cuda::make_host_unique<int32_t[]>(localsize * info.trotters);
277
278 using namespace chimera_cuda;
279
280 // copy interaction info to std::vector variables
281 for (size_t r = 0; r < info.rows; r++) {
282 for (size_t c = 0; c < info.cols; c++) {
283 for (size_t i = 0; i < info.chimera_unitsize; i++) {
284
285 J_out_p[glIdx(info, r, c, i)] = 0;
286 J_out_n[glIdx(info, r, c, i)] = 0;
287 J_in_04[glIdx(info, r, c, i)] = 0;
288 J_in_15[glIdx(info, r, c, i)] = 0;
289 J_in_26[glIdx(info, r, c, i)] = 0;
290 J_in_37[glIdx(info, r, c, i)] = 0;
291 h[glIdx(info, r, c, i)] = 0;
292
293 if (r > 0 && i < 4) {
294 // MINUS_R
295 J_out_p[glIdx(info, r, c, i)] =
296 init_interaction.J(r, c, i, graph::ChimeraDir::MINUS_R);
297 }
298 if (c > 0 && 4 <= i) {
299 // MINUS_C
300 J_out_p[glIdx(info, r, c, i)] =
301 init_interaction.J(r, c, i, graph::ChimeraDir::MINUS_C);
302 }
303 if (r < info.rows - 1 && i < 4) {
304 // PLUS_R
305 J_out_n[glIdx(info, r, c, i)] =
306 init_interaction.J(r, c, i, graph::ChimeraDir::PLUS_R);
307 }
308 if (c < info.cols - 1 && 4 <= i) {
309 // PLUS_C
310 J_out_n[glIdx(info, r, c, i)] =
311 init_interaction.J(r, c, i, graph::ChimeraDir::PLUS_C);
312 }
313
314 // inside chimera unit
315 J_in_04[glIdx(info, r, c, i)] =
316 init_interaction.J(r, c, i, graph::ChimeraDir::IN_0or4);
317 J_in_15[glIdx(info, r, c, i)] =
318 init_interaction.J(r, c, i, graph::ChimeraDir::IN_1or5);
319 J_in_26[glIdx(info, r, c, i)] =
320 init_interaction.J(r, c, i, graph::ChimeraDir::IN_2or6);
321 J_in_37[glIdx(info, r, c, i)] =
322 init_interaction.J(r, c, i, graph::ChimeraDir::IN_3or7);
323
324 // local field
325 h[glIdx(info, r, c, i)] = init_interaction.h(r, c, i);
326 }
327 }
328 }
329
330 // copy spin info to std::vector variables
331 for (size_t t = 0; t < info.trotters; t++) {
332 for (size_t r = 0; r < info.rows; r++) {
333 for (size_t c = 0; c < info.cols; c++) {
334 for (size_t i = 0; i < info.chimera_unitsize; i++) {
335 temp_spin[glIdx(info, r, c, i, t)] =
336 trotter_spins[t][init_interaction.to_ind(r, c, i)];
337 }
338 }
339 }
340 }
341
342 // cudaMemcpy
343 HANDLE_ERROR_CUDA(cudaMemcpy(interaction.J_out_p.get(), J_out_p.get(),
344 localsize * sizeof(FloatType),
345 cudaMemcpyHostToDevice));
346 HANDLE_ERROR_CUDA(cudaMemcpy(interaction.J_out_n.get(), J_out_n.get(),
347 localsize * sizeof(FloatType),
348 cudaMemcpyHostToDevice));
349 HANDLE_ERROR_CUDA(cudaMemcpy(interaction.J_in_04.get(), J_in_04.get(),
350 localsize * sizeof(FloatType),
351 cudaMemcpyHostToDevice));
352 HANDLE_ERROR_CUDA(cudaMemcpy(interaction.J_in_15.get(), J_in_15.get(),
353 localsize * sizeof(FloatType),
354 cudaMemcpyHostToDevice));
355 HANDLE_ERROR_CUDA(cudaMemcpy(interaction.J_in_26.get(), J_in_26.get(),
356 localsize * sizeof(FloatType),
357 cudaMemcpyHostToDevice));
358 HANDLE_ERROR_CUDA(cudaMemcpy(interaction.J_in_37.get(), J_in_37.get(),
359 localsize * sizeof(FloatType),
360 cudaMemcpyHostToDevice));
361 HANDLE_ERROR_CUDA(cudaMemcpy(interaction.h.get(), h.get(),
362 localsize * sizeof(FloatType),
363 cudaMemcpyHostToDevice));
364
365 HANDLE_ERROR_CUDA(cudaMemcpy(spin.get(), temp_spin.get(),
366 localsize * info.trotters * sizeof(int32_t),
367 cudaMemcpyHostToDevice));
368 }
369};
370
385template <std::size_t rows_per_block = 2, std::size_t cols_per_block = 2,
386 std::size_t trotters_per_block = 2, typename FloatType>
387ChimeraTransverseGPU<FloatType, rows_per_block, cols_per_block,
388 trotters_per_block>
389make_chimera_transverse_gpu(const TrotterSpins &init_trotter_spins,
390 const graph::Chimera<FloatType> &init_interaction,
391 double gamma, int device_num = 0) {
392 return ChimeraTransverseGPU<FloatType, rows_per_block, cols_per_block,
393 trotters_per_block>(
394 init_trotter_spins, init_interaction, gamma, device_num);
395}
396
411template <std::size_t rows_per_block = 2, std::size_t cols_per_block = 2,
412 std::size_t trotters_per_block = 2, typename FloatType>
413ChimeraTransverseGPU<FloatType, rows_per_block, cols_per_block,
414 trotters_per_block>
415make_chimera_transverse_gpu(const graph::Spins &classical_spins,
416 const graph::Chimera<FloatType> &init_interaction,
417 double gamma, size_t num_trotter_slices,
418 int device_num = 0) {
419 return ChimeraTransverseGPU<FloatType, rows_per_block, cols_per_block,
420 trotters_per_block>(
421 classical_spins, init_interaction, gamma, num_trotter_slices, device_num);
422}
423
424} // namespace system
425} // namespace openjij
426
427#endif
428#endif
auto json_parse(const json &obj, bool relabel=true)
parse json object from bqm.to_serializable
Definition parse.hpp:50
std::vector< Spin > Spins
Definition graph.hpp:27
std::vector< graph::Spins > TrotterSpins
trotterized spin (std::vector<Spins>) trotter_spins[i][j] -> jth spin in ith trotter slice.
Definition transverse_ising.hpp:32
Definition algorithm.hpp:24
double FloatType
Note:
Definition compile_config.hpp:37