25 #include <tbb/enumerable_thread_specific.h> 149 for(std::vector<Gate*>::iterator it =
gates.begin(); it !=
gates.end(); ++it) {
170 if ( idx>= (
int)
gates.size() )
return;
212 std::stringstream sstream;
217 apply_to(parameters, block_mtx, parallel);
220 if (block_mtx.
isnan()) {
221 std::string err(
"Gates_block::get_matrix: block_mtx contains NaN." ) ;
241 apply_to(parameters, block_mtx, parallel);
251 template<
typename Params,
typename Input>
252 static void apply_to_list_impl(
Gates_block*
self, Params& parameters_mtx, std::vector<Input>& inputs,
int parallel) {
254 for (Input& input : inputs) {
255 self->apply_to(parameters_mtx, input, parallel);
261 tbb::parallel_for( tbb::blocked_range<int>(0, static_cast<int>(inputs.size()), work_batch),
262 [&](tbb::blocked_range<int> r) {
263 for (
int idx = r.begin(); idx < r.end(); ++idx) {
264 self->apply_to(parameters_mtx, inputs[idx], parallel);
270 const int parameter_count =
static_cast<int>(parameters.
size());
271 if (parameter_count <= 0) {
282 const int parameter_count =
static_cast<int>(parameters.
size());
283 if (parameter_count <= 0) {
294 if (mtx.
rows != matrix_size || mtx.
cols != matrix_size || mtx.
stride != matrix_size) {
295 mtx =
Matrix(matrix_size, matrix_size);
299 mtx[idx*mtx.
stride + idx].real = 1.0;
303 static void reset_identity(
Matrix_float& mtx,
int matrix_size) {
304 if (mtx.
rows != matrix_size || mtx.
cols != matrix_size || mtx.
stride != matrix_size) {
309 mtx[idx*mtx.
stride + idx].real = 1.0f;
313 struct BlockDerivativeWorkspace {
314 std::vector<Gate> suffix_gates;
315 std::vector<Matrix> suffix_matrices;
316 std::vector<Matrix> forward_inputs;
317 std::vector<std::vector<Matrix>> gate_gradients;
318 std::vector<int> suffix_targets;
322 struct BlockDerivativeWorkspaceFloat {
323 std::vector<Gate> suffix_gates;
324 std::vector<Matrix_float> suffix_matrices;
325 std::vector<Matrix_float> forward_inputs;
326 std::vector<std::vector<Matrix_float>> gate_gradients;
327 std::vector<int> suffix_targets;
331 static void prepare_suffix_gates(std::vector<Gate>& suffix_gates,
size_t gate_count,
int qbit_num) {
332 if (suffix_gates.size() == gate_count
333 && (suffix_gates.empty() || suffix_gates[0].get_qbit_num() ==
qbit_num)) {
337 suffix_gates.clear();
338 suffix_gates.reserve(gate_count);
339 for (
size_t idx = 0; idx < gate_count; ++idx) {
340 suffix_gates.emplace_back(qbit_num);
358 static bool should_use_suffix(
int qbit_num,
size_t gate_count,
int parameter_num) {
359 if (qbit_num <= 4)
return false;
360 if (qbit_num >= 7)
return true;
361 double m = (double)(1 << qbit_num);
362 return (
double)parameter_num * (double)gate_count > ((
double)gate_count + (double)parameter_num) * m;
365 static void prepare_all_qubits(std::vector<int>&
qubits,
int qbit_num) {
366 if (qubits.size() !=
static_cast<size_t>(
qbit_num)) {
367 qubits.resize(static_cast<size_t>(qbit_num));
369 for (
int idx = 0; idx <
qbit_num; ++idx) {
370 qubits[
static_cast<size_t>(idx)] = idx;
374 static void build_suffix_gates(
375 const std::vector<Gate*>&
gates,
380 std::vector<Gate>& suffix_gates,
381 std::vector<Matrix>& suffix_matrices,
382 std::vector<int>& targets,
385 prepare_suffix_gates(suffix_gates, gates.size(),
qbit_num);
386 suffix_matrices.resize(gates.size());
388 if (gates.size() < 2) {
392 prepare_all_qubits(targets, qbit_num);
393 reset_identity(suffix, matrix_size);
395 for (
int idx = static_cast<int>(gates.size()) - 1; idx >= 0; --idx) {
396 if (static_cast<size_t>(idx) + 1 < gates.size()) {
397 Matrix& suffix_after_current = suffix_matrices[
static_cast<size_t>(idx)];
398 suffix.
copy_to(suffix_after_current);
399 Gate& suffix_gate = suffix_gates[
static_cast<size_t>(idx)];
404 Gate* operation = gates[
static_cast<size_t>(idx)];
408 parameters_mtx_in.
get_data() + op_param_start_idx,
413 precomputed_sincos.
get_data() + 2 * op_param_start_idx,
430 static void build_forward_inputs(
431 const std::vector<Gate*>& gates,
436 std::vector<Matrix>& forward_inputs) {
438 forward_inputs.resize(gates.size());
443 input.
copy_to(forward_inputs[0]);
444 for (
size_t idx = 0; idx + 1 < gates.size(); ++idx) {
445 forward_inputs[idx].copy_to(forward_inputs[idx + 1]);
446 Gate* operation = gates[idx];
450 parameters_mtx_in.
get_data() + op_param_start_idx,
455 precomputed_sincos.
get_data() + 2 * op_param_start_idx,
460 if (op_param_num == 0) {
461 operation->
apply_to(forward_inputs[idx + 1], parallel);
464 operation->
apply_to(parameters_mtx, forward_inputs[idx + 1], parallel);
467 operation->
apply_to_inner(parameters_mtx, precomputed_sincos_loc, forward_inputs[idx + 1], parallel);
472 static void build_forward_inputs(
473 const std::vector<Gate*>& gates,
478 std::vector<Matrix_float>& forward_inputs) {
480 forward_inputs.resize(gates.size());
485 input.
copy_to(forward_inputs[0]);
486 for (
size_t idx = 0; idx + 1 < gates.size(); ++idx) {
487 forward_inputs[idx].copy_to(forward_inputs[idx + 1]);
488 Gate* operation = gates[idx];
492 parameters_mtx_in.
get_data() + op_param_start_idx,
497 precomputed_sincos.
get_data() + 2 * op_param_start_idx,
502 if (op_param_num == 0) {
503 operation->
apply_to(forward_inputs[idx + 1], parallel);
506 operation->
apply_to(parameters_mtx, forward_inputs[idx + 1], parallel);
509 operation->
apply_to_inner(parameters_mtx, precomputed_sincos_loc, forward_inputs[idx + 1], parallel);
514 static void build_suffix_gates(
515 const std::vector<Gate*>& gates,
520 std::vector<Gate>& suffix_gates,
521 std::vector<Matrix_float>& suffix_matrices,
522 std::vector<int>& targets,
525 prepare_suffix_gates(suffix_gates, gates.size(),
qbit_num);
526 suffix_matrices.resize(gates.size());
528 if (gates.size() < 2) {
532 prepare_all_qubits(targets, qbit_num);
533 reset_identity(suffix, matrix_size);
535 for (
int idx = static_cast<int>(gates.size()) - 1; idx >= 0; --idx) {
536 if (static_cast<size_t>(idx) + 1 < gates.size()) {
537 Matrix_float& suffix_after_current = suffix_matrices[
static_cast<size_t>(idx)];
538 suffix.
copy_to(suffix_after_current);
539 Gate& suffix_gate = suffix_gates[
static_cast<size_t>(idx)];
544 Gate* operation = gates[
static_cast<size_t>(idx)];
548 parameters_mtx_in.
get_data() + op_param_start_idx,
553 precomputed_sincos.
get_data() + 2 * op_param_start_idx,
580 apply_to_list_impl(
this, parameters_mtx, inputs, parallel);
594 apply_to_list_impl(
this, parameters_mtx, inputs, parallel);
608 Matrix_real precomputed_sincos = precompute_block_sincos(parameters_mtx_in);
609 apply_to_inner(parameters_mtx_in, precomputed_sincos, input, parallel);
621 std::string err(
"Gates_block::apply_to: Wrong input size in Gates_block gate apply.");
626 std::string err(
"Gates_block::apply_to: Number of qubits supported up to 31");
630 int size =
static_cast<int>(involved_qubits.size());
635 static tbb::enumerable_thread_specific<std::deque<Matrix>> Umtx_mini_reusable_tls([](){
return std::deque<Matrix>{}; });
636 std::deque<Matrix>& Umtx_mini_reusable = Umtx_mini_reusable_tls.local();
637 if (Umtx_mini_reusable.size() <=
static_cast<size_t>(fusion_depth)) {
638 Umtx_mini_reusable.resize(fusion_depth + 1);
640 Matrix& Umtx_mini = Umtx_mini_reusable[fusion_depth];
644 std::vector<int> old_to_new(
qbit_num, -2);
645 for (
int i = 0; i < size; i++){
646 old_to_new[i] = involved_qubits[i];
656 fb->apply_to_inner(parameters_mtx_in, precomputed_sincos_in, Umtx_mini, parallel);
659 static tbb::enumerable_thread_specific<std::deque<Gate>> merged_gate_reusable_tls([](){
return std::deque<Gate>{}; });
660 static tbb::enumerable_thread_specific<std::deque<int>> merged_gate_qbit_num_tls([](){
return std::deque<int>{}; });
661 std::deque<Gate>& merged_gate_reusable = merged_gate_reusable_tls.local();
662 std::deque<int>& merged_gate_qbit_num = merged_gate_qbit_num_tls.local();
663 if (merged_gate_reusable.size() <=
static_cast<size_t>(fusion_depth)) {
664 merged_gate_reusable.resize(fusion_depth + 1);
665 merged_gate_qbit_num.resize(fusion_depth + 1, -1);
667 Gate& merged_gate = merged_gate_reusable[fusion_depth];
668 int& merged_gate_qbits = merged_gate_qbit_num[fusion_depth];
669 if (merged_gate_qbits !=
qbit_num) {
677 int fused_parallel = parallel;
678 if (parallel != 0 && size <= 5 && qbit_num >= 14) {
681 merged_gate.
apply_to(input, fused_parallel);
683 for(
size_t idx=0; idx<
gates.size(); idx++) {
688 Matrix_real parameters_mtx_loc(parameters_mtx_in.
get_data() + op_param_start_idx, 1, op_param_num);
689 Matrix_real precomputed_sincos_loc(precomputed_sincos_in.
get_data() + 2 * op_param_start_idx, op_param_num, 2);
692 operation->
apply_to(input, parallel);
696 operation->
apply_to(parameters_mtx_loc, input, parallel);
699 operation->
apply_to_inner(parameters_mtx_loc, precomputed_sincos_loc, input, parallel);
704 std::string err(
"Gates_block::apply_to: transformed matrix contains NaN." );
717 apply_to(parameters_empty, input, parallel);
724 Matrix_real_float precomputed_sincos = precompute_block_sincos(parameters_mtx_in);
725 apply_to_inner(parameters_mtx_in, precomputed_sincos, input, parallel);
735 std::string err(
"Gates_block::apply_to(Matrix_real_float&, Matrix_float&): Wrong input size in Gates_block gate apply.");
740 std::string err(
"Gates_block::apply_to(Matrix_real_float&, Matrix_float&): Number of qubits supported up to 31");
744 int size =
static_cast<int>(involved_qubits.size());
749 static tbb::enumerable_thread_specific<std::deque<Matrix_float>> Umtx_mini_reusable_tls([](){
return std::deque<Matrix_float>{}; });
750 std::deque<Matrix_float>& Umtx_mini_reusable = Umtx_mini_reusable_tls.local();
751 if (Umtx_mini_reusable.size() <=
static_cast<size_t>(fusion_depth)) {
752 Umtx_mini_reusable.resize(fusion_depth + 1);
754 Matrix_float& Umtx_mini = Umtx_mini_reusable[fusion_depth];
758 std::vector<int> old_to_new(
qbit_num, -2);
759 for (
int i = 0; i < size; i++) {
760 old_to_new[i] = involved_qubits[i];
770 fb->apply_to_inner(parameters_mtx_in, precomputed_sincos_in, Umtx_mini, parallel);
773 static tbb::enumerable_thread_specific<std::deque<Gate>> merged_gate_reusable_tls([](){
return std::deque<Gate>{}; });
774 static tbb::enumerable_thread_specific<std::deque<int>> merged_gate_qbit_num_tls([](){
return std::deque<int>{}; });
775 std::deque<Gate>& merged_gate_reusable = merged_gate_reusable_tls.local();
776 std::deque<int>& merged_gate_qbit_num = merged_gate_qbit_num_tls.local();
777 if (merged_gate_reusable.size() <=
static_cast<size_t>(fusion_depth)) {
778 merged_gate_reusable.resize(fusion_depth + 1);
779 merged_gate_qbit_num.resize(fusion_depth + 1, -1);
781 Gate& merged_gate = merged_gate_reusable[fusion_depth];
782 int& merged_gate_qbits = merged_gate_qbit_num[fusion_depth];
783 if (merged_gate_qbits !=
qbit_num) {
791 int fused_parallel = parallel;
792 if (parallel != 0 && size <= 5 && qbit_num >= 14) {
795 merged_gate.
apply_to(input, fused_parallel);
798 for (
size_t idx = 0; idx <
gates.size(); idx++) {
804 parameters_mtx_in.
get_data() + op_param_start_idx,
810 precomputed_sincos_in.
get_data() + 2 * op_param_start_idx,
816 operation->
apply_to(input, parallel);
820 operation->
apply_to(parameters_mtx_loc, input, parallel);
823 operation->
apply_to_inner(parameters_mtx_loc, precomputed_sincos_loc, input, parallel);
828 std::string err(
"Gates_block::apply_to(Matrix_real_float&, Matrix_float&): transformed matrix contains NaN.");
850 std::string err(
"Gates_block::apply_to(Matrix_real_any&, Matrix_any&): precision mismatch between parameters and input");
864 bool is_qbit_present(std::vector<int> involved_qubits,
int new_qbit,
int num_of_qbits){
866 bool contained=
false;
868 for (
int idx=0; idx<num_of_qbits; idx++) {
870 if(involved_qubits[idx] == new_qbit) {
887 Matrix_real precomputed_sincos = precompute_block_sincos(parameters_mtx);
895 for (
int idx = static_cast<int>(
gates.size()) - 1; idx >= 0; --idx) {
902 parameters_mtx.
get_data() + op_param_start_idx,
907 precomputed_sincos.
get_data() + 2 * op_param_start_idx,
926 std::string err(
"Gates_block::apply_from_right: transformed matrix contains NaN." );
949 for (
int idx = static_cast<int>(
gates.size()) - 1; idx >= 0; --idx) {
956 parameters_mtx.
get_data() + op_param_start_idx,
962 precomputed_sincos.
get_data() + 2 * op_param_start_idx,
981 std::string err(
"Gates_block::apply_from_right(Matrix_real_float&, Matrix_float&): transformed matrix contains NaN.");
998 std::vector<Matrix> grad;
1014 const size_t output_size = output_offset +
static_cast<size_t>(
parameter_num);
1015 if (resize_output) {
1016 output.resize(output_size);
1018 else if (output.size() < output_size) {
1019 std::string err(
"Gates_block::apply_derivate_to: output vector is too small.");
1023 Matrix_real precomputed_sincos = precompute_block_sincos(parameters_mtx_in);
1024 static tbb::enumerable_thread_specific<std::deque<BlockDerivativeWorkspace>> workspace_tls;
1025 std::deque<BlockDerivativeWorkspace>& workspaces = workspace_tls.local();
1027 if (workspaces.size() <=
static_cast<size_t>(workspace_depth)) {
1028 workspaces.resize(static_cast<size_t>(workspace_depth) + 1);
1030 BlockDerivativeWorkspace& workspace = workspaces[
static_cast<size_t>(workspace_depth)];
1031 std::vector<Gate>& suffix_gates = workspace.suffix_gates;
1032 std::vector<Matrix>& suffix_matrices = workspace.suffix_matrices;
1033 std::vector<Matrix>& forward_inputs = workspace.forward_inputs;
1034 forward_inputs.resize(
gates.size());
1035 workspace.gate_gradients.resize(
gates.size());
1039 if (parallel == 0 ||
gates.size() < 2) {
1041 build_suffix_gates(
gates,
qbit_num,
matrix_size, parameters_mtx_in, precomputed_sincos, suffix_gates, suffix_matrices, workspace.suffix_targets, workspace.suffix);
1043 build_forward_inputs(
gates, input, parameters_mtx_in, precomputed_sincos, parallel, forward_inputs);
1047 tbb::parallel_invoke(
1049 build_suffix_gates(
gates,
qbit_num,
matrix_size, parameters_mtx_in, precomputed_sincos, suffix_gates, suffix_matrices, workspace.suffix_targets, workspace.suffix);
1052 build_forward_inputs(
gates, input, parameters_mtx_in, precomputed_sincos, parallel, forward_inputs);
1056 build_forward_inputs(
gates, input, parameters_mtx_in, precomputed_sincos, parallel, forward_inputs);
1060 auto apply_derivative_for_gate = [&](
size_t deriv_idx) {
1071 static tbb::enumerable_thread_specific<std::deque<Matrix>> input_loc_reusable_tls([](){
return std::deque<Matrix>{}; });
1072 std::deque<Matrix>& input_loc_reusable = input_loc_reusable_tls.local();
1073 if (input_loc_reusable.size() <=
static_cast<size_t>(derivative_depth)) {
1074 input_loc_reusable.resize(derivative_depth + 1);
1076 Matrix& input_loc = input_loc_reusable[derivative_depth];
1077 forward_inputs[deriv_idx].
copy_to(input_loc);
1083 Matrix_real parameters_mtx(parameters_mtx_in.
get_data() + op_param_start_idx, 1, op_param_num);
1084 std::vector<Matrix>& grad_loc = workspace.gate_gradients[deriv_idx];
1093 if (deriv_idx + 1 <
gates.size()) {
1095 Gate& suffix_gate = suffix_gates[deriv_idx];
1096 if (parallel == 0) {
1100 tbb::parallel_for(tbb::blocked_range<int>(0, static_cast<int>(grad_loc.size()), 1),
1101 [&](tbb::blocked_range<int> r) {
1102 for (
int grad_idx = r.begin(); grad_idx < r.end(); ++grad_idx) {
1103 suffix_gate.
apply_to(grad_loc[static_cast<size_t>(grad_idx)], parallel);
1109 for (
size_t g = deriv_idx + 1; g <
gates.size(); ++g) {
1114 for (
auto& m : grad_loc) op->
apply_to(m, parallel);
1119 for (
auto& m : grad_loc) op->
apply_to(pm, m, parallel);
1121 for (
auto& m : grad_loc) op->
apply_to_inner(pm, psc, m, parallel);
1130 for (
int idx = 0; idx<(
int)grad_loc.size(); idx++ ) {
1131 grad_loc[idx].copy_to(output[output_offset + static_cast<size_t>(deriv_parameter_idx + idx)]);
1135 if (parallel == 0) {
1136 for (
size_t deriv_idx=0; deriv_idx<
gates.size(); ++deriv_idx) {
1137 apply_derivative_for_gate(deriv_idx);
1143 tbb::parallel_for( tbb::blocked_range<size_t>(0,
gates.size(),work_batch), [&](tbb::blocked_range<size_t> r) {
1144 for (
size_t deriv_idx=r.begin(); deriv_idx<r.end(); ++deriv_idx) {
1145 apply_derivative_for_gate(deriv_idx);
1161 std::vector<Matrix_float>
1164 std::vector<Matrix_float> grad;
1180 const size_t output_size = output_offset +
static_cast<size_t>(
parameter_num);
1181 if (resize_output) {
1182 output.resize(output_size);
1184 else if (output.size() < output_size) {
1185 std::string err(
"Gates_block::apply_derivate_to(Matrix_real_float): output vector is too small.");
1189 Matrix_real_float precomputed_sincos = precompute_block_sincos(parameters_mtx_in);
1190 static tbb::enumerable_thread_specific<std::deque<BlockDerivativeWorkspaceFloat>> workspace_tls;
1191 std::deque<BlockDerivativeWorkspaceFloat>& workspaces = workspace_tls.local();
1193 if (workspaces.size() <=
static_cast<size_t>(workspace_depth)) {
1194 workspaces.resize(static_cast<size_t>(workspace_depth) + 1);
1196 BlockDerivativeWorkspaceFloat& workspace = workspaces[
static_cast<size_t>(workspace_depth)];
1197 std::vector<Gate>& suffix_gates = workspace.suffix_gates;
1198 std::vector<Matrix_float>& suffix_matrices = workspace.suffix_matrices;
1199 std::vector<Matrix_float>& forward_inputs = workspace.forward_inputs;
1200 forward_inputs.resize(
gates.size());
1201 workspace.gate_gradients.resize(
gates.size());
1205 if (parallel == 0 ||
gates.size() < 2) {
1207 build_suffix_gates(
gates,
qbit_num,
matrix_size, parameters_mtx_in, precomputed_sincos, suffix_gates, suffix_matrices, workspace.suffix_targets, workspace.suffix);
1209 build_forward_inputs(
gates, input, parameters_mtx_in, precomputed_sincos, parallel, forward_inputs);
1213 tbb::parallel_invoke(
1215 build_suffix_gates(
gates,
qbit_num,
matrix_size, parameters_mtx_in, precomputed_sincos, suffix_gates, suffix_matrices, workspace.suffix_targets, workspace.suffix);
1218 build_forward_inputs(
gates, input, parameters_mtx_in, precomputed_sincos, parallel, forward_inputs);
1222 build_forward_inputs(
gates, input, parameters_mtx_in, precomputed_sincos, parallel, forward_inputs);
1226 auto apply_derivative_for_gate = [&](
size_t deriv_idx) {
1237 static tbb::enumerable_thread_specific<std::deque<Matrix_float>> input_loc_reusable_tls([](){
return std::deque<Matrix_float>{}; });
1238 std::deque<Matrix_float>& input_loc_reusable = input_loc_reusable_tls.local();
1239 if (input_loc_reusable.size() <=
static_cast<size_t>(derivative_depth)) {
1240 input_loc_reusable.resize(derivative_depth + 1);
1242 Matrix_float& input_loc = input_loc_reusable[derivative_depth];
1243 forward_inputs[deriv_idx].
copy_to(input_loc);
1250 std::vector<Matrix_float>& grad_loc = workspace.gate_gradients[deriv_idx];
1259 if (deriv_idx + 1 <
gates.size()) {
1261 Gate& suffix_gate = suffix_gates[deriv_idx];
1262 if (parallel == 0) {
1266 tbb::parallel_for(tbb::blocked_range<int>(0, static_cast<int>(grad_loc.size()), 1),
1267 [&](tbb::blocked_range<int> r) {
1268 for (
int grad_idx = r.begin(); grad_idx < r.end(); ++grad_idx) {
1269 suffix_gate.
apply_to(grad_loc[static_cast<size_t>(grad_idx)], parallel);
1275 for (
size_t g = deriv_idx + 1; g <
gates.size(); ++g) {
1280 for (
auto& m : grad_loc) op->
apply_to(m, parallel);
1285 for (
auto& m : grad_loc) op->
apply_to(pm, m, parallel);
1287 for (
auto& m : grad_loc) op->
apply_to_inner(pm, psc, m, parallel);
1296 for (
int idx = 0; idx<(
int)grad_loc.size(); idx++ ) {
1297 grad_loc[idx].copy_to(output[output_offset + static_cast<size_t>(deriv_parameter_idx + idx)]);
1301 if (parallel == 0) {
1302 for (
size_t deriv_idx=0; deriv_idx<
gates.size(); ++deriv_idx) {
1303 apply_derivative_for_gate(deriv_idx);
1309 tbb::parallel_for( tbb::blocked_range<size_t>(0,
gates.size(),work_batch), [&](tbb::blocked_range<size_t> r) {
1310 for (
size_t deriv_idx=r.begin(); deriv_idx<r.end(); ++deriv_idx) {
1311 apply_derivative_for_gate(deriv_idx);
1322 Matrix_real precomputed_sincos = precompute_block_sincos(parameters_mtx_in);
1330 Matrix_real precomputed_sincos = precompute_block_sincos(parameters_mtx_in);
1338 std::vector<Matrix> ret;
1348 if (parallel == 0) {
1350 apply_to_inner(parameters_mtx_in, precomputed_sincos, output[0], parallel);
1354 tbb::parallel_invoke(
1357 apply_to_inner(parameters_mtx_in, precomputed_sincos, output[0], parallel);
1367 std::vector<Matrix_float>
1370 Matrix_real_float precomputed_sincos = precompute_block_sincos(parameters_mtx_in);
1378 Matrix_real_float precomputed_sincos = precompute_block_sincos(parameters_mtx_in);
1383 std::vector<Matrix_float>
1386 std::vector<Matrix_float> ret;
1396 if (parallel == 0) {
1398 apply_to_inner(parameters_mtx_in, precomputed_sincos, output[0], parallel);
1402 tbb::parallel_invoke(
1405 apply_to_inner(parameters_mtx_in, precomputed_sincos, output[0], parallel);
2413 for(std::vector<Gate*>::iterator it = gates_in.begin(); it != gates_in.end(); ++it) {
2427 for(std::vector<Gate*>::iterator it = gates_in.end(); it != gates_in.begin(); --it) {
2473 const Matrix& operation_mtx,
2479 std::string err(
"Gates_block::add_general_operation: operation matrix has invalid size.");
2485 if (!target_qbits.empty()) {
2488 if (!control_qbits.empty()) {
2511 gates.push_back(gate);
2600 for(std::vector<Gate*>::iterator it =
gates.begin(); it !=
gates.end(); ++it) {
2611 std::string gate_name = gate->
get_name();
2613 if( gate_nums.find(gate_name) == gate_nums.end() ) {
2614 gate_nums[ gate_name ] = 1;
2617 gate_nums[ gate_name ] = gate_nums[ gate_name ] + 1;
2632 std::map<std::string, int> gate_nums;
2657 return static_cast<int>(
gates.size());
2670 std::stringstream sstream;
2671 sstream << std::endl <<
"The gates in the list of gates:" << std::endl;
2674 int gate_idx = start_index;
2676 double *parameters_data = parameters.
get_data();
2680 for(
size_t op_idx = 0; op_idx<
gates.size(); op_idx++) {
2685 CNOT* cnot_gate =
static_cast<CNOT*
>(gate);
2686 std::stringstream sstream;
2687 sstream << gate_idx <<
"th gate: CNOT with control qubit: " << cnot_gate->
get_control_qbit() <<
" and target qubit: " << cnot_gate->
get_target_qbit() << std::endl;
2689 gate_idx = gate_idx + 1;
2692 CROT* crot_gate =
static_cast<CROT*
>(gate);
2693 std::stringstream sstream;
2695 theta0 = std::fmod( 2*parameters_data[parameter_idx], 4*
M_PI);
2696 phi0 = std::fmod( parameters_data[parameter_idx+1], 2*
M_PI);
2697 parameter_idx = parameter_idx + 2;
2698 sstream << gate_idx <<
"th gate: CROT with control qubit: " << crot_gate->
get_control_qbit() <<
" and target qubit: " << crot_gate->
get_target_qbit()<<
" and parameters theta=" << theta0 <<
" and phi="<< phi0 << std::endl;
2700 gate_idx = gate_idx + 1;
2703 CZ* cz_gate =
static_cast<CZ*
>(gate);
2704 std::stringstream sstream;
2705 sstream << gate_idx <<
"th gate: CZ with control qubit: " << cz_gate->
get_control_qbit() <<
" and target qubit: " << cz_gate->
get_target_qbit() << std::endl;
2707 gate_idx = gate_idx + 1;
2710 CH* ch_gate =
static_cast<CH*
>(gate);
2711 std::stringstream sstream;
2712 sstream << gate_idx <<
"th gate: CH with control qubit: " << ch_gate->
get_control_qbit() <<
" and target qubit: " << ch_gate->
get_target_qbit() << std::endl;
2714 gate_idx = gate_idx + 1;
2717 SYC* syc_gate =
static_cast<SYC*
>(gate);
2718 std::stringstream sstream;
2719 sstream << gate_idx <<
"th gate: Sycamore gate with control qubit: " << syc_gate->
get_control_qbit() <<
" and target qubit: " << syc_gate->
get_target_qbit() << std::endl;
2721 gate_idx = gate_idx + 1;
2724 U1* u1_gate =
static_cast<U1*
>(gate);
2725 double lambda = std::fmod(parameters_data[parameter_idx], 2*
M_PI);
2726 parameter_idx = parameter_idx + 1;
2727 std::stringstream sstream;
2728 sstream << gate_idx <<
"th gate: U1 on target qubit: " << u1_gate->
get_target_qbit() <<
" with parameter lambda = " << lambda << std::endl;
2730 gate_idx = gate_idx + 1;
2733 U2* u2_gate =
static_cast<U2*
>(gate);
2734 double phi = std::fmod(parameters_data[parameter_idx], 2*
M_PI);
2735 double lambda = std::fmod(parameters_data[parameter_idx+1], 2*
M_PI);
2736 parameter_idx = parameter_idx + 2;
2737 std::stringstream sstream;
2738 sstream << gate_idx <<
"th gate: U2 on target qubit: " << u2_gate->
get_target_qbit() <<
" with parameters phi = " << phi <<
" and lambda = " << lambda << std::endl;
2740 gate_idx = gate_idx + 1;
2743 U3* u3_gate =
static_cast<U3*
>(gate);
2744 double theta = std::fmod(parameters_data[parameter_idx], 4*
M_PI);
2745 double phi = std::fmod(parameters_data[parameter_idx+1], 2*
M_PI);
2746 double lambda = std::fmod(parameters_data[parameter_idx+2], 2*
M_PI);
2747 parameter_idx = parameter_idx + 3;
2748 std::stringstream sstream;
2749 sstream << gate_idx <<
"th gate: U3 on target qubit: " << u3_gate->
get_target_qbit() <<
" with parameters theta = " << theta <<
", phi = " << phi <<
" and lambda = " << lambda << std::endl;
2751 gate_idx = gate_idx + 1;
2755 double vartheta,varphi;
2757 R* r_gate =
static_cast<R*
>(gate);
2758 vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*
M_PI);
2759 varphi = std::fmod( parameters_data[parameter_idx+1], 2*
M_PI);
2760 parameter_idx = parameter_idx + 2;
2762 std::stringstream sstream;
2763 sstream << gate_idx <<
"th gate: R on target qubit: " << r_gate->
get_target_qbit() <<
" and with parameters theta = " << vartheta <<
" and phi:" << varphi << std::endl;
2765 gate_idx = gate_idx + 1;
2771 RX* rx_gate =
static_cast<RX*
>(gate);
2772 vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*
M_PI);
2773 parameter_idx = parameter_idx + 1;
2775 std::stringstream sstream;
2776 sstream << gate_idx <<
"th gate: RX on target qubit: " << rx_gate->
get_target_qbit() <<
" and with parameters theta = " << vartheta << std::endl;
2778 gate_idx = gate_idx + 1;
2784 RXX* rxx_gate =
static_cast<RXX*
>(gate);
2785 vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*
M_PI);
2786 parameter_idx = parameter_idx + 1;
2788 std::stringstream sstream;
2789 sstream << gate_idx <<
"th gate: RXX on target qubits: " << involved_qbits[0] <<
" and " << involved_qbits[1] <<
" and with parameters theta = " << vartheta << std::endl;
2791 gate_idx = gate_idx + 1;
2797 RYY* ryy_gate =
static_cast<RYY*
>(gate);
2798 vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*
M_PI);
2799 parameter_idx = parameter_idx + 1;
2801 std::stringstream sstream;
2802 sstream << gate_idx <<
"th gate: RYY on target qubits: " << involved_qbits[0] <<
" and " << involved_qbits[1] <<
" and with parameters theta = " << vartheta << std::endl;
2804 gate_idx = gate_idx + 1;
2810 RZZ* rzz_gate =
static_cast<RZZ*
>(gate);
2811 vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*
M_PI);
2812 parameter_idx = parameter_idx + 1;
2814 std::stringstream sstream;
2815 sstream << gate_idx <<
"th gate: RZZ on target qubits: " << involved_qbits[0] <<
" and " << involved_qbits[1] <<
" and with parameters theta = " << vartheta << std::endl;
2817 gate_idx = gate_idx + 1;
2823 RY* ry_gate =
static_cast<RY*
>(gate);
2824 vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*
M_PI);
2825 parameter_idx = parameter_idx + 1;
2827 std::stringstream sstream;
2828 sstream << gate_idx <<
"th gate: RY on target qubit: " << ry_gate->
get_target_qbit() <<
" and with parameters theta = " << vartheta << std::endl;
2830 gate_idx = gate_idx + 1;
2836 CRY* cry_gate =
static_cast<CRY*
>(gate);
2837 vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*
M_PI);
2838 parameter_idx = parameter_idx + 1;
2840 std::stringstream sstream;
2841 sstream << gate_idx <<
"th gate: CRY on target qubit: " << cry_gate->
get_target_qbit() <<
", control qubit" << cry_gate->
get_control_qbit() <<
" and with parameters theta = " << vartheta << std::endl;
2843 gate_idx = gate_idx + 1;
2849 CRX* crx_gate =
static_cast<CRX*
>(gate);
2850 vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*
M_PI);
2851 parameter_idx = parameter_idx + 1;
2853 std::stringstream sstream;
2854 sstream << gate_idx <<
"th gate: CRX on target qubit: " << crx_gate->
get_target_qbit() <<
", control qubit" << crx_gate->
get_control_qbit() <<
" and with parameters theta = " << vartheta << std::endl;
2856 gate_idx = gate_idx + 1;
2862 CRZ* crz_gate =
static_cast<CRZ*
>(gate);
2863 vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*
M_PI);
2864 parameter_idx = parameter_idx + 1;
2866 std::stringstream sstream;
2867 sstream << gate_idx <<
"th gate: CRZ on target qubit: " << crz_gate->
get_target_qbit() <<
", control qubit" << crz_gate->
get_control_qbit() <<
" and with parameters theta = " << vartheta << std::endl;
2869 gate_idx = gate_idx + 1;
2875 CP* cp_gate =
static_cast<CP*
>(gate);
2876 lambda = std::fmod( parameters_data[parameter_idx], 2*
M_PI);
2877 parameter_idx = parameter_idx + 1;
2879 std::stringstream sstream;
2880 sstream << gate_idx <<
"th gate: CP on target qubit: " << cp_gate->
get_target_qbit() <<
", control qubit" << cp_gate->
get_control_qbit() <<
" and with parameters lambda = " << lambda << std::endl;
2882 gate_idx = gate_idx + 1;
2886 double vartheta,varphi;
2888 CR* cr_gate =
static_cast<CR*
>(gate);
2889 vartheta = std::fmod( 2*parameters_data[parameter_idx], 4*
M_PI);
2890 varphi = std::fmod(parameters_data[parameter_idx+1],2*
M_PI);
2891 parameter_idx = parameter_idx + 2;
2893 std::stringstream sstream;
2894 sstream << gate_idx <<
"th gate: CR on target qubit: " << cr_gate->
get_target_qbit() <<
", control qubit" << cr_gate->
get_control_qbit() <<
" and with parameters theta and phi = " << vartheta <<
" , " << varphi << std::endl;
2896 gate_idx = gate_idx + 1;
2902 RZ* rz_gate =
static_cast<RZ*
>(gate);
2903 varphi = std::fmod( 2*parameters_data[parameter_idx], 2*
M_PI);
2904 parameter_idx = parameter_idx + 1;
2906 std::stringstream sstream;
2907 sstream << gate_idx <<
"th gate: RZ on target qubit: " << rz_gate->
get_target_qbit() <<
" and with parameters varphi = " << varphi << std::endl;
2909 gate_idx = gate_idx + 1;
2913 H* h_gate =
static_cast<H*
>(gate);
2914 std::stringstream sstream;
2915 sstream << gate_idx <<
"th gate: Hadamard on target qubit: " << h_gate->
get_target_qbit() << std::endl;
2917 gate_idx = gate_idx + 1;
2921 X* x_gate =
static_cast<X*
>(gate);
2922 std::stringstream sstream;
2923 sstream << gate_idx <<
"th gate: X on target qubit: " << x_gate->
get_target_qbit() << std::endl;
2925 gate_idx = gate_idx + 1;
2929 Y* y_gate =
static_cast<Y*
>(gate);
2930 std::stringstream sstream;
2931 sstream << gate_idx <<
"th gate: Y on target qubit: " << y_gate->
get_target_qbit() << std::endl;
2933 gate_idx = gate_idx + 1;
2937 Z* z_gate =
static_cast<Z*
>(gate);
2938 std::stringstream sstream;
2939 sstream << gate_idx <<
"th gate: Z on target qubit: " << z_gate->
get_target_qbit() << std::endl;
2941 gate_idx = gate_idx + 1;
2945 S* s_gate =
static_cast<S*
>(gate);
2946 std::stringstream sstream;
2947 sstream << gate_idx <<
"th gate: S on target qubit: " << s_gate->
get_target_qbit() << std::endl;
2949 gate_idx = gate_idx + 1;
2953 SDG* sdg_gate =
static_cast<SDG*
>(gate);
2954 std::stringstream sstream;
2955 sstream << gate_idx <<
"th gate: Sdg on target qubit: " << sdg_gate->
get_target_qbit() << std::endl;
2957 gate_idx = gate_idx + 1;
2961 SX* sx_gate =
static_cast<SX*
>(gate);
2963 std::stringstream sstream;
2964 sstream << gate_idx <<
"th gate: SX on target qubit: " << sx_gate->
get_target_qbit() << std::endl;
2966 gate_idx = gate_idx + 1;
2970 SXdg* sxdg_gate =
static_cast<SXdg*
>(gate);
2972 std::stringstream sstream;
2973 sstream << gate_idx <<
"th gate: SXdg on target qubit: " << sxdg_gate->
get_target_qbit() << std::endl;
2975 gate_idx = gate_idx + 1;
2980 block_gate->
list_gates( parameters_layer, gate_idx );
2989 Theta = std::fmod( 2*parameters_data[parameter_idx], 4*
M_PI);
2990 parameter_idx = parameter_idx + 1;
2992 std::stringstream sstream;
2993 sstream << gate_idx <<
"th gate: Adaptive gate on target qubit: " << ad_gate->
get_target_qbit() <<
", control qubit " << ad_gate->
get_control_qbit() <<
" and with parameters Theta = " << Theta << std::endl;
2995 gate_idx = gate_idx + 1;
2998 std::string err(
"Gates_block::list_gates: unimplemented gate");
3032 for(std::vector<Gate*>::iterator it =
gates.begin(); it !=
gates.end(); ++it) {
3064 if (!target_qbits.empty()) {
3066 std::vector<int> remapped_targets;
3068 if (qbit_map.find(
target_qbit) != qbit_map.end()) {
3069 remapped_targets.push_back(qbit_map.at(
target_qbit));
3071 std::string err(
"Gates_block::create_remapped_circuit: Missing target qubit from the qbit map.");
3079 if (target_qbit != -1) {
3080 if (qbit_map.find(target_qbit) != qbit_map.end()) {
3083 std::string err(
"Gates_block::create_remapped_circuit: Missing target qubit from the qbit map.");
3091 if (!control_qbits.empty()) {
3093 std::vector<int> remapped_controls;
3096 remapped_controls.push_back(qbit_map.at(
control_qbit));
3098 std::string err(
"Gates_block::create_remapped_circuit: Missing control qubit from the qbit map.");
3106 if (control_qbit != -1) {
3107 if (qbit_map.find(control_qbit) != qbit_map.end()) {
3110 std::string err(
"Gates_block::create_remapped_circuit: Missing control qubit from the qbit map.");
3126 std::string err(
"Gates_block::create_remapped_circuit: unimplemented gate");
3142 for(std::vector<Gate*>::iterator it =
gates.begin(); it !=
gates.end(); ++it) {
3170 std::vector<int> involved_qbits;
3173 for(std::vector<Gate*>::iterator it =
gates.begin(); it !=
gates.end(); ++it) {
3180 for (std::vector<int>::iterator in_it = gate_qbits.begin(); in_it != gate_qbits.end(); ++in_it){
3181 const int qbit = *in_it;
3185 if (qbit >= static_cast<int>(seen.size())) {
3186 if (std::find(involved_qbits.begin(), involved_qbits.end(), qbit) == involved_qbits.end()) {
3187 involved_qbits.push_back(qbit);
3190 else if (!seen[qbit]) {
3192 involved_qbits.push_back(qbit);
3198 std::sort(involved_qbits.begin(), involved_qbits.end());
3212 return involved_qbits;
3231 if (idx > (
int)
gates.size() ) {
3246 std::vector<Gate*> gates_in = op_block->
get_gates();
3250 std::string err(
"Gates_block::combine: number of qubits in the circuits must be the same");
3254 for(std::vector<Gate*>::iterator it = (gates_in).begin(); it != (gates_in).end(); ++it) {
3267 for (
size_t i = 0; i <
gates.size(); i++){
3284 for(std::vector<Gate*>::iterator it =
gates.begin(); it !=
gates.end(); ++it) {
3309 std::string err(
"Gates_block::set_qbit_num: unimplemented gate");
3332 std::string err(
"Gates_block::clone(): extracting gates was not succesfull");
3350 for ( std::vector<Gate*>::iterator it=
gates.begin(); it !=
gates.end(); ++it ) {
3378 std::string err(
"Gates_block::extract_gates: unimplemented gate");
3396 for ( std::vector<Gate*>::iterator it=
gates.begin(); it !=
gates.end(); ++it ) {
3405 if ( ret )
return true;
3451 if (input_state.
cols != 1) {
3452 std::string error(
"Gates_block::get_reduced_density_matrix: The number of columns in input state should be 1");
3458 std::string error(
"Gates_block::get_reduced_density_matrix: The number of rows in input state should be 2^qbit_num");
3464 if ( parameters_mtx.
size() > 0 ) {
3465 bool parallel =
true;
3466 apply_to( parameters_mtx, transformed_state, parallel );
3470 int subset_qbit_num = qbit_list_subset.
size();
3471 int complementary_qbit_num =
qbit_num - subset_qbit_num;
3476 int qbit_idx_count = 0;
3477 for (
int qbit_idx=0; qbit_idx<
qbit_num; qbit_idx++) {
3479 bool qbit_idx_in_subset =
false;
3481 for (
int subset_qbit_idx=0; subset_qbit_idx<subset_qbit_num; subset_qbit_idx++) {
3482 if ( qbit_idx == qbit_list_subset[subset_qbit_idx] ) {
3483 qbit_idx_in_subset =
true;
3489 if ( qbit_idx_in_subset ) {
3493 qbit_list_complementary[qbit_idx_count] = qbit_idx;
3500 for (
int qbit_idx=0; qbit_idx<
qbit_num; qbit_idx++) {
3501 qbit_masks[ qbit_idx ] = 1 << qbit_idx;
3507 int rho_matrix_size = 1 << subset_qbit_num;
3509 Matrix rho(rho_matrix_size, rho_matrix_size);
3515 int complementary_basis_num = 1 << complementary_qbit_num;
3516 for (
int row_idx=0; row_idx<rho_matrix_size; row_idx++ ) {
3520 for (
int qbit_idx=0; qbit_idx<subset_qbit_num; qbit_idx++) {
3521 if ( row_idx & qbit_masks[ qbit_idx ] ) {
3522 idx = idx | qbit_masks[ qbit_list_subset[qbit_idx] ];
3526 for (
int col_idx=row_idx; col_idx<rho_matrix_size; col_idx++ ) {
3530 for (
int qbit_idx=0; qbit_idx<subset_qbit_num; qbit_idx++) {
3531 if ( col_idx & qbit_masks[ qbit_idx ] ) {
3532 jdx = jdx | qbit_masks[ qbit_list_subset[qbit_idx] ];
3538 tbb::combinable<QGD_Complex16> priv_addend {[](){
QGD_Complex16 ret; ret.
real = 0.0; ret.
imag = 0.0;
return ret;}};
3541 tbb::parallel_for( tbb::blocked_range<int>(0, complementary_basis_num, 1024), [&](tbb::blocked_range<int> r) {
3545 for (
int compl_idx=r.begin(); compl_idx<r.end(); compl_idx++) {
3551 for (
int qbit_idx=0; qbit_idx<complementary_qbit_num; qbit_idx++) {
3552 if ( compl_idx & qbit_masks[ qbit_idx ] ) {
3553 idx_loc = idx_loc | qbit_masks[ qbit_list_complementary[qbit_idx] ];
3554 jdx_loc = jdx_loc | qbit_masks[ qbit_list_complementary[qbit_idx] ];
3562 element_idx.
imag = -element_idx.
imag;
3566 rho_element_priv.
real = rho_element_priv.
real + addend.
real;
3567 rho_element_priv.
imag = rho_element_priv.
imag + addend.
imag;
3576 rho_element.
real = 0.0;
3577 rho_element.imag = 0.0;
3580 rho_element.real = rho_element.real + a.
real;
3581 rho_element.imag = rho_element.imag + a.
imag;
3584 rho[ row_idx * rho.
stride + col_idx ].real += rho_element.real;
3585 rho[ row_idx * rho.
stride + col_idx ].imag += rho_element.imag;
3587 if ( row_idx == col_idx ) {
3591 rho[ col_idx * rho.
stride + row_idx ].real += rho_element.real;
3592 rho[ col_idx * rho.
stride + row_idx ].imag -= rho_element.imag;
3602 for(
int idx=0; idx<rho_matrix_size; idx++) {
3603 trace = trace + rho[idx*rho.
stride+idx].real;
3606 if ( abs( trace-1.0 ) > 1e-6 ) {
3607 std::stringstream sstream;
3608 sstream <<
"Warning: Gates_block::get_reduced_density_matrix: The error of the trace of the reduced density matrix is " << abs( trace-1.0 ) << std::endl;
3633 double trace_rho_square = 0.0;
3635 for (
int idx=0; idx<rho.
rows; idx++) {
3637 double trace_tmp = 0.0;
3639 for (
int jdx=0; jdx<rho.
rows; jdx++) {
3643 trace_tmp = trace_tmp + tmp;
3647 trace_rho_square = trace_rho_square + trace_tmp;
3655 double entropy = -log(trace_rho_square);
3671 std::vector<int> ret = list1;
3673 for( std::vector<int>::iterator it2 = list2.begin(); it2 != list2.end(); it2++ ) {
3675 std::vector<int>::iterator element_found = std::find(ret.begin(), ret.end(), *it2);
3677 if( element_found != ret.end() ) {
3678 ret.erase( element_found );
3707 for(
int idx=static_cast<int>(
gates.size()-1); idx>=0; idx-- ) {
3713 if( reduced_qbit_list.size() < involved_qubits.size() ) {
3719 involved_qubits = std::move(reduced_qbit_list);
3726 if( involved_qubits.size() == 0 ) {
3747 for(
size_t idx=0; idx<
gates.size(); idx++ ) {
3753 if( reduced_qbit_list.size() < involved_qubits.size() ) {
3759 involved_qubits = std::move(reduced_qbit_list);
3766 if( involved_qubits.size() == 0 ) {
3782 for( std::vector<Gate*>::iterator gate_it =
gates.begin(); gate_it !=
gates.end(); gate_it++ ) {
3784 Gate* gate = *gate_it;
3802 for( std::vector<Gate*>::iterator gate_it =
gates.begin(); gate_it !=
gates.end(); gate_it++ ) {
3803 Gate* gate = *gate_it;
3810 for( std::vector<Gate*>::iterator gate_it =
gates.begin(); gate_it !=
gates.end(); gate_it++ ) {
3811 Gate* gate = *gate_it;
3832 for( std::vector<Gate*>::iterator gate_it=
gates.begin(); gate_it !=
gates.end(); gate_it++ ) {
3834 Gate* gate = *gate_it;
3841 flat_circuit->
combine( flat_circuit_inner );
3843 delete( flat_circuit_inner );
3853 return flat_circuit;
3869 std::string err(
"Gates_block::extract_parameters: Cant extract parameters, since th einput arary has not enough elements.");
3877 return extracted_parameters;
3889 DFEgate_kernel_type* Gates_block::convert_to_DFE_gates_with_derivates(
Matrix_real& parameters_mtx,
int& gatesNum,
int& gateSetNum,
int& redundantGateSets,
bool only_derivates ) {
3892 if ( parameter_num != parameters_mtx.
size() ) {
3893 std::string error(
"Gates_block::convert_to_DFE_gates: wrong number of parameters");
3898 int gates_total_num = 0;
3899 for(
auto it=gate_nums.begin(); it != gate_nums.end(); it++ ) {
3900 gates_total_num = gates_total_num + it->second;
3904 int gate_padding = gates_total_num % chained_gates_num == 0 ? 0 : chained_gates_num - (gates_total_num % chained_gates_num);
3905 gatesNum = gates_total_num+gate_padding;
3912 gateSetNum = only_derivates ?
parameter_num : parameter_num+1;
3917 redundantGateSets = 0;
3921 gateSetNum = gateSetNum + redundantGateSets;
3924 int rem = gateSetNum % 4;
3926 redundantGateSets = 0;
3929 redundantGateSets = 4 - (gateSetNum % 4);
3930 gateSetNum = gateSetNum + redundantGateSets;
3939 convert_to_DFE_gates( parameters_mtx, DFEgates, gate_idx );
3943 for (
int idx=gate_idx; idx<gatesNum; idx++ ){
3952 DFEGate.
Phi = (int32_t)(0);
3953 DFEGate.
Lambda = (int32_t)(0);
3965 if (only_derivates ) {
3966 for (
int idx=1; idx<(gateSetNum-1); idx++) {
3971 for (
int idx=0; idx<(gateSetNum-1); idx++) {
3977 int gate_set_index = parameter_num-1;
3978 if (only_derivates) {
3979 adjust_parameters_for_derivation( DFEgates, gatesNum, gate_idx, gate_set_index );
3982 adjust_parameters_for_derivation( DFEgates+gatesNum, gatesNum, gate_idx, gate_set_index );
4000 void Gates_block::adjust_parameters_for_derivation(
DFEgate_kernel_type* DFEgates,
const int gatesNum,
int& gate_idx,
int& gate_set_index) {
4005 int32_t parameter_shift = (int32_t)(
M_PI/2*(1<<25));
4007 for(
int op_idx =
gates.size()-1; op_idx>=0; op_idx--) {
4013 gate_idx = gate_idx + 1;
4016 gate_idx = gate_idx + 1;
4019 gate_idx = gate_idx + 1;
4022 std::string error(
"Gates_block::convert_to_DFE_gates: SYC_gate not implemented");
4030 gate_set_index = gate_set_index - 1;
4032 parameter_idx = parameter_idx - 1;
4033 gate_idx = gate_idx + 1;
4040 gate_set_index = gate_set_index - 1;
4044 DFEGate.
Phi = DFEGate.
Phi + parameter_shift;
4046 gate_set_index = gate_set_index - 1;
4048 parameter_idx = parameter_idx - 2;
4049 gate_idx = gate_idx + 1;
4056 gate_set_index = gate_set_index - 1;
4060 DFEGate2.
Phi = DFEGate2.
Phi + parameter_shift;
4062 gate_set_index = gate_set_index - 1;
4068 gate_set_index = gate_set_index - 1;
4070 parameter_idx = parameter_idx - 3;
4071 gate_idx = gate_idx + 1;
4078 gate_set_index = gate_set_index - 1;
4080 parameter_idx = parameter_idx - 1;
4082 gate_idx = gate_idx + 1;
4089 gate_set_index = gate_set_index - 1;
4091 parameter_idx = parameter_idx - 1;
4094 gate_idx = gate_idx + 1;
4101 gate_set_index = gate_set_index - 1;
4103 parameter_idx = parameter_idx - 1;
4105 gate_idx = gate_idx + 1;
4109 std::string error(
"Gates_block::adjust_parameters_for_derivation: RZ gate not implemented for DFE");
4113 std::string error(
"Gates_block::convert_to_DFE_gates: CU_gate not implemented");
4118 std::string error(
"Gates_block::convert_to_DFE_gates: S_gate not implemented");
4123 std::string error(
"Gates_block::convert_to_DFE_gates: Sdg_gate not implemented");
4128 std::string error(
"Gates_block::convert_to_DFE_gates: H_gate not implemented");
4133 std::string error(
"Gates_block::convert_to_DFE_gates: X_gate not implemented");
4138 std::string error(
"Gates_block::convert_to_DFE_gates: Y_gate not implemented");
4143 std::string error(
"Gates_block::convert_to_DFE_gates: Z_gate not implemented");
4148 std::string error(
"Gates_block::convert_to_DFE_gates: T_gate not implemented");
4153 std::string error(
"Gates_block::convert_to_DFE_gates: Tdg_gate not implemented");
4157 std::string error(
"Gates_block::convert_to_DFE_gates: SX_gate not implemented");
4161 std::string error(
"Gates_block::convert_to_DFE_gates: SXdg_gate not implemented");
4167 block_gate->adjust_parameters_for_derivation( DFEgates, gatesNum, gate_idx, gate_set_index);
4173 std::string error(
"Gates_block::convert_to_DFE_gates: general_gate not implemented");
4181 gate_set_index = gate_set_index - 1;
4183 parameter_idx = parameter_idx - 1;
4185 gate_idx = gate_idx + 1;
4188 std::string err(
"Gates_block::adjust_parameters_for_derivation: unimplemented gate");
4203 Gates_block::convert_to_batched_DFE_gates( std::vector<Matrix_real>& parameters_mtx_vec,
int& gatesNum,
int& gateSetNum,
int& redundantGateSets ) {
4207 int gates_total_num = 0;
4208 for(
auto it=gate_nums.begin(); it != gate_nums.end(); it++ ) {
4209 gates_total_num = gates_total_num + it->second;
4213 int gate_padding = gates_total_num % chained_gates_num == 0 ? 0 : chained_gates_num - (gates_total_num % chained_gates_num);
4214 gatesNum = gates_total_num+gate_padding;
4221 gateSetNum = parameters_mtx_vec.size();
4226 redundantGateSets = 0;
4230 gateSetNum = gateSetNum + redundantGateSets;
4233 int rem = gateSetNum % 4;
4235 redundantGateSets = 0;
4238 redundantGateSets = 4 - (gateSetNum % 4);
4239 gateSetNum = gateSetNum + redundantGateSets;
4246 tbb::parallel_for( 0, gateSetNum, 1, [&](
int gateset_idx) {
4248 int gate_idx = gateset_idx * gatesNum;
4250 if ( gateset_idx < parameters_mtx_vec.size() ) {
4251 Matrix_real& parameters_mtx = parameters_mtx_vec[gateset_idx];
4252 convert_to_DFE_gates( parameters_mtx, DFEgates, gate_idx );
4256 for (
int idx=gate_idx; idx<(gateset_idx+1)*gatesNum; idx++ ){
4265 DFEGate.
Phi = (int32_t)(0);
4266 DFEGate.
Lambda = (int32_t)(0);
4287 if ( parameter_num != parameters_mtx.
size() ) {
4288 std::string error(
"Gates_block::convert_to_DFE_gates: wrong number of parameters");
4294 int gates_total_num = 0;
4295 for(
auto it=gate_nums.begin(); it != gate_nums.end(); it++ ) {
4296 gates_total_num = gates_total_num + it->second;
4300 int gate_padding = chained_gates_num - (gates_total_num % chained_gates_num);
4301 gatesNum = gates_total_num+gate_padding;
4308 convert_to_DFE_gates( parameters_mtx, DFEgates, gate_idx );
4312 for (
int idx=gate_idx; idx<gatesNum; idx++ ){
4321 DFEGate.
Phi = (int32_t)(0);
4322 DFEGate.
Lambda = (int32_t)(0);
4347 int& gate_idx = start_index;
4349 double *parameters_data = parameters_mtx.
get_data();
4353 for(
int op_idx =
gates.size()-1; op_idx>=0; op_idx--) {
4359 CNOT* cnot_gate =
static_cast<CNOT*
>(gate);
4364 DFEGate.
Phi = (int32_t)(0);
4367 gate_idx = gate_idx + 1;
4370 CZ* cz_gate =
static_cast<CZ*
>(gate);
4375 DFEGate.
Phi = (int32_t)(0);
4378 gate_idx = gate_idx + 1;
4381 CH* ch_gate =
static_cast<CH*
>(gate);
4386 DFEGate.
Phi = (int32_t)(0);
4389 gate_idx = gate_idx + 1;
4392 std::string error(
"Gates_block::convert_to_DFE_gates: SYC_gate not implemented");
4396 double lambda = std::fmod(parameters_data[parameter_idx-1], 2*
M_PI);
4397 parameter_idx = parameter_idx - 1;
4403 DFEGate.
Phi = (int32_t)(0);
4404 DFEGate.
Lambda = (int32_t)(lambda*(1<<25));
4406 gate_idx = gate_idx + 1;
4409 double phi = std::fmod(parameters_data[parameter_idx-2], 2*
M_PI);
4410 double lambda = std::fmod(parameters_data[parameter_idx-1], 2*
M_PI);
4411 parameter_idx = parameter_idx - 2;
4417 DFEGate.
Phi = (int32_t)(phi*(1<<25));
4418 DFEGate.
Lambda = (int32_t)(lambda*(1<<25));
4420 gate_idx = gate_idx + 1;
4423 double theta = std::fmod(parameters_data[parameter_idx-3], 4*
M_PI);
4424 double phi = std::fmod(parameters_data[parameter_idx-2], 2*
M_PI);
4425 double lambda = std::fmod(parameters_data[parameter_idx-1], 2*
M_PI);
4426 parameter_idx = parameter_idx - 3;
4431 DFEGate.
ThetaOver2 = (int32_t)(theta/2.0*(1<<25));
4432 DFEGate.
Phi = (int32_t)(phi*(1<<25));
4433 DFEGate.
Lambda = (int32_t)(lambda*(1<<25));
4435 gate_idx = gate_idx + 1;
4439 double varthetaOver2;
4441 RX* rx_gate =
static_cast<RX*
>(gate);
4442 varthetaOver2 = std::fmod( parameters_data[parameter_idx-1], 2*
M_PI);
4443 parameter_idx = parameter_idx - 1;
4448 DFEGate.
ThetaOver2 = (int32_t)(varthetaOver2*(1<<25));
4449 DFEGate.
Phi = (int32_t)(-
M_PI/2*(1<<25));
4453 gate_idx = gate_idx + 1;
4457 double varthetaOver2;
4459 RY* ry_gate =
static_cast<RY*
>(gate);
4460 varthetaOver2 = std::fmod( parameters_data[parameter_idx-1], 2*
M_PI);
4461 parameter_idx = parameter_idx - 1;
4466 DFEGate.
ThetaOver2 = (int32_t)(varthetaOver2*(1<<25));
4467 DFEGate.
Phi = (int32_t)(0);
4468 DFEGate.
Lambda = (int32_t)(0);
4471 gate_idx = gate_idx + 1;
4477 CRY* cry_gate =
static_cast<CRY*
>(gate);
4478 double varthetaOver2 = std::fmod( parameters_data[parameter_idx-1], 2*
M_PI);
4479 parameter_idx = parameter_idx - 1;
4483 DFEGate.
ThetaOver2 = (int32_t)(varthetaOver2*(1<<25));
4484 DFEGate.
Phi = (int32_t)(0);
4485 DFEGate.
Lambda = (int32_t)(0);
4488 gate_idx = gate_idx + 1;
4492 std::string error(
"Gates_block::convert_to_DFE_gates: RZ gate not implemented for DFE");
4497 H* h_gate =
static_cast<H*
>(gate);
4499 std::string error(
"Gates_block::convert_to_DFE_gates: Hadamard gate not implemented");
4502 gate_idx = gate_idx + 1;
4506 X* x_gate =
static_cast<X*
>(gate);
4512 DFEGate.
Phi = (int32_t)(0);
4516 gate_idx = gate_idx + 1;
4520 Y* y_gate =
static_cast<Y*
>(gate);
4526 DFEGate.
Phi = (int32_t)(
M_PI/2*(1<<25));
4530 gate_idx = gate_idx + 1;
4534 Z* z_gate =
static_cast<Z*
>(gate);
4540 DFEGate.
Phi = (int32_t)(0);
4544 gate_idx = gate_idx + 1;
4548 CU* s_gate =
static_cast<CU*
>(gate);
4549 std::string error(
"Gates_block::convert_to_DFE_gates: CU_gate not implemented");
4554 S* s_gate =
static_cast<S*
>(gate);
4555 std::string error(
"Gates_block::convert_to_DFE_gates: S_gate not implemented");
4560 SDG* s_gate =
static_cast<SDG*
>(gate);
4561 std::string error(
"Gates_block::convert_to_DFE_gates: Sdg_gate not implemented");
4566 SX* sx_gate =
static_cast<SX*
>(gate);
4567 std::string error(
"Gates_block::convert_to_DFE_gates: SX_gate not implemented");
4573 block_gate->convert_to_DFE_gates( parameters_layer_mtx, DFEgates, gate_idx );
4577 std::string error(
"Gates_block::convert_to_DFE_gates: general_gate not implemented");
4586 parameter_idx = parameter_idx - 1;
4590 DFEGate.
ThetaOver2 = (int32_t)(varthetaOver2*(1<<25));
4591 DFEGate.
Phi = (int32_t)(0);
4592 DFEGate.
Lambda = (int32_t)(0);
4595 gate_idx = gate_idx + 1;
4598 std::string err(
"Gates_block::convert_to_DFE_gates: unimplemented gate");
4623 Gates_block::extract_gate_kernels_target_and_control_qubits(std::vector<Matrix> &u3_qbit, std::vector<int> &
target_qbit, std::vector<int> &
control_qbit,
Matrix_real& parameters_mtx)
4626 if ( u3_qbit.size() == 0 ) {
4628 int gates_total_num = 0;
4629 for(
auto it=gate_nums.begin(); it != gate_nums.end(); it++ ) {
4630 gates_total_num = gates_total_num + it->second;
4633 u3_qbit.reserve( gates_total_num );
4634 target_qbit.reserve( gates_total_num );
4635 control_qbit.reserve( gates_total_num );
4645 for(
int idx=0; idx<
gates.size(); idx++) {
4655 u3_qbit.push_back(operation->
gate_kernel(empty_params));
4660 u3_qbit.push_back(operation->
gate_kernel(empty_params));
4665 u3_qbit.push_back(operation->
gate_kernel(empty_params));
4670 u3_qbit.push_back(operation->
gate_kernel(empty_params));
4675 u3_qbit.push_back(operation->
gate_kernel(empty_params));
4680 u3_qbit.push_back(operation->
gate_kernel(empty_params));
4685 u3_qbit.push_back(operation->
gate_kernel(empty_params));
4690 u3_qbit.push_back(operation->
gate_kernel(empty_params));
4695 u3_qbit.push_back(operation->
gate_kernel(empty_params));
4700 u3_qbit.push_back(operation->
gate_kernel(empty_params));
4705 u3_qbit.push_back(operation->
gate_kernel(empty_params));
4722 double ThetaOver2 = params_mtx[0];
4729 double ThetaOver2 = params_mtx[0];
4736 double ThetaOver2 = params_mtx[0];
4753 if ( involved_qubits.size() == 1 && block_operation->
gates.size() > 1 && block_operation->
get_qbit_num() > 1 ) {
4758 for (
int idx=0; idx<block_operation->
gates.size(); idx++){
4759 Gate* gate = block_operation->
gates[idx]->clone();
4768 gates_block_mini.
apply_to(params_mtx, merged_kernel);
4770 u3_qbit.push_back( merged_kernel );
4771 target_qbit.push_back( involved_qubits[0] );
4772 control_qbit.push_back( -1 );
4776 block_operation->extract_gate_kernels_target_and_control_qubits(u3_qbit, target_qbit, control_qbit, params_mtx);
4784 std::string err(
"Optimization_Interface::apply_to: unimplemented gate (" + std::to_string(operation->
get_type()) +
")");
4809 std::stringstream sstream;
4810 sstream <<
"Exporting circuit into binary format. Filename: " << filename << std::endl;
4813 log.
print(sstream, 3);
4816 const char* c_filename = filename.c_str();
4819 errno_t err = fopen_s(&pFile, c_filename,
"wb");
4824 pFile = fopen(c_filename,
"wb");
4826 if (pFile==NULL) {fputs (
"File error",stderr); exit (1);}
4848 fwrite(&qbit_num,
sizeof(
int), 1, pFile);
4851 fwrite(¶meter_num,
sizeof(
int), 1, pFile);
4855 fwrite(&gates_num,
sizeof(
int), 1, pFile);
4860 double* parameters_data = parameters.
get_data();
4862 for ( std::vector<Gate*>::iterator it=gates.begin(); it != gates.end(); ++it ) {
4867 fwrite(>_type,
sizeof(
gate_type), 1, pFile);
4874 fwrite(&target_qbit,
sizeof(
int), 1, pFile);
4875 fwrite(&control_qbit,
sizeof(
int), 1, pFile);
4879 fwrite(&target_qbit,
sizeof(
int), 1, pFile);
4880 fwrite(parameters_data,
sizeof(
double), parameter_num, pFile);
4884 fwrite(&target_qbit,
sizeof(
int), 1, pFile);
4886 fwrite(parameters_data,
sizeof(
double), parameter_num, pFile);
4891 fwrite(&target_qbit,
sizeof(
int), 1, pFile);
4892 fwrite(&control_qbit,
sizeof(
int), 1, pFile);
4894 fwrite(parameters_data,
sizeof(
double), parameter_num, pFile);
4899 fwrite(&target_qbit,
sizeof(
int), 1, pFile);
4903 Matrix_real parameters_loc(parameters_data, 1, parameter_num);
4910 fwrite(&target_qbit,
sizeof(
int), 1, pFile);
4911 fwrite(&control_qbit,
sizeof(
int), 1, pFile);
4913 fwrite(parameters_data,
sizeof(
double), parameter_num, pFile);
4916 std::string err(
"export_gate_list_to_binary: unimplemented gate");
4936 std::stringstream sstream;
4937 sstream <<
"Importing quantum circuit from binary file " << filename << std::endl;
4940 log.
print(sstream, 2);
4943 const char* c_filename = filename.c_str();
4946 errno_t err = fopen_s(&pFile, c_filename,
"rb");
4951 pFile = fopen(c_filename,
"rb");
4953 if (pFile==NULL) {fputs (
"File error",stderr); exit (1);}
4972 std::stringstream sstream;
4977 sstream <<
"qbit_num: " << qbit_num << std::endl;
4982 sstream <<
"parameter_num: " << parameter_num << std::endl;
4984 double* parameters_data = parameters.
get_data();
4988 sstream <<
"gates_num: " << gates_num << std::endl;
4990 std::vector<int> gate_block_level_gates_num;
4991 std::vector<Gates_block*> gate_block_levels;
4992 gate_block_level_gates_num.push_back( gates_num );
4993 gate_block_levels.push_back(gate_block);
4994 int current_level = 0;
4998 int iter_max = 100000;
5000 while ( gate_block_level_gates_num[0] > 0 && iter < iter_max) {
5008 sstream <<
"importing CNOT gate" << std::endl;
5012 sstream <<
"target_qbit: " << target_qbit << std::endl;
5016 sstream <<
"control_qbit: " << control_qbit << std::endl;
5018 gate_block_levels[current_level]->add_cnot(target_qbit, control_qbit);
5019 gate_block_level_gates_num[current_level]--;
5022 sstream <<
"importing CZ gate" << std::endl;
5026 sstream <<
"target_qbit: " << target_qbit << std::endl;
5030 sstream <<
"control_qbit: " << control_qbit << std::endl;
5032 gate_block_levels[current_level]->add_cz(target_qbit, control_qbit);
5033 gate_block_level_gates_num[current_level]--;
5036 sstream <<
"importing CH gate" << std::endl;
5040 sstream <<
"target_qbit: " << target_qbit << std::endl;
5044 sstream <<
"control_qbit: " << control_qbit << std::endl;
5046 gate_block_levels[current_level]->add_ch(target_qbit, control_qbit);
5047 gate_block_level_gates_num[current_level]--;
5050 sstream <<
"importing SYCAMORE gate" << std::endl;
5054 sstream <<
"target_qbit: " << target_qbit << std::endl;
5058 sstream <<
"control_qbit: " << control_qbit << std::endl;
5060 gate_block_levels[current_level]->add_syc(target_qbit, control_qbit);
5061 gate_block_level_gates_num[current_level]--;
5064 sstream <<
"importing U1 gate" << std::endl;
5068 sstream <<
"target_qbit: " << target_qbit << std::endl;
5073 gate_block_levels[current_level]->add_u1(target_qbit);
5074 gate_block_level_gates_num[current_level]--;
5077 sstream <<
"importing U2 gate" << std::endl;
5081 sstream <<
"target_qbit: " << target_qbit << std::endl;
5086 gate_block_levels[current_level]->add_u2(target_qbit);
5087 gate_block_level_gates_num[current_level]--;
5090 sstream <<
"importing U3 gate" << std::endl;
5094 sstream <<
"target_qbit: " << target_qbit << std::endl;
5098 parameters_data += 3;
5099 gate_block_levels[current_level]->add_u3(target_qbit);
5100 gate_block_level_gates_num[current_level]--;
5104 sstream <<
"importing RX gate" << std::endl;
5108 sstream <<
"target_qbit: " << target_qbit << std::endl;
5113 gate_block_levels[current_level]->add_rx(target_qbit);
5114 gate_block_level_gates_num[current_level]--;
5119 sstream <<
"importing RY gate" << std::endl;
5123 sstream <<
"target_qbit: " << target_qbit << std::endl;
5128 gate_block_levels[current_level]->add_ry(target_qbit);
5129 gate_block_level_gates_num[current_level]--;
5134 sstream <<
"importing CRY gate" << std::endl;
5138 sstream <<
"target_qbit: " << target_qbit << std::endl;
5142 sstream <<
"control_qbit: " << control_qbit << std::endl;
5147 gate_block_levels[current_level]->add_cry(target_qbit, control_qbit);
5148 gate_block_level_gates_num[current_level]--;
5153 sstream <<
"importing RZ gate" << std::endl;
5157 sstream <<
"target_qbit: " << target_qbit << std::endl;
5162 gate_block_levels[current_level]->add_rz(target_qbit);
5163 gate_block_level_gates_num[current_level]--;
5168 sstream <<
"importing Hadamard gate" << std::endl;
5172 sstream <<
"target_qbit: " << target_qbit << std::endl;
5174 gate_block_levels[current_level]->add_h(target_qbit);
5175 gate_block_level_gates_num[current_level]--;
5180 sstream <<
"importing X gate" << std::endl;
5184 sstream <<
"target_qbit: " << target_qbit << std::endl;
5186 gate_block_levels[current_level]->add_x(target_qbit);
5187 gate_block_level_gates_num[current_level]--;
5192 sstream <<
"importing Y gate" << std::endl;
5196 sstream <<
"target_qbit: " << target_qbit << std::endl;
5198 gate_block_levels[current_level]->add_y(target_qbit);
5199 gate_block_level_gates_num[current_level]--;
5204 sstream <<
"importing Z gate" << std::endl;
5208 sstream <<
"target_qbit: " << target_qbit << std::endl;
5210 gate_block_levels[current_level]->add_z(target_qbit);
5211 gate_block_level_gates_num[current_level]--;
5216 sstream <<
"importing S gate" << std::endl;
5220 sstream <<
"target_qbit: " << target_qbit << std::endl;
5222 gate_block_levels[current_level]->add_s(target_qbit);
5223 gate_block_level_gates_num[current_level]--;
5228 sstream <<
"importing Sdg gate" << std::endl;
5232 sstream <<
"target_qbit: " << target_qbit << std::endl;
5234 gate_block_levels[current_level]->add_sdg(target_qbit);
5235 gate_block_level_gates_num[current_level]--;
5240 sstream <<
"importing T gate" << std::endl;
5244 sstream <<
"target_qbit: " << target_qbit << std::endl;
5246 gate_block_levels[current_level]->add_t(target_qbit);
5247 gate_block_level_gates_num[current_level]--;
5252 sstream <<
"importing Tdg gate" << std::endl;
5256 sstream <<
"target_qbit: " << target_qbit << std::endl;
5258 gate_block_levels[current_level]->add_t(target_qbit);
5259 gate_block_level_gates_num[current_level]--;
5264 sstream <<
"importing SX gate" << std::endl;
5268 sstream <<
"target_qbit: " << target_qbit << std::endl;
5270 gate_block_levels[current_level]->add_sx(target_qbit);
5271 gate_block_level_gates_num[current_level]--;
5277 sstream <<
"******* importing gates block ********" << std::endl;
5284 int parameter_num_loc;
5293 gate_block_levels.push_back( gate_block_inner );
5294 gate_block_level_gates_num.push_back(gates_num_loc);
5299 sstream <<
"importing adaptive gate" << std::endl;
5303 sstream <<
"target_qbit: " << target_qbit << std::endl;
5307 sstream <<
"control_qbit: " << control_qbit << std::endl;
5312 gate_block_levels[current_level]->add_adaptive(target_qbit, control_qbit);
5313 gate_block_level_gates_num[current_level]--;
5317 std::string err(
"import_gate_list_from_binary: unimplemented gate");
5322 if ( gate_block_level_gates_num[current_level] == 0 ) {
5323 gate_block_levels[ current_level-1 ]->add_gate( static_cast<Gate*>(gate_block_levels[ current_level ]) );
5324 gate_block_levels.pop_back();
5325 gate_block_level_gates_num.pop_back();
5327 gate_block_level_gates_num[current_level]--;
5328 sstream <<
"finishing gates block" << std::endl;
5337 log.
print(sstream, 4);
5340 if ( iter == iter_max ) {
5341 std::string error(
"Corrupted input file, reached end of the file before contructing the whole gate structure");
5359 if ( parameters_in.
cols > 1 && parameters_in.
rows > 1 ) {
5360 std::string error(
"reverse_parameters: Input array should have a single column or a single row.");
5367 int parameters_num_total = 0;
5368 for (
int idx=0; idx<num_of_gates; idx++) {
5371 Gate* gate = *(gates_it++);
5377 if ( parameters_num_total == 0) {
5385 Matrix_real parameters_ret(1, parameters_num_total);
5386 int parameter_num_copied = 0;
5389 for (
int idx=num_of_gates-0; idx>0; idx--) {
5392 Gate* gate = *(--gates_it);
5396 if ( parameter_num_gate == 0 ) {
5405 Matrix_real parameters_of_block( parameters_in.
get_data()+parameters_num_total, 1, parameter_num_gate );
5410 std::vector<Gate*> gates_loc = block_gate->
get_gates();
5412 Matrix_real parameters_of_block_reversed =
reverse_parameters( parameters_of_block, gates_loc.begin(),
static_cast<int>(gates_loc.size()) );
5416 memcpy( parameters_ret.
get_data()+parameter_num_copied, parameters_of_block_reversed.
get_data(), parameters_of_block_reversed.
size()*
sizeof(double) );
5417 parameter_num_copied = parameter_num_copied + parameters_of_block_reversed.
size();
5439 return parameters_ret;
5457 if ( parameters_in.
cols > 1 && parameters_in.
rows > 1 ) {
5458 std::string error(
"reverse_parameters: Input array should have a single column or a single row.");
5464 int parameters_num_total = 0;
5465 for (
int idx=0; idx<num_of_gates; idx++) {
5468 Gate* gate = *(gates_it++);
5474 if ( parameters_num_total == 0) {
5482 Matrix_real parameters_ret(1, parameters_num_total);
5483 int parameter_num_copied = 0;
5486 for (
int idx=num_of_gates-0; idx>0; idx--) {
5489 Gate* gate = *(--gates_it);
5493 if ( parameter_num_gate == 0 ) {
5502 Matrix_real parameters_of_block( parameters_in.
get_data()+parameters_num_total, 1, parameter_num_gate );
5507 std::vector<Gate*> gates_loc = block_gate->
get_gates();
5509 Matrix_real parameters_of_block_reversed =
reverse_parameters( parameters_of_block, gates_loc.begin(),
static_cast<int>(gates_loc.size()) );
5513 memcpy( parameters_ret.
get_data()+parameter_num_copied, parameters_of_block_reversed.
get_data(), parameters_of_block_reversed.
size()*
sizeof(double) );
5514 parameter_num_copied = parameter_num_copied + parameters_of_block_reversed.
size();
5536 return parameters_ret;
void add_crz(int target_qbit, int control_qbit)
Append a CRY gate to the list of gates.
std::vector< Gate * > parents
list of parent gates to be applied in the circuit prior to this current gate
Gates_block * get_flat_circuit()
Method to generate a flat circuit.
Gate()
Default constructor of the class.
Copyright (C) Miklos Maroti, 2021 SPDX-License-Identifier: Apache-2.0.
void add_swap_to_front(const std::vector< int > &target_qbits)
Add a SWAP gate to the front of the list of gates.
virtual void reorder_qubits(std::vector< int > qbit_list) override
Call to reorder the qubits in the matrix of the gates (Obsolete function)
void add_adaptive(int target_qbit, int control_qbit)
Append a Adaptive gate to the list of gates.
void add_cu(int target_qbit, int control_qbit)
Append a CU gate (i.e.
void add_rxx_to_front(std::vector< int > target_qbits)
Add a RXX gate to the front of the list of gates.
Header file for a class representing a CSWAP (Controlled SWAP) operation.
int get_chained_gates_num()
Call to retrieve the number of gates that should be chained up during the execution of the DFE librar...
A class representing a RXX gate.
Header file for a class representing a CP gate.
void add_rxx(std::vector< int > target_qbits)
Append a RXX gate to the list of gates.
void print(const std::stringstream &sstream, int verbose_level=1) const
Call to print output messages in the function of the verbosity level.
void set_control_qbits(const std::vector< int > &control_qbits_in)
Call to set the control qubits for the gate operation.
Class to store single-precision real arrays and properties.
A class representing a CCX (Toffoli) operation.
void release_gate(int idx)
Call to release one gate in the list.
void determine_parents(Gate *gate)
Call to obtain the parent gates in the circuit.
void add_cswap(const std::vector< int > &target_qbits, const std::vector< int > &control_qbits)
Append a CSWAP gate (Controlled SWAP) to the list of gates.
void add_z_to_front(int target_qbit)
Add a Z gate to the front of the list of gates.
void add_child(Gate *child)
Call to add a child gate to the current gate.
void add_h(int target_qbit)
Append a Hadamard gate to the list of gates.
void add_sdg_to_front(int target_qbit)
Add a Sdg gate to the front of the list of gates.
virtual Matrix get_matrix()
Retrieve the gate matrix for zero-parameter gates (no parameters).
Header file for a class representing a controlled Z rotation gate.
void clear_children()
Call to erase data on children.
std::map< std::string, int > get_gate_nums()
Call to get the number of the individual gate types in the list of gates.
A class representing a controlled RX gate.
A class representing a CP gate.
std::shared_ptr< tbb::spin_mutex > involved_qubits_cache_mutex
std::vector< int > target_qbits
Vector of target qubit indices (for multi-qubit gates)
void add_x(int target_qbit)
Append a X gate to the list of gates.
void add_sdg(int target_qbit)
Append a Sdg gate to the list of gates.
int control_qbit
The index of the qubit which acts as a control qubit (control_qbit >= 0) in controlled operations...
virtual std::vector< Matrix > apply_derivate_to(Matrix_real ¶meters_mtx_in, Matrix &input, int parallel)
Call to evaluate the derivate of the circuit on an inout with respect to all of the free parameters...
virtual Gate * clone()
Call to create a clone of the present class.
void add_gate(Gate *gate)
Append a general gate to the list of gates.
int stride
The column stride of the array. (The array elements in one row are a_0, a_1, ... a_{cols-1}, 0, 0, 0, 0. The number of zeros is stride-cols)
void set_children(std::vector< Gate *> &children_)
Call to set the children of the current gate.
Header file for a class representing a controlled rotation gate around the Y axis.
void add_u2(int target_qbit)
Append a U2 gate to the list of gates.
void add_cp(int target_qbit, int control_qbit)
Append a CRY gate to the list of gates.
virtual void set_qbit_num(int qbit_num_in)
Set the number of qubits spanning the matrix of the operation.
void add_cnot_to_front(int target_qbit, int control_qbit)
Add a C_NOT gate gate to the front of the list of gates.
void add_u1(int target_qbit)
Append a U1 gate to the list of gates.
Structure type representing single-precision complex numbers.
Header file for a class representing a controlled rotation gate around the Y axis.
int target_qbit
The index of the qubit on which the operation acts (target_qbit >= 0)
Matrix_real reverse_parameters(const Matrix_real ¶meters_in, std::vector< Gate *>::iterator gates_it, int num_of_gates)
Call to reverse the order of the parameters in an array.
std::vector< Gate * > get_gates()
Call to get the gates stored in the class.
Gates_block * create_remapped_circuit(const std::map< int, int > &qbit_map)
Call to create a new circuit with remapped qubits.
void release_gates()
Call to release the stored gates.
void add_cswap_to_front(const std::vector< int > &target_qbits, const std::vector< int > &control_qbits)
Add a CSWAP gate (Controlled SWAP) to the front of the list of gates.
void add_general_operation(const Matrix &operation_mtx, const std::vector< int > &target_qbits=std::vector< int >(), const std::vector< int > &control_qbits=std::vector< int >())
Append a GENERAL_OPERATION gate with an explicitly provided matrix.
Header file for a class representing a CH operation.
Header file for a class representing a controlled X rotation gate.
Header file for a class representing a SWAP operation.
void add_r(int target_qbit)
Append a R gate to the list of gates.
Header file for a class responsible for grouping gates into subcircuits. (Subcircuits can be nested) ...
virtual Gates_block * clone() override
Create a clone of the present class.
int layer_num
number of gate layers
void add_cnot(int target_qbit, int control_qbit)
Append a CNOT gate gate to the list of gates.
A class representing a SWAP operation.
void add_cr(int target_qbit, int control_qbit)
Append a CR gate to the list of gates.
QGD_Complex16 mult(QGD_Complex16 &a, QGD_Complex16 &b)
Call to calculate the product of two complex scalars.
virtual void set_qbit_num(int qbit_num_in) override
Set the number of qubits spanning the matrix of the gates stored in the block of gates.
void add_cz_to_front(int target_qbit, int control_qbit)
Add a CZ gate gate to the front of the list of gates.
void apply_to_list(Matrix_real ¶meters, std::vector< Matrix > &inputs, int parallel) override
Call to apply the gate on the input array/matrix by U3*input.
void add_ryy(std::vector< int > target_qbits)
Append a RYY gate to the list of gates.
bool involved_qubits_cache_valid
int matrix_size
The size N of the NxN matrix associated with the operations.
Header file for a class representing a CCX (Toffoli) operation.
scalar * get_data() const
Call to get the pointer to the stored data.
static tbb::enumerable_thread_specific< int > gates_block_fusion_depth([](){ return 0;})
void add_rz_to_front(int target_qbit)
Add a RZ gate to the front of the list of gates.
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).
Non-owning carrier that references either Matrix (complex128) or Matrix_float (complex64) without dat...
void add_r_to_front(int target_qbit)
Add a R gate to the front of the list of gates.
std::shared_ptr< T > get() const
Class representing a RZZ gate.
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.
int get_gate_num()
Call to get the number of gates grouped in the class.
void add_crx_to_front(int target_qbit, int control_qbit)
Add a CRY gate to the front of the list of gates.
void add_h_to_front(int target_qbit)
Add a Hadamard gate to the front of the list of gates.
void add_ccx_to_front(int target_qbit, const std::vector< int > &control_qbits)
Add a CCX gate (i.e.
A class representing a RYY gate.
Non-owning carrier that can reference either Matrix_real or Matrix_real_float.
std::vector< Gate * > gates
The list of stored gates.
A class representing a CROT gate.
void add_x_to_front(int target_qbit)
Add a X gate to the front of the list of gates.
virtual void apply_from_right_inner(Matrix_real ¶meter_mtx, const Matrix_real &precomputed_sincos, Matrix &input)
Internal right-apply entry that consumes already precomputed sin/cos values.
void add_sx_to_front(int target_qbit)
Add a SX gate to the front of the list of gates.
std::vector< int > involved_target_qubits_cache
void add_sxdg(int target_qbit)
Append a SXdg gate to the list of gates.
A class representing a CZ operation.
virtual void apply_to_inner(Matrix_real ¶meter_mtx, const Matrix_real &precomputed_sincos, Matrix &input, int parallel)
Internal apply entry that consumes already precomputed sin/cos values.
~Gates_block() override
Destructor of the class.
Header file for a class representing a CNOT operation.
A class containing basic methods for setting up the verbosity level.
void add_y_to_front(int target_qbit)
Add a Y gate to the front of the list of gates.
void add_syc(int target_qbit, int control_qbit)
Append a Sycamore gate (i.e.
gate_type type
The type of the operation (see enumeration gate_type)
double get_second_Renyi_entropy(Matrix_real ¶meters_mtx, Matrix &input_state, matrix_base< int > &qbit_list)
Call to evaluate the seconf Rényi entropy.
void add_syc_to_front(int target_qbit, int control_qbit)
Add a Sycamore gate (i.e.
void add_ch(int target_qbit, int control_qbit)
Append a CH gate (i.e.
void add_s_to_front(int target_qbit)
Add a S gate to the front of the list of gates.
A class representing a CRY gate.
virtual void apply_from_right(Matrix &input)
Call to apply the gate on the input array/matrix by input*Gate.
void update(std::shared_ptr< T > p)
std::vector< int > get_control_qbits() const
Call to get the vector of control qubits.
int rows
The number of rows.
A class representing a CH operation.
int cols
The number of columns.
void add_ch_to_front(int target_qbit, int control_qbit)
Add a CH gate (i.e.
void add_u2_to_front(int target_qbit)
Add a U2 gate to the front of the list of gates.
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.
void add_rz(int target_qbit)
Append a RZ gate to the list of gates.
Matrix_float & as_float32()
Matrix_real & as_float64()
void add_y(int target_qbit)
Append a Y gate to the list of gates.
void reset_dependency_graph()
Method to reset the dependency graph of the gates in the circuit.
void combine(Gates_block *op_block)
Call to append the gates of an gate block to the current block.
void add_ry(int target_qbit)
Append a RY gate to the list of gates.
virtual void apply_from_right(Matrix_real ¶meters_mtx, Matrix &input) override
Call to apply the gate on the input array/matrix by input*CNOT.
void set_control_qbit(int control_qbit_in)
Call to set the control qubit for the gate operation.
void set_parameter_start_idx(int start_idx)
Call to set the starting index of the parameters in the parameter array corresponding to the circuit ...
bool involved_target_qubits_cache_valid
Header file for a class representing a CZ operation.
std::vector< int > involved_qubits_cache
int get_parameter_start_idx()
Call to get the starting index of the parameters in the parameter array corresponding to the circuit ...
void add_parent(Gate *parent)
Call to add a parent gate to the current gate.
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.
void set_min_fusion(int min_fusion)
void qgd_sincos_batch< double >(const double *input, double *output, std::size_t count, int stride)
void add_ccx(int target_qbit, const std::vector< int > &control_qbits)
Append a CCX gate (i.e.
void set_target_qbit(int target_qbit_in)
Call to set the target qubit for the gate operation.
void add_cu_to_front(int target_qbit, int control_qbit)
Add a CU gate (i.e.
A class representing a RZZ gate.
Structure type representing complex numbers in the SQUANDER package.
A class representing a CNOT operation.
void add_s(int target_qbit)
Append a S gate to the list of gates.
virtual void apply_to_inner(Matrix_real ¶meters_mtx, const Matrix_real &precomputed_sincos, Matrix &input, int parallel=0) override
Internal apply entry that consumes already precomputed sin/cos values.
int verbose
Set the verbosity level of the output messages.
Matrix copy() const
Call to create a copy of the matrix.
void clear_parents()
Call to erase data on parents.
void determine_children(Gate *gate)
Call to obtain the child gates in the circuit.
void add_u1_to_front(int target_qbit)
Add a U1 gate to the front of the list of gates.
int extract_gates(Gates_block *op_block)
Call to extract the gates stored in the class.
void set_matrix(Matrix input)
Call to set the stored matrix in the operation.
void add_cry_to_front(int target_qbit, int control_qbit)
Add a CRY gate to the front of the list of gates.
int Power_of_2(int n)
Calculates the n-th power of 2.
std::vector< int > get_target_qbits() const
Call to get the vector of target qubits.
bool contains_adaptive_gate()
Call to determine, whether the circuit contains daptive gate or not.
Double-precision complex matrix (float64).
void add_gates_to_front(std::vector< Gate *> gates_in)
Add an array of gates to the front of the list of gates.
void add_gate_to_front(Gate *gate)
Add an gate to the front of the list of gates.
void copy_to(matrix_base< scalar > &target) const
Copy the current matrix storage into a reusable target matrix.
void add_z(int target_qbit)
Append a Z gate to the list of gates.
Header file for a class representing a gate used in adaptive decomposition.
void add_ryy_to_front(std::vector< int > target_qbits)
Add a RYY gate to the front of the list of gates.
int size() const
Call to get the number of the allocated elements.
std::vector< int > control_qbits
Vector of control qubit indices (for multi-qubit gates)
void add_cry(int target_qbit, int control_qbit)
Append a CRY gate to the list of gates.
A class representing a controlled RZ gate.
Gates_block()
Default constructor of the class.
void add_rx_to_front(int target_qbit)
Add a RX gate to the front of the list of gates.
A class representing a CRY gate.
virtual int get_parameter_num()
Call to get the number of free parameters.
void add_tdg_to_front(int target_qbit)
Add a Tdg gate to the front of the list of gates.
A class responsible for grouping two-qubit (CNOT,CZ,CH) and one-qubit gates into layers.
void add_tdg(int target_qbit)
Append a Tdg gate to the list of gates.
virtual Matrix gate_kernel(const Matrix_real &precomputed_sincos)
Compute the gate kernel matrix from precomputed trigonometric values.
void add_u3_to_front(int target_qbit)
Add a U3 gate to the front of the list of gates.
std::string name
A string labeling the gate operation.
virtual std::vector< Matrix > apply_to_combined_inner(Matrix_real ¶meters_mtx, const Matrix_real &precomputed_sincos, Matrix &input, int parallel) override
Internal combined forward+derivative entry with precomputed sin/cos.
Single-precision complex matrix (float32).
void add_cz(int target_qbit, int control_qbit)
Append a CZ gate gate to the list of gates.
std::vector< Gate * > children
list of child gates to be applied after this current gate
Fixed point data related to a gate operation.
bool is_qbit_present(std::vector< int > involved_qubits, int new_qbit, int num_of_qbits)
Call to check whether the given qubit is involved in the sub-circuit or not.
int get_target_qbit()
Call to get the index of the target qubit.
std::vector< int > remove_list_intersection(std::vector< int > &list1, std::vector< int > &list2)
Call to remove those integer elements from list1 which are present in list.
Base class for the representation of general gate operations.
void add_rzz_to_front(std::vector< int > target_qbits)
Add a RZZ gate to the front of the list of gates.
void set_target_qbits(const std::vector< int > &target_qbits_in)
Call to set the target qubits for the gate operation.
std::string get_name()
Call to get the name label of the gate.
Matrix create_identity(int matrix_size)
Call to create an identity matrix.
void add_gate_nums(std::map< std::string, int > &gate_nums)
Call to add the number of the individual gate types in the circuit to the map given in the argument...
int get_limit()
???????????
void add_ry_to_front(int target_qbit)
Add a RY gate to the front of the list of gates.
Header file for a class representing a controlled rotation gate around the Y axis.
int parameter_num
the number of free parameters of the operation
virtual void apply_to_list(std::vector< Matrix > &inputs, int parallel)
Call to apply the gate on a list of inputs.
int min_fusion
maximal number of qubits in partitions
void add_rx(int target_qbit)
Append a RX gate to the list of gates.
Matrix_real_float & as_float32()
void set_parents(std::vector< Gate *> &parents_)
Call to set the parents of the current gate.
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.
A class representing a SYC operation.
void insert_gate(Gate *gate, int idx)
Call to insert a gate at a given position.
double real
the real part of a complex number
void reset_parameter_start_indices()
Method to reset the parameter start indices of gate operations incorporated in the circuit...
A class representing a CRY gate.
void add_crz_to_front(int target_qbit, int control_qbit)
Add a CRY gate to the front of the list of gates.
int qbit_num
number of qubits spanning the matrix of the operation
void add_t_to_front(int target_qbit)
Add a T gate to the front of the list of gates.
void add_crot(int target_qbit, int control_qbit)
Append a CROT gate gate to the list of gates.
void add_crot_to_front(int target_qbit, int control_qbit)
Add a CROT gate gate to the front of the list of gates.
int get_qbit_num()
Call to get the number of qubits composing the unitary.
virtual Matrix_real extract_parameters(Matrix_real ¶meters) override
Call to extract parameters from the parameter array corresponding to the circuit, in which the gate i...
gate_type
Type definition of operation types (also generalized for decomposition classes derived from the class...
void add_crx(int target_qbit, int control_qbit)
Append a CRY gate to the list of gates.
Gate * get_gate(int idx)
Call to get the gates stored in the class.
void add_cr_to_front(int target_qbit, int control_qbit)
Add a CR gate to the front of the list of gates.
void fread_wrapper(void *buffer, size_t size, size_t count, FILE *stream)
Wrapper function aound fread with error handling.
virtual void apply_to(Matrix &input, int parallel)
Call to apply the gate on the input array/matrix.
void list_gates(const Matrix_real ¶meters, int start_index)
Call to print the list of gates stored in the block of gates for a specific set of parameters...
virtual std::vector< Matrix > apply_to_combined(Matrix_real ¶meters_mtx, Matrix &input, int parallel) override
Combined forward + derivative application with shared precomputed trig cache.
Matrix get_reduced_density_matrix(Matrix_real ¶meters_mtx, Matrix &input_state, matrix_base< int > &qbit_list_subset)
Call to evaluate the reduced densiy matrix.
void add_adaptive_to_front(int target_qbit, int control_qbit)
Add a Adaptive gate to the front of the list of gates.
void qgd_sincos_batch< float >(const float *input, float *output, std::size_t count, int stride)
virtual std::vector< int > get_involved_qubits(bool only_target=false)
Call to get the qubits involved in the gate operation.
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.
int get_parameter_num() override
Call to get the number of free parameters.
virtual void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the operation.
void invalidate_structure_cache()
static tbb::enumerable_thread_specific< int > gates_block_derivative_depth([](){ return 0;})
void add_gates(std::vector< Gate *> gates_in)
Append a list of gates to the list of gates.
void add_cp_to_front(int target_qbit, int control_qbit)
Add a CRY gate to the front of the list of gates.
Matrix_real inverse_reverse_parameters(const Matrix_real ¶meters_in, std::vector< Gate *>::iterator gates_it, int num_of_gates)
Call to inverse-reverse the order of the parameters in an array.
void add_sxdg_to_front(int target_qbit)
Add a SXdg gate to the front of the list of gates.
void add_t(int target_qbit)
Append a T gate to the list of gates.
int get_control_qbit()
Call to get the index of the control qubit.
Class to store data of complex arrays and its properties.
SmartAtomicPtr< Gates_block > fusion_block
virtual void apply_from_right_inner(Matrix_real ¶meters_mtx, const Matrix_real &precomputed_sincos, Matrix &input) override
Internal right-apply entry that consumes already precomputed sin/cos values.
virtual std::vector< Matrix > apply_derivate_to(Matrix_real ¶meters_mtx, Matrix &input, int parallel) override
Call to evaluate the derivate of the circuit on an inout with respect to all of the free parameters...
A class representing a CSWAP (Controlled SWAP) operation.
double imag
the imaginary part of a complex number
Class representing a RYY gate.
void add_rzz(std::vector< int > target_qbits)
Append a RZZ gate to the list of gates.
void add_sx(int target_qbit)
Append a SX gate to the list of gates.
Matrix_float create_identity_float(int matrix_size)
Call to create a single-precision complex identity matrix.
void add_swap(const std::vector< int > &target_qbits)
Append a SWAP gate to the list of gates.
Header file for a class representing a Sycamore gate.