Sequential Quantum Gate Decomposer  v1.9.6
Powerful decomposition of general unitarias into one- and two-qubit gates gates
common_GROQ.cpp
Go to the documentation of this file.
1 /*
2 Created on Fri Jun 26 14:13:26 2020
3 Copyright 2020 Peter Rakyta, Ph.D.
4 
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8 
9  http://www.apache.org/licenses/LICENSE-2.0
10 
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 
17 @author: Peter Rakyta, Ph.D.
18 */
24 #include "common_GROQ.h"
25 #include "matrix_base.hpp"
26 
27 #include <dlfcn.h>
28 #include <unistd.h>
29 #include <tbb/queuing_mutex.h>
30 
31 namespace {
32 
33 tbb::queuing_mutex libmutex;
34 
35 void unload_groq_sv_lib_unlocked();
36 int init_groq_sv_lib_unlocked(const int reserved_device_num, int initialize_id_in);
37 
38 }
39 
40 
41 // pointer to the dynamically loaded groq library (sv stands for state vector)
42 void* handle_sv = NULL;
43 
44 extern "C" {
45 
48 int (*calcsvKernelGroq_dll)(int num_gates, float* gates, int* target_qubits, int* control_qubits, float* result_real, float* result_imag, int device_num) = NULL;
49 int (*load_sv_dll)(float* data, size_t num_qubits, size_t device_num) = NULL;
50 void (*releive_groq_sv_dll)() = NULL;
51 int (*initialize_groq_sv_dll)( int accelerator_num ) = NULL;
52 
53 }
54 
55 // The ID of the class that has initialized the accelerator lib (used to not initialze again if not necessary)
56 int initialize_id = -1;
57 
58 
59 
65 
66  return initialize_id;
67 
68 }
69 
70 
71 
72 
73 
74 
79 {
80  tbb::queuing_mutex::scoped_lock lock(libmutex);
81  unload_groq_sv_lib_unlocked();
82 }
83 
84 
85 namespace {
86 
87 void unload_groq_sv_lib_unlocked()
88 {
89  if (handle_sv) {
91  dlclose(handle_sv);
92  handle_sv = NULL;
93  }
94 }
95 
96 }
97 
98 
105 int init_groq_sv_lib( const int reserved_device_num, int initialize_id_in ) {
106  tbb::queuing_mutex::scoped_lock lock(libmutex);
107  return init_groq_sv_lib_unlocked(reserved_device_num, initialize_id_in);
108 }
109 
110 
111 namespace {
112 
113 int init_groq_sv_lib_unlocked( const int reserved_device_num, int initialize_id_in ) {
114 
115  initialize_id = initialize_id_in;
116 
117  unload_groq_sv_lib_unlocked();
118 
119 
120  std::string lib_name = DFE_LIB_SV;
121 
122  // dynamic-loading the Groq calculator from shared library
123  handle_sv = dlopen(lib_name.c_str(), RTLD_NOW); //"MAXELEROSDIR"
124  if (handle_sv == NULL) {
125  std::string err("init_groq_lib: failed to load library " + lib_name + " - " + std::string(dlerror()));
126  throw err;
127  }
128  else {
129  get_accelerator_avail_num_sv_dll = (size_t (*)())dlsym(handle_sv, "get_accelerator_avail_num_sv");
130  get_accelerator_free_num_sv_dll = (size_t (*)())dlsym(handle_sv, "get_accelerator_free_num_sv");
131  calcsvKernelGroq_dll = (int (*)(int, float*, int*, int*, float*, float*, int))dlsym(handle_sv, "calcsvKernelGroq");
132  load_sv_dll = (int (*)(float*, size_t, size_t))dlsym(handle_sv, "prepare_state_vector");
133  releive_groq_sv_dll = (void (*)())dlsym(handle_sv, "releive_groq_sv");
134  initialize_groq_sv_dll = (int (*)(int))dlsym(handle_sv, "initialize_groq_sv");
135 
136  if (initialize_groq_sv_dll(reserved_device_num)) return 0;
137 
138  }
139  return 1;
140 
141 }
142 
143 }
144 
145 
157 void apply_to_groq_sv(int reserved_device_num, int chosen_device_num, int qbit_num, std::vector<Matrix>& u3_qbit, std::vector<int>& target_qbits, std::vector<int>& control_qbits, Matrix& quantum_state, int id_in) {
158 
159  //struct timespec starttime;
160  //timespec_get(&starttime, TIME_UTC);
161 
162  size_t matrix_size = 1 << qbit_num;
163 
164  // the number of chips to be allocated for the calculations
165  {
166  tbb::queuing_mutex::scoped_lock lock(libmutex);
167  if (handle_sv == NULL && !init_groq_sv_lib_unlocked(reserved_device_num, id_in)) {
168  throw std::string("Could not load and initialize Groq library");
169  }
170  }
171 
172  //struct timespec t;
173  //timespec_get(&t, TIME_UTC);
174  //printf("Total time on uploading the Groq program: %.9f\n", (t.tv_sec - starttime.tv_sec) + (t.tv_nsec - starttime.tv_nsec) / 1e9);
175 
176 
177 {
178  tbb::queuing_mutex::scoped_lock lock(libmutex);
179 
180  if ( quantum_state.size() == 0 ) {
181  if (load_sv_dll( NULL, qbit_num, chosen_device_num) ) {
182  throw std::string("Error occured while reseting the state vector to Groq LPU");
183  }
184 
185  quantum_state = Matrix( matrix_size, 1);
186 
187  }
188  else {
189 
190  if ( quantum_state.size() != matrix_size ) {
191  throw std::string("apply_to_groq_sv: the size of the input vector should be in match with the number of qubits");
192  }
193 
194  if ( quantum_state.cols != 1 ) {
195  throw std::string("apply_to_groq_sv: the input state should have a single column");
196  }
197 
198  //timespec_get(&starttime, TIME_UTC);
199  std::vector<float> inout;
200  inout.reserve(quantum_state.size()*2);
201  for (size_t idx = 0; idx < quantum_state.rows; idx++) {
202  inout.push_back(quantum_state.data[idx].real);
203  inout.push_back(quantum_state.data[idx].imag);
204  }
205 
206  //timespec_get(&t, TIME_UTC);
207  //printf("Total time on converting State data to float: %.9f\n", (t.tv_sec - starttime.tv_sec) + (t.tv_nsec - starttime.tv_nsec) / 1e9);
208 
209 
210  //timespec_get(&starttime, TIME_UTC);
211  if (load_sv_dll(inout.data(), qbit_num, chosen_device_num)) {
212  throw std::string("Error occured while uploading state vector to Groq LPU");
213  }
214 
215  //timespec_get(&t, TIME_UTC);
216  //printf("Total time on uploading the state vector: %.9f\n", (t.tv_sec - starttime.tv_sec) + (t.tv_nsec - starttime.tv_nsec) / 1e9);
217 
218  }
219 }
220 
221 
222  std::vector<float> gateMatrices;
223  gateMatrices.reserve( 4*u3_qbit.size()*2 );
224  for (const Matrix& m : u3_qbit) {
225  for (size_t i = 0; i < m.rows; i++) {
226  for (size_t j = 0; j < m.cols; j++) {
227 
228  gateMatrices.push_back( m.data[i*m.stride+j].real );
229  gateMatrices.push_back( m.data[i*m.stride+j].imag );
230 
231  }
232  }
233  }
234 
235  //timespec_get(&starttime, TIME_UTC);
236  // evaluate the gate kernels on the Groq chip
237  matrix_base<float> transformed_sv_real( matrix_size, 1);
238  matrix_base<float> transformed_sv_imag( matrix_size, 1);
239 
240  if (calcsvKernelGroq_dll(u3_qbit.size(), gateMatrices.data(), target_qbits.data(), control_qbits.data(), transformed_sv_real.get_data(), transformed_sv_imag.get_data(), chosen_device_num)) {
241  throw std::string("Error running gate kernels on groq");
242  }
243 
244  //timespec_get(&t, TIME_UTC);
245  //printf("Total time on calcsvKernelGroq: %.9f\n", (t.tv_sec - starttime.tv_sec) + (t.tv_nsec - starttime.tv_nsec) / 1e9);
246 
247 
248  //timespec_get(&starttime, TIME_UTC);
249  // transform the state vector to double representation
250  for (size_t idx = 0; idx < matrix_size; idx++) {
251  quantum_state.data[idx].real = transformed_sv_real[idx];
252  quantum_state.data[idx].imag = transformed_sv_imag[idx];
253  }
254  //timespec_get(&t, TIME_UTC);
255  //printf("Total time on transforming state vector to double: %.9f\n", (t.tv_sec - starttime.tv_sec) + (t.tv_nsec - starttime.tv_nsec) / 1e9);
256 
257 
258 
259 }
void apply_to_groq_sv(int reserved_device_num, int chosen_device_num, int qbit_num, std::vector< Matrix > &u3_qbit, std::vector< int > &target_qbits, std::vector< int > &control_qbits, Matrix &quantum_state, int id_in)
Call to pefrom the state vector simulation on the Groq hardware.
void unload_groq_sv_lib()
Call to unload the programs from the reserved Groq cards.
Definition: common_GROQ.cpp:78
size_t(* get_accelerator_avail_num_sv_dll)()
Definition: common_GROQ.cpp:46
int init_groq_sv_lib(const int reserved_device_num, int initialize_id_in)
Call to allocated Groq cards for calculations.
int(* load_sv_dll)(float *data, size_t num_qubits, size_t device_num)
Definition: common_GROQ.cpp:49
int get_initialize_id()
Call to get the identification number of the inititalization of the library.
Definition: common_GROQ.cpp:64
int initialize_id
Definition: common_GROQ.cpp:56
int(* initialize_groq_sv_dll)(int accelerator_num)
Definition: common_GROQ.cpp:51
scalar * data
pointer to the stored data
Definition: matrix_base.hpp:48
void * handle_sv
Definition: common_GROQ.cpp:42
data
load the unitary from file
Definition: example.py:51
Header file for Groq LPU support in state vector simulation.
scalar * get_data() const
Call to get the pointer to the stored data.
int rows
The number of rows.
Definition: matrix_base.hpp:42
int cols
The number of columns.
Definition: matrix_base.hpp:44
matrix_size
[load Umtx]
Definition: example.py:58
#define DFE_LIB_SV
Definition: common_GROQ.h:41
void(* releive_groq_sv_dll)()
Definition: common_GROQ.cpp:50
int(* calcsvKernelGroq_dll)(int num_gates, float *gates, int *target_qubits, int *control_qubits, float *result_real, float *result_imag, int device_num)
Definition: common_GROQ.cpp:48
Double-precision complex matrix (float64).
Definition: matrix.h:38
int size() const
Call to get the number of the allocated elements.
size_t(* get_accelerator_free_num_sv_dll)()
Definition: common_GROQ.cpp:47
double real
the real part of a complex number
Definition: QGDTypes.h:40
double imag
the imaginary part of a complex number
Definition: QGDTypes.h:42