Sequential Quantum Gate Decomposer  v1.9.3
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 <tbb/scalable_allocator.h>
29 
30 
34 double activation_function( double Phi, int limit ) {
35 
36 
37  return Phi;
38 
39 /*
40  while (Phi < 0 ) {
41  Phi = Phi + 2*M_PI;
42  }
43 
44  while (Phi > 2*M_PI ) {
45  Phi = Phi - 2*M_PI;
46  }
47 
48 
49  double ret = Phi;
50 
51 
52  for (int idx=0; idx<limit; idx++) {
53 
54 
55  ret = 0.5*(1.0-std::cos(ret))*M_PI;
56 
57  if ( Phi > M_PI ) {
58  ret = 2*M_PI - ret;
59  }
60 
61  }
62 
63  return ret;
64 */
65 }
66 
67 
74 void* qgd_calloc( int element_num, int size, int alignment ) {
75 
76  void* ret = scalable_aligned_malloc( size*element_num, CACHELINE);
77  memset(ret, 0, element_num*size);
78  return ret;
79 }
80 
90 void* qgd_realloc(void* aligned_ptr, int element_num, int size, int alignment ) {
91 
92  void* ret = scalable_aligned_realloc(aligned_ptr, size*element_num, CACHELINE);
93  return ret;
94 
95 }
96 
97 
98 
102 void qgd_free( void* ptr ) {
103 
104  // preventing double free corruption
105  if (ptr != NULL ) {
106  scalable_aligned_free(ptr);
107  }
108  ptr = NULL;
109 }
110 
111 
117 int Power_of_2(int n) {
118  if (n == 0) return 1;
119  if (n == 1) return 2;
120 
121  return 2 * Power_of_2(n-1);
122 }
123 
124 
125 
131 void add_unique_elelement( std::vector<int> &involved_qbits, int qbit ) {
132 
133  if ( involved_qbits.size() == 0 ) {
134  involved_qbits.push_back( qbit );
135  }
136 
137  for(std::vector<int>::iterator it = involved_qbits.begin(); it != involved_qbits.end(); ++it) {
138 
139  int current_val = *it;
140 
141  if (current_val == qbit) {
142  return;
143  }
144  else if (current_val > qbit) {
145  involved_qbits.insert( it, qbit );
146  return;
147  }
148 
149  }
150 
151  // add the qbit to the end if neither of the conditions were satisfied
152  involved_qbits.push_back( qbit );
153 
154  return;
155 
156 }
157 
158 
165 
166  Matrix mtx = Matrix(matrix_size, matrix_size);
167  memset(mtx.get_data(), 0, mtx.size()*sizeof(QGD_Complex16) );
168 
169  // setting the diagonal elelments to identity
170  for(int idx = 0; idx < matrix_size; ++idx)
171  {
172  int element_index = idx*matrix_size + idx;
173  mtx[element_index].real = 1.0;
174  }
175 
176  return mtx;
177 
178 }
179 
180 
181 
188 Matrix
189 reduce_zgemm( std::vector<Matrix>& mtxs ) {
190 
191 
192 
193  if (mtxs.size() == 0 ) {
194  return Matrix();
195  }
196 
197  // pointers to matrices to be used in the multiplications
198  Matrix A;
199  Matrix B;
200  Matrix C;
201 
202  // the iteration number
203  int iteration = 0;
204 
205 
206  A = *mtxs.begin();
207 
208  // calculate the product of complex matrices
209  for(std::vector<Matrix>::iterator it=++mtxs.begin(); it != mtxs.end(); ++it) {
210 
211  iteration++;
212  B = *it;
213 
214  if ( iteration>1 ) {
215  A = C;
216  }
217 
218  // calculate the product of A and B
219  C = dot(A, B);
220 /*
221 A.print_matrix();
222 B.print_matrix();
223 C.print_matrix();
224 */
225  }
226 
227  //C.print_matrix();
228  return C;
229 
230 }
231 
232 
239 
240  int matrix_size = mtx.rows;
241 
242  for(int idx = 0; idx < matrix_size; idx++) {
243  int element_idx = idx*matrix_size+idx;
244  mtx[element_idx].real = mtx[element_idx].real - scalar.real;
245  mtx[element_idx].imag = mtx[element_idx].imag - scalar.imag;
246  }
247 
248 }
249 
250 
251 
252 
260 
261  QGD_Complex16 ret;
262  ret.real = a.real*b.real - a.imag*b.imag;
263  ret.imag = a.real*b.imag + a.imag*b.real;
264 
265  return ret;
266 
267 }
268 
276 
277  QGD_Complex16 ret;
278  ret.real = a*b.real;
279  ret.imag = a*b.imag;
280 
281  return ret;
282 
283 }
284 
285 
286 
292 void mult( QGD_Complex16 a, Matrix& b ) {
293 
294  int element_num = b.size();
295 
296  for (int idx=0; idx<element_num; idx++) {
297  QGD_Complex16 tmp = b[idx];
298  b[idx].real = a.real*tmp.real - a.imag*tmp.imag;
299  b[idx].imag = a.real*tmp.imag + a.imag*tmp.real;
300  }
301 
302  return;
303 
304 }
305 
306 
307 
314 
315  if ( b.cols != 1 ) {
316  std::string error("mult: The input argument b should be a single-column vector.");
317  throw error;
318  }
319 
320  int n_rows = a.rows;
321  Matrix ret = Matrix(n_rows,1);
322 
323  tbb::parallel_for( tbb::blocked_range<int>(0, n_rows, 32), [&](tbb::blocked_range<int> r) {
324 
325  for (int idx=r.begin(); idx<r.end(); ++idx){
326 
327  ret[idx].imag = 0.0;
328  ret[idx].real = 0.0;
329  int nz_start = a.indptr[idx];
330  int nz_end = a.indptr[idx+1];
331 
332  for (int nz_idx=nz_start; nz_idx<nz_end; nz_idx++){
333 
334  int jdx = a.indices[nz_idx];
335  QGD_Complex16& state = b[jdx];
336  QGD_Complex16 result = mult(a.data[nz_idx], state);
337 
338  ret[idx].real += result.real;
339  ret[idx].imag += result.imag;
340 
341  }
342  }
343  });
344 
345  return ret;
346 }
347 
348 
349 
354 double arg( const QGD_Complex16& a ) {
355 
356 
357  double angle;
358 
359  if ( a.real > 0 && a.imag > 0 ) {
360  angle = std::atan(a.imag/a.real);
361  return angle;
362  }
363  else if ( a.real > 0 && a.imag <= 0 ) {
364  angle = std::atan(a.imag/a.real);
365  return angle;
366  }
367  else if ( a.real < 0 && a.imag > 0 ) {
368  angle = std::atan(a.imag/a.real) + M_PI;
369  return angle;
370  }
371  else if ( a.real < 0 && a.imag <= 0 ) {
372  angle = std::atan(a.imag/a.real) - M_PI;
373  return angle;
374  }
375  else if ( std::abs(a.real) < 1e-8 && a.imag > 0 ) {
376  angle = M_PI/2;
377  return angle;
378  }
379  else {
380  angle = -M_PI/2;
381  return angle;
382  }
383 
384 
385 
386 }
387 
388 
389 
390 
391 
392 
393 
394 
396 
397  int samples = b.cols;
398  Matrix_real d(1,samples);
399  Matrix_real g(1,samples);
400  double sk =0.0;
401 
402  for (int rdx=0; rdx<samples; rdx++){
403  d[rdx] = b[rdx];
404 
405  for(int cdx=0; cdx<samples; cdx++){
406  d[rdx] = d[rdx] - A[rdx*samples+cdx]*x0[cdx];
407  }
408 
409  g[rdx] = -1.*d[rdx];
410  sk = sk + d[rdx]*d[rdx];
411  }
412 
413  int iter=0.0;
414  while (std::sqrt(sk/b.cols) > tol && iter<1000){
415 
416  double dAd=0.0;
417  Matrix_real Ad(1,b.cols);
418  for (int rdx=0; rdx<samples; rdx++){
419 
420  Ad[rdx] = 0.;
421 
422  for(int cdx=0; cdx<samples; cdx++){
423  Ad[rdx] = Ad[rdx] + A[rdx*samples+cdx]*d[cdx];
424  }
425 
426  dAd = dAd + d[rdx]*Ad[rdx];
427  }
428 
429  double mu_k = sk / dAd;
430  double sk_new = 0.;
431 
432  for(int idx=0; idx<samples; idx++){
433 
434  x0[idx] = x0[idx] + mu_k*d[idx];
435  g[idx] = g[idx] + mu_k*Ad[idx];
436  sk_new = sk_new + g[idx]*g[idx];
437 
438  }
439 
440  for (int idx=0; idx<samples;idx++){
441  d[idx] = (sk_new/sk)*d[idx] - g[idx];
442  }
443 
444  sk = sk_new;
445 
446  iter++;
447  }
448  return;
449 
450 }
451 
452 
453 
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
void * qgd_calloc(int element_num, int size, int alignment)
custom defined memory allocation function.
Definition: common.cpp:74
void conjugate_gradient(Matrix_real A, Matrix_real b, Matrix_real &x0, double tol)
Definition: common.cpp:395
void qgd_free(void *ptr)
custom defined memory release function.
Definition: common.cpp:102
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:259
Class to store data of complex arrays and its properties.
Definition: matrix_sparse.h:38
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:189
double arg(const QGD_Complex16 &a)
Call to retrieve the phase of a complex number.
Definition: common.cpp:354
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
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:117
Class to store data of complex arrays and its properties.
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:238
Matrix create_identity(int matrix_size)
Call to create an identity matrix.
Definition: common.cpp:164
Header file for commonly used functions and wrappers to CBLAS functions.
double activation_function(double Phi, int limit)
?????
Definition: common.cpp:34
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:131
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:90
result
the result of the Qiskit job
Class to store data of complex arrays and its properties.
Definition: matrix_real.h:39
double imag
the imaginary part of a complex number
Definition: QGDTypes.h:42