Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
CROT.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 "CROT.h"
26 
27 static double M_PIOver2 = M_PI/2;
28 
29 //static tbb::spin_mutex my_mutex;
34 
35  // A string describing the type of the gate
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 
43  target_qbit = -1;
44  // The index of the qubit which acts as a control qubit (control_qbit >= 0) in controlled gates
45  control_qbit = -1;
46  parameter_num = 0;
47 
48  name = "CROT";
49 
50 }
51 
52 
53 
62 CROT::CROT(int qbit_num_in, int target_qbit_in, int control_qbit_in) {
63 
64  name = "CROT";
65 
66  // number of qubits spanning the matrix of the gate
67  qbit_num = qbit_num_in;
68  // the size of the matrix
70  // A string describing the type of the gate
71 
72  // A string describing the type of the gate
74 
75 
76 
77 
78  if (control_qbit_in >= qbit_num) {
79  std::stringstream sstream;
80  sstream << "The index of the control qubit is larger than the number of qubits in CROT gate." << std::endl;
81  print(sstream, 0);
82  throw sstream.str();
83  }
84 
85  // The index of the qubit which acts as a control qubit (control_qbit >= 0) in controlled gates
86  control_qbit = control_qbit_in;
87 
88 
89  // The index of the qubit on which the gate acts (target_qbit >= 0)
90  target_qbit = target_qbit_in;
91 
92 
93  parameter_num=2;
94 
96 }
97 
102 
103 }
104 
105 
111 void
112 CROT::apply_to_list( Matrix_real& parameters_mtx, std::vector<Matrix>& input ) {
113 
114 
115  for ( std::vector<Matrix>::iterator it=input.begin(); it != input.end(); it++ ) {
116  apply_to( parameters_mtx, *it, 0);
117  }
118 
119 }
120 
127 void
128 CROT::apply_to_list( Matrix_real& parameters_mtx, std::vector<Matrix>& inputs, int parallel ) {
129 
130  int work_batch = 1;
131  if ( parallel == 0 ) {
132  work_batch = inputs.size();
133  }
134  else {
135  work_batch = 1;
136  }
137 
138 
139  tbb::parallel_for( tbb::blocked_range<int>(0,inputs.size(),work_batch), [&](tbb::blocked_range<int> r) {
140  for (int idx=r.begin(); idx<r.end(); ++idx) {
141 
142  Matrix* input = &inputs[idx];
143 
144  apply_to( parameters_mtx, *input, parallel );
145 
146  }
147 
148  });
149 
150 }
151 
158 void
159 CROT::apply_to( Matrix_real& parameters_mtx, Matrix& input, int parallel ) {
160 
161 
162  if (input.rows != matrix_size ) {
163  std::stringstream sstream;
164  sstream << "Wrong matrix size in CROT gate apply" << std::endl;
165  print(sstream, 0);
166  exit(-1);
167  }
168 
169 
170  double ThetaOver2, Phi;
171 
172 
173  ThetaOver2 = parameters_mtx[0];
174  Phi = parameters_mtx[1];
175 
176  if (input.cols==1){
177 
178  Matrix U_2qbit(4,4);
179  memset(U_2qbit.get_data(),0.0,(U_2qbit.size()*2)*sizeof(double));
180  U_2qbit[0].real = std::cos(ThetaOver2);
181  U_2qbit[2].real = std::sin(ThetaOver2)*std::sin(Phi);
182  U_2qbit[2].imag = std::sin(ThetaOver2)*std::cos(Phi);
183  U_2qbit[1*4+3].real = -1.*std::sin(-1.*ThetaOver2)*std::sin(Phi);
184  U_2qbit[1*4+3].imag = -1.*std::sin(-1.*ThetaOver2)*std::cos(Phi);
185  U_2qbit[1*4+1].real = std::cos(-1.*ThetaOver2);
186  U_2qbit[2*4+2].real = std::cos(ThetaOver2);
187  U_2qbit[2*4].real = -1.*std::sin(ThetaOver2)*std::sin(Phi);
188  U_2qbit[2*4].imag = std::sin(ThetaOver2)*std::cos(Phi);
189  U_2qbit[3*4+3].real = std::cos(-1.*ThetaOver2);
190  U_2qbit[3*4+1].real = std::sin(-1.*ThetaOver2)*std::sin(Phi);
191  U_2qbit[3*4+1].imag = -1.*std::sin(-1.*ThetaOver2)*std::cos(Phi);
192 
193  // apply the computing kernel on the matrix
194  std::vector<int> involved_qbits = {control_qbit,target_qbit};
195  if (parallel){
196  apply_large_kernel_to_input_AVX(U_2qbit,input,involved_qbits,input.size());
197  }
198  else{
199  apply_large_kernel_to_input(U_2qbit,input,involved_qbits,input.size());
200  }
201 
202  }
203 
204  else{
205 
206  Matrix U3_matrix = calc_one_qubit_u3(ThetaOver2, Phi-M_PIOver2, -1*Phi+M_PIOver2 );
207  Matrix U3_matrix2 = calc_one_qubit_u3(-1.*ThetaOver2, Phi-M_PIOver2, -1*Phi+M_PIOver2 );
208  if(parallel){
209  apply_crot_kernel_to_matrix_input_AVX_parallel(U3_matrix2,U3_matrix, input, target_qbit, control_qbit, input.rows);
210  }
211  else{
212  apply_crot_kernel_to_matrix_input_AVX(U3_matrix2,U3_matrix, input, target_qbit, control_qbit, input.rows);
213  }
214  }
215 
216 
217 
218 }
219 
220 
221 
227 void
229 
230 
231 
232 }
233 
234 
240 std::vector<Matrix>
241 CROT::apply_derivate_to( Matrix_real& parameters_mtx, Matrix& input, int parallel ) {
242 
243  if (input.rows != matrix_size ) {
244  std::stringstream sstream;
245  sstream << "Wrong matrix size in CROT gate apply" << std::endl;
246  print(sstream, 0);
247  exit(-1);
248  }
249 
250  std::vector<Matrix> ret;
251 
252  double ThetaOver2, Phi;
253 
254 
255  ThetaOver2 = parameters_mtx[0];
256 
257  Phi = parameters_mtx[1];
258 
259 
260 
261 
262 
263  // the resulting matrix
264 
265 
266  if (input.cols==1){
267 
268  double Theta0Over2_shifted = ThetaOver2 + M_PIOver2;
269  double Theta1Over2_shifted;
270 
271  Theta1Over2_shifted = -1.*Theta0Over2_shifted;
272 
273  double Phi0_shifted = Phi + M_PIOver2;
274  double Phi1_shifted = Phi + M_PIOver2;
275 
276  //Theta derivative
277  Matrix res_mtx = input.copy();
278  Matrix U_2qbit(4,4);
279  memset(U_2qbit.get_data(),0.0,(U_2qbit.size()*2)*sizeof(double));
280 
281  U_2qbit[0].real = std::cos(Theta0Over2_shifted);
282  U_2qbit[2].real = std::sin(Theta0Over2_shifted)*std::sin(Phi);
283  U_2qbit[2].imag = std::sin(Theta0Over2_shifted)*std::cos(Phi);
284 
285  U_2qbit[2*4+2].real = std::cos(Theta0Over2_shifted);
286  U_2qbit[2*4].real = -1.*std::sin(Theta0Over2_shifted)*std::sin(Phi);
287  U_2qbit[2*4].imag = std::sin(Theta0Over2_shifted)*std::cos(Phi);
288 
289  U_2qbit[1*4+3].real = -1.*std::sin(Theta1Over2_shifted)*std::sin(Phi);
290  U_2qbit[1*4+3].imag = -1.*std::sin(Theta1Over2_shifted)*std::cos(Phi);
291  U_2qbit[1*4+1].real = std::cos(Theta1Over2_shifted);
292 
293  U_2qbit[3*4+3].real = std::cos(Theta1Over2_shifted);
294  U_2qbit[3*4+1].real = std::sin(Theta1Over2_shifted)*std::sin(Phi);
295  U_2qbit[3*4+1].imag = -1.*std::sin(Theta1Over2_shifted)*std::cos(Phi);
296 
297 
298  std::vector<int> involved_qbits = {control_qbit,target_qbit};
299 
300  apply_large_kernel_to_input(U_2qbit,res_mtx,involved_qbits,res_mtx.size());
301  ret.push_back(res_mtx);
302 
303  //Phi derivative
304  Matrix res_mtx1 = input.copy();
305  memset(U_2qbit.get_data(),0.0,(U_2qbit.size()*2)*sizeof(double));
306 
307  U_2qbit[2].real = std::sin(ThetaOver2)*std::sin(Phi0_shifted);
308  U_2qbit[2].imag = std::sin(ThetaOver2)*std::cos(Phi0_shifted);
309 
310  U_2qbit[2*4].real = -1.*std::sin(ThetaOver2)*std::sin(Phi0_shifted);
311  U_2qbit[2*4].imag = std::sin(ThetaOver2)*std::cos(Phi0_shifted);
312 
313  U_2qbit[1*4+3].real = -1.*std::sin(-1.*ThetaOver2)*std::sin(Phi1_shifted);
314  U_2qbit[1*4+3].imag = -1.*std::sin(-1.*ThetaOver2)*std::cos(Phi1_shifted);
315 
316  U_2qbit[3*4+1].real = std::sin(-1.*ThetaOver2)*std::sin(Phi1_shifted);
317  U_2qbit[3*4+1].imag = -1.*std::sin(-1.*ThetaOver2)*std::cos(Phi1_shifted);
318 
319  apply_large_kernel_to_input(U_2qbit,res_mtx1,involved_qbits,res_mtx1.size());
320  ret.push_back(res_mtx1);
321 
322 
323  }
324  else{
325 
326  //Theta derivative
327  Matrix res_mtx = input.copy();
328  Matrix U3_matrix = calc_one_qubit_u3(ThetaOver2+M_PIOver2, Phi-M_PIOver2, -1*Phi+M_PIOver2 );
329  Matrix U3_matrix2 = calc_one_qubit_u3(-1.*(ThetaOver2+M_PIOver2), Phi-M_PIOver2, -1*Phi+M_PIOver2 );
330 
331  apply_crot_kernel_to_matrix_input(U3_matrix2, U3_matrix, res_mtx, target_qbit, control_qbit, res_mtx.rows);
332  ret.push_back(res_mtx);
334  Matrix res_mtx1 = input.copy();
335  U3_matrix = calc_one_qubit_u3(ThetaOver2, Phi, -1*Phi );
336  U3_matrix2 = calc_one_qubit_u3(-1.*ThetaOver2, Phi, -1*Phi );
337  U3_matrix[0].real = 0;
338  U3_matrix[0].imag = 0;
339  U3_matrix[3].real = 0;
340  U3_matrix[3].imag = 0;
341  U3_matrix2[0].real = 0;
342  U3_matrix2[0].imag = 0;
343  U3_matrix2[3].real = 0;
344  U3_matrix2[3].imag = 0;
345  apply_crot_kernel_to_matrix_input(U3_matrix2, U3_matrix, res_mtx1, target_qbit, control_qbit, res_mtx1.rows);
346  ret.push_back(res_mtx1);
347 
348  }
349 
350 
351  return ret;
352 
353 
354 }
355 
360 void CROT::set_qbit_num(int qbit_num_in) {
361 
362  // setting the number of qubits
363  Gate::set_qbit_num(qbit_num_in);
364 }
365 
366 
367 
372 void CROT::reorder_qubits( std::vector<int> qbit_list) {
373 
374  Gate::reorder_qubits(qbit_list);
375 
376 }
377 
378 
379 
385 
386  CROT* ret = new CROT(qbit_num, target_qbit, control_qbit);
387 
389  ret->set_parents( parents );
390  ret->set_children( children );
391 
392  return ret;
393 
394 }
395 
403 
404  if ( get_parameter_start_idx() + get_parameter_num() > parameters.size() ) {
405  std::string err("CROT::extract_parameters: Cant extract parameters, since the dinput arary has not enough elements.");
406  throw err;
407  }
408 
409  Matrix_real extracted_parameters(1,2);
410 
411  extracted_parameters[0] = std::fmod( 2*parameters[ get_parameter_start_idx() ], 4*M_PI);
412  extracted_parameters[1] = std::fmod( parameters[ get_parameter_start_idx() + 1 ], 2*M_PI);
413 
414  return extracted_parameters;
415 
416 }
std::vector< Gate * > parents
list of parent gates to be applied in the circuit prior to this current gate
Definition: Gate.h:96
virtual Matrix_real extract_parameters(Matrix_real &parameters)
Call to extract parameters from the parameter array corresponding to the circuit, in which the gate i...
Definition: CROT.cpp:402
void print(const std::stringstream &sstream, int verbose_level=1) const
Call to print output messages in the function of the verbosity level.
Definition: logging.cpp:55
virtual void apply_from_right(Matrix_real &parameters, Matrix &input)
Call to apply the gate on the input array/matrix by input*CROT.
Definition: CROT.cpp:228
int control_qbit
The index of the qubit which acts as a control qubit (control_qbit >= 0) in controlled operations...
Definition: Gate.h:88
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
Header file for a class representing a controlled rotation gate around the Y axis.
int target_qbit
The index of the qubit on which the operation acts (target_qbit >= 0)
Definition: Gate.h:86
void apply_large_kernel_to_input(Matrix &unitary, Matrix &input, std::vector< int > involved_qbits, const int &matrix_size)
void apply_crot_kernel_to_matrix_input(Matrix &u3_1qbit1, Matrix &u3_1qbit2, Matrix &input, const int &target_qbit, const int &control_qbit, const int &matrix_size)
Call to apply crot gate kernel on an input matrix.
int matrix_size
The size N of the NxN matrix associated with the operations.
Definition: Gate.h:90
scalar * get_data() const
Call to get the pointer to the stored data.
A class representing a CROT gate.
Definition: CROT.h:38
void apply_to_list(Matrix_real &parameters_mtx, std::vector< Matrix > &input)
Call to apply the gate on the input array/matrix by U3*input.
Definition: CROT.cpp:112
void apply_large_kernel_to_input_AVX(Matrix &unitary, Matrix &input, std::vector< int > involved_qbits, const int &matrix_size)
Call to apply kernel to apply multi qubit gate kernel on an input matrix.
virtual void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the gate.
Definition: CROT.cpp:372
gate_type type
The type of the operation (see enumeration gate_type)
Definition: Gate.h:84
int rows
The number of rows.
Definition: matrix_base.hpp:42
int cols
The number of columns.
Definition: matrix_base.hpp:44
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
int get_parameter_start_idx()
Call to get the starting index of the parameters in the parameter array corresponding to the circuit ...
Definition: Gate.cpp:814
virtual void apply_to(Matrix_real &parameters_mtx, Matrix &input, int parallel)
Call to apply the gate on the input array/matrix by CROT3*input.
Definition: CROT.cpp:159
virtual Matrix calc_one_qubit_u3()
Calculate the matrix of the constans gates.
Definition: Gate.cpp:750
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.
int get_parameter_num()
Call to get the number of free parameters.
Definition: Gate.cpp:486
void apply_crot_kernel_to_matrix_input_AVX_parallel(Matrix &u3_1qbit1, Matrix &u3_1qbit2, Matrix &input, const int &target_qbit, const int &control_qbit, const int &matrix_size)
Call to apply crot gate kernel on an input matrix using AVX and TBB.
static double M_PIOver2
Definition: CROT.cpp:27
std::string name
A string labeling the gate operation.
Definition: Gate.h:80
Matrix_real parameters
Definition: CROT.h:45
void apply_crot_kernel_to_matrix_input_AVX(Matrix &u3_1qbit1, Matrix &u3_1qbit2, Matrix &input, const int &target_qbit, const int &control_qbit, const int &matrix_size)
Call to apply crot gate kernel on an input matrix using AVX.
std::vector< Gate * > children
list of child gates to be applied after this current gate
Definition: Gate.h:98
int parameter_num
the number of free parameters of the operation
Definition: Gate.h:92
virtual void set_qbit_num(int qbit_num_in)
Call to set the number of qubits spanning the matrix of the gate.
Definition: CROT.cpp:360
virtual CROT * clone()
Call to create a clone of the present class.
Definition: CROT.cpp:384
CROT()
Nullary constructor of the class.
Definition: CROT.cpp:33
void set_parents(std::vector< Gate *> &parents_)
Call to set the parents of the current gate.
Definition: Gate.cpp:790
Matrix copy()
Call to create a copy of the matrix.
Definition: matrix.cpp:105
virtual ~CROT()
Destructor of the class.
Definition: CROT.cpp:101
int qbit_num
number of qubits spanning the matrix of the operation
Definition: Gate.h:82
virtual std::vector< Matrix > apply_derivate_to(Matrix_real &parameters_mtx, Matrix &input, int parallel)
Call to evaluate the derivate of the circuit on an inout with respect to all of the free parameters...
Definition: CROT.cpp:241
virtual void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the operation.
Definition: Gate.cpp:339
Class to store data of complex arrays and its properties.
Definition: matrix_real.h:39