Sequential Quantum Gate Decomposer  v1.9.6
Powerful decomposition of general unitarias into one- and two-qubit gates gates
common.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 */
23 //
24 // @brief A base class responsible for constructing matrices of C-NOT, U3
25 // gates acting on the N-qubit space
26 
27 #include "common.h"
28 #include "matrix_float.h"
29 #include <tbb/scalable_allocator.h>
30 
31 
35 double activation_function( double Phi, int limit ) {
36 
37 
38  return Phi;
39 
40 /*
41  while (Phi < 0 ) {
42  Phi = Phi + 2*M_PI;
43  }
44 
45  while (Phi > 2*M_PI ) {
46  Phi = Phi - 2*M_PI;
47  }
48 
49 
50  double ret = Phi;
51 
52 
53  for (int idx=0; idx<limit; idx++) {
54 
55 
56  ret = 0.5*(1.0-std::cos(ret))*M_PI;
57 
58  if ( Phi > M_PI ) {
59  ret = 2*M_PI - ret;
60  }
61 
62  }
63 
64  return ret;
65 */
66 }
67 
75 void fread_wrapper( void * buffer, size_t size, size_t count, FILE * stream) {
76 
77  size_t fread_status = fread(buffer, size, count, stream);
78 
79  if ( fread_status < count ) {
80  std::string err("Reached the end of the file before finishing reading");
81  throw err;
82  }
83 
84 }
85 
86 
93 void* qgd_calloc( int element_num, int size, int alignment ) {
94 
95  void* ret = scalable_aligned_malloc( size*element_num, CACHELINE);
96  memset(ret, 0, element_num*size);
97  return ret;
98 }
99 
109 void* qgd_realloc(void* aligned_ptr, int element_num, int size, int alignment ) {
110 
111  void* ret = scalable_aligned_realloc(aligned_ptr, size*element_num, CACHELINE);
112  return ret;
113 
114 }
115 
116 
117 
121 void qgd_free( void* ptr ) {
122 
123  // preventing double free corruption
124  if (ptr != NULL ) {
125  scalable_aligned_free(ptr);
126  }
127  ptr = NULL;
128 }
129 
130 
136 int Power_of_2(int n) {
137  if (n == 0) return 1;
138 
139  return 1 << n;
140 }
141 
142 
143 
149 void add_unique_elelement( std::vector<int> &involved_qbits, int qbit ) {
150 
151  if ( involved_qbits.size() == 0 ) {
152  involved_qbits.push_back( qbit );
153  }
154 
155  for(std::vector<int>::iterator it = involved_qbits.begin(); it != involved_qbits.end(); ++it) {
156 
157  int current_val = *it;
158 
159  if (current_val == qbit) {
160  return;
161  }
162  else if (current_val > qbit) {
163  involved_qbits.insert( it, qbit );
164  return;
165  }
166 
167  }
168 
169  // add the qbit to the end if neither of the conditions were satisfied
170  involved_qbits.push_back( qbit );
171 
172  return;
173 
174 }
175 
176 
183 
184  Matrix mtx = Matrix(matrix_size, matrix_size);
185  memset(mtx.get_data(), 0, mtx.size()*sizeof(QGD_Complex16) );
186 
187  // setting the diagonal elelments to identity
188  for(int idx = 0; idx < matrix_size; ++idx)
189  {
190  int element_index = idx*matrix_size + idx;
191  mtx[element_index].real = 1.0;
192  }
193 
194  return mtx;
195 
196 }
197 
204 
205  Matrix_float mtx = Matrix_float(matrix_size, matrix_size);
206  memset(mtx.get_data(), 0, mtx.size()*sizeof(QGD_Complex8) );
207 
208  // setting the diagonal elements to identity
209  for(int idx = 0; idx < matrix_size; ++idx)
210  {
211  int element_index = idx*mtx.stride + idx;
212  mtx[element_index].real = 1.0f;
213  }
214 
215  return mtx;
216 
217 }
218 
219 
220 
227 Matrix
228 reduce_zgemm( std::vector<Matrix>& mtxs ) {
229 
230 
231 
232  if (mtxs.size() == 0 ) {
233  return Matrix();
234  }
235 
236  // pointers to matrices to be used in the multiplications
237  Matrix A;
238  Matrix B;
239  Matrix C;
240 
241  // the iteration number
242  int iteration = 0;
243 
244 
245  A = *mtxs.begin();
246 
247  // calculate the product of complex matrices
248  for(std::vector<Matrix>::iterator it=++mtxs.begin(); it != mtxs.end(); ++it) {
249 
250  iteration++;
251  B = *it;
252 
253  if ( iteration>1 ) {
254  A = C;
255  }
256 
257  // calculate the product of A and B
258  C = dot(A, B);
259 /*
260 A.print_matrix();
261 B.print_matrix();
262 C.print_matrix();
263 */
264  }
265 
266  //C.print_matrix();
267  return C;
268 
269 }
270 
271 
278 
279  int matrix_size = mtx.rows;
280 
281  for(int idx = 0; idx < matrix_size; idx++) {
282  int element_idx = idx*matrix_size+idx;
283  mtx[element_idx].real = mtx[element_idx].real - scalar.real;
284  mtx[element_idx].imag = mtx[element_idx].imag - scalar.imag;
285  }
286 
287 }
288 
289 
290 
291 
299 
300  QGD_Complex16 ret;
301  ret.real = a.real*b.real - a.imag*b.imag;
302  ret.imag = a.real*b.imag + a.imag*b.real;
303 
304  return ret;
305 
306 }
307 
315 
316  QGD_Complex8 ret;
317  ret.real = a.real*b.real - a.imag*b.imag;
318  ret.imag = a.real*b.imag + a.imag*b.real;
319 
320  return ret;
321 
322 }
323 
331 
332  QGD_Complex16 ret;
333  ret.real = a*b.real;
334  ret.imag = a*b.imag;
335 
336  return ret;
337 
338 }
339 
347 
348  QGD_Complex8 ret;
349  ret.real = a*b.real;
350  ret.imag = a*b.imag;
351 
352  return ret;
353 
354 }
355 
356 
357 
363 void mult( QGD_Complex16 a, Matrix& b ) {
364 
365  int element_num = b.size();
366 
367  for (int idx=0; idx<element_num; idx++) {
368  QGD_Complex16 tmp = b[idx];
369  b[idx].real = a.real*tmp.real - a.imag*tmp.imag;
370  b[idx].imag = a.real*tmp.imag + a.imag*tmp.real;
371  }
372 
373  return;
374 
375 }
376 
383 
384  int element_num = b.size();
385 
386  for (int idx=0; idx<element_num; idx++) {
387  QGD_Complex8 tmp = b[idx];
388  b[idx].real = a.real*tmp.real - a.imag*tmp.imag;
389  b[idx].imag = a.real*tmp.imag + a.imag*tmp.real;
390  }
391 
392  return;
393 
394 }
395 
396 
397 
404 
405  if ( b.cols != 1 ) {
406  std::string error("mult: The input argument b should be a single-column vector.");
407  throw error;
408  }
409 
410  int n_rows = a.rows;
411  Matrix ret = Matrix(n_rows,1);
412 
413  tbb::parallel_for( tbb::blocked_range<int>(0, n_rows, 32), [&](tbb::blocked_range<int> r) {
414 
415  for (int idx=r.begin(); idx<r.end(); ++idx){
416 
417  ret[idx].imag = 0.0;
418  ret[idx].real = 0.0;
419  int nz_start = a.indptr[idx];
420  int nz_end = a.indptr[idx+1];
421 
422  for (int nz_idx=nz_start; nz_idx<nz_end; nz_idx++){
423 
424  int jdx = a.indices[nz_idx];
425  QGD_Complex16& state = b[jdx];
426  QGD_Complex16 result = mult(a.data[nz_idx], state);
427 
428  ret[idx].real += result.real;
429  ret[idx].imag += result.imag;
430 
431  }
432  }
433  });
434 
435  return ret;
436 }
437 
438 
439 
444 double arg( const QGD_Complex16& a ) {
445 
446 
447  double angle;
448 
449  if ( a.real > 0 && a.imag > 0 ) {
450  angle = std::atan(a.imag/a.real);
451  return angle;
452  }
453  else if ( a.real > 0 && a.imag <= 0 ) {
454  angle = std::atan(a.imag/a.real);
455  return angle;
456  }
457  else if ( a.real < 0 && a.imag > 0 ) {
458  angle = std::atan(a.imag/a.real) + M_PI;
459  return angle;
460  }
461  else if ( a.real < 0 && a.imag <= 0 ) {
462  angle = std::atan(a.imag/a.real) - M_PI;
463  return angle;
464  }
465  else if ( std::abs(a.real) < 1e-8 && a.imag > 0 ) {
466  angle = M_PI/2;
467  return angle;
468  }
469  else {
470  angle = -M_PI/2;
471  return angle;
472  }
473 
474 
475 
476 }
477 
478 
479 
480 
481 
482 
483 
484 
486 
487  int samples = b.cols;
488  Matrix_real d(1,samples);
489  Matrix_real g(1,samples);
490  double sk =0.0;
491 
492  for (int rdx=0; rdx<samples; rdx++){
493  d[rdx] = b[rdx];
494 
495  for(int cdx=0; cdx<samples; cdx++){
496  d[rdx] = d[rdx] - A[rdx*samples+cdx]*x0[cdx];
497  }
498 
499  g[rdx] = -1.*d[rdx];
500  sk = sk + d[rdx]*d[rdx];
501  }
502 
503  int iter=0;
504  while (std::sqrt(sk/b.cols) > tol && iter<1000){
505 
506  double dAd=0.0;
507  Matrix_real Ad(1,b.cols);
508  for (int rdx=0; rdx<samples; rdx++){
509 
510  Ad[rdx] = 0.;
511 
512  for(int cdx=0; cdx<samples; cdx++){
513  Ad[rdx] = Ad[rdx] + A[rdx*samples+cdx]*d[cdx];
514  }
515 
516  dAd = dAd + d[rdx]*Ad[rdx];
517  }
518 
519  double mu_k = sk / dAd;
520  double sk_new = 0.;
521 
522  for(int idx=0; idx<samples; idx++){
523 
524  x0[idx] = x0[idx] + mu_k*d[idx];
525  g[idx] = g[idx] + mu_k*Ad[idx];
526  sk_new = sk_new + g[idx]*g[idx];
527 
528  }
529 
530  for (int idx=0; idx<samples;idx++){
531  d[idx] = (sk_new/sk)*d[idx] - g[idx];
532  }
533 
534  sk = sk_new;
535 
536  iter++;
537  }
538  return;
539 
540 }
541 
542 
543 
Matrix dot(Matrix &A, Matrix &B)
Call to calculate the product of two complex matrices by calling method zgemm3m from the CBLAS librar...
Definition: dot.cpp:38
Header file of single-precision complex array storage with automatic and thread safe reference counti...
void * qgd_calloc(int element_num, int size, int alignment)
custom defined memory allocation function.
Definition: common.cpp:93
void conjugate_gradient(Matrix_real A, Matrix_real b, Matrix_real &x0, double tol)
Definition: common.cpp:485
void qgd_free(void *ptr)
custom defined memory release function.
Definition: common.cpp:121
int stride
The column stride of the array. (The array elements in one row are a_0, a_1, ... a_{cols-1}, 0, 0, 0, 0. The number of zeros is stride-cols)
Definition: matrix_base.hpp:46
float real
real part
Definition: QGDTypes.h:47
Structure type representing single-precision complex numbers.
Definition: QGDTypes.h:46
QGD_Complex16 * data
Definition: matrix_sparse.h:47
QGD_Complex16 mult(QGD_Complex16 &a, QGD_Complex16 &b)
Call to calculate the product of two complex scalars.
Definition: common.cpp:298
Class to store data of complex arrays and its properties.
Definition: matrix_sparse.h:38
float imag
imaginary part
Definition: QGDTypes.h:48
scalar * get_data() const
Call to get the pointer to the stored data.
#define CACHELINE
Definition: QGDTypes.h:33
Matrix reduce_zgemm(std::vector< Matrix > &mtxs)
Calculate the product of several square shaped complex matrices stored in a vector.
Definition: common.cpp:228
double arg(const QGD_Complex16 &a)
Call to retrieve the phase of a complex number.
Definition: common.cpp:444
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 M_PI
Definition: qgd_math.h:42
Structure type representing complex numbers in the SQUANDER package.
Definition: QGDTypes.h:38
int Power_of_2(int n)
Calculates the n-th power of 2.
Definition: common.cpp:136
Double-precision complex matrix (float64).
Definition: matrix.h:38
int size() const
Call to get the number of the allocated elements.
void subtract_diag(Matrix &mtx, QGD_Complex16 scalar)
Call to subtract a scalar from the diagonal of a complex matrix.
Definition: common.cpp:277
Single-precision complex matrix (float32).
Definition: matrix_float.h:41
Matrix create_identity(int matrix_size)
Call to create an identity matrix.
Definition: common.cpp:182
Header file for commonly used functions and wrappers to CBLAS functions.
double activation_function(double Phi, int limit)
?????
Definition: common.cpp:35
void add_unique_elelement(std::vector< int > &involved_qbits, int qbit)
Add an integer to a vector of integers if the integer is not already an element of the vector...
Definition: common.cpp:149
double real
the real part of a complex number
Definition: QGDTypes.h:40
void * qgd_realloc(void *aligned_ptr, int element_num, int size, int alignment)
custom defined memory reallocation function.
Definition: common.cpp:109
void fread_wrapper(void *buffer, size_t size, size_t count, FILE *stream)
Wrapper function aound fread with error handling.
Definition: common.cpp:75
Class to store data of complex arrays and its properties.
Definition: matrix_real.h:41
double imag
the imaginary part of a complex number
Definition: QGDTypes.h:42
Matrix_float create_identity_float(int matrix_size)
Call to create a single-precision complex identity matrix.
Definition: common.cpp:203