Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
N_Qubit_Decomposition_Tree_Search.cpp
Go to the documentation of this file.
1 /*
2 Created on Fri Jun 26 14:13:26 2020
3 Copyright 2020 Peter Rakyta, Ph.D.
4 
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8 
9  http://www.apache.org/licenses/LICENSE-2.0
10 
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 
17 @author: Peter Rakyta, Ph.D.
18 */
25 #include "Random_Orthogonal.h"
26 #include "Random_Unitary.h"
27 #include "n_aryGrayCodeCounter.h"
28 #include <random>
29 
30 #include "X.h"
31 
32 #include <time.h>
33 #include <stdlib.h>
34 
35 #include <iostream>
36 
37 #ifdef __DFE__
38 #include "common_DFE.h"
39 #endif
40 
41 
42 
43 
44 
45 
46 
52 
53 
54  // set the level limit
55  level_limit = 0;
56 
57 
58 
59  // BFGS is better for smaller problems, while ADAM for larger ones
60  if ( qbit_num <= 5 ) {
62 
63  // Maximal number of iteartions in the optimization process
65  max_inner_iterations = 10000;
66  }
67  else {
69 
70  // Maximal number of iteartions in the optimization process
72  }
73 
74 
75 
76 
77 }
78 
88 N_Qubit_Decomposition_Tree_Search::N_Qubit_Decomposition_Tree_Search( Matrix Umtx_in, int qbit_num_in, int level_limit_in, std::map<std::string, Config_Element>& config, int accelerator_num ) : Optimization_Interface(Umtx_in, qbit_num_in, false, config, RANDOM, accelerator_num) {
89 
90 
91  // set the level limit
92  level_limit = level_limit_in;
93 
94  // BFGS is better for smaller problems, while ADAM for larger ones
95  if ( qbit_num <= 5 ) {
97 
98  // Maximal number of iteartions in the optimization process
100 
101  max_inner_iterations = 10000;
102 
103  }
104  else {
105  set_optimizer( ADAM );
106 
107  // Maximal number of iteartions in the optimization process
109 
110  }
111 
112  if( topology.size() == 0 ) {
113  for( int qbit1=0; qbit1<qbit_num; qbit1++ ) {
114  for( int qbit2=qbit1; qbit2<qbit_num; qbit2++ ) {
115  matrix_base<int> edge(2,1);
116  edge[0] = qbit1;
117  edge[1] = qbit2;
118 
119  topology.push_back( edge );
120  }
121  }
122  }
123 
124  // construct the possible CNOT combinations within a single level
125  // the number of possible CNOT connections netween the qubits (including topology constraints)
126  int n_ary_limit_max = topology.size();
127 
128  possible_target_qbits = matrix_base<int>(1, n_ary_limit_max);
129  possible_control_qbits = matrix_base<int>(1, n_ary_limit_max);
130  for( int element_idx = 0; element_idx<n_ary_limit_max; element_idx++ ) {
131 
132  matrix_base<int>& edge = topology[ element_idx ];
133  possible_target_qbits[element_idx] = edge[0];
134  possible_control_qbits[element_idx] = edge[1];
135 
136  }
137 
138 
139 
140 
141 
142 }
143 
144 
145 
156 N_Qubit_Decomposition_Tree_Search::N_Qubit_Decomposition_Tree_Search( Matrix Umtx_in, int qbit_num_in, int level_limit_in, std::vector<matrix_base<int>> topology_in, std::map<std::string, Config_Element>& config, int accelerator_num ) : Optimization_Interface(Umtx_in, qbit_num_in, false, config, RANDOM, accelerator_num) {
157 
158 
159 
160  // set the level limit
161  level_limit = level_limit_in;
162 
163  // Maximal number of iteartions in the optimization process
165 
166 
167  // setting the topology
168  topology = topology_in;
169 
170  if( topology.size() == 0 ) {
171  for( int qbit1=0; qbit1<qbit_num; qbit1++ ) {
172  for( int qbit2=qbit1+1; qbit2<qbit_num; qbit2++ ) {
173  matrix_base<int> edge(2,1);
174  edge[0] = qbit1;
175  edge[1] = qbit2;
176 
177  topology.push_back( edge );
178  }
179  }
180  }
181 
182 
183  // construct the possible CNOT combinations within a single level
184  // the number of possible CNOT connections netween the qubits (including topology constraints)
185  int n_ary_limit_max = topology.size();
186 
187  possible_target_qbits = matrix_base<int>(1, n_ary_limit_max);
188  possible_control_qbits = matrix_base<int>(1, n_ary_limit_max);
189  for( int element_idx = 0; element_idx<n_ary_limit_max; element_idx++ ) {
190 
191  matrix_base<int>& edge = topology[ element_idx ];
192  possible_target_qbits[element_idx] = edge[0];
193  possible_control_qbits[element_idx] = edge[1];
194 
195  }
196 
197 
198 
199 
200  // BFGS is better for smaller problems, while ADAM for larger ones
201  if ( qbit_num <= 5 ) {
202  alg = BFGS;
203 
204  // Maximal number of iteartions in the optimization process
206  max_inner_iterations = 10000;
207  }
208  else {
209  alg = ADAM;
210 
211  // Maximal number of iteartions in the optimization process
213  }
214 
215 
216 }
217 
222 
223 }
224 
225 
226 
227 
228 
233 void
235 
236 
237  //The string stream input to store the output messages.
238  std::stringstream sstream;
239  sstream << "***************************************************************" << std::endl;
240  sstream << "Starting to disentangle " << qbit_num << "-qubit matrix" << std::endl;
241  sstream << "***************************************************************" << std::endl << std::endl << std::endl;
242 
243  print(sstream, 1);
244 
245 
246 // temporarily turn off OpenMP parallelism
247 #if BLAS==0 // undefined BLAS
250 #elif BLAS==1 // MKL
251  num_threads = mkl_get_max_threads();
252  MKL_Set_Num_Threads(1);
253 #elif BLAS==2 //OpenBLAS
254  num_threads = openblas_get_num_threads();
255  openblas_set_num_threads(1);
256 #endif
257  //measure the time for the decompositin
258  tbb::tick_count start_time = tbb::tick_count::now();
259 
260  if (level_limit == 0 ) {
261  std::stringstream sstream;
262  sstream << "please increase level limit" << std::endl;
263  print(sstream, 0);
264  return;
265  }
266 
267 
268 
269 
271 
272 
273 
274 
275 
276 
277  long long export_circuit_2_binary_loc;
278  if ( config.count("export_circuit_2_binary") > 0 ) {
279  config["export_circuit_2_binary"].get_property( export_circuit_2_binary_loc );
280  }
281  else {
282  export_circuit_2_binary_loc = 0;
283  }
284 
285 
286  if ( export_circuit_2_binary_loc > 0 ) {
287  std::string filename("circuit_squander.binary");
288  if (project_name != "") {
289  filename = project_name+ "_" +filename;
290  }
291  export_gate_list_to_binary(optimized_parameters_mtx, gate_structure_loc, filename, verbose);
292 
293  std::string unitaryname("unitary_squander.binary");
294  if (project_name != "") {
295  filename = project_name+ "_" +unitaryname;
296  }
297  export_unitary(unitaryname);
298 
299  }
300 
301  // store the created gate structure
302  release_gates();
303  combine( gate_structure_loc );
304  delete( gate_structure_loc );
305 
307 
308 
309 #if BLAS==0 // undefined BLAS
311 #elif BLAS==1 //MKL
312  MKL_Set_Num_Threads(num_threads);
313 #elif BLAS==2 //OpenBLAS
314  openblas_set_num_threads(num_threads);
315 #endif
316 }
317 
318 
319 
324 Gates_block*
326 
327 
328  double optimization_tolerance_loc;
329  long long level_max;
330  if ( config.count("optimization_tolerance") > 0 ) {
331  config["optimization_tolerance"].get_property( optimization_tolerance_loc );
332 
333  }
334  else {
335  optimization_tolerance_loc = optimization_tolerance;
336  }
337 
338  if (config.count("tree_level_max") > 0 ){
339  std::cout << "lefut\n";
340  config["tree_level_max"].get_property( level_max );
341  }
342  else {
343  level_max = 14;
344  }
345 
346  level_limit = (int)level_max;
347 
348  GrayCode gcode_best_solution;
349  double minimum_best_solution = current_minimum;
350 
351  for ( int level = 0; level <= level_max; level++ ) {
352 
354 
355  if (current_minimum < minimum_best_solution) {
356 
357  minimum_best_solution = current_minimum;
358  gcode_best_solution = gcode;
359 
360  }
361 
362  if (current_minimum < optimization_tolerance_loc ) {
363  break;
364  }
365 
366 
367 
368  }
369 
370 
371  if (current_minimum > optimization_tolerance_loc) {
372  std::stringstream sstream;
373  sstream << "Decomposition did not reached prescribed high numerical precision." << std::endl;
374  print(sstream, 1);
375  }
376 
377  return construct_gate_structure_from_Gray_code( gcode_best_solution );
378 
379 }
380 
381 
382 
383 
384 
390 GrayCode
392 
393  tbb::spin_mutex tree_search_mutex;
394 
395 
396  double optimization_tolerance_loc;
397  if ( config.count("optimization_tolerance") > 0 ) {
398  config["optimization_tolerance"].get_property( optimization_tolerance_loc );
399  }
400  else {
401  optimization_tolerance_loc = optimization_tolerance;
402  }
403 
404 
405  if (level_num == 0){
406 
407  // empty Gray code describing a circuit without two-qubit gates
408  GrayCode gcode;
409  Gates_block* gate_structure_loc = construct_gate_structure_from_Gray_code( gcode );
410 
411  std::stringstream sstream;
412  sstream << "Starting optimization with " << gate_structure_loc->get_gate_num() << " decomposing layers." << std::endl;
413  print(sstream, 1);
414 
415 
416 
417  N_Qubit_Decomposition_custom&& cDecomp_custom_random = perform_optimization( gate_structure_loc );
418 
419  number_of_iters += cDecomp_custom_random.get_num_iters(); // retrive the number of iterations spent on optimization
420 
421 
422  double current_minimum_tmp = cDecomp_custom_random.get_current_minimum();
423  sstream.str("");
424  sstream << "Optimization with " << level_num << " levels converged to " << current_minimum_tmp;
425  print(sstream, 1);
426 
427 
428  if( current_minimum_tmp < current_minimum ) {
429  current_minimum = current_minimum_tmp;
430  optimized_parameters_mtx = cDecomp_custom_random.get_optimized_parameters();
431  }
432 
433  //std::cout << "iiiiiiiiiiiiiiiiii " << current_minimum_tmp << std::endl;
434  delete( gate_structure_loc );
435  return gcode;
436 
437  }
438 
439 
440  GrayCode gcode_best_solution;
441  bool found_optimal_solution = false;
442 
443 
444 
445  // set the limits for the N-ary Gray counter
446 
447  int n_ary_limit_max = topology.size();
448  matrix_base<int> n_ary_limits( 1, level_num ); //array containing the limits of the individual Gray code elements
449  memset( n_ary_limits.get_data(), n_ary_limit_max, n_ary_limits.size()*sizeof(int) );
450 
451  for( int idx=0; idx<n_ary_limits.size(); idx++) {
452  n_ary_limits[idx] = n_ary_limit_max;
453  }
454 
455 
456  int64_t iteration_max = pow( (int64_t)n_ary_limit_max, level_num );
457 
458 
459  // determine the concurrency of the calculation
460  unsigned int nthreads = std::thread::hardware_concurrency();
461  int64_t concurrency = (int64_t)nthreads;
462  concurrency = concurrency < iteration_max ? concurrency : iteration_max;
463 
464 
465  int parallel = get_parallel_configuration();
466 
467  int64_t work_batch = 1;
468  if( parallel==0) {
469  work_batch = concurrency;
470  }
471 
472 //std::cout << "levels " << level_num << std::endl;
473  tbb::parallel_for( tbb::blocked_range<int64_t>((int64_t)0, concurrency, work_batch), [&](tbb::blocked_range<int64_t> r) {
474  for (int64_t job_idx=r.begin(); job_idx<r.end(); ++job_idx) {
475 
476  //for( int64_t job_idx=0; job_idx<concurrency; job_idx++ ) {
477 
478  // initial offset and upper boundary of the gray code counter
479  int64_t work_batch = iteration_max/concurrency;
480  int64_t initial_offset = job_idx*work_batch;
481  int64_t offset_max = (job_idx+1)*work_batch-1;
482 
483  if ( job_idx == concurrency-1) {
484  offset_max = iteration_max-1;
485  }
486 
487  //std::cout << initial_offset << " " << offset_max << " " << iteration_max << " " << work_batch << " " << concurrency << std::endl;
488 
489  n_aryGrayCodeCounter gcode_counter(n_ary_limits, initial_offset); // see piquassoboost for deatils of the implementation
490  gcode_counter.set_offset_max( offset_max );
491 
492 
493  for (int64_t iter_idx=initial_offset; iter_idx<offset_max+1; iter_idx++ ) {
494 
495  if( found_optimal_solution ) {
496  return;
497  }
498 
499 
500 
501  GrayCode&& gcode = gcode_counter.get();
502 
503 
504  Gates_block* gate_structure_loc = construct_gate_structure_from_Gray_code( gcode );
505 
506 
507 
508  // ----------- start the decomposition -----------
509 
510  std::stringstream sstream;
511  sstream << "Starting optimization with " << gate_structure_loc->get_gate_num() << " decomposing layers." << std::endl;
512  print(sstream, 1);
513 
514  N_Qubit_Decomposition_custom&& cDecomp_custom_random = perform_optimization( gate_structure_loc );
515 
516  delete( gate_structure_loc );
517  gate_structure_loc = NULL;
518 
519 
520  number_of_iters += cDecomp_custom_random.get_num_iters(); // retrive the number of iterations spent on optimization
521 
522  double current_minimum_tmp = cDecomp_custom_random.get_current_minimum();
523  sstream.str("");
524  sstream << "Optimization with " << level_num << " levels converged to " << current_minimum_tmp;
525  print(sstream, 1);
526 
527 
528 
529  //std::cout << "Optimization with " << level_num << " levels converged to " << current_minimum_tmp << std::endl;
530 
531  {
532  tbb::spin_mutex::scoped_lock tree_search_lock{tree_search_mutex};
533 
534  if( current_minimum_tmp < current_minimum && !found_optimal_solution) {
535 
536  current_minimum = current_minimum_tmp;
537  gcode_best_solution = gcode;
538 
539  optimized_parameters_mtx = cDecomp_custom_random.get_optimized_parameters();
540  }
541 
542 
543 
544  if ( current_minimum < optimization_tolerance_loc && !found_optimal_solution) {
545  found_optimal_solution = true;
546  }
547 
548  }
549 
550 
551  /*
552  for( int gcode_idx=0; gcode_idx<gcode.size(); gcode_idx++ ) {
553  std::cout << gcode[gcode_idx] << ", ";
554  }
555  std::cout << current_minimum_tmp << std::endl;
556  */
557 
558  // iterate the Gray code to the next element
559  int changed_index, value_prev, value;
560  if ( gcode_counter.next(changed_index, value_prev, value) ) {
561  // exit from the for loop if no further gcode is present
562  break;
563  }
564 
565 
566  }
567 
568  }
569 
570  });
571 
572 
573  return gcode_best_solution;
574 
575 
576 }
577 
578 
579 
580 
581 
582 
583 
590 
591 
592  double optimization_tolerance_loc;
593  if ( config.count("optimization_tolerance") > 0 ) {
594  config["optimization_tolerance"].get_property( optimization_tolerance_loc );
595  }
596  else {
597  optimization_tolerance_loc = optimization_tolerance;
598  }
599 
600 
602  cDecomp_custom_random.set_custom_gate_structure( gate_structure_loc );
603  cDecomp_custom_random.set_optimization_blocks( gate_structure_loc->get_gate_num() );
604  cDecomp_custom_random.set_max_iteration( max_outer_iterations );
605 #ifndef __DFE__
606  cDecomp_custom_random.set_verbose(verbose);
607 #else
608  cDecomp_custom_random.set_verbose(0);
609 #endif
610  cDecomp_custom_random.set_cost_function_variant( cost_fnc );
611  cDecomp_custom_random.set_debugfile("");
612  cDecomp_custom_random.set_optimization_tolerance( optimization_tolerance_loc );
613  cDecomp_custom_random.set_trace_offset( trace_offset );
614  cDecomp_custom_random.set_optimizer( alg );
615  cDecomp_custom_random.set_project_name( project_name );
616  if ( alg == ADAM || alg == BFGS2 ) {
617  int param_num_loc = gate_structure_loc->get_parameter_num();
618  int max_inner_iterations_loc = (double)param_num_loc/852 * 1e7;
619  cDecomp_custom_random.set_max_inner_iterations( max_inner_iterations_loc );
620  cDecomp_custom_random.set_random_shift_count_max( 10000 );
621  }
622  else if ( alg==ADAM_BATCHED ) {
623  cDecomp_custom_random.set_optimizer( alg );
624  int max_inner_iterations_loc = 2000;
625  cDecomp_custom_random.set_max_inner_iterations( max_inner_iterations_loc );
626  cDecomp_custom_random.set_random_shift_count_max( 5 );
627  }
628  else if ( alg==BFGS ) {
629  cDecomp_custom_random.set_optimizer( alg );
630  int max_inner_iterations_loc = 10000;
631  cDecomp_custom_random.set_max_inner_iterations( max_inner_iterations_loc );
632  }
633 
634 
635  cDecomp_custom_random.start_decomposition();
636  return cDecomp_custom_random;
637 }
638 
639 
640 
646 Gates_block*
648 
649 
650  // determine the target qubit indices and control qbit indices for the CNOT gates from the Gray code counter
651  matrix_base<int> target_qbits(1, gcode.size());
652  matrix_base<int> control_qbits(1, gcode.size());
653 
654 
655  for( int gcode_idx=0; gcode_idx<gcode.size(); gcode_idx++ ) {
656 
657  int target_qbit = possible_target_qbits[ gcode[gcode_idx] ];
658  int control_qbit = possible_control_qbits[ gcode[gcode_idx] ];
659 
660 
661  target_qbits[gcode_idx] = target_qbit;
662  control_qbits[gcode_idx] = control_qbit;
663 
664 
665  //std::cout << target_qbit << " " << control_qbit << std::endl;
666  }
667 
668 
669  // ----------- contruct the gate structure to be optimized -----------
670  Gates_block* gate_structure_loc = new Gates_block(qbit_num);
671 
672 
673  for (int gcode_idx=0; gcode_idx<gcode.size(); gcode_idx++) {
674 
675  // add new 2-qbit block to the circuit
676  add_two_qubit_block( gate_structure_loc, target_qbits[gcode_idx], control_qbits[gcode_idx] );
677  }
678 
679  // add finalyzing layer to the the gate structure
680  add_finalyzing_layer( gate_structure_loc );
681 
682  return gate_structure_loc;
683 
684 }
685 
686 
687 
688 
695 void
697 
698  if ( control_qbit >= qbit_num || target_qbit>= qbit_num ) {
699  std::string error( "N_Qubit_Decomposition_Tree_Search::add_two_qubit_block: Label of control/target qubit should be less than the number of qubits in the register.");
700  throw error;
701  }
702 
703  if ( control_qbit == target_qbit ) {
704  std::string error( "N_Qubit_Decomposition_Tree_Search::add_two_qubit_block: Target and control qubits should be different");
705  throw error;
706  }
707 
708  Gates_block* layer = new Gates_block( qbit_num );
709 /*
710 layer->add_rz(target_qbit);
711 layer->add_ry(target_qbit);
712 layer->add_rz(target_qbit);
713 
714 layer->add_rz(control_qbit);
715 layer->add_ry(control_qbit);
716 layer->add_rz(control_qbit);
717 */
718 
719  layer->add_u3(target_qbit);
720  layer->add_u3(control_qbit);
721  layer->add_cnot(target_qbit, control_qbit);
722  gate_structure->add_gate(layer);
723 
724 }
725 
726 
727 
728 
729 
730 
734 void
736 
737 
738  // creating block of gates
739  Gates_block* block = new Gates_block( qbit_num );
740 /*
741  block->add_un();
742  block->add_ry(qbit_num-1);
743 */
744  for (int idx=0; idx<qbit_num; idx++) {
745  bool Theta = true;
746  bool Phi = true;
747  bool Lambda = true;
748 block->add_rz(idx);
749 block->add_ry(idx);
750 block->add_rz(idx);
751 
752  //block->add_u3(idx, Theta, Phi, Lambda);
753 // block->add_ry(idx);
754  }
755 
756 
757  // adding the opeartion block to the gates
758  if ( gate_structure == NULL ) {
759  throw ("N_Qubit_Decomposition_Tree_Search::add_finalyzing_layer: gate_structure is null pointer");
760  }
761  else {
762  gate_structure->add_gate( block );
763  }
764 
765 
766 }
767 
768 
769 
774 void
776 
777  Umtx = Umtx_new;
778 
779 #ifdef __DFE__
780  if( qbit_num >= 5 ) {
781  upload_Umtx_to_DFE();
782  }
783 #endif
784 
785 }
786 
787 
788 
789 
790 
791 
optimization_aglorithms alg
The optimization algorithm to be used in the optimization.
void print(const std::stringstream &sstream, int verbose_level=1) const
Call to print output messages in the function of the verbosity level.
Definition: logging.cpp:55
virtual Gates_block * determine_gate_structure(Matrix_real &optimized_parameters_mtx)
Call determine the gate structrue of the decomposing circuit.
int get_num_iters()
Get the number of processed iterations during the optimization process.
void set_optimizer(optimization_aglorithms alg_in)
Call to set the optimizer engine to be used in solving the optimization problem.
void set_project_name(std::string &project_name_new)
Call to set the name of the project.
Header file for a class representing the X gate.
void add_two_qubit_block(Gates_block *gate_structure, int target_qbit, int control_qbit)
Call to add two-qubit building block (two single qubit rotation blocks and one two-qubit gate) to the...
void set_custom_gate_structure(Gates_block *gate_structure_in)
Call to set custom layers to the gate structure that are intended to be used in the subdecomposition...
int control_qbit
The index of the qubit which acts as a control qubit (control_qbit >= 0) in controlled operations...
Definition: Gate.h:87
double current_minimum
The current minimum of the optimization problem.
void add_gate(Gate *gate)
Append a general gate to the list of gates.
cost_function_type cost_fnc
The chosen variant of the cost function.
N_Qubit_Decomposition_Tree_Search()
Nullary constructor of the class.
matrix_base< int > possible_target_qbits
List of possible target qubits according to the topology – paired up with possible control qubits...
int target_qbit
The index of the qubit on which the operation acts (target_qbit >= 0)
Definition: Gate.h:85
double get_current_minimum()
Call to get the obtained minimum of the cost function.
void release_gates()
Call to release the stored gates.
void set_trace_offset(int trace_offset_in)
Set the trace offset used in the evaluation of the cost function.
int trace_offset
The offset in the first columns from which the "trace" is calculated. In this case Tr(A) = sum_(i-off...
Copyright 2021 Budapest Quantum Computing Group.
GrayCode tree_search_over_gate_structures(int level_num)
Call to perform tree search over possible gate structures.
void add_cnot(int target_qbit, int control_qbit)
Append a CNOT gate gate to the list of gates.
void set_random_shift_count_max(int random_shift_count_max_in)
Call to set the maximal number of parameter randomization tries to escape a local minimum...
scalar * get_data() const
Call to get the pointer to the stored data.
void set_offset_max(const int64_t &value)
N_Qubit_Decomposition_custom perform_optimization(Gates_block *gate_structure_loc)
Call to perform the optimization on the given gate structure.
int level_limit
The maximal number of adaptive layers used in the decomposition.
int next()
Iterate the counter to the next value.
int get_gate_num()
Call to get the number of gates grouped in the class.
int max_outer_iterations
Maximal number of iterations allowed in the optimization process.
std::string project_name
the name of the project
void set_max_inner_iterations(int max_inner_iterations_in)
Call to set the maximal number of iterations for which an optimization engine tries to solve the opti...
A base class to determine the decomposition of an N-qubit unitary into a sequence of CNOT and U3 gate...
double optimization_tolerance
The maximal allowed error of the optimization problem (The error of the decomposition would scale wit...
int get_parameter_num()
Call to get the number of free parameters.
int accelerator_num
number of utilized accelerators
std::vector< matrix_base< int > > topology
A vector of index pairs encoding the connectivity between the qubits.
matrix_base< int > possible_control_qbits
List of possible control qubits according to the topology – paired up with possible target qubits...
void set_debugfile(std::string debugfile)
Call to set the debugfile name.
Definition: logging.cpp:95
int number_of_iters
number of iterations
Matrix_real get_optimized_parameters()
Call to get the optimized parameters.
virtual void add_finalyzing_layer()
Call to add further layer to the gate structure used in the subdecomposition.
void add_u3(int target_qbit)
Append a U3 gate to the list of gates.
A base class to determine the decomposition of an N-qubit unitary into a sequence of CNOT and U3 gate...
void add_rz(int target_qbit)
Append a RZ gate to the list of gates.
Header file for a class implementing the adaptive gate decomposition algorithm of arXiv:2203...
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.
int num_threads
Store the number of OpenMP threads. (During the calculations OpenMP multithreading is turned off...
int verbose
Set the verbosity level of the output messages.
Definition: logging.h:50
void set_optimization_tolerance(double tolerance_in)
Call to set the tolerance of the optimization processes.
Class to store data of complex arrays and its properties.
Definition: matrix.h:38
int size() const
Call to get the number of the allocated elements.
Gates_block()
Default constructor of the class.
Definition: Gates_block.cpp:64
A class responsible for grouping two-qubit (CNOT,CZ,CH) and one-qubit gates into layers.
Definition: Gates_block.h:41
void omp_set_num_threads(int num_threads)
Set the number of threads on runtime in MKL.
virtual void start_decomposition()
Start the disentanglig process of the unitary.
GrayCode get()
Get the current gray code counter value.
void set_verbose(int verbose_in)
Call to set the verbose attribute.
Definition: logging.cpp:85
std::map< std::string, Config_Element > config
config metadata utilized during the optimization
virtual void start_decomposition()
Start the disentanglig process of the unitary.
void set_unitary(Matrix &Umtx_new)
Set unitary matrix.
Header file for the paralleized calculation of the cost function of the final optimization problem (s...
Matrix Umtx
The unitary to be decomposed.
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
void export_unitary(std::string &filename)
exports unitary matrix to binary file
int qbit_num
number of qubits spanning the matrix of the operation
Definition: Gate.h:81
Header file for DFE support in unitary simulation.
void set_max_iteration(int max_outer_iterations_in)
Call to set the maximal number of the iterations in the optimization process.
double decomposition_error
error of the final decomposition
int max_inner_iterations
the maximal number of iterations for which an optimization engine tries to solve the optimization pro...
Matrix_real optimized_parameters_mtx
The optimized parameters for the gates.
int get_parallel_configuration()
Get the parallel configuration from the config.
void set_cost_function_variant(cost_function_type variant)
Call to set the variant of the cost function used in the calculations.
Gates_block * construct_gate_structure_from_Gray_code(const GrayCode &gcode)
Call to construct a gate structure corresponding to the configuration of the two-qubit gates describe...
virtual ~N_Qubit_Decomposition_Tree_Search()
Destructor of the class.
void set_optimization_blocks(int optimization_block_in)
Call to set the number of gate blocks to be optimized in one shot.
Class to store data of complex arrays and its properties.
Definition: matrix_real.h:39
int omp_get_max_threads()
get the number of threads in MKL