87 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) {
121 N_Qubit_Decomposition_adaptive::N_Qubit_Decomposition_adaptive(
Matrix_float 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) {
163 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) {
204 N_Qubit_Decomposition_adaptive::N_Qubit_Decomposition_adaptive(
Matrix_float 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) {
260 std::stringstream sstream;
261 sstream <<
"***************************************************************" << std::endl;
262 sstream <<
"Starting to disentangle " <<
qbit_num <<
"-qubit matrix" << std::endl;
263 sstream <<
"***************************************************************" << std::endl << std::endl << std::endl;
291 #if BLAS==0 // undefined BLAS 296 MKL_Set_Num_Threads(1);
297 #elif BLAS==2 //OpenBLAS 299 openblas_set_num_threads(1);
303 std::stringstream sstream;
304 sstream <<
"please increase level limit" << std::endl;
313 if (
gates.size() > 0 ) {
314 std::stringstream sstream;
315 sstream <<
"Using imported gate structure for the decomposition." << std::endl;
320 std::stringstream sstream;
321 sstream <<
"Construct initial gate structure for the decomposition." << std::endl;
327 long long export_circuit_2_binary_loc;
328 if (
config.count(
"export_circuit_2_binary") > 0 ) {
329 config[
"export_circuit_2_binary"].get_property( export_circuit_2_binary_loc );
332 export_circuit_2_binary_loc = 0;
336 if ( export_circuit_2_binary_loc > 0 ) {
337 std::string
filename(
"circuit_squander.binary");
343 std::string unitaryname(
"unitary_squander.binary");
354 delete( gate_structure_loc );
357 #if BLAS==0 // undefined BLAS 361 #elif BLAS==2 //OpenBLAS 375 #if BLAS==0 // undefined BLAS 380 MKL_Set_Num_Threads(1);
381 #elif BLAS==2 //OpenBLAS 383 openblas_set_num_threads(1);
386 std::stringstream sstream;
388 sstream << std::endl;
389 sstream << std::endl;
390 sstream <<
"**************************************************************" << std::endl;
391 sstream <<
"***************** Compressing Gate structure *****************" << std::endl;
392 sstream <<
"**************************************************************" << std::endl;
395 if (
gates.size() > 0 ) {
396 std::stringstream sstream;
397 sstream <<
"Using imported gate structure for the compression." << std::endl;
403 std::stringstream sstream;
404 sstream <<
"No circuit initalised." << std::endl;
410 sstream <<
"Compressing gate structure consisting of " << gate_structure_loc->
get_gate_num() <<
" decomposing layers." << std::endl;
416 int uncompressed_iter_num = 0;
418 long long export_circuit_2_binary_loc;
419 if (
config.count(
"export_circuit_2_binary") > 0 ) {
420 config[
"export_circuit_2_binary"].get_property( export_circuit_2_binary_loc );
423 export_circuit_2_binary_loc = 0;
427 while ( iter<25 || uncompressed_iter_num <= 5 ) {
428 std::stringstream sstream;
430 sstream <<
"iteration " << iter+1 <<
": ";
436 uncompressed_iter_num = 0;
439 uncompressed_iter_num++;
442 if ( gate_structure_compressed != gate_structure_loc ) {
444 delete( gate_structure_loc );
445 gate_structure_loc = gate_structure_compressed;
446 gate_structure_compressed = NULL;
450 if ( export_circuit_2_binary_loc > 0 ) {
451 std::string
filename(
"circuit_compression.binary");
458 std::string filename_unitary(
"unitary_compression.binary");
470 if (uncompressed_iter_num>1)
break;
478 delete( gate_structure_loc );
480 #if BLAS==0 // undefined BLAS 484 #elif BLAS==2 //OpenBLAS 503 #if BLAS==0 // undefined BLAS 508 MKL_Set_Num_Threads(1);
509 #elif BLAS==2 //OpenBLAS 511 openblas_set_num_threads(1);
518 std::stringstream sstream;
520 sstream <<
"**************************************************************" << std::endl;
521 sstream <<
"************ Final tuning of the Gate structure **************" << std::endl;
522 sstream <<
"**************************************************************" << std::endl;
526 if (
config.count(
"optimization_tolerance") > 0 ) {
528 config[
"optimization_tolerance"].get_property( value );
559 std::map<std::string, Config_Element> config_copy;
561 if (
config.count(
"max_inner_iterations_final") > 0 ) {
563 config[
"max_inner_iterations_final"].get_property( val );
566 config_copy[
"max_inner_iterations"] = element;
590 int max_inner_iterations_loc =
static_cast<int>((double)param_num_loc/852 * 10000000.0);
596 int max_inner_iterations_loc = 2500;
602 int max_inner_iterations_loc = 10000;
614 delete( gate_structure_tmp );
622 long long export_circuit_2_binary_loc;
623 if (
config.count(
"export_circuit_2_binary") > 0 ) {
624 config[
"export_circuit_2_binary"].get_property( export_circuit_2_binary_loc );
627 export_circuit_2_binary_loc = 0;
631 if ( export_circuit_2_binary_loc > 0 ) {
632 std::string filename2(
"circuit_final.binary");
651 for(
auto it=gate_nums.begin(); it != gate_nums.end(); it++ ) {
652 sstream << it->second <<
" " << it->first <<
" gates" << std::endl;
655 sstream << std::endl;
658 #if BLAS==0 // undefined BLAS 662 #elif BLAS==2 //OpenBLAS 678 tbb::tick_count start_time_loc = tbb::tick_count::now();
680 std::stringstream sstream;
681 sstream <<
"Starting optimization with " << gate_structure_loc->
get_gate_num() <<
" decomposing layers." << std::endl;
684 double optimization_tolerance_loc;
685 if (
config.count(
"optimization_tolerance") > 0 ) {
686 config[
"optimization_tolerance"].get_property( optimization_tolerance_loc );
715 int max_inner_iterations_loc =
static_cast<int>((double)param_num_loc/852 * 10000000.0);
721 int max_inner_iterations_loc = 2500;
727 int max_inner_iterations_loc = 10000;
734 tbb::tick_count end_time_loc = tbb::tick_count::now();
742 std::stringstream sstream;
743 sstream <<
"Optimization problem solved with " << gate_structure_loc->
get_gate_num() <<
" decomposing layers in " << (end_time_loc-start_time_loc).seconds() <<
" seconds." << std::endl;
747 std::stringstream sstream;
748 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;
753 std::stringstream sstream;
754 sstream <<
"Decomposition did not reached prescribed high numerical precision." << std::endl;
760 sstream <<
"Continue with the compression of gate structure consisting of " << gate_structure_loc->
get_gate_num() <<
" decomposing layers." << std::endl;
762 return gate_structure_loc;
776 std::vector<double> minimum_vec;
777 std::vector<Gates_block*> gate_structure_vec;
778 std::vector<Matrix_real> optimized_parameters_vec;
780 double optimization_tolerance_loc;
781 if (
config.count(
"optimization_tolerance") > 0 ) {
782 config[
"optimization_tolerance"].get_property( optimization_tolerance_loc );
788 int max_outer_iterations_loc;
789 double value_placeholder;
790 if (
config.count(
"max_outer_iterations") > 0 ) {
791 config[
"max_outer_iterations"].get_property( value_placeholder );
792 max_outer_iterations_loc = (
int) value_placeholder;
807 for (
int idx=0; idx<
level; idx++) {
819 tbb::tick_count start_time_loc = tbb::tick_count::now();
824 std::stringstream sstream;
825 sstream <<
"Starting optimization with " << gate_structure_loc->
get_gate_num() <<
" decomposing layers." << std::endl;
859 int max_inner_iterations_loc =
static_cast<int>((double)param_num_loc/852 * 10000000.0);
865 int max_inner_iterations_loc = 2000;
871 int max_inner_iterations_loc = 10000;
908 tbb::tick_count end_time_loc = tbb::tick_count::now();
916 double current_minimum_loc;
920 if ( current_minimum_random < optimization_tolerance_loc && current_minimum_close_to_zero > optimization_tolerance_loc ) {
921 current_minimum_loc = current_minimum_random;
925 else if ( current_minimum_random > optimization_tolerance_loc && current_minimum_close_to_zero < optimization_tolerance_loc ) {
926 current_minimum_loc = current_minimum_close_to_zero;
930 else if ( current_minimum_random < optimization_tolerance_loc && current_minimum_close_to_zero < optimization_tolerance_loc ) {
934 int panelty_random =
get_panelty(gate_structure_loc, optimized_parameters_mtx_random);
935 int panelty_close_to_zero =
get_panelty(gate_structure_loc, optimized_parameters_mtx_close_to_zero );
937 if ( panelty_random < panelty_close_to_zero ) {
938 current_minimum_loc = current_minimum_random;
943 current_minimum_loc = current_minimum_close_to_zero;
950 if ( current_minimum_random < current_minimum_close_to_zero ) {
951 current_minimum_loc = current_minimum_random;
956 current_minimum_loc = current_minimum_close_to_zero;
963 minimum_vec.push_back(current_minimum_loc);
964 gate_structure_vec.push_back(gate_structure_loc);
965 optimized_parameters_vec.push_back(optimized_parameters_mtx_loc);
969 if ( current_minimum_loc < optimization_tolerance_loc ) {
970 std::stringstream sstream;
971 sstream <<
"Optimization problem solved with " << gate_structure_loc->
get_gate_num() <<
" decomposing layers in " << (end_time_loc-start_time_loc).seconds() <<
" seconds." << std::endl;
976 std::stringstream sstream;
977 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;
989 for (
int idx=1; idx<(
int)minimum_vec.size(); idx++) {
990 if( current_minimum > minimum_vec[idx] ) {
992 current_minimum = minimum_vec[idx];
997 Gates_block* gate_structure_loc = gate_structure_vec[idx_min];
998 optimized_parameters_mtx_loc = optimized_parameters_vec[idx_min];
1001 for (
int idx=0; idx<(
int)minimum_vec.size(); idx++) {
1002 if( idx == idx_min ) {
1005 delete( gate_structure_vec[idx] );
1007 minimum_vec.clear();
1008 gate_structure_vec.clear();
1009 optimized_parameters_vec.clear();
1013 if (current_minimum > optimization_tolerance_loc) {
1014 std::stringstream sstream;
1015 sstream <<
"Decomposition did not reached prescribed high numerical precision." << std::endl;
1017 optimization_tolerance_loc = 1.5*current_minimum < 1e-2 ? 1.5*
current_minimum : 1e-2;
1021 return gate_structure_loc;
1038 if ( layer_num_orig < 50 ) layer_num_max = layer_num_orig;
1039 else if ( layer_num_orig < 60 ) layer_num_max = 4;
1040 else layer_num_max = 2;
1041 double optimization_tolerance_loc;
1042 if (
config.count(
"optimization_tolerance") > 0 ) {
1043 config[
"optimization_tolerance"].get_property( optimization_tolerance_loc );
1050 std::uniform_int_distribution<> distrib_int(0, 5000);
1052 std::vector<int> layers_to_remove;
1053 if (uncompressed_iter_num==0){
1054 layer_num_max = 5<layer_num_orig ? 5 : layer_num_orig;
1056 std::vector<double> layers_parameters(layer_num_orig,15.0);
1057 std::vector<int> layers_idx_sorted(layer_num_orig,0);
1059 for (
int idx=0; idx<layer_num_orig;idx++){
1061 layers_idx_sorted[idx] = idx;
1064 std::iota(layers_idx_sorted.begin(),layers_idx_sorted.end(),0);
1065 sort( layers_idx_sorted.begin(),layers_idx_sorted.end(), [&](
int i,
int j){
return layers_parameters[i]<layers_parameters[j];} );
1067 for (
int idx=0; idx<layer_num_max; idx++ ) {
1068 layers_to_remove.push_back( layers_idx_sorted[idx]);
1072 layers_to_remove.reserve(layer_num_orig);
1073 for (
int idx=0; idx<layer_num_orig; idx++ ) {
1074 layers_to_remove.push_back(idx);
1078 while ( (
int)layers_to_remove.size() > layer_num_max ) {
1079 int remove_idx = distrib_int(
gen) % layers_to_remove.size();
1081 layers_to_remove.erase( layers_to_remove.begin() + remove_idx );
1087 MPI_Bcast( &layers_to_remove[0], layers_to_remove.size(), MPI_INT, 0, MPI_COMM_WORLD);
1093 int panelties_num = layer_num_max < layer_num_orig ? layer_num_max : layer_num_orig;
1095 if ( panelties_num == 0 ) {
1100 std::vector<unsigned int> panelties(panelties_num, 1<<31);
1101 std::vector<Gates_block*> gate_structures_vec(panelties_num, NULL);
1102 std::vector<double> current_minimum_vec(panelties_num, DBL_MAX);
1103 std::vector<int> iteration_num_vec(panelties_num, 0);
1106 std::vector<Matrix_real> optimized_parameters_vec(panelties_num,
Matrix_real(0,0));
1107 std::vector<Matrix> Umtx_vec(panelties_num,
Matrix(0,0));
1111 for (
int idx=0; idx<panelties_num; idx++) {
1115 double current_minimum_loc = DBL_MAX;
1116 int iteration_num = 0;
1119 Gates_block* gate_structure_reduced =
compress_gate_structure( gate_structure, layers_to_remove[idx], optimized_parameters_loc, current_minimum_loc, iteration_num );
1120 if ( optimized_parameters_loc.
size() == 0 ) {
1127 gate_structure_tmp = gate_structure_reduced->
clone();
1130 gate_structure_tmp =
remove_trivial_CRY_gates( gate_structure_reduced, optimized_parameters_loc, current_minimum_loc );
1133 panelties[idx] =
get_panelty(gate_structure_tmp, optimized_parameters_loc);
1134 gate_structures_vec[idx] = gate_structure_tmp;
1135 current_minimum_vec[idx] = current_minimum_loc;
1136 iteration_num_vec[idx] = iteration_num;
1139 optimized_parameters_vec[idx] = optimized_parameters_loc;
1140 Umtx_vec[idx] =
Umtx;
1143 delete(gate_structure_reduced);
1146 if ( current_minimum_vec[idx] < optimization_tolerance_loc ) {
1155 unsigned int panelty_min = panelties[0];
1156 unsigned int idx_min = 0;
1158 for (
size_t idx=0; idx<panelties.size(); idx++) {
1159 if ( panelty_min > panelties[idx] ) {
1160 panelty_min = panelties[idx];
1161 idx_min =
static_cast<unsigned int>(idx);
1164 else if ( panelty_min == panelties[idx] ) {
1166 if ( (distrib_int(
gen) % 2) == 1 ) {
1167 idx_min =
static_cast<unsigned int>(idx);
1169 panelty_min = panelties[idx];
1177 MPI_Bcast( &idx_min, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD);
1182 for (
size_t idx=0; idx<panelties.size(); idx++) {
1188 if ( gate_structures_vec[idx] == gate_structure) {
1192 if ( gate_structures_vec[idx] ) {
1193 delete( gate_structures_vec[idx] );
1194 gate_structures_vec[idx] = NULL;
1200 gate_structure = gate_structures_vec[idx_min];
1204 Umtx = Umtx_vec[idx_min];
1208 if ( layer_num < layer_num_orig+1 ) {
1209 std::stringstream sstream;
1210 sstream <<
"gate structure reduced from " << layer_num_orig+1 <<
" to " << layer_num <<
" decomposing layers" << std::endl;
1214 std::stringstream sstream;
1215 sstream <<
"gate structure kept at " << layer_num <<
" layers" << std::endl;
1242 if ( optimized_parameters.
size() > 0 ) {
1253 std::map<std::string, Config_Element> config_copy;
1255 if (
config.count(
"max_inner_iterations_compression") > 0 ) {
1257 config[
"max_inner_iterations_compression"].get_property( val );
1260 config_copy[
"max_inner_iterations"] = element;
1263 double optimization_tolerance_loc;
1264 if (
config.count(
"optimization_tolerance") > 0 ) {
1265 config[
"optimization_tolerance"].get_property( optimization_tolerance_loc );
1297 int max_inner_iterations_loc = 100;
1304 if ( current_minimum_tmp < optimization_tolerance_loc ) {
1307 current_minimum_loc = current_minimum_tmp;
1308 return gate_structure_reduced;
1312 return gate_structure->
clone();
1332 for (
int layer_idx=0; layer_idx<
layer_num; layer_idx++) {
1338 for(
int gate_idx=0; gate_idx<gate_num; gate_idx++ ) {
1350 if ( std::abs(std::sin(parameter)) < 0.999 && std::abs(std::cos(parameter)) < 1e-3 ) {
1354 else if ( std::abs(std::sin(parameter)) < 1e-3 && std::abs(1-std::cos(parameter)) < 1e-3 ) {
1389 if (
gates.size() > 0 ) {
1393 std::stringstream sstream;
1394 sstream <<
"No circuit initalised." << std::endl;
1396 throw( sstream.str() );
1414 for (
int idx=0; idx<
layer_num; idx++ ) {
1419 std::string err =
"N_Qubit_Decomposition_adaptive::replace_CRY_gates: Only block gates are accepted in this conversion.";
1444 if ( gate_tmp->
get_type() ==
ADAPTIVE_OPERATION && std::abs(std::sin(parameter)) > 0.999 && std::abs(std::cos(parameter)) < 1e-3) {
1452 CZ* cz_gate =
new CZ(
qbit_num, target_qbit, control_qbit);
1467 memcpy(parameters_new.get_data(), optimized_parameters.
get_data(), parameter_idx*
sizeof(double));
1469 memcpy(parameters_new.get_data()+parameter_idx+3, optimized_parameters.
get_data()+parameter_idx+1, (optimized_parameters.
size()-parameter_idx-1)*
sizeof(
double));
1472 parameters_new[parameter_idx+1] =
M_PI/4;
1475 if ( std::sin(parameter) < 0 ) {
1477 parameters_new[parameter_idx+2] = -
M_PI/4;
1480 global_phase_factor_new.
real = std::cos( -
M_PI/4 );
1481 global_phase_factor_new.
imag = std::sin( -
M_PI/4 );
1487 parameters_new[parameter_idx+2] =
M_PI/4;
1490 global_phase_factor_new.
real = std::cos(
M_PI/4 );
1491 global_phase_factor_new.
imag = std::sin(
M_PI/4 );
1497 optimized_parameters = parameters_new;
1504 else if ( gate_tmp->
get_type() ==
ADAPTIVE_OPERATION && std::abs(std::sin(parameter)) < 1e-3 && std::abs(1-std::cos(parameter)) < 1e-3 ) {
1510 memcpy(parameters_new.get_data(), optimized_parameters.
get_data(), parameter_idx*
sizeof(double));
1511 memcpy(parameters_new.get_data()+
parameter_idx, optimized_parameters.
get_data()+parameter_idx+1, (optimized_parameters.
size()-parameter_idx-1)*
sizeof(
double));
1512 optimized_parameters = parameters_new;
1538 memcpy(parameters_new.get_data(), optimized_parameters.
get_data(), parameter_idx*
sizeof(double));
1539 memcpy(parameters_new.get_data()+parameter_idx+2, optimized_parameters.
get_data()+parameter_idx+1, (optimized_parameters.
size()-parameter_idx-1)*
sizeof(
double));
1540 optimized_parameters = parameters_new;
1543 optimized_parameters[parameter_idx+1] = -parameter/2;
1574 return gate_structure_ret;
1586 if (
gates.size() == 0 ) {
1587 std::stringstream sstream;
1588 sstream <<
"No circuit initalised." << std::endl;
1600 int layers_before = gate_structure_loc->
get_gate_num();
1602 delete( gate_structure_loc );
1603 gate_structure_loc = gate_structure_tmp;
1604 if ( gate_structure_loc->
get_gate_num() >= layers_before ) {
1610 combine( gate_structure_loc );
1611 delete( gate_structure_loc );
1615 std::stringstream sstream;
1616 sstream <<
"Circuit after removing trivial CRY gates: " 1617 << gate_num_before <<
" -> " <<
get_gate_num() <<
" layer(s), " 1638 for (
int idx=0; idx<
layer_num; idx++ ) {
1666 for(
size_t rdx=0; rdx<involved_qbits.size(); rdx++ ) {
1668 U3* U_gate_to_be_removed =
static_cast<U3*
>(layer->
get_gate(static_cast<int>(rdx)));
1671 int parameter_idx_loc = parameter_idx_to_be_removed + layer->
get_parameter_num();
1673 bool found_match =
false;
1674 U3* matching_gate = NULL;
1677 for (
int kdx=idx+1; kdx<
layer_num; kdx++ ) {
1683 for (
int hdx=0; hdx<gate_num; hdx++ ) {
1690 if ( qbit_to_be_matched == target_qbit_loc ) {
1692 matching_gate =
static_cast<U3*
>(gate_test);
1702 if ( found_match )
break;
1707 if ( found_match ==
false ) {
1709 if ( new_layer == NULL ) {
1716 memset(optimized_parameters_loc_tmp.
get_data(), 0, optimized_parameters_loc_tmp.
size()*
sizeof(double));
1717 memcpy(optimized_parameters_loc_tmp.
get_data(), optimized_parameters_loc.
get_data(), optimized_parameters_loc.
size()*
sizeof(double));
1720 memcpy(optimized_parameters_loc_tmp.
get_data()+optimized_parameters_loc.
size(), param1.get_data(), U_gate_to_be_removed->
get_parameter_num()*
sizeof(double));
1722 optimized_parameters_loc = optimized_parameters_loc_tmp;
1724 optimized_parameters_loc[parameter_idx_to_be_removed] = 0.0;
1725 optimized_parameters_loc[parameter_idx_to_be_removed+1] = 0.0;
1726 optimized_parameters_loc[parameter_idx_to_be_removed+2] = 0.0;
1727 parameter_idx_to_be_removed = parameter_idx_to_be_removed + U_gate_to_be_removed->
get_parameter_num();
1738 Matrix U3_prod =
dot(U3_matrix2, U3_matrix1);
1740 optimized_parameters_loc[parameter_idx_to_be_removed] = 0.0;
1741 optimized_parameters_loc[parameter_idx_to_be_removed+1] = 0.0;
1742 optimized_parameters_loc[parameter_idx_to_be_removed+2] = 0.0;
1743 parameter_idx_to_be_removed = parameter_idx_to_be_removed + U_gate_to_be_removed->
get_parameter_num();
1747 double ctheta3_over2 = std::sqrt(U3_prod[0].
real*U3_prod[0].
real+U3_prod[0].imag*U3_prod[0].imag);
1748 double stheta3_over2 = std::sqrt(U3_prod[2].
real*U3_prod[2].
real+U3_prod[2].imag*U3_prod[2].imag);
1749 double theta3_over2 = std::atan2(stheta3_over2,ctheta3_over2);
1751 double alpha = std::atan2(U3_prod[0].imag,U3_prod[0].
real);
1756 if (std::abs(stheta3_over2)<4e-8){
1757 lambda3 = (std::atan2(U3_prod[3].imag,U3_prod[3].real)-
alpha)/2;
1761 lambda3 = std::atan2(-1*U3_prod[1].imag,-1*U3_prod[1].real)-
alpha;
1762 phi3 = std::atan2(U3_prod[2].imag,U3_prod[2].real)-
alpha;
1768 global_phase_factor_new.
real = std::cos(alpha);
1769 global_phase_factor_new.
imag = std::sin(alpha);
1773 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) {
1777 param2[0] = theta3_over2;
1779 param2[2] = lambda3;
1798 gate_structure_reduced = gate_structure->
clone();
1799 if ( new_layer != NULL ) {
1800 gate_structure_reduced->
add_gate(new_layer);
1806 if ( optimized_parameters_loc.
size() > 0 ) {
1821 optimized_parameters = optimized_parameters_loc;
1829 if ( gate_structure_reduced == NULL ) {
1830 gate_structure_reduced = gate_structure->
clone();
1833 return gate_structure_reduced;
1853 for (
int idx=0; idx<layer_idx; idx++) {
1863 Matrix_real reduced_parameters(1, optimized_parameters.
size() - param_num_removed );
1864 memcpy( reduced_parameters.get_data(), optimized_parameters.
get_data(), (
parameter_idx)*
sizeof(
double));
1865 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));
1868 return reduced_parameters;
1896 gate_structure->
combine( layer );
1912 std::stringstream sstream;
1917 std::vector<Gates_block* >
layers;
1923 if ( it->size() != 2 ) {
1924 std::string err(
"The connectivity data should contains two qubits.");
1928 int control_qbit_loc = (*it)[0];
1929 int target_qbit_loc = (*it)[1];
1932 std::string err(
"Label of control/target qubit should be less than the number of qubits in the register.");
1938 layer->
add_u3(target_qbit_loc);
1939 layer->
add_u3(control_qbit_loc);
1940 layer->
add_adaptive(target_qbit_loc, control_qbit_loc);
1942 layers.push_back(layer);
1950 for (
int target_qbit_loc = 0; target_qbit_loc<
qbit_num; target_qbit_loc++) {
1951 for (
int control_qbit_loc = target_qbit_loc+1; control_qbit_loc<
qbit_num; control_qbit_loc++) {
1955 layer->
add_u3(target_qbit_loc);
1956 layer->
add_u3(control_qbit_loc);
1957 layer->
add_adaptive(target_qbit_loc, control_qbit_loc);
1959 layers.push_back(layer);
1973 bool randomized_adaptive_layers_loc;
1974 if (
config.count(
"randomized_adaptive_layers") > 0 ) {
1975 config[
"randomized_adaptive_layers"].get_property( randomized_adaptive_layers_loc );
1983 if (randomized_adaptive_layers_loc) {
1985 std::uniform_int_distribution<> distrib_int(0, 5000);
1987 while (layers.size()>0) {
1988 int idx = distrib_int(
gen) % layers.size();
1991 MPI_Bcast( &idx, 1, MPI_INT, 0, MPI_COMM_WORLD);
1994 layers.erase( layers.begin() + idx );
1999 while (layers.size()>0) {
2001 layers.erase( layers.begin() );
2032 for (
int idx=0; idx<
qbit_num; idx++) {
2039 if ( gate_structure == NULL ) {
2040 throw (
"N_Qubit_Decomposition_adaptive::add_finalyzing_layer: gate_structure is null pointer");
2048 memset(optimized_parameters_mtx_tmp.
get_data(), 0, optimized_parameters_mtx_tmp.
size()*
sizeof(double));
2065 if (
gates.size() > 0 ) {
2089 upload_Umtx_to_DFE();
2108 upload_Umtx_to_DFE();
2123 upload_Umtx_to_DFE();
2141 if (
gates.size() > 0 ) {
2142 gate_structure_tmp->
combine( static_cast<Gates_block*>(
this) );
2145 combine( gate_structure_tmp );
2156 combine( gate_structure_tmp );
2170 if (
gates.size() == 0 ) {
2175 std::stringstream sstream;
2210 std::stringstream sstream;
2211 sstream <<
"Add new layer to the adaptive gate structure." << std::endl;
2220 memset( tmp.get_data(), 0, tmp.size()*
sizeof(double) );
2233 double ThetaOver2=0.;
2234 for (
int gate_idx=0; gate_idx<layer_gate_num; gate_idx++){
2238 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.
Copyright (C) Miklos Maroti, 2021 SPDX-License-Identifier: Apache-2.0.
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.
Class to store single-precision real arrays and properties.
void release_gate(int idx)
Call to release one gate in the list.
Matrix_float to_float32() const
Convert to single precision.
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.
std::map< std::string, int > get_gate_nums()
Call to get the number of the individual gate types in the list of gates.
Gates_block * replace_CRY_gates()
Call to replace CRY gates in the circuit that are close to either an identity or to a CNOT gate...
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...
void add_gate(Gate *gate)
Append a general gate to the list of gates.
Matrix to_float64() const
Convert to double precision.
bool use_float
Selects float32 circuit application for parameter/unitary/state data.
cost_function_type cost_fnc
The chosen variant of the cost function.
void add_finalyzing_layer()
Call to add finalyzing layer (single qubit rotations on all of the qubits) to the gate structure stor...
virtual void remove_trivial_CRY_gates()
Remove blocks containing a trivial CRY gate from the circuit stored by the class. ...
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.
int trace_offset
The offset in the first columns from which the "trace" is calculated. In this case Tr(A) = sum_(i-off...
virtual Gates_block * clone() override
Create a clone of the present class.
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.
void increment_num_iters(int delta=1)
Atomically increment the tracked number of optimization iterations.
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
static Matrix calc_one_qubit_u3(double ThetaOver2=0.0, double Phi=0.0, double Lambda=0.0)
Build a 2x2 U3 kernel from angles (theta/2, phi, lambda).
void sync_optimized_parameters_float()
Synchronize the float32 parameter mirror from the double optimizer storage.
Gates_block * import_gate_list_from_binary(Matrix_real ¶meters, const std::string &filename, int verbosity)
Use to import a quantum circuit from a binary format.
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...
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.
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...
Matrix_float Umtx_float
Float32 copy of the unitary used when config["use_float"] is true.
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 void apply_to(Matrix_real ¶meters_mtx, Matrix &input, int parallel=0) override
Call to apply the gate on the input array/matrix Gates_block*input.
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.
Matrix copy() const
Call to create a copy of the matrix.
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.
Double-precision complex matrix (float64).
int size() const
Call to get the number of the allocated elements.
Gates_block()
Default constructor of the class.
virtual 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.
Single-precision complex matrix (float32).
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...
volatile double current_minimum
The current minimum of the optimization problem.
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)
Use to export a quantum circuit into binary format.
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.
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.
std::vector< int > get_involved_qubits(bool only_target=false) override
Call to get the qubits involved in the gates stored in the block of gates.
void set_cost_function_variant(cost_function_type variant)
Call to set the variant of the cost function used in the calculations.
int get_parameter_num() override
Call to get the number of free parameters.
Matrix_float copy() const
Call to create a copy of the matrix.
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