Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
SYC.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 #include "SYC.h"
24 
25 
26 
27 using namespace std;
28 
29 
34 
35  // A string labeling the gate operation
36  name = "SYC";
37 
38  // number of qubits spanning the matrix of the gate
39  qbit_num = -1;
40  // the size of the matrix
41  matrix_size = -1;
42  // A string describing the type of the gate
44  // The number of free parameters
45  parameter_num = 0;
46 
47  // The index of the qubit on which the gate acts (target_qbit >= 0)
48  target_qbit = -1;
49 
50  // The index of the qubit which acts as a control qubit (control_qbit >= 0) in controlled gate
51  control_qbit = -1;
52 
53 
54 }
55 
56 
63 SYC::SYC(int qbit_num_in, int target_qbit_in, int control_qbit_in) {
64 
65  // A string labeling the gate operation
66  name = "SYC";
67 
68  // number of qubits spanning the matrix of the gate
69  qbit_num = qbit_num_in;
70  // the size of the matrix
72  // A string describing the type of the gate
74  // The number of free parameters
75  parameter_num = 0;
76 
77  if (target_qbit_in >= qbit_num) {
78  std::stringstream sstream;
79  sstream << "The index of the target qubit is larger than the number of qubits" << std::endl;
80  print(sstream, 0);
81  throw "The index of the target qubit is larger than the number of qubits";
82  }
83 
84  // The index of the qubit on which the gate acts (target_qbit >= 0)
85  target_qbit = target_qbit_in;
86 
87 
88  if (control_qbit_in >= qbit_num) {
89  std::stringstream sstream;
90  sstream << "The index of the control qubit is larger than the number of qubits" << std::endl;
91  print(sstream, 0);
92  throw "The index of the control qubit is larger than the number of qubits";
93  }
94 
95  // The index of the qubit which acts as a control qubit (control_qbit >= 0) in controlled gate
96  control_qbit = control_qbit_in;
97 
98 }
99 
104 }
105 
110 Matrix
112 
113 
114  return get_matrix( false );
115 
116 }
117 
118 
124 Matrix
125 SYC::get_matrix( int parallel) {
126 
127  Matrix SYC_matrix = create_identity(matrix_size);
128  apply_to(SYC_matrix, parallel);
129 
130  return SYC_matrix;
131 
132 }
133 
134 
140 void
141 SYC::apply_to( Matrix& input, int parallel ) {
142 
143  if (input.rows != matrix_size ) {
144  std::string err("SYC::apply_to: Wrong input size in SYC gate apply.");
145  throw err;
146  }
147 
148  int index_step_target = Power_of_2(target_qbit);
149  int index_step_control = Power_of_2(control_qbit);
150 
151  int loopSize = index_step_target < index_step_control ? index_step_target : index_step_control;
153 
154  // |control, target>
155  int idx00 = 0;
156  int idx01 = index_step_target;
157  int idx10 = index_step_control;
158  int idx11 = index_step_target + index_step_control;
159 
160 /*
161 std::cout << "target qubit: " << target_qbit << std::endl;
162 std::cout << "control qubit: " << control_qbit << std::endl;
163 std::cout << "iterations: " << iterations << std::endl;
164 std::cout << "loopSize: " << loopSize << std::endl;
165 */
166  while ( idx11 < matrix_size ) {
167 
168  for ( int jdx=0; jdx<iterations; jdx++ ) {
169 
170  tbb::parallel_for(0, loopSize, 1, [&](int idx) {
171 
172  // |control, target>
173  //int idx00_loc = idx00 + idx;
174  int idx01_loc = idx01 + idx;
175  int idx10_loc = idx10 + idx;
176  int idx11_loc = idx11 + idx;
177 
178 
179  //int offset00 = idx00_loc*input.stride;
180  int offset01 = idx01_loc*input.stride;
181  int offset10 = idx10_loc*input.stride;
182  int offset11 = idx11_loc*input.stride;
183 
184 
185  for (int col_idx=0; col_idx<input.cols; col_idx++) {
186 
187  // transform elements 10 and 01
188  QGD_Complex16 element01 = input[ offset01 + col_idx ];
189  QGD_Complex16 element10 = input[ offset10 + col_idx ];
190  input[ offset01 + col_idx ].real = element10.imag;
191  input[ offset01 + col_idx ].imag = -element10.real;
192 
193  input[ offset10 + col_idx ].real = element01.imag;
194  input[ offset10 + col_idx ].imag = -element01.real;
195 
196 
197  // transform element 11
198  QGD_Complex16 element11 = input[ offset11 + col_idx ];
199  QGD_Complex16 factor;
200  factor.real = sqrt(3)/2;
201  factor.imag = -0.5;
202  input[ offset11 + col_idx ] = mult(element11, factor);
203  }
204 
205 
206 
207  //std::cout << current_idx_target << " " << current_idx_target_pair << std::endl;
208 
209 
210  });
211 
212 
213 
214  idx00 = idx00 + 2*loopSize;
215  idx01 = idx01 + 2*loopSize;
216  idx10 = idx10 + 2*loopSize;
217  idx11 = idx11 + 2*loopSize;
218 
219 
220  }
221 
222 
223  idx00 = idx00 + 2*loopSize*iterations;
224  idx01 = idx01 + 2*loopSize*iterations;
225  idx10 = idx10 + 2*loopSize*iterations;
226  idx11 = idx11 + 2*loopSize*iterations;
227 
228 
229  }
230 
231 
232 }
233 
234 
239 void
241 /*
242 Matrix SYC_gate = get_matrix();
243 SYC_gate.print_matrix();
244 Matrix res = dot(input, SYC_gate);
245 memcpy( input.get_data(), res.get_data(), res.size()*sizeof(QGD_Complex16) );
246 return;
247 */
248  int index_step_target = Power_of_2(target_qbit);
249  int index_step_control = Power_of_2(control_qbit);
250 
251  int loopSize = index_step_target < index_step_control ? index_step_target : index_step_control;
253 
254 
255 
256  // loop over the rows of the input matrix
257  tbb::parallel_for(0, matrix_size, 1, [&](int idx) {
258 
259  int offset = idx*input.stride;
260 
261  // |control, target>
262  int idx00 = 0;
263  int idx01 = index_step_target;
264  int idx10 = index_step_control;
265  int idx11 = index_step_target + index_step_control;
266 
267  while ( idx11 < matrix_size ) {
268 
269  for ( int jdx=0; jdx<iterations; jdx++ ) {
270 
271 
272  for ( int idx=0; idx<loopSize; idx++ ) {
273 
274  // |control, target>
275  //int idx00_loc = idx00 + idx;
276  int idx01_loc = idx01 + idx;
277  int idx10_loc = idx10 + idx;
278  int idx11_loc = idx11 + idx;
279 
280  // transform elements 10 and 01
281  QGD_Complex16 element01 = input[ offset + idx01_loc ];
282  QGD_Complex16 element10 = input[ offset + idx10_loc ];
283  input[ offset + idx01_loc ].real = element10.imag;
284  input[ offset + idx01_loc ].imag = -element10.real;
285 
286  input[ offset + idx10_loc ].real = element01.imag;
287  input[ offset + idx10_loc ].imag = -element01.real;
288 
289 
290  // transform element 11
291  QGD_Complex16 element11 = input[ offset + idx11_loc ];
292  QGD_Complex16 factor;
293  factor.real = sqrt(3)/2;
294  factor.imag = -0.5;
295  input[ offset + idx11_loc ] = mult(element11, factor);
296 
297  }
298 
299  idx00 = idx00 + 2*loopSize;
300  idx01 = idx01 + 2*loopSize;
301  idx10 = idx10 + 2*loopSize;
302  idx11 = idx11 + 2*loopSize;
303 
304 
305  }
306 
307  idx00 = idx00 + 2*loopSize*iterations;
308  idx01 = idx01 + 2*loopSize*iterations;
309  idx10 = idx10 + 2*loopSize*iterations;
310  idx11 = idx11 + 2*loopSize*iterations;
311 
312  }
313 
314  });
315 
316 
317 }
318 
319 
320 
326  // setting the number of qubits
327  Gate::set_qbit_num(qbit_num);
328 
329 }
330 
331 
332 
337 void SYC::reorder_qubits( vector<int> qbit_list) {
338 
339  Gate::reorder_qubits(qbit_list);
340 
341 }
342 
343 
344 
350 
351  SYC* ret = new SYC( qbit_num, target_qbit, control_qbit );
352 
353  ret->set_parameter_start_idx( get_parameter_start_idx() );
354  ret->set_parents( parents );
355  ret->set_children( children );
356 
357  return ret;
358 
359 }
360 
361 
362 
parameter_num
[set adaptive gate structure]
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
void set_children(std::vector< Gate *> &children_)
Call to set the children of the current gate.
Definition: Gate.cpp:802
virtual void set_qbit_num(int qbit_num_in)
Set the number of qubits spanning the matrix of the operation.
Definition: Gate.cpp:102
SYC()
Nullary constructor of the class.
Definition: SYC.cpp:33
SYC * clone()
Call to create a clone of the present class.
Definition: SYC.cpp:349
void apply_from_right(Matrix &input)
Call to apply the gate on the input array/matrix by input*SYC.
Definition: SYC.cpp:240
QGD_Complex16 mult(QGD_Complex16 &a, QGD_Complex16 &b)
Call to calculate the product of two complex scalars.
Definition: common.cpp:259
name
Definition: setup.py:33
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
void set_qbit_num(int qbit_num)
Call to set the number of qubits spanning the matrix of the operation.
Definition: SYC.cpp:325
void apply_to(Matrix &input, int parallel)
Call to apply the gate on the input array/matrix by SYC*input.
Definition: SYC.cpp:141
void set_parameter_start_idx(int start_idx)
Call to set the starting index of the parameters in the parameter array corresponding to the circuit ...
Definition: Gate.cpp:779
~SYC()
Destructor of the class.
Definition: SYC.cpp:103
def apply_to(self, parameters_mtx, unitary_mtx, parallel=1)
Definition: qgd_Circuit.py:302
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
void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the operation.
Definition: SYC.cpp:337
Class to store data of complex arrays and its properties.
Definition: matrix.h:38
Matrix get_matrix()
Call to retrieve the operation matrix.
Definition: SYC.cpp:111
Matrix create_identity(int matrix_size)
Call to create an identity matrix.
Definition: common.cpp:164
void set_parents(std::vector< Gate *> &parents_)
Call to set the parents of the current gate.
Definition: Gate.cpp:790
A class representing a SYC operation.
Definition: SYC.h:36
double real
the real part of a complex number
Definition: QGDTypes.h:40
virtual void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the operation.
Definition: Gate.cpp:339
double imag
the imaginary part of a complex number
Definition: QGDTypes.h:42
Header file for a class representing a Sycamore gate.