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);
516 if (
gates.size() > 0 ) {
517 std::stringstream sstream;
518 sstream <<
"Using imported gate structure for the compression." << std::endl;
524 std::stringstream sstream;
525 sstream <<
"No circuit initalised." << std::endl;
531 std::stringstream sstream;
533 sstream <<
"**************************************************************" << std::endl;
534 sstream <<
"************ Final tuning of the Gate structure **************" << std::endl;
535 sstream <<
"**************************************************************" << std::endl;
539 if (
config.count(
"optimization_tolerance") > 0 ) {
541 config[
"optimization_tolerance"].get_property( value );
572 std::map<std::string, Config_Element> config_copy;
574 if (
config.count(
"max_inner_iterations_final") > 0 ) {
576 config[
"max_inner_iterations_final"].get_property( val );
579 config_copy[
"max_inner_iterations"] = element;
603 int max_inner_iterations_loc =
static_cast<int>((double)param_num_loc/852 * 10000000.0);
609 int max_inner_iterations_loc = 2500;
615 int max_inner_iterations_loc = 10000;
627 delete( gate_structure_tmp );
628 delete( gate_structure_loc );
636 long long export_circuit_2_binary_loc;
637 if (
config.count(
"export_circuit_2_binary") > 0 ) {
638 config[
"export_circuit_2_binary"].get_property( export_circuit_2_binary_loc );
641 export_circuit_2_binary_loc = 0;
645 if ( export_circuit_2_binary_loc > 0 ) {
646 std::string filename2(
"circuit_final.binary");
665 for(
auto it=gate_nums.begin(); it != gate_nums.end(); it++ ) {
666 sstream << it->second <<
" " << it->first <<
" gates" << std::endl;
669 sstream << std::endl;
672 #if BLAS==0 // undefined BLAS 676 #elif BLAS==2 //OpenBLAS 692 tbb::tick_count start_time_loc = tbb::tick_count::now();
694 std::stringstream sstream;
695 sstream <<
"Starting optimization with " << gate_structure_loc->
get_gate_num() <<
" decomposing layers." << std::endl;
698 double optimization_tolerance_loc;
699 if (
config.count(
"optimization_tolerance") > 0 ) {
700 config[
"optimization_tolerance"].get_property( optimization_tolerance_loc );
729 int max_inner_iterations_loc =
static_cast<int>((double)param_num_loc/852 * 10000000.0);
735 int max_inner_iterations_loc = 2500;
741 int max_inner_iterations_loc = 10000;
748 tbb::tick_count end_time_loc = tbb::tick_count::now();
756 std::stringstream sstream;
757 sstream <<
"Optimization problem solved with " << gate_structure_loc->
get_gate_num() <<
" decomposing layers in " << (end_time_loc-start_time_loc).seconds() <<
" seconds." << std::endl;
761 std::stringstream sstream;
762 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;
767 std::stringstream sstream;
768 sstream <<
"Decomposition did not reached prescribed high numerical precision." << std::endl;
774 sstream <<
"Continue with the compression of gate structure consisting of " << gate_structure_loc->
get_gate_num() <<
" decomposing layers." << std::endl;
776 return gate_structure_loc;
790 std::vector<double> minimum_vec;
791 std::vector<Gates_block*> gate_structure_vec;
792 std::vector<Matrix_real> optimized_parameters_vec;
794 double optimization_tolerance_loc;
795 if (
config.count(
"optimization_tolerance") > 0 ) {
796 config[
"optimization_tolerance"].get_property( optimization_tolerance_loc );
802 int max_outer_iterations_loc;
803 double value_placeholder;
804 if (
config.count(
"max_outer_iterations") > 0 ) {
805 config[
"max_outer_iterations"].get_property( value_placeholder );
806 max_outer_iterations_loc = (
int) value_placeholder;
821 for (
int idx=0; idx<
level; idx++) {
833 tbb::tick_count start_time_loc = tbb::tick_count::now();
838 std::stringstream sstream;
839 sstream <<
"Starting optimization with " << gate_structure_loc->
get_gate_num() <<
" decomposing layers." << std::endl;
873 int max_inner_iterations_loc =
static_cast<int>((double)param_num_loc/852 * 10000000.0);
879 int max_inner_iterations_loc = 2000;
885 int max_inner_iterations_loc = 10000;
922 tbb::tick_count end_time_loc = tbb::tick_count::now();
930 double current_minimum_loc;
934 if ( current_minimum_random < optimization_tolerance_loc && current_minimum_close_to_zero > optimization_tolerance_loc ) {
935 current_minimum_loc = current_minimum_random;
939 else if ( current_minimum_random > optimization_tolerance_loc && current_minimum_close_to_zero < optimization_tolerance_loc ) {
940 current_minimum_loc = current_minimum_close_to_zero;
944 else if ( current_minimum_random < optimization_tolerance_loc && current_minimum_close_to_zero < optimization_tolerance_loc ) {
948 int panelty_random =
get_panelty(gate_structure_loc, optimized_parameters_mtx_random);
949 int panelty_close_to_zero =
get_panelty(gate_structure_loc, optimized_parameters_mtx_close_to_zero );
951 if ( panelty_random < panelty_close_to_zero ) {
952 current_minimum_loc = current_minimum_random;
957 current_minimum_loc = current_minimum_close_to_zero;
964 if ( current_minimum_random < current_minimum_close_to_zero ) {
965 current_minimum_loc = current_minimum_random;
970 current_minimum_loc = current_minimum_close_to_zero;
977 minimum_vec.push_back(current_minimum_loc);
978 gate_structure_vec.push_back(gate_structure_loc);
979 optimized_parameters_vec.push_back(optimized_parameters_mtx_loc);
983 if ( current_minimum_loc < optimization_tolerance_loc ) {
984 std::stringstream sstream;
985 sstream <<
"Optimization problem solved with " << gate_structure_loc->
get_gate_num() <<
" decomposing layers in " << (end_time_loc-start_time_loc).seconds() <<
" seconds." << std::endl;
990 std::stringstream sstream;
991 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;
1003 for (
int idx=1; idx<(
int)minimum_vec.size(); idx++) {
1004 if( current_minimum > minimum_vec[idx] ) {
1006 current_minimum = minimum_vec[idx];
1011 Gates_block* gate_structure_loc = gate_structure_vec[idx_min];
1012 optimized_parameters_mtx_loc = optimized_parameters_vec[idx_min];
1015 for (
int idx=0; idx<(
int)minimum_vec.size(); idx++) {
1016 if( idx == idx_min ) {
1019 delete( gate_structure_vec[idx] );
1021 minimum_vec.clear();
1022 gate_structure_vec.clear();
1023 optimized_parameters_vec.clear();
1027 if (current_minimum > optimization_tolerance_loc) {
1028 std::stringstream sstream;
1029 sstream <<
"Decomposition did not reached prescribed high numerical precision." << std::endl;
1031 optimization_tolerance_loc = 1.5*current_minimum < 1e-2 ? 1.5*
current_minimum : 1e-2;
1035 return gate_structure_loc;
1052 if ( layer_num_orig < 50 ) layer_num_max = layer_num_orig;
1053 else if ( layer_num_orig < 60 ) layer_num_max = 4;
1054 else layer_num_max = 2;
1055 double optimization_tolerance_loc;
1056 if (
config.count(
"optimization_tolerance") > 0 ) {
1057 config[
"optimization_tolerance"].get_property( optimization_tolerance_loc );
1064 std::uniform_int_distribution<> distrib_int(0, 5000);
1066 std::vector<int> layers_to_remove;
1067 if (uncompressed_iter_num==0){
1068 layer_num_max = 5<layer_num_orig ? 5 : layer_num_orig;
1070 std::vector<double> layers_parameters(layer_num_orig,15.0);
1071 std::vector<int> layers_idx_sorted(layer_num_orig,0);
1073 for (
int idx=0; idx<layer_num_orig;idx++){
1075 layers_idx_sorted[idx] = idx;
1078 std::iota(layers_idx_sorted.begin(),layers_idx_sorted.end(),0);
1079 sort( layers_idx_sorted.begin(),layers_idx_sorted.end(), [&](
int i,
int j){
return layers_parameters[i]<layers_parameters[j];} );
1081 for (
int idx=0; idx<layer_num_max; idx++ ) {
1082 layers_to_remove.push_back( layers_idx_sorted[idx]);
1086 layers_to_remove.reserve(layer_num_orig);
1087 for (
int idx=0; idx<layer_num_orig; idx++ ) {
1088 layers_to_remove.push_back(idx);
1092 while ( (
int)layers_to_remove.size() > layer_num_max ) {
1093 int remove_idx = distrib_int(
gen) % layers_to_remove.size();
1095 layers_to_remove.erase( layers_to_remove.begin() + remove_idx );
1101 MPI_Bcast( &layers_to_remove[0], layers_to_remove.size(), MPI_INT, 0, MPI_COMM_WORLD);
1107 int panelties_num = layer_num_max < layer_num_orig ? layer_num_max : layer_num_orig;
1109 if ( panelties_num == 0 ) {
1114 std::vector<unsigned int> panelties(panelties_num, 1<<31);
1115 std::vector<Gates_block*> gate_structures_vec(panelties_num, NULL);
1116 std::vector<double> current_minimum_vec(panelties_num, DBL_MAX);
1117 std::vector<int> iteration_num_vec(panelties_num, 0);
1120 std::vector<Matrix_real> optimized_parameters_vec(panelties_num,
Matrix_real(0,0));
1121 std::vector<Matrix> Umtx_vec(panelties_num,
Matrix(0,0));
1125 for (
int idx=0; idx<panelties_num; idx++) {
1129 double current_minimum_loc = DBL_MAX;
1130 int iteration_num = 0;
1133 Gates_block* gate_structure_reduced =
compress_gate_structure( gate_structure, layers_to_remove[idx], optimized_parameters_loc, current_minimum_loc, iteration_num );
1134 if ( optimized_parameters_loc.
size() == 0 ) {
1141 gate_structure_tmp = gate_structure_reduced->
clone();
1144 gate_structure_tmp =
remove_trivial_gates( gate_structure_reduced, optimized_parameters_loc, current_minimum_loc );
1147 panelties[idx] =
get_panelty(gate_structure_tmp, optimized_parameters_loc);
1148 gate_structures_vec[idx] = gate_structure_tmp;
1149 current_minimum_vec[idx] = current_minimum_loc;
1150 iteration_num_vec[idx] = iteration_num;
1153 optimized_parameters_vec[idx] = optimized_parameters_loc;
1154 Umtx_vec[idx] =
Umtx;
1157 delete(gate_structure_reduced);
1160 if ( current_minimum_vec[idx] < optimization_tolerance_loc ) {
1169 unsigned int panelty_min = panelties[0];
1170 unsigned int idx_min = 0;
1172 for (
size_t idx=0; idx<panelties.size(); idx++) {
1173 if ( panelty_min > panelties[idx] ) {
1174 panelty_min = panelties[idx];
1175 idx_min =
static_cast<unsigned int>(idx);
1178 else if ( panelty_min == panelties[idx] ) {
1180 if ( (distrib_int(
gen) % 2) == 1 ) {
1181 idx_min =
static_cast<unsigned int>(idx);
1183 panelty_min = panelties[idx];
1191 MPI_Bcast( &idx_min, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD);
1196 for (
size_t idx=0; idx<panelties.size(); idx++) {
1202 if ( gate_structures_vec[idx] == gate_structure) {
1206 if ( gate_structures_vec[idx] ) {
1207 delete( gate_structures_vec[idx] );
1208 gate_structures_vec[idx] = NULL;
1214 gate_structure = gate_structures_vec[idx_min];
1218 Umtx = Umtx_vec[idx_min];
1222 if ( layer_num < layer_num_orig+1 ) {
1223 std::stringstream sstream;
1224 sstream <<
"gate structure reduced from " << layer_num_orig+1 <<
" to " << layer_num <<
" decomposing layers" << std::endl;
1228 std::stringstream sstream;
1229 sstream <<
"gate structure kept at " << layer_num <<
" layers" << std::endl;
1256 if ( optimized_parameters.
size() > 0 ) {
1267 std::map<std::string, Config_Element> config_copy;
1269 if (
config.count(
"max_inner_iterations_compression") > 0 ) {
1271 config[
"max_inner_iterations_compression"].get_property( val );
1274 config_copy[
"max_inner_iterations"] = element;
1277 double optimization_tolerance_loc;
1278 if (
config.count(
"optimization_tolerance") > 0 ) {
1279 config[
"optimization_tolerance"].get_property( optimization_tolerance_loc );
1311 int max_inner_iterations_loc = 100;
1318 if ( current_minimum_tmp < optimization_tolerance_loc ) {
1321 current_minimum_loc = current_minimum_tmp;
1322 return gate_structure_reduced;
1326 return gate_structure->
clone();
1346 for (
int layer_idx=0; layer_idx<
layer_num; layer_idx++) {
1352 for(
int gate_idx=0; gate_idx<gate_num; gate_idx++ ) {
1364 if ( std::abs(std::sin(parameter)) < 0.999 && std::abs(std::cos(parameter)) < 1e-3 ) {
1368 else if ( std::abs(std::sin(parameter)) < 1e-3 && std::abs(1-std::cos(parameter)) < 1e-3 ) {
1413 for (
int idx=0; idx<
layer_num; idx++ ) {
1418 std::string err =
"N_Qubit_Decomposition_adaptive::replace_trivial_adaptive_gates: Only block gates are accepted in this conversion.";
1443 if ( gate_tmp->
get_type() ==
ADAPTIVE_OPERATION && std::abs(std::sin(parameter)) > 0.999 && std::abs(std::cos(parameter)) < 1e-3) {
1451 CZ* cz_gate =
new CZ(
qbit_num, target_qbit, control_qbit);
1466 memcpy(parameters_new.get_data(), optimized_parameters.
get_data(), parameter_idx*
sizeof(double));
1468 memcpy(parameters_new.get_data()+parameter_idx+3, optimized_parameters.
get_data()+parameter_idx+1, (optimized_parameters.
size()-parameter_idx-1)*
sizeof(
double));
1471 parameters_new[parameter_idx+1] =
M_PI/4;
1474 if ( std::sin(parameter) < 0 ) {
1476 parameters_new[parameter_idx+2] = -
M_PI/4;
1479 global_phase_factor_new.
real = std::cos( -
M_PI/4 );
1480 global_phase_factor_new.
imag = std::sin( -
M_PI/4 );
1486 parameters_new[parameter_idx+2] =
M_PI/4;
1489 global_phase_factor_new.
real = std::cos(
M_PI/4 );
1490 global_phase_factor_new.
imag = std::sin(
M_PI/4 );
1496 optimized_parameters = parameters_new;
1503 else if ( gate_tmp->
get_type() ==
ADAPTIVE_OPERATION && std::abs(std::sin(parameter)) < 1e-3 && std::abs(1-std::cos(parameter)) < 1e-3 ) {
1509 memcpy(parameters_new.get_data(), optimized_parameters.
get_data(), parameter_idx*
sizeof(double));
1510 memcpy(parameters_new.get_data()+
parameter_idx, optimized_parameters.
get_data()+parameter_idx+1, (optimized_parameters.
size()-parameter_idx-1)*
sizeof(
double));
1511 optimized_parameters = parameters_new;
1537 memcpy(parameters_new.get_data(), optimized_parameters.
get_data(), parameter_idx*
sizeof(double));
1538 memcpy(parameters_new.get_data()+parameter_idx+2, optimized_parameters.
get_data()+parameter_idx+1, (optimized_parameters.
size()-parameter_idx-1)*
sizeof(
double));
1539 optimized_parameters = parameters_new;
1542 optimized_parameters[parameter_idx+1] = -parameter/2;
1572 return gate_structure_ret;
1593 for (
int idx=0; idx<
layer_num; idx++ ) {
1617 for(
size_t rdx=0; rdx<involved_qbits.size(); rdx++ ) {
1619 U3* U_gate_to_be_removed =
static_cast<U3*
>(layer->
get_gate(static_cast<int>(rdx)));
1622 int parameter_idx_loc = parameter_idx_to_be_removed + layer->
get_parameter_num();
1624 bool found_match =
false;
1625 U3* matching_gate = NULL;
1628 for (
int kdx=idx+1; kdx<
layer_num; kdx++ ) {
1634 for (
int hdx=0; hdx<gate_num; hdx++ ) {
1641 if ( qbit_to_be_matched == target_qbit_loc ) {
1643 matching_gate =
static_cast<U3*
>(gate_test);
1653 if ( found_match )
break;
1658 if ( found_match ==
false ) {
1660 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.");
1670 Matrix U3_prod =
dot(U3_matrix2, U3_matrix1);
1672 optimized_parameters_loc[parameter_idx_to_be_removed] = 0.0;
1673 optimized_parameters_loc[parameter_idx_to_be_removed+1] = 0.0;
1674 optimized_parameters_loc[parameter_idx_to_be_removed+2] = 0.0;
1675 parameter_idx_to_be_removed = parameter_idx_to_be_removed + U_gate_to_be_removed->
get_parameter_num();
1679 double ctheta3_over2 = std::sqrt(U3_prod[0].
real*U3_prod[0].
real+U3_prod[0].imag*U3_prod[0].imag);
1680 double stheta3_over2 = std::sqrt(U3_prod[2].
real*U3_prod[2].
real+U3_prod[2].imag*U3_prod[2].imag);
1681 double theta3_over2 = std::atan2(stheta3_over2,ctheta3_over2);
1683 double alpha = std::atan2(U3_prod[0].imag,U3_prod[0].
real);
1688 if (std::abs(stheta3_over2)<4e-8){
1689 lambda3 = (std::atan2(U3_prod[3].imag,U3_prod[3].real)-
alpha)/2;
1693 lambda3 = std::atan2(-1*U3_prod[1].imag,-1*U3_prod[1].real)-
alpha;
1694 phi3 = std::atan2(U3_prod[2].imag,U3_prod[2].real)-
alpha;
1700 global_phase_factor_new.
real = std::cos(alpha);
1701 global_phase_factor_new.
imag = std::sin(alpha);
1705 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) {
1709 param2[0] = theta3_over2;
1711 param2[2] = lambda3;
1723 std::stringstream sstream;
1724 sstream <<
"N_Qubit_Decomposition_adaptive::remove_trivial_gates: Removing trivial gateblock" << std::endl;
1729 int iteration_num_loc = 0;
1738 optimized_parameters = optimized_parameters_loc;
1739 delete( gate_structure_loc );
1740 gate_structure_loc = gate_structure_tmp;
1754 return gate_structure_loc;
1774 for (
int idx=0; idx<layer_idx; idx++) {
1784 Matrix_real reduced_parameters(1, optimized_parameters.
size() - param_num_removed );
1785 memcpy( reduced_parameters.get_data(), optimized_parameters.
get_data(), (
parameter_idx)*
sizeof(
double));
1786 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));
1789 return reduced_parameters;
1817 gate_structure->
combine( layer );
1833 std::stringstream sstream;
1838 std::vector<Gates_block* >
layers;
1844 if ( it->size() != 2 ) {
1845 std::string err(
"The connectivity data should contains two qubits.");
1849 int control_qbit_loc = (*it)[0];
1850 int target_qbit_loc = (*it)[1];
1853 std::string err(
"Label of control/target qubit should be less than the number of qubits in the register.");
1859 layer->
add_u3(target_qbit_loc);
1860 layer->
add_u3(control_qbit_loc);
1861 layer->
add_adaptive(target_qbit_loc, control_qbit_loc);
1863 layers.push_back(layer);
1871 for (
int target_qbit_loc = 0; target_qbit_loc<
qbit_num; target_qbit_loc++) {
1872 for (
int control_qbit_loc = target_qbit_loc+1; control_qbit_loc<
qbit_num; control_qbit_loc++) {
1876 layer->
add_u3(target_qbit_loc);
1877 layer->
add_u3(control_qbit_loc);
1878 layer->
add_adaptive(target_qbit_loc, control_qbit_loc);
1880 layers.push_back(layer);
1894 bool randomized_adaptive_layers_loc;
1895 if (
config.count(
"randomized_adaptive_layers") > 0 ) {
1896 config[
"randomized_adaptive_layers"].get_property( randomized_adaptive_layers_loc );
1904 if (randomized_adaptive_layers_loc) {
1906 std::uniform_int_distribution<> distrib_int(0, 5000);
1908 while (layers.size()>0) {
1909 int idx = distrib_int(
gen) % layers.size();
1912 MPI_Bcast( &idx, 1, MPI_INT, 0, MPI_COMM_WORLD);
1915 layers.erase( layers.begin() + idx );
1920 while (layers.size()>0) {
1922 layers.erase( layers.begin() );
1954 for (
int idx=0; idx<
qbit_num; idx++) {
1961 if ( gate_structure == NULL ) {
1962 throw (
"N_Qubit_Decomposition_adaptive::add_finalyzing_layer: gate_structure is null pointer");
1981 if (
gates.size() > 0 ) {
2004 upload_Umtx_to_DFE();
2023 upload_Umtx_to_DFE();
2038 upload_Umtx_to_DFE();
2056 if (
gates.size() > 0 ) {
2057 gate_structure_tmp->
combine( static_cast<Gates_block*>(
this) );
2060 combine( gate_structure_tmp );
2071 combine( gate_structure_tmp );
2085 if (
gates.size() == 0 ) {
2090 std::stringstream sstream;
2125 std::stringstream sstream;
2126 sstream <<
"Add new layer to the adaptive gate structure." << std::endl;
2135 memset( tmp.get_data(), 0, tmp.size()*
sizeof(double) );
2148 double ThetaOver2=0.;
2149 for (
int gate_idx=0; gate_idx<layer_gate_num; gate_idx++){
2153 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.
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...
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.
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.
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.
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