Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
Gates_block.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 "CZ.h"
24 #include "CH.h"
25 #include "CNOT.h"
26 #include "U1.h"
27 #include "U2.h"
28 #include "U3.h"
29 #include "RX.h"
30 #include "RY.h"
31 #include "R.h"
32 #include "CRY.h"
33 #include "RZ.h"
34 #include "H.h"
35 #include "X.h"
36 #include "Y.h"
37 #include "Z.h"
38 #include "T.h"
39 #include "Tdg.h"
40 #include "SX.h"
41 #include "SYC.h"
42 #include "UN.h"
43 #include "ON.h"
44 #include "CROT.h"
45 #include "Adaptive.h"
46 #include "CZ_NU.h"
47 #include "Composite.h"
48 #include "Gates_block.h"
49 
51 
52 
54 
55 #ifdef USE_AVX
57 #endif
58 
59 
60 //static tbb::spin_mutex my_mutex;
65 
66  // A string labeling the gate operation
67  name = "Circuit";
68 
69  // A string describing the type of the operation
71  // number of operation layers
72  layer_num = 0;
73 }
74 
75 
76 
81 Gates_block::Gates_block(int qbit_num_in) : Gate(qbit_num_in) {
82 
83  // A string labeling the gate operation
84  name = "Circuit";
85 
86  // A string describing the type of the operation
88  // number of operation layers
89  layer_num = 0;
90 
91  fragmented = false;
92  fragmentation_type = -1;
93  max_fusion = -1;
94 
95 }
96 
97 
102 
103  release_gates();
104 
105 }
106 
110 void
112 
113  //free the alloctaed memory of the stored gates
114  for(std::vector<Gate*>::iterator it = gates.begin(); it != gates.end(); ++it) {
115 
116  Gate* gate = *it;
117  delete gate;
118 
119  }
120 
121  gates.clear();
122  layer_num = 0;
123  parameter_num = 0;
124 
125 }
126 
127 
131 void
133 
134  if ( idx>= (int)gates.size() ) return;
135 
136  // fist decrese the number of parameters
137  Gate* gate = gates[idx];
138  parameter_num -= gate->get_parameter_num();
139 
140  gates.erase( gates.begin() + idx );
141 
142  // TODO: develop a more efficient method for large circuits. Now it is updating the whole circuit
145 
146 
147 }
148 
154 Matrix
156 
157  return get_matrix( parameters, false );
158 
159 
160 }
161 
162 
163 
170 Matrix
172 
173  //The stringstream input to store the output messages.
174  std::stringstream sstream;
175 
176  // create matrix representation of the gate operations
177  Matrix block_mtx = create_identity(matrix_size);
178 
179  apply_to(parameters, block_mtx, parallel);
180 
181 #ifdef DEBUG
182  if (block_mtx.isnan()) {
183  std::stringstream sstream;
184  sstream << "Gates_block::get_matrix: block_mtx contains NaN." << std::endl;
185  print(sstream, 0);
186  }
187 #endif
188 
189  return block_mtx;
190 
191 
192 }
193 
194 
195 
201 void
202 Gates_block::apply_to_list( Matrix_real& parameters_mtx, std::vector<Matrix>& inputs, int parallel ) {
203 
204  int work_batch = 1;
205  if ( parallel == 0 ) {
206  work_batch = inputs.size();
207  }
208  else {
209  work_batch = 1;
210  }
211 
212 
213  tbb::parallel_for( tbb::blocked_range<int>(0,inputs.size(),work_batch), [&](tbb::blocked_range<int> r) {
214  for (int idx=r.begin(); idx<r.end(); ++idx) {
215 
216  Matrix* input = &inputs[idx];
217 
218  apply_to( parameters_mtx, *input, parallel );
219 
220  }
221 
222  });
223 
224 
225 }
226 
227 
234 void
235 Gates_block::apply_to( Matrix_real& parameters_mtx_in, Matrix& input, int parallel ) {
236 
237  std::vector<int> involved_qubits = get_involved_qubits();
238 
239  if (input.rows != matrix_size ) {
240  std::string err("Gates_block::apply_to: Wrong input size in Gates_block gate apply.");
241  throw err;
242  }
243 
244  // TODO: GATE fusion has not been adopted to reversed parameter ordering!!!!!!!!!!!!!!!!!!!
245  if(max_fusion !=-1 && ((qbit_num>max_fusion && input.cols == 1) && involved_qubits.size()>1)){
246 
247 
248  std::string error("Gates_block::apply_to: GATE fusion has not been adopted to reversed parameter ordering!!!!!!!!!!!!!!!!!!!");
249  throw error;
250 
251  double* parameters = parameters_mtx_in.get_data();
252 
253  if (fragmented==false){
255  };
256 
257  int outer_idx = gates.size()-1;
258  for (int block_idx=0; block_idx<involved_qbits.size(); block_idx++){
259 
260  if (block_type[block_idx] != 1){
261 
262  Gates_block gates_block_mini = Gates_block(block_type[block_idx]);
263  std::vector<int> qbits = involved_qbits[block_idx];
264 #ifdef _WIN32
265  int* indices = (int*)_malloca(qbit_num*sizeof(int));
266 #else
267  int indices[qbit_num];
268 #endif
269 
270  for (int jdx=0; jdx<(int)qbits.size(); jdx++){
271  indices[qbits[jdx]]=jdx;
272  }
273 
274  for (int idx=outer_idx; idx>=block_end[block_idx]; idx--){
275 
276  Gate* gate = gates[idx]->clone();
277  int trgt_qbit = gate->get_target_qbit();
278  int ctrl_qbit = gate->get_control_qbit();
279  int target_qubit_new = indices[trgt_qbit];
280  gate->set_target_qbit(target_qubit_new);
281 
282  int control_qubit_new = (ctrl_qbit==-1) ? -1:indices[ctrl_qbit];
283  gate->set_control_qbit(control_qubit_new);
284  gates_block_mini.add_gate(gate);
285  }
286 
287  Matrix Umtx_mini = create_identity(Power_of_2(block_type[block_idx]));
288  parameters = parameters - gates_block_mini.get_parameter_num();
289 
290  Matrix_real parameters_mtx(parameters, 1, gates_block_mini.get_parameter_num());
291  gates_block_mini.apply_to(parameters_mtx, Umtx_mini);
292 
293  outer_idx = block_end[block_idx]-1;
294 
295 #ifdef USE_AVX
296  apply_large_kernel_to_input_AVX(Umtx_mini, input, qbits, input.size() );
297 #else
298  apply_large_kernel_to_state_vector_input(Umtx_mini, input, qbits, input.size() );
299 #endif
300 
301 
302 
303  }
304  else{
305 
306  Gates_block gates_block_mini = Gates_block(qbit_num);
307  for (int idx=outer_idx;idx>=0;idx--){
308  Gate* gate = gates[idx]->clone();
309  gates_block_mini.add_gate(gate);
310  }
311  parameters = parameters - gates_block_mini.get_parameter_num();
312  Matrix_real parameters_mtx(parameters, 1, gates_block_mini.get_parameter_num());
313  gates_block_mini.apply_to(parameters_mtx, input);
314  }
315  }
316  }
317  else if ( involved_qubits.size() == 1 && gates.size() > 1 && qbit_num > 1 ) {
318  // merge successive single qubit gates
319 
320  Gates_block gates_block_mini = Gates_block(1);
321 
322  for (int idx=0; idx<gates.size(); idx++){
323 
324  Gate* gate = gates[idx]->clone();
325  gate->set_target_qbit(0);
326  gate->set_qbit_num(1);
327 
328  gates_block_mini.add_gate(gate);
329  }
330  // TODO check gates block
331  Matrix Umtx_mini = create_identity(2);
332 
333  Matrix_real parameters_mtx_loc(parameters_mtx_in.get_data() + gates[0]->get_parameter_start_idx(), 1, gates_block_mini.get_parameter_num());
334  gates_block_mini.apply_to(parameters_mtx_loc, Umtx_mini);
335 
336  custom_kernel_1qubit_gate merged_gate( qbit_num, involved_qubits[0], Umtx_mini );
337  merged_gate.apply_to( input );
338  }
339  else {
340 
341  // No gate fusion
342  for( int idx=0; idx<gates.size(); idx++) {
343 
344  Gate* operation = gates[idx];
345 
346  Matrix_real parameters_mtx_loc(parameters_mtx_in.get_data() + operation->get_parameter_start_idx(), 1, operation->get_parameter_num());
347 
348  if ( parameters_mtx_loc.size() == 0 && operation->get_type() != BLOCK_OPERATION ) {
349  operation->apply_to(input, parallel);
350  }
351  else {
352  operation->apply_to( parameters_mtx_loc, input, parallel );
353  }
354 #ifdef DEBUG
355  if (input.isnan()) {
356  std::stringstream sstream;
357  sstream << "Gates_block::apply_to: transformed matrix contains NaN." << std::endl;
358  print(sstream, 0);
359  }
360 #endif
361 
362 
363  }
364 
365  }
366 
367 }
368 
369 
370 
372 
379 bool is_qbit_present(std::vector<int> involved_qubits, int new_qbit, int num_of_qbits){
380 
381  bool contained=false;
382 
383  for (int idx=0; idx<num_of_qbits; idx++) {
384 
385  if(involved_qubits[idx] == new_qbit) {
386  contained=true;
387  }
388  }
389 
390  return contained;
391 
392 }
393 
394 
395 
396 
397 
399 
400  std::vector<int> qbits;
401  int num_of_qbits=0;
402  int max_fusion_temp = (fragmentation_type==-1) ? max_fusion:fragmentation_type;
403 
404  for (int idx = gates.size()-1; idx>=0; idx--){
405 
406  Gate* gate = gates[idx];
407  int target_new = gate -> get_target_qbit();
408  int control_new = gate->get_control_qbit();
409 
410  if (num_of_qbits == 0) {
411  qbits.push_back(target_new);
412  num_of_qbits++;
413 
414  }
415 
416  bool target_contained = is_qbit_present(qbits,target_new,num_of_qbits);
417  bool control_contained = (control_new==-1) ? true : is_qbit_present(qbits, control_new, num_of_qbits);
418 
419  if (num_of_qbits == max_fusion_temp && (target_contained == false || control_contained == false)){
420  int vidx = 1;
421 
422  while(vidx<num_of_qbits){
423  int jdx=vidx;
424 
425  while(jdx>0 && qbits[jdx-1]>qbits[jdx]){
426  int qbit_temp = qbits[jdx];
427  qbits[jdx] = qbits[jdx-1];
428  qbits[jdx-1] = qbit_temp;
429  jdx--;
430  }
431 
432  vidx++;
433  }
434 
435  involved_qbits.push_back(qbits);
436  block_end.push_back(idx+1);
437  block_type.push_back(num_of_qbits);
438  max_fusion_temp = max_fusion;
439  idx++;
440  qbits=std::vector<int>{};
441  num_of_qbits=0;
442  continue;
443  }
444 
445  if (num_of_qbits<max_fusion_temp && target_contained==false){
446  qbits.push_back(target_new);
447  num_of_qbits++;
448  }
449 
450  if (num_of_qbits<max_fusion_temp && control_contained==false){
451  qbits.push_back(control_new);
452  num_of_qbits++;
453  }
454 
455 
456  }
457 
458  if (num_of_qbits == 1){
459  involved_qbits.push_back(qbits);
460  block_type.push_back(1);
461  }
462 
463  else{
464  int vidx = 1;
465 
466  while(vidx<num_of_qbits){
467  int jdx=vidx;
468 
469  while(jdx>0 && qbits[jdx-1]>qbits[jdx]){
470  int qbit_temp = qbits[jdx];
471  qbits[jdx] = qbits[jdx-1];
472  qbits[jdx-1] = qbit_temp;
473  jdx--;
474  }
475 
476  vidx++;
477  }
478 
479  involved_qbits.push_back(qbits);
480  block_type.push_back(num_of_qbits);
481  block_end.push_back(0);
482  }
483 
484  block_end.push_back(0);
485  fragmented = true;
486 
487 }
488 
489 
490 
492  int parameter_idx = 0;
493  double *data = range_max.get_data();
494  for(int op_idx = 0; op_idx<gates.size(); op_idx++) {
495 
496  Gate* gate = gates[op_idx];
497  switch (gate->get_type()) {
498  case U1_OPERATION: {
499  data[parameter_idx] = 2 * M_PI; // Lambda (0 to 2pi)
500  parameter_idx = parameter_idx + 1;
501  break;
502  }
503  case U2_OPERATION: {
504  data[parameter_idx] = 2 * M_PI; // Phi (0 to 2pi)
505  data[parameter_idx+1] = 2 * M_PI; // Lambda (0 to 2pi)
506  parameter_idx = parameter_idx + 2;
507  break;
508  }
509  case U3_OPERATION: {
510  data[parameter_idx] = 4 * M_PI; // Theta (0 to 4pi)
511  data[parameter_idx+1] = 2 * M_PI; // Phi (0 to 2pi)
512  data[parameter_idx+2] = 2 * M_PI; // Lambda (0 to 2pi)
513  parameter_idx = parameter_idx + 3;
514  break;
515  }
516  case CROT_OPERATION: {
517  CROT* crot_gate = static_cast<CROT*>(gate);
518  if ((crot_gate->get_subtype() == CONTROL_R) || (crot_gate->get_subtype() == CONTROL_OPPOSITE)){
519  data[parameter_idx-2] = 4 * M_PI;
520  data[parameter_idx-1] = 2 * M_PI;
521  parameter_idx = parameter_idx - 2;
522  }
523  else if (crot_gate->get_subtype() == CONTROL_INDEPENDENT){
524  data[parameter_idx-4] = 4 * M_PI;
525  data[parameter_idx-3] = 2 * M_PI;
526  data[parameter_idx-2] = 4 * M_PI;
527  data[parameter_idx-1] = 2 * M_PI;
528  parameter_idx = parameter_idx - 4;
529  }
530  break;}
531  case R_OPERATION:{
532  data[parameter_idx-1] = 4*M_PI;
533  data[parameter_idx-2] = 2*M_PI;
534  parameter_idx = parameter_idx - 2;
535  break;}
536  case RX_OPERATION:
537  case RY_OPERATION:
538  case CRY_OPERATION:
539  case ADAPTIVE_OPERATION:
540  data[parameter_idx] = 4 * M_PI;
541  parameter_idx = parameter_idx + 1;
542  break;
543  case CZ_NU_OPERATION:
544  data[parameter_idx] = 2 * M_PI;
545  parameter_idx = parameter_idx + 1;
546  break;
547  case BLOCK_OPERATION: {
548  Gates_block* block_gate = static_cast<Gates_block*>(gate);
549  Matrix_real parameters_layer(range_max.get_data() + parameter_idx + gate->get_parameter_num(), 1, gate->get_parameter_num() );
550  block_gate->get_parameter_max( parameters_layer );
551  parameter_idx = parameter_idx + block_gate->get_parameter_num();
552  break; }
553  default:
554  for (int i = 0; i < gate->get_parameter_num(); i++)
555  data[parameter_idx+i] = 2 * M_PI;
556  parameter_idx = parameter_idx + gate->get_parameter_num();
557  }
558  }
559 }
560 
562 
563 
568 void
570 
571 
572  //The stringstream input to store the output messages.
573  std::stringstream sstream;
574 
575 
576 
577  // determine the number of parameters
578  int parameters_num_total = 0;
579  for (int idx=0; idx<gates.size(); idx++) {
580 
581  // The current gate
582  Gate* gate = gates[idx];
583  parameters_num_total = parameters_num_total + gate->get_parameter_num();
584 
585  }
586 
587 
588  double* parameters = parameters_mtx.get_data() + parameters_num_total;
589 
590 
591 
592  for( int idx=0; idx<(int)gates.size(); idx++) {
593 
594  Gate* operation = gates[idx];
595  Matrix_real parameters_mtx(parameters-operation->get_parameter_num(), 1, operation->get_parameter_num());
596 
597  switch (operation->get_type()) {
598  case CNOT_OPERATION: case CZ_OPERATION:
599  case CH_OPERATION: case SYC_OPERATION:
600  case X_OPERATION: case Y_OPERATION:
601  case Z_OPERATION: case SX_OPERATION:
602  case T_OPERATION: case TDG_OPERATION:
603  case GENERAL_OPERATION: case H_OPERATION:
604  operation->apply_from_right(input);
605  break;
606  case U1_OPERATION: {
607  U1* u1_operation = static_cast<U1*>(operation);
608  u1_operation->apply_from_right( parameters_mtx, input );
609  break;
610  }
611  case U2_OPERATION: {
612  U2* u2_operation = static_cast<U2*>(operation);
613  u2_operation->apply_from_right( parameters_mtx, input );
614  break;
615  }
616  case U3_OPERATION: {
617  U3* u3_operation = static_cast<U3*>(operation);
618  u3_operation->apply_from_right( parameters_mtx, input );
619  break;
620  }
621  case R_OPERATION: {
622  R* r_operation = static_cast<R*>(operation);
623  r_operation->apply_from_right( parameters_mtx, input );
624  break;
625  }
626  case RX_OPERATION: {
627  RX* rx_operation = static_cast<RX*>(operation);
628  rx_operation->apply_from_right( parameters_mtx, input );
629  break;
630  }
631  case RY_OPERATION: {
632  RY* ry_operation = static_cast<RY*>(operation);
633  ry_operation->apply_from_right( parameters_mtx, input );
634  break;
635  }
636  case CRY_OPERATION: {
637  CRY* cry_operation = static_cast<CRY*>(operation);
638  cry_operation->apply_from_right( parameters_mtx, input );
639  break;
640  }
641  case RZ_OPERATION: {
642  RZ* rz_operation = static_cast<RZ*>(operation);
643  rz_operation->apply_from_right( parameters_mtx, input );
644  break;
645  }
646  case UN_OPERATION: {
647  UN* un_operation = static_cast<UN*>(operation);
648  un_operation->apply_from_right( parameters_mtx, input );
649  break;
650  }
651  case ON_OPERATION: {
652  ON* on_operation = static_cast<ON*>(operation);
653  on_operation->apply_from_right( parameters_mtx, input );
654  break;
655  }
656  case BLOCK_OPERATION: {
657  Gates_block* block_operation = static_cast<Gates_block*>(operation);
658  block_operation->apply_from_right(parameters_mtx, input);
659  break;
660  }
661  case CZ_NU_OPERATION: {
662  CZ_NU* cz_nu_operation = static_cast<CZ_NU*>(operation);
663  cz_nu_operation->apply_from_right( parameters_mtx, input );
664  break;
665  }
666  case COMPOSITE_OPERATION: {
667  Composite* com_operation = static_cast<Composite*>(operation);
668  com_operation->apply_from_right( parameters_mtx, input );
669  break;
670  }
671  case ADAPTIVE_OPERATION: {
672  Adaptive* ad_operation = static_cast<Adaptive*>(operation);
673  ad_operation->apply_from_right( parameters_mtx, input );
674  break;
675  }
676  default:
677  std::string err("Gates_block::apply_from_right: unimplemented gate");
678  throw err;
679  }
680 
681  parameters = parameters - operation->get_parameter_num();
682 
683 #ifdef DEBUG
684  if (input.isnan()) {
685  std::stringstream sstream;
686  sstream << "Gates_block::apply_from_right: transformed matrix contains NaN." << std::endl;
687  print(sstream, 0);
688  }
689 #endif
690 
691 
692  }
693 
694 
695 }
696 
697 
704 std::vector<Matrix>
705 Gates_block::apply_derivate_to( Matrix_real& parameters_mtx_in, Matrix& input, int parallel ) {
706 
707  //The stringstream input to store the output messages.
708  std::stringstream sstream;
709 
710  std::vector<Matrix> grad(parameter_num, Matrix(0,0));
711 
712  int work_batch = 1;
713  if ( parallel == 0 ) {
714  work_batch = gates.size();
715  }
716  else {
717  work_batch = 1;
718  }
719 
720  // deriv_idx ... the index of the gate block for which the gradient is to be calculated
721 
722  tbb::parallel_for( tbb::blocked_range<int>(0,gates.size(),work_batch), [&](tbb::blocked_range<int> r) {
723  for (int deriv_idx=r.begin(); deriv_idx<r.end(); ++deriv_idx) {
724 
725  //for (int deriv_idx=0; deriv_idx<gates.size(); ++deriv_idx) {
726 
727 
728  Gate* gate_deriv = gates[deriv_idx];
729 
730  // for constant gate no gardient component is calculated
731  if ( gate_deriv->get_parameter_num() == 0 ) {
732  continue;
733  }
734 
735  int deriv_parameter_idx = gate_deriv->get_parameter_start_idx();
736 
737 
738 
739  Matrix&& input_loc = input.copy();
740 
741  std::vector<Matrix> grad_loc;
742 
743  for( int idx=0; idx<gates.size(); idx++) {
744 
745  Gate* operation = gates[idx];
746 
747 
748  Matrix_real parameters_mtx(parameters_mtx_in.get_data() + operation->get_parameter_start_idx(), 1, operation->get_parameter_num());
749 
750  switch (operation->get_type()) {
751  case UN_OPERATION:
752  case ON_OPERATION:
753  case SYC_OPERATION:
754  case COMPOSITE_OPERATION: {
755  int gate_type = (int)operation->get_type();
756  std::string err( "Gates_block::apply_derivate_to: Given operation not supported in gardient calculation");
757  throw( err );
758  break;
759  }
760  default :
761 
762  if ( operation->get_parameter_num() == 0 ) {
763 
764  if( idx < deriv_idx ) {
765  operation->apply_to( input_loc, parallel );
766  }
767  else {
768  operation->apply_to_list(grad_loc, parallel );
769  }
770 
771  }
772  else {
773  // Gates such as U1, U2, and U3 fall here.
774  if( idx < deriv_idx ) {
775  operation->apply_to( parameters_mtx, input_loc, parallel );
776  }
777  else if ( idx == deriv_idx ) {
778  grad_loc = operation->apply_derivate_to( parameters_mtx, input_loc, parallel );
779  }
780  else {
781  operation->apply_to_list(parameters_mtx, grad_loc, parallel );
782  }
783 
784  }
785 
786  }
787  }
788 
789 
790  for ( int idx = 0; idx<(int)grad_loc.size(); idx++ ) {
791  grad[deriv_parameter_idx+idx] = grad_loc[idx];
792  }
793 
794 
795  } // tbb range end
796 
797  });
798 
799 
800  return grad;
801 
802 }
803 
809 
810  // create the operation
811  Gate* operation = static_cast<Gate*>(new U1( qbit_num, target_qbit ));
812 
813  // adding the operation to the end of the list of gates
814  add_gate( operation );
815 }
816 
822 
823  // create the operation
824  Gate* gate = static_cast<Gate*>(new U1( qbit_num, target_qbit ));
825 
826  // adding the operation to the front of the list of gates
827  add_gate_to_front( gate );
828 }
829 
835 
836  // create the operation
837  Gate* operation = static_cast<Gate*>(new U2( qbit_num, target_qbit ));
838 
839  // adding the operation to the end of the list of gates
840  add_gate( operation );
841 }
842 
848 
849  // create the operation
850  Gate* gate = static_cast<Gate*>(new U2( qbit_num, target_qbit ));
851 
852  // adding the operation to the front of the list of gates
853  add_gate_to_front( gate );
854 }
855 
861 
862  // create the operation
863  Gate* operation = static_cast<Gate*>(new U3( qbit_num, target_qbit ));
864 
865  // adding the operation to the end of the list of gates
866  add_gate( operation );
867 }
868 
874 
875  // create the operation
876  Gate* gate = static_cast<Gate*>(new U3( qbit_num, target_qbit ));
877 
878  // adding the operation to the front of the list of gates
879  add_gate_to_front( gate );
880 
881 }
882 
888 
889  // create the operation
890  Gate* operation = static_cast<Gate*>(new RX( qbit_num, target_qbit));
891 
892  // adding the operation to the end of the list of gates
893  add_gate( operation );
894 }
895 
901 
902  // create the operation
903  Gate* gate = static_cast<Gate*>(new RX( qbit_num, target_qbit ));
904 
905  // adding the operation to the front of the list of gates
906  add_gate_to_front( gate );
907 
908 }
909 
915 
916  // create the operation
917  Gate* operation = static_cast<Gate*>(new R( qbit_num, target_qbit));
918 
919  // adding the operation to the end of the list of gates
920  add_gate( operation );
921 }
922 
928 
929  // create the operation
930  Gate* gate = static_cast<Gate*>(new R( qbit_num, target_qbit ));
931 
932  // adding the operation to the front of the list of gates
933  add_gate_to_front( gate );
934 
935 }
936 
937 
943 
944  // create the operation
945  Gate* operation = static_cast<Gate*>(new RY( qbit_num, target_qbit));
946 
947  // adding the operation to the end of the list of gates
948  add_gate( operation );
949 }
950 
951 
957 
958  // create the operation
959  Gate* gate = static_cast<Gate*>(new RY( qbit_num, target_qbit ));
960 
961  // adding the operation to the front of the list of gates
962  add_gate_to_front( gate );
963 
964 }
965 
966 
967 
968 
975 
976  // create the operation
977  Gate* operation = static_cast<Gate*>(new CRY( qbit_num, target_qbit, control_qbit));
978 
979  // adding the operation to the end of the list of gates
980  add_gate( operation );
981 }
982 
983 
984 
991 
992  // create the operation
993  Gate* gate = static_cast<Gate*>(new CRY( qbit_num, target_qbit, control_qbit ));
994 
995  // adding the operation to the front of the list of gates
996  add_gate_to_front( gate );
997 
998 }
999 
1000 
1007 
1008  // create the operation
1009  Gate* operation = static_cast<Gate*>(new CROT( qbit_num, target_qbit, control_qbit, subtype_in));
1010 
1011  // adding the operation to the end of the list of gates
1012  add_gate( operation );
1013 }
1014 
1015 
1016 
1023 
1024  // create the operation
1025  Gate* gate = static_cast<Gate*>(new CROT( qbit_num, target_qbit, control_qbit,subtype_in ));
1026 
1027  // adding the operation to the front of the list of gates
1028  add_gate_to_front( gate );
1029 
1030 }
1031 
1038 
1039  // create the operation
1040  Gate* operation = static_cast<Gate*>(new CZ_NU( qbit_num, target_qbit, control_qbit));
1041 
1042  // adding the operation to the end of the list of gates
1043  add_gate( operation );
1044 }
1045 
1046 
1047 
1054 
1055  // create the operation
1056  Gate* gate = static_cast<Gate*>(new CZ_NU( qbit_num, target_qbit, control_qbit ));
1057 
1058  // adding the operation to the front of the list of gates
1059  add_gate_to_front( gate );
1060 
1061 }
1062 
1063 
1064 
1070 
1071  // create the operation
1072  Gate* operation = static_cast<Gate*>(new RZ( qbit_num, target_qbit));
1073 
1074  // adding the operation to the end of the list of gates
1075  add_gate( operation );
1076 }
1077 
1083 
1084  // create the operation
1085  Gate* gate = static_cast<Gate*>(new RZ( qbit_num, target_qbit ));
1086 
1087  // adding the operation to the front of the list of gates
1088  add_gate_to_front( gate );
1089 
1090 }
1091 
1092 
1093 
1094 
1101 
1102  // new cnot operation
1103  Gate* gate = static_cast<Gate*>(new CNOT(qbit_num, target_qbit, control_qbit ));
1104 
1105  // append the operation to the list
1106  add_gate(gate);
1107 
1108 }
1109 
1110 
1111 
1118 
1119  // new cnot operation
1120  Gate* gate = static_cast<Gate*>(new CNOT(qbit_num, target_qbit, control_qbit ));
1121 
1122  // put the operation to tghe front of the list
1123  add_gate_to_front(gate);
1124 
1125 }
1126 
1127 
1128 
1129 
1136 
1137  // new cz operation
1138  Gate* gate = static_cast<Gate*>(new CZ(qbit_num, target_qbit, control_qbit ));
1139 
1140  // append the operation to the list
1141  add_gate(gate);
1142 
1143 }
1144 
1145 
1146 
1153 
1154  // new cz operation
1155  Gate* gate = static_cast<Gate*>(new CZ(qbit_num, target_qbit, control_qbit ));
1156 
1157  // put the operation to tghe front of the list
1158  add_gate_to_front(gate);
1159 
1160 }
1161 
1167 
1168  // create the operation
1169  Gate* operation = static_cast<Gate*>(new H( qbit_num, target_qbit));
1170 
1171  // adding the operation to the end of the list of gates
1172  add_gate( operation );
1173 }
1174 
1180 
1181  // create the operation
1182  Gate* gate = static_cast<Gate*>(new H( qbit_num, target_qbit ));
1183 
1184  // adding the operation to the front of the list of gates
1185  add_gate_to_front( gate );
1186 
1187 }
1188 
1189 
1190 
1191 
1192 
1198 
1199  // create the operation
1200  Gate* operation = static_cast<Gate*>(new X( qbit_num, target_qbit));
1201 
1202  // adding the operation to the end of the list of gates
1203  add_gate( operation );
1204 }
1205 
1211 
1212  // create the operation
1213  Gate* gate = static_cast<Gate*>(new X( qbit_num, target_qbit ));
1214 
1215  // adding the operation to the front of the list of gates
1216  add_gate_to_front( gate );
1217 
1218 }
1219 
1220 
1221 
1227 
1228  // create the operation
1229  Gate* operation = static_cast<Gate*>(new Y( qbit_num, target_qbit));
1230 
1231  // adding the operation to the end of the list of gates
1232  add_gate( operation );
1233 }
1234 
1240 
1241  // create the operation
1242  Gate* gate = static_cast<Gate*>(new Y( qbit_num, target_qbit ));
1243 
1244  // adding the operation to the front of the list of gates
1245  add_gate_to_front( gate );
1246 
1247 }
1248 
1249 
1250 
1256 
1257  // create the operation
1258  Gate* operation = static_cast<Gate*>(new Z( qbit_num, target_qbit));
1259 
1260  // adding the operation to the end of the list of gates
1261  add_gate( operation );
1262 }
1263 
1269 
1270  // create the operation
1271  Gate* gate = static_cast<Gate*>(new Z( qbit_num, target_qbit ));
1272 
1273  // adding the operation to the front of the list of gates
1274  add_gate_to_front( gate );
1275 
1276 }
1277 
1278 
1279 
1280 
1286 
1287  // create the operation
1288  Gate* operation = static_cast<Gate*>(new T( qbit_num, target_qbit));
1289 
1290  // adding the operation to the end of the list of gates
1291  add_gate( operation );
1292 }
1293 
1299 
1300  // create the operation
1301  Gate* gate = static_cast<Gate*>(new T( qbit_num, target_qbit ));
1302 
1303  // adding the operation to the front of the list of gates
1304  add_gate_to_front( gate );
1305 
1306 }
1307 
1308 
1309 
1310 
1316 
1317  // create the operation
1318  Gate* operation = static_cast<Gate*>(new Tdg( qbit_num, target_qbit));
1319 
1320  // adding the operation to the end of the list of gates
1321  add_gate( operation );
1322 }
1323 
1329 
1330  // create the operation
1331  Gate* gate = static_cast<Gate*>(new Tdg( qbit_num, target_qbit ));
1332 
1333  // adding the operation to the front of the list of gates
1334  add_gate_to_front( gate );
1335 
1336 }
1337 
1338 
1339 
1340 
1341 
1342 
1348 
1349  // create the operation
1350  Gate* operation = static_cast<Gate*>(new SX( qbit_num, target_qbit));
1351 
1352  // adding the operation to the end of the list of gates
1353  add_gate( operation );
1354 }
1355 
1361 
1362  // create the operation
1363  Gate* gate = static_cast<Gate*>(new SX( qbit_num, target_qbit ));
1364 
1365  // adding the operation to the front of the list of gates
1366  add_gate_to_front( gate );
1367 
1368 }
1369 
1370 
1371 
1372 
1373 
1380 
1381  // new cz operation
1382  Gate* gate = static_cast<Gate*>(new SYC(qbit_num, target_qbit, control_qbit ));
1383 
1384  // append the operation to the list
1385  add_gate(gate);
1386 
1387 }
1388 
1389 
1390 
1397 
1398  // new cz operation
1399  Gate* gate = static_cast<Gate*>(new SYC(qbit_num, target_qbit, control_qbit ));
1400 
1401  // put the operation to tghe front of the list
1402  add_gate_to_front(gate);
1403 
1404 }
1405 
1406 
1407 
1408 
1415 
1416  // new cz operation
1417  Gate* gate = static_cast<Gate*>(new CH(qbit_num, target_qbit, control_qbit ));
1418 
1419  // append the operation to the list
1420  add_gate(gate);
1421 
1422 }
1423 
1424 
1425 
1432 
1433  // new cz operation
1434  Gate* gate = static_cast<Gate*>(new CH(qbit_num, target_qbit, control_qbit ));
1435 
1436  // put the operation to tghe front of the list
1437  add_gate_to_front(gate);
1438 
1439 }
1440 
1445 void Gates_block::add_gates( std::vector<Gate*> gates_in) {
1446 
1447  for(std::vector<Gate*>::iterator it = gates_in.begin(); it != gates_in.end(); ++it) {
1448  add_gate( *it );
1449  }
1450 
1451 }
1452 
1453 
1458 void Gates_block::add_gates_to_front( std::vector<Gate*> gates_in) {
1459 
1460  // adding gates in reversed order!!
1461  for(std::vector<Gate*>::iterator it = gates_in.end(); it != gates_in.begin(); --it) {
1462  add_gate_to_front( *it );
1463  }
1464 
1465 }
1466 
1467 
1468 
1473 
1474  // create the operation
1475  Gate* operation = static_cast<Gate*>(new UN( qbit_num ));
1476 
1477  // adding the operation to the end of the list of gates
1478  add_gate( operation );
1479 }
1480 
1485 
1486  // create the operation
1487  Gate* gate = static_cast<Gate*>(new UN( qbit_num ));
1488 
1489  // adding the operation to the front of the list of gates
1490  add_gate_to_front( gate );
1491 
1492 }
1493 
1494 
1499 
1500  // create the operation
1501  Gate* operation = static_cast<Gate*>(new ON( qbit_num ));
1502 
1503  // adding the operation to the end of the list of gates
1504  add_gate( operation );
1505 }
1506 
1511 
1512  // create the operation
1513  Gate* gate = static_cast<Gate*>(new ON( qbit_num ));
1514 
1515  // adding the operation to the front of the list of gates
1516  add_gate_to_front( gate );
1517 
1518 }
1519 
1520 
1525 
1526  // create the operation
1527  Gate* operation = static_cast<Gate*>(new Composite( qbit_num ));
1528 
1529  // adding the operation to the end of the list of gates
1530  add_gate( operation );
1531 }
1532 
1537 
1538  // create the operation
1539  Gate* gate = static_cast<Gate*>(new Composite( qbit_num ));
1540 
1541  // adding the operation to the front of the list of gates
1542  add_gate_to_front( gate );
1543 
1544 }
1545 
1546 
1547 
1554 
1555  // create the operation
1556  Gate* operation = static_cast<Gate*>(new Adaptive( qbit_num, target_qbit, control_qbit));
1557 
1558  // adding the operation to the end of the list of gates
1559  add_gate( operation );
1560 }
1561 
1562 
1569 
1570  // create the operation
1571  Gate* gate = static_cast<Gate*>(new Adaptive( qbit_num, target_qbit, control_qbit ));
1572 
1573  // adding the operation to the front of the list of gates
1574  add_gate_to_front( gate );
1575 
1576 }
1577 
1578 
1579 
1585 
1586  //set the number of qubit in the gate
1587  gate->set_qbit_num( qbit_num );
1588 
1589  // determine the parents of the gate
1590  determine_parents( gate );
1591 
1592  // append the gate to the list
1593  gates.push_back(gate);
1594 
1595  // set the parameter starting index in the parameters array used to execute the circuit.
1597 
1598  // increase the number of parameters by the number of parameters
1600 
1601  // increase the number of layers if necessary
1602  if (gate->get_type() == BLOCK_OPERATION) {
1603  layer_num = layer_num + 1;
1604  }
1605 
1606 }
1607 
1608 
1609 
1615 
1616 
1617  // set the number of qubit in the gate
1618  gate->set_qbit_num( qbit_num );
1619 
1620  // determine the parents of the gate
1621  determine_children( gate );
1622 
1623  gates.insert( gates.begin(), gate);
1624 
1625  // increase the number of U3 gate parameters by the number of parameters
1627 
1628  // increase the number of layers if necessary
1629  if (gate->get_type() == BLOCK_OPERATION) {
1630  layer_num = layer_num + 1;
1631  }
1632 
1633  // TODO: develop a more efficient method for large circuits. Now it is updating the whole circuit
1636 
1637 }
1638 
1639 
1640 
1646 void
1647 Gates_block::insert_gate( Gate* gate, int idx ) {
1648 
1649 
1650  // set the number of qubit in the gate
1651  gate->set_qbit_num( qbit_num );
1652 
1653  gates.insert( gates.begin()+idx, gate);
1654 
1655  // increase the number of U3 gate parameters by the number of parameters
1657 
1658  // increase the number of layers if necessary
1659  if (gate->get_type() == BLOCK_OPERATION) {
1660  layer_num = layer_num + 1;
1661  }
1662 
1663  // TODO: develop a more efficient method for large circuits. Now it is updating the whole circuit
1666 
1667 
1668 }
1669 
1670 
1675 void Gates_block::add_gate_nums( std::map<std::string, int>& gate_nums ) {
1676 
1677  for(std::vector<Gate*>::iterator it = gates.begin(); it != gates.end(); ++it) {
1678 
1679  // get the specific gate in the circuit (might be a gate or another subcircuit)
1680  Gate* gate = *it;
1681 
1682 
1683  if (gate->get_type() == BLOCK_OPERATION) {
1684  Gates_block* circuit = static_cast<Gates_block*>(gate);
1685  circuit->add_gate_nums( gate_nums );
1686  }
1687  else {
1688  std::string gate_name = gate->get_name();
1689 
1690  if( gate_nums.find(gate_name) == gate_nums.end() ) {
1691  gate_nums[ gate_name ] = 1;
1692  }
1693  else {
1694  gate_nums[ gate_name ] = gate_nums[ gate_name ] + 1;
1695  }
1696  }
1697 
1698  }
1699 
1700 }
1701 
1702 
1707 std::map<std::string, int> Gates_block::get_gate_nums() {
1708 
1709  std::map<std::string, int> gate_nums;
1710 
1711  add_gate_nums( gate_nums );
1712 
1713  return gate_nums;
1714 
1715 }
1716 
1717 
1723  return parameter_num;
1724 }
1725 
1726 
1727 
1728 
1734  return gates.size();
1735 }
1736 
1737 
1743 void Gates_block::list_gates( const Matrix_real &parameters, int start_index ) {
1744 
1745 
1746  //The stringstream input to store the output messages.
1747  std::stringstream sstream;
1748  sstream << std::endl << "The gates in the list of gates:" << std::endl;
1749  print(sstream, 1);
1750 
1751  int gate_idx = start_index;
1752  int parameter_idx = 0;
1753  double *parameters_data = parameters.get_data();
1754  //const_cast <Matrix_real&>(parameters);
1755 
1756 
1757  for(int op_idx = 0; op_idx<gates.size(); op_idx++) {
1758 
1759  Gate* gate = gates[op_idx];
1760 
1761  if (gate->get_type() == CNOT_OPERATION) {
1762  CNOT* cnot_gate = static_cast<CNOT*>(gate);
1763  std::stringstream sstream;
1764  sstream << gate_idx << "th gate: CNOT with control qubit: " << cnot_gate->get_control_qbit() << " and target qubit: " << cnot_gate->get_target_qbit() << std::endl;
1765  print(sstream, 1);
1766  gate_idx = gate_idx + 1;
1767  }
1768  else if (gate->get_type() == CROT_OPERATION) {
1769  CROT* crot_gate = static_cast<CROT*>(gate);
1770  std::stringstream sstream;
1771  if ((crot_gate->get_subtype() == CONTROL_R)){
1772  double theta0,phi0;
1773  theta0 = std::fmod( 2*parameters_data[parameter_idx-2], 4*M_PI);
1774  phi0 = std::fmod( parameters_data[parameter_idx-1], 2*M_PI);
1775  parameter_idx = parameter_idx - 2;
1776  sstream << gate_idx << "th gate: CROT_CONTROL_R with control qubit: " << crot_gate->get_control_qbit() << " and target qubit: " << crot_gate->get_target_qbit()<< " and parameters theta=" << theta0 <<" and phi="<< phi0 << std::endl;
1777  print(sstream, 1);
1778  }
1779  else if ((crot_gate->get_subtype() == CONTROL_OPPOSITE)){
1780  double theta0,phi0;
1781  theta0 = std::fmod( 2*parameters_data[parameter_idx-2], 4*M_PI);
1782  phi0 = std::fmod( parameters_data[parameter_idx-1], 2*M_PI);
1783  parameter_idx = parameter_idx - 2;
1784  sstream << gate_idx << "th gate: CROT_OPPOSITE with control qubit: " << crot_gate->get_control_qbit() << " and target qubit: " << crot_gate->get_target_qbit()<< " and parameters theta=" << theta0 <<" and phi="<< phi0 << std::endl;
1785  print(sstream, 1);
1786  }
1787  else if (crot_gate->get_subtype() == CONTROL_INDEPENDENT){
1788  double theta0,phi0,theta1,phi1;
1789  theta0 = std::fmod( 2*parameters_data[parameter_idx-4], 4*M_PI);
1790  phi0 = std::fmod( parameters_data[parameter_idx-3], 2*M_PI);
1791  theta1 = std::fmod( 2*parameters_data[parameter_idx-2], 4*M_PI);
1792  phi1 = std::fmod( parameters_data[parameter_idx-1], 2*M_PI);
1793  sstream << gate_idx << "th gate: CROT_INDEPENDENT with control qubit: " << crot_gate->get_control_qbit() << " and target qubit: " << crot_gate->get_target_qbit()<< " and parameters theta0=" << theta0 <<", phi0="<< phi0 << ", theta1=" << theta1 <<" and phi1="<< phi1 << std::endl;
1794  print(sstream, 1);
1795  parameter_idx = parameter_idx - 4;
1796  }
1797  gate_idx = gate_idx + 1;
1798  }
1799  else if (gate->get_type() == CZ_OPERATION) {
1800  CZ* cz_gate = static_cast<CZ*>(gate);
1801  std::stringstream sstream;
1802  sstream << gate_idx << "th gate: CZ with control qubit: " << cz_gate->get_control_qbit() << " and target qubit: " << cz_gate->get_target_qbit() << std::endl;
1803  print(sstream, 1);
1804  gate_idx = gate_idx + 1;
1805  }
1806  else if (gate->get_type() == CH_OPERATION) {
1807  CH* ch_gate = static_cast<CH*>(gate);
1808  std::stringstream sstream;
1809  sstream << gate_idx << "th gate: CH with control qubit: " << ch_gate->get_control_qbit() << " and target qubit: " << ch_gate->get_target_qbit() << std::endl;
1810  print(sstream, 1);
1811  gate_idx = gate_idx + 1;
1812  }
1813  else if (gate->get_type() == SYC_OPERATION) {
1814  SYC* syc_gate = static_cast<SYC*>(gate);
1815  std::stringstream sstream;
1816  sstream << gate_idx << "th gate: Sycamore gate with control qubit: " << syc_gate->get_control_qbit() << " and target qubit: " << syc_gate->get_target_qbit() << std::endl;
1817  print(sstream, 1);
1818  gate_idx = gate_idx + 1;
1819  }
1820  else if (gate->get_type() == U1_OPERATION) {
1821  U1* u1_gate = static_cast<U1*>(gate);
1822  double lambda = std::fmod(parameters_data[parameter_idx], 2*M_PI);
1823  parameter_idx = parameter_idx + 1;
1824  std::stringstream sstream;
1825  sstream << gate_idx << "th gate: U1 on target qubit: " << u1_gate->get_target_qbit() << " with parameter lambda = " << lambda << std::endl;
1826  print(sstream, 1);
1827  gate_idx = gate_idx + 1;
1828  }
1829  else if (gate->get_type() == U2_OPERATION) {
1830  U2* u2_gate = static_cast<U2*>(gate);
1831  double phi = std::fmod(parameters_data[parameter_idx], 2*M_PI);
1832  double lambda = std::fmod(parameters_data[parameter_idx+1], 2*M_PI);
1833  parameter_idx = parameter_idx + 2;
1834  std::stringstream sstream;
1835  sstream << gate_idx << "th gate: U2 on target qubit: " << u2_gate->get_target_qbit() << " with parameters phi = " << phi << " and lambda = " << lambda << std::endl;
1836  print(sstream, 1);
1837  gate_idx = gate_idx + 1;
1838  }
1839  else if (gate->get_type() == U3_OPERATION) {
1840  U3* u3_gate = static_cast<U3*>(gate);
1841  double theta = std::fmod(parameters_data[parameter_idx], 4*M_PI);
1842  double phi = std::fmod(parameters_data[parameter_idx+1], 2*M_PI);
1843  double lambda = std::fmod(parameters_data[parameter_idx+2], 2*M_PI);
1844  parameter_idx = parameter_idx + 3;
1845  std::stringstream sstream;
1846  sstream << gate_idx << "th gate: U3 on target qubit: " << u3_gate->get_target_qbit() << " with parameters theta = " << theta << ", phi = " << phi << " and lambda = " << lambda << std::endl;
1847  print(sstream, 1);
1848  gate_idx = gate_idx + 1;
1849  }
1850  else if (gate->get_type() == R_OPERATION) {
1851  // definig the rotation parameter
1852  double vartheta,varphi;
1853  // get the inverse parameters of the U3 rotation
1854  R* r_gate = static_cast<R*>(gate);
1855  vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*M_PI);
1856  varphi = std::fmod( parameters_data[parameter_idx+1], 2*M_PI);
1857  parameter_idx = parameter_idx + 2;
1858 
1859  std::stringstream sstream;
1860  sstream << gate_idx << "th gate: R on target qubit: " << r_gate->get_target_qbit() << " and with parameters theta = " << vartheta << " and phi:" << varphi << std::endl;
1861  print(sstream, 1);
1862  gate_idx = gate_idx + 1;
1863  }
1864  else if (gate->get_type() == RX_OPERATION) {
1865  // definig the rotation parameter
1866  double vartheta;
1867  // get the inverse parameters of the U3 rotation
1868  RX* rx_gate = static_cast<RX*>(gate);
1869  vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*M_PI);
1870  parameter_idx = parameter_idx + 1;
1871 
1872  std::stringstream sstream;
1873  sstream << gate_idx << "th gate: RX on target qubit: " << rx_gate->get_target_qbit() << " and with parameters theta = " << vartheta << std::endl;
1874  print(sstream, 1);
1875  gate_idx = gate_idx + 1;
1876  }
1877  else if (gate->get_type() == RY_OPERATION) {
1878  // definig the rotation parameter
1879  double vartheta;
1880  // get the inverse parameters of the U3 rotation
1881  RY* ry_gate = static_cast<RY*>(gate);
1882  vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*M_PI);
1883  parameter_idx = parameter_idx + 1;
1884 
1885  std::stringstream sstream;
1886  sstream << gate_idx << "th gate: RY on target qubit: " << ry_gate->get_target_qbit() << " and with parameters theta = " << vartheta << std::endl;
1887  print(sstream, 1);
1888  gate_idx = gate_idx + 1;
1889  }
1890  else if (gate->get_type() == CRY_OPERATION) {
1891  // definig the rotation parameter
1892  double vartheta;
1893  // get the inverse parameters of the U3 rotation
1894  CRY* cry_gate = static_cast<CRY*>(gate);
1895  vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*M_PI);
1896  parameter_idx = parameter_idx + 1;
1897 
1898  std::stringstream sstream;
1899  sstream << gate_idx << "th gate: CRY on target qubit: " << cry_gate->get_target_qbit() << ", control qubit" << cry_gate->get_control_qbit() << " and with parameters theta = " << vartheta << std::endl;
1900  print(sstream, 1);
1901  gate_idx = gate_idx + 1;
1902  }
1903  else if (gate->get_type() == RZ_OPERATION) {
1904  // definig the rotation parameter
1905  double varphi;
1906  // get the inverse parameters of the U3 rotation
1907  RZ* rz_gate = static_cast<RZ*>(gate);
1908  varphi = std::fmod( 2*parameters_data[parameter_idx], 2*M_PI);
1909  parameter_idx = parameter_idx + 1;
1910 
1911  std::stringstream sstream;
1912  sstream << gate_idx << "th gate: RZ on target qubit: " << rz_gate->get_target_qbit() << " and with parameters varphi = " << varphi << std::endl;
1913  print(sstream, 1);
1914  gate_idx = gate_idx + 1;
1915  }
1916  else if (gate->get_type() == H_OPERATION) {
1917  // get the inverse parameters of the U3 rotation
1918  H* h_gate = static_cast<H*>(gate);
1919  std::stringstream sstream;
1920  sstream << gate_idx << "th gate: Hadamard on target qubit: " << h_gate->get_target_qbit() << std::endl;
1921  print(sstream, 1);
1922  gate_idx = gate_idx + 1;
1923  }
1924  else if (gate->get_type() == X_OPERATION) {
1925  // get the inverse parameters of the U3 rotation
1926  X* x_gate = static_cast<X*>(gate);
1927  std::stringstream sstream;
1928  sstream << gate_idx << "th gate: X on target qubit: " << x_gate->get_target_qbit() << std::endl;
1929  print(sstream, 1);
1930  gate_idx = gate_idx + 1;
1931  }
1932  else if (gate->get_type() == Y_OPERATION) {
1933  // get the inverse parameters of the U3 rotation
1934  Y* y_gate = static_cast<Y*>(gate);
1935  std::stringstream sstream;
1936  sstream << gate_idx << "th gate: Y on target qubit: " << y_gate->get_target_qbit() << std::endl;
1937  print(sstream, 1);
1938  gate_idx = gate_idx + 1;
1939  }
1940  else if (gate->get_type() == Z_OPERATION) {
1941  // get the inverse parameters of the U3 rotation
1942  Z* z_gate = static_cast<Z*>(gate);
1943  std::stringstream sstream;
1944  sstream << gate_idx << "th gate: Z on target qubit: " << z_gate->get_target_qbit() << std::endl;
1945  print(sstream, 1);
1946  gate_idx = gate_idx + 1;
1947  }
1948  else if (gate->get_type() == SX_OPERATION) {
1949  // get the inverse parameters of the U3 rotation
1950  SX* sx_gate = static_cast<SX*>(gate);
1951 
1952  std::stringstream sstream;
1953  sstream << gate_idx << "th gate: SX on target qubit: " << sx_gate->get_target_qbit() << std::endl;
1954  print(sstream, 1);
1955  gate_idx = gate_idx + 1;
1956  }
1957  else if (gate->get_type() == BLOCK_OPERATION) {
1958  Gates_block* block_gate = static_cast<Gates_block*>(gate);
1959  const Matrix_real parameters_layer(parameters.get_data() + parameter_idx, 1, gate->get_parameter_num() );
1960  block_gate->list_gates( parameters_layer, gate_idx );
1961  parameter_idx = parameter_idx + block_gate->get_parameter_num();
1962  gate_idx = gate_idx + block_gate->get_gate_num();
1963  }
1964  else if (gate->get_type() == UN_OPERATION) {
1965  parameter_idx = parameter_idx + gate->get_parameter_num();
1966 
1967  std::stringstream sstream;
1968  sstream << gate_idx << "th gate: UN " << gate->get_parameter_num() << " parameters" << std::endl;
1969  print(sstream, 1);
1970  gate_idx = gate_idx + 1;
1971  }
1972  else if (gate->get_type() == CZ_NU_OPERATION) {
1973  // definig the rotation parameter
1974  double Theta;
1975  // get the inverse parameters of the U3 rotation
1976  CZ_NU* cz_nu_gate = static_cast<CZ_NU*>(gate);
1977  Theta = std::fmod( parameters_data[parameter_idx], 2*M_PI);
1978  parameter_idx = parameter_idx +1;
1979 
1980  std::stringstream sstream;
1981  sstream << gate_idx << "th gate: CZ_NU gate on target qubit: " << cz_nu_gate->get_target_qbit() << ", control qubit " << cz_nu_gate->get_control_qbit() << " and with parameters Theta = " << Theta << std::endl;
1982  print(sstream, 1);
1983  gate_idx = gate_idx + 1;
1984  }
1985  else if (gate->get_type() == ON_OPERATION) {
1986  parameter_idx = parameter_idx + gate->get_parameter_num();
1987  std::stringstream sstream;
1988  sstream << gate_idx << "th gate: ON " << gate->get_parameter_num() << " parameters" << std::endl;
1989  print(sstream, 1);
1990  gate_idx = gate_idx + 1;
1991  }
1992  else if (gate->get_type() == COMPOSITE_OPERATION) {
1993  parameter_idx = parameter_idx + gate->get_parameter_num();
1994 
1995  std::stringstream sstream;
1996  sstream << gate_idx << "th gate: Composite " << gate->get_parameter_num() << " parameters" << std::endl;
1997  print(sstream, 1);
1998  gate_idx = gate_idx + 1;
1999  }
2000  else if (gate->get_type() == ADAPTIVE_OPERATION) {
2001  // definig the rotation parameter
2002  double Theta;
2003  // get the inverse parameters of the U3 rotation
2004  Adaptive* ad_gate = static_cast<Adaptive*>(gate);
2005  Theta = std::fmod( 2*parameters_data[parameter_idx], 4*M_PI);
2006  parameter_idx = parameter_idx + 1;
2007 
2008  std::stringstream sstream;
2009  sstream << gate_idx << "th gate: Adaptive gate on target qubit: " << ad_gate->get_target_qbit() << ", control qubit " << ad_gate->get_control_qbit() << " and with parameters Theta = " << Theta << std::endl;
2010  print(sstream, 1);
2011  gate_idx = gate_idx + 1;
2012  }
2013  else {
2014  std::string err("Gates_block::list_gates: unimplemented gate");
2015  throw err;
2016  }
2017 
2018  }
2019 
2020 
2021 }
2022 
2023 
2029 Gates_block*
2030 Gates_block::create_remapped_circuit( const std::map<int, int>& qbit_map ) {
2031 
2032  return create_remapped_circuit( qbit_map, qbit_num );
2033 
2034 }
2035 
2036 
2043 Gates_block*
2044 Gates_block::create_remapped_circuit( const std::map<int, int>& qbit_map, const int qbit_num_ ) {
2045 
2046 
2047  Gates_block* ret = new Gates_block( qbit_num_ );
2048  for(std::vector<Gate*>::iterator it = gates.begin(); it != gates.end(); ++it) {
2049 
2050  Gate* op = *it;
2051  switch (op->get_type()) {
2052  case CNOT_OPERATION: case CZ_OPERATION:
2053  case CH_OPERATION: case SYC_OPERATION:
2054  case U1_OPERATION: case U2_OPERATION: case U3_OPERATION:
2055  case RY_OPERATION: case CRY_OPERATION: case RX_OPERATION:
2056  case RZ_OPERATION: case X_OPERATION:
2057  case Y_OPERATION: case Z_OPERATION:
2058  case SX_OPERATION: case BLOCK_OPERATION:
2059  case GENERAL_OPERATION: case UN_OPERATION:
2060  case ON_OPERATION: case COMPOSITE_OPERATION:
2061  case ADAPTIVE_OPERATION:
2062  case H_OPERATION:
2063  case T_OPERATION: case TDG_OPERATION:
2064  case CZ_NU_OPERATION:
2065  {
2066  Gate* cloned_op = op->clone();
2067 
2068  int target_qbit = cloned_op->get_target_qbit();
2069  int control_qbit = cloned_op->get_control_qbit();
2070 
2071  if ( qbit_num_ > qbit_num ) {
2072  // qbit num needs to be set in prior to avoid conflict
2073  cloned_op->set_qbit_num( qbit_num_ );
2074  }
2075 
2076  if (qbit_map.find( target_qbit ) != qbit_map.end()) {
2077  cloned_op->set_target_qbit( qbit_map.at(target_qbit) );
2078  } else {
2079  std::string err("Gates_block::create_remapped_circuit: Missing target qubit from the qbit map.");
2080  throw err;
2081  }
2082 
2083 
2084  if ( control_qbit != -1 ) {
2085  if ( qbit_map.find( control_qbit ) != qbit_map.end() ) {
2086  cloned_op->set_control_qbit( qbit_map.at(control_qbit) );
2087  } else {
2088  std::string err("Gates_block::create_remapped_circuit: Missing control qubit from the qbit map.");
2089  throw err;
2090  }
2091  }
2092 
2093  if ( qbit_num_ < qbit_num ) {
2094  // qbit num needs to be set post to avoid conflict
2095  cloned_op->set_qbit_num( qbit_num_ );
2096  }
2097 
2098  ret->add_gate( cloned_op );
2099 
2100  break;
2101  }
2102  default:
2103  std::string err("Gates_block::create_remapped_circuit: unimplemented gate");
2104  throw err;
2105  }
2106 
2107  }
2108 
2109  return ret;
2110 }
2111 
2112 
2117 void Gates_block::reorder_qubits( std::vector<int> qbit_list ) {
2118 
2119  for(std::vector<Gate*>::iterator it = gates.begin(); it != gates.end(); ++it) {
2120 
2121  Gate* gate = *it;
2122 
2123  if (gate->get_type() == CNOT_OPERATION) {
2124  CNOT* cnot_gate = static_cast<CNOT*>(gate);
2125  cnot_gate->reorder_qubits( qbit_list );
2126  }
2127  else if (gate->get_type() == CZ_OPERATION) {
2128  CZ* cz_gate = static_cast<CZ*>(gate);
2129  cz_gate->reorder_qubits( qbit_list );
2130  }
2131  else if (gate->get_type() == CH_OPERATION) {
2132  CH* ch_gate = static_cast<CH*>(gate);
2133  ch_gate->reorder_qubits( qbit_list );
2134  }
2135  else if (gate->get_type() == SYC_OPERATION) {
2136  SYC* syc_gate = static_cast<SYC*>(gate);
2137  syc_gate->reorder_qubits( qbit_list );
2138  }
2139  else if (gate->get_type() == U1_OPERATION) {
2140  U1* u1_gate = static_cast<U1*>(gate);
2141  u1_gate->reorder_qubits( qbit_list );
2142  }
2143  else if (gate->get_type() == U2_OPERATION) {
2144  U2* u2_gate = static_cast<U2*>(gate);
2145  u2_gate->reorder_qubits( qbit_list );
2146  }
2147  else if (gate->get_type() == U3_OPERATION) {
2148  U3* u3_gate = static_cast<U3*>(gate);
2149  u3_gate->reorder_qubits( qbit_list );
2150  }
2151  else if (gate->get_type() == R_OPERATION) {
2152  R* r_gate = static_cast<R*>(gate);
2153  r_gate->reorder_qubits( qbit_list );
2154  }
2155  else if (gate->get_type() == RX_OPERATION) {
2156  RX* rx_gate = static_cast<RX*>(gate);
2157  rx_gate->reorder_qubits( qbit_list );
2158  }
2159  else if (gate->get_type() == RY_OPERATION) {
2160  RY* ry_gate = static_cast<RY*>(gate);
2161  ry_gate->reorder_qubits( qbit_list );
2162  }
2163  else if (gate->get_type() == CRY_OPERATION) {
2164  CRY* cry_gate = static_cast<CRY*>(gate);
2165  cry_gate->reorder_qubits( qbit_list );
2166  }
2167  else if (gate->get_type() == CROT_OPERATION) {
2168  CROT* crot_gate = static_cast<CROT*>(gate);
2169  crot_gate->reorder_qubits( qbit_list );
2170  }
2171  else if (gate->get_type() == RZ_OPERATION) {
2172  RZ* rz_gate = static_cast<RZ*>(gate);
2173  rz_gate->reorder_qubits( qbit_list );
2174  }
2175  else if (gate->get_type() == H_OPERATION) {
2176  H* h_gate = static_cast<H*>(gate);
2177  h_gate->reorder_qubits( qbit_list );
2178  }
2179  else if (gate->get_type() == X_OPERATION) {
2180  X* x_gate = static_cast<X*>(gate);
2181  x_gate->reorder_qubits( qbit_list );
2182  }
2183  else if (gate->get_type() == Y_OPERATION) {
2184  Y* y_gate = static_cast<Y*>(gate);
2185  y_gate->reorder_qubits( qbit_list );
2186  }
2187  else if (gate->get_type() == Z_OPERATION) {
2188  Z* z_gate = static_cast<Z*>(gate);
2189  z_gate->reorder_qubits( qbit_list );
2190  }
2191  else if (gate->get_type() == T_OPERATION) {
2192  T* t_gate = static_cast<T*>(gate);
2193  t_gate->reorder_qubits( qbit_list );
2194  }
2195  else if (gate->get_type() == TDG_OPERATION) {
2196  Tdg* tdg_gate = static_cast<Tdg*>(gate);
2197  tdg_gate->reorder_qubits( qbit_list );
2198  }
2199  else if (gate->get_type() == SX_OPERATION) {
2200  SX* sx_gate = static_cast<SX*>(gate);
2201  sx_gate->reorder_qubits( qbit_list );
2202  }
2203  else if (gate->get_type() == BLOCK_OPERATION) {
2204  Gates_block* block_gate = static_cast<Gates_block*>(gate);
2205  block_gate->reorder_qubits( qbit_list );
2206  }
2207  else if (gate->get_type() == UN_OPERATION) {
2208  UN* un_gate = static_cast<UN*>(gate);
2209  un_gate->reorder_qubits( qbit_list );
2210  }
2211  else if (gate->get_type() == ON_OPERATION) {
2212  ON* on_gate = static_cast<ON*>(gate);
2213  on_gate->reorder_qubits( qbit_list );
2214  }
2215  else if (gate->get_type() == COMPOSITE_OPERATION) {
2216  Composite* com_gate = static_cast<Composite*>(gate);
2217  com_gate->reorder_qubits( qbit_list );
2218  }
2219  else if (gate->get_type() == ADAPTIVE_OPERATION) {
2220  Adaptive* ad_gate = static_cast<Adaptive*>(gate);
2221  ad_gate->reorder_qubits( qbit_list );
2222  }
2223  else {
2224  std::string err("Gates_block::reorder_qubits: unimplemented gate");
2225  throw err;
2226  }
2227 
2228 
2229  }
2230 
2231 }
2232 
2238 
2239  std::vector<int> involved_qbits;
2240 
2241  int qbit;
2242 
2243 
2244  for(std::vector<Gate*>::iterator it = gates.begin(); it != gates.end(); ++it) {
2245 
2246  Gate* gate = *it;
2247 
2248  qbit = gate->get_target_qbit();
2249  if (qbit != -1) {
2250  add_unique_elelement( involved_qbits, qbit );
2251  }
2252 
2253 
2254  qbit = gate->get_control_qbit();
2255  if (qbit != -1) {
2256  add_unique_elelement( involved_qbits, qbit );
2257  }
2258 
2259  }
2260 
2261  return involved_qbits;
2262 }
2263 
2264 
2269 std::vector<Gate*> Gates_block::get_gates() {
2270  return gates;
2271 }
2272 
2273 
2279 
2280  if (idx > (int)gates.size() ) {
2281  return NULL;
2282  }
2283 
2284  return gates[idx];
2285 }
2286 
2287 
2293 
2294  // getting the list of gates
2295  std::vector<Gate*> gates_in = op_block->get_gates();
2296 
2297  int qbit_num_loc = op_block->get_qbit_num();
2298  if ( qbit_num_loc != qbit_num ) {
2299  std::string err("Gates_block::combine: number of qubits in the circuits must be the same");
2300  throw err;
2301  }
2302 
2303  for(std::vector<Gate*>::iterator it = (gates_in).begin(); it != (gates_in).end(); ++it) {
2304  Gate* op = *it;
2305  Gate* op_cloned = op->clone();
2306  add_gate( op_cloned );
2307  }
2308 
2309 }
2310 
2311 
2316 void Gates_block::set_qbit_num( int qbit_num_in ) {
2317 
2318  if (qbit_num_in > 30) {
2319  std::string err("Gates_block::set_qbit_num: Number of qubits supported up to 30");
2320  throw err;
2321  }
2322 
2323  // setting the number of qubits
2324  Gate::set_qbit_num(qbit_num_in);
2325 
2326  // setting the number of qubit in the gates
2327  for(std::vector<Gate*>::iterator it = gates.begin(); it != gates.end(); ++it) {
2328  Gate* op = *it;
2329  switch (op->get_type()) {
2330  case CNOT_OPERATION: case CZ_OPERATION:
2331  case CH_OPERATION: case SYC_OPERATION:
2332  case U1_OPERATION: case U2_OPERATION: case U3_OPERATION:
2333  case RY_OPERATION: case CRY_OPERATION: case RX_OPERATION:
2334  case RZ_OPERATION: case X_OPERATION:
2335  case Y_OPERATION: case Z_OPERATION:
2336  case SX_OPERATION: case BLOCK_OPERATION:
2337  case GENERAL_OPERATION: case UN_OPERATION:
2338  case ON_OPERATION: case COMPOSITE_OPERATION:
2340  case H_OPERATION: case R_OPERATION:
2341  case CZ_NU_OPERATION:
2342  case T_OPERATION: case TDG_OPERATION:
2343  op->set_qbit_num( qbit_num_in );
2344  break;
2345  default:
2346  std::string err("Gates_block::set_qbit_num: unimplemented gate");
2347  throw err;
2348  }
2349  }
2350 }
2351 
2352 
2358 
2359  // creatign new instance of class Gates_block
2360  Gates_block* ret = new Gates_block( qbit_num );
2361 
2363  ret->set_parents( parents );
2364  ret->set_children( children );
2365 
2366  // extracting the gates from the current class
2367  if (extract_gates( ret ) != 0 ) {
2368  std::string err("Gates_block::clone(): extracting gates was not succesfull");
2369  throw err;
2370  };
2371 
2372  return ret;
2373 
2374 }
2375 
2376 
2383 
2384  op_block->release_gates();
2385 
2386  for ( std::vector<Gate*>::iterator it=gates.begin(); it != gates.end(); ++it ) {
2387  Gate* op = *it;
2388  switch (op->get_type()) {
2389  case CNOT_OPERATION: case CZ_OPERATION:
2390  case CH_OPERATION: case SYC_OPERATION:
2391  case U1_OPERATION: case U2_OPERATION: case U3_OPERATION:
2392  case RY_OPERATION: case CRY_OPERATION: case RX_OPERATION:
2393  case RZ_OPERATION: case X_OPERATION:
2394  case Y_OPERATION: case Z_OPERATION:
2395  case SX_OPERATION: case BLOCK_OPERATION:
2396  case GENERAL_OPERATION: case UN_OPERATION:
2397  case ON_OPERATION: case COMPOSITE_OPERATION:
2399  case H_OPERATION: case R_OPERATION:
2400  case CZ_NU_OPERATION:
2401  case T_OPERATION: case TDG_OPERATION:
2402  {
2403  Gate* op_cloned = op->clone();
2404  op_block->add_gate( op_cloned );
2405  break; }
2406  default:
2407  std::string err("Gates_block::extract_gates: unimplemented gate");
2408  throw err;
2409  }
2410 
2411  }
2412 
2413  return 0;
2414 
2415 }
2416 
2417 
2418 
2424 
2425  for ( std::vector<Gate*>::iterator it=gates.begin(); it != gates.end(); ++it ) {
2426  Gate* op = *it;
2427 
2428  if (op->get_type() == ADAPTIVE_OPERATION) {
2429  return true;
2430  }
2431  else if (op->get_type() == BLOCK_OPERATION) {
2432  Gates_block* block_op = static_cast<Gates_block*>( op );
2433  bool ret = block_op->contains_adaptive_gate();
2434  if ( ret ) return true;
2435  }
2436  }
2437 
2438  return false;
2439 
2440 }
2441 
2442 
2443 
2444 
2451 
2452 
2453  Gate* op = gates[idx];
2454 
2455  if (op->get_type() == ADAPTIVE_OPERATION) {
2456  return true;
2457  }
2458  else if (op->get_type() == BLOCK_OPERATION) {
2459  Gates_block* block_op = static_cast<Gates_block*>( op );
2460  return block_op->contains_adaptive_gate();
2461  }
2462 
2463  return false;
2464 
2465 }
2466 
2467 
2468 
2476 Matrix
2477 Gates_block::get_reduced_density_matrix( Matrix_real& parameters_mtx, Matrix& input_state, matrix_base<int>& qbit_list_subset ) {
2478 
2479 
2480  if (input_state.cols != 1) {
2481  std::string error("Gates_block::get_reduced_density_matrix: The number of columns in input state should be 1");
2482  throw error;
2483  }
2484 
2485 
2486  if (input_state.rows != matrix_size) {
2487  std::string error("Gates_block::get_reduced_density_matrix: The number of rows in input state should be 2^qbit_num");
2488  throw error;
2489  }
2490 
2491  // determine the transformed state
2492  Matrix transformed_state = input_state.copy();
2493  if ( parameters_mtx.size() > 0 ) {
2494  bool parallel = true;
2495  apply_to( parameters_mtx, transformed_state, parallel );
2496  }
2497 
2498 
2499  int subset_qbit_num = qbit_list_subset.size();
2500  int complementary_qbit_num = qbit_num - subset_qbit_num;
2501 
2502 
2503  // list of complementary qubits
2504  matrix_base<int> qbit_list_complementary( complementary_qbit_num, 1);
2505  int qbit_idx_count = 0;
2506  for (int qbit_idx=0; qbit_idx<qbit_num; qbit_idx++) {
2507 
2508  bool qbit_idx_in_subset = false;
2509 
2510  for (int subset_qbit_idx=0; subset_qbit_idx<subset_qbit_num; subset_qbit_idx++) {
2511  if ( qbit_idx == qbit_list_subset[subset_qbit_idx] ) {
2512  qbit_idx_in_subset = true;
2513  break;
2514  }
2515  }
2516 
2517 
2518  if ( qbit_idx_in_subset ) {
2519  continue;
2520  }
2521 
2522  qbit_list_complementary[qbit_idx_count] = qbit_idx;
2523  qbit_idx_count++;
2524  }
2525 
2526 
2527  // 000010000 one-hot encoded numbers indicating the bit position of the qubits in the register
2528  matrix_base<int> qbit_masks(qbit_num, 1);
2529  for (int qbit_idx=0; qbit_idx<qbit_num; qbit_idx++) {
2530  qbit_masks[ qbit_idx ] = 1 << qbit_idx;
2531  }
2532 
2533 
2534 
2535  // retrieve the reduced density matrix
2536  int rho_matrix_size = 1 << subset_qbit_num;
2537 
2538  Matrix rho(rho_matrix_size, rho_matrix_size);
2539  memset( rho.get_data(), 0.0, rho.size()*sizeof(QGD_Complex16) );
2540 
2541 
2542 
2543 
2544  int complementary_basis_num = 1 << complementary_qbit_num;
2545  for ( int row_idx=0; row_idx<rho_matrix_size; row_idx++ ) {
2546 
2547  // index of the amplitude in the state vector
2548  int idx = 0;
2549  for (int qbit_idx=0; qbit_idx<subset_qbit_num; qbit_idx++) {
2550  if ( row_idx & qbit_masks[ qbit_idx ] ) {
2551  idx = idx | qbit_masks[ qbit_list_subset[qbit_idx] ];
2552  }
2553  }
2554 
2555  for ( int col_idx=row_idx; col_idx<rho_matrix_size; col_idx++ ) {
2556 
2557  // index of the amplitude in the state vector
2558  int jdx = 0;
2559  for (int qbit_idx=0; qbit_idx<subset_qbit_num; qbit_idx++) {
2560  if ( col_idx & qbit_masks[ qbit_idx ] ) {
2561  jdx = jdx | qbit_masks[ qbit_list_subset[qbit_idx] ];
2562  }
2563  }
2564 
2565 
2566  // thread local storage for partial permanent
2567  tbb::combinable<QGD_Complex16> priv_addend {[](){QGD_Complex16 ret; ret.real = 0.0; ret.imag = 0.0; return ret;}};
2568 
2569 
2570  tbb::parallel_for( tbb::blocked_range<int>(0, complementary_basis_num, 1024), [&](tbb::blocked_range<int> r) {
2571 
2572  QGD_Complex16& rho_element_priv = priv_addend.local();
2573 
2574  for (int compl_idx=r.begin(); compl_idx<r.end(); compl_idx++) {
2575 
2576 
2577  int idx_loc = idx;
2578  int jdx_loc = jdx;
2579 
2580  for (int qbit_idx=0; qbit_idx<complementary_qbit_num; qbit_idx++) {
2581  if ( compl_idx & qbit_masks[ qbit_idx ] ) {
2582  idx_loc = idx_loc | qbit_masks[ qbit_list_complementary[qbit_idx] ];
2583  jdx_loc = jdx_loc | qbit_masks[ qbit_list_complementary[qbit_idx] ];
2584  }
2585  }
2586 
2587  QGD_Complex16 element_idx = transformed_state[ idx_loc ];
2588  QGD_Complex16& element_jdx = transformed_state[ jdx_loc ];
2589 
2590  // conjugate because of the bra-vector
2591  element_idx.imag = -element_idx.imag;
2592 
2593  QGD_Complex16 addend = mult( element_idx, element_jdx );
2594 
2595  rho_element_priv.real = rho_element_priv.real + addend.real;
2596  rho_element_priv.imag = rho_element_priv.imag + addend.imag;
2597 
2598 
2599  }
2600  });
2601 
2602 
2603 
2604  QGD_Complex16 rho_element;
2605  rho_element.real = 0.0;
2606  rho_element.imag = 0.0;
2607 
2608  priv_addend.combine_each([&](QGD_Complex16 &a) {
2609  rho_element.real = rho_element.real + a.real;
2610  rho_element.imag = rho_element.imag + a.imag;
2611  });
2612 
2613  rho[ row_idx * rho.stride + col_idx ].real += rho_element.real;
2614  rho[ row_idx * rho.stride + col_idx ].imag += rho_element.imag;
2615 
2616  if ( row_idx == col_idx ) {
2617  continue;
2618  }
2619 
2620  rho[ col_idx * rho.stride + row_idx ].real += rho_element.real;
2621  rho[ col_idx * rho.stride + row_idx ].imag -= rho_element.imag;
2622 
2623  }
2624 
2625 
2626  }
2627 
2628 
2629  // test the trace of the reduced density matrix
2630  double trace = 0.0;
2631  for( int idx=0; idx<rho_matrix_size; idx++) {
2632  trace = trace + rho[idx*rho.stride+idx].real;
2633  }
2634 
2635  if ( abs( trace-1.0 ) > 1e-6 ) {
2636  std::stringstream sstream;
2637  sstream << "Warning: Gates_block::get_reduced_density_matrix: The error of the trace of the reduced density matrix is " << abs( trace-1.0 ) << std::endl;
2638  print(sstream, 1);
2639  }
2640 
2641  return rho;
2642 
2643 
2644 }
2645 
2646 
2654 double Gates_block::get_second_Renyi_entropy( Matrix_real& parameters_mtx, Matrix& input_state, matrix_base<int>& qbit_list_subset ) {
2655 
2656  // determine the reduced density matrix
2657  Matrix rho = get_reduced_density_matrix( parameters_mtx, input_state, qbit_list_subset );
2658 
2659 
2660  // calculate the second Rényi entropy
2661  // Tr( rho @ rho )
2662  double trace_rho_square = 0.0;
2663 
2664  for (int idx=0; idx<rho.rows; idx++) {
2665 
2666  double trace_tmp = 0.0;
2667 
2668  for (int jdx=0; jdx<rho.rows; jdx++) {
2669  QGD_Complex16& element = rho[ idx*rho.stride + jdx ];
2670  double tmp = element.real * element.real + element.imag * element.imag;
2671 
2672  trace_tmp = trace_tmp + tmp;
2673  }
2674 
2675 
2676  trace_rho_square = trace_rho_square + trace_tmp;
2677 
2678 
2679  }
2680 
2681 
2682 
2683 
2684  double entropy = -log(trace_rho_square);
2685 
2686 
2687  return entropy;
2688 
2689 }
2690 
2691 
2698 std::vector<int> remove_list_intersection( std::vector<int>& list1, std::vector<int>& list2 ) {
2699 
2700  std::vector<int> ret = list1;
2701 
2702  for( std::vector<int>::iterator it2 = list2.begin(); it2 != list2.end(); it2++ ) {
2703 
2704  std::vector<int>::iterator element_found = std::find(ret.begin(), ret.end(), *it2);
2705 
2706  if( element_found != ret.end() ) {
2707  ret.erase( element_found );
2708  }
2709 
2710  }
2711 
2712  return ret;
2713 
2714 
2715 
2716 }
2717 
2718 
2723 void
2725 
2726 
2727  std::vector<int>&& involved_qubits = gate->get_involved_qubits();
2728 /*
2729  std::cout << "involved qubits in the current gate: " << std::endl;
2730  for( int idx=0; idx<involved_qubits.size(); idx++ ) {
2731  std::cout << involved_qubits[idx] << ", ";
2732  }
2733  std::cout << std::endl;
2734  */
2735  // iterate over gates in the circuit
2736  for( int idx=gates.size()-1; idx>=0; idx-- ) {
2737  Gate* gate_loc = gates[idx];
2738  std::vector<int>&& involved_qubits_loc = gate_loc->get_involved_qubits();
2739 
2740  std::vector<int>&& reduced_qbit_list = remove_list_intersection( involved_qubits, involved_qubits_loc );
2741 
2742  if( reduced_qbit_list.size() < involved_qubits.size() ) {
2743  // parent gate found, setting parent-child relation
2744 
2745  gate->add_parent( gate_loc );
2746  gate_loc->add_child( gate );
2747 
2748  involved_qubits = std::move(reduced_qbit_list);
2749 
2750 
2751  }
2752 
2753 
2754  // return if no further involved qubits left
2755  if( involved_qubits.size() == 0 ) {
2756  break;
2757  }
2758  }
2759 
2760 
2761 }
2762 
2763 
2764 
2769 void
2771 
2772 
2773  std::vector<int>&& involved_qubits = gate->get_involved_qubits();
2774 
2775  // iterate over gates in the circuit
2776  for( int idx=0; idx<gates.size(); idx++ ) {
2777  Gate* gate_loc = gates[idx];
2778  std::vector<int>&& involved_qubits_loc = gate_loc->get_involved_qubits();
2779 
2780  std::vector<int>&& reduced_qbit_list = remove_list_intersection( involved_qubits, involved_qubits_loc );
2781 
2782  if( reduced_qbit_list.size() < involved_qubits.size() ) {
2783  // child gate found, setting parent-child relation
2784 
2785  gate->add_child( gate_loc );
2786  gate_loc->add_parent( gate );
2787 
2788  involved_qubits = std::move(reduced_qbit_list);
2789 
2790 
2791  }
2792 
2793 
2794  // return if no further involved qubits left
2795  if( involved_qubits.size() == 0 ) {
2796  break;
2797  }
2798  }
2799 
2800 }
2801 
2802 
2806 void
2808 
2809  int parameter_idx = 0;
2810 
2811  for( std::vector<Gate*>::iterator gate_it = gates.begin(); gate_it != gates.end(); gate_it++ ) {
2812 
2813  Gate* gate = *gate_it;
2814 
2815  gate->set_parameter_start_idx( parameter_idx );
2816 
2817  parameter_idx = parameter_idx + gate->get_parameter_num();
2818 
2819  }
2820 
2821 }
2822 
2823 
2827 void
2829 
2830  // first clear parent/children data from the gates
2831  for( std::vector<Gate*>::iterator gate_it = gates.begin(); gate_it != gates.end(); gate_it++ ) {
2832  Gate* gate = *gate_it;
2833  gate->clear_children();
2834  gate->clear_parents();
2835  }
2836 
2837 
2838  // first clear parent/children data from the gates
2839  for( std::vector<Gate*>::iterator gate_it = gates.begin(); gate_it != gates.end(); gate_it++ ) {
2840  Gate* gate = *gate_it;
2841 
2842  // determine the parents of the gate
2843  determine_parents( gate );
2844 
2845  }
2846 
2847 
2848 
2849 
2850 }
2851 
2852 
2856 Gates_block*
2858 
2859  Gates_block* flat_circuit = new Gates_block( qbit_num );
2860 
2861  for( std::vector<Gate*>::iterator gate_it=gates.begin(); gate_it != gates.end(); gate_it++ ) {
2862 
2863  Gate* gate = *gate_it;
2864 
2865  if( gate->get_type() == BLOCK_OPERATION ) {
2866 
2867  Gates_block* circuit_inner = static_cast<Gates_block*>( gate );
2868  Gates_block* flat_circuit_inner = circuit_inner->get_flat_circuit();
2869 
2870  flat_circuit->combine( flat_circuit_inner );
2871 
2872  delete( flat_circuit_inner );
2873  }
2874  else {
2875  flat_circuit->add_gate( gate->clone() );
2876  }
2877 
2878  }
2879 
2880 
2881 
2882  return flat_circuit;
2883 
2884 
2885 }
2886 
2887 
2888 
2894 Matrix_real
2896 
2897  if ( get_parameter_start_idx() + get_parameter_num() < parameters.size() ) {
2898  std::string err("Gates_block::extract_parameters: Cant extract parameters, since th einput arary has not enough elements.");
2899  throw err;
2900  }
2901 
2902  Matrix_real extracted_parameters(1, get_parameter_num());
2903 
2904  memcpy( extracted_parameters.get_data(), parameters.get_data() + get_parameter_start_idx(), get_parameter_num()*sizeof(double) );
2905 
2906  return extracted_parameters;
2907 
2908 }
2909 
2910 
2911 #ifdef __DFE__
2912 
2913 
2918 DFEgate_kernel_type* Gates_block::convert_to_DFE_gates_with_derivates( Matrix_real& parameters_mtx, int& gatesNum, int& gateSetNum, int& redundantGateSets, bool only_derivates ) {
2919 
2921  if ( parameter_num != parameters_mtx.size() ) {
2922  std::string error("Gates_block::convert_to_DFE_gates: wrong number of parameters");
2923  throw error;
2924  }
2925 
2926  std::map<std::string, int> gate_nums = get_gate_nums();
2927  int gates_total_num = 0;
2928  for( auto it=gate_nums.begin(); it != gate_nums.end(); it++ ) {
2929  gates_total_num = gates_total_num + it->second;
2930  }
2931 
2932  int chained_gates_num = get_chained_gates_num();
2933  int gate_padding = gates_total_num % chained_gates_num == 0 ? 0 : chained_gates_num - (gates_total_num % chained_gates_num);
2934  gatesNum = gates_total_num+gate_padding;
2935 /*
2936 std::cout << "chained gates num: " << chained_gates_num << std::endl;
2937 std::cout << "number of gates: " << gatesNum << std::endl;
2938 */
2939 
2940 
2941  gateSetNum = only_derivates ? parameter_num : parameter_num+1;
2942 
2943 #ifdef __MPI__
2944  int rem = gateSetNum % (4 * world_size );
2945  if ( rem == 0 ) {
2946  redundantGateSets = 0;
2947  }
2948  else {
2949  redundantGateSets = (4 * world_size ) - (gateSetNum % (4 * world_size ));
2950  gateSetNum = gateSetNum + redundantGateSets;
2951  }
2952 #else
2953  int rem = gateSetNum % 4;
2954  if ( rem == 0 ) {
2955  redundantGateSets = 0;
2956  }
2957  else {
2958  redundantGateSets = 4 - (gateSetNum % 4);
2959  gateSetNum = gateSetNum + redundantGateSets;
2960  }
2961 #endif
2962 
2963 
2964  DFEgate_kernel_type* DFEgates = new DFEgate_kernel_type[gatesNum*gateSetNum];
2965 
2966 
2967  int gate_idx = 0;
2968  convert_to_DFE_gates( parameters_mtx, DFEgates, gate_idx );
2969 
2970 
2971  // padding with identity gates
2972  for (int idx=gate_idx; idx<gatesNum; idx++ ){
2973 
2974  DFEgate_kernel_type& DFEGate = DFEgates[idx];
2975 
2976 
2977  DFEGate.target_qbit = 0;
2978  DFEGate.control_qbit = -1;
2979  DFEGate.gate_type = U3_OPERATION;
2980  DFEGate.ThetaOver2 = (int32_t)(0);
2981  DFEGate.Phi = (int32_t)(0);
2982  DFEGate.Lambda = (int32_t)(0);
2983  DFEGate.metadata = 0;
2984 
2985  }
2986 /*
2987  for ( int idx=0; idx<gatesNum; idx++ ) {
2988 
2989  std::cout << "target qubit: " << (int)DFEgates[idx].target_qbit << " control qubit: " << (int)DFEgates[idx].control_qbit << " gate type: " << (int)DFEgates[idx].gate_type << std::endl;
2990  }
2991 */
2992 
2993  // adjust parameters for derivation
2994  if (only_derivates ) {
2995  for (int idx=1; idx<(gateSetNum-1); idx++) {
2996  memcpy(DFEgates+idx*gatesNum, DFEgates, gatesNum*sizeof(DFEgate_kernel_type));
2997  }
2998  }
2999  else {
3000  for (int idx=0; idx<(gateSetNum-1); idx++) {
3001  memcpy(DFEgates+(idx+1)*gatesNum, DFEgates, gatesNum*sizeof(DFEgate_kernel_type));
3002  }
3003  }
3004 
3005  gate_idx = 0;
3006  int gate_set_index = parameter_num-1;
3007  if (only_derivates) {
3008  adjust_parameters_for_derivation( DFEgates, gatesNum, gate_idx, gate_set_index );
3009  }
3010  else {
3011  adjust_parameters_for_derivation( DFEgates+gatesNum, gatesNum, gate_idx, gate_set_index );
3012  }
3013 
3014 /*
3015  for ( int idx=0; idx<gatesNum*(parameter_num+1); idx++ ) {
3016 
3017  std::cout << "target qubit: " << (int)DFEgates[idx].target_qbit << " control qubit: " << (int)DFEgates[idx].control_qbit << " theta: " << (int)DFEgates[idx].ThetaOver2 << " lambda: " << (int)DFEgates[idx].Lambda << std::endl;
3018  }
3019 */
3020  return DFEgates;
3021 
3022 }
3023 
3024 
3029 void Gates_block::adjust_parameters_for_derivation( DFEgate_kernel_type* DFEgates, const int gatesNum, int& gate_idx, int& gate_set_index) {
3030 
3032  //int gate_set_index = parameter_num-1;
3033 
3034  int32_t parameter_shift = (int32_t)(M_PI/2*(1<<25));
3035 
3036  for(int op_idx = gates.size()-1; op_idx>=0; op_idx--) {
3037 
3038  Gate* gate = gates[op_idx];
3039 //std::cout << gate_idx << " " << gate_set_index << " " << gate->get_type() << std::endl;
3040 
3041  if (gate->get_type() == CNOT_OPERATION) {
3042  gate_idx = gate_idx + 1;
3043  }
3044  else if (gate->get_type() == CZ_OPERATION) {
3045  gate_idx = gate_idx + 1;
3046  }
3047  else if (gate->get_type() == CH_OPERATION) {
3048  gate_idx = gate_idx + 1;
3049  }
3050  else if (gate->get_type() == SYC_OPERATION) {
3051  std::string error("Gates_block::convert_to_DFE_gates: SYC_gate not implemented");
3052  throw error;
3053  }
3054  else if (gate->get_type() == U1_OPERATION) {
3055  // Lambda parameter derivative
3056  DFEgate_kernel_type& DFEGate = DFEgates[gate_set_index*gatesNum + gate_idx];
3057  DFEGate.Lambda = DFEGate.Lambda + parameter_shift;
3058  DFEGate.metadata = 5 + (1<<7); // Lambda parameter derivative// The 0st and 3nd element in kernel matrix should be zero for derivates and 5 = 0101, plus the leading bit indicates that derivate is processed
3059  gate_set_index = gate_set_index - 1;
3060 
3061  parameter_idx = parameter_idx - 1;
3062  gate_idx = gate_idx + 1;
3063  }
3064  else if (gate->get_type() == U2_OPERATION) {
3065  // Lambda parameter derivative
3066  DFEgate_kernel_type& DFEGate2 = DFEgates[gate_set_index*gatesNum + gate_idx];
3067  DFEGate2.Lambda = DFEGate2.Lambda + parameter_shift;
3068  DFEGate2.metadata = 5 + (1<<7); // The 0st and 3nd element in kernel matrix should be zero for derivates and 5 = 0101, plus the leading bit indicates that derivate is processed
3069  gate_set_index = gate_set_index - 1;
3070 
3071  // Phi parameter derivative
3072  DFEgate_kernel_type& DFEGate = DFEgates[gate_set_index*gatesNum + gate_idx];
3073  DFEGate.Phi = DFEGate.Phi + parameter_shift;
3074  DFEGate.metadata = 3 + (1<<7); // The 0st and 3nd element in kernel matrix should be zero for derivates and 5 = 0101, plus the leading bit indicates that derivate is processed
3075  gate_set_index = gate_set_index - 1;
3076 
3077  parameter_idx = parameter_idx - 2;
3078  gate_idx = gate_idx + 1;
3079  }
3080  else if (gate->get_type() == U3_OPERATION) {
3081  // Lambda parameter derivative
3082  DFEgate_kernel_type& DFEGate3 = DFEgates[gate_set_index*gatesNum + gate_idx];
3083  DFEGate3.Lambda = DFEGate3.Lambda + parameter_shift;
3084  DFEGate3.metadata = 5 + (1<<7); // The 0st and 3nd element in kernel matrix should be zero for derivates and 5 = 0101, plus the leading bit indicates that derivate is processed
3085  gate_set_index = gate_set_index - 1;
3086 
3087  // Phi parameter derivative
3088  DFEgate_kernel_type& DFEGate2 = DFEgates[gate_set_index*gatesNum + gate_idx];
3089  DFEGate2.Phi = DFEGate2.Phi + parameter_shift;
3090  DFEGate2.metadata = 3 + (1<<7); // The 0st and 3nd element in kernel matrix should be zero for derivates and 5 = 0101, plus the leading bit indicates that derivate is processed
3091  gate_set_index = gate_set_index - 1;
3092 
3093  // Theta parameter derivative
3094  DFEgate_kernel_type& DFEGate = DFEgates[gate_set_index*gatesNum + gate_idx];
3095  DFEGate.ThetaOver2 = DFEGate.ThetaOver2 + parameter_shift;
3096  DFEGate.metadata = (1<<7); // the leading bit indicates that derivate is processed
3097  gate_set_index = gate_set_index - 1;
3098 
3099  parameter_idx = parameter_idx - 3;
3100  gate_idx = gate_idx + 1;
3101  }
3102  else if (gate->get_type() == RX_OPERATION) { // Did not cehcked
3103 
3104  DFEgate_kernel_type& DFEGate = DFEgates[gate_set_index*gatesNum + gate_idx];
3105  DFEGate.ThetaOver2 = DFEGate.ThetaOver2 + parameter_shift;
3106  DFEGate.metadata = (1<<7); // the leading bit indicates that derivate is processed
3107  gate_set_index = gate_set_index - 1;
3108 
3109  parameter_idx = parameter_idx - 1;
3110 
3111  gate_idx = gate_idx + 1;
3112  }
3113  else if (gate->get_type() == RY_OPERATION) { // Did not cehcked
3114 
3115  DFEgate_kernel_type& DFEGate = DFEgates[gate_set_index*gatesNum + gate_idx];
3116  DFEGate.ThetaOver2 = DFEGate.ThetaOver2 + parameter_shift;
3117  DFEGate.metadata = (1<<7); // the leading bit indicates that derivate is processed
3118  gate_set_index = gate_set_index - 1;
3119 
3120  parameter_idx = parameter_idx - 1;
3121 
3122 
3123  gate_idx = gate_idx + 1;
3124  }
3125  else if (gate->get_type() == CRY_OPERATION) {
3126 
3127  DFEgate_kernel_type& DFEGate = DFEgates[gate_set_index*gatesNum + gate_idx];
3128  DFEGate.ThetaOver2 = DFEGate.ThetaOver2 + parameter_shift;
3129  DFEGate.metadata = (1<<7); // the leading bit indicates that derivate is processed
3130  gate_set_index = gate_set_index - 1;
3131 
3132  parameter_idx = parameter_idx - 1;
3133 
3134  gate_idx = gate_idx + 1;
3135  }
3136  else if (gate->get_type() == RZ_OPERATION) { // Did not cehcked
3137 
3138  std::string error("Gates_block::adjust_parameters_for_derivation: RZ gate not implemented for DFE");
3139  throw error;
3140  }
3141  else if (gate->get_type() == RZ_P_OPERATION) { // Did not cehcked
3142 
3143  DFEgate_kernel_type& DFEGate = DFEgates[gate_set_index*gatesNum + gate_idx];
3144  DFEGate.Phi = DFEGate.Phi + parameter_shift;
3145  DFEGate.metadata = 3 + (1<<7); // The 0-th and 1st element in kernel matrix should be zero for derivates and 3 = 0011, plus the leading bit indicates that derivate is processed
3146  gate_set_index = gate_set_index - 1;
3147 
3148  parameter_idx = parameter_idx - 1;
3149 
3150  gate_idx = gate_idx + 1;
3151  }
3152  else if (gate->get_type() == H_OPERATION) {
3153  std::string error("Gates_block::convert_to_DFE_gates: H_gate not implemented");
3154  throw error;
3155 
3156  }
3157  else if (gate->get_type() == X_OPERATION) {
3158  std::string error("Gates_block::convert_to_DFE_gates: X_gate not implemented");
3159  throw error;
3160 
3161  }
3162  else if (gate->get_type() == Y_OPERATION) {
3163  std::string error("Gates_block::convert_to_DFE_gates: Y_gate not implemented");
3164  throw error;
3165 
3166  }
3167  else if (gate->get_type() == Z_OPERATION) {
3168  std::string error("Gates_block::convert_to_DFE_gates: Z_gate not implemented");
3169  throw error;
3170 
3171  }
3172  else if (gate->get_type() == T_OPERATION) {
3173  std::string error("Gates_block::convert_to_DFE_gates: T_gate not implemented");
3174  throw error;
3175 
3176  }
3177  else if (gate->get_type() == TDG_OPERATION) {
3178  std::string error("Gates_block::convert_to_DFE_gates: Tdg_gate not implemented");
3179  throw error;
3180  }
3181  else if (gate->get_type() == SX_OPERATION) {
3182  std::string error("Gates_block::convert_to_DFE_gates: SX_gate not implemented");
3183  throw error;
3184  }
3185  else if (gate->get_type() == BLOCK_OPERATION) {
3186 
3187  Gates_block* block_gate = static_cast<Gates_block*>(gate);
3188  block_gate->adjust_parameters_for_derivation( DFEgates, gatesNum, gate_idx, gate_set_index);
3189  //gate_set_index = gate_set_index - block_gate->get_parameter_num();
3190 
3191  parameter_idx = parameter_idx - block_gate->get_parameter_num();
3192  }
3193  else if (gate->get_type() == UN_OPERATION) {
3194  std::string error("Gates_block::convert_to_DFE_gates: UN_gate not implemented");
3195  throw error;
3196  }
3197  else if (gate->get_type() == ON_OPERATION) {
3198 
3199  // THE LAST GATE IS A GENERAL GATE APPENDED IN THE BLOCK-WISE OPTIMISATION ROUTINE OF DECOMPOSITION_BASE
3200  std::string error("Gates_block::convert_to_DFE_gates: ON_gate not implemented");
3201  throw error;
3202  }
3203  else if (gate->get_type() == COMPOSITE_OPERATION) {
3204  std::string error("Gates_block::convert_to_DFE_gates: Composite_gate not implemented");
3205  throw error;
3206  }
3207  else if (gate->get_type() == GENERAL_OPERATION) {
3208  std::string error("Gates_block::convert_to_DFE_gates: general_gate not implemented");
3209  throw error;
3210  }
3211  else if (gate->get_type() == ADAPTIVE_OPERATION) {
3212 
3213  DFEgate_kernel_type& DFEGate = DFEgates[gate_set_index*gatesNum + gate_idx];
3214  DFEGate.metadata = (1<<7); // the leading bit indicates that derivate is processed
3215  DFEGate.ThetaOver2 = DFEGate.ThetaOver2 + parameter_shift;
3216  gate_set_index = gate_set_index - 1;
3217 
3218  parameter_idx = parameter_idx - 1;
3219 
3220  gate_idx = gate_idx + 1;
3221  }
3222  else {
3223  std::string err("Gates_block::adjust_parameters_for_derivation: unimplemented gate");
3224  throw err;
3225  }
3226 
3227  }
3228 
3229 
3230 }
3231 
3232 
3238 Gates_block::convert_to_batched_DFE_gates( std::vector<Matrix_real>& parameters_mtx_vec, int& gatesNum, int& gateSetNum, int& redundantGateSets ) {
3239 
3240 
3241  std::map<std::string, int> gate_nums = get_gate_nums();
3242  int gates_total_num = 0;
3243  for( auto it=gate_nums.begin(); it != gate_nums.end(); it++ ) {
3244  gates_total_num = gates_total_num + it->second;
3245  }
3246 
3247  int chained_gates_num = get_chained_gates_num();
3248  int gate_padding = gates_total_num % chained_gates_num == 0 ? 0 : chained_gates_num - (gates_total_num % chained_gates_num);
3249  gatesNum = gates_total_num+gate_padding;
3250 /*
3251 std::cout << "chained gates num: " << chained_gates_num << std::endl;
3252 std::cout << "number of gates: " << gatesNum << std::endl;
3253 */
3254 
3255 
3256  gateSetNum = parameters_mtx_vec.size();
3257 
3258 #ifdef __MPI__
3259  int rem = gateSetNum % (4 * world_size );
3260  if ( rem == 0 ) {
3261  redundantGateSets = 0;
3262  }
3263  else {
3264  redundantGateSets = (4 * world_size ) - (gateSetNum % (4 * world_size ));
3265  gateSetNum = gateSetNum + redundantGateSets;
3266  }
3267 #else
3268  int rem = gateSetNum % 4;
3269  if ( rem == 0 ) {
3270  redundantGateSets = 0;
3271  }
3272  else {
3273  redundantGateSets = 4 - (gateSetNum % 4);
3274  gateSetNum = gateSetNum + redundantGateSets;
3275  }
3276 #endif
3277 
3278  DFEgate_kernel_type* DFEgates = new DFEgate_kernel_type[gatesNum*gateSetNum];
3279 
3280 
3281  tbb::parallel_for( 0, gateSetNum, 1, [&](int gateset_idx) {
3282 
3283  int gate_idx = gateset_idx * gatesNum;
3284 
3285  if ( gateset_idx < parameters_mtx_vec.size() ) {
3286  Matrix_real& parameters_mtx = parameters_mtx_vec[gateset_idx];
3287  convert_to_DFE_gates( parameters_mtx, DFEgates, gate_idx );
3288  }
3289 
3290  // padding with identity gates
3291  for (int idx=gate_idx; idx<(gateset_idx+1)*gatesNum; idx++ ){
3292 
3293  DFEgate_kernel_type& DFEGate = DFEgates[idx];
3294 
3295 
3296  DFEGate.target_qbit = 0;
3297  DFEGate.control_qbit = -1;
3298  DFEGate.gate_type = U3_OPERATION;
3299  DFEGate.ThetaOver2 = (int32_t)(0);
3300  DFEGate.Phi = (int32_t)(0);
3301  DFEGate.Lambda = (int32_t)(0);
3302  DFEGate.metadata = 0;
3303 
3304  gate_idx++;
3305 
3306  }
3307 
3308  });
3309 
3310 
3311  return DFEgates;
3312 
3313 }
3314 
3319 DFEgate_kernel_type* Gates_block::convert_to_DFE_gates( Matrix_real& parameters_mtx, int& gatesNum ) {
3320 
3322  if ( parameter_num != parameters_mtx.size() ) {
3323  std::string error("Gates_block::convert_to_DFE_gates: wrong number of parameters");
3324  throw error;
3325  }
3326 
3327 
3328  std::map<std::string, int> gate_nums = get_gate_nums();
3329  int gates_total_num = 0;
3330  for( auto it=gate_nums.begin(); it != gate_nums.end(); it++ ) {
3331  gates_total_num = gates_total_num + it->second;
3332  }
3333 
3334  int chained_gates_num = get_chained_gates_num();
3335  int gate_padding = chained_gates_num - (gates_total_num % chained_gates_num);
3336  gatesNum = gates_total_num+gate_padding;
3337 
3338 
3339 
3340  DFEgate_kernel_type* DFEgates = new DFEgate_kernel_type[gates_total_num+gate_padding];
3341 
3342  int gate_idx = 0;
3343  convert_to_DFE_gates( parameters_mtx, DFEgates, gate_idx );
3344 
3345 
3346  // padding with identity gates
3347  for (int idx=gate_idx; idx<gatesNum; idx++ ){
3348 
3349  DFEgate_kernel_type& DFEGate = DFEgates[idx];
3350 
3351 
3352  DFEGate.target_qbit = 0;
3353  DFEGate.control_qbit = -1;
3354  DFEGate.gate_type = U3_OPERATION;
3355  DFEGate.ThetaOver2 = (int32_t)(0);
3356  DFEGate.Phi = (int32_t)(0);
3357  DFEGate.Lambda = (int32_t)(0);
3358  DFEGate.metadata = 0;
3359 
3360  }
3361 /*
3362  for ( int idx=0; idx<gatesNum; idx++ ) {
3363 
3364  std::cout << "target qubit: " << (int)DFEgates[idx].target_qbit << " control qubit: " << (int)DFEgates[idx].control_qbit << " gate type: " << (int)DFEgates[idx].gate_type << std::endl;
3365  }
3366 */
3367 
3368 
3369  return DFEgates;
3370 
3371 }
3372 
3373 
3374 
3379 void Gates_block::convert_to_DFE_gates( const Matrix_real& parameters_mtx, DFEgate_kernel_type* DFEgates, int& start_index ) {
3380 
3381 
3382  int& gate_idx = start_index;
3384  double *parameters_data = parameters_mtx.get_data();
3385  //const_cast <Matrix_real&>(parameters);
3386 
3387 
3388  for(int op_idx = gates.size()-1; op_idx>=0; op_idx--) {
3389 
3390  Gate* gate = gates[op_idx];
3391  DFEgate_kernel_type& DFEGate = DFEgates[gate_idx];
3392 
3393  if (gate->get_type() == CNOT_OPERATION) {
3394  CNOT* cnot_gate = static_cast<CNOT*>(gate);
3395  DFEGate.target_qbit = cnot_gate->get_target_qbit();
3396  DFEGate.control_qbit = cnot_gate->get_control_qbit();
3397  DFEGate.gate_type = CNOT_OPERATION;
3398  DFEGate.ThetaOver2 = (int32_t)(M_PI/2*(1<<25));
3399  DFEGate.Phi = (int32_t)(0);
3400  DFEGate.Lambda = (int32_t)(M_PI*(1<<25));
3401  DFEGate.metadata = 0;
3402  gate_idx = gate_idx + 1;
3403  }
3404  else if (gate->get_type() == CZ_OPERATION) {
3405  CZ* cz_gate = static_cast<CZ*>(gate);
3406  DFEGate.target_qbit = cz_gate->get_target_qbit();
3407  DFEGate.control_qbit = cz_gate->get_control_qbit();
3408  DFEGate.gate_type = CZ_OPERATION;
3409  DFEGate.ThetaOver2 = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3410  DFEGate.Phi = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3411  DFEGate.Lambda = (int32_t)(M_PI*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3412  DFEGate.metadata = 0;
3413  gate_idx = gate_idx + 1;
3414  }
3415  else if (gate->get_type() == CH_OPERATION) {
3416  CH* ch_gate = static_cast<CH*>(gate);
3417  DFEGate.target_qbit = ch_gate->get_target_qbit();
3418  DFEGate.control_qbit = ch_gate->get_control_qbit();
3419  DFEGate.gate_type = CH_OPERATION;
3420  DFEGate.ThetaOver2 = (int32_t)(M_PI/4*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3421  DFEGate.Phi = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3422  DFEGate.Lambda = (int32_t)(M_PI*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3423  DFEGate.metadata = 0;
3424  gate_idx = gate_idx + 1;
3425  }
3426  else if (gate->get_type() == SYC_OPERATION) {
3427  std::string error("Gates_block::convert_to_DFE_gates: SYC_gate not implemented");
3428  throw error;
3429  }
3430  else if (gate->get_type() == U1_OPERATION) {
3431  double lambda = std::fmod(parameters_data[parameter_idx-1], 2*M_PI);
3432  parameter_idx = parameter_idx - 1;
3433 
3434  DFEGate.target_qbit = gate->get_target_qbit();
3435  DFEGate.control_qbit = -1;
3436  DFEGate.gate_type = U1_OPERATION;
3437  DFEGate.ThetaOver2 = (int32_t)(0);
3438  DFEGate.Phi = (int32_t)(0);
3439  DFEGate.Lambda = (int32_t)(lambda*(1<<25));
3440  DFEGate.metadata = 0;
3441  gate_idx = gate_idx + 1;
3442  }
3443  else if (gate->get_type() == U2_OPERATION) {
3444  double phi = std::fmod(parameters_data[parameter_idx-2], 2*M_PI);
3445  double lambda = std::fmod(parameters_data[parameter_idx-1], 2*M_PI);
3446  parameter_idx = parameter_idx - 2;
3447 
3448  DFEGate.target_qbit = gate->get_target_qbit();
3449  DFEGate.control_qbit = -1;
3450  DFEGate.gate_type = U2_OPERATION;
3451  DFEGate.ThetaOver2 = (int32_t)(M_PI/4*(1<<25)); // theta/2 = pi/4 for U2
3452  DFEGate.Phi = (int32_t)(phi*(1<<25));
3453  DFEGate.Lambda = (int32_t)(lambda*(1<<25));
3454  DFEGate.metadata = 0;
3455  gate_idx = gate_idx + 1;
3456  }
3457  else if (gate->get_type() == U3_OPERATION) {
3458  double theta = std::fmod(parameters_data[parameter_idx-3], 4*M_PI);
3459  double phi = std::fmod(parameters_data[parameter_idx-2], 2*M_PI);
3460  double lambda = std::fmod(parameters_data[parameter_idx-1], 2*M_PI);
3461  parameter_idx = parameter_idx - 3;
3462 
3463  DFEGate.target_qbit = gate->get_target_qbit();
3464  DFEGate.control_qbit = -1;
3465  DFEGate.gate_type = U3_OPERATION;
3466  DFEGate.ThetaOver2 = (int32_t)(theta/2.0*(1<<25)); // theta/2
3467  DFEGate.Phi = (int32_t)(phi*(1<<25));
3468  DFEGate.Lambda = (int32_t)(lambda*(1<<25));
3469  DFEGate.metadata = 0;
3470  gate_idx = gate_idx + 1;
3471  }
3472  else if (gate->get_type() == RX_OPERATION) {
3473  // definig the rotation parameter
3474  double varthetaOver2;
3475  // get the inverse parameters of the U3 rotation
3476  RX* rx_gate = static_cast<RX*>(gate);
3477  varthetaOver2 = std::fmod( parameters_data[parameter_idx-1], 2*M_PI);
3478  parameter_idx = parameter_idx - 1;
3479 
3480  DFEGate.target_qbit = rx_gate->get_target_qbit();
3481  DFEGate.control_qbit = -1;
3482  DFEGate.gate_type = RX_OPERATION;
3483  DFEGate.ThetaOver2 = (int32_t)(varthetaOver2*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3484  DFEGate.Phi = (int32_t)(-M_PI/2*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3485  DFEGate.Lambda = (int32_t)(M_PI/2*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3486  DFEGate.metadata = 0;
3487 
3488  gate_idx = gate_idx + 1;
3489  }
3490  else if (gate->get_type() == RY_OPERATION) {
3491  // definig the rotation parameter
3492  double varthetaOver2;
3493  // get the inverse parameters of the U3 rotation
3494  RY* ry_gate = static_cast<RY*>(gate);
3495  varthetaOver2 = std::fmod( parameters_data[parameter_idx-1], 2*M_PI);
3496  parameter_idx = parameter_idx - 1;
3497 
3498  DFEGate.target_qbit = ry_gate->get_target_qbit();
3499  DFEGate.control_qbit = -1;
3500  DFEGate.gate_type = RY_OPERATION;
3501  DFEGate.ThetaOver2 = (int32_t)(varthetaOver2*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3502  DFEGate.Phi = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3503  DFEGate.Lambda = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3504  DFEGate.metadata = 0;
3505 
3506  gate_idx = gate_idx + 1;
3507  }
3508  else if (gate->get_type() == CRY_OPERATION) {
3509  // definig the rotation parameter
3510  double Phi;
3511  // get the inverse parameters of the U3 rotation
3512  CRY* cry_gate = static_cast<CRY*>(gate);
3513  double varthetaOver2 = std::fmod( parameters_data[parameter_idx-1], 2*M_PI);
3514  parameter_idx = parameter_idx - 1;
3515  DFEGate.target_qbit = cry_gate->get_target_qbit();
3516  DFEGate.control_qbit = cry_gate->get_control_qbit();
3517  DFEGate.gate_type = CRY_OPERATION;
3518  DFEGate.ThetaOver2 = (int32_t)(varthetaOver2*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3519  DFEGate.Phi = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3520  DFEGate.Lambda = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3521  DFEGate.metadata = 0;
3522 
3523  gate_idx = gate_idx + 1;
3524  }
3525  else if (gate->get_type() == RZ_OPERATION) { // Did not cehcked
3526 
3527  std::string error("Gates_block::convert_to_DFE_gates: RZ gate not implemented for DFE. Use RZ_P gate instead that differs from RZ gate by a global phase");
3528  throw error;
3529  }
3530  else if (gate->get_type() == RZ_P_OPERATION) {
3531 
3532 
3533  // definig the rotation parameter
3534  double varphi;
3535  // get the inverse parameters of the U3 rotation
3536  RZ* rz_gate = static_cast<RZ*>(gate);
3537  varphi = std::fmod( parameters_data[parameter_idx-1], 2*M_PI);
3538  parameter_idx = parameter_idx - 1;
3539 
3540  DFEGate.target_qbit = rz_gate->get_target_qbit();
3541  DFEGate.control_qbit = -1;
3542  DFEGate.gate_type = RZ_P_OPERATION;
3543  DFEGate.ThetaOver2 = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3544  DFEGate.Phi = (int32_t)(varphi*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3545  DFEGate.Lambda = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3546  DFEGate.metadata = 0;
3547 
3548  gate_idx = gate_idx + 1;
3549  }
3550  else if (gate->get_type() == H_OPERATION) {
3551  // get the inverse parameters of the Hadamard rotation
3552  H* h_gate = static_cast<H*>(gate);
3553 
3554  std::string error("Gates_block::convert_to_DFE_gates: Hadamard gate not implemented");
3555  throw error;
3556 
3557  gate_idx = gate_idx + 1;
3558  }
3559  else if (gate->get_type() == X_OPERATION) {
3560  // get the inverse parameters of the U3 rotation
3561  X* x_gate = static_cast<X*>(gate);
3562 
3563  DFEGate.target_qbit = x_gate->get_target_qbit();
3564  DFEGate.control_qbit = -1;
3565  DFEGate.gate_type = X_OPERATION;
3566  DFEGate.ThetaOver2 = (int32_t)(M_PI/2*(1<<25));
3567  DFEGate.Phi = (int32_t)(0);
3568  DFEGate.Lambda = (int32_t)(M_PI*(1<<25));
3569  DFEGate.metadata = 0;
3570 
3571  gate_idx = gate_idx + 1;
3572  }
3573  else if (gate->get_type() == Y_OPERATION) {
3574  // get the inverse parameters of the U3 rotation
3575  Y* y_gate = static_cast<Y*>(gate);
3576 
3577  DFEGate.target_qbit = y_gate->get_target_qbit();
3578  DFEGate.control_qbit = -1;
3579  DFEGate.gate_type = Y_OPERATION;
3580  DFEGate.ThetaOver2 = (int32_t)(M_PI/2*(1<<25));
3581  DFEGate.Phi = (int32_t)(M_PI/2*(1<<25));
3582  DFEGate.Lambda = (int32_t)(M_PI/2*(1<<25));
3583  DFEGate.metadata = 0;
3584 
3585  gate_idx = gate_idx + 1;
3586  }
3587  else if (gate->get_type() == Z_OPERATION) {
3588  // get the inverse parameters of the U3 rotation
3589  Z* z_gate = static_cast<Z*>(gate);
3590 
3591  DFEGate.target_qbit = z_gate->get_target_qbit();
3592  DFEGate.control_qbit = -1;
3593  DFEGate.gate_type = Z_OPERATION;
3594  DFEGate.ThetaOver2 = (int32_t)(0);
3595  DFEGate.Phi = (int32_t)(0);
3596  DFEGate.Lambda = (int32_t)(M_PI*(1<<25));
3597  DFEGate.metadata = 0;
3598 
3599  gate_idx = gate_idx + 1;
3600  }
3601  else if (gate->get_type() == SX_OPERATION) {
3602  // get the inverse parameters of the U3 rotation
3603  SX* sx_gate = static_cast<SX*>(gate);
3604  std::string error("Gates_block::convert_to_DFE_gates: SX_gate not implemented");
3605  throw error;
3606  }
3607  else if (gate->get_type() == BLOCK_OPERATION) {
3608  Gates_block* block_gate = static_cast<Gates_block*>(gate);
3609  const Matrix_real parameters_layer_mtx(parameters_mtx.get_data() + parameter_idx - gate->get_parameter_num(), 1, gate->get_parameter_num() );
3610  block_gate->convert_to_DFE_gates( parameters_layer_mtx, DFEgates, gate_idx );
3611  parameter_idx = parameter_idx - block_gate->get_parameter_num();
3612  }
3613  else if (gate->get_type() == UN_OPERATION) {
3614  std::string error("Gates_block::convert_to_DFE_gates: UN_gate not implemented");
3615  throw error;
3616  }
3617  else if (gate->get_type() == ON_OPERATION) {
3618 
3619  // THE LAST GATE IS A GENERAL GATE APPENDED IN THE BLOCK-WISE OPTIMISATION ROUTINE OF DECOMPOSITION_BASE
3620  std::string error("Gates_block::convert_to_DFE_gates: ON_gate not implemented");
3621  throw error;
3622  }
3623  else if (gate->get_type() == COMPOSITE_OPERATION) {
3624  std::string error("Gates_block::convert_to_DFE_gates: Composite_gate not implemented");
3625  throw error;
3626  }
3627  else if (gate->get_type() == GENERAL_OPERATION) {
3628  std::string error("Gates_block::convert_to_DFE_gates: general_gate not implemented");
3629  throw error;
3630  }
3631  else if (gate->get_type() == ADAPTIVE_OPERATION) {
3632  // definig the rotation parameter
3633  double Phi;
3634  // get the inverse parameters of the U3 rotation
3635  Adaptive* ad_gate = static_cast<Adaptive*>(gate);
3636  double varthetaOver2 = std::fmod( activation_function(parameters_data[parameter_idx-1], ad_gate->get_limit()), 2*M_PI);
3637  parameter_idx = parameter_idx - 1;
3638  DFEGate.target_qbit = ad_gate->get_target_qbit();
3639  DFEGate.control_qbit = ad_gate->get_control_qbit();
3640  DFEGate.gate_type = ADAPTIVE_OPERATION;
3641  DFEGate.ThetaOver2 = (int32_t)(varthetaOver2*(1<<25));
3642  DFEGate.Phi = (int32_t)(0);
3643  DFEGate.Lambda = (int32_t)(0);
3644  DFEGate.metadata = 0;
3645 
3646  gate_idx = gate_idx + 1;
3647  }
3648  else {
3649  std::string err("Gates_block::convert_to_DFE_gates: unimplemented gate");
3650  throw err;
3651  }
3652 
3653  }
3654 
3655 
3656  return;
3657 
3658 }
3659 
3660 
3661 #endif
3662 
3663 
3664 #ifdef __GROQ__
3665 
3666 //TODO docstring
3667 void
3668 Gates_block::extract_gate_kernels_target_and_control_qubits(std::vector<Matrix> &u3_qbit, std::vector<int> &target_qbit, std::vector<int> &control_qbit, Matrix_real& parameters_mtx)
3669 {
3670 
3671  if ( u3_qbit.size() == 0 ) {
3672  std::map<std::string, int> gate_nums = get_gate_nums();
3673  int gates_total_num = 0;
3674  for( auto it=gate_nums.begin(); it != gate_nums.end(); it++ ) {
3675  gates_total_num = gates_total_num + it->second;
3676  }
3677 
3678  u3_qbit.reserve( gates_total_num );
3679  target_qbit.reserve( gates_total_num );
3680  control_qbit.reserve( gates_total_num );
3681  }
3682 /*
3683  u3_qbit.reserve(u3_qbit.capacity() + gates.size());
3684  target_qbit.reserve(target_qbit.capacity() + gates.size());
3685  control_qbit.reserve(control_qbit.capacity() + gates.size());
3686 */
3687  double* parameters = parameters_mtx.get_data();
3688 
3689 
3690  for( int idx=0; idx<gates.size(); idx++) {
3691  Gate* operation = gates[idx];
3692  //parameters = parameters + operation->get_parameter_num();
3693 
3694  Matrix_real params_mtx(parameters + operation->get_parameter_start_idx(), 1, operation->get_parameter_num());
3695 
3696  switch (operation->get_type()) {
3697  case CNOT_OPERATION: case CZ_OPERATION:
3698  case CH_OPERATION: {
3699  CNOT* cnot_operation = static_cast<CNOT*>(operation);
3700  u3_qbit.push_back(cnot_operation->calc_one_qubit_u3());
3701  break;
3702  }
3703  case H_OPERATION: {
3704  H* h_operation = static_cast<H*>(operation);
3705  u3_qbit.push_back(h_operation->calc_one_qubit_u3());
3706  break;
3707  }
3708  case X_OPERATION: {
3709  X* x_operation = static_cast<X*>(operation);
3710  u3_qbit.push_back(x_operation->calc_one_qubit_u3());
3711  break;
3712  }
3713  case Y_OPERATION: {
3714  Y* y_operation = static_cast<Y*>(operation);
3715  u3_qbit.push_back(y_operation->calc_one_qubit_u3());
3716  break;
3717  }
3718  case Z_OPERATION: {
3719  Z* z_operation = static_cast<Z*>(operation);
3720  u3_qbit.push_back(z_operation->calc_one_qubit_u3());
3721  break;
3722  }
3723  case T_OPERATION: {
3724  T* t_operation = static_cast<T*>(operation);
3725  u3_qbit.push_back(t_operation->calc_one_qubit_u3());
3726  break;
3727  }
3728  case TDG_OPERATION: {
3729  Tdg* tdg_operation = static_cast<Tdg*>(operation);
3730  u3_qbit.push_back(tdg_operation->calc_one_qubit_u3());
3731  break;
3732  }
3733  case SX_OPERATION: {
3734  SX* sx_operation = static_cast<SX*>(operation);
3735  u3_qbit.push_back(sx_operation->calc_one_qubit_u3());
3736  break;
3737  }
3738  case U1_OPERATION: {
3739  U1* u1_operation = static_cast<U1*>(operation);
3740  u3_qbit.push_back(u1_operation->calc_one_qubit_u3(params_mtx[0]));
3741  break;
3742  }
3743  case U2_OPERATION: {
3744  U2* u2_operation = static_cast<U2*>(operation);
3745  u3_qbit.push_back(u2_operation->calc_one_qubit_u3(params_mtx[0], params_mtx[1]));
3746  break;
3747  }
3748  case U3_OPERATION: {
3749  U3* u3_operation = static_cast<U3*>(operation);
3750  u3_qbit.push_back(u3_operation->calc_one_qubit_u3(params_mtx[0], params_mtx[1], params_mtx[2]));
3751  break;
3752  }
3753  case RX_OPERATION: {
3754  RX* rx_operation = static_cast<RX*>(operation);
3755  // set static values for the angles
3756  double ThetaOver2 = params_mtx[0];
3757  double Phi = -M_PI/2;
3758  double Lambda = M_PI/2;
3759  rx_operation->parameters_for_calc_one_qubit(ThetaOver2, Phi, Lambda);
3760  u3_qbit.push_back(rx_operation->calc_one_qubit_u3(ThetaOver2, Phi, Lambda));
3761  break;
3762  }
3763  case RY_OPERATION: {
3764  RY* ry_operation = static_cast<RY*>(operation);
3765  double ThetaOver2 = params_mtx[0];
3766  double Phi = 0.0;
3767  double Lambda = 0.0;
3768  ry_operation->parameters_for_calc_one_qubit(ThetaOver2, Phi, Lambda);
3769  u3_qbit.push_back(ry_operation->calc_one_qubit_u3(ThetaOver2, Phi, Lambda));
3770  break;
3771  }
3772  case CRY_OPERATION: {
3773  CRY* cry_operation = static_cast<CRY*>(operation);
3774  double ThetaOver2, Phi, Lambda;
3775  ThetaOver2 = params_mtx[0];
3776  cry_operation->parameters_for_calc_one_qubit(ThetaOver2, Phi, Lambda);
3777  u3_qbit.push_back(cry_operation->calc_one_qubit_u3(ThetaOver2, Phi, Lambda));
3778  break;
3779  }
3780  case RZ_OPERATION: {
3781  RZ* rz_operation = static_cast<RZ*>(operation);
3782  u3_qbit.push_back(rz_operation->calc_one_qubit_u3(params_mtx[0]));
3783  break;
3784  }
3785 /*
3786  case RZ_P_OPERATION: {
3787  RZ_P* rz_p_operation = static_cast<RZ_P*>(operation);
3788  double ThetaOver2, Phi, Lambda;
3789  Phi = params_mtx[0];
3790  rz_p_operation->parameters_for_calc_one_qubit(ThetaOver2, Phi, Lambda);
3791  u3_qbit.push_back(rz_p_operation->calc_one_qubit_u3(ThetaOver2, Phi, Lambda));
3792  break;
3793  }
3794 */
3795  case BLOCK_OPERATION: {
3796 
3797  Gates_block* block_operation = static_cast<Gates_block*>(operation);
3798  //std::vector<Gate*> involved_gates = block_operation->get_gates();
3799 
3800  std::vector<int>&& involved_qubits = block_operation->get_involved_qubits();
3801 
3802  if ( involved_qubits.size() == 1 && block_operation->gates.size() > 1 && block_operation->get_qbit_num() > 1 ) {
3803  // possibly merge successive single qubit gates
3804 
3805  Gates_block gates_block_mini = Gates_block(1);
3806 
3807  for (int idx=0; idx<block_operation->gates.size(); idx++){
3808  Gate* gate = block_operation->gates[idx]->clone();
3809  gate->set_target_qbit(0);
3810  gate->set_qbit_num(1);
3811 
3812  gates_block_mini.add_gate(gate);
3813  }
3814 
3815  Matrix merged_kernel = create_identity(2);
3816 
3817  gates_block_mini.apply_to(params_mtx, merged_kernel);
3818 
3819  u3_qbit.push_back( merged_kernel );
3820  target_qbit.push_back( involved_qubits[0] );
3821  control_qbit.push_back( -1 );
3822 
3823  }
3824  else {
3825  block_operation->extract_gate_kernels_target_and_control_qubits(u3_qbit, target_qbit, control_qbit, params_mtx);
3826  }
3827  continue;
3828  }
3829  //case ADAPTIVE_OPERATION:
3830  //case SYC_OPERATION:
3831  //case UN_OPERATION:
3832  //case ON_OPERATION:
3833  //case COMPOSITE_OPERATION:
3834  //case GENERAL_OPERATION:
3835  default:
3836  std::string err("Optimization_Interface::apply_to: unimplemented gate (" + std::to_string(operation->get_type()) + ")");
3837  throw err;
3838  }
3839 
3840  target_qbit.push_back(operation->get_target_qbit());
3841  control_qbit.push_back(operation->get_control_qbit());
3842  }
3843 
3844 
3845 
3846 }
3847 #endif
3848 
3849 
3850 
3855 void
3856 export_gate_list_to_binary(Matrix_real& parameters, Gates_block* gates_block, const std::string& filename, int verbosity) {
3857 
3858  std::stringstream sstream;
3859  sstream << "Exporting circuit into binary format. Filename: " << filename << std::endl;
3860  logging log;
3861  log.verbose = verbosity;
3862  log.print(sstream, 3);
3863 
3864  FILE* pFile;
3865  const char* c_filename = filename.c_str();
3866 
3867  pFile = fopen(c_filename, "wb");
3868  if (pFile==NULL) {fputs ("File error",stderr); exit (1);}
3869 
3870  export_gate_list_to_binary( parameters, gates_block, pFile, verbosity );
3871 
3872  fclose(pFile);
3873  return;
3874 
3875 }
3876 
3877 
3878 
3883 void
3884 export_gate_list_to_binary(Matrix_real& parameters, Gates_block* gates_block, FILE* pFile, int verbosity) {
3885 
3886  int qbit_num = gates_block->get_qbit_num();
3887  fwrite(&qbit_num, sizeof(int), 1, pFile);
3888 
3889  int parameter_num = gates_block->get_parameter_num();
3890  fwrite(&parameter_num, sizeof(int), 1, pFile);
3891 
3892 
3893  int gates_num = gates_block->get_gate_num();
3894  fwrite(&gates_num, sizeof(int), 1, pFile);
3895 
3896 
3897 
3898  std::vector<Gate*> gates = gates_block->get_gates();
3899  double* parameters_data = parameters.get_data();
3900 
3901  for ( std::vector<Gate*>::iterator it=gates.begin(); it != gates.end(); ++it ) {
3902  Gate* op = *it;
3903 
3904  gate_type gt_type = op->get_type();
3905 
3906  fwrite(&gt_type, sizeof(gate_type), 1, pFile);
3907 
3908  int parameter_num = op->get_parameter_num();
3909 
3910  if (gt_type == CNOT_OPERATION || gt_type == CZ_OPERATION || gt_type == CH_OPERATION || gt_type == SYC_OPERATION) {
3911  int target_qbit = op->get_target_qbit();
3912  int control_qbit = op->get_control_qbit();
3913  fwrite(&target_qbit, sizeof(int), 1, pFile);
3914  fwrite(&control_qbit, sizeof(int), 1, pFile);
3915  }
3916  else if (gt_type == U1_OPERATION || gt_type == U2_OPERATION || gt_type == U3_OPERATION ) {
3917  int target_qbit = op->get_target_qbit();
3918  fwrite(&target_qbit, sizeof(int), 1, pFile);
3919  fwrite(parameters_data, sizeof(double), parameter_num, pFile);
3920  }
3921  else if (gt_type == RX_OPERATION || gt_type == RY_OPERATION || gt_type == RZ_OPERATION ) {
3922  int target_qbit = op->get_target_qbit();
3923  fwrite(&target_qbit, sizeof(int), 1, pFile);
3924 
3925  fwrite(parameters_data, sizeof(double), parameter_num, pFile);
3926  }
3927  else if (gt_type == CRY_OPERATION) {
3928  int target_qbit = op->get_target_qbit();
3929  int control_qbit = op->get_control_qbit();
3930  fwrite(&target_qbit, sizeof(int), 1, pFile);
3931  fwrite(&control_qbit, sizeof(int), 1, pFile);
3932 
3933  fwrite(parameters_data, sizeof(double), parameter_num, pFile);
3934  }
3935 
3936  else if (gt_type == X_OPERATION || gt_type == Y_OPERATION || gt_type == Z_OPERATION || gt_type == SX_OPERATION || gt_type == H_OPERATION) {
3937  int target_qbit = op->get_target_qbit();
3938  fwrite(&target_qbit, sizeof(int), 1, pFile);
3939  }
3940  else if (gt_type == BLOCK_OPERATION) {
3941  Gates_block* block_op = static_cast<Gates_block*>( op );
3942  Matrix_real parameters_loc(parameters_data, 1, parameter_num);
3943  export_gate_list_to_binary( parameters_loc, block_op, pFile );
3944 
3945  }
3946  else if (gt_type == ADAPTIVE_OPERATION) {
3947  int target_qbit = op->get_target_qbit();
3948  int control_qbit = op->get_control_qbit();
3949  fwrite(&target_qbit, sizeof(int), 1, pFile);
3950  fwrite(&control_qbit, sizeof(int), 1, pFile);
3951 
3952  fwrite(parameters_data, sizeof(double), parameter_num, pFile);
3953  }
3954  else {
3955  std::string err("export_gate_list_to_binary: unimplemented gate");
3956  throw err;
3957  }
3958 
3959 
3960  parameters_data = parameters_data + parameter_num;
3961 
3962  }
3963 
3964 }
3965 
3966 
3972 
3973  std::stringstream sstream;
3974  sstream << "Importing quantum circuit from binary file " << filename << std::endl;
3975  logging log;
3976  log.verbose = verbosity;
3977  log.print(sstream, 2);
3978 
3979  FILE* pFile;
3980  const char* c_filename = filename.c_str();
3981 
3982  pFile = fopen(c_filename, "rb");
3983  if (pFile==NULL) {fputs ("File error",stderr); exit (1);}
3984 
3985  Gates_block* ret = import_gate_list_from_binary(parameters, pFile, verbosity);
3986 
3987  fclose(pFile);
3988  return ret;
3989 }
3990 
3996 
3997  std::stringstream sstream;
3998 
3999  int qbit_num;
4000  size_t fread_status;
4001 
4002  fread_status = fread(&qbit_num, sizeof(int), 1, pFile);
4003  sstream << "qbit_num: " << qbit_num << std::endl;
4004  Gates_block* gate_block = new Gates_block(qbit_num);
4005 
4006  int parameter_num;
4007  fread_status = fread(&parameter_num, sizeof(int), 1, pFile);
4008  sstream << "parameter_num: " << parameter_num << std::endl;
4009  parameters = Matrix_real(1, parameter_num);
4010  double* parameters_data = parameters.get_data();
4011 
4012  int gates_num;
4013  fread_status = fread(&gates_num, sizeof(int), 1, pFile);
4014  sstream << "gates_num: " << gates_num << std::endl;
4015 
4016  std::vector<int> gate_block_level_gates_num;
4017  std::vector<Gates_block*> gate_block_levels;
4018  gate_block_level_gates_num.push_back( gates_num );
4019  gate_block_levels.push_back(gate_block);
4020  int current_level = 0;
4021 
4022 
4023 
4024  int iter_max = 1e5;
4025  int iter = 0;
4026  while ( gate_block_level_gates_num[0] > 0 && iter < iter_max) {
4027 
4028  gate_type gt_type;
4029  fread_status = fread(&gt_type, sizeof(gate_type), 1, pFile);
4030 
4031  //std::cout << "gate type: " << gt_type << std::endl;
4032 
4033  if (gt_type == CNOT_OPERATION) {
4034  sstream << "importing CNOT gate" << std::endl;
4035 
4036  int target_qbit;
4037  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4038  sstream << "target_qbit: " << target_qbit << std::endl;
4039 
4040  int control_qbit;
4041  fread_status = fread(&control_qbit, sizeof(int), 1, pFile);
4042  sstream << "control_qbit: " << control_qbit << std::endl;
4043 
4044  gate_block_levels[current_level]->add_cnot(target_qbit, control_qbit);
4045  gate_block_level_gates_num[current_level]--;
4046  }
4047  else if (gt_type == CZ_OPERATION) {
4048  sstream << "importing CZ gate" << std::endl;
4049 
4050  int target_qbit;
4051  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4052  sstream << "target_qbit: " << target_qbit << std::endl;
4053 
4054  int control_qbit;
4055  fread_status = fread(&control_qbit, sizeof(int), 1, pFile);
4056  sstream << "control_qbit: " << control_qbit << std::endl;
4057 
4058  gate_block_levels[current_level]->add_cz(target_qbit, control_qbit);
4059  gate_block_level_gates_num[current_level]--;
4060  }
4061  else if (gt_type == CH_OPERATION) {
4062  sstream << "importing CH gate" << std::endl;
4063 
4064  int target_qbit;
4065  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4066  sstream << "target_qbit: " << target_qbit << std::endl;
4067 
4068  int control_qbit;
4069  fread_status = fread(&control_qbit, sizeof(int), 1, pFile);
4070  sstream << "control_qbit: " << control_qbit << std::endl;
4071 
4072  gate_block_levels[current_level]->add_ch(target_qbit, control_qbit);
4073  gate_block_level_gates_num[current_level]--;
4074  }
4075  else if (gt_type == SYC_OPERATION) {
4076  sstream << "importing SYCAMORE gate" << std::endl;
4077 
4078  int target_qbit;
4079  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4080  sstream << "target_qbit: " << target_qbit << std::endl;
4081 
4082  int control_qbit;
4083  fread_status = fread(&control_qbit, sizeof(int), 1, pFile);
4084  sstream << "control_qbit: " << control_qbit << std::endl;
4085 
4086  gate_block_levels[current_level]->add_syc(target_qbit, control_qbit);
4087  gate_block_level_gates_num[current_level]--;
4088  }
4089  else if (gt_type == U1_OPERATION) {
4090  sstream << "importing U1 gate" << std::endl;
4091 
4092  int target_qbit;
4093  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4094  sstream << "target_qbit: " << target_qbit << std::endl;
4095 
4096  fread_status = fread(parameters_data, sizeof(double), 1, pFile);
4097 
4098  parameters_data++;
4099  gate_block_levels[current_level]->add_u1(target_qbit);
4100  gate_block_level_gates_num[current_level]--;
4101  }
4102  else if (gt_type == U2_OPERATION) {
4103  sstream << "importing U2 gate" << std::endl;
4104 
4105  int target_qbit;
4106  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4107  sstream << "target_qbit: " << target_qbit << std::endl;
4108 
4109  fread_status = fread(parameters_data, sizeof(double), 2, pFile);
4110 
4111  parameters_data+=2;
4112  gate_block_levels[current_level]->add_u2(target_qbit);
4113  gate_block_level_gates_num[current_level]--;
4114  }
4115  else if (gt_type == U3_OPERATION) {
4116  sstream << "importing U3 gate" << std::endl;
4117 
4118  int target_qbit;
4119  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4120  sstream << "target_qbit: " << target_qbit << std::endl;
4121 
4122  fread_status = fread(parameters_data, sizeof(double), 3, pFile);
4123 
4124  parameters_data += 3;
4125  gate_block_levels[current_level]->add_u3(target_qbit);
4126  gate_block_level_gates_num[current_level]--;
4127  }
4128  else if (gt_type == RX_OPERATION) {
4129 
4130  sstream << "importing RX gate" << std::endl;
4131 
4132  int target_qbit;
4133  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4134  sstream << "target_qbit: " << target_qbit << std::endl;
4135 
4136  fread_status = fread(parameters_data, sizeof(double), 1, pFile);
4137  parameters_data++;
4138 
4139  gate_block_levels[current_level]->add_rx(target_qbit);
4140  gate_block_level_gates_num[current_level]--;
4141 
4142  }
4143  else if (gt_type == RY_OPERATION) {
4144 
4145  sstream << "importing RY gate" << std::endl;
4146 
4147  int target_qbit;
4148  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4149  sstream << "target_qbit: " << target_qbit << std::endl;
4150 
4151  fread_status = fread(parameters_data, sizeof(double), 1, pFile);
4152  parameters_data++;
4153 
4154  gate_block_levels[current_level]->add_ry(target_qbit);
4155  gate_block_level_gates_num[current_level]--;
4156 
4157  }
4158  else if (gt_type == CRY_OPERATION) {
4159 
4160  sstream << "importing CRY gate" << std::endl;
4161 
4162  int target_qbit;
4163  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4164  sstream << "target_qbit: " << target_qbit << std::endl;
4165 
4166  int control_qbit;
4167  fread_status = fread(&control_qbit, sizeof(int), 1, pFile);
4168  sstream << "control_qbit: " << control_qbit << std::endl;
4169 
4170  fread_status = fread(parameters_data, sizeof(double), 1, pFile);
4171  parameters_data++;
4172 
4173  gate_block_levels[current_level]->add_cry(target_qbit, control_qbit);
4174  gate_block_level_gates_num[current_level]--;
4175 
4176  }
4177  else if (gt_type == RZ_OPERATION) {
4178 
4179  sstream << "importing RZ gate" << std::endl;
4180 
4181  int target_qbit;
4182  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4183  sstream << "target_qbit: " << target_qbit << std::endl;
4184 
4185  fread_status = fread(parameters_data, sizeof(double), 1, pFile);
4186  parameters_data++;
4187 
4188  gate_block_levels[current_level]->add_rz(target_qbit);
4189  gate_block_level_gates_num[current_level]--;
4190 
4191  }
4192  else if (gt_type == H_OPERATION) {
4193 
4194  sstream << "importing Hadamard gate" << std::endl;
4195 
4196  int target_qbit;
4197  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4198  sstream << "target_qbit: " << target_qbit << std::endl;
4199 
4200  gate_block_levels[current_level]->add_h(target_qbit);
4201  gate_block_level_gates_num[current_level]--;
4202 
4203  }
4204  else if (gt_type == X_OPERATION) {
4205 
4206  sstream << "importing X gate" << std::endl;
4207 
4208  int target_qbit;
4209  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4210  sstream << "target_qbit: " << target_qbit << std::endl;
4211 
4212  gate_block_levels[current_level]->add_x(target_qbit);
4213  gate_block_level_gates_num[current_level]--;
4214 
4215  }
4216  else if (gt_type == Y_OPERATION) {
4217 
4218  sstream << "importing Y gate" << std::endl;
4219 
4220  int target_qbit;
4221  fread(&target_qbit, sizeof(int), 1, pFile);
4222  sstream << "target_qbit: " << target_qbit << std::endl;
4223 
4224  gate_block_levels[current_level]->add_y(target_qbit);
4225  gate_block_level_gates_num[current_level]--;
4226 
4227  }
4228  else if (gt_type == Z_OPERATION) {
4229 
4230  sstream << "importing Z gate" << std::endl;
4231 
4232  int target_qbit;
4233  fread(&target_qbit, sizeof(int), 1, pFile);
4234  sstream << "target_qbit: " << target_qbit << std::endl;
4235 
4236  gate_block_levels[current_level]->add_z(target_qbit);
4237  gate_block_level_gates_num[current_level]--;
4238 
4239  }
4240  else if (gt_type == T_OPERATION) {
4241 
4242  sstream << "importing T gate" << std::endl;
4243 
4244  int target_qbit;
4245  fread(&target_qbit, sizeof(int), 1, pFile);
4246  sstream << "target_qbit: " << target_qbit << std::endl;
4247 
4248  gate_block_levels[current_level]->add_t(target_qbit);
4249  gate_block_level_gates_num[current_level]--;
4250 
4251  }
4252  else if (gt_type == TDG_OPERATION) {
4253 
4254  sstream << "importing Tdg gate" << std::endl;
4255 
4256  int target_qbit;
4257  fread(&target_qbit, sizeof(int), 1, pFile);
4258  sstream << "target_qbit: " << target_qbit << std::endl;
4259 
4260  gate_block_levels[current_level]->add_t(target_qbit);
4261  gate_block_level_gates_num[current_level]--;
4262 
4263  }
4264  else if (gt_type == SX_OPERATION) {
4265 
4266  sstream << "importing SX gate" << std::endl;
4267 
4268  int target_qbit;
4269  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4270  sstream << "target_qbit: " << target_qbit << std::endl;
4271 
4272  gate_block_levels[current_level]->add_sx(target_qbit);
4273  gate_block_level_gates_num[current_level]--;
4274 
4275  }
4276  else if (gt_type == BLOCK_OPERATION) {
4277 
4278 
4279  sstream << "******* importing gates block ********" << std::endl;
4280 
4281  int qbit_num_loc;
4282  fread_status = fread(&qbit_num_loc, sizeof(int), 1, pFile);
4283  //std::cout << "qbit_num_loc: " << qbit_num_loc << std::endl;
4284  Gates_block* gate_block_inner = new Gates_block(qbit_num_loc);
4285 
4286  int parameter_num_loc;
4287  fread_status = fread(&parameter_num_loc, sizeof(int), 1, pFile);
4288  //std::cout << "parameter_num_loc: " << parameter_num_loc << std::endl;
4289 
4290 
4291  int gates_num_loc;
4292  fread_status = fread(&gates_num_loc, sizeof(int), 1, pFile);
4293  //std::cout << "gates_num_loc: " << gates_num_loc << std::endl;
4294 
4295  gate_block_levels.push_back( gate_block_inner );
4296  gate_block_level_gates_num.push_back(gates_num_loc);
4297  current_level++;
4298  }
4299  else if (gt_type == ADAPTIVE_OPERATION) {
4300 
4301  sstream << "importing adaptive gate" << std::endl;
4302 
4303  int target_qbit;
4304  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4305  sstream << "target_qbit: " << target_qbit << std::endl;
4306 
4307  int control_qbit;
4308  fread_status = fread(&control_qbit, sizeof(int), 1, pFile);
4309  sstream << "control_qbit: " << control_qbit << std::endl;
4310 
4311  fread_status = fread(parameters_data, sizeof(double), 1, pFile);
4312  parameters_data++;
4313 
4314  gate_block_levels[current_level]->add_adaptive(target_qbit, control_qbit);
4315  gate_block_level_gates_num[current_level]--;
4316 
4317  }
4318  else {
4319  std::string err("import_gate_list_from_binary: unimplemented gate");
4320  throw err;
4321  }
4322 
4323 
4324  if ( gate_block_level_gates_num[current_level] == 0 ) {
4325  gate_block_levels[ current_level-1 ]->add_gate( static_cast<Gate*>(gate_block_levels[ current_level ]) );
4326  gate_block_levels.pop_back();
4327  gate_block_level_gates_num.pop_back();
4328  current_level--;
4329  gate_block_level_gates_num[current_level]--;
4330  sstream << "finishing gates block" << std::endl;
4331  }
4332 
4333 
4334  iter++;
4335  }
4336 
4337  logging log;
4338  log.verbose = verbosity;
4339  log.print(sstream, 4);
4340 
4341 
4342  if ( iter == iter_max ) {
4343  std::string error("Corrupted input file, reached end of the file before contructing the whole gate structure");
4344  throw error;
4345  }
4346 
4347  return gate_block;
4348 
4349 }
4350 
4351 
4352 
4359 Matrix_real reverse_parameters( const Matrix_real& parameters_in, std::vector<Gate*>::iterator gates_it, int num_of_gates ) {
4360 
4361  if ( parameters_in.cols > 1 && parameters_in.rows > 1 ) {
4362  std::string error("reverse_parameters: Input array should have a single column or a single row.");
4363  throw error;
4364  }
4365 
4366 //return parameters_in.copy();
4367 
4368  // determine the number of parameters
4369  int parameters_num_total = 0;
4370  for (int idx=0; idx<num_of_gates; idx++) {
4371 
4372  // The current gate
4373  Gate* gate = *(gates_it++);
4374  parameters_num_total = parameters_num_total + gate->get_parameter_num();
4375 
4376  }
4377 
4378 
4379  if ( parameters_num_total == 0) {
4380  return Matrix_real(0,0);
4381  }
4382 
4383  //std::cout << "uu" << std::endl;
4384  //parameters_in.print_matrix();
4385 
4386 
4387  Matrix_real parameters_ret(1, parameters_num_total);
4388  int parameter_num_copied = 0;
4389 
4390  // apply the gate operations on the inital matrix
4391  for (int idx=num_of_gates-0; idx>0; idx--) {
4392 
4393  // The current gate
4394  Gate* gate = *(--gates_it);
4395 
4396  int parameter_num_gate = gate->get_parameter_num();
4397 
4398  if ( parameter_num_gate == 0 ) {
4399  continue;
4400  }
4401 
4402  else if (gate->get_type() == BLOCK_OPERATION ) {
4403 
4404  //std::cout << "block: " << parameter_num_gate << " " << parameters_num_total << std::endl;
4405  parameters_num_total = parameters_num_total - gate->get_parameter_num();
4406 
4407  Matrix_real parameters_of_block( parameters_in.get_data()+parameters_num_total, 1, parameter_num_gate );
4408  //parameters_of_block.print_matrix();
4409 
4410  Gates_block* block_gate = static_cast<Gates_block*>( gate );
4411 
4412  std::vector<Gate*> gates_loc = block_gate->get_gates();
4413 
4414  Matrix_real parameters_of_block_reversed = reverse_parameters( parameters_of_block, gates_loc.begin(), gates_loc.size() );
4415 
4416  //parameters_of_block_reversed.print_matrix();
4417 
4418  memcpy( parameters_ret.get_data()+parameter_num_copied, parameters_of_block_reversed.get_data(), parameters_of_block_reversed.size()*sizeof(double) );
4419  parameter_num_copied = parameter_num_copied + parameters_of_block_reversed.size();
4420 
4421  //parameters_ret.print_matrix();
4422 
4423  }
4424 
4425  else {
4426 
4427  //std::cout << parameter_num_gate << std::endl;
4428 
4429  parameters_num_total = parameters_num_total - gate->get_parameter_num();
4430  memcpy( parameters_ret.get_data()+parameter_num_copied, parameters_in.get_data()+parameters_num_total, gate->get_parameter_num()*sizeof(double) );
4431  parameter_num_copied = parameter_num_copied + gate->get_parameter_num();
4432 
4433  }
4434 
4435 
4436  }
4437 
4438 
4439 
4440 
4441  return parameters_ret;
4442 
4443 
4444 
4445 
4446 }
4447 
4448 
4449 
4450 
4457 Matrix_real inverse_reverse_parameters( const Matrix_real& parameters_in, std::vector<Gate*>::iterator gates_it, int num_of_gates ) {
4458 
4459  if ( parameters_in.cols > 1 && parameters_in.rows > 1 ) {
4460  std::string error("reverse_parameters: Input array should have a single column or a single row.");
4461  throw error;
4462  }
4463 
4464 
4465  // determine the number of parameters
4466  int parameters_num_total = 0;
4467  for (int idx=0; idx<num_of_gates; idx++) {
4468 
4469  // The current gate
4470  Gate* gate = *(gates_it++);
4471  parameters_num_total = parameters_num_total + gate->get_parameter_num();
4472 
4473  }
4474 
4475 
4476  if ( parameters_num_total == 0) {
4477  return Matrix_real(0,0);
4478  }
4479 
4480  //std::cout << "uu" << std::endl;
4481  //parameters_in.print_matrix();
4482 
4483 
4484  Matrix_real parameters_ret(1, parameters_num_total);
4485  int parameter_num_copied = 0;
4486 
4487  // apply the gate operations on the inital matrix
4488  for (int idx=num_of_gates-0; idx>0; idx--) {
4489 
4490  // The current gate
4491  Gate* gate = *(--gates_it);
4492 
4493  int parameter_num_gate = gate->get_parameter_num();
4494 
4495  if ( parameter_num_gate == 0 ) {
4496  continue;
4497  }
4498 
4499  else if (gate->get_type() == BLOCK_OPERATION ) {
4500 
4501  //std::cout << "block: " << parameter_num_gate << " " << parameters_num_total << std::endl;
4502  parameters_num_total = parameters_num_total - gate->get_parameter_num();
4503 
4504  Matrix_real parameters_of_block( parameters_in.get_data()+parameters_num_total, 1, parameter_num_gate );
4505  //parameters_of_block.print_matrix();
4506 
4507  Gates_block* block_gate = static_cast<Gates_block*>( gate );
4508 
4509  std::vector<Gate*> gates_loc = block_gate->get_gates();
4510 
4511  Matrix_real parameters_of_block_reversed = reverse_parameters( parameters_of_block, gates_loc.begin(), gates_loc.size() );
4512 
4513  //parameters_of_block_reversed.print_matrix();
4514 
4515  memcpy( parameters_ret.get_data()+parameter_num_copied, parameters_of_block_reversed.get_data(), parameters_of_block_reversed.size()*sizeof(double) );
4516  parameter_num_copied = parameter_num_copied + parameters_of_block_reversed.size();
4517 
4518  //parameters_ret.print_matrix();
4519 
4520  }
4521 
4522  else {
4523 
4524  //std::cout << parameter_num_gate << std::endl;
4525 
4526  parameters_num_total = parameters_num_total - gate->get_parameter_num();
4527  memcpy( parameters_ret.get_data()+parameters_num_total, parameters_in.get_data()+parameter_num_copied, gate->get_parameter_num()*sizeof(double) );
4528  parameter_num_copied = parameter_num_copied + gate->get_parameter_num();
4529 
4530  }
4531 
4532 
4533  }
4534 
4535 
4536 
4537 
4538  return parameters_ret;
4539 
4540 
4541 
4542 
4543 }
4544 
Matrix calc_one_qubit_u3()
Set static values for matrix of the gates.
Definition: CNOT.cpp:211
std::vector< Gate * > parents
list of parent gates to be applied in the circuit prior to this current gate
Definition: Gate.h:95
bool isnan()
Call to check the array for NaN entries.
Definition: matrix.cpp:128
Header file for a class representing the T gate.
Gates_block * get_flat_circuit()
Method to generate a flat circuit.
A class representing a U3 gate.
Definition: U3.h:36
void add_adaptive(int target_qbit, int control_qbit)
Append a Adaptive gate to the list of gates.
A class representing a U3 gate.
Definition: X.h:36
virtual void apply_from_right(Matrix_real &parameters, Matrix &input)
Call to apply the gate on the input array/matrix by input*U3.
Definition: RY.cpp:141
Header file for a class representing a single qubit gate with custom gate kernel. ...
virtual void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the operation.
Definition: ON.cpp:247
crot_type get_subtype()
Definition: CROT.cpp:527
void add_composite_to_front()
Add a Composite gate to the front of the list of gates.
int get_chained_gates_num()
Call to retrieve the number of gates that should be chained up during the execution of the DFE librar...
Definition: common_DFE.cpp:220
Base class for the representation of general gate operations.
Definition: Composite.h:47
void parameters_for_calc_one_qubit(double &ThetaOver2, double &Phi, double &Lambda)
Calculate the matrix of a U3 gate gate corresponding to the given parameters acting on a single qbit ...
Definition: RY.cpp:208
void add_cz_nu(int target_qbit, int control_qbit)
Append a CZ_NU gate to the list of gates.
Matrix calc_one_qubit_u3()
Set static values for matrix of the gates.
Definition: X.cpp:284
void apply_to_list(Matrix_real &parameters, std::vector< Matrix > &inputs, int parallel)
Call to apply the gate on the input array/matrix by U3*input.
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
Header file for a class representing a rotation gate around the X axis.
void release_gate(int idx)
Call to release one gate in the list.
void determine_parents(Gate *gate)
Call to obtain the parent gates in the circuit.
void add_z_to_front(int target_qbit)
Add a Z gate to the front of the list of gates.
Header file for a class for a composite gate operation.
void add_child(Gate *child)
Call to add a child gate to the current gate.
Definition: Gate.cpp:426
void add_h(int target_qbit)
Append a Hadamard gate to the list of gates.
A class representing a U2 gate.
Definition: U2.h:36
virtual Matrix get_matrix()
Call to retrieve the operation matrix.
Definition: Gate.cpp:129
void clear_children()
Call to erase data on children.
Definition: Gate.cpp:441
A class representing a custom_kernel_1qubit_gate gate.
Header file for a class representing the X gate.
Matrix calc_one_qubit_u3()
Set static values for matrix of the gates.
Definition: H.cpp:291
std::map< std::string, int > get_gate_nums()
Call to get the number of the individual gate types in the list of gates.
Header file for a class representing the Y gate.
void fragment_circuit()
void add_x(int target_qbit)
Append a X gate to the list of gates.
void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the gate.
Definition: H.cpp:268
int control_qbit
The index of the qubit which acts as a control qubit (control_qbit >= 0) in controlled operations...
Definition: Gate.h:87
virtual std::vector< Matrix > apply_derivate_to(Matrix_real &parameters_mtx_in, Matrix &input, int parallel)
Call to evaluate the derivate of the circuit on an inout with respect to all of the free parameters...
Definition: Gate.cpp:271
Matrix calc_one_qubit_u3()
Set static values for matrix of the gates.
Definition: Y.cpp:234
void add_cz_nu_to_front(int target_qbit, int control_qbit)
Add a CZ_NU gate to the front of the list of gates.
virtual Gate * clone()
Call to create a clone of the present class.
Definition: Gate.cpp:513
void add_gate(Gate *gate)
Append a general gate to the list of gates.
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
void apply_from_right(Matrix_real &parameters, Matrix &input)
Call to apply the gate on the input array/matrix by input*U3.
Definition: Adaptive.cpp:142
Header file for a class representing a controlled rotation gate around the Y axis.
void add_u2(int target_qbit)
Append a U2 gate to the list of gates.
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 the SX axis.
std::vector< int > get_involved_qubits()
Call to get the qubits involved in the gates stored in the block of gates.
virtual void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the operation.
Definition: UN.cpp:246
void add_cnot_to_front(int target_qbit, int control_qbit)
Add a C_NOT gate gate to the front of the list of gates.
void parameters_for_calc_one_qubit(double &ThetaOver2, double &Phi, double &Lambda)
Calculate the matrix of a U3 gate gate corresponding to the given parameters acting on a single qbit ...
Definition: RX.cpp:207
int max_fusion
maximal number of qubits in partitions
Definition: Gates_block.h:57
void add_u1(int target_qbit)
Append a U1 gate to the list of gates.
void add_on_to_front()
Add a OUN gate to the front of the list of gates.
Header file for a class representing a controlled rotation gate around the Y axis.
void apply_from_right(Matrix_real &parameters, Matrix &input)
Call to apply the gate on the input array/matrix by input*CZ.
Definition: CZ_NU.cpp:162
int target_qbit
The index of the qubit on which the operation acts (target_qbit >= 0)
Definition: Gate.h:85
Matrix_real reverse_parameters(const Matrix_real &parameters_in, std::vector< Gate *>::iterator gates_it, int num_of_gates)
Call to reverse the order of the parameters in an array.
void apply_from_right(Matrix_real &parameters, Matrix &input)
Call to apply the gate on the input array/matrix by input*Gate.
Definition: UN.cpp:186
std::vector< Gate * > get_gates()
Call to get the gates stored in the class.
Gates_block * create_remapped_circuit(const std::map< int, int > &qbit_map)
Call to create a new circuit with remapped qubits.
void release_gates()
Call to release the stored gates.
virtual void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the gates (Obsolete function)
std::vector< int > block_type
Definition: Gates_block.h:60
Header file for a class representing a CH operation.
void get_parameter_max(Matrix_real &range_max)
data
load the unitary from file
Definition: example.py:51
void add_r(int target_qbit)
Append a R gate to the list of gates.
std::vector< std::vector< int > > involved_qbits
Definition: Gates_block.h:58
Header file for a class responsible for grouping gates into subcircuits. (Subcircuits can be nested) ...
A class representing a U3 gate.
Definition: Tdg.h:35
Header file for a class representing the Tdg gate.
int layer_num
number of gate layers
Definition: Gates_block.h:48
void add_cnot(int target_qbit, int control_qbit)
Append a CNOT gate gate to the list of gates.
QGD_Complex16 mult(QGD_Complex16 &a, QGD_Complex16 &b)
Call to calculate the product of two complex scalars.
Definition: common.cpp:259
A class representing a U3 gate.
Definition: U1.h:36
Matrix calc_one_qubit_u3()
Set static values for matrix of the gates.
Definition: SX.cpp:292
bool fragmented
boolean variable indicating whether the circuit was already partitioned or not
Definition: Gates_block.h:54
void add_cz_to_front(int target_qbit, int control_qbit)
Add a CZ gate gate to the front of the list of gates.
virtual void apply_to(Matrix_real &parameters_mtx, Matrix &input, int parallel=0)
Call to apply the gate on the input array/matrix Gates_block*input.
int matrix_size
The size N of the NxN matrix associated with the operations.
Definition: Gate.h:89
scalar * get_data() const
Call to get the pointer to the stored data.
void add_crot(int target_qbit, int control_qbit, crot_type subtype_in)
Append a CNOT gate gate to the list of gates.
void add_rz_to_front(int target_qbit)
Add a RZ gate to the front of the list of gates.
void add_r_to_front(int target_qbit)
Add a R gate to the front of the list of gates.
void add_un_to_front()
Add a UN gate to the front of the list of gates.
Gates_block * import_gate_list_from_binary(Matrix_real &parameters, const std::string &filename, int verbosity)
?????????
int get_gate_num()
Call to get the number of gates grouped in the class.
void add_h_to_front(int target_qbit)
Add a Hadamard gate to the front of the list of gates.
virtual void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the gate.
Definition: U3.cpp:271
std::vector< Gate * > gates
The list of stored gates.
Definition: Gates_block.h:46
A class representing a CROT gate.
Definition: CROT.h:39
void add_x_to_front(int target_qbit)
Add a X gate to the front of the list of gates.
void add_sx_to_front(int target_qbit)
Add a SX gate to the front of the list of gates.
void apply_from_right(Matrix_real &parameters, Matrix &input)
Call to apply the gate on the input array/matrix by input*Gate.
Definition: Composite.cpp:183
A class representing a CZ operation.
Definition: CZ.h:36
Header file for a class representing a CNOT operation.
std::vector< int > block_end
Definition: Gates_block.h:59
A class containing basic methods for setting up the verbosity level.
Definition: logging.h:43
void apply_from_right(Matrix_real &parameters, Matrix &input)
Call to apply the gate on the input array/matrix by input*U3.
Definition: RZ.cpp:149
void apply_large_kernel_to_input_AVX(Matrix &unitary, Matrix &input, std::vector< int > involved_qbits, const int &matrix_size)
Matrix calc_one_qubit_u3()
Set static values for matrix of the gates.
Definition: T.cpp:241
void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the gate.
Definition: SX.cpp:269
virtual void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the gate.
Definition: CROT.cpp:547
void add_y_to_front(int target_qbit)
Add a Y gate to the front of the list of gates.
A class representing a U3 gate.
Definition: Z.h:36
void add_syc(int target_qbit, int control_qbit)
Append a Sycamore gate (i.e.
A class representing a RZ gate.
Definition: RZ.h:36
gate_type type
The type of the operation (see enumeration gate_type)
Definition: Gate.h:83
int get_parameter_num()
Call to get the number of free parameters.
double get_second_Renyi_entropy(Matrix_real &parameters_mtx, Matrix &input_state, matrix_base< int > &qbit_list)
Call to evaluate the seconf Rényi entropy.
void add_syc_to_front(int target_qbit, int control_qbit)
Add a Sycamore gate (i.e.
virtual void apply_from_right(Matrix_real &parameters, Matrix &input)
Call to apply the gate on the input array/matrix by input*U3.
Definition: U3.cpp:196
void add_ch(int target_qbit, int control_qbit)
Append a CH gate (i.e.
A class representing a CRY gate.
Definition: CRY.h:37
virtual void apply_from_right(Matrix &input)
Call to apply the gate on the input array/matrix by input*Gate.
Definition: Gate.cpp:285
int rows
The number of rows.
Definition: matrix_base.hpp:42
A class representing a CH operation.
Definition: CH.h:36
int cols
The number of columns.
Definition: matrix_base.hpp:44
Header file for a class representing a rotation gate around the Z axis.
void add_ch_to_front(int target_qbit, int control_qbit)
Add a CH gate (i.e.
void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the operation.
Definition: CH.cpp:191
void add_composite()
Append a Composite gate to the list of gates.
Header file for a class representing the Hadamard gate.
virtual Matrix calc_one_qubit_u3(double Theta, double Phi, double Lambda)
Calculate the matrix of a U3 gate gate corresponding to the given parameters acting on a single qbit ...
Definition: Gate.cpp:695
int fragmentation_type
Definition: Gates_block.h:55
void add_u2_to_front(int target_qbit)
Add a U2 gate to the front of the list of gates.
gate_type get_type()
Call to get the type of the operation.
Definition: Gate.cpp:495
virtual void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the operation.
Definition: CNOT.cpp:200
void add_u3(int target_qbit)
Append a U3 gate to the list of gates.
void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the gate.
Definition: T.cpp:219
void add_rz(int target_qbit)
Append a RZ gate to the list of gates.
Header file for a class for the representation of general gate operations on the first qbit_num-1 qub...
void apply_to(Matrix &input)
Call to apply the gate on the input array/matrix by U3*input.
void add_y(int target_qbit)
Append a Y gate to the list of gates.
void reset_dependency_graph()
Method to reset the dependency graph of the gates in the circuit.
void combine(Gates_block *op_block)
Call to append the gates of an gate block to the current block.
void add_ry(int target_qbit)
Append a RY gate to the list of gates.
void set_control_qbit(int control_qbit_in)
Call to set the control qubit for the gate operation.
Definition: Gate.cpp:308
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
void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the gate.
Definition: X.cpp:261
Header file for a class representing a CZ operation.
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
void add_parent(Gate *parent)
Call to add a parent gate to the current gate.
Definition: Gate.cpp:409
void apply_from_right(Matrix_real &parameters, Matrix &input)
Call to apply the gate on the input array/matrix by input*U3.
Definition: R.cpp:149
void set_target_qbit(int target_qbit_in)
Call to set the target qubit for the gate operation.
Definition: Gate.cpp:324
void add_on()
Append a ON gate to the list of gates.
Structure type representing complex numbers in the SQUANDER package.
Definition: QGDTypes.h:38
A class representing a CNOT operation.
Definition: CNOT.h:35
int verbose
Set the verbosity level of the output messages.
Definition: logging.h:50
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...
virtual void apply_from_right(Matrix_real &parameters, Matrix &input)
Call to apply the gate on the input array/matrix by input*CRY.
Definition: CRY.cpp:133
void clear_parents()
Call to erase data on parents.
Definition: Gate.cpp:451
void determine_children(Gate *gate)
Call to obtain the child gates in the circuit.
void add_u1_to_front(int target_qbit)
Add a U1 gate to the front of the list of gates.
int extract_gates(Gates_block *op_block)
Call to extract the gates stored in the class.
void add_cry_to_front(int target_qbit, int control_qbit)
Add a CRY gate to the front of the list of gates.
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
void add_crot_to_front(int target_qbit, int control_qbit, crot_type subtype_in)
Add a C_NOT gate gate to the front of the list of gates.
virtual Gates_block * clone()
Create a clone of the present class.
void apply_from_right(Matrix_real &parameters, Matrix &input)
Call to apply the gate on the input array/matrix by input*U3.
Definition: U1.cpp:129
virtual void apply_from_right(Matrix_real &parameters_mtx, Matrix &input)
Call to apply the gate on the input array/matrix by input*CNOT.
bool contains_adaptive_gate()
Call to determine, whether the circuit contains daptive gate or not.
Class to store data of complex arrays and its properties.
Definition: matrix.h:38
void add_gates_to_front(std::vector< Gate *> gates_in)
Add an array of gates to the front of the list of gates.
void add_gate_to_front(Gate *gate)
Add an gate to the front of the list of gates.
A class representing a Hadamard gate.
Definition: H.h:36
A class representing a U3 gate.
Definition: Y.h:36
void add_z(int target_qbit)
Append a Z gate to the list of gates.
Header file for a class representing a U2 gate.
Header file for a class representing a gate used in adaptive decomposition.
A class representing a U3 gate.
Definition: RY.h:36
int size() const
Call to get the number of the allocated elements.
void add_cry(int target_qbit, int control_qbit)
Append a CRY gate to the list of gates.
void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the gate.
Definition: Z.cpp:219
Gates_block()
Default constructor of the class.
Definition: Gates_block.cpp:64
void add_rx_to_front(int target_qbit)
Add a RX gate to the front of the list of gates.
int get_parameter_num()
Call to get the number of free parameters.
Definition: Gate.cpp:486
void add_tdg_to_front(int target_qbit)
Add a Tdg gate to the front of the list of gates.
A class responsible for grouping two-qubit (CNOT,CZ,CH) and one-qubit gates into layers.
Definition: Gates_block.h:41
Header file for a class representing a U3 gate.
void add_tdg(int target_qbit)
Append a Tdg gate to the list of gates.
A class representing a CZ operation.
Definition: CZ_NU.h:36
void add_u3_to_front(int target_qbit)
Add a U3 gate to the front of the list of gates.
Matrix calc_one_qubit_u3()
Set static values for matrix of the gates.
Definition: Tdg.cpp:241
std::string name
A string labeling the gate operation.
Definition: Gate.h:79
void add_cz(int target_qbit, int control_qbit)
Append a CZ gate gate to the list of gates.
A class representing a U3 gate.
Definition: R.h:36
std::vector< Gate * > children
list of child gates to be applied after this current gate
Definition: Gate.h:97
Fixed point data related to a gate operation.
Definition: common_DFE.h:61
bool is_qbit_present(std::vector< int > involved_qubits, int new_qbit, int num_of_qbits)
Call to check whether the given qubit is involved in the sub-circuit or not.
int get_target_qbit()
Call to get the index of the target qubit.
Definition: Gate.cpp:370
std::vector< int > remove_list_intersection(std::vector< int > &list1, std::vector< int > &list2)
Call to remove those integer elements from list1 which are present in list.
Header file for a class representing a rotation gate around the X axis.
Base class for the representation of general gate operations.
Definition: Gate.h:73
Base class for the representation of general gate operations.
Definition: UN.h:35
Header file for a class representing a rotation gate around the Y axis.
std::string get_name()
Call to get the name label of the gate.
Definition: Gate.cpp:839
virtual std::vector< int > get_involved_qubits()
Call to get the qubits involved in the gate operation.
Definition: Gate.cpp:386
Matrix create_identity(int matrix_size)
Call to create an identity matrix.
Definition: common.cpp:164
void add_gate_nums(std::map< std::string, int > &gate_nums)
Call to add the number of the individual gate types in the circuit to the map given in the argument...
int get_limit()
???????????
Definition: Adaptive.cpp:270
void add_ry_to_front(int target_qbit)
Add a RY gate to the front of the list of gates.
int parameter_num
the number of free parameters of the operation
Definition: Gate.h:91
virtual ~Gates_block()
Destructor of the class.
Definition: CROT.h:34
virtual void apply_to_list(std::vector< Matrix > &inputs, int parallel)
Call to apply the gate on a list of inputs.
Definition: Gate.cpp:187
void add_rx(int target_qbit)
Append a RX gate to the list of gates.
void apply_from_right(Matrix_real &parameters, Matrix &input)
Call to apply the gate on the input array/matrix by input*Gate.
Definition: ON.cpp:189
Matrix calc_one_qubit_u3(double PhiOver2)
Calculate the matrix of a U3 gate gate corresponding to the given parameters acting on a single qbit ...
Definition: RZ.cpp:243
void apply_from_right(Matrix_real &parameters, Matrix &input)
Call to apply the gate on the input array/matrix by input*U3.
Definition: RX.cpp:139
void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the operation.
Definition: CZ.cpp:184
void set_parents(std::vector< Gate *> &parents_)
Call to set the parents of the current gate.
Definition: Gate.cpp:790
double activation_function(double Phi, int limit)
?????
Definition: common.cpp:34
void add_un()
Append a UN gate to the list of gates.
void export_gate_list_to_binary(Matrix_real &parameters, Gates_block *gates_block, const std::string &filename, int verbosity)
?????????
Matrix copy()
Call to create a copy of the matrix.
Definition: matrix.cpp:105
A class representing a SYC operation.
Definition: SYC.h:36
void insert_gate(Gate *gate, int idx)
Call to insert a gate at a given position.
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
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...
void reset_parameter_start_indices()
Method to reset the parameter start indices of gate operations incorporated in the circuit...
A class representing a CRY gate.
Definition: Adaptive.h:36
Header file for a class representing the Z gate.
int qbit_num
number of qubits spanning the matrix of the operation
Definition: Gate.h:81
Header file for a class for the representation of general gate operations on the first qbit_num-1 qub...
void add_t_to_front(int target_qbit)
Add a T gate to the front of the list of gates.
A class representing a U3 gate.
Definition: SX.h:38
int get_qbit_num()
Call to get the number of qubits composing the unitary.
Definition: Gate.cpp:504
gate_type
Type definition of operation types (also generalized for decomposition classes derived from the class...
Definition: Gate.h:34
A class representing a U3 gate.
Definition: T.h:35
Gate * get_gate(int idx)
Call to get the gates stored in the class.
Base class for the representation of general gate operations.
Definition: ON.h:35
A class representing a U3 gate.
Definition: RX.h:36
virtual void apply_to(Matrix &input, int parallel)
Call to apply the gate on the input array/matrix.
Definition: Gate.cpp:237
void list_gates(const Matrix_real &parameters, int start_index)
Call to print the list of gates stored in the block of gates for a specific set of parameters...
Matrix get_reduced_density_matrix(Matrix_real &parameters_mtx, Matrix &input_state, matrix_base< int > &qbit_list_subset)
Call to evaluate the reduced densiy matrix.
void add_adaptive_to_front(int target_qbit, int control_qbit)
Add a Adaptive gate to the front of the list of gates.
virtual void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the operation.
Definition: Composite.cpp:216
void add_gates(std::vector< Gate *> gates_in)
Append a list of gates to the list of gates.
Header file for a class representing a U1 gate.
Matrix_real inverse_reverse_parameters(const Matrix_real &parameters_in, std::vector< Gate *>::iterator gates_it, int num_of_gates)
Call to inverse-reverse the order of the parameters in an array.
void add_t(int target_qbit)
Append a T gate to the list of gates.
Matrix calc_one_qubit_u3()
Set static values for matrix of the gates.
Definition: Z.cpp:241
int get_control_qbit()
Call to get the index of the control qubit.
Definition: Gate.cpp:378
Class to store data of complex arrays and its properties.
Definition: matrix_real.h:39
crot_type
Definition: CROT.h:34
void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the gate.
Definition: Y.cpp:211
double imag
the imaginary part of a complex number
Definition: QGDTypes.h:42
void add_sx(int target_qbit)
Append a SX gate to the list of gates.
virtual void set_qbit_num(int qbit_num_in)
Set the number of qubits spanning the matrix of the gates stored in the block of gates.
void apply_from_right(Matrix_real &parameters, Matrix &input)
Call to apply the gate on the input array/matrix by input*U2.
Definition: U2.cpp:130
Header file for a class representing a Sycamore gate.
void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the gate.
Definition: Tdg.cpp:219