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 "CR.h"
34 #include "RZ.h"
35 #include "H.h"
36 #include "X.h"
37 #include "Y.h"
38 #include "Z.h"
39 #include "T.h"
40 #include "Tdg.h"
41 #include "SX.h"
42 #include "SYC.h"
43 #include "UN.h"
44 #include "ON.h"
45 #include "CROT.h"
46 #include "Adaptive.h"
47 #include "CZ_NU.h"
48 #include "Composite.h"
49 #include "Gates_block.h"
50 
52 
53 
55 
56 #ifdef USE_AVX
58 #endif
59 
60 
61 //static tbb::spin_mutex my_mutex;
66 
67  // A string labeling the gate operation
68  name = "Circuit";
69 
70  // A string describing the type of the operation
72  // number of operation layers
73  layer_num = 0;
74 }
75 
76 
77 
82 Gates_block::Gates_block(int qbit_num_in) : Gate(qbit_num_in) {
83 
84  // A string labeling the gate operation
85  name = "Circuit";
86 
87  // A string describing the type of the operation
89  // number of operation layers
90  layer_num = 0;
91 
92  fragmented = false;
93  fragmentation_type = -1;
94  max_fusion = -1;
95 
96 }
97 
98 
103 
104  release_gates();
105 
106 }
107 
111 void
113 
114  //free the alloctaed memory of the stored gates
115  for(std::vector<Gate*>::iterator it = gates.begin(); it != gates.end(); ++it) {
116 
117  Gate* gate = *it;
118  delete gate;
119 
120  }
121 
122  gates.clear();
123  layer_num = 0;
124  parameter_num = 0;
125 
126 }
127 
128 
132 void
134 
135  if ( idx>= (int)gates.size() ) return;
136 
137  // fist decrese the number of parameters
138  Gate* gate = gates[idx];
139  parameter_num -= gate->get_parameter_num();
140 
141  gates.erase( gates.begin() + idx );
142 
143  // TODO: develop a more efficient method for large circuits. Now it is updating the whole circuit
146 
147 
148 }
149 
155 Matrix
157 
158  return get_matrix( parameters, false );
159 
160 
161 }
162 
163 
164 
171 Matrix
173 
174  //The stringstream input to store the output messages.
175  std::stringstream sstream;
176 
177  // create matrix representation of the gate operations
178  Matrix block_mtx = create_identity(matrix_size);
179 
180  apply_to(parameters, block_mtx, parallel);
181 
182 #ifdef DEBUG
183  if (block_mtx.isnan()) {
184  std::stringstream sstream;
185  sstream << "Gates_block::get_matrix: block_mtx contains NaN." << std::endl;
186  print(sstream, 0);
187  }
188 #endif
189 
190  return block_mtx;
191 
192 
193 }
194 
195 
196 
202 void
203 Gates_block::apply_to_list( Matrix_real& parameters_mtx, std::vector<Matrix>& inputs, int parallel ) {
204 
205  int work_batch = 1;
206  if ( parallel == 0 ) {
207  work_batch = inputs.size();
208  }
209  else {
210  work_batch = 1;
211  }
212 
213 
214  tbb::parallel_for( tbb::blocked_range<int>(0,inputs.size(),work_batch), [&](tbb::blocked_range<int> r) {
215  for (int idx=r.begin(); idx<r.end(); ++idx) {
216 
217  Matrix* input = &inputs[idx];
218 
219  apply_to( parameters_mtx, *input, parallel );
220 
221  }
222 
223  });
224 
225 
226 }
227 
228 
235 void
236 Gates_block::apply_to( Matrix_real& parameters_mtx_in, Matrix& input, int parallel ) {
237 
238  std::vector<int> involved_qubits = get_involved_qubits();
239 
240  if (input.rows != matrix_size ) {
241  std::string err("Gates_block::apply_to: Wrong input size in Gates_block gate apply.");
242  throw err;
243  }
244 
245  // TODO: GATE fusion has not been adopted to reversed parameter ordering!!!!!!!!!!!!!!!!!!!
246  if(max_fusion !=-1 && ((qbit_num>max_fusion && input.cols == 1) && involved_qubits.size()>1)){
247 
248 
249  std::string error("Gates_block::apply_to: GATE fusion has not been adopted to reversed parameter ordering!!!!!!!!!!!!!!!!!!!");
250  throw error;
251 
252  double* parameters = parameters_mtx_in.get_data();
253 
254  if (fragmented==false){
256  };
257 
258  int outer_idx = gates.size()-1;
259  for (int block_idx=0; block_idx<involved_qbits.size(); block_idx++){
260 
261  if (block_type[block_idx] != 1){
262 
263  Gates_block gates_block_mini = Gates_block(block_type[block_idx]);
264  std::vector<int> qbits = involved_qbits[block_idx];
265 #ifdef _WIN32
266  int* indices = (int*)_malloca(qbit_num*sizeof(int));
267 #else
268  int indices[qbit_num];
269 #endif
270 
271  for (int jdx=0; jdx<(int)qbits.size(); jdx++){
272  indices[qbits[jdx]]=jdx;
273  }
274 
275  for (int idx=outer_idx; idx>=block_end[block_idx]; idx--){
276 
277  Gate* gate = gates[idx]->clone();
278  int trgt_qbit = gate->get_target_qbit();
279  int ctrl_qbit = gate->get_control_qbit();
280  int target_qubit_new = indices[trgt_qbit];
281  gate->set_target_qbit(target_qubit_new);
282 
283  int control_qubit_new = (ctrl_qbit==-1) ? -1:indices[ctrl_qbit];
284  gate->set_control_qbit(control_qubit_new);
285  gates_block_mini.add_gate(gate);
286  }
287 
288  Matrix Umtx_mini = create_identity(Power_of_2(block_type[block_idx]));
289  parameters = parameters - gates_block_mini.get_parameter_num();
290 
291  Matrix_real parameters_mtx(parameters, 1, gates_block_mini.get_parameter_num());
292  gates_block_mini.apply_to(parameters_mtx, Umtx_mini);
293 
294  outer_idx = block_end[block_idx]-1;
295 
296 #ifdef USE_AVX
297  apply_large_kernel_to_input_AVX(Umtx_mini, input, qbits, input.size() );
298 #else
299  apply_large_kernel_to_state_vector_input(Umtx_mini, input, qbits, input.size() );
300 #endif
301 
302 
303 
304  }
305  else{
306 
307  Gates_block gates_block_mini = Gates_block(qbit_num);
308  for (int idx=outer_idx;idx>=0;idx--){
309  Gate* gate = gates[idx]->clone();
310  gates_block_mini.add_gate(gate);
311  }
312  parameters = parameters - gates_block_mini.get_parameter_num();
313  Matrix_real parameters_mtx(parameters, 1, gates_block_mini.get_parameter_num());
314  gates_block_mini.apply_to(parameters_mtx, input);
315  }
316  }
317  }
318  else if ( involved_qubits.size() == 1 && gates.size() > 1 && qbit_num > 1 ) {
319  // merge successive single qubit gates
320 
321  Gates_block gates_block_mini = Gates_block(1);
322 
323  for (int idx=0; idx<gates.size(); idx++){
324 
325  Gate* gate = gates[idx]->clone();
326  gate->set_target_qbit(0);
327  gate->set_qbit_num(1);
328 
329  gates_block_mini.add_gate(gate);
330  }
331  // TODO check gates block
332  Matrix Umtx_mini = create_identity(2);
333 
334  Matrix_real parameters_mtx_loc(parameters_mtx_in.get_data() + gates[0]->get_parameter_start_idx(), 1, gates_block_mini.get_parameter_num());
335  gates_block_mini.apply_to(parameters_mtx_loc, Umtx_mini);
336 
337  custom_kernel_1qubit_gate merged_gate( qbit_num, involved_qubits[0], Umtx_mini );
338  merged_gate.apply_to( input );
339  }
340  else {
341 
342  // No gate fusion
343  for( int idx=0; idx<gates.size(); idx++) {
344 
345  Gate* operation = gates[idx];
346 
347  Matrix_real parameters_mtx_loc(parameters_mtx_in.get_data() + operation->get_parameter_start_idx(), 1, operation->get_parameter_num());
348 
349  if ( parameters_mtx_loc.size() == 0 && operation->get_type() != BLOCK_OPERATION ) {
350  operation->apply_to(input, parallel);
351  }
352  else {
353  operation->apply_to( parameters_mtx_loc, input, parallel );
354  }
355 #ifdef DEBUG
356  if (input.isnan()) {
357  std::stringstream sstream;
358  sstream << "Gates_block::apply_to: transformed matrix contains NaN." << std::endl;
359  print(sstream, 0);
360  }
361 #endif
362 
363 
364  }
365 
366  }
367 
368 }
369 
370 
371 
373 
380 bool is_qbit_present(std::vector<int> involved_qubits, int new_qbit, int num_of_qbits){
381 
382  bool contained=false;
383 
384  for (int idx=0; idx<num_of_qbits; idx++) {
385 
386  if(involved_qubits[idx] == new_qbit) {
387  contained=true;
388  }
389  }
390 
391  return contained;
392 
393 }
394 
395 
396 
397 
398 
400 
401  std::vector<int> qbits;
402  int num_of_qbits=0;
403  int max_fusion_temp = (fragmentation_type==-1) ? max_fusion:fragmentation_type;
404 
405  for (int idx = gates.size()-1; idx>=0; idx--){
406 
407  Gate* gate = gates[idx];
408  int target_new = gate -> get_target_qbit();
409  int control_new = gate->get_control_qbit();
410 
411  if (num_of_qbits == 0) {
412  qbits.push_back(target_new);
413  num_of_qbits++;
414 
415  }
416 
417  bool target_contained = is_qbit_present(qbits,target_new,num_of_qbits);
418  bool control_contained = (control_new==-1) ? true : is_qbit_present(qbits, control_new, num_of_qbits);
419 
420  if (num_of_qbits == max_fusion_temp && (target_contained == false || control_contained == false)){
421  int vidx = 1;
422 
423  while(vidx<num_of_qbits){
424  int jdx=vidx;
425 
426  while(jdx>0 && qbits[jdx-1]>qbits[jdx]){
427  int qbit_temp = qbits[jdx];
428  qbits[jdx] = qbits[jdx-1];
429  qbits[jdx-1] = qbit_temp;
430  jdx--;
431  }
432 
433  vidx++;
434  }
435 
436  involved_qbits.push_back(qbits);
437  block_end.push_back(idx+1);
438  block_type.push_back(num_of_qbits);
439  max_fusion_temp = max_fusion;
440  idx++;
441  qbits=std::vector<int>{};
442  num_of_qbits=0;
443  continue;
444  }
445 
446  if (num_of_qbits<max_fusion_temp && target_contained==false){
447  qbits.push_back(target_new);
448  num_of_qbits++;
449  }
450 
451  if (num_of_qbits<max_fusion_temp && control_contained==false){
452  qbits.push_back(control_new);
453  num_of_qbits++;
454  }
455 
456 
457  }
458 
459  if (num_of_qbits == 1){
460  involved_qbits.push_back(qbits);
461  block_type.push_back(1);
462  }
463 
464  else{
465  int vidx = 1;
466 
467  while(vidx<num_of_qbits){
468  int jdx=vidx;
469 
470  while(jdx>0 && qbits[jdx-1]>qbits[jdx]){
471  int qbit_temp = qbits[jdx];
472  qbits[jdx] = qbits[jdx-1];
473  qbits[jdx-1] = qbit_temp;
474  jdx--;
475  }
476 
477  vidx++;
478  }
479 
480  involved_qbits.push_back(qbits);
481  block_type.push_back(num_of_qbits);
482  block_end.push_back(0);
483  }
484 
485  block_end.push_back(0);
486  fragmented = true;
487 
488 }
489 
490 
491 
493  int parameter_idx = 0;
494  double *data = range_max.get_data();
495  for(int op_idx = 0; op_idx<gates.size(); op_idx++) {
496 
497  Gate* gate = gates[op_idx];
498  switch (gate->get_type()) {
499  case U1_OPERATION: {
500  data[parameter_idx] = 2 * M_PI; // Lambda (0 to 2pi)
501  parameter_idx = parameter_idx + 1;
502  break;
503  }
504  case U2_OPERATION: {
505  data[parameter_idx] = 2 * M_PI; // Phi (0 to 2pi)
506  data[parameter_idx+1] = 2 * M_PI; // Lambda (0 to 2pi)
507  parameter_idx = parameter_idx + 2;
508  break;
509  }
510  case U3_OPERATION: {
511  data[parameter_idx] = 4 * M_PI; // Theta (0 to 4pi)
512  data[parameter_idx+1] = 2 * M_PI; // Phi (0 to 2pi)
513  data[parameter_idx+2] = 2 * M_PI; // Lambda (0 to 2pi)
514  parameter_idx = parameter_idx + 3;
515  break;
516  }
517  case CROT_OPERATION:
518  case R_OPERATION:
519  case CR_OPERATION:{
520  data[parameter_idx-1] = 4*M_PI;
521  data[parameter_idx-2] = 2*M_PI;
522  parameter_idx = parameter_idx - 2;
523  break;}
524  case RX_OPERATION:
525  case RY_OPERATION:
526  case CRY_OPERATION:
527  case ADAPTIVE_OPERATION:
528  data[parameter_idx] = 4 * M_PI;
529  parameter_idx = parameter_idx + 1;
530  break;
531  case CZ_NU_OPERATION:
532  data[parameter_idx] = 2 * M_PI;
533  parameter_idx = parameter_idx + 1;
534  break;
535  case BLOCK_OPERATION: {
536  Gates_block* block_gate = static_cast<Gates_block*>(gate);
537  Matrix_real parameters_layer(range_max.get_data() + parameter_idx + gate->get_parameter_num(), 1, gate->get_parameter_num() );
538  block_gate->get_parameter_max( parameters_layer );
539  parameter_idx = parameter_idx + block_gate->get_parameter_num();
540  break; }
541  default:
542  for (int i = 0; i < gate->get_parameter_num(); i++)
543  data[parameter_idx+i] = 2 * M_PI;
544  parameter_idx = parameter_idx + gate->get_parameter_num();
545  }
546  }
547 }
548 
550 
551 
556 void
558 
559 
560  //The stringstream input to store the output messages.
561  std::stringstream sstream;
562 
563 
564 
565  // determine the number of parameters
566  int parameters_num_total = 0;
567  for (int idx=0; idx<gates.size(); idx++) {
568 
569  // The current gate
570  Gate* gate = gates[idx];
571  parameters_num_total = parameters_num_total + gate->get_parameter_num();
572 
573  }
574 
575 
576  double* parameters = parameters_mtx.get_data() + parameters_num_total;
577 
578 
579 
580  for( int idx=0; idx<(int)gates.size(); idx++) {
581 
582  Gate* operation = gates[idx];
583  Matrix_real parameters_mtx(parameters-operation->get_parameter_num(), 1, operation->get_parameter_num());
584 
585  switch (operation->get_type()) {
586  case CNOT_OPERATION: case CZ_OPERATION:
587  case CH_OPERATION: case SYC_OPERATION:
588  case X_OPERATION: case Y_OPERATION:
589  case Z_OPERATION: case SX_OPERATION:
590  case T_OPERATION: case TDG_OPERATION:
591  case GENERAL_OPERATION: case H_OPERATION:
592  operation->apply_from_right(input);
593  break;
594  case U1_OPERATION: {
595  U1* u1_operation = static_cast<U1*>(operation);
596  u1_operation->apply_from_right( parameters_mtx, input );
597  break;
598  }
599  case U2_OPERATION: {
600  U2* u2_operation = static_cast<U2*>(operation);
601  u2_operation->apply_from_right( parameters_mtx, input );
602  break;
603  }
604  case U3_OPERATION: {
605  U3* u3_operation = static_cast<U3*>(operation);
606  u3_operation->apply_from_right( parameters_mtx, input );
607  break;
608  }
609  case R_OPERATION: {
610  R* r_operation = static_cast<R*>(operation);
611  r_operation->apply_from_right( parameters_mtx, input );
612  break;
613  }
614  case RX_OPERATION: {
615  RX* rx_operation = static_cast<RX*>(operation);
616  rx_operation->apply_from_right( parameters_mtx, input );
617  break;
618  }
619  case RY_OPERATION: {
620  RY* ry_operation = static_cast<RY*>(operation);
621  ry_operation->apply_from_right( parameters_mtx, input );
622  break;
623  }
624  case CRY_OPERATION: {
625  CRY* cry_operation = static_cast<CRY*>(operation);
626  cry_operation->apply_from_right( parameters_mtx, input );
627  break;
628  }
629  case CR_OPERATION: {
630  CR* cr_operation = static_cast<CR*>(operation);
631  cr_operation->apply_from_right( parameters_mtx, input );
632  break;
633  }
634  case RZ_OPERATION: {
635  RZ* rz_operation = static_cast<RZ*>(operation);
636  rz_operation->apply_from_right( parameters_mtx, input );
637  break;
638  }
639  case UN_OPERATION: {
640  UN* un_operation = static_cast<UN*>(operation);
641  un_operation->apply_from_right( parameters_mtx, input );
642  break;
643  }
644  case ON_OPERATION: {
645  ON* on_operation = static_cast<ON*>(operation);
646  on_operation->apply_from_right( parameters_mtx, input );
647  break;
648  }
649  case BLOCK_OPERATION: {
650  Gates_block* block_operation = static_cast<Gates_block*>(operation);
651  block_operation->apply_from_right(parameters_mtx, input);
652  break;
653  }
654  case CZ_NU_OPERATION: {
655  CZ_NU* cz_nu_operation = static_cast<CZ_NU*>(operation);
656  cz_nu_operation->apply_from_right( parameters_mtx, input );
657  break;
658  }
659  case COMPOSITE_OPERATION: {
660  Composite* com_operation = static_cast<Composite*>(operation);
661  com_operation->apply_from_right( parameters_mtx, input );
662  break;
663  }
664  case ADAPTIVE_OPERATION: {
665  Adaptive* ad_operation = static_cast<Adaptive*>(operation);
666  ad_operation->apply_from_right( parameters_mtx, input );
667  break;
668  }
669  default:
670  std::string err("Gates_block::apply_from_right: unimplemented gate");
671  throw err;
672  }
673 
674  parameters = parameters - operation->get_parameter_num();
675 
676 #ifdef DEBUG
677  if (input.isnan()) {
678  std::stringstream sstream;
679  sstream << "Gates_block::apply_from_right: transformed matrix contains NaN." << std::endl;
680  print(sstream, 0);
681  }
682 #endif
683 
684 
685  }
686 
687 
688 }
689 
690 
697 std::vector<Matrix>
698 Gates_block::apply_derivate_to( Matrix_real& parameters_mtx_in, Matrix& input, int parallel ) {
699 
700  //The stringstream input to store the output messages.
701  std::stringstream sstream;
702 
703  std::vector<Matrix> grad(parameter_num, Matrix(0,0));
704 
705  int work_batch = 1;
706  if ( parallel == 0 ) {
707  work_batch = gates.size();
708  }
709  else {
710  work_batch = 1;
711  }
712 
713  // deriv_idx ... the index of the gate block for which the gradient is to be calculated
714 
715  tbb::parallel_for( tbb::blocked_range<int>(0,gates.size(),work_batch), [&](tbb::blocked_range<int> r) {
716  for (int deriv_idx=r.begin(); deriv_idx<r.end(); ++deriv_idx) {
717 
718  //for (int deriv_idx=0; deriv_idx<gates.size(); ++deriv_idx) {
719 
720 
721  Gate* gate_deriv = gates[deriv_idx];
722 
723  // for constant gate no gardient component is calculated
724  if ( gate_deriv->get_parameter_num() == 0 ) {
725  continue;
726  }
727 
728  int deriv_parameter_idx = gate_deriv->get_parameter_start_idx();
729 
730 
731 
732  Matrix&& input_loc = input.copy();
733 
734  std::vector<Matrix> grad_loc;
735 
736  for( int idx=0; idx<gates.size(); idx++) {
737 
738  Gate* operation = gates[idx];
739 
740 
741  Matrix_real parameters_mtx(parameters_mtx_in.get_data() + operation->get_parameter_start_idx(), 1, operation->get_parameter_num());
742 
743  switch (operation->get_type()) {
744  case UN_OPERATION:
745  case ON_OPERATION:
746  case SYC_OPERATION:
747  case COMPOSITE_OPERATION: {
748  int gate_type = (int)operation->get_type();
749  std::string err( "Gates_block::apply_derivate_to: Given operation not supported in gardient calculation");
750  throw( err );
751  break;
752  }
753  default :
754 
755  if ( operation->get_parameter_num() == 0 ) {
756 
757  if( idx < deriv_idx ) {
758  operation->apply_to( input_loc, parallel );
759  }
760  else {
761  operation->apply_to_list(grad_loc, parallel );
762  }
763 
764  }
765  else {
766  // Gates such as U1, U2, and U3 fall here.
767  if( idx < deriv_idx ) {
768  operation->apply_to( parameters_mtx, input_loc, parallel );
769  }
770  else if ( idx == deriv_idx ) {
771  grad_loc = operation->apply_derivate_to( parameters_mtx, input_loc, parallel );
772  }
773  else {
774  operation->apply_to_list(parameters_mtx, grad_loc, parallel );
775  }
776 
777  }
778 
779  }
780  }
781 
782 
783  for ( int idx = 0; idx<(int)grad_loc.size(); idx++ ) {
784  grad[deriv_parameter_idx+idx] = grad_loc[idx];
785  }
786 
787 
788  } // tbb range end
789 
790  });
791 
792 
793  return grad;
794 
795 }
796 
802 
803  // create the operation
804  Gate* operation = static_cast<Gate*>(new U1( qbit_num, target_qbit ));
805 
806  // adding the operation to the end of the list of gates
807  add_gate( operation );
808 }
809 
815 
816  // create the operation
817  Gate* gate = static_cast<Gate*>(new U1( qbit_num, target_qbit ));
818 
819  // adding the operation to the front of the list of gates
820  add_gate_to_front( gate );
821 }
822 
828 
829  // create the operation
830  Gate* operation = static_cast<Gate*>(new U2( qbit_num, target_qbit ));
831 
832  // adding the operation to the end of the list of gates
833  add_gate( operation );
834 }
835 
841 
842  // create the operation
843  Gate* gate = static_cast<Gate*>(new U2( qbit_num, target_qbit ));
844 
845  // adding the operation to the front of the list of gates
846  add_gate_to_front( gate );
847 }
848 
854 
855  // create the operation
856  Gate* operation = static_cast<Gate*>(new U3( qbit_num, target_qbit ));
857 
858  // adding the operation to the end of the list of gates
859  add_gate( operation );
860 }
861 
867 
868  // create the operation
869  Gate* gate = static_cast<Gate*>(new U3( qbit_num, target_qbit ));
870 
871  // adding the operation to the front of the list of gates
872  add_gate_to_front( gate );
873 
874 }
875 
881 
882  // create the operation
883  Gate* operation = static_cast<Gate*>(new RX( qbit_num, target_qbit));
884 
885  // adding the operation to the end of the list of gates
886  add_gate( operation );
887 }
888 
894 
895  // create the operation
896  Gate* gate = static_cast<Gate*>(new RX( qbit_num, target_qbit ));
897 
898  // adding the operation to the front of the list of gates
899  add_gate_to_front( gate );
900 
901 }
902 
908 
909  // create the operation
910  Gate* operation = static_cast<Gate*>(new R( qbit_num, target_qbit));
911 
912  // adding the operation to the end of the list of gates
913  add_gate( operation );
914 }
915 
921 
922  // create the operation
923  Gate* gate = static_cast<Gate*>(new R( qbit_num, target_qbit ));
924 
925  // adding the operation to the front of the list of gates
926  add_gate_to_front( gate );
927 
928 }
929 
930 
936 
937  // create the operation
938  Gate* operation = static_cast<Gate*>(new RY( qbit_num, target_qbit));
939 
940  // adding the operation to the end of the list of gates
941  add_gate( operation );
942 }
943 
944 
950 
951  // create the operation
952  Gate* gate = static_cast<Gate*>(new RY( qbit_num, target_qbit ));
953 
954  // adding the operation to the front of the list of gates
955  add_gate_to_front( gate );
956 
957 }
958 
959 
960 
961 
968 
969  // create the operation
970  Gate* operation = static_cast<Gate*>(new CRY( qbit_num, target_qbit, control_qbit));
971 
972  // adding the operation to the end of the list of gates
973  add_gate( operation );
974 }
975 
976 
977 
984 
985  // create the operation
986  Gate* gate = static_cast<Gate*>(new CRY( qbit_num, target_qbit, control_qbit ));
987 
988  // adding the operation to the front of the list of gates
989  add_gate_to_front( gate );
990 
991 }
992 
999 
1000  // create the operation
1001  Gate* operation = static_cast<Gate*>(new CR( qbit_num, target_qbit, control_qbit));
1002 
1003  // adding the operation to the end of the list of gates
1004  add_gate( operation );
1005 }
1006 
1007 
1008 
1015 
1016  // create the operation
1017  Gate* gate = static_cast<Gate*>(new CR( qbit_num, target_qbit, control_qbit ));
1018 
1019  // adding the operation to the front of the list of gates
1020  add_gate_to_front( gate );
1021 
1022 }
1023 
1024 
1031 
1032  // create the operation
1033  Gate* operation = static_cast<Gate*>(new CROT( qbit_num, target_qbit, control_qbit));
1034 
1035  // adding the operation to the end of the list of gates
1036  add_gate( operation );
1037 }
1038 
1039 
1040 
1047 
1048  // create the operation
1049  Gate* gate = static_cast<Gate*>(new CROT( qbit_num, target_qbit, control_qbit ));
1050 
1051  // adding the operation to the front of the list of gates
1052  add_gate_to_front( gate );
1053 
1054 }
1055 
1062 
1063  // create the operation
1064  Gate* operation = static_cast<Gate*>(new CZ_NU( qbit_num, target_qbit, control_qbit));
1065 
1066  // adding the operation to the end of the list of gates
1067  add_gate( operation );
1068 }
1069 
1070 
1071 
1078 
1079  // create the operation
1080  Gate* gate = static_cast<Gate*>(new CZ_NU( qbit_num, target_qbit, control_qbit ));
1081 
1082  // adding the operation to the front of the list of gates
1083  add_gate_to_front( gate );
1084 
1085 }
1086 
1087 
1088 
1094 
1095  // create the operation
1096  Gate* operation = static_cast<Gate*>(new RZ( qbit_num, target_qbit));
1097 
1098  // adding the operation to the end of the list of gates
1099  add_gate( operation );
1100 }
1101 
1107 
1108  // create the operation
1109  Gate* gate = static_cast<Gate*>(new RZ( qbit_num, target_qbit ));
1110 
1111  // adding the operation to the front of the list of gates
1112  add_gate_to_front( gate );
1113 
1114 }
1115 
1116 
1117 
1118 
1125 
1126  // new cnot operation
1127  Gate* gate = static_cast<Gate*>(new CNOT(qbit_num, target_qbit, control_qbit ));
1128 
1129  // append the operation to the list
1130  add_gate(gate);
1131 
1132 }
1133 
1134 
1135 
1142 
1143  // new cnot operation
1144  Gate* gate = static_cast<Gate*>(new CNOT(qbit_num, target_qbit, control_qbit ));
1145 
1146  // put the operation to tghe front of the list
1147  add_gate_to_front(gate);
1148 
1149 }
1150 
1151 
1152 
1153 
1160 
1161  // new cz operation
1162  Gate* gate = static_cast<Gate*>(new CZ(qbit_num, target_qbit, control_qbit ));
1163 
1164  // append the operation to the list
1165  add_gate(gate);
1166 
1167 }
1168 
1169 
1170 
1177 
1178  // new cz operation
1179  Gate* gate = static_cast<Gate*>(new CZ(qbit_num, target_qbit, control_qbit ));
1180 
1181  // put the operation to tghe front of the list
1182  add_gate_to_front(gate);
1183 
1184 }
1185 
1191 
1192  // create the operation
1193  Gate* operation = static_cast<Gate*>(new H( qbit_num, target_qbit));
1194 
1195  // adding the operation to the end of the list of gates
1196  add_gate( operation );
1197 }
1198 
1204 
1205  // create the operation
1206  Gate* gate = static_cast<Gate*>(new H( qbit_num, target_qbit ));
1207 
1208  // adding the operation to the front of the list of gates
1209  add_gate_to_front( gate );
1210 
1211 }
1212 
1213 
1214 
1215 
1216 
1222 
1223  // create the operation
1224  Gate* operation = static_cast<Gate*>(new X( qbit_num, target_qbit));
1225 
1226  // adding the operation to the end of the list of gates
1227  add_gate( operation );
1228 }
1229 
1235 
1236  // create the operation
1237  Gate* gate = static_cast<Gate*>(new X( qbit_num, target_qbit ));
1238 
1239  // adding the operation to the front of the list of gates
1240  add_gate_to_front( gate );
1241 
1242 }
1243 
1244 
1245 
1251 
1252  // create the operation
1253  Gate* operation = static_cast<Gate*>(new Y( qbit_num, target_qbit));
1254 
1255  // adding the operation to the end of the list of gates
1256  add_gate( operation );
1257 }
1258 
1264 
1265  // create the operation
1266  Gate* gate = static_cast<Gate*>(new Y( qbit_num, target_qbit ));
1267 
1268  // adding the operation to the front of the list of gates
1269  add_gate_to_front( gate );
1270 
1271 }
1272 
1273 
1274 
1280 
1281  // create the operation
1282  Gate* operation = static_cast<Gate*>(new Z( qbit_num, target_qbit));
1283 
1284  // adding the operation to the end of the list of gates
1285  add_gate( operation );
1286 }
1287 
1293 
1294  // create the operation
1295  Gate* gate = static_cast<Gate*>(new Z( qbit_num, target_qbit ));
1296 
1297  // adding the operation to the front of the list of gates
1298  add_gate_to_front( gate );
1299 
1300 }
1301 
1302 
1303 
1304 
1310 
1311  // create the operation
1312  Gate* operation = static_cast<Gate*>(new T( qbit_num, target_qbit));
1313 
1314  // adding the operation to the end of the list of gates
1315  add_gate( operation );
1316 }
1317 
1323 
1324  // create the operation
1325  Gate* gate = static_cast<Gate*>(new T( qbit_num, target_qbit ));
1326 
1327  // adding the operation to the front of the list of gates
1328  add_gate_to_front( gate );
1329 
1330 }
1331 
1332 
1333 
1334 
1340 
1341  // create the operation
1342  Gate* operation = static_cast<Gate*>(new Tdg( qbit_num, target_qbit));
1343 
1344  // adding the operation to the end of the list of gates
1345  add_gate( operation );
1346 }
1347 
1353 
1354  // create the operation
1355  Gate* gate = static_cast<Gate*>(new Tdg( qbit_num, target_qbit ));
1356 
1357  // adding the operation to the front of the list of gates
1358  add_gate_to_front( gate );
1359 
1360 }
1361 
1362 
1363 
1364 
1365 
1366 
1372 
1373  // create the operation
1374  Gate* operation = static_cast<Gate*>(new SX( qbit_num, target_qbit));
1375 
1376  // adding the operation to the end of the list of gates
1377  add_gate( operation );
1378 }
1379 
1385 
1386  // create the operation
1387  Gate* gate = static_cast<Gate*>(new SX( qbit_num, target_qbit ));
1388 
1389  // adding the operation to the front of the list of gates
1390  add_gate_to_front( gate );
1391 
1392 }
1393 
1394 
1395 
1396 
1397 
1404 
1405  // new cz operation
1406  Gate* gate = static_cast<Gate*>(new SYC(qbit_num, target_qbit, control_qbit ));
1407 
1408  // append the operation to the list
1409  add_gate(gate);
1410 
1411 }
1412 
1413 
1414 
1421 
1422  // new cz operation
1423  Gate* gate = static_cast<Gate*>(new SYC(qbit_num, target_qbit, control_qbit ));
1424 
1425  // put the operation to tghe front of the list
1426  add_gate_to_front(gate);
1427 
1428 }
1429 
1430 
1431 
1432 
1439 
1440  // new cz operation
1441  Gate* gate = static_cast<Gate*>(new CH(qbit_num, target_qbit, control_qbit ));
1442 
1443  // append the operation to the list
1444  add_gate(gate);
1445 
1446 }
1447 
1448 
1449 
1456 
1457  // new cz operation
1458  Gate* gate = static_cast<Gate*>(new CH(qbit_num, target_qbit, control_qbit ));
1459 
1460  // put the operation to tghe front of the list
1461  add_gate_to_front(gate);
1462 
1463 }
1464 
1469 void Gates_block::add_gates( std::vector<Gate*> gates_in) {
1470 
1471  for(std::vector<Gate*>::iterator it = gates_in.begin(); it != gates_in.end(); ++it) {
1472  add_gate( *it );
1473  }
1474 
1475 }
1476 
1477 
1482 void Gates_block::add_gates_to_front( std::vector<Gate*> gates_in) {
1483 
1484  // adding gates in reversed order!!
1485  for(std::vector<Gate*>::iterator it = gates_in.end(); it != gates_in.begin(); --it) {
1486  add_gate_to_front( *it );
1487  }
1488 
1489 }
1490 
1491 
1492 
1497 
1498  // create the operation
1499  Gate* operation = static_cast<Gate*>(new UN( qbit_num ));
1500 
1501  // adding the operation to the end of the list of gates
1502  add_gate( operation );
1503 }
1504 
1509 
1510  // create the operation
1511  Gate* gate = static_cast<Gate*>(new UN( qbit_num ));
1512 
1513  // adding the operation to the front of the list of gates
1514  add_gate_to_front( gate );
1515 
1516 }
1517 
1518 
1523 
1524  // create the operation
1525  Gate* operation = static_cast<Gate*>(new ON( qbit_num ));
1526 
1527  // adding the operation to the end of the list of gates
1528  add_gate( operation );
1529 }
1530 
1535 
1536  // create the operation
1537  Gate* gate = static_cast<Gate*>(new ON( qbit_num ));
1538 
1539  // adding the operation to the front of the list of gates
1540  add_gate_to_front( gate );
1541 
1542 }
1543 
1544 
1549 
1550  // create the operation
1551  Gate* operation = static_cast<Gate*>(new Composite( qbit_num ));
1552 
1553  // adding the operation to the end of the list of gates
1554  add_gate( operation );
1555 }
1556 
1561 
1562  // create the operation
1563  Gate* gate = static_cast<Gate*>(new Composite( qbit_num ));
1564 
1565  // adding the operation to the front of the list of gates
1566  add_gate_to_front( gate );
1567 
1568 }
1569 
1570 
1571 
1578 
1579  // create the operation
1580  Gate* operation = static_cast<Gate*>(new Adaptive( qbit_num, target_qbit, control_qbit));
1581 
1582  // adding the operation to the end of the list of gates
1583  add_gate( operation );
1584 }
1585 
1586 
1593 
1594  // create the operation
1595  Gate* gate = static_cast<Gate*>(new Adaptive( qbit_num, target_qbit, control_qbit ));
1596 
1597  // adding the operation to the front of the list of gates
1598  add_gate_to_front( gate );
1599 
1600 }
1601 
1602 
1603 
1609 
1610  //set the number of qubit in the gate
1611  gate->set_qbit_num( qbit_num );
1612 
1613  // determine the parents of the gate
1614  determine_parents( gate );
1615 
1616  // append the gate to the list
1617  gates.push_back(gate);
1618 
1619  // set the parameter starting index in the parameters array used to execute the circuit.
1621 
1622  // increase the number of parameters by the number of parameters
1624 
1625  // increase the number of layers if necessary
1626  if (gate->get_type() == BLOCK_OPERATION) {
1627  layer_num = layer_num + 1;
1628  }
1629 
1630 }
1631 
1632 
1633 
1639 
1640 
1641  // set the number of qubit in the gate
1642  gate->set_qbit_num( qbit_num );
1643 
1644  // determine the parents of the gate
1645  determine_children( gate );
1646 
1647  gates.insert( gates.begin(), gate);
1648 
1649  // increase the number of U3 gate parameters by the number of parameters
1651 
1652  // increase the number of layers if necessary
1653  if (gate->get_type() == BLOCK_OPERATION) {
1654  layer_num = layer_num + 1;
1655  }
1656 
1657  // TODO: develop a more efficient method for large circuits. Now it is updating the whole circuit
1660 
1661 }
1662 
1663 
1664 
1670 void
1671 Gates_block::insert_gate( Gate* gate, int idx ) {
1672 
1673 
1674  // set the number of qubit in the gate
1675  gate->set_qbit_num( qbit_num );
1676 
1677  gates.insert( gates.begin()+idx, gate);
1678 
1679  // increase the number of U3 gate parameters by the number of parameters
1681 
1682  // increase the number of layers if necessary
1683  if (gate->get_type() == BLOCK_OPERATION) {
1684  layer_num = layer_num + 1;
1685  }
1686 
1687  // TODO: develop a more efficient method for large circuits. Now it is updating the whole circuit
1690 
1691 
1692 }
1693 
1694 
1699 void Gates_block::add_gate_nums( std::map<std::string, int>& gate_nums ) {
1700 
1701  for(std::vector<Gate*>::iterator it = gates.begin(); it != gates.end(); ++it) {
1702 
1703  // get the specific gate in the circuit (might be a gate or another subcircuit)
1704  Gate* gate = *it;
1705 
1706 
1707  if (gate->get_type() == BLOCK_OPERATION) {
1708  Gates_block* circuit = static_cast<Gates_block*>(gate);
1709  circuit->add_gate_nums( gate_nums );
1710  }
1711  else {
1712  std::string gate_name = gate->get_name();
1713 
1714  if( gate_nums.find(gate_name) == gate_nums.end() ) {
1715  gate_nums[ gate_name ] = 1;
1716  }
1717  else {
1718  gate_nums[ gate_name ] = gate_nums[ gate_name ] + 1;
1719  }
1720  }
1721 
1722  }
1723 
1724 }
1725 
1726 
1731 std::map<std::string, int> Gates_block::get_gate_nums() {
1732 
1733  std::map<std::string, int> gate_nums;
1734 
1735  add_gate_nums( gate_nums );
1736 
1737  return gate_nums;
1738 
1739 }
1740 
1741 
1747  return parameter_num;
1748 }
1749 
1750 
1751 
1752 
1758  return gates.size();
1759 }
1760 
1761 
1767 void Gates_block::list_gates( const Matrix_real &parameters, int start_index ) {
1768 
1769 
1770  //The stringstream input to store the output messages.
1771  std::stringstream sstream;
1772  sstream << std::endl << "The gates in the list of gates:" << std::endl;
1773  print(sstream, 1);
1774 
1775  int gate_idx = start_index;
1776  int parameter_idx = 0;
1777  double *parameters_data = parameters.get_data();
1778  //const_cast <Matrix_real&>(parameters);
1779 
1780 
1781  for(int op_idx = 0; op_idx<gates.size(); op_idx++) {
1782 
1783  Gate* gate = gates[op_idx];
1784 
1785  if (gate->get_type() == CNOT_OPERATION) {
1786  CNOT* cnot_gate = static_cast<CNOT*>(gate);
1787  std::stringstream sstream;
1788  sstream << gate_idx << "th gate: CNOT with control qubit: " << cnot_gate->get_control_qbit() << " and target qubit: " << cnot_gate->get_target_qbit() << std::endl;
1789  print(sstream, 1);
1790  gate_idx = gate_idx + 1;
1791  }
1792  else if (gate->get_type() == CROT_OPERATION) {
1793  CROT* crot_gate = static_cast<CROT*>(gate);
1794  std::stringstream sstream;
1795  double theta0,phi0;
1796  theta0 = std::fmod( 2*parameters_data[parameter_idx], 4*M_PI);
1797  phi0 = std::fmod( parameters_data[parameter_idx+1], 2*M_PI);
1798  parameter_idx = parameter_idx + 2;
1799  sstream << gate_idx << "th gate: CROT 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;
1800  print(sstream, 1);
1801  gate_idx = gate_idx + 1;
1802  }
1803  else if (gate->get_type() == CZ_OPERATION) {
1804  CZ* cz_gate = static_cast<CZ*>(gate);
1805  std::stringstream sstream;
1806  sstream << gate_idx << "th gate: CZ with control qubit: " << cz_gate->get_control_qbit() << " and target qubit: " << cz_gate->get_target_qbit() << std::endl;
1807  print(sstream, 1);
1808  gate_idx = gate_idx + 1;
1809  }
1810  else if (gate->get_type() == CH_OPERATION) {
1811  CH* ch_gate = static_cast<CH*>(gate);
1812  std::stringstream sstream;
1813  sstream << gate_idx << "th gate: CH with control qubit: " << ch_gate->get_control_qbit() << " and target qubit: " << ch_gate->get_target_qbit() << std::endl;
1814  print(sstream, 1);
1815  gate_idx = gate_idx + 1;
1816  }
1817  else if (gate->get_type() == SYC_OPERATION) {
1818  SYC* syc_gate = static_cast<SYC*>(gate);
1819  std::stringstream sstream;
1820  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;
1821  print(sstream, 1);
1822  gate_idx = gate_idx + 1;
1823  }
1824  else if (gate->get_type() == U1_OPERATION) {
1825  U1* u1_gate = static_cast<U1*>(gate);
1826  double lambda = std::fmod(parameters_data[parameter_idx], 2*M_PI);
1827  parameter_idx = parameter_idx + 1;
1828  std::stringstream sstream;
1829  sstream << gate_idx << "th gate: U1 on target qubit: " << u1_gate->get_target_qbit() << " with parameter lambda = " << lambda << std::endl;
1830  print(sstream, 1);
1831  gate_idx = gate_idx + 1;
1832  }
1833  else if (gate->get_type() == U2_OPERATION) {
1834  U2* u2_gate = static_cast<U2*>(gate);
1835  double phi = std::fmod(parameters_data[parameter_idx], 2*M_PI);
1836  double lambda = std::fmod(parameters_data[parameter_idx+1], 2*M_PI);
1837  parameter_idx = parameter_idx + 2;
1838  std::stringstream sstream;
1839  sstream << gate_idx << "th gate: U2 on target qubit: " << u2_gate->get_target_qbit() << " with parameters phi = " << phi << " and lambda = " << lambda << std::endl;
1840  print(sstream, 1);
1841  gate_idx = gate_idx + 1;
1842  }
1843  else if (gate->get_type() == U3_OPERATION) {
1844  U3* u3_gate = static_cast<U3*>(gate);
1845  double theta = std::fmod(parameters_data[parameter_idx], 4*M_PI);
1846  double phi = std::fmod(parameters_data[parameter_idx+1], 2*M_PI);
1847  double lambda = std::fmod(parameters_data[parameter_idx+2], 2*M_PI);
1848  parameter_idx = parameter_idx + 3;
1849  std::stringstream sstream;
1850  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;
1851  print(sstream, 1);
1852  gate_idx = gate_idx + 1;
1853  }
1854  else if (gate->get_type() == R_OPERATION) {
1855  // definig the rotation parameter
1856  double vartheta,varphi;
1857  // get the inverse parameters of the U3 rotation
1858  R* r_gate = static_cast<R*>(gate);
1859  vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*M_PI);
1860  varphi = std::fmod( parameters_data[parameter_idx+1], 2*M_PI);
1861  parameter_idx = parameter_idx + 2;
1862 
1863  std::stringstream sstream;
1864  sstream << gate_idx << "th gate: R on target qubit: " << r_gate->get_target_qbit() << " and with parameters theta = " << vartheta << " and phi:" << varphi << std::endl;
1865  print(sstream, 1);
1866  gate_idx = gate_idx + 1;
1867  }
1868  else if (gate->get_type() == RX_OPERATION) {
1869  // definig the rotation parameter
1870  double vartheta;
1871  // get the inverse parameters of the U3 rotation
1872  RX* rx_gate = static_cast<RX*>(gate);
1873  vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*M_PI);
1874  parameter_idx = parameter_idx + 1;
1875 
1876  std::stringstream sstream;
1877  sstream << gate_idx << "th gate: RX on target qubit: " << rx_gate->get_target_qbit() << " and with parameters theta = " << vartheta << std::endl;
1878  print(sstream, 1);
1879  gate_idx = gate_idx + 1;
1880  }
1881  else if (gate->get_type() == RY_OPERATION) {
1882  // definig the rotation parameter
1883  double vartheta;
1884  // get the inverse parameters of the U3 rotation
1885  RY* ry_gate = static_cast<RY*>(gate);
1886  vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*M_PI);
1887  parameter_idx = parameter_idx + 1;
1888 
1889  std::stringstream sstream;
1890  sstream << gate_idx << "th gate: RY on target qubit: " << ry_gate->get_target_qbit() << " and with parameters theta = " << vartheta << std::endl;
1891  print(sstream, 1);
1892  gate_idx = gate_idx + 1;
1893  }
1894  else if (gate->get_type() == CRY_OPERATION) {
1895  // definig the rotation parameter
1896  double vartheta;
1897  // get the inverse parameters of the U3 rotation
1898  CRY* cry_gate = static_cast<CRY*>(gate);
1899  vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*M_PI);
1900  parameter_idx = parameter_idx + 1;
1901 
1902  std::stringstream sstream;
1903  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;
1904  print(sstream, 1);
1905  gate_idx = gate_idx + 1;
1906  }
1907  else if (gate->get_type() == CR_OPERATION) {
1908  // definig the rotation parameter
1909  double vartheta,varphi;
1910  // get the inverse parameters of the U3 rotation
1911  CR* cr_gate = static_cast<CR*>(gate);
1912  vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*M_PI);
1913  varphi = std::fmod(parameters_data[parameter_idx+1],2*M_PI);
1914  parameter_idx = parameter_idx + 2;
1915 
1916  std::stringstream sstream;
1917  sstream << gate_idx << "th gate: CR on target qubit: " << cr_gate->get_target_qbit() << ", control qubit" << cr_gate->get_control_qbit() << " and with parameters theta and phi = " << vartheta << " , " << varphi << std::endl;
1918  print(sstream, 1);
1919  gate_idx = gate_idx + 1;
1920  }
1921  else if (gate->get_type() == RZ_OPERATION) {
1922  // definig the rotation parameter
1923  double varphi;
1924  // get the inverse parameters of the U3 rotation
1925  RZ* rz_gate = static_cast<RZ*>(gate);
1926  varphi = std::fmod( 2*parameters_data[parameter_idx], 2*M_PI);
1927  parameter_idx = parameter_idx + 1;
1928 
1929  std::stringstream sstream;
1930  sstream << gate_idx << "th gate: RZ on target qubit: " << rz_gate->get_target_qbit() << " and with parameters varphi = " << varphi << std::endl;
1931  print(sstream, 1);
1932  gate_idx = gate_idx + 1;
1933  }
1934  else if (gate->get_type() == H_OPERATION) {
1935  // get the inverse parameters of the U3 rotation
1936  H* h_gate = static_cast<H*>(gate);
1937  std::stringstream sstream;
1938  sstream << gate_idx << "th gate: Hadamard on target qubit: " << h_gate->get_target_qbit() << std::endl;
1939  print(sstream, 1);
1940  gate_idx = gate_idx + 1;
1941  }
1942  else if (gate->get_type() == X_OPERATION) {
1943  // get the inverse parameters of the U3 rotation
1944  X* x_gate = static_cast<X*>(gate);
1945  std::stringstream sstream;
1946  sstream << gate_idx << "th gate: X on target qubit: " << x_gate->get_target_qbit() << std::endl;
1947  print(sstream, 1);
1948  gate_idx = gate_idx + 1;
1949  }
1950  else if (gate->get_type() == Y_OPERATION) {
1951  // get the inverse parameters of the U3 rotation
1952  Y* y_gate = static_cast<Y*>(gate);
1953  std::stringstream sstream;
1954  sstream << gate_idx << "th gate: Y on target qubit: " << y_gate->get_target_qbit() << std::endl;
1955  print(sstream, 1);
1956  gate_idx = gate_idx + 1;
1957  }
1958  else if (gate->get_type() == Z_OPERATION) {
1959  // get the inverse parameters of the U3 rotation
1960  Z* z_gate = static_cast<Z*>(gate);
1961  std::stringstream sstream;
1962  sstream << gate_idx << "th gate: Z on target qubit: " << z_gate->get_target_qbit() << std::endl;
1963  print(sstream, 1);
1964  gate_idx = gate_idx + 1;
1965  }
1966  else if (gate->get_type() == SX_OPERATION) {
1967  // get the inverse parameters of the U3 rotation
1968  SX* sx_gate = static_cast<SX*>(gate);
1969 
1970  std::stringstream sstream;
1971  sstream << gate_idx << "th gate: SX on target qubit: " << sx_gate->get_target_qbit() << std::endl;
1972  print(sstream, 1);
1973  gate_idx = gate_idx + 1;
1974  }
1975  else if (gate->get_type() == BLOCK_OPERATION) {
1976  Gates_block* block_gate = static_cast<Gates_block*>(gate);
1977  const Matrix_real parameters_layer(parameters.get_data() + parameter_idx, 1, gate->get_parameter_num() );
1978  block_gate->list_gates( parameters_layer, gate_idx );
1979  parameter_idx = parameter_idx + block_gate->get_parameter_num();
1980  gate_idx = gate_idx + block_gate->get_gate_num();
1981  }
1982  else if (gate->get_type() == UN_OPERATION) {
1983  parameter_idx = parameter_idx + gate->get_parameter_num();
1984 
1985  std::stringstream sstream;
1986  sstream << gate_idx << "th gate: UN " << gate->get_parameter_num() << " parameters" << std::endl;
1987  print(sstream, 1);
1988  gate_idx = gate_idx + 1;
1989  }
1990  else if (gate->get_type() == CZ_NU_OPERATION) {
1991  // definig the rotation parameter
1992  double Theta;
1993  // get the inverse parameters of the U3 rotation
1994  CZ_NU* cz_nu_gate = static_cast<CZ_NU*>(gate);
1995  Theta = std::fmod( parameters_data[parameter_idx], 2*M_PI);
1996  parameter_idx = parameter_idx +1;
1997 
1998  std::stringstream sstream;
1999  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;
2000  print(sstream, 1);
2001  gate_idx = gate_idx + 1;
2002  }
2003  else if (gate->get_type() == ON_OPERATION) {
2004  parameter_idx = parameter_idx + gate->get_parameter_num();
2005  std::stringstream sstream;
2006  sstream << gate_idx << "th gate: ON " << gate->get_parameter_num() << " parameters" << std::endl;
2007  print(sstream, 1);
2008  gate_idx = gate_idx + 1;
2009  }
2010  else if (gate->get_type() == COMPOSITE_OPERATION) {
2011  parameter_idx = parameter_idx + gate->get_parameter_num();
2012 
2013  std::stringstream sstream;
2014  sstream << gate_idx << "th gate: Composite " << gate->get_parameter_num() << " parameters" << std::endl;
2015  print(sstream, 1);
2016  gate_idx = gate_idx + 1;
2017  }
2018  else if (gate->get_type() == ADAPTIVE_OPERATION) {
2019  // definig the rotation parameter
2020  double Theta;
2021  // get the inverse parameters of the U3 rotation
2022  Adaptive* ad_gate = static_cast<Adaptive*>(gate);
2023  Theta = std::fmod( 2*parameters_data[parameter_idx], 4*M_PI);
2024  parameter_idx = parameter_idx + 1;
2025 
2026  std::stringstream sstream;
2027  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;
2028  print(sstream, 1);
2029  gate_idx = gate_idx + 1;
2030  }
2031  else {
2032  std::string err("Gates_block::list_gates: unimplemented gate");
2033  throw err;
2034  }
2035 
2036  }
2037 
2038 
2039 }
2040 
2041 
2047 Gates_block*
2048 Gates_block::create_remapped_circuit( const std::map<int, int>& qbit_map ) {
2049 
2050  return create_remapped_circuit( qbit_map, qbit_num );
2051 
2052 }
2053 
2054 
2061 Gates_block*
2062 Gates_block::create_remapped_circuit( const std::map<int, int>& qbit_map, const int qbit_num_ ) {
2063 
2064 
2065  Gates_block* ret = new Gates_block( qbit_num_ );
2066  for(std::vector<Gate*>::iterator it = gates.begin(); it != gates.end(); ++it) {
2067 
2068  Gate* op = *it;
2069  switch (op->get_type()) {
2070  case CNOT_OPERATION: case CZ_OPERATION:
2071  case CH_OPERATION: case SYC_OPERATION:
2072  case U1_OPERATION: case U2_OPERATION: case U3_OPERATION:
2073  case RY_OPERATION: case CRY_OPERATION: case RX_OPERATION:
2074  case RZ_OPERATION: case X_OPERATION:
2075  case Y_OPERATION: case Z_OPERATION:
2076  case SX_OPERATION: case BLOCK_OPERATION:
2077  case GENERAL_OPERATION: case UN_OPERATION:
2078  case ON_OPERATION: case COMPOSITE_OPERATION:
2079  case ADAPTIVE_OPERATION:
2080  case H_OPERATION:
2081  case T_OPERATION: case TDG_OPERATION:
2082  case CZ_NU_OPERATION:
2083  {
2084  Gate* cloned_op = op->clone();
2085 
2086  int target_qbit = cloned_op->get_target_qbit();
2087  int control_qbit = cloned_op->get_control_qbit();
2088 
2089  if ( qbit_num_ > qbit_num ) {
2090  // qbit num needs to be set in prior to avoid conflict
2091  cloned_op->set_qbit_num( qbit_num_ );
2092  }
2093 
2094  if (qbit_map.find( target_qbit ) != qbit_map.end()) {
2095  cloned_op->set_target_qbit( qbit_map.at(target_qbit) );
2096  } else {
2097  std::string err("Gates_block::create_remapped_circuit: Missing target qubit from the qbit map.");
2098  throw err;
2099  }
2100 
2101 
2102  if ( control_qbit != -1 ) {
2103  if ( qbit_map.find( control_qbit ) != qbit_map.end() ) {
2104  cloned_op->set_control_qbit( qbit_map.at(control_qbit) );
2105  } else {
2106  std::string err("Gates_block::create_remapped_circuit: Missing control qubit from the qbit map.");
2107  throw err;
2108  }
2109  }
2110 
2111  if ( qbit_num_ < qbit_num ) {
2112  // qbit num needs to be set post to avoid conflict
2113  cloned_op->set_qbit_num( qbit_num_ );
2114  }
2115 
2116  ret->add_gate( cloned_op );
2117 
2118  break;
2119  }
2120  default:
2121  std::string err("Gates_block::create_remapped_circuit: unimplemented gate");
2122  throw err;
2123  }
2124 
2125  }
2126 
2127  return ret;
2128 }
2129 
2130 
2135 void Gates_block::reorder_qubits( std::vector<int> qbit_list ) {
2136 
2137  for(std::vector<Gate*>::iterator it = gates.begin(); it != gates.end(); ++it) {
2138 
2139  Gate* gate = *it;
2140 
2141  if (gate->get_type() == CNOT_OPERATION) {
2142  CNOT* cnot_gate = static_cast<CNOT*>(gate);
2143  cnot_gate->reorder_qubits( qbit_list );
2144  }
2145  else if (gate->get_type() == CZ_OPERATION) {
2146  CZ* cz_gate = static_cast<CZ*>(gate);
2147  cz_gate->reorder_qubits( qbit_list );
2148  }
2149  else if (gate->get_type() == CH_OPERATION) {
2150  CH* ch_gate = static_cast<CH*>(gate);
2151  ch_gate->reorder_qubits( qbit_list );
2152  }
2153  else if (gate->get_type() == SYC_OPERATION) {
2154  SYC* syc_gate = static_cast<SYC*>(gate);
2155  syc_gate->reorder_qubits( qbit_list );
2156  }
2157  else if (gate->get_type() == U1_OPERATION) {
2158  U1* u1_gate = static_cast<U1*>(gate);
2159  u1_gate->reorder_qubits( qbit_list );
2160  }
2161  else if (gate->get_type() == U2_OPERATION) {
2162  U2* u2_gate = static_cast<U2*>(gate);
2163  u2_gate->reorder_qubits( qbit_list );
2164  }
2165  else if (gate->get_type() == U3_OPERATION) {
2166  U3* u3_gate = static_cast<U3*>(gate);
2167  u3_gate->reorder_qubits( qbit_list );
2168  }
2169  else if (gate->get_type() == R_OPERATION) {
2170  R* r_gate = static_cast<R*>(gate);
2171  r_gate->reorder_qubits( qbit_list );
2172  }
2173  else if (gate->get_type() == RX_OPERATION) {
2174  RX* rx_gate = static_cast<RX*>(gate);
2175  rx_gate->reorder_qubits( qbit_list );
2176  }
2177  else if (gate->get_type() == RY_OPERATION) {
2178  RY* ry_gate = static_cast<RY*>(gate);
2179  ry_gate->reorder_qubits( qbit_list );
2180  }
2181  else if (gate->get_type() == CRY_OPERATION) {
2182  CRY* cry_gate = static_cast<CRY*>(gate);
2183  cry_gate->reorder_qubits( qbit_list );
2184  }
2185  else if (gate->get_type() == CR_OPERATION) {
2186  CR* cr_gate = static_cast<CR*>(gate);
2187  cr_gate->reorder_qubits( qbit_list );
2188  }
2189  else if (gate->get_type() == CROT_OPERATION) {
2190  CROT* crot_gate = static_cast<CROT*>(gate);
2191  crot_gate->reorder_qubits( qbit_list );
2192  }
2193  else if (gate->get_type() == RZ_OPERATION) {
2194  RZ* rz_gate = static_cast<RZ*>(gate);
2195  rz_gate->reorder_qubits( qbit_list );
2196  }
2197  else if (gate->get_type() == H_OPERATION) {
2198  H* h_gate = static_cast<H*>(gate);
2199  h_gate->reorder_qubits( qbit_list );
2200  }
2201  else if (gate->get_type() == X_OPERATION) {
2202  X* x_gate = static_cast<X*>(gate);
2203  x_gate->reorder_qubits( qbit_list );
2204  }
2205  else if (gate->get_type() == Y_OPERATION) {
2206  Y* y_gate = static_cast<Y*>(gate);
2207  y_gate->reorder_qubits( qbit_list );
2208  }
2209  else if (gate->get_type() == Z_OPERATION) {
2210  Z* z_gate = static_cast<Z*>(gate);
2211  z_gate->reorder_qubits( qbit_list );
2212  }
2213  else if (gate->get_type() == T_OPERATION) {
2214  T* t_gate = static_cast<T*>(gate);
2215  t_gate->reorder_qubits( qbit_list );
2216  }
2217  else if (gate->get_type() == TDG_OPERATION) {
2218  Tdg* tdg_gate = static_cast<Tdg*>(gate);
2219  tdg_gate->reorder_qubits( qbit_list );
2220  }
2221  else if (gate->get_type() == SX_OPERATION) {
2222  SX* sx_gate = static_cast<SX*>(gate);
2223  sx_gate->reorder_qubits( qbit_list );
2224  }
2225  else if (gate->get_type() == BLOCK_OPERATION) {
2226  Gates_block* block_gate = static_cast<Gates_block*>(gate);
2227  block_gate->reorder_qubits( qbit_list );
2228  }
2229  else if (gate->get_type() == UN_OPERATION) {
2230  UN* un_gate = static_cast<UN*>(gate);
2231  un_gate->reorder_qubits( qbit_list );
2232  }
2233  else if (gate->get_type() == ON_OPERATION) {
2234  ON* on_gate = static_cast<ON*>(gate);
2235  on_gate->reorder_qubits( qbit_list );
2236  }
2237  else if (gate->get_type() == COMPOSITE_OPERATION) {
2238  Composite* com_gate = static_cast<Composite*>(gate);
2239  com_gate->reorder_qubits( qbit_list );
2240  }
2241  else if (gate->get_type() == ADAPTIVE_OPERATION) {
2242  Adaptive* ad_gate = static_cast<Adaptive*>(gate);
2243  ad_gate->reorder_qubits( qbit_list );
2244  }
2245  else {
2246  std::string err("Gates_block::reorder_qubits: unimplemented gate");
2247  throw err;
2248  }
2249 
2250 
2251  }
2252 
2253 }
2254 
2260 
2261  std::vector<int> involved_qbits;
2262 
2263  int qbit;
2264 
2265 
2266  for(std::vector<Gate*>::iterator it = gates.begin(); it != gates.end(); ++it) {
2267 
2268  Gate* gate = *it;
2269 
2270  qbit = gate->get_target_qbit();
2271  if (qbit != -1) {
2272  add_unique_elelement( involved_qbits, qbit );
2273  }
2274 
2275 
2276  qbit = gate->get_control_qbit();
2277  if (qbit != -1) {
2278  add_unique_elelement( involved_qbits, qbit );
2279  }
2280 
2281  }
2282 
2283  return involved_qbits;
2284 }
2285 
2286 
2291 std::vector<Gate*> Gates_block::get_gates() {
2292  return gates;
2293 }
2294 
2295 
2301 
2302  if (idx > (int)gates.size() ) {
2303  return NULL;
2304  }
2305 
2306  return gates[idx];
2307 }
2308 
2309 
2315 
2316  // getting the list of gates
2317  std::vector<Gate*> gates_in = op_block->get_gates();
2318 
2319  int qbit_num_loc = op_block->get_qbit_num();
2320  if ( qbit_num_loc != qbit_num ) {
2321  std::string err("Gates_block::combine: number of qubits in the circuits must be the same");
2322  throw err;
2323  }
2324 
2325  for(std::vector<Gate*>::iterator it = (gates_in).begin(); it != (gates_in).end(); ++it) {
2326  Gate* op = *it;
2327  Gate* op_cloned = op->clone();
2328  add_gate( op_cloned );
2329  }
2330 
2331 }
2332 
2333 
2338 void Gates_block::set_qbit_num( int qbit_num_in ) {
2339 
2340  if (qbit_num_in > 30) {
2341  std::string err("Gates_block::set_qbit_num: Number of qubits supported up to 30");
2342  throw err;
2343  }
2344 
2345  // setting the number of qubits
2346  Gate::set_qbit_num(qbit_num_in);
2347 
2348  // setting the number of qubit in the gates
2349  for(std::vector<Gate*>::iterator it = gates.begin(); it != gates.end(); ++it) {
2350  Gate* op = *it;
2351  switch (op->get_type()) {
2352  case CNOT_OPERATION: case CZ_OPERATION:
2353  case CH_OPERATION: case SYC_OPERATION:
2354  case U1_OPERATION: case U2_OPERATION: case U3_OPERATION:
2355  case RY_OPERATION: case CRY_OPERATION: case RX_OPERATION: case CR_OPERATION:
2356  case RZ_OPERATION: case X_OPERATION:
2357  case Y_OPERATION: case Z_OPERATION:
2358  case SX_OPERATION: case BLOCK_OPERATION:
2359  case GENERAL_OPERATION: case UN_OPERATION:
2360  case ON_OPERATION: case COMPOSITE_OPERATION:
2362  case H_OPERATION: case R_OPERATION:
2363  case CZ_NU_OPERATION:
2364  case T_OPERATION: case TDG_OPERATION:
2365  op->set_qbit_num( qbit_num_in );
2366  break;
2367  default:
2368  std::string err("Gates_block::set_qbit_num: unimplemented gate");
2369  throw err;
2370  }
2371  }
2372 }
2373 
2374 
2380 
2381  // creatign new instance of class Gates_block
2382  Gates_block* ret = new Gates_block( qbit_num );
2383 
2385  ret->set_parents( parents );
2386  ret->set_children( children );
2387 
2388  // extracting the gates from the current class
2389  if (extract_gates( ret ) != 0 ) {
2390  std::string err("Gates_block::clone(): extracting gates was not succesfull");
2391  throw err;
2392  };
2393 
2394  return ret;
2395 
2396 }
2397 
2398 
2405 
2406  op_block->release_gates();
2407 
2408  for ( std::vector<Gate*>::iterator it=gates.begin(); it != gates.end(); ++it ) {
2409  Gate* op = *it;
2410  switch (op->get_type()) {
2411  case CNOT_OPERATION: case CZ_OPERATION:
2412  case CH_OPERATION: case SYC_OPERATION:
2413  case U1_OPERATION: case U2_OPERATION: case U3_OPERATION:
2414  case RY_OPERATION: case CRY_OPERATION: case RX_OPERATION: case CR_OPERATION:
2415  case RZ_OPERATION: case X_OPERATION:
2416  case Y_OPERATION: case Z_OPERATION:
2417  case SX_OPERATION: case BLOCK_OPERATION:
2418  case GENERAL_OPERATION: case UN_OPERATION:
2419  case ON_OPERATION: case COMPOSITE_OPERATION:
2421  case H_OPERATION: case R_OPERATION:
2422  case CZ_NU_OPERATION:
2423  case T_OPERATION: case TDG_OPERATION:
2424  {
2425  Gate* op_cloned = op->clone();
2426  op_block->add_gate( op_cloned );
2427  break; }
2428  default:
2429  std::string err("Gates_block::extract_gates: unimplemented gate");
2430  throw err;
2431  }
2432 
2433  }
2434 
2435  return 0;
2436 
2437 }
2438 
2439 
2440 
2446 
2447  for ( std::vector<Gate*>::iterator it=gates.begin(); it != gates.end(); ++it ) {
2448  Gate* op = *it;
2449 
2450  if (op->get_type() == ADAPTIVE_OPERATION) {
2451  return true;
2452  }
2453  else if (op->get_type() == BLOCK_OPERATION) {
2454  Gates_block* block_op = static_cast<Gates_block*>( op );
2455  bool ret = block_op->contains_adaptive_gate();
2456  if ( ret ) return true;
2457  }
2458  }
2459 
2460  return false;
2461 
2462 }
2463 
2464 
2465 
2466 
2473 
2474 
2475  Gate* op = gates[idx];
2476 
2477  if (op->get_type() == ADAPTIVE_OPERATION) {
2478  return true;
2479  }
2480  else if (op->get_type() == BLOCK_OPERATION) {
2481  Gates_block* block_op = static_cast<Gates_block*>( op );
2482  return block_op->contains_adaptive_gate();
2483  }
2484 
2485  return false;
2486 
2487 }
2488 
2489 
2490 
2498 Matrix
2499 Gates_block::get_reduced_density_matrix( Matrix_real& parameters_mtx, Matrix& input_state, matrix_base<int>& qbit_list_subset ) {
2500 
2501 
2502  if (input_state.cols != 1) {
2503  std::string error("Gates_block::get_reduced_density_matrix: The number of columns in input state should be 1");
2504  throw error;
2505  }
2506 
2507 
2508  if (input_state.rows != matrix_size) {
2509  std::string error("Gates_block::get_reduced_density_matrix: The number of rows in input state should be 2^qbit_num");
2510  throw error;
2511  }
2512 
2513  // determine the transformed state
2514  Matrix transformed_state = input_state.copy();
2515  if ( parameters_mtx.size() > 0 ) {
2516  bool parallel = true;
2517  apply_to( parameters_mtx, transformed_state, parallel );
2518  }
2519 
2520 
2521  int subset_qbit_num = qbit_list_subset.size();
2522  int complementary_qbit_num = qbit_num - subset_qbit_num;
2523 
2524 
2525  // list of complementary qubits
2526  matrix_base<int> qbit_list_complementary( complementary_qbit_num, 1);
2527  int qbit_idx_count = 0;
2528  for (int qbit_idx=0; qbit_idx<qbit_num; qbit_idx++) {
2529 
2530  bool qbit_idx_in_subset = false;
2531 
2532  for (int subset_qbit_idx=0; subset_qbit_idx<subset_qbit_num; subset_qbit_idx++) {
2533  if ( qbit_idx == qbit_list_subset[subset_qbit_idx] ) {
2534  qbit_idx_in_subset = true;
2535  break;
2536  }
2537  }
2538 
2539 
2540  if ( qbit_idx_in_subset ) {
2541  continue;
2542  }
2543 
2544  qbit_list_complementary[qbit_idx_count] = qbit_idx;
2545  qbit_idx_count++;
2546  }
2547 
2548 
2549  // 000010000 one-hot encoded numbers indicating the bit position of the qubits in the register
2550  matrix_base<int> qbit_masks(qbit_num, 1);
2551  for (int qbit_idx=0; qbit_idx<qbit_num; qbit_idx++) {
2552  qbit_masks[ qbit_idx ] = 1 << qbit_idx;
2553  }
2554 
2555 
2556 
2557  // retrieve the reduced density matrix
2558  int rho_matrix_size = 1 << subset_qbit_num;
2559 
2560  Matrix rho(rho_matrix_size, rho_matrix_size);
2561  memset( rho.get_data(), 0.0, rho.size()*sizeof(QGD_Complex16) );
2562 
2563 
2564 
2565 
2566  int complementary_basis_num = 1 << complementary_qbit_num;
2567  for ( int row_idx=0; row_idx<rho_matrix_size; row_idx++ ) {
2568 
2569  // index of the amplitude in the state vector
2570  int idx = 0;
2571  for (int qbit_idx=0; qbit_idx<subset_qbit_num; qbit_idx++) {
2572  if ( row_idx & qbit_masks[ qbit_idx ] ) {
2573  idx = idx | qbit_masks[ qbit_list_subset[qbit_idx] ];
2574  }
2575  }
2576 
2577  for ( int col_idx=row_idx; col_idx<rho_matrix_size; col_idx++ ) {
2578 
2579  // index of the amplitude in the state vector
2580  int jdx = 0;
2581  for (int qbit_idx=0; qbit_idx<subset_qbit_num; qbit_idx++) {
2582  if ( col_idx & qbit_masks[ qbit_idx ] ) {
2583  jdx = jdx | qbit_masks[ qbit_list_subset[qbit_idx] ];
2584  }
2585  }
2586 
2587 
2588  // thread local storage for partial permanent
2589  tbb::combinable<QGD_Complex16> priv_addend {[](){QGD_Complex16 ret; ret.real = 0.0; ret.imag = 0.0; return ret;}};
2590 
2591 
2592  tbb::parallel_for( tbb::blocked_range<int>(0, complementary_basis_num, 1024), [&](tbb::blocked_range<int> r) {
2593 
2594  QGD_Complex16& rho_element_priv = priv_addend.local();
2595 
2596  for (int compl_idx=r.begin(); compl_idx<r.end(); compl_idx++) {
2597 
2598 
2599  int idx_loc = idx;
2600  int jdx_loc = jdx;
2601 
2602  for (int qbit_idx=0; qbit_idx<complementary_qbit_num; qbit_idx++) {
2603  if ( compl_idx & qbit_masks[ qbit_idx ] ) {
2604  idx_loc = idx_loc | qbit_masks[ qbit_list_complementary[qbit_idx] ];
2605  jdx_loc = jdx_loc | qbit_masks[ qbit_list_complementary[qbit_idx] ];
2606  }
2607  }
2608 
2609  QGD_Complex16 element_idx = transformed_state[ idx_loc ];
2610  QGD_Complex16& element_jdx = transformed_state[ jdx_loc ];
2611 
2612  // conjugate because of the bra-vector
2613  element_idx.imag = -element_idx.imag;
2614 
2615  QGD_Complex16 addend = mult( element_idx, element_jdx );
2616 
2617  rho_element_priv.real = rho_element_priv.real + addend.real;
2618  rho_element_priv.imag = rho_element_priv.imag + addend.imag;
2619 
2620 
2621  }
2622  });
2623 
2624 
2625 
2626  QGD_Complex16 rho_element;
2627  rho_element.real = 0.0;
2628  rho_element.imag = 0.0;
2629 
2630  priv_addend.combine_each([&](QGD_Complex16 &a) {
2631  rho_element.real = rho_element.real + a.real;
2632  rho_element.imag = rho_element.imag + a.imag;
2633  });
2634 
2635  rho[ row_idx * rho.stride + col_idx ].real += rho_element.real;
2636  rho[ row_idx * rho.stride + col_idx ].imag += rho_element.imag;
2637 
2638  if ( row_idx == col_idx ) {
2639  continue;
2640  }
2641 
2642  rho[ col_idx * rho.stride + row_idx ].real += rho_element.real;
2643  rho[ col_idx * rho.stride + row_idx ].imag -= rho_element.imag;
2644 
2645  }
2646 
2647 
2648  }
2649 
2650 
2651  // test the trace of the reduced density matrix
2652  double trace = 0.0;
2653  for( int idx=0; idx<rho_matrix_size; idx++) {
2654  trace = trace + rho[idx*rho.stride+idx].real;
2655  }
2656 
2657  if ( abs( trace-1.0 ) > 1e-6 ) {
2658  std::stringstream sstream;
2659  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;
2660  print(sstream, 1);
2661  }
2662 
2663  return rho;
2664 
2665 
2666 }
2667 
2668 
2676 double Gates_block::get_second_Renyi_entropy( Matrix_real& parameters_mtx, Matrix& input_state, matrix_base<int>& qbit_list_subset ) {
2677 
2678  // determine the reduced density matrix
2679  Matrix rho = get_reduced_density_matrix( parameters_mtx, input_state, qbit_list_subset );
2680 
2681 
2682  // calculate the second Rényi entropy
2683  // Tr( rho @ rho )
2684  double trace_rho_square = 0.0;
2685 
2686  for (int idx=0; idx<rho.rows; idx++) {
2687 
2688  double trace_tmp = 0.0;
2689 
2690  for (int jdx=0; jdx<rho.rows; jdx++) {
2691  QGD_Complex16& element = rho[ idx*rho.stride + jdx ];
2692  double tmp = element.real * element.real + element.imag * element.imag;
2693 
2694  trace_tmp = trace_tmp + tmp;
2695  }
2696 
2697 
2698  trace_rho_square = trace_rho_square + trace_tmp;
2699 
2700 
2701  }
2702 
2703 
2704 
2705 
2706  double entropy = -log(trace_rho_square);
2707 
2708 
2709  return entropy;
2710 
2711 }
2712 
2713 
2720 std::vector<int> remove_list_intersection( std::vector<int>& list1, std::vector<int>& list2 ) {
2721 
2722  std::vector<int> ret = list1;
2723 
2724  for( std::vector<int>::iterator it2 = list2.begin(); it2 != list2.end(); it2++ ) {
2725 
2726  std::vector<int>::iterator element_found = std::find(ret.begin(), ret.end(), *it2);
2727 
2728  if( element_found != ret.end() ) {
2729  ret.erase( element_found );
2730  }
2731 
2732  }
2733 
2734  return ret;
2735 
2736 
2737 
2738 }
2739 
2740 
2745 void
2747 
2748 
2749  std::vector<int>&& involved_qubits = gate->get_involved_qubits();
2750 /*
2751  std::cout << "involved qubits in the current gate: " << std::endl;
2752  for( int idx=0; idx<involved_qubits.size(); idx++ ) {
2753  std::cout << involved_qubits[idx] << ", ";
2754  }
2755  std::cout << std::endl;
2756  */
2757  // iterate over gates in the circuit
2758  for( int idx=gates.size()-1; idx>=0; idx-- ) {
2759  Gate* gate_loc = gates[idx];
2760  std::vector<int>&& involved_qubits_loc = gate_loc->get_involved_qubits();
2761 
2762  std::vector<int>&& reduced_qbit_list = remove_list_intersection( involved_qubits, involved_qubits_loc );
2763 
2764  if( reduced_qbit_list.size() < involved_qubits.size() ) {
2765  // parent gate found, setting parent-child relation
2766 
2767  gate->add_parent( gate_loc );
2768  gate_loc->add_child( gate );
2769 
2770  involved_qubits = std::move(reduced_qbit_list);
2771 
2772 
2773  }
2774 
2775 
2776  // return if no further involved qubits left
2777  if( involved_qubits.size() == 0 ) {
2778  break;
2779  }
2780  }
2781 
2782 
2783 }
2784 
2785 
2786 
2791 void
2793 
2794 
2795  std::vector<int>&& involved_qubits = gate->get_involved_qubits();
2796 
2797  // iterate over gates in the circuit
2798  for( int idx=0; idx<gates.size(); idx++ ) {
2799  Gate* gate_loc = gates[idx];
2800  std::vector<int>&& involved_qubits_loc = gate_loc->get_involved_qubits();
2801 
2802  std::vector<int>&& reduced_qbit_list = remove_list_intersection( involved_qubits, involved_qubits_loc );
2803 
2804  if( reduced_qbit_list.size() < involved_qubits.size() ) {
2805  // child gate found, setting parent-child relation
2806 
2807  gate->add_child( gate_loc );
2808  gate_loc->add_parent( gate );
2809 
2810  involved_qubits = std::move(reduced_qbit_list);
2811 
2812 
2813  }
2814 
2815 
2816  // return if no further involved qubits left
2817  if( involved_qubits.size() == 0 ) {
2818  break;
2819  }
2820  }
2821 
2822 }
2823 
2824 
2828 void
2830 
2831  int parameter_idx = 0;
2832 
2833  for( std::vector<Gate*>::iterator gate_it = gates.begin(); gate_it != gates.end(); gate_it++ ) {
2834 
2835  Gate* gate = *gate_it;
2836 
2837  gate->set_parameter_start_idx( parameter_idx );
2838 
2839  parameter_idx = parameter_idx + gate->get_parameter_num();
2840 
2841  }
2842 
2843 }
2844 
2845 
2849 void
2851 
2852  // first clear parent/children data from the gates
2853  for( std::vector<Gate*>::iterator gate_it = gates.begin(); gate_it != gates.end(); gate_it++ ) {
2854  Gate* gate = *gate_it;
2855  gate->clear_children();
2856  gate->clear_parents();
2857  }
2858 
2859 
2860  // first clear parent/children data from the gates
2861  for( std::vector<Gate*>::iterator gate_it = gates.begin(); gate_it != gates.end(); gate_it++ ) {
2862  Gate* gate = *gate_it;
2863 
2864  // determine the parents of the gate
2865  determine_parents( gate );
2866 
2867  }
2868 
2869 
2870 
2871 
2872 }
2873 
2874 
2878 Gates_block*
2880 
2881  Gates_block* flat_circuit = new Gates_block( qbit_num );
2882 
2883  for( std::vector<Gate*>::iterator gate_it=gates.begin(); gate_it != gates.end(); gate_it++ ) {
2884 
2885  Gate* gate = *gate_it;
2886 
2887  if( gate->get_type() == BLOCK_OPERATION ) {
2888 
2889  Gates_block* circuit_inner = static_cast<Gates_block*>( gate );
2890  Gates_block* flat_circuit_inner = circuit_inner->get_flat_circuit();
2891 
2892  flat_circuit->combine( flat_circuit_inner );
2893 
2894  delete( flat_circuit_inner );
2895  }
2896  else {
2897  flat_circuit->add_gate( gate->clone() );
2898  }
2899 
2900  }
2901 
2902 
2903 
2904  return flat_circuit;
2905 
2906 
2907 }
2908 
2909 
2910 
2916 Matrix_real
2918 
2919  if ( get_parameter_start_idx() + get_parameter_num() < parameters.size() ) {
2920  std::string err("Gates_block::extract_parameters: Cant extract parameters, since th einput arary has not enough elements.");
2921  throw err;
2922  }
2923 
2924  Matrix_real extracted_parameters(1, get_parameter_num());
2925 
2926  memcpy( extracted_parameters.get_data(), parameters.get_data() + get_parameter_start_idx(), get_parameter_num()*sizeof(double) );
2927 
2928  return extracted_parameters;
2929 
2930 }
2931 
2932 
2933 #ifdef __DFE__
2934 
2935 
2940 DFEgate_kernel_type* Gates_block::convert_to_DFE_gates_with_derivates( Matrix_real& parameters_mtx, int& gatesNum, int& gateSetNum, int& redundantGateSets, bool only_derivates ) {
2941 
2943  if ( parameter_num != parameters_mtx.size() ) {
2944  std::string error("Gates_block::convert_to_DFE_gates: wrong number of parameters");
2945  throw error;
2946  }
2947 
2948  std::map<std::string, int> gate_nums = get_gate_nums();
2949  int gates_total_num = 0;
2950  for( auto it=gate_nums.begin(); it != gate_nums.end(); it++ ) {
2951  gates_total_num = gates_total_num + it->second;
2952  }
2953 
2954  int chained_gates_num = get_chained_gates_num();
2955  int gate_padding = gates_total_num % chained_gates_num == 0 ? 0 : chained_gates_num - (gates_total_num % chained_gates_num);
2956  gatesNum = gates_total_num+gate_padding;
2957 /*
2958 std::cout << "chained gates num: " << chained_gates_num << std::endl;
2959 std::cout << "number of gates: " << gatesNum << std::endl;
2960 */
2961 
2962 
2963  gateSetNum = only_derivates ? parameter_num : parameter_num+1;
2964 
2965 #ifdef __MPI__
2966  int rem = gateSetNum % (4 * world_size );
2967  if ( rem == 0 ) {
2968  redundantGateSets = 0;
2969  }
2970  else {
2971  redundantGateSets = (4 * world_size ) - (gateSetNum % (4 * world_size ));
2972  gateSetNum = gateSetNum + redundantGateSets;
2973  }
2974 #else
2975  int rem = gateSetNum % 4;
2976  if ( rem == 0 ) {
2977  redundantGateSets = 0;
2978  }
2979  else {
2980  redundantGateSets = 4 - (gateSetNum % 4);
2981  gateSetNum = gateSetNum + redundantGateSets;
2982  }
2983 #endif
2984 
2985 
2986  DFEgate_kernel_type* DFEgates = new DFEgate_kernel_type[gatesNum*gateSetNum];
2987 
2988 
2989  int gate_idx = 0;
2990  convert_to_DFE_gates( parameters_mtx, DFEgates, gate_idx );
2991 
2992 
2993  // padding with identity gates
2994  for (int idx=gate_idx; idx<gatesNum; idx++ ){
2995 
2996  DFEgate_kernel_type& DFEGate = DFEgates[idx];
2997 
2998 
2999  DFEGate.target_qbit = 0;
3000  DFEGate.control_qbit = -1;
3001  DFEGate.gate_type = U3_OPERATION;
3002  DFEGate.ThetaOver2 = (int32_t)(0);
3003  DFEGate.Phi = (int32_t)(0);
3004  DFEGate.Lambda = (int32_t)(0);
3005  DFEGate.metadata = 0;
3006 
3007  }
3008 /*
3009  for ( int idx=0; idx<gatesNum; idx++ ) {
3010 
3011  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;
3012  }
3013 */
3014 
3015  // adjust parameters for derivation
3016  if (only_derivates ) {
3017  for (int idx=1; idx<(gateSetNum-1); idx++) {
3018  memcpy(DFEgates+idx*gatesNum, DFEgates, gatesNum*sizeof(DFEgate_kernel_type));
3019  }
3020  }
3021  else {
3022  for (int idx=0; idx<(gateSetNum-1); idx++) {
3023  memcpy(DFEgates+(idx+1)*gatesNum, DFEgates, gatesNum*sizeof(DFEgate_kernel_type));
3024  }
3025  }
3026 
3027  gate_idx = 0;
3028  int gate_set_index = parameter_num-1;
3029  if (only_derivates) {
3030  adjust_parameters_for_derivation( DFEgates, gatesNum, gate_idx, gate_set_index );
3031  }
3032  else {
3033  adjust_parameters_for_derivation( DFEgates+gatesNum, gatesNum, gate_idx, gate_set_index );
3034  }
3035 
3036 /*
3037  for ( int idx=0; idx<gatesNum*(parameter_num+1); idx++ ) {
3038 
3039  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;
3040  }
3041 */
3042  return DFEgates;
3043 
3044 }
3045 
3046 
3051 void Gates_block::adjust_parameters_for_derivation( DFEgate_kernel_type* DFEgates, const int gatesNum, int& gate_idx, int& gate_set_index) {
3052 
3054  //int gate_set_index = parameter_num-1;
3055 
3056  int32_t parameter_shift = (int32_t)(M_PI/2*(1<<25));
3057 
3058  for(int op_idx = gates.size()-1; op_idx>=0; op_idx--) {
3059 
3060  Gate* gate = gates[op_idx];
3061 //std::cout << gate_idx << " " << gate_set_index << " " << gate->get_type() << std::endl;
3062 
3063  if (gate->get_type() == CNOT_OPERATION) {
3064  gate_idx = gate_idx + 1;
3065  }
3066  else if (gate->get_type() == CZ_OPERATION) {
3067  gate_idx = gate_idx + 1;
3068  }
3069  else if (gate->get_type() == CH_OPERATION) {
3070  gate_idx = gate_idx + 1;
3071  }
3072  else if (gate->get_type() == SYC_OPERATION) {
3073  std::string error("Gates_block::convert_to_DFE_gates: SYC_gate not implemented");
3074  throw error;
3075  }
3076  else if (gate->get_type() == U1_OPERATION) {
3077  // Lambda parameter derivative
3078  DFEgate_kernel_type& DFEGate = DFEgates[gate_set_index*gatesNum + gate_idx];
3079  DFEGate.Lambda = DFEGate.Lambda + parameter_shift;
3080  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
3081  gate_set_index = gate_set_index - 1;
3082 
3083  parameter_idx = parameter_idx - 1;
3084  gate_idx = gate_idx + 1;
3085  }
3086  else if (gate->get_type() == U2_OPERATION) {
3087  // Lambda parameter derivative
3088  DFEgate_kernel_type& DFEGate2 = DFEgates[gate_set_index*gatesNum + gate_idx];
3089  DFEGate2.Lambda = DFEGate2.Lambda + parameter_shift;
3090  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
3091  gate_set_index = gate_set_index - 1;
3092 
3093  // Phi parameter derivative
3094  DFEgate_kernel_type& DFEGate = DFEgates[gate_set_index*gatesNum + gate_idx];
3095  DFEGate.Phi = DFEGate.Phi + parameter_shift;
3096  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
3097  gate_set_index = gate_set_index - 1;
3098 
3099  parameter_idx = parameter_idx - 2;
3100  gate_idx = gate_idx + 1;
3101  }
3102  else if (gate->get_type() == U3_OPERATION) {
3103  // Lambda parameter derivative
3104  DFEgate_kernel_type& DFEGate3 = DFEgates[gate_set_index*gatesNum + gate_idx];
3105  DFEGate3.Lambda = DFEGate3.Lambda + parameter_shift;
3106  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
3107  gate_set_index = gate_set_index - 1;
3108 
3109  // Phi parameter derivative
3110  DFEgate_kernel_type& DFEGate2 = DFEgates[gate_set_index*gatesNum + gate_idx];
3111  DFEGate2.Phi = DFEGate2.Phi + parameter_shift;
3112  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
3113  gate_set_index = gate_set_index - 1;
3114 
3115  // Theta parameter derivative
3116  DFEgate_kernel_type& DFEGate = DFEgates[gate_set_index*gatesNum + gate_idx];
3117  DFEGate.ThetaOver2 = DFEGate.ThetaOver2 + parameter_shift;
3118  DFEGate.metadata = (1<<7); // the leading bit indicates that derivate is processed
3119  gate_set_index = gate_set_index - 1;
3120 
3121  parameter_idx = parameter_idx - 3;
3122  gate_idx = gate_idx + 1;
3123  }
3124  else if (gate->get_type() == RX_OPERATION) { // Did not cehcked
3125 
3126  DFEgate_kernel_type& DFEGate = DFEgates[gate_set_index*gatesNum + gate_idx];
3127  DFEGate.ThetaOver2 = DFEGate.ThetaOver2 + parameter_shift;
3128  DFEGate.metadata = (1<<7); // the leading bit indicates that derivate is processed
3129  gate_set_index = gate_set_index - 1;
3130 
3131  parameter_idx = parameter_idx - 1;
3132 
3133  gate_idx = gate_idx + 1;
3134  }
3135  else if (gate->get_type() == RY_OPERATION) { // Did not cehcked
3136 
3137  DFEgate_kernel_type& DFEGate = DFEgates[gate_set_index*gatesNum + gate_idx];
3138  DFEGate.ThetaOver2 = DFEGate.ThetaOver2 + parameter_shift;
3139  DFEGate.metadata = (1<<7); // the leading bit indicates that derivate is processed
3140  gate_set_index = gate_set_index - 1;
3141 
3142  parameter_idx = parameter_idx - 1;
3143 
3144 
3145  gate_idx = gate_idx + 1;
3146  }
3147  else if (gate->get_type() == CRY_OPERATION) {
3148 
3149  DFEgate_kernel_type& DFEGate = DFEgates[gate_set_index*gatesNum + gate_idx];
3150  DFEGate.ThetaOver2 = DFEGate.ThetaOver2 + parameter_shift;
3151  DFEGate.metadata = (1<<7); // the leading bit indicates that derivate is processed
3152  gate_set_index = gate_set_index - 1;
3153 
3154  parameter_idx = parameter_idx - 1;
3155 
3156  gate_idx = gate_idx + 1;
3157  }
3158  else if (gate->get_type() == RZ_OPERATION) { // Did not cehcked
3159 
3160  std::string error("Gates_block::adjust_parameters_for_derivation: RZ gate not implemented for DFE");
3161  throw error;
3162  }
3163  else if (gate->get_type() == RZ_P_OPERATION) { // Did not cehcked
3164 
3165  DFEgate_kernel_type& DFEGate = DFEgates[gate_set_index*gatesNum + gate_idx];
3166  DFEGate.Phi = DFEGate.Phi + parameter_shift;
3167  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
3168  gate_set_index = gate_set_index - 1;
3169 
3170  parameter_idx = parameter_idx - 1;
3171 
3172  gate_idx = gate_idx + 1;
3173  }
3174  else if (gate->get_type() == H_OPERATION) {
3175  std::string error("Gates_block::convert_to_DFE_gates: H_gate not implemented");
3176  throw error;
3177 
3178  }
3179  else if (gate->get_type() == X_OPERATION) {
3180  std::string error("Gates_block::convert_to_DFE_gates: X_gate not implemented");
3181  throw error;
3182 
3183  }
3184  else if (gate->get_type() == Y_OPERATION) {
3185  std::string error("Gates_block::convert_to_DFE_gates: Y_gate not implemented");
3186  throw error;
3187 
3188  }
3189  else if (gate->get_type() == Z_OPERATION) {
3190  std::string error("Gates_block::convert_to_DFE_gates: Z_gate not implemented");
3191  throw error;
3192 
3193  }
3194  else if (gate->get_type() == T_OPERATION) {
3195  std::string error("Gates_block::convert_to_DFE_gates: T_gate not implemented");
3196  throw error;
3197 
3198  }
3199  else if (gate->get_type() == TDG_OPERATION) {
3200  std::string error("Gates_block::convert_to_DFE_gates: Tdg_gate not implemented");
3201  throw error;
3202  }
3203  else if (gate->get_type() == SX_OPERATION) {
3204  std::string error("Gates_block::convert_to_DFE_gates: SX_gate not implemented");
3205  throw error;
3206  }
3207  else if (gate->get_type() == BLOCK_OPERATION) {
3208 
3209  Gates_block* block_gate = static_cast<Gates_block*>(gate);
3210  block_gate->adjust_parameters_for_derivation( DFEgates, gatesNum, gate_idx, gate_set_index);
3211  //gate_set_index = gate_set_index - block_gate->get_parameter_num();
3212 
3213  parameter_idx = parameter_idx - block_gate->get_parameter_num();
3214  }
3215  else if (gate->get_type() == UN_OPERATION) {
3216  std::string error("Gates_block::convert_to_DFE_gates: UN_gate not implemented");
3217  throw error;
3218  }
3219  else if (gate->get_type() == ON_OPERATION) {
3220 
3221  // THE LAST GATE IS A GENERAL GATE APPENDED IN THE BLOCK-WISE OPTIMISATION ROUTINE OF DECOMPOSITION_BASE
3222  std::string error("Gates_block::convert_to_DFE_gates: ON_gate not implemented");
3223  throw error;
3224  }
3225  else if (gate->get_type() == COMPOSITE_OPERATION) {
3226  std::string error("Gates_block::convert_to_DFE_gates: Composite_gate not implemented");
3227  throw error;
3228  }
3229  else if (gate->get_type() == GENERAL_OPERATION) {
3230  std::string error("Gates_block::convert_to_DFE_gates: general_gate not implemented");
3231  throw error;
3232  }
3233  else if (gate->get_type() == ADAPTIVE_OPERATION) {
3234 
3235  DFEgate_kernel_type& DFEGate = DFEgates[gate_set_index*gatesNum + gate_idx];
3236  DFEGate.metadata = (1<<7); // the leading bit indicates that derivate is processed
3237  DFEGate.ThetaOver2 = DFEGate.ThetaOver2 + parameter_shift;
3238  gate_set_index = gate_set_index - 1;
3239 
3240  parameter_idx = parameter_idx - 1;
3241 
3242  gate_idx = gate_idx + 1;
3243  }
3244  else {
3245  std::string err("Gates_block::adjust_parameters_for_derivation: unimplemented gate");
3246  throw err;
3247  }
3248 
3249  }
3250 
3251 
3252 }
3253 
3254 
3260 Gates_block::convert_to_batched_DFE_gates( std::vector<Matrix_real>& parameters_mtx_vec, int& gatesNum, int& gateSetNum, int& redundantGateSets ) {
3261 
3262 
3263  std::map<std::string, int> gate_nums = get_gate_nums();
3264  int gates_total_num = 0;
3265  for( auto it=gate_nums.begin(); it != gate_nums.end(); it++ ) {
3266  gates_total_num = gates_total_num + it->second;
3267  }
3268 
3269  int chained_gates_num = get_chained_gates_num();
3270  int gate_padding = gates_total_num % chained_gates_num == 0 ? 0 : chained_gates_num - (gates_total_num % chained_gates_num);
3271  gatesNum = gates_total_num+gate_padding;
3272 /*
3273 std::cout << "chained gates num: " << chained_gates_num << std::endl;
3274 std::cout << "number of gates: " << gatesNum << std::endl;
3275 */
3276 
3277 
3278  gateSetNum = parameters_mtx_vec.size();
3279 
3280 #ifdef __MPI__
3281  int rem = gateSetNum % (4 * world_size );
3282  if ( rem == 0 ) {
3283  redundantGateSets = 0;
3284  }
3285  else {
3286  redundantGateSets = (4 * world_size ) - (gateSetNum % (4 * world_size ));
3287  gateSetNum = gateSetNum + redundantGateSets;
3288  }
3289 #else
3290  int rem = gateSetNum % 4;
3291  if ( rem == 0 ) {
3292  redundantGateSets = 0;
3293  }
3294  else {
3295  redundantGateSets = 4 - (gateSetNum % 4);
3296  gateSetNum = gateSetNum + redundantGateSets;
3297  }
3298 #endif
3299 
3300  DFEgate_kernel_type* DFEgates = new DFEgate_kernel_type[gatesNum*gateSetNum];
3301 
3302 
3303  tbb::parallel_for( 0, gateSetNum, 1, [&](int gateset_idx) {
3304 
3305  int gate_idx = gateset_idx * gatesNum;
3306 
3307  if ( gateset_idx < parameters_mtx_vec.size() ) {
3308  Matrix_real& parameters_mtx = parameters_mtx_vec[gateset_idx];
3309  convert_to_DFE_gates( parameters_mtx, DFEgates, gate_idx );
3310  }
3311 
3312  // padding with identity gates
3313  for (int idx=gate_idx; idx<(gateset_idx+1)*gatesNum; idx++ ){
3314 
3315  DFEgate_kernel_type& DFEGate = DFEgates[idx];
3316 
3317 
3318  DFEGate.target_qbit = 0;
3319  DFEGate.control_qbit = -1;
3320  DFEGate.gate_type = U3_OPERATION;
3321  DFEGate.ThetaOver2 = (int32_t)(0);
3322  DFEGate.Phi = (int32_t)(0);
3323  DFEGate.Lambda = (int32_t)(0);
3324  DFEGate.metadata = 0;
3325 
3326  gate_idx++;
3327 
3328  }
3329 
3330  });
3331 
3332 
3333  return DFEgates;
3334 
3335 }
3336 
3341 DFEgate_kernel_type* Gates_block::convert_to_DFE_gates( Matrix_real& parameters_mtx, int& gatesNum ) {
3342 
3344  if ( parameter_num != parameters_mtx.size() ) {
3345  std::string error("Gates_block::convert_to_DFE_gates: wrong number of parameters");
3346  throw error;
3347  }
3348 
3349 
3350  std::map<std::string, int> gate_nums = get_gate_nums();
3351  int gates_total_num = 0;
3352  for( auto it=gate_nums.begin(); it != gate_nums.end(); it++ ) {
3353  gates_total_num = gates_total_num + it->second;
3354  }
3355 
3356  int chained_gates_num = get_chained_gates_num();
3357  int gate_padding = chained_gates_num - (gates_total_num % chained_gates_num);
3358  gatesNum = gates_total_num+gate_padding;
3359 
3360 
3361 
3362  DFEgate_kernel_type* DFEgates = new DFEgate_kernel_type[gates_total_num+gate_padding];
3363 
3364  int gate_idx = 0;
3365  convert_to_DFE_gates( parameters_mtx, DFEgates, gate_idx );
3366 
3367 
3368  // padding with identity gates
3369  for (int idx=gate_idx; idx<gatesNum; idx++ ){
3370 
3371  DFEgate_kernel_type& DFEGate = DFEgates[idx];
3372 
3373 
3374  DFEGate.target_qbit = 0;
3375  DFEGate.control_qbit = -1;
3376  DFEGate.gate_type = U3_OPERATION;
3377  DFEGate.ThetaOver2 = (int32_t)(0);
3378  DFEGate.Phi = (int32_t)(0);
3379  DFEGate.Lambda = (int32_t)(0);
3380  DFEGate.metadata = 0;
3381 
3382  }
3383 /*
3384  for ( int idx=0; idx<gatesNum; idx++ ) {
3385 
3386  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;
3387  }
3388 */
3389 
3390 
3391  return DFEgates;
3392 
3393 }
3394 
3395 
3396 
3401 void Gates_block::convert_to_DFE_gates( const Matrix_real& parameters_mtx, DFEgate_kernel_type* DFEgates, int& start_index ) {
3402 
3403 
3404  int& gate_idx = start_index;
3406  double *parameters_data = parameters_mtx.get_data();
3407  //const_cast <Matrix_real&>(parameters);
3408 
3409 
3410  for(int op_idx = gates.size()-1; op_idx>=0; op_idx--) {
3411 
3412  Gate* gate = gates[op_idx];
3413  DFEgate_kernel_type& DFEGate = DFEgates[gate_idx];
3414 
3415  if (gate->get_type() == CNOT_OPERATION) {
3416  CNOT* cnot_gate = static_cast<CNOT*>(gate);
3417  DFEGate.target_qbit = cnot_gate->get_target_qbit();
3418  DFEGate.control_qbit = cnot_gate->get_control_qbit();
3419  DFEGate.gate_type = CNOT_OPERATION;
3420  DFEGate.ThetaOver2 = (int32_t)(M_PI/2*(1<<25));
3421  DFEGate.Phi = (int32_t)(0);
3422  DFEGate.Lambda = (int32_t)(M_PI*(1<<25));
3423  DFEGate.metadata = 0;
3424  gate_idx = gate_idx + 1;
3425  }
3426  else if (gate->get_type() == CZ_OPERATION) {
3427  CZ* cz_gate = static_cast<CZ*>(gate);
3428  DFEGate.target_qbit = cz_gate->get_target_qbit();
3429  DFEGate.control_qbit = cz_gate->get_control_qbit();
3430  DFEGate.gate_type = CZ_OPERATION;
3431  DFEGate.ThetaOver2 = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3432  DFEGate.Phi = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3433  DFEGate.Lambda = (int32_t)(M_PI*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3434  DFEGate.metadata = 0;
3435  gate_idx = gate_idx + 1;
3436  }
3437  else if (gate->get_type() == CH_OPERATION) {
3438  CH* ch_gate = static_cast<CH*>(gate);
3439  DFEGate.target_qbit = ch_gate->get_target_qbit();
3440  DFEGate.control_qbit = ch_gate->get_control_qbit();
3441  DFEGate.gate_type = CH_OPERATION;
3442  DFEGate.ThetaOver2 = (int32_t)(M_PI/4*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3443  DFEGate.Phi = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3444  DFEGate.Lambda = (int32_t)(M_PI*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3445  DFEGate.metadata = 0;
3446  gate_idx = gate_idx + 1;
3447  }
3448  else if (gate->get_type() == SYC_OPERATION) {
3449  std::string error("Gates_block::convert_to_DFE_gates: SYC_gate not implemented");
3450  throw error;
3451  }
3452  else if (gate->get_type() == U1_OPERATION) {
3453  double lambda = std::fmod(parameters_data[parameter_idx-1], 2*M_PI);
3454  parameter_idx = parameter_idx - 1;
3455 
3456  DFEGate.target_qbit = gate->get_target_qbit();
3457  DFEGate.control_qbit = -1;
3458  DFEGate.gate_type = U1_OPERATION;
3459  DFEGate.ThetaOver2 = (int32_t)(0);
3460  DFEGate.Phi = (int32_t)(0);
3461  DFEGate.Lambda = (int32_t)(lambda*(1<<25));
3462  DFEGate.metadata = 0;
3463  gate_idx = gate_idx + 1;
3464  }
3465  else if (gate->get_type() == U2_OPERATION) {
3466  double phi = std::fmod(parameters_data[parameter_idx-2], 2*M_PI);
3467  double lambda = std::fmod(parameters_data[parameter_idx-1], 2*M_PI);
3468  parameter_idx = parameter_idx - 2;
3469 
3470  DFEGate.target_qbit = gate->get_target_qbit();
3471  DFEGate.control_qbit = -1;
3472  DFEGate.gate_type = U2_OPERATION;
3473  DFEGate.ThetaOver2 = (int32_t)(M_PI/4*(1<<25)); // theta/2 = pi/4 for U2
3474  DFEGate.Phi = (int32_t)(phi*(1<<25));
3475  DFEGate.Lambda = (int32_t)(lambda*(1<<25));
3476  DFEGate.metadata = 0;
3477  gate_idx = gate_idx + 1;
3478  }
3479  else if (gate->get_type() == U3_OPERATION) {
3480  double theta = std::fmod(parameters_data[parameter_idx-3], 4*M_PI);
3481  double phi = std::fmod(parameters_data[parameter_idx-2], 2*M_PI);
3482  double lambda = std::fmod(parameters_data[parameter_idx-1], 2*M_PI);
3483  parameter_idx = parameter_idx - 3;
3484 
3485  DFEGate.target_qbit = gate->get_target_qbit();
3486  DFEGate.control_qbit = -1;
3487  DFEGate.gate_type = U3_OPERATION;
3488  DFEGate.ThetaOver2 = (int32_t)(theta/2.0*(1<<25)); // theta/2
3489  DFEGate.Phi = (int32_t)(phi*(1<<25));
3490  DFEGate.Lambda = (int32_t)(lambda*(1<<25));
3491  DFEGate.metadata = 0;
3492  gate_idx = gate_idx + 1;
3493  }
3494  else if (gate->get_type() == RX_OPERATION) {
3495  // definig the rotation parameter
3496  double varthetaOver2;
3497  // get the inverse parameters of the U3 rotation
3498  RX* rx_gate = static_cast<RX*>(gate);
3499  varthetaOver2 = std::fmod( parameters_data[parameter_idx-1], 2*M_PI);
3500  parameter_idx = parameter_idx - 1;
3501 
3502  DFEGate.target_qbit = rx_gate->get_target_qbit();
3503  DFEGate.control_qbit = -1;
3504  DFEGate.gate_type = RX_OPERATION;
3505  DFEGate.ThetaOver2 = (int32_t)(varthetaOver2*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3506  DFEGate.Phi = (int32_t)(-M_PI/2*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3507  DFEGate.Lambda = (int32_t)(M_PI/2*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3508  DFEGate.metadata = 0;
3509 
3510  gate_idx = gate_idx + 1;
3511  }
3512  else if (gate->get_type() == RY_OPERATION) {
3513  // definig the rotation parameter
3514  double varthetaOver2;
3515  // get the inverse parameters of the U3 rotation
3516  RY* ry_gate = static_cast<RY*>(gate);
3517  varthetaOver2 = std::fmod( parameters_data[parameter_idx-1], 2*M_PI);
3518  parameter_idx = parameter_idx - 1;
3519 
3520  DFEGate.target_qbit = ry_gate->get_target_qbit();
3521  DFEGate.control_qbit = -1;
3522  DFEGate.gate_type = RY_OPERATION;
3523  DFEGate.ThetaOver2 = (int32_t)(varthetaOver2*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3524  DFEGate.Phi = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3525  DFEGate.Lambda = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3526  DFEGate.metadata = 0;
3527 
3528  gate_idx = gate_idx + 1;
3529  }
3530  else if (gate->get_type() == CRY_OPERATION) {
3531  // definig the rotation parameter
3532  double Phi;
3533  // get the inverse parameters of the U3 rotation
3534  CRY* cry_gate = static_cast<CRY*>(gate);
3535  double varthetaOver2 = std::fmod( parameters_data[parameter_idx-1], 2*M_PI);
3536  parameter_idx = parameter_idx - 1;
3537  DFEGate.target_qbit = cry_gate->get_target_qbit();
3538  DFEGate.control_qbit = cry_gate->get_control_qbit();
3539  DFEGate.gate_type = CRY_OPERATION;
3540  DFEGate.ThetaOver2 = (int32_t)(varthetaOver2*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3541  DFEGate.Phi = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3542  DFEGate.Lambda = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3543  DFEGate.metadata = 0;
3544 
3545  gate_idx = gate_idx + 1;
3546  }
3547  else if (gate->get_type() == RZ_OPERATION) { // Did not cehcked
3548 
3549  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");
3550  throw error;
3551  }
3552  else if (gate->get_type() == RZ_P_OPERATION) {
3553 
3554 
3555  // definig the rotation parameter
3556  double varphi;
3557  // get the inverse parameters of the U3 rotation
3558  RZ* rz_gate = static_cast<RZ*>(gate);
3559  varphi = std::fmod( parameters_data[parameter_idx-1], 2*M_PI);
3560  parameter_idx = parameter_idx - 1;
3561 
3562  DFEGate.target_qbit = rz_gate->get_target_qbit();
3563  DFEGate.control_qbit = -1;
3564  DFEGate.gate_type = RZ_P_OPERATION;
3565  DFEGate.ThetaOver2 = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3566  DFEGate.Phi = (int32_t)(varphi*(1<<25)); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3567  DFEGate.Lambda = (int32_t)(0); // TODO: check !!!!!!!!!!!!!!!!!!!!!!!!!!!
3568  DFEGate.metadata = 0;
3569 
3570  gate_idx = gate_idx + 1;
3571  }
3572  else if (gate->get_type() == H_OPERATION) {
3573  // get the inverse parameters of the Hadamard rotation
3574  H* h_gate = static_cast<H*>(gate);
3575 
3576  std::string error("Gates_block::convert_to_DFE_gates: Hadamard gate not implemented");
3577  throw error;
3578 
3579  gate_idx = gate_idx + 1;
3580  }
3581  else if (gate->get_type() == X_OPERATION) {
3582  // get the inverse parameters of the U3 rotation
3583  X* x_gate = static_cast<X*>(gate);
3584 
3585  DFEGate.target_qbit = x_gate->get_target_qbit();
3586  DFEGate.control_qbit = -1;
3587  DFEGate.gate_type = X_OPERATION;
3588  DFEGate.ThetaOver2 = (int32_t)(M_PI/2*(1<<25));
3589  DFEGate.Phi = (int32_t)(0);
3590  DFEGate.Lambda = (int32_t)(M_PI*(1<<25));
3591  DFEGate.metadata = 0;
3592 
3593  gate_idx = gate_idx + 1;
3594  }
3595  else if (gate->get_type() == Y_OPERATION) {
3596  // get the inverse parameters of the U3 rotation
3597  Y* y_gate = static_cast<Y*>(gate);
3598 
3599  DFEGate.target_qbit = y_gate->get_target_qbit();
3600  DFEGate.control_qbit = -1;
3601  DFEGate.gate_type = Y_OPERATION;
3602  DFEGate.ThetaOver2 = (int32_t)(M_PI/2*(1<<25));
3603  DFEGate.Phi = (int32_t)(M_PI/2*(1<<25));
3604  DFEGate.Lambda = (int32_t)(M_PI/2*(1<<25));
3605  DFEGate.metadata = 0;
3606 
3607  gate_idx = gate_idx + 1;
3608  }
3609  else if (gate->get_type() == Z_OPERATION) {
3610  // get the inverse parameters of the U3 rotation
3611  Z* z_gate = static_cast<Z*>(gate);
3612 
3613  DFEGate.target_qbit = z_gate->get_target_qbit();
3614  DFEGate.control_qbit = -1;
3615  DFEGate.gate_type = Z_OPERATION;
3616  DFEGate.ThetaOver2 = (int32_t)(0);
3617  DFEGate.Phi = (int32_t)(0);
3618  DFEGate.Lambda = (int32_t)(M_PI*(1<<25));
3619  DFEGate.metadata = 0;
3620 
3621  gate_idx = gate_idx + 1;
3622  }
3623  else if (gate->get_type() == SX_OPERATION) {
3624  // get the inverse parameters of the U3 rotation
3625  SX* sx_gate = static_cast<SX*>(gate);
3626  std::string error("Gates_block::convert_to_DFE_gates: SX_gate not implemented");
3627  throw error;
3628  }
3629  else if (gate->get_type() == BLOCK_OPERATION) {
3630  Gates_block* block_gate = static_cast<Gates_block*>(gate);
3631  const Matrix_real parameters_layer_mtx(parameters_mtx.get_data() + parameter_idx - gate->get_parameter_num(), 1, gate->get_parameter_num() );
3632  block_gate->convert_to_DFE_gates( parameters_layer_mtx, DFEgates, gate_idx );
3633  parameter_idx = parameter_idx - block_gate->get_parameter_num();
3634  }
3635  else if (gate->get_type() == UN_OPERATION) {
3636  std::string error("Gates_block::convert_to_DFE_gates: UN_gate not implemented");
3637  throw error;
3638  }
3639  else if (gate->get_type() == ON_OPERATION) {
3640 
3641  // THE LAST GATE IS A GENERAL GATE APPENDED IN THE BLOCK-WISE OPTIMISATION ROUTINE OF DECOMPOSITION_BASE
3642  std::string error("Gates_block::convert_to_DFE_gates: ON_gate not implemented");
3643  throw error;
3644  }
3645  else if (gate->get_type() == COMPOSITE_OPERATION) {
3646  std::string error("Gates_block::convert_to_DFE_gates: Composite_gate not implemented");
3647  throw error;
3648  }
3649  else if (gate->get_type() == GENERAL_OPERATION) {
3650  std::string error("Gates_block::convert_to_DFE_gates: general_gate not implemented");
3651  throw error;
3652  }
3653  else if (gate->get_type() == ADAPTIVE_OPERATION) {
3654  // definig the rotation parameter
3655  double Phi;
3656  // get the inverse parameters of the U3 rotation
3657  Adaptive* ad_gate = static_cast<Adaptive*>(gate);
3658  double varthetaOver2 = std::fmod( activation_function(parameters_data[parameter_idx-1], ad_gate->get_limit()), 2*M_PI);
3659  parameter_idx = parameter_idx - 1;
3660  DFEGate.target_qbit = ad_gate->get_target_qbit();
3661  DFEGate.control_qbit = ad_gate->get_control_qbit();
3662  DFEGate.gate_type = ADAPTIVE_OPERATION;
3663  DFEGate.ThetaOver2 = (int32_t)(varthetaOver2*(1<<25));
3664  DFEGate.Phi = (int32_t)(0);
3665  DFEGate.Lambda = (int32_t)(0);
3666  DFEGate.metadata = 0;
3667 
3668  gate_idx = gate_idx + 1;
3669  }
3670  else {
3671  std::string err("Gates_block::convert_to_DFE_gates: unimplemented gate");
3672  throw err;
3673  }
3674 
3675  }
3676 
3677 
3678  return;
3679 
3680 }
3681 
3682 
3683 #endif
3684 
3685 
3686 #ifdef __GROQ__
3687 
3688 //TODO docstring
3689 void
3690 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)
3691 {
3692 
3693  if ( u3_qbit.size() == 0 ) {
3694  std::map<std::string, int> gate_nums = get_gate_nums();
3695  int gates_total_num = 0;
3696  for( auto it=gate_nums.begin(); it != gate_nums.end(); it++ ) {
3697  gates_total_num = gates_total_num + it->second;
3698  }
3699 
3700  u3_qbit.reserve( gates_total_num );
3701  target_qbit.reserve( gates_total_num );
3702  control_qbit.reserve( gates_total_num );
3703  }
3704 /*
3705  u3_qbit.reserve(u3_qbit.capacity() + gates.size());
3706  target_qbit.reserve(target_qbit.capacity() + gates.size());
3707  control_qbit.reserve(control_qbit.capacity() + gates.size());
3708 */
3709  double* parameters = parameters_mtx.get_data();
3710 
3711 
3712  for( int idx=0; idx<gates.size(); idx++) {
3713  Gate* operation = gates[idx];
3714  //parameters = parameters + operation->get_parameter_num();
3715 
3716  Matrix_real params_mtx(parameters + operation->get_parameter_start_idx(), 1, operation->get_parameter_num());
3717 
3718  switch (operation->get_type()) {
3719  case CNOT_OPERATION: case CZ_OPERATION:
3720  case CH_OPERATION: {
3721  CNOT* cnot_operation = static_cast<CNOT*>(operation);
3722  u3_qbit.push_back(cnot_operation->calc_one_qubit_u3());
3723  break;
3724  }
3725  case H_OPERATION: {
3726  H* h_operation = static_cast<H*>(operation);
3727  u3_qbit.push_back(h_operation->calc_one_qubit_u3());
3728  break;
3729  }
3730  case X_OPERATION: {
3731  X* x_operation = static_cast<X*>(operation);
3732  u3_qbit.push_back(x_operation->calc_one_qubit_u3());
3733  break;
3734  }
3735  case Y_OPERATION: {
3736  Y* y_operation = static_cast<Y*>(operation);
3737  u3_qbit.push_back(y_operation->calc_one_qubit_u3());
3738  break;
3739  }
3740  case Z_OPERATION: {
3741  Z* z_operation = static_cast<Z*>(operation);
3742  u3_qbit.push_back(z_operation->calc_one_qubit_u3());
3743  break;
3744  }
3745  case T_OPERATION: {
3746  T* t_operation = static_cast<T*>(operation);
3747  u3_qbit.push_back(t_operation->calc_one_qubit_u3());
3748  break;
3749  }
3750  case TDG_OPERATION: {
3751  Tdg* tdg_operation = static_cast<Tdg*>(operation);
3752  u3_qbit.push_back(tdg_operation->calc_one_qubit_u3());
3753  break;
3754  }
3755  case SX_OPERATION: {
3756  SX* sx_operation = static_cast<SX*>(operation);
3757  u3_qbit.push_back(sx_operation->calc_one_qubit_u3());
3758  break;
3759  }
3760  case U1_OPERATION: {
3761  U1* u1_operation = static_cast<U1*>(operation);
3762  u3_qbit.push_back(u1_operation->calc_one_qubit_u3(params_mtx[0]));
3763  break;
3764  }
3765  case U2_OPERATION: {
3766  U2* u2_operation = static_cast<U2*>(operation);
3767  u3_qbit.push_back(u2_operation->calc_one_qubit_u3(params_mtx[0], params_mtx[1]));
3768  break;
3769  }
3770  case U3_OPERATION: {
3771  U3* u3_operation = static_cast<U3*>(operation);
3772  u3_qbit.push_back(u3_operation->calc_one_qubit_u3(params_mtx[0], params_mtx[1], params_mtx[2]));
3773  break;
3774  }
3775  case RX_OPERATION: {
3776  RX* rx_operation = static_cast<RX*>(operation);
3777  // set static values for the angles
3778  double ThetaOver2 = params_mtx[0];
3779  double Phi = -M_PI/2;
3780  double Lambda = M_PI/2;
3781  rx_operation->parameters_for_calc_one_qubit(ThetaOver2, Phi, Lambda);
3782  u3_qbit.push_back(rx_operation->calc_one_qubit_u3(ThetaOver2, Phi, Lambda));
3783  break;
3784  }
3785  case RY_OPERATION: {
3786  RY* ry_operation = static_cast<RY*>(operation);
3787  double ThetaOver2 = params_mtx[0];
3788  double Phi = 0.0;
3789  double Lambda = 0.0;
3790  ry_operation->parameters_for_calc_one_qubit(ThetaOver2, Phi, Lambda);
3791  u3_qbit.push_back(ry_operation->calc_one_qubit_u3(ThetaOver2, Phi, Lambda));
3792  break;
3793  }
3794  case CRY_OPERATION: {
3795  CRY* cry_operation = static_cast<CRY*>(operation);
3796  double ThetaOver2, Phi, Lambda;
3797  ThetaOver2 = params_mtx[0];
3798  cry_operation->parameters_for_calc_one_qubit(ThetaOver2, Phi, Lambda);
3799  u3_qbit.push_back(cry_operation->calc_one_qubit_u3(ThetaOver2, Phi, Lambda));
3800  break;
3801  }
3802  case RZ_OPERATION: {
3803  RZ* rz_operation = static_cast<RZ*>(operation);
3804  u3_qbit.push_back(rz_operation->calc_one_qubit_u3(params_mtx[0]));
3805  break;
3806  }
3807 /*
3808  case RZ_P_OPERATION: {
3809  RZ_P* rz_p_operation = static_cast<RZ_P*>(operation);
3810  double ThetaOver2, Phi, Lambda;
3811  Phi = params_mtx[0];
3812  rz_p_operation->parameters_for_calc_one_qubit(ThetaOver2, Phi, Lambda);
3813  u3_qbit.push_back(rz_p_operation->calc_one_qubit_u3(ThetaOver2, Phi, Lambda));
3814  break;
3815  }
3816 */
3817  case BLOCK_OPERATION: {
3818 
3819  Gates_block* block_operation = static_cast<Gates_block*>(operation);
3820  //std::vector<Gate*> involved_gates = block_operation->get_gates();
3821 
3822  std::vector<int>&& involved_qubits = block_operation->get_involved_qubits();
3823 
3824  if ( involved_qubits.size() == 1 && block_operation->gates.size() > 1 && block_operation->get_qbit_num() > 1 ) {
3825  // possibly merge successive single qubit gates
3826 
3827  Gates_block gates_block_mini = Gates_block(1);
3828 
3829  for (int idx=0; idx<block_operation->gates.size(); idx++){
3830  Gate* gate = block_operation->gates[idx]->clone();
3831  gate->set_target_qbit(0);
3832  gate->set_qbit_num(1);
3833 
3834  gates_block_mini.add_gate(gate);
3835  }
3836 
3837  Matrix merged_kernel = create_identity(2);
3838 
3839  gates_block_mini.apply_to(params_mtx, merged_kernel);
3840 
3841  u3_qbit.push_back( merged_kernel );
3842  target_qbit.push_back( involved_qubits[0] );
3843  control_qbit.push_back( -1 );
3844 
3845  }
3846  else {
3847  block_operation->extract_gate_kernels_target_and_control_qubits(u3_qbit, target_qbit, control_qbit, params_mtx);
3848  }
3849  continue;
3850  }
3851  //case ADAPTIVE_OPERATION:
3852  //case SYC_OPERATION:
3853  //case UN_OPERATION:
3854  //case ON_OPERATION:
3855  //case COMPOSITE_OPERATION:
3856  //case GENERAL_OPERATION:
3857  default:
3858  std::string err("Optimization_Interface::apply_to: unimplemented gate (" + std::to_string(operation->get_type()) + ")");
3859  throw err;
3860  }
3861 
3862  target_qbit.push_back(operation->get_target_qbit());
3863  control_qbit.push_back(operation->get_control_qbit());
3864  }
3865 
3866 
3867 
3868 }
3869 #endif
3870 
3871 
3872 
3877 void
3878 export_gate_list_to_binary(Matrix_real& parameters, Gates_block* gates_block, const std::string& filename, int verbosity) {
3879 
3880  std::stringstream sstream;
3881  sstream << "Exporting circuit into binary format. Filename: " << filename << std::endl;
3882  logging log;
3883  log.verbose = verbosity;
3884  log.print(sstream, 3);
3885 
3886  FILE* pFile;
3887  const char* c_filename = filename.c_str();
3888 
3889  pFile = fopen(c_filename, "wb");
3890  if (pFile==NULL) {fputs ("File error",stderr); exit (1);}
3891 
3892  export_gate_list_to_binary( parameters, gates_block, pFile, verbosity );
3893 
3894  fclose(pFile);
3895  return;
3896 
3897 }
3898 
3899 
3900 
3905 void
3906 export_gate_list_to_binary(Matrix_real& parameters, Gates_block* gates_block, FILE* pFile, int verbosity) {
3907 
3908  int qbit_num = gates_block->get_qbit_num();
3909  fwrite(&qbit_num, sizeof(int), 1, pFile);
3910 
3911  int parameter_num = gates_block->get_parameter_num();
3912  fwrite(&parameter_num, sizeof(int), 1, pFile);
3913 
3914 
3915  int gates_num = gates_block->get_gate_num();
3916  fwrite(&gates_num, sizeof(int), 1, pFile);
3917 
3918 
3919 
3920  std::vector<Gate*> gates = gates_block->get_gates();
3921  double* parameters_data = parameters.get_data();
3922 
3923  for ( std::vector<Gate*>::iterator it=gates.begin(); it != gates.end(); ++it ) {
3924  Gate* op = *it;
3925 
3926  gate_type gt_type = op->get_type();
3927 
3928  fwrite(&gt_type, sizeof(gate_type), 1, pFile);
3929 
3930  int parameter_num = op->get_parameter_num();
3931 
3932  if (gt_type == CNOT_OPERATION || gt_type == CZ_OPERATION || gt_type == CH_OPERATION || gt_type == SYC_OPERATION) {
3933  int target_qbit = op->get_target_qbit();
3934  int control_qbit = op->get_control_qbit();
3935  fwrite(&target_qbit, sizeof(int), 1, pFile);
3936  fwrite(&control_qbit, sizeof(int), 1, pFile);
3937  }
3938  else if (gt_type == U1_OPERATION || gt_type == U2_OPERATION || gt_type == U3_OPERATION ) {
3939  int target_qbit = op->get_target_qbit();
3940  fwrite(&target_qbit, sizeof(int), 1, pFile);
3941  fwrite(parameters_data, sizeof(double), parameter_num, pFile);
3942  }
3943  else if (gt_type == RX_OPERATION || gt_type == RY_OPERATION || gt_type == RZ_OPERATION ) {
3944  int target_qbit = op->get_target_qbit();
3945  fwrite(&target_qbit, sizeof(int), 1, pFile);
3946 
3947  fwrite(parameters_data, sizeof(double), parameter_num, pFile);
3948  }
3949  else if (gt_type == CRY_OPERATION) {
3950  int target_qbit = op->get_target_qbit();
3951  int control_qbit = op->get_control_qbit();
3952  fwrite(&target_qbit, sizeof(int), 1, pFile);
3953  fwrite(&control_qbit, sizeof(int), 1, pFile);
3954 
3955  fwrite(parameters_data, sizeof(double), parameter_num, pFile);
3956  }
3957 
3958  else if (gt_type == X_OPERATION || gt_type == Y_OPERATION || gt_type == Z_OPERATION || gt_type == SX_OPERATION || gt_type == H_OPERATION) {
3959  int target_qbit = op->get_target_qbit();
3960  fwrite(&target_qbit, sizeof(int), 1, pFile);
3961  }
3962  else if (gt_type == BLOCK_OPERATION) {
3963  Gates_block* block_op = static_cast<Gates_block*>( op );
3964  Matrix_real parameters_loc(parameters_data, 1, parameter_num);
3965  export_gate_list_to_binary( parameters_loc, block_op, pFile );
3966 
3967  }
3968  else if (gt_type == ADAPTIVE_OPERATION) {
3969  int target_qbit = op->get_target_qbit();
3970  int control_qbit = op->get_control_qbit();
3971  fwrite(&target_qbit, sizeof(int), 1, pFile);
3972  fwrite(&control_qbit, sizeof(int), 1, pFile);
3973 
3974  fwrite(parameters_data, sizeof(double), parameter_num, pFile);
3975  }
3976  else {
3977  std::string err("export_gate_list_to_binary: unimplemented gate");
3978  throw err;
3979  }
3980 
3981 
3982  parameters_data = parameters_data + parameter_num;
3983 
3984  }
3985 
3986 }
3987 
3988 
3994 
3995  std::stringstream sstream;
3996  sstream << "Importing quantum circuit from binary file " << filename << std::endl;
3997  logging log;
3998  log.verbose = verbosity;
3999  log.print(sstream, 2);
4000 
4001  FILE* pFile;
4002  const char* c_filename = filename.c_str();
4003 
4004  pFile = fopen(c_filename, "rb");
4005  if (pFile==NULL) {fputs ("File error",stderr); exit (1);}
4006 
4007  Gates_block* ret = import_gate_list_from_binary(parameters, pFile, verbosity);
4008 
4009  fclose(pFile);
4010  return ret;
4011 }
4012 
4018 
4019  std::stringstream sstream;
4020 
4021  int qbit_num;
4022  size_t fread_status;
4023 
4024  fread_status = fread(&qbit_num, sizeof(int), 1, pFile);
4025  sstream << "qbit_num: " << qbit_num << std::endl;
4026  Gates_block* gate_block = new Gates_block(qbit_num);
4027 
4028  int parameter_num;
4029  fread_status = fread(&parameter_num, sizeof(int), 1, pFile);
4030  sstream << "parameter_num: " << parameter_num << std::endl;
4031  parameters = Matrix_real(1, parameter_num);
4032  double* parameters_data = parameters.get_data();
4033 
4034  int gates_num;
4035  fread_status = fread(&gates_num, sizeof(int), 1, pFile);
4036  sstream << "gates_num: " << gates_num << std::endl;
4037 
4038  std::vector<int> gate_block_level_gates_num;
4039  std::vector<Gates_block*> gate_block_levels;
4040  gate_block_level_gates_num.push_back( gates_num );
4041  gate_block_levels.push_back(gate_block);
4042  int current_level = 0;
4043 
4044 
4045 
4046  int iter_max = 1e5;
4047  int iter = 0;
4048  while ( gate_block_level_gates_num[0] > 0 && iter < iter_max) {
4049 
4050  gate_type gt_type;
4051  fread_status = fread(&gt_type, sizeof(gate_type), 1, pFile);
4052 
4053  //std::cout << "gate type: " << gt_type << std::endl;
4054 
4055  if (gt_type == CNOT_OPERATION) {
4056  sstream << "importing CNOT gate" << std::endl;
4057 
4058  int target_qbit;
4059  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4060  sstream << "target_qbit: " << target_qbit << std::endl;
4061 
4062  int control_qbit;
4063  fread_status = fread(&control_qbit, sizeof(int), 1, pFile);
4064  sstream << "control_qbit: " << control_qbit << std::endl;
4065 
4066  gate_block_levels[current_level]->add_cnot(target_qbit, control_qbit);
4067  gate_block_level_gates_num[current_level]--;
4068  }
4069  else if (gt_type == CZ_OPERATION) {
4070  sstream << "importing CZ gate" << std::endl;
4071 
4072  int target_qbit;
4073  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4074  sstream << "target_qbit: " << target_qbit << std::endl;
4075 
4076  int control_qbit;
4077  fread_status = fread(&control_qbit, sizeof(int), 1, pFile);
4078  sstream << "control_qbit: " << control_qbit << std::endl;
4079 
4080  gate_block_levels[current_level]->add_cz(target_qbit, control_qbit);
4081  gate_block_level_gates_num[current_level]--;
4082  }
4083  else if (gt_type == CH_OPERATION) {
4084  sstream << "importing CH gate" << std::endl;
4085 
4086  int target_qbit;
4087  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4088  sstream << "target_qbit: " << target_qbit << std::endl;
4089 
4090  int control_qbit;
4091  fread_status = fread(&control_qbit, sizeof(int), 1, pFile);
4092  sstream << "control_qbit: " << control_qbit << std::endl;
4093 
4094  gate_block_levels[current_level]->add_ch(target_qbit, control_qbit);
4095  gate_block_level_gates_num[current_level]--;
4096  }
4097  else if (gt_type == SYC_OPERATION) {
4098  sstream << "importing SYCAMORE gate" << std::endl;
4099 
4100  int target_qbit;
4101  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4102  sstream << "target_qbit: " << target_qbit << std::endl;
4103 
4104  int control_qbit;
4105  fread_status = fread(&control_qbit, sizeof(int), 1, pFile);
4106  sstream << "control_qbit: " << control_qbit << std::endl;
4107 
4108  gate_block_levels[current_level]->add_syc(target_qbit, control_qbit);
4109  gate_block_level_gates_num[current_level]--;
4110  }
4111  else if (gt_type == U1_OPERATION) {
4112  sstream << "importing U1 gate" << std::endl;
4113 
4114  int target_qbit;
4115  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4116  sstream << "target_qbit: " << target_qbit << std::endl;
4117 
4118  fread_status = fread(parameters_data, sizeof(double), 1, pFile);
4119 
4120  parameters_data++;
4121  gate_block_levels[current_level]->add_u1(target_qbit);
4122  gate_block_level_gates_num[current_level]--;
4123  }
4124  else if (gt_type == U2_OPERATION) {
4125  sstream << "importing U2 gate" << std::endl;
4126 
4127  int target_qbit;
4128  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4129  sstream << "target_qbit: " << target_qbit << std::endl;
4130 
4131  fread_status = fread(parameters_data, sizeof(double), 2, pFile);
4132 
4133  parameters_data+=2;
4134  gate_block_levels[current_level]->add_u2(target_qbit);
4135  gate_block_level_gates_num[current_level]--;
4136  }
4137  else if (gt_type == U3_OPERATION) {
4138  sstream << "importing U3 gate" << std::endl;
4139 
4140  int target_qbit;
4141  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4142  sstream << "target_qbit: " << target_qbit << std::endl;
4143 
4144  fread_status = fread(parameters_data, sizeof(double), 3, pFile);
4145 
4146  parameters_data += 3;
4147  gate_block_levels[current_level]->add_u3(target_qbit);
4148  gate_block_level_gates_num[current_level]--;
4149  }
4150  else if (gt_type == RX_OPERATION) {
4151 
4152  sstream << "importing RX gate" << std::endl;
4153 
4154  int target_qbit;
4155  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4156  sstream << "target_qbit: " << target_qbit << std::endl;
4157 
4158  fread_status = fread(parameters_data, sizeof(double), 1, pFile);
4159  parameters_data++;
4160 
4161  gate_block_levels[current_level]->add_rx(target_qbit);
4162  gate_block_level_gates_num[current_level]--;
4163 
4164  }
4165  else if (gt_type == RY_OPERATION) {
4166 
4167  sstream << "importing RY gate" << std::endl;
4168 
4169  int target_qbit;
4170  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4171  sstream << "target_qbit: " << target_qbit << std::endl;
4172 
4173  fread_status = fread(parameters_data, sizeof(double), 1, pFile);
4174  parameters_data++;
4175 
4176  gate_block_levels[current_level]->add_ry(target_qbit);
4177  gate_block_level_gates_num[current_level]--;
4178 
4179  }
4180  else if (gt_type == CRY_OPERATION) {
4181 
4182  sstream << "importing CRY gate" << std::endl;
4183 
4184  int target_qbit;
4185  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4186  sstream << "target_qbit: " << target_qbit << std::endl;
4187 
4188  int control_qbit;
4189  fread_status = fread(&control_qbit, sizeof(int), 1, pFile);
4190  sstream << "control_qbit: " << control_qbit << std::endl;
4191 
4192  fread_status = fread(parameters_data, sizeof(double), 1, pFile);
4193  parameters_data++;
4194 
4195  gate_block_levels[current_level]->add_cry(target_qbit, control_qbit);
4196  gate_block_level_gates_num[current_level]--;
4197 
4198  }
4199  else if (gt_type == RZ_OPERATION) {
4200 
4201  sstream << "importing RZ gate" << std::endl;
4202 
4203  int target_qbit;
4204  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4205  sstream << "target_qbit: " << target_qbit << std::endl;
4206 
4207  fread_status = fread(parameters_data, sizeof(double), 1, pFile);
4208  parameters_data++;
4209 
4210  gate_block_levels[current_level]->add_rz(target_qbit);
4211  gate_block_level_gates_num[current_level]--;
4212 
4213  }
4214  else if (gt_type == H_OPERATION) {
4215 
4216  sstream << "importing Hadamard gate" << std::endl;
4217 
4218  int target_qbit;
4219  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4220  sstream << "target_qbit: " << target_qbit << std::endl;
4221 
4222  gate_block_levels[current_level]->add_h(target_qbit);
4223  gate_block_level_gates_num[current_level]--;
4224 
4225  }
4226  else if (gt_type == X_OPERATION) {
4227 
4228  sstream << "importing X gate" << std::endl;
4229 
4230  int target_qbit;
4231  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4232  sstream << "target_qbit: " << target_qbit << std::endl;
4233 
4234  gate_block_levels[current_level]->add_x(target_qbit);
4235  gate_block_level_gates_num[current_level]--;
4236 
4237  }
4238  else if (gt_type == Y_OPERATION) {
4239 
4240  sstream << "importing Y gate" << std::endl;
4241 
4242  int target_qbit;
4243  fread(&target_qbit, sizeof(int), 1, pFile);
4244  sstream << "target_qbit: " << target_qbit << std::endl;
4245 
4246  gate_block_levels[current_level]->add_y(target_qbit);
4247  gate_block_level_gates_num[current_level]--;
4248 
4249  }
4250  else if (gt_type == Z_OPERATION) {
4251 
4252  sstream << "importing Z gate" << std::endl;
4253 
4254  int target_qbit;
4255  fread(&target_qbit, sizeof(int), 1, pFile);
4256  sstream << "target_qbit: " << target_qbit << std::endl;
4257 
4258  gate_block_levels[current_level]->add_z(target_qbit);
4259  gate_block_level_gates_num[current_level]--;
4260 
4261  }
4262  else if (gt_type == T_OPERATION) {
4263 
4264  sstream << "importing T gate" << std::endl;
4265 
4266  int target_qbit;
4267  fread(&target_qbit, sizeof(int), 1, pFile);
4268  sstream << "target_qbit: " << target_qbit << std::endl;
4269 
4270  gate_block_levels[current_level]->add_t(target_qbit);
4271  gate_block_level_gates_num[current_level]--;
4272 
4273  }
4274  else if (gt_type == TDG_OPERATION) {
4275 
4276  sstream << "importing Tdg gate" << std::endl;
4277 
4278  int target_qbit;
4279  fread(&target_qbit, sizeof(int), 1, pFile);
4280  sstream << "target_qbit: " << target_qbit << std::endl;
4281 
4282  gate_block_levels[current_level]->add_t(target_qbit);
4283  gate_block_level_gates_num[current_level]--;
4284 
4285  }
4286  else if (gt_type == SX_OPERATION) {
4287 
4288  sstream << "importing SX gate" << std::endl;
4289 
4290  int target_qbit;
4291  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4292  sstream << "target_qbit: " << target_qbit << std::endl;
4293 
4294  gate_block_levels[current_level]->add_sx(target_qbit);
4295  gate_block_level_gates_num[current_level]--;
4296 
4297  }
4298  else if (gt_type == BLOCK_OPERATION) {
4299 
4300 
4301  sstream << "******* importing gates block ********" << std::endl;
4302 
4303  int qbit_num_loc;
4304  fread_status = fread(&qbit_num_loc, sizeof(int), 1, pFile);
4305  //std::cout << "qbit_num_loc: " << qbit_num_loc << std::endl;
4306  Gates_block* gate_block_inner = new Gates_block(qbit_num_loc);
4307 
4308  int parameter_num_loc;
4309  fread_status = fread(&parameter_num_loc, sizeof(int), 1, pFile);
4310  //std::cout << "parameter_num_loc: " << parameter_num_loc << std::endl;
4311 
4312 
4313  int gates_num_loc;
4314  fread_status = fread(&gates_num_loc, sizeof(int), 1, pFile);
4315  //std::cout << "gates_num_loc: " << gates_num_loc << std::endl;
4316 
4317  gate_block_levels.push_back( gate_block_inner );
4318  gate_block_level_gates_num.push_back(gates_num_loc);
4319  current_level++;
4320  }
4321  else if (gt_type == ADAPTIVE_OPERATION) {
4322 
4323  sstream << "importing adaptive gate" << std::endl;
4324 
4325  int target_qbit;
4326  fread_status = fread(&target_qbit, sizeof(int), 1, pFile);
4327  sstream << "target_qbit: " << target_qbit << std::endl;
4328 
4329  int control_qbit;
4330  fread_status = fread(&control_qbit, sizeof(int), 1, pFile);
4331  sstream << "control_qbit: " << control_qbit << std::endl;
4332 
4333  fread_status = fread(parameters_data, sizeof(double), 1, pFile);
4334  parameters_data++;
4335 
4336  gate_block_levels[current_level]->add_adaptive(target_qbit, control_qbit);
4337  gate_block_level_gates_num[current_level]--;
4338 
4339  }
4340  else {
4341  std::string err("import_gate_list_from_binary: unimplemented gate");
4342  throw err;
4343  }
4344 
4345 
4346  if ( gate_block_level_gates_num[current_level] == 0 ) {
4347  gate_block_levels[ current_level-1 ]->add_gate( static_cast<Gate*>(gate_block_levels[ current_level ]) );
4348  gate_block_levels.pop_back();
4349  gate_block_level_gates_num.pop_back();
4350  current_level--;
4351  gate_block_level_gates_num[current_level]--;
4352  sstream << "finishing gates block" << std::endl;
4353  }
4354 
4355 
4356  iter++;
4357  }
4358 
4359  logging log;
4360  log.verbose = verbosity;
4361  log.print(sstream, 4);
4362 
4363 
4364  if ( iter == iter_max ) {
4365  std::string error("Corrupted input file, reached end of the file before contructing the whole gate structure");
4366  throw error;
4367  }
4368 
4369  return gate_block;
4370 
4371 }
4372 
4373 
4374 
4381 Matrix_real reverse_parameters( const Matrix_real& parameters_in, std::vector<Gate*>::iterator gates_it, int num_of_gates ) {
4382 
4383  if ( parameters_in.cols > 1 && parameters_in.rows > 1 ) {
4384  std::string error("reverse_parameters: Input array should have a single column or a single row.");
4385  throw error;
4386  }
4387 
4388 //return parameters_in.copy();
4389 
4390  // determine the number of parameters
4391  int parameters_num_total = 0;
4392  for (int idx=0; idx<num_of_gates; idx++) {
4393 
4394  // The current gate
4395  Gate* gate = *(gates_it++);
4396  parameters_num_total = parameters_num_total + gate->get_parameter_num();
4397 
4398  }
4399 
4400 
4401  if ( parameters_num_total == 0) {
4402  return Matrix_real(0,0);
4403  }
4404 
4405  //std::cout << "uu" << std::endl;
4406  //parameters_in.print_matrix();
4407 
4408 
4409  Matrix_real parameters_ret(1, parameters_num_total);
4410  int parameter_num_copied = 0;
4411 
4412  // apply the gate operations on the inital matrix
4413  for (int idx=num_of_gates-0; idx>0; idx--) {
4414 
4415  // The current gate
4416  Gate* gate = *(--gates_it);
4417 
4418  int parameter_num_gate = gate->get_parameter_num();
4419 
4420  if ( parameter_num_gate == 0 ) {
4421  continue;
4422  }
4423 
4424  else if (gate->get_type() == BLOCK_OPERATION ) {
4425 
4426  //std::cout << "block: " << parameter_num_gate << " " << parameters_num_total << std::endl;
4427  parameters_num_total = parameters_num_total - gate->get_parameter_num();
4428 
4429  Matrix_real parameters_of_block( parameters_in.get_data()+parameters_num_total, 1, parameter_num_gate );
4430  //parameters_of_block.print_matrix();
4431 
4432  Gates_block* block_gate = static_cast<Gates_block*>( gate );
4433 
4434  std::vector<Gate*> gates_loc = block_gate->get_gates();
4435 
4436  Matrix_real parameters_of_block_reversed = reverse_parameters( parameters_of_block, gates_loc.begin(), gates_loc.size() );
4437 
4438  //parameters_of_block_reversed.print_matrix();
4439 
4440  memcpy( parameters_ret.get_data()+parameter_num_copied, parameters_of_block_reversed.get_data(), parameters_of_block_reversed.size()*sizeof(double) );
4441  parameter_num_copied = parameter_num_copied + parameters_of_block_reversed.size();
4442 
4443  //parameters_ret.print_matrix();
4444 
4445  }
4446 
4447  else {
4448 
4449  //std::cout << parameter_num_gate << std::endl;
4450 
4451  parameters_num_total = parameters_num_total - gate->get_parameter_num();
4452  memcpy( parameters_ret.get_data()+parameter_num_copied, parameters_in.get_data()+parameters_num_total, gate->get_parameter_num()*sizeof(double) );
4453  parameter_num_copied = parameter_num_copied + gate->get_parameter_num();
4454 
4455  }
4456 
4457 
4458  }
4459 
4460 
4461 
4462 
4463  return parameters_ret;
4464 
4465 
4466 
4467 
4468 }
4469 
4470 
4471 
4472 
4479 Matrix_real inverse_reverse_parameters( const Matrix_real& parameters_in, std::vector<Gate*>::iterator gates_it, int num_of_gates ) {
4480 
4481  if ( parameters_in.cols > 1 && parameters_in.rows > 1 ) {
4482  std::string error("reverse_parameters: Input array should have a single column or a single row.");
4483  throw error;
4484  }
4485 
4486 
4487  // determine the number of parameters
4488  int parameters_num_total = 0;
4489  for (int idx=0; idx<num_of_gates; idx++) {
4490 
4491  // The current gate
4492  Gate* gate = *(gates_it++);
4493  parameters_num_total = parameters_num_total + gate->get_parameter_num();
4494 
4495  }
4496 
4497 
4498  if ( parameters_num_total == 0) {
4499  return Matrix_real(0,0);
4500  }
4501 
4502  //std::cout << "uu" << std::endl;
4503  //parameters_in.print_matrix();
4504 
4505 
4506  Matrix_real parameters_ret(1, parameters_num_total);
4507  int parameter_num_copied = 0;
4508 
4509  // apply the gate operations on the inital matrix
4510  for (int idx=num_of_gates-0; idx>0; idx--) {
4511 
4512  // The current gate
4513  Gate* gate = *(--gates_it);
4514 
4515  int parameter_num_gate = gate->get_parameter_num();
4516 
4517  if ( parameter_num_gate == 0 ) {
4518  continue;
4519  }
4520 
4521  else if (gate->get_type() == BLOCK_OPERATION ) {
4522 
4523  //std::cout << "block: " << parameter_num_gate << " " << parameters_num_total << std::endl;
4524  parameters_num_total = parameters_num_total - gate->get_parameter_num();
4525 
4526  Matrix_real parameters_of_block( parameters_in.get_data()+parameters_num_total, 1, parameter_num_gate );
4527  //parameters_of_block.print_matrix();
4528 
4529  Gates_block* block_gate = static_cast<Gates_block*>( gate );
4530 
4531  std::vector<Gate*> gates_loc = block_gate->get_gates();
4532 
4533  Matrix_real parameters_of_block_reversed = reverse_parameters( parameters_of_block, gates_loc.begin(), gates_loc.size() );
4534 
4535  //parameters_of_block_reversed.print_matrix();
4536 
4537  memcpy( parameters_ret.get_data()+parameter_num_copied, parameters_of_block_reversed.get_data(), parameters_of_block_reversed.size()*sizeof(double) );
4538  parameter_num_copied = parameter_num_copied + parameters_of_block_reversed.size();
4539 
4540  //parameters_ret.print_matrix();
4541 
4542  }
4543 
4544  else {
4545 
4546  //std::cout << parameter_num_gate << std::endl;
4547 
4548  parameters_num_total = parameters_num_total - gate->get_parameter_num();
4549  memcpy( parameters_ret.get_data()+parameters_num_total, parameters_in.get_data()+parameter_num_copied, gate->get_parameter_num()*sizeof(double) );
4550  parameter_num_copied = parameter_num_copied + gate->get_parameter_num();
4551 
4552  }
4553 
4554 
4555  }
4556 
4557 
4558 
4559 
4560  return parameters_ret;
4561 
4562 
4563 
4564 
4565 }
4566 
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:96
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
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:88
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:86
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.
void add_cr(int target_qbit, int control_qbit)
Append a CR 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:90
scalar * get_data() const
Call to get the pointer to the stored data.
void add_rz_to_front(int target_qbit)
Add a RZ gate to the front of the list of gates.
virtual void apply_from_right(Matrix_real &parameters, Matrix &input)
Call to apply the gate on the input array/matrix by input*CRY.
Definition: CR.cpp:121
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:38
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)
Call to apply kernel to apply multi qubit gate kernel on an input matrix.
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:372
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:84
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
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:65
void add_rx_to_front(int target_qbit)
Add a RX gate to the front of the list of gates.
A class representing a CRY gate.
Definition: CR.h:37
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:80
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:98
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:74
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:92
virtual ~Gates_block()
Destructor of the class.
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:82
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
void add_crot(int target_qbit, int control_qbit)
Append a CROT gate gate to the list of gates.
void add_crot_to_front(int target_qbit, int control_qbit)
Add a CROT gate gate to the front of the list of gates.
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.
void add_cr_to_front(int target_qbit, int control_qbit)
Add a CR gate to the front of the list of gates.
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
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