86 N_Qubit_Decomposition_adaptive::N_Qubit_Decomposition_adaptive(
Matrix Umtx_in,
int qbit_num_in,
int level_limit_in,
int level_limit_min_in, std::map<std::string, Config_Element>&
config,
int accelerator_num ) :
Optimization_Interface(Umtx_in, qbit_num_in, false, config,
RANDOM, accelerator_num) {
128 N_Qubit_Decomposition_adaptive::N_Qubit_Decomposition_adaptive(
Matrix Umtx_in,
int qbit_num_in,
int level_limit_in,
int level_limit_min_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) {
184 std::stringstream sstream;
185 sstream <<
"***************************************************************" << std::endl;
186 sstream <<
"Starting to disentangle " <<
qbit_num <<
"-qubit matrix" << std::endl;
187 sstream <<
"***************************************************************" << std::endl << std::endl << std::endl;
215 #if BLAS==0 // undefined BLAS 220 MKL_Set_Num_Threads(1);
221 #elif BLAS==2 //OpenBLAS 223 openblas_set_num_threads(1);
226 tbb::tick_count
start_time = tbb::tick_count::now();
229 std::stringstream sstream;
230 sstream <<
"please increase level limit" << std::endl;
239 if (
gates.size() > 0 ) {
240 std::stringstream sstream;
241 sstream <<
"Using imported gate structure for the decomposition." << std::endl;
246 std::stringstream sstream;
247 sstream <<
"Construct initial gate structure for the decomposition." << std::endl;
253 long long export_circuit_2_binary_loc;
254 if (
config.count(
"export_circuit_2_binary") > 0 ) {
255 config[
"export_circuit_2_binary"].get_property( export_circuit_2_binary_loc );
258 export_circuit_2_binary_loc = 0;
262 if ( export_circuit_2_binary_loc > 0 ) {
263 std::string
filename(
"circuit_squander.binary");
269 std::string unitaryname(
"unitary_squander.binary");
280 delete( gate_structure_loc );
283 #if BLAS==0 // undefined BLAS 287 #elif BLAS==2 //OpenBLAS 301 #if BLAS==0 // undefined BLAS 306 MKL_Set_Num_Threads(1);
307 #elif BLAS==2 //OpenBLAS 309 openblas_set_num_threads(1);
312 std::stringstream sstream;
314 sstream << std::endl;
315 sstream << std::endl;
316 sstream <<
"**************************************************************" << std::endl;
317 sstream <<
"***************** Compressing Gate structure *****************" << std::endl;
318 sstream <<
"**************************************************************" << std::endl;
321 if (
gates.size() > 0 ) {
322 std::stringstream sstream;
323 sstream <<
"Using imported gate structure for the compression." << std::endl;
329 std::stringstream sstream;
330 sstream <<
"No circuit initalised." << std::endl;
336 sstream <<
"Compressing gate structure consisting of " << gate_structure_loc->
get_gate_num() <<
" decomposing layers." << std::endl;
342 int uncompressed_iter_num = 0;
344 long long export_circuit_2_binary_loc;
345 if (
config.count(
"export_circuit_2_binary") > 0 ) {
346 config[
"export_circuit_2_binary"].get_property( export_circuit_2_binary_loc );
349 export_circuit_2_binary_loc = 0;
353 while ( iter<25 || uncompressed_iter_num <= 5 ) {
354 std::stringstream sstream;
356 sstream <<
"iteration " << iter+1 <<
": ";
362 uncompressed_iter_num = 0;
365 uncompressed_iter_num++;
368 if ( gate_structure_compressed != gate_structure_loc ) {
370 delete( gate_structure_loc );
371 gate_structure_loc = gate_structure_compressed;
372 gate_structure_compressed = NULL;
376 if ( export_circuit_2_binary_loc > 0 ) {
377 std::string
filename(
"circuit_compression.binary");
384 std::string filename_unitary(
"unitary_compression.binary");
396 if (uncompressed_iter_num>1)
break;
404 delete( gate_structure_loc );
406 #if BLAS==0 // undefined BLAS 410 #elif BLAS==2 //OpenBLAS 429 #if BLAS==0 // undefined BLAS 434 MKL_Set_Num_Threads(1);
435 #elif BLAS==2 //OpenBLAS 437 openblas_set_num_threads(1);
442 if (
gates.size() > 0 ) {
443 std::stringstream sstream;
444 sstream <<
"Using imported gate structure for the compression." << std::endl;
450 std::stringstream sstream;
451 sstream <<
"No circuit initalised." << std::endl;
457 std::stringstream sstream;
459 sstream <<
"**************************************************************" << std::endl;
460 sstream <<
"************ Final tuning of the Gate structure **************" << std::endl;
461 sstream <<
"**************************************************************" << std::endl;
465 if (
config.count(
"optimization_tolerance") > 0 ) {
467 config[
"optimization_tolerance"].get_property( value );
498 std::map<std::string, Config_Element> config_copy;
500 if (
config.count(
"max_inner_iterations_final") > 0 ) {
502 config[
"max_inner_iterations_final"].get_property( val );
505 config_copy[
"max_inner_iterations"] = element;
524 int max_inner_iterations_loc = (double)param_num_loc/852 * 1e7;
530 int max_inner_iterations_loc = 2500;
536 int max_inner_iterations_loc = 10000;
547 delete( gate_structure_tmp );
548 delete( gate_structure_loc );
556 long long export_circuit_2_binary_loc;
557 if (
config.count(
"export_circuit_2_binary") > 0 ) {
558 config[
"export_circuit_2_binary"].get_property( export_circuit_2_binary_loc );
561 export_circuit_2_binary_loc = 0;
565 if ( export_circuit_2_binary_loc > 0 ) {
566 std::string filename2(
"circuit_final.binary");
585 for(
auto it=gate_nums.begin(); it != gate_nums.end(); it++ ) {
586 sstream << it->second <<
" " << it->first <<
" gates" << std::endl;
589 sstream << std::endl;
592 #if BLAS==0 // undefined BLAS 596 #elif BLAS==2 //OpenBLAS 612 tbb::tick_count start_time_loc = tbb::tick_count::now();
614 std::stringstream sstream;
615 sstream <<
"Starting optimization with " << gate_structure_loc->
get_gate_num() <<
" decomposing layers." << std::endl;
618 double optimization_tolerance_loc;
619 if (
config.count(
"optimization_tolerance") > 0 ) {
620 config[
"optimization_tolerance"].get_property( optimization_tolerance_loc );
644 int max_inner_iterations_loc = (double)param_num_loc/852 * 1e7;
650 int max_inner_iterations_loc = 2500;
656 int max_inner_iterations_loc = 10000;
663 tbb::tick_count end_time_loc = tbb::tick_count::now();
671 std::stringstream sstream;
672 sstream <<
"Optimization problem solved with " << gate_structure_loc->
get_gate_num() <<
" decomposing layers in " << (end_time_loc-start_time_loc).seconds() <<
" seconds." << std::endl;
676 std::stringstream sstream;
677 sstream <<
"Optimization problem converged to " << cDecomp_custom.
get_current_minimum() <<
" with " << gate_structure_loc->
get_gate_num() <<
" decomposing layers in " << (end_time_loc-start_time_loc).seconds() <<
" seconds." << std::endl;
682 std::stringstream sstream;
683 sstream <<
"Decomposition did not reached prescribed high numerical precision." << std::endl;
689 sstream <<
"Continue with the compression of gate structure consisting of " << gate_structure_loc->
get_gate_num() <<
" decomposing layers." << std::endl;
691 return gate_structure_loc;
705 std::vector<double> minimum_vec;
706 std::vector<Gates_block*> gate_structure_vec;
707 std::vector<Matrix_real> optimized_parameters_vec;
709 double optimization_tolerance_loc;
710 if (
config.count(
"optimization_tolerance") > 0 ) {
711 config[
"optimization_tolerance"].get_property( optimization_tolerance_loc );
717 int max_outer_iterations_loc;
718 double value_placeholder;
719 if (
config.count(
"max_outer_iterations") > 0 ) {
720 config[
"max_outer_iterations"].get_property( value_placeholder );
721 max_outer_iterations_loc = (
int) value_placeholder;
736 for (
int idx=0; idx<
level; idx++) {
748 tbb::tick_count start_time_loc = tbb::tick_count::now();
753 std::stringstream sstream;
754 sstream <<
"Starting optimization with " << gate_structure_loc->
get_gate_num() <<
" decomposing layers." << std::endl;
783 int max_inner_iterations_loc = (double)param_num_loc/852 * 1e7;
789 int max_inner_iterations_loc = 2000;
795 int max_inner_iterations_loc = 10000;
832 tbb::tick_count end_time_loc = tbb::tick_count::now();
840 double current_minimum_loc;
844 if ( current_minimum_random < optimization_tolerance_loc && current_minimum_close_to_zero > optimization_tolerance_loc ) {
845 current_minimum_loc = current_minimum_random;
849 else if ( current_minimum_random > optimization_tolerance_loc && current_minimum_close_to_zero < optimization_tolerance_loc ) {
850 current_minimum_loc = current_minimum_close_to_zero;
854 else if ( current_minimum_random < optimization_tolerance_loc && current_minimum_close_to_zero < optimization_tolerance_loc ) {
858 int panelty_random =
get_panelty(gate_structure_loc, optimized_parameters_mtx_random);
859 int panelty_close_to_zero =
get_panelty(gate_structure_loc, optimized_parameters_mtx_close_to_zero );
861 if ( panelty_random < panelty_close_to_zero ) {
862 current_minimum_loc = current_minimum_random;
867 current_minimum_loc = current_minimum_close_to_zero;
874 if ( current_minimum_random < current_minimum_close_to_zero ) {
875 current_minimum_loc = current_minimum_random;
880 current_minimum_loc = current_minimum_close_to_zero;
887 minimum_vec.push_back(current_minimum_loc);
888 gate_structure_vec.push_back(gate_structure_loc);
889 optimized_parameters_vec.push_back(optimized_parameters_mtx_loc);
893 if ( current_minimum_loc < optimization_tolerance_loc ) {
894 std::stringstream sstream;
895 sstream <<
"Optimization problem solved with " << gate_structure_loc->
get_gate_num() <<
" decomposing layers in " << (end_time_loc-start_time_loc).seconds() <<
" seconds." << std::endl;
900 std::stringstream sstream;
901 sstream <<
"Optimization problem converged to " << current_minimum_loc <<
" with " << gate_structure_loc->
get_gate_num() <<
" decomposing layers in " << (end_time_loc-start_time_loc).seconds() <<
" seconds." << std::endl;
913 for (
int idx=1; idx<(
int)minimum_vec.size(); idx++) {
914 if( current_minimum > minimum_vec[idx] ) {
916 current_minimum = minimum_vec[idx];
921 Gates_block* gate_structure_loc = gate_structure_vec[idx_min];
922 optimized_parameters_mtx_loc = optimized_parameters_vec[idx_min];
925 for (
int idx=0; idx<(
int)minimum_vec.size(); idx++) {
926 if( idx == idx_min ) {
929 delete( gate_structure_vec[idx] );
932 gate_structure_vec.clear();
933 optimized_parameters_vec.clear();
937 if (current_minimum > optimization_tolerance_loc) {
938 std::stringstream sstream;
939 sstream <<
"Decomposition did not reached prescribed high numerical precision." << std::endl;
941 optimization_tolerance_loc = 1.5*current_minimum < 1e-2 ? 1.5*
current_minimum : 1e-2;
945 return gate_structure_loc;
962 if ( layer_num_orig < 50 ) layer_num_max = layer_num_orig;
963 else if ( layer_num_orig < 60 ) layer_num_max = 4;
964 else layer_num_max = 2;
965 double optimization_tolerance_loc;
966 if (
config.count(
"optimization_tolerance") > 0 ) {
967 config[
"optimization_tolerance"].get_property( optimization_tolerance_loc );
974 std::uniform_int_distribution<> distrib_int(0, 5000);
976 std::vector<int> layers_to_remove;
977 if (uncompressed_iter_num==0){
978 layer_num_max = 5<layer_num_orig ? 5 : layer_num_orig;
980 std::vector<double> layers_parameters(layer_num_orig,15.0);
981 std::vector<int> layers_idx_sorted(layer_num_orig,0);
983 for (
int idx=0; idx<layer_num_orig;idx++){
985 layers_idx_sorted[idx] = idx;
988 std::iota(layers_idx_sorted.begin(),layers_idx_sorted.end(),0);
989 sort( layers_idx_sorted.begin(),layers_idx_sorted.end(), [&](
int i,
int j){
return layers_parameters[i]<layers_parameters[j];} );
991 for (
int idx=0; idx<layer_num_max; idx++ ) {
992 layers_to_remove.push_back( layers_idx_sorted[idx]);
996 layers_to_remove.reserve(layer_num_orig);
997 for (
int idx=0; idx<layer_num_orig; idx++ ) {
998 layers_to_remove.push_back(idx);
1002 while ( (
int)layers_to_remove.size() > layer_num_max ) {
1003 int remove_idx = distrib_int(
gen) % layers_to_remove.size();
1005 layers_to_remove.erase( layers_to_remove.begin() + remove_idx );
1011 MPI_Bcast( &layers_to_remove[0], layers_to_remove.size(), MPI_INT, 0, MPI_COMM_WORLD);
1017 int panelties_num = layer_num_max < layer_num_orig ? layer_num_max : layer_num_orig;
1019 if ( panelties_num == 0 ) {
1024 std::vector<unsigned int> panelties(panelties_num, 1<<31);
1025 std::vector<Gates_block*> gate_structures_vec(panelties_num, NULL);
1026 std::vector<double> current_minimum_vec(panelties_num, DBL_MAX);
1027 std::vector<int> iteration_num_vec(panelties_num, 0);
1030 std::vector<Matrix_real> optimized_parameters_vec(panelties_num,
Matrix_real(0,0));
1031 std::vector<Matrix> Umtx_vec(panelties_num,
Matrix(0,0));
1035 for (
int idx=0; idx<panelties_num; idx++) {
1039 double current_minimum_loc = DBL_MAX;
1040 int iteration_num = 0;
1043 Gates_block* gate_structure_reduced =
compress_gate_structure( gate_structure, layers_to_remove[idx], optimized_parameters_loc, current_minimum_loc, iteration_num );
1044 if ( optimized_parameters_loc.
size() == 0 ) {
1051 gate_structure_tmp = gate_structure_reduced->
clone();
1054 gate_structure_tmp =
remove_trivial_gates( gate_structure_reduced, optimized_parameters_loc, current_minimum_loc );
1057 panelties[idx] =
get_panelty(gate_structure_tmp, optimized_parameters_loc);
1058 gate_structures_vec[idx] = gate_structure_tmp;
1059 current_minimum_vec[idx] = current_minimum_loc;
1060 iteration_num_vec[idx] = iteration_num;
1063 optimized_parameters_vec[idx] = optimized_parameters_loc;
1064 Umtx_vec[idx] =
Umtx;
1067 delete(gate_structure_reduced);
1070 if ( current_minimum_vec[idx] < optimization_tolerance_loc ) {
1079 unsigned int panelty_min = panelties[0];
1080 unsigned int idx_min = 0;
1082 for (
size_t idx=0; idx<panelties.size(); idx++) {
1083 if ( panelty_min > panelties[idx] ) {
1084 panelty_min = panelties[idx];
1088 else if ( panelty_min == panelties[idx] ) {
1090 if ( (distrib_int(
gen) % 2) == 1 ) {
1093 panelty_min = panelties[idx];
1101 MPI_Bcast( &idx_min, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD);
1106 for (
size_t idx=0; idx<panelties.size(); idx++) {
1112 if ( gate_structures_vec[idx] == gate_structure) {
1116 if ( gate_structures_vec[idx] ) {
1117 delete( gate_structures_vec[idx] );
1118 gate_structures_vec[idx] = NULL;
1124 gate_structure = gate_structures_vec[idx_min];
1128 Umtx = Umtx_vec[idx_min];
1132 if ( layer_num < layer_num_orig+1 ) {
1133 std::stringstream sstream;
1134 sstream <<
"gate structure reduced from " << layer_num_orig+1 <<
" to " << layer_num <<
" decomposing layers" << std::endl;
1138 std::stringstream sstream;
1139 sstream <<
"gate structure kept at " << layer_num <<
" layers" << std::endl;
1166 if ( optimized_parameters.
size() > 0 ) {
1177 std::map<std::string, Config_Element> config_copy;
1179 if (
config.count(
"max_inner_iterations_compression") > 0 ) {
1181 config[
"max_inner_iterations_compression"].get_property( val );
1184 config_copy[
"max_inner_iterations"] = element;
1187 double optimization_tolerance_loc;
1188 if (
config.count(
"optimization_tolerance") > 0 ) {
1189 config[
"optimization_tolerance"].get_property( optimization_tolerance_loc );
1216 int max_inner_iterations_loc = 100;
1223 if ( current_minimum_tmp < optimization_tolerance_loc ) {
1226 current_minimum_loc = current_minimum_tmp;
1227 return gate_structure_reduced;
1231 return gate_structure->
clone();
1251 for (
int layer_idx=0; layer_idx<
layer_num; layer_idx++) {
1257 for(
int gate_idx=0; gate_idx<gate_num; gate_idx++ ) {
1269 if ( std::abs(std::sin(parameter)) < 0.999 && std::abs(std::cos(parameter)) < 1e-3 ) {
1273 else if ( std::abs(std::sin(parameter)) < 1e-3 && std::abs(1-std::cos(parameter)) < 1e-3 ) {
1318 for (
int idx=0; idx<
layer_num; idx++ ) {
1323 std::string err =
"N_Qubit_Decomposition_adaptive::replace_trivial_adaptive_gates: Only block gates are accepted in this conversion.";
1348 if ( gate_tmp->
get_type() ==
ADAPTIVE_OPERATION && std::abs(std::sin(parameter)) > 0.999 && std::abs(std::cos(parameter)) < 1e-3) {
1356 CZ* cz_gate =
new CZ(
qbit_num, target_qbit, control_qbit);
1371 memcpy(parameters_new.get_data(), optimized_parameters.
get_data(), parameter_idx*
sizeof(double));
1373 memcpy(parameters_new.get_data()+parameter_idx+3, optimized_parameters.
get_data()+parameter_idx+1, (optimized_parameters.
size()-parameter_idx-1)*
sizeof(
double));
1376 parameters_new[parameter_idx+1] = M_PI/4;
1379 if ( std::sin(parameter) < 0 ) {
1381 parameters_new[parameter_idx+2] = -M_PI/4;
1384 global_phase_factor_new.
real = std::cos( -M_PI/4 );
1385 global_phase_factor_new.
imag = std::sin( -M_PI/4 );
1391 parameters_new[parameter_idx+2] = M_PI/4;
1394 global_phase_factor_new.
real = std::cos( M_PI/4 );
1395 global_phase_factor_new.
imag = std::sin( M_PI/4 );
1401 optimized_parameters = parameters_new;
1408 else if ( gate_tmp->
get_type() ==
ADAPTIVE_OPERATION && std::abs(std::sin(parameter)) < 1e-3 && std::abs(1-std::cos(parameter)) < 1e-3 ) {
1414 memcpy(parameters_new.get_data(), optimized_parameters.
get_data(), parameter_idx*
sizeof(double));
1415 memcpy(parameters_new.get_data()+
parameter_idx, optimized_parameters.
get_data()+parameter_idx+1, (optimized_parameters.
size()-parameter_idx-1)*
sizeof(
double));
1416 optimized_parameters = parameters_new;
1442 memcpy(parameters_new.get_data(), optimized_parameters.
get_data(), parameter_idx*
sizeof(double));
1443 memcpy(parameters_new.get_data()+parameter_idx+2, optimized_parameters.
get_data()+parameter_idx+1, (optimized_parameters.
size()-parameter_idx-1)*
sizeof(
double));
1444 optimized_parameters = parameters_new;
1447 optimized_parameters[parameter_idx+1] = -parameter/2;
1477 return gate_structure_ret;
1498 for (
int idx=0; idx<
layer_num; idx++ ) {
1522 for(
size_t rdx=0; rdx<involved_qbits.size(); rdx++ ) {
1524 U3* U_gate_to_be_removed =
static_cast<U3*
>(layer->
get_gate(rdx));
1527 int parameter_idx_loc = parameter_idx_to_be_removed + layer->
get_parameter_num();
1529 bool found_match =
false;
1530 U3* matching_gate = NULL;
1533 for (
int kdx=idx+1; kdx<
layer_num; kdx++ ) {
1539 for (
int hdx=0; hdx<gate_num; hdx++ ) {
1546 if ( qbit_to_be_matched == target_qbit_loc ) {
1548 matching_gate =
static_cast<U3*
>(gate_test);
1558 if ( found_match )
break;
1563 if ( found_match ==
false ) {
1565 std::string err(
"N_Qubit_Decomposition_adaptive::remove_trivial_gates: No matching U3 gate was found. Need to append a U3 gate to the end, but this functionality is not developed yet.");
1575 Matrix U3_prod =
dot(U3_matrix2, U3_matrix1);
1577 optimized_parameters_loc[parameter_idx_to_be_removed] = 0.0;
1578 optimized_parameters_loc[parameter_idx_to_be_removed+1] = 0.0;
1579 optimized_parameters_loc[parameter_idx_to_be_removed+2] = 0.0;
1580 parameter_idx_to_be_removed = parameter_idx_to_be_removed + U_gate_to_be_removed->
get_parameter_num();
1584 double ctheta3_over2 = std::sqrt(U3_prod[0].
real*U3_prod[0].
real+U3_prod[0].imag*U3_prod[0].imag);
1585 double stheta3_over2 = std::sqrt(U3_prod[2].
real*U3_prod[2].
real+U3_prod[2].imag*U3_prod[2].imag);
1586 double theta3_over2 = std::atan2(stheta3_over2,ctheta3_over2);
1588 double alpha = std::atan2(U3_prod[0].imag,U3_prod[0].
real);
1593 if (std::abs(stheta3_over2)<4e-8){
1594 lambda3 = (std::atan2(U3_prod[3].imag,U3_prod[3].real)-
alpha)/2;
1598 lambda3 = std::atan2(-1*U3_prod[1].imag,-1*U3_prod[1].real)-
alpha;
1599 phi3 = std::atan2(U3_prod[2].imag,U3_prod[2].real)-
alpha;
1605 global_phase_factor_new.
real = std::cos(alpha);
1606 global_phase_factor_new.
imag = std::sin(alpha);
1610 if (std::sqrt((U3_new[3].real-U3_prod[3].real)*(U3_new[3].real-U3_prod[3].real)) + std::sqrt((U3_new[3].imag-U3_prod[3].imag)*(U3_new[3].imag-U3_prod[3].imag)) < 1e-8 && (stheta3_over2*stheta3_over2+ctheta3_over2*ctheta3_over2) > 0.99) {
1614 param2[0] = theta3_over2;
1616 param2[2] = lambda3;
1628 std::stringstream sstream;
1629 sstream <<
"N_Qubit_Decomposition_adaptive::remove_trivial_gates: Removing trivial gateblock" << std::endl;
1634 int iteration_num_loc = 0;
1643 optimized_parameters = optimized_parameters_loc;
1644 delete( gate_structure_loc );
1645 gate_structure_loc = gate_structure_tmp;
1659 return gate_structure_loc;
1680 for (
int idx=0; idx<layer_idx; idx++) {
1690 Matrix_real reduced_parameters(1, optimized_parameters.
size() - param_num_removed );
1691 memcpy( reduced_parameters.get_data(), optimized_parameters.
get_data(), (
parameter_idx)*
sizeof(
double));
1692 memcpy( reduced_parameters.get_data()+
parameter_idx, optimized_parameters.
get_data()+parameter_idx+param_num_removed, (optimized_parameters.
size()-parameter_idx-param_num_removed)*
sizeof(
double));
1695 return reduced_parameters;
1723 gate_structure->
combine( layer );
1739 std::stringstream sstream;
1744 std::vector<Gates_block* >
layers;
1750 if ( it->size() != 2 ) {
1751 std::string err(
"The connectivity data should contains two qubits.");
1755 int control_qbit_loc = (*it)[0];
1756 int target_qbit_loc = (*it)[1];
1759 std::string err(
"Label of control/target qubit should be less than the number of qubits in the register.");
1765 layer->
add_u3(target_qbit_loc);
1766 layer->
add_u3(control_qbit_loc);
1767 layer->
add_adaptive(target_qbit_loc, control_qbit_loc);
1769 layers.push_back(layer);
1777 for (
int target_qbit_loc = 0; target_qbit_loc<
qbit_num; target_qbit_loc++) {
1778 for (
int control_qbit_loc = target_qbit_loc+1; control_qbit_loc<
qbit_num; control_qbit_loc++) {
1782 layer->
add_u3(target_qbit_loc);
1783 layer->
add_u3(control_qbit_loc);
1784 layer->
add_adaptive(target_qbit_loc, control_qbit_loc);
1786 layers.push_back(layer);
1800 bool randomized_adaptive_layers_loc;
1801 if (
config.count(
"randomized_adaptive_layers") > 0 ) {
1802 config[
"randomized_adaptive_layers"].get_property( randomized_adaptive_layers_loc );
1810 if (randomized_adaptive_layers_loc) {
1812 std::uniform_int_distribution<> distrib_int(0, 5000);
1814 while (layers.size()>0) {
1815 int idx = distrib_int(
gen) % layers.size();
1818 MPI_Bcast( &idx, 1, MPI_INT, 0, MPI_COMM_WORLD);
1821 layers.erase( layers.begin() + idx );
1826 while (layers.size()>0) {
1828 layers.erase( layers.begin() );
1863 for (
int idx=0; idx<
qbit_num; idx++) {
1870 if ( gate_structure == NULL ) {
1871 throw (
"N_Qubit_Decomposition_adaptive::add_finalyzing_layer: gate_structure is null pointer");
1890 if (
gates.size() > 0 ) {
1912 upload_Umtx_to_DFE();
1928 upload_Umtx_to_DFE();
1946 if (
gates.size() > 0 ) {
1947 gate_structure_tmp->
combine( static_cast<Gates_block*>(
this) );
1950 combine( gate_structure_tmp );
1961 combine( gate_structure_tmp );
1975 if (
gates.size() == 0 ) {
1980 std::stringstream sstream;
2004 std::stringstream sstream;
2005 sstream <<
"Add new layer to the adaptive gate structure." << std::endl;
2014 memset( tmp.get_data(), 0, tmp.size()*
sizeof(double) );
2027 double ThetaOver2=0.;
2028 for (
int gate_idx=0; gate_idx<layer_gate_num; gate_idx++){
2032 ThetaOver2 = std::sin(parameter)*std::sin(parameter);
Matrix dot(Matrix &A, Matrix &B)
Call to calculate the product of two complex matrices by calling method zgemm3m from the CBLAS librar...
optimization_aglorithms alg
The optimization algorithm to be used in the optimization.
A class representing a U3 gate.
void add_adaptive(int target_qbit, int control_qbit)
Append a Adaptive gate to the list of gates.
virtual unsigned int get_panelty(Gates_block *gate_structure, Matrix_real &optimized_parameters)
Call to get the panelty derived from the number of CRY and CNOT gates in the circuit.
void print(const std::stringstream &sstream, int verbose_level=1) const
Call to print output messages in the function of the verbosity level.
void release_gate(int idx)
Call to release one gate in the list.
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.
Gates_block * optimize_imported_gate_structure(Matrix_real &optimized_parameters_mtx_loc)
Call to optimize an imported gate structure.
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.
std::map< std::string, int > get_gate_nums()
Call to get the number of the individual gate types in the list of gates.
void add_adaptive_layers()
Call to add adaptive layers to the gate structure stored by the class.
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...
Matrix_real copy() const
Call to create a copy of the matrix.
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.
std::vector< int > get_involved_qubits()
Call to get the qubits involved in the gates stored in the block of gates.
void add_finalyzing_layer()
Call to add finalyzing layer (single qubit rotations on all of the qubits) to the gate structure stor...
Gates_block * compress_gate_structure(Gates_block *gate_structure, int uncompressed_iter_num)
Call to run compression iterations on the circuit.
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.
bool randomized_adaptive_layers
Boolean variable to determine whether randomized adaptive layers are used or not. ...
int level_limit
The maximal number of adaptive layers used in the decomposition.
double optimization_problem(double *parameters)
Evaluate the optimization problem of the optimization.
void set_trace_offset(int trace_offset_in)
Set the trace offset used in the evaluation of the cost function.
std::vector< std::vector< int > > involved_qbits
int trace_offset
The offset in the first columns from which the "trace" is calculated. In this case Tr(A) = sum_(i-off...
int layer_num
number of gate layers
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...
A class describing a universal configuration element.
virtual void apply_to(Matrix_real ¶meters_mtx, Matrix &input, int parallel=0)
Call to apply the gate on the input array/matrix Gates_block*input.
std::vector< matrix_base< int > > topology
A vector of index pairs encoding the connectivity between the qubits.
scalar * get_data() const
Call to get the pointer to the stored data.
guess_type initial_guess
type to guess the initial values for the optimization. Possible values: ZEROS=0, RANDOM=1, CLOSE_TO_ZERO=2
Gates_block * import_gate_list_from_binary(Matrix_real ¶meters, const std::string &filename, int verbosity)
?????????
void apply_global_phase_factor()
Call to apply the current global phase to the unitary matrix.
int get_gate_num()
Call to get the number of gates grouped in the class.
virtual ~N_Qubit_Decomposition_adaptive()
Destructor of the class.
Matrix_real create_reduced_parameters(Gates_block *gate_structure, Matrix_real &optimized_parameters, int layer_idx)
Call to remove those parameters from the array, which correspond to gates that are about to be remove...
std::vector< Gate * > gates
The list of stored gates.
int max_outer_iterations
Maximal number of iterations allowed in the optimization process.
N_Qubit_Decomposition_adaptive()
Nullary constructor of the class.
A class representing a CZ operation.
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...
A class representing a RZ gate.
int get_parameter_num()
Call to get the number of free parameters.
int accelerator_num
number of utilized accelerators
int level_limit_min
The minimal number of adaptive layers used in the decomposition.
void apply_imported_gate_structure()
Call to apply the imported gate structure on the unitary.
void set_debugfile(std::string debugfile)
Call to set the debugfile name.
void set_unitary_from_file(std::string filename)
Set unitary matrix from file.
int number_of_iters
number of iterations
void set_adaptive_gate_structure(std::string filename)
Call to set custom layers to the gate structure that are intended to be used in the decomposition...
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 ...
Matrix_real get_optimized_parameters()
Call to get the optimized parameters.
gate_type get_type()
Call to get the type of the operation.
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 combine(Gates_block *op_block)
Call to append the gates of an gate block to the current block.
std::map< int, int > iteration_loops
A map of <int n: int num> indicating the number of iteration in each step of the decomposition.
void set_optimized_parameters(double *parameters, int num_of_parameters)
Call to set the optimized parameters for initial optimization.
int get_parameter_start_idx()
Call to get the starting index of the parameters in the parameter array corresponding to the circuit ...
virtual Gates_block * remove_trivial_gates(Gates_block *gate_structure, Matrix_real &optimized_parameters, double &currnt_minimum_loc)
Call to remove those blocks from the circuit that contain a trivial CRY gate (i.e.
int num_threads
Store the number of OpenMP threads. (During the calculations OpenMP multithreading is turned off...
virtual void compress_circuit()
Compress the circuit.
Structure type representing complex numbers in the SQUANDER package.
A class representing a CNOT operation.
void add_adaptive_gate_structure(std::string filename)
Call to append custom layers to the gate structure that are intended to be used in the decomposition...
virtual void get_initial_circuit()
get initial circuit
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.
Gates_block * construct_adaptive_gate_layers()
Call to construct adaptive layers.
virtual Gates_block * clone()
Create a clone of the present class.
Class to store data of complex arrays and its properties.
A class representing a U3 gate.
int size() const
Call to get the number of the allocated elements.
Gates_block()
Default constructor of the class.
int get_parameter_num()
Call to get the number of free parameters.
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 finalize_circuit()
Finalize the circuit.
void set_verbose(int verbose_in)
Call to set the verbose attribute.
void add_layer_to_imported_gate_structure()
Call to add an adaptive layer to the gate structure previously imported gate structure.
int get_target_qbit()
Call to get the index of the target qubit.
void set_property(std::string name_, double val_)
Call to set a double value.
std::map< std::string, Config_Element > config
config metadata utilized during the optimization
dictionary gate_structure
Base class for the representation of general gate operations.
virtual void start_decomposition()
Start the disentanglig process of the unitary.
double extract_theta_from_layer(Gates_block *gate_structure, int layer_idx, Matrix_real &optimized_parameters)
virtual void start_decomposition()
Start the disentanglig process of the unitary.
Header file for the paralleized calculation of the cost function of the final optimization problem (s...
Matrix Umtx
The unitary to be decomposed.
double activation_function(double Phi, int limit)
?????
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 insert_gate(Gate *gate, int idx)
Call to insert a gate at a given position.
void set_unitary(Matrix &Umtx_new)
Set unitary matrix.
double real
the real part of a complex number
Header file for a class implementing the adaptive gate decomposition algorithm of arXiv:2203...
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.
int optimization_block
number of gate blocks used in one shot of the optimization process
double decomposition_error
error of the final decomposition
Gate * get_gate(int idx)
Call to get the gates stored in the class.
int set_iteration_loops(int n, int iteration_loops_in)
Set the number of iteration loops during the subdecomposition of the n-th qubit.
A class representing a U3 gate.
int max_inner_iterations
the maximal number of iterations for which an optimization engine tries to solve the optimization pro...
Matrix import_unitary_from_binary(std::string &filename)
Import a Unitary matrix from a file.
Gates_block * determine_initial_gate_structure(Matrix_real &optimized_parameters_mtx)
Call determine the gate structrue of the decomposing circuit.
Matrix_real optimized_parameters_mtx
The optimized parameters for the gates.
void set_cost_function_variant(cost_function_type variant)
Call to set the variant of the cost function used in the calculations.
Gates_block * replace_trivial_CRY_gates(Gates_block *gate_structure, Matrix_real &optimized_parameters)
Call to replace CRY gates in the circuit that are close to either an identity or to a CNOT gate...
void set_optimization_blocks(int optimization_block_in)
Call to set the number of gate blocks to be optimized in one shot.
int get_control_qbit()
Call to get the index of the control qubit.
Class to store data of complex arrays and its properties.
std::mt19937 gen
Standard mersenne_twister_engine seeded with rd()
double imag
the imaginary part of a complex number
int omp_get_max_threads()
get the number of threads in MKL