Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
apply_kernel_to_state_vector_input.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 */
25 //#include <immintrin.h>
26 #include "tbb/tbb.h"
27 
37 void
38 apply_kernel_to_state_vector_input(Matrix& u3_1qbit, Matrix& input, const bool& deriv, const int& target_qbit, const int& control_qbit, const int& matrix_size) {
39 
40 
41  int index_step_target = 1 << target_qbit;
42  int current_idx = 0;
43 
44 
45  for ( int current_idx_pair=current_idx + index_step_target; current_idx_pair<matrix_size; current_idx_pair=current_idx_pair+(index_step_target << 1) ) {
46 
47  for (int idx = 0; idx < index_step_target; idx++) {
48  //tbb::parallel_for(0, index_step_target, 1, [&](int idx) {
49 
50  int current_idx_loc = current_idx + idx;
51  int current_idx_pair_loc = current_idx_pair + idx;
52 
53  int row_offset = current_idx_loc * input.stride;
54  int row_offset_pair = current_idx_pair_loc * input.stride;
55 
56  if (control_qbit < 0 || ((current_idx_loc >> control_qbit) & 1)) {
57 
58  QGD_Complex16 element = input[row_offset];
59  QGD_Complex16 element_pair = input[row_offset_pair];
60 
61  QGD_Complex16 tmp1 = mult(u3_1qbit[0], element);
62  QGD_Complex16 tmp2 = mult(u3_1qbit[1], element_pair);
63 
64  input[row_offset].real = tmp1.real + tmp2.real;
65  input[row_offset].imag = tmp1.imag + tmp2.imag;
66 
67  tmp1 = mult(u3_1qbit[2], element);
68  tmp2 = mult(u3_1qbit[3], element_pair);
69 
70  input[row_offset_pair].real = tmp1.real + tmp2.real;
71  input[row_offset_pair].imag = tmp1.imag + tmp2.imag;
72 
73 
74 
75  }
76  else if (deriv) {
77  // when calculating derivatives, the constant element should be zeros
78  memset(input.get_data() + row_offset, 0.0, input.cols * sizeof(QGD_Complex16));
79  memset(input.get_data() + row_offset_pair, 0.0, input.cols * sizeof(QGD_Complex16));
80  }
81  else {
82  // leave the state as it is
83  continue;
84  }
85 
86 
87  //std::cout << current_idx_target << " " << current_idx_target_pair << std::endl;
88 
89 
90  //});
91  }
92 
93 
94  current_idx = current_idx + (index_step_target << 1);
95 
96 
97  }
98 
99 
100 
101 
102 }
103 
104 
105 
106 
107 
117 void
118 apply_kernel_to_state_vector_input_parallel(Matrix& u3_1qbit, Matrix& input, const bool& deriv, const int& target_qbit, const int& control_qbit, const int& matrix_size) {
119 
120 
121  int index_step_target = 1 << target_qbit;
122 
123  int parallel_outer_cycles = matrix_size/(index_step_target << 1);
124  int outer_grain_size;
125  if ( index_step_target <= 2 ) {
126  outer_grain_size = 64;
127  }
128  else if ( index_step_target <= 4 ) {
129  outer_grain_size = 32;
130  }
131  else if ( index_step_target <= 8 ) {
132  outer_grain_size = 16;
133  }
134  else if ( index_step_target <= 16 ) {
135  outer_grain_size = 8;
136  }
137  else {
138  outer_grain_size = 2;
139  }
140 
141  int inner_grain_size = 64;
142 
143  tbb::parallel_for( tbb::blocked_range<int>(0, parallel_outer_cycles, outer_grain_size), [&](tbb::blocked_range<int> r) {
144 
145  int current_idx = r.begin()*(index_step_target << 1);
146  int current_idx_pair = index_step_target + r.begin()*(index_step_target << 1);
147 
148  for (int rdx=r.begin(); rdx<r.end(); rdx++) {
149 
150 
151  tbb::parallel_for( tbb::blocked_range<int>(0,index_step_target,inner_grain_size), [&](tbb::blocked_range<int> r) {
152  for (int idx=r.begin(); idx<r.end(); ++idx) {
153 
154 
155 
156  int current_idx_loc = current_idx + idx;
157  int current_idx_pair_loc = current_idx_pair + idx;
158 
159  int row_offset = current_idx_loc * input.stride;
160  int row_offset_pair = current_idx_pair_loc * input.stride;
161 
162  if (control_qbit < 0 || ((current_idx_loc >> control_qbit) & 1)) {
163 
164  QGD_Complex16 element = input[row_offset];
165  QGD_Complex16 element_pair = input[row_offset_pair];
166 
167  QGD_Complex16 tmp1 = mult(u3_1qbit[0], element);
168  QGD_Complex16 tmp2 = mult(u3_1qbit[1], element_pair);
169 
170  input[row_offset].real = tmp1.real + tmp2.real;
171  input[row_offset].imag = tmp1.imag + tmp2.imag;
172 
173  tmp1 = mult(u3_1qbit[2], element);
174  tmp2 = mult(u3_1qbit[3], element_pair);
175 
176  input[row_offset_pair].real = tmp1.real + tmp2.real;
177  input[row_offset_pair].imag = tmp1.imag + tmp2.imag;
178 
179 
180 
181  }
182  else if (deriv) {
183  // when calculating derivatives, the constant element should be zeros
184  memset(input.get_data() + row_offset, 0.0, input.cols * sizeof(QGD_Complex16));
185  memset(input.get_data() + row_offset_pair, 0.0, input.cols * sizeof(QGD_Complex16));
186  }
187  else {
188  // leave the state as it is
189  continue;
190  }
191 
192 
193  //std::cout << current_idx_target << " " << current_idx_target_pair << std::endl;
194 
195 
196  }
197  });
198 
199 
200 
201  current_idx = current_idx + (index_step_target << 1);
202  current_idx_pair = current_idx_pair + (index_step_target << 1);
203 
204  }
205  });
206 
207 
208 
209 
210 }
211 
212 
213 
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
QGD_Complex16 mult(QGD_Complex16 &a, QGD_Complex16 &b)
Call to calculate the product of two complex scalars.
Definition: common.cpp:259
scalar * get_data() const
Call to get the pointer to the stored data.
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
Class to store data of complex arrays and its properties.
Definition: matrix.h:38
double real
the real part of a complex number
Definition: QGDTypes.h:40
void apply_kernel_to_state_vector_input(Matrix &u3_1qbit, Matrix &input, const bool &deriv, const int &target_qbit, const int &control_qbit, const int &matrix_size)
Call to apply a gate kernel on a state vector.
void apply_kernel_to_state_vector_input_parallel(Matrix &u3_1qbit, Matrix &input, const bool &deriv, const int &target_qbit, const int &control_qbit, const int &matrix_size)
Call to apply a gate kernel on a state vector.
double imag
the imaginary part of a complex number
Definition: QGDTypes.h:42