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) {
113 for(
int qbit1=0; qbit1<
qbit_num; qbit1++ ) {
114 for(
int qbit2=qbit1; qbit2<
qbit_num; qbit2++ ) {
126 int n_ary_limit_max =
topology.size();
130 for(
int element_idx = 0; element_idx<n_ary_limit_max; element_idx++ ) {
134 possible_control_qbits[element_idx] = edge[1];
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) {
171 for(
int qbit1=0; qbit1<
qbit_num; qbit1++ ) {
172 for(
int qbit2=qbit1+1; qbit2<
qbit_num; qbit2++ ) {
185 int n_ary_limit_max =
topology.size();
189 for(
int element_idx = 0; element_idx<n_ary_limit_max; element_idx++ ) {
193 possible_control_qbits[element_idx] = edge[1];
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;
247 #if BLAS==0 // undefined BLAS 252 MKL_Set_Num_Threads(1);
253 #elif BLAS==2 //OpenBLAS 255 openblas_set_num_threads(1);
258 tbb::tick_count
start_time = tbb::tick_count::now();
261 std::stringstream sstream;
262 sstream <<
"please increase level limit" << std::endl;
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 );
282 export_circuit_2_binary_loc = 0;
286 if ( export_circuit_2_binary_loc > 0 ) {
287 std::string
filename(
"circuit_squander.binary");
293 std::string unitaryname(
"unitary_squander.binary");
304 delete( gate_structure_loc );
309 #if BLAS==0 // undefined BLAS 313 #elif BLAS==2 //OpenBLAS 328 double optimization_tolerance_loc;
330 if (
config.count(
"optimization_tolerance") > 0 ) {
331 config[
"optimization_tolerance"].get_property( optimization_tolerance_loc );
338 if (
config.count(
"tree_level_max") > 0 ){
339 std::cout <<
"lefut\n";
340 config[
"tree_level_max"].get_property( level_max );
358 gcode_best_solution = gcode;
372 std::stringstream sstream;
373 sstream <<
"Decomposition did not reached prescribed high numerical precision." << std::endl;
393 tbb::spin_mutex tree_search_mutex;
396 double optimization_tolerance_loc;
397 if (
config.count(
"optimization_tolerance") > 0 ) {
398 config[
"optimization_tolerance"].get_property( optimization_tolerance_loc );
411 std::stringstream sstream;
412 sstream <<
"Starting optimization with " << gate_structure_loc->
get_gate_num() <<
" decomposing layers." << std::endl;
424 sstream <<
"Optimization with " << level_num <<
" levels converged to " << current_minimum_tmp;
434 delete( gate_structure_loc );
441 bool found_optimal_solution =
false;
447 int n_ary_limit_max =
topology.size();
449 memset( n_ary_limits.
get_data(), n_ary_limit_max, n_ary_limits.
size()*
sizeof(
int) );
451 for(
int idx=0; idx<n_ary_limits.
size(); idx++) {
452 n_ary_limits[idx] = n_ary_limit_max;
456 int64_t iteration_max = pow( (int64_t)n_ary_limit_max, level_num );
460 unsigned int nthreads = std::thread::hardware_concurrency();
461 int64_t concurrency = (int64_t)nthreads;
462 concurrency = concurrency < iteration_max ? concurrency : iteration_max;
467 int64_t work_batch = 1;
469 work_batch = concurrency;
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) {
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;
483 if ( job_idx == concurrency-1) {
484 offset_max = iteration_max-1;
493 for (int64_t iter_idx=initial_offset; iter_idx<offset_max+1; iter_idx++ ) {
495 if( found_optimal_solution ) {
510 std::stringstream sstream;
511 sstream <<
"Starting optimization with " << gate_structure_loc->
get_gate_num() <<
" decomposing layers." << std::endl;
516 delete( gate_structure_loc );
517 gate_structure_loc = NULL;
524 sstream <<
"Optimization with " << level_num <<
" levels converged to " << current_minimum_tmp;
532 tbb::spin_mutex::scoped_lock tree_search_lock{tree_search_mutex};
534 if( current_minimum_tmp <
current_minimum && !found_optimal_solution) {
537 gcode_best_solution = gcode;
544 if (
current_minimum < optimization_tolerance_loc && !found_optimal_solution) {
545 found_optimal_solution =
true;
559 int changed_index, value_prev, value;
560 if ( gcode_counter.
next(changed_index, value_prev, value) ) {
573 return gcode_best_solution;
592 double optimization_tolerance_loc;
593 if (
config.count(
"optimization_tolerance") > 0 ) {
594 config[
"optimization_tolerance"].get_property( optimization_tolerance_loc );
618 int max_inner_iterations_loc = (double)param_num_loc/852 * 1e7;
624 int max_inner_iterations_loc = 2000;
630 int max_inner_iterations_loc = 10000;
636 return cDecomp_custom_random;
655 for(
int gcode_idx=0; gcode_idx<gcode.
size(); gcode_idx++ ) {
673 for (
int gcode_idx=0; gcode_idx<gcode.
size(); gcode_idx++) {
676 add_two_qubit_block( gate_structure_loc, target_qbits[gcode_idx], control_qbits[gcode_idx] );
682 return gate_structure_loc;
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.");
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");
719 layer->
add_u3(target_qbit);
720 layer->
add_u3(control_qbit);
721 layer->
add_cnot(target_qbit, control_qbit);
744 for (
int idx=0; idx<
qbit_num; idx++) {
758 if ( gate_structure == NULL ) {
759 throw (
"N_Qubit_Decomposition_Tree_Search::add_finalyzing_layer: gate_structure is null pointer");
781 upload_Umtx_to_DFE();
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.
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...
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)
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.
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.
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.
int size() const
Call to get the number of the allocated elements.
Gates_block()
Default constructor of the class.
A class responsible for grouping two-qubit (CNOT,CZ,CH) and one-qubit gates into layers.
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.
std::map< std::string, Config_Element > config
config metadata utilized during the optimization
dictionary gate_structure
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 ¶meters, Gates_block *gates_block, const std::string &filename, int verbosity)
?????????
Matrix copy()
Call to create a copy of the matrix.
void export_unitary(std::string &filename)
exports unitary matrix to binary file
int qbit_num
number of qubits spanning the matrix of the operation
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.
int omp_get_max_threads()
get the number of threads in MKL