From ef25257a988bddf2d0e15ae65915dd9a96c2bc2a Mon Sep 17 00:00:00 2001 From: Tom Peham Date: Wed, 20 Nov 2024 15:29:39 +0100 Subject: [PATCH] Automated Synthesis of Encoder Circuits for Stabilizer Codes (#275) ## Description This PR introduces functionality to automatically synthesize encoder circuits for arbitrary stabilizer codes. Since this is closely related to state preparation circuit synthesis, this PR refactors and unifies the respective synthesis methods into a `circuit_synthesis` module. Planned Features: - [x] Optimal (gate or depth) encoder circuit synthesis for CSS codes - [x] Heuristic encoder circuit synthesis for CSS codes - [ ] ~~Optimal (gate or depth) circuit synthesis for non-CSS ancilla states~~ - [ ] ~~Heuristic circuit synthesis for non-CSS ancilla states~~ The last parts were canceled because qecc functionality already allows for the construction of such state preparation circuits. ## Checklist: - [x] The pull request only contains commits that are related to it. - [x] I have added appropriate tests and documentation. - [x] I have made sure that all CI jobs on GitHub pass. - [x] The pull request introduces no new warnings and follows the project's style guidelines. --- docs/StatePrep.ipynb | 14 +- docs/images/full_ft_scheme.svg | 1 + docs/library/StatePrep.rst | 2 +- .../eval/estimate_logical_error_rate.py | 4 +- .../__init__.py | 8 +- src/mqt/qecc/circuit_synthesis/encoding.py | 257 +++++ .../encoding_circuits/10_1_2.qasm | 21 + .../encoding_circuits/4_2_2.qasm | 10 + .../encoding_circuits/6_2_2.qasm | 14 + .../encoding_circuits/carbon.qasm | 31 + .../encoding_circuits/hamming.qasm | 43 + .../encoding_circuits/shor.qasm | 15 + .../encoding_circuits/steane.qasm | 16 + .../encoding_circuits/surface.qasm | 17 + .../encoding_circuits/tetrahedral.qasm | 32 + .../examples/Encoding_Circuit.ipynb | 148 +++ .../examples/Non_CSS_Ancillas.ipynb | 119 +++ .../non_css_ancillas/five_qubit_code.qasm | 19 + .../five_qubit_code_verified.qasm | 27 + .../non_css_ancillas/gottesman_8_3_3.qasm | 33 + .../gottesman_8_3_3_verified.qasm | 63 ++ .../simulation.py | 0 .../simulation_det.py | 0 .../state_prep.py | 866 ++--------------- .../state_prep_det.py | 6 +- .../stateprep_eval/README.md | 11 + .../carbon/zero_ft_heuristic_heuristic.qasm | 55 ++ .../carbon/zero_ft_heuristic_heuristic.stim | 9 + .../carbon/zero_ft_heuristic_opt.qasm | 57 ++ .../carbon/zero_ft_heuristic_opt.stim | 14 + .../circuits/carbon/zero_ft_opt_opt.qasm | 49 + .../circuits/carbon/zero_ft_opt_opt.stim | 9 + .../carbon/zero_non_ft_heuristic.qasm | 24 + .../carbon/zero_non_ft_heuristic.stim | 2 + .../circuits/carbon/zero_non_ft_opt.qasm | 24 + .../circuits/carbon/zero_non_ft_opt.stim | 2 + .../cc_4_8_8/zero_ft_heuristic_opt.qasm | 111 +++ .../cc_4_8_8/zero_ft_heuristic_opt.stim | 25 + .../cc_4_8_8/zero_non_ft_heuristic.qasm | 34 + .../cc_4_8_8/zero_non_ft_heuristic.stim | 2 + .../cc_6_6_6/zero_ft_heuristic_opt.qasm | 184 ++++ .../cc_6_6_6/zero_ft_heuristic_opt.stim | 51 + .../cc_6_6_6/zero_non_ft_heuristic.qasm | 39 + .../cc_6_6_6/zero_non_ft_heuristic.stim | 2 + .../hamming/plus_ft_heuristic_heuristic.qasm | 57 ++ .../hamming/plus_ft_heuristic_heuristic.stim | 8 + .../hamming/plus_ft_heuristic_opt.qasm | 51 + .../hamming/plus_ft_heuristic_opt.stim | 8 + .../circuits/hamming/plus_ft_opt_opt.qasm | 50 + .../circuits/hamming/plus_ft_opt_opt.stim | 10 + .../hamming/plus_non_ft_heuristic.qasm | 36 + .../hamming/plus_non_ft_heuristic.stim | 2 + .../circuits/hamming/plus_non_ft_opt.qasm | 36 + .../circuits/hamming/plus_non_ft_opt.stim | 2 + .../hamming/zero_ft_heuristic_heuristic.qasm | 46 + .../hamming/zero_ft_heuristic_heuristic.stim | 3 + .../hamming/zero_ft_heuristic_opt.qasm | 40 + .../hamming/zero_ft_heuristic_opt.stim | 3 + .../circuits/hamming/zero_ft_opt_opt.qasm | 39 + .../circuits/hamming/zero_ft_opt_opt.stim | 3 + .../hamming/zero_non_ft_heuristic.qasm | 46 + .../hamming/zero_non_ft_heuristic.stim | 3 + .../circuits/hamming/zero_non_ft_opt.qasm | 29 + .../circuits/hamming/zero_non_ft_opt.stim | 2 + .../plus_ft_heuristic_heuristic.qasm | 23 + .../plus_ft_heuristic_heuristic.stim | 6 + .../plus_ft_heuristic_opt.qasm | 23 + .../plus_ft_heuristic_opt.stim | 6 + .../rotated_surface_d3/plus_ft_opt_opt.qasm | 24 + .../rotated_surface_d3/plus_ft_opt_opt.stim | 6 + .../plus_non_ft_heuristic.qasm | 16 + .../plus_non_ft_heuristic.stim | 2 + .../rotated_surface_d3/plus_non_ft_opt.qasm | 16 + .../rotated_surface_d3/plus_non_ft_opt.stim | 2 + .../zero_ft_heuristic_heuristic.qasm | 22 + .../zero_ft_heuristic_heuristic.stim | 3 + .../zero_ft_heuristic_opt.qasm | 21 + .../zero_ft_heuristic_opt.stim | 3 + .../rotated_surface_d3/zero_ft_opt_opt.qasm | 21 + .../rotated_surface_d3/zero_ft_opt_opt.stim | 3 + .../zero_non_ft_heuristic.qasm | 19 + .../zero_non_ft_heuristic.stim | 2 + .../rotated_surface_d3/zero_non_ft_opt.qasm | 15 + .../rotated_surface_d3/zero_non_ft_opt.stim | 2 + .../zero_ft_heuristic_naive.qasm | 383 ++++++++ .../zero_ft_heuristic_naive.stim | 87 ++ .../zero_ft_heuristic_opt.qasm | 195 ++++ .../zero_ft_heuristic_opt.stim | 32 + .../zero_non_ft_heuristic.qasm | 43 + .../zero_non_ft_heuristic.stim | 2 + .../shor/plus_ft_heuristic_heuristic.qasm | 12 + .../shor/plus_ft_heuristic_heuristic.stim | 2 + .../circuits/shor/plus_ft_heuristic_opt.qasm | 12 + .../circuits/shor/plus_ft_heuristic_opt.stim | 2 + .../circuits/shor/plus_ft_opt_opt.qasm | 12 + .../circuits/shor/plus_ft_opt_opt.stim | 2 + .../circuits/shor/plus_non_ft_heuristic.qasm | 12 + .../circuits/shor/plus_non_ft_heuristic.stim | 2 + .../circuits/shor/plus_non_ft_opt.qasm | 12 + .../circuits/shor/plus_non_ft_opt.stim | 2 + .../shor/zero_ft_heuristic_heuristic.qasm | 23 + .../shor/zero_ft_heuristic_heuristic.stim | 3 + .../circuits/shor/zero_ft_heuristic_opt.qasm | 23 + .../circuits/shor/zero_ft_heuristic_opt.stim | 5 + .../circuits/shor/zero_ft_opt_opt.qasm | 19 + .../circuits/shor/zero_ft_opt_opt.stim | 3 + .../circuits/shor/zero_non_ft_heuristic.qasm | 14 + .../circuits/shor/zero_non_ft_heuristic.stim | 2 + .../circuits/shor/zero_non_ft_opt.qasm | 13 + .../circuits/shor/zero_non_ft_opt.stim | 2 + .../steane/plus_ft_heuristic_heuristic.qasm | 23 + .../steane/plus_ft_heuristic_heuristic.stim | 6 + .../steane/plus_ft_heuristic_opt.qasm | 23 + .../steane/plus_ft_heuristic_opt.stim | 6 + .../circuits/steane/plus_ft_opt_opt.qasm | 23 + .../circuits/steane/plus_ft_opt_opt.stim | 6 + .../steane/plus_non_ft_heuristic.qasm | 15 + .../steane/plus_non_ft_heuristic.stim | 2 + .../circuits/steane/plus_non_ft_opt.qasm | 15 + .../circuits/steane/plus_non_ft_opt.stim | 2 + .../steane/zero_ft_heuristic_heuristic.qasm | 20 + .../steane/zero_ft_heuristic_heuristic.stim | 3 + .../steane/zero_ft_heuristic_opt.qasm | 20 + .../steane/zero_ft_heuristic_opt.stim | 3 + .../circuits/steane/zero_ft_opt_opt.qasm | 20 + .../circuits/steane/zero_ft_opt_opt.stim | 3 + .../steane/zero_non_ft_heuristic.qasm | 14 + .../steane/zero_non_ft_heuristic.stim | 2 + .../circuits/steane/zero_non_ft_opt.qasm | 14 + .../circuits/steane/zero_non_ft_opt.stim | 2 + .../plus_ft_heuristic_heuristic.qasm | 43 + .../plus_ft_heuristic_heuristic.stim | 4 + .../tetrahedral/plus_ft_heuristic_opt.qasm | 43 + .../tetrahedral/plus_ft_heuristic_opt.stim | 4 + .../tetrahedral/plus_non_ft_heuristic.qasm | 31 + .../tetrahedral/plus_non_ft_heuristic.stim | 2 + .../zero_ft_heuristic_heuristic.qasm | 35 + .../zero_ft_heuristic_heuristic.stim | 3 + .../tetrahedral/zero_ft_heuristic_opt.qasm | 35 + .../tetrahedral/zero_ft_heuristic_opt.stim | 3 + .../circuits/tetrahedral/zero_ft_opt_opt.qasm | 35 + .../circuits/tetrahedral/zero_ft_opt_opt.stim | 3 + .../tetrahedral/zero_non_ft_heuristic.qasm | 29 + .../tetrahedral/zero_non_ft_heuristic.stim | 2 + .../circuits/tetrahedral/zero_non_ft_opt.qasm | 29 + .../circuits/tetrahedral/zero_non_ft_opt.stim | 2 + .../estimate_logical_error_rate.py | 100 ++ .../stateprep_eval/run_eval_on_code.sh | 17 + .../qecc/circuit_synthesis/synthesis_utils.py | 877 ++++++++++++++++++ test/python/circuit_synthesis/__init__.py | 1 + .../test_deterministic.py | 8 +- .../test_encoder_synthesis.py | 132 +++ .../test_simulation.py | 2 +- .../test_stateprep.py | 67 +- test/python/circuit_synthesis/test_utils.py | 276 ++++++ test/python/circuit_synthesis/utils.py | 76 ++ 156 files changed, 5337 insertions(+), 842 deletions(-) create mode 100644 docs/images/full_ft_scheme.svg rename src/mqt/qecc/{ft_stateprep => circuit_synthesis}/__init__.py (73%) create mode 100644 src/mqt/qecc/circuit_synthesis/encoding.py create mode 100644 src/mqt/qecc/circuit_synthesis/encoding_circuits/10_1_2.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/encoding_circuits/4_2_2.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/encoding_circuits/6_2_2.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/encoding_circuits/carbon.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/encoding_circuits/hamming.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/encoding_circuits/shor.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/encoding_circuits/steane.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/encoding_circuits/surface.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/encoding_circuits/tetrahedral.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/examples/Encoding_Circuit.ipynb create mode 100644 src/mqt/qecc/circuit_synthesis/examples/Non_CSS_Ancillas.ipynb create mode 100644 src/mqt/qecc/circuit_synthesis/non_css_ancillas/five_qubit_code.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/non_css_ancillas/five_qubit_code_verified.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/non_css_ancillas/gottesman_8_3_3.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/non_css_ancillas/gottesman_8_3_3_verified.qasm rename src/mqt/qecc/{ft_stateprep => circuit_synthesis}/simulation.py (100%) rename src/mqt/qecc/{ft_stateprep => circuit_synthesis}/simulation_det.py (100%) rename src/mqt/qecc/{ft_stateprep => circuit_synthesis}/state_prep.py (60%) rename src/mqt/qecc/{ft_stateprep => circuit_synthesis}/state_prep_det.py (99%) create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/README.md create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_heuristic_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_heuristic_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_heuristic_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_heuristic_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_opt_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_opt_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_non_ft_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_non_ft_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_non_ft_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_non_ft_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_4_8_8/zero_ft_heuristic_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_4_8_8/zero_ft_heuristic_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_4_8_8/zero_non_ft_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_4_8_8/zero_non_ft_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_6_6_6/zero_ft_heuristic_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_6_6_6/zero_ft_heuristic_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_6_6_6/zero_non_ft_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_6_6_6/zero_non_ft_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_heuristic_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_heuristic_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_heuristic_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_heuristic_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_opt_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_opt_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_non_ft_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_non_ft_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_non_ft_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_non_ft_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_heuristic_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_heuristic_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_heuristic_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_heuristic_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_opt_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_opt_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_non_ft_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_non_ft_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_non_ft_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_non_ft_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_heuristic_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_heuristic_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_heuristic_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_heuristic_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_opt_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_opt_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_non_ft_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_non_ft_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_non_ft_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_non_ft_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_heuristic_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_heuristic_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_heuristic_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_heuristic_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_opt_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_opt_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_non_ft_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_non_ft_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_non_ft_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_non_ft_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_ft_heuristic_naive.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_ft_heuristic_naive.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_ft_heuristic_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_ft_heuristic_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_non_ft_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_non_ft_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_heuristic_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_heuristic_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_heuristic_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_heuristic_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_opt_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_opt_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_non_ft_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_non_ft_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_non_ft_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_non_ft_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_heuristic_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_heuristic_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_heuristic_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_heuristic_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_opt_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_opt_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_non_ft_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_non_ft_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_non_ft_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_non_ft_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_heuristic_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_heuristic_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_heuristic_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_heuristic_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_opt_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_opt_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_non_ft_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_non_ft_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_non_ft_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_non_ft_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_heuristic_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_heuristic_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_heuristic_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_heuristic_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_opt_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_opt_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_non_ft_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_non_ft_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_non_ft_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_non_ft_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_ft_heuristic_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_ft_heuristic_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_ft_heuristic_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_ft_heuristic_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_non_ft_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_non_ft_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_heuristic_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_heuristic_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_heuristic_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_heuristic_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_opt_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_opt_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_non_ft_heuristic.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_non_ft_heuristic.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_non_ft_opt.qasm create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_non_ft_opt.stim create mode 100644 src/mqt/qecc/circuit_synthesis/stateprep_eval/estimate_logical_error_rate.py create mode 100755 src/mqt/qecc/circuit_synthesis/stateprep_eval/run_eval_on_code.sh create mode 100644 src/mqt/qecc/circuit_synthesis/synthesis_utils.py create mode 100644 test/python/circuit_synthesis/__init__.py rename test/python/{ft_stateprep => circuit_synthesis}/test_deterministic.py (96%) create mode 100644 test/python/circuit_synthesis/test_encoder_synthesis.py rename test/python/{ft_stateprep => circuit_synthesis}/test_simulation.py (99%) rename test/python/{ft_stateprep => circuit_synthesis}/test_stateprep.py (90%) create mode 100644 test/python/circuit_synthesis/test_utils.py create mode 100644 test/python/circuit_synthesis/utils.py diff --git a/docs/StatePrep.ipynb b/docs/StatePrep.ipynb index 69f275f0..f76e5c75 100644 --- a/docs/StatePrep.ipynb +++ b/docs/StatePrep.ipynb @@ -45,7 +45,7 @@ "metadata": {}, "outputs": [], "source": [ - "from mqt.qecc.ft_stateprep import gate_optimal_prep_circuit\n", + "from mqt.qecc.circuit_synthesis import gate_optimal_prep_circuit\n", "\n", "non_ft_sp = gate_optimal_prep_circuit(steane_code, zero_state=True, max_timeout=2)\n", "\n", @@ -76,7 +76,7 @@ "metadata": {}, "outputs": [], "source": [ - "from mqt.qecc.ft_stateprep import gate_optimal_verification_circuit\n", + "from mqt.qecc.circuit_synthesis import gate_optimal_verification_circuit\n", "\n", "ft_sp = gate_optimal_verification_circuit(non_ft_sp)\n", "\n", @@ -105,7 +105,7 @@ "metadata": {}, "outputs": [], "source": [ - "from mqt.qecc.ft_stateprep import NoisyNDFTStatePrepSimulator\n", + "from mqt.qecc.circuit_synthesis import NoisyNDFTStatePrepSimulator\n", "\n", "p = 0.05\n", "\n", @@ -178,8 +178,8 @@ "metadata": {}, "outputs": [], "source": [ + "from mqt.qecc.circuit_synthesis import heuristic_prep_circuit\n", "from mqt.qecc.codes import SquareOctagonColorCode\n", - "from mqt.qecc.ft_stateprep import heuristic_prep_circuit\n", "\n", "cc = SquareOctagonColorCode(5)\n", "cc_non_ft_sp = heuristic_prep_circuit(cc, zero_state=True, optimize_depth=True)\n", @@ -222,7 +222,7 @@ "metadata": {}, "outputs": [], "source": [ - "from mqt.qecc.ft_stateprep import naive_verification_circuit\n", + "from mqt.qecc.circuit_synthesis import naive_verification_circuit\n", "\n", "cc_ft_naive = naive_verification_circuit(cc_non_ft_sp)\n", "\n", @@ -293,7 +293,7 @@ "metadata": {}, "outputs": [], "source": [ - "from mqt.qecc.ft_stateprep import DeterministicVerificationHelper\n", + "from mqt.qecc.circuit_synthesis import DeterministicVerificationHelper\n", "\n", "det_helper = DeterministicVerificationHelper(non_ft_sp)" ] @@ -393,7 +393,7 @@ "source": [ "from qsample import callbacks, noise\n", "\n", - "from mqt.qecc.ft_stateprep import NoisyDFTStatePrepSimulator\n", + "from mqt.qecc.circuit_synthesis import NoisyDFTStatePrepSimulator\n", "\n", "error_model = noise.E1_1 # depolarizing error model\n", "err_params = {\"q\": [1e-4, 5e-4, 1e-3, 5e-3, 1e-2, 5e-2, 1e-1, 5e-1]}\n", diff --git a/docs/images/full_ft_scheme.svg b/docs/images/full_ft_scheme.svg new file mode 100644 index 00000000..dfff94a4 --- /dev/null +++ b/docs/images/full_ft_scheme.svg @@ -0,0 +1 @@ +XXXZZZXXXXZZZZZZXXXXVerify X errorsVerify 1 propagated errorVerify 𝑑12propagated errorsVerify Z errorsNon-FT State preparationVerify 1 propagated errorVerify 𝑑12propagated errors0𝐿𝑘ZX(a)(c)(e)(d)(b)(f) diff --git a/docs/library/StatePrep.rst b/docs/library/StatePrep.rst index 938ec52d..3b8b7164 100644 --- a/docs/library/StatePrep.rst +++ b/docs/library/StatePrep.rst @@ -3,7 +3,7 @@ Fault tolerant state preparation QECC provides functionality to synthesize and simulate state preparation circuits for logical basis states for arbitrary :math:`[[n, k, d]]` quantum CSS codes. - .. currentmodule:: mqt.qecc.ft_stateprep + .. currentmodule:: mqt.qecc.circuit_synthesis Non-fault tolerant state preparation circuits can be synthesized using :func:`depth_optimal_prep_circuit`, :func:`gate_optimal_prep_circuit` and :func:`heuristic_prep_circuit`. diff --git a/scripts/ft_stateprep/eval/estimate_logical_error_rate.py b/scripts/ft_stateprep/eval/estimate_logical_error_rate.py index aff0360e..7348f28a 100644 --- a/scripts/ft_stateprep/eval/estimate_logical_error_rate.py +++ b/scripts/ft_stateprep/eval/estimate_logical_error_rate.py @@ -8,8 +8,7 @@ from qiskit import QuantumCircuit from mqt.qecc import CSSCode -from mqt.qecc.codes import HexagonalColorCode, SquareOctagonColorCode -from mqt.qecc.ft_stateprep import ( +from mqt.qecc.circuit_synthesis import ( NoisyNDFTStatePrepSimulator, gate_optimal_prep_circuit, gate_optimal_verification_circuit, @@ -17,6 +16,7 @@ heuristic_verification_circuit, naive_verification_circuit, ) +from mqt.qecc.codes import HexagonalColorCode, SquareOctagonColorCode def main() -> None: diff --git a/src/mqt/qecc/ft_stateprep/__init__.py b/src/mqt/qecc/circuit_synthesis/__init__.py similarity index 73% rename from src/mqt/qecc/ft_stateprep/__init__.py rename to src/mqt/qecc/circuit_synthesis/__init__.py index e1df66bf..bab7f97d 100644 --- a/src/mqt/qecc/ft_stateprep/__init__.py +++ b/src/mqt/qecc/circuit_synthesis/__init__.py @@ -1,7 +1,8 @@ -"""Methods for synthesizing fault tolerant state preparation circuits.""" +"""Methods and utilities for synthesizing fault-tolerant circuits and gadgets.""" from __future__ import annotations +from .encoding import depth_optimal_encoding_circuit, gate_optimal_encoding_circuit, heuristic_encoding_circuit from .simulation import LutDecoder, NoisyNDFTStatePrepSimulator from .simulation_det import NoisyDFTStatePrepSimulator from .state_prep import ( @@ -16,6 +17,7 @@ naive_verification_circuit, ) from .state_prep_det import DeterministicVerification, DeterministicVerificationHelper +from .synthesis_utils import qiskit_to_stim_circuit __all__ = [ "DeterministicVerification", @@ -24,12 +26,16 @@ "NoisyDFTStatePrepSimulator", "NoisyNDFTStatePrepSimulator", "StatePrepCircuit", + "depth_optimal_encoding_circuit", "depth_optimal_prep_circuit", + "gate_optimal_encoding_circuit", "gate_optimal_prep_circuit", "gate_optimal_verification_circuit", "gate_optimal_verification_stabilizers", + "heuristic_encoding_circuit", "heuristic_prep_circuit", "heuristic_verification_circuit", "heuristic_verification_stabilizers", "naive_verification_circuit", + "qiskit_to_stim_circuit", ] diff --git a/src/mqt/qecc/circuit_synthesis/encoding.py b/src/mqt/qecc/circuit_synthesis/encoding.py new file mode 100644 index 00000000..241e68e4 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/encoding.py @@ -0,0 +1,257 @@ +"""Methods for synthesizing encoding circuits for CSS codes.""" + +from __future__ import annotations + +import functools +import logging +import operator +from typing import TYPE_CHECKING + +import numpy as np +import z3 + +from ..codes import InvalidCSSCodeError +from .synthesis_utils import build_css_circuit_from_cnot_list, heuristic_gaussian_elimination, optimal_elimination + +if TYPE_CHECKING: # pragma: no cover + import numpy.typing as npt + from qiskit import QuantumCircuit + + from ..codes import CSSCode + +logger = logging.getLogger(__name__) + + +def heuristic_encoding_circuit( + code: CSSCode, optimize_depth: bool = True, balance_checks: bool = True +) -> QuantumCircuit: + """Synthesize an encoding circuit for the given CSS code using a heuristic greedy search. + + Args: + code: The CSS code to synthesize the encoding circuit for. + optimize_depth: Whether to optimize the depth of the circuit. + balance_checks: Whether to balance the entries of the stabilizer matrix via row operations. + + Returns: + The synthesized encoding circuit and the qubits that are used to encode the logical qubits. + """ + logging.info("Starting encoding circuit synthesis.") + + checks, logicals, use_x_checks = _get_matrix_with_fewest_checks(code) + n_checks = checks.shape[0] + + if balance_checks: + _balance_matrix(logicals) + + checks, cnots = heuristic_gaussian_elimination( + np.vstack((checks, logicals)), + parallel_elimination=optimize_depth, + ) + + # after reduction there still might be some overlap between initialized qubits and encoding qubits, we simply perform CNOTs to correct this + encoding_qubits = np.where(checks[n_checks:, :].sum(axis=0) != 0)[0] + initialization_qubits = np.where(checks[:n_checks, :].sum(axis=0) != 0)[0] + # remove encoding qubits from initialization qubits + initialization_qubits = np.setdiff1d(initialization_qubits, encoding_qubits) + rows = [] # type: list[int] + qubit_to_row = {} + for qubit in initialization_qubits: + cand = np.where(checks[:n_checks, qubit] == 1)[0] + np.setdiff1d(cand, np.array(rows)) + rows.append(cand[0]) + qubit_to_row[qubit] = cand[0] + + for init_qubit in initialization_qubits: + for encoding_qubit in encoding_qubits: + row = qubit_to_row[init_qubit] + if checks[row, encoding_qubit] == 1: + cnots.append((init_qubit, encoding_qubit)) + checks[row, encoding_qubit] = 0 + + cnots = cnots[::-1] + + return _build_css_encoder_from_cnot_list(n_checks, checks, cnots, use_x_checks) + + +def gate_optimal_encoding_circuit( + code: CSSCode, + min_gates: int = 1, + max_gates: int = 10, + min_timeout: int = 1, + max_timeout: int = 3600, +) -> QuantumCircuit: + """Synthesize an encoding circuit for the given CSS code using the minimal number of gates. + + Args: + code: The CSS code to synthesize the encoding circuit for. + min_gates: The minimum number of gates to use in the circuit. + max_gates: The maximum number of gates to use in the circuit. + min_timeout: The minimum time to spend on the synthesis. + max_timeout: The maximum time to spend on the synthesis. + + Returns: + The synthesized encoding circuit and the qubits that are used to encode the logical qubits. + """ + logging.info("Starting optimal encoding circuit synthesis.") + checks, logicals, use_x_checks = _get_matrix_with_fewest_checks(code) + assert checks is not None + n_checks = checks.shape[0] + checks_and_logicals = np.vstack((checks, logicals)) + termination_criteria = functools.partial( + _final_matrix_constraint_partially_full_reduction, + full_reduction_rows=list(range(checks.shape[0], checks.shape[0] + logicals.shape[0])), + ) + res = optimal_elimination( + checks_and_logicals, + termination_criteria, + "column_ops", + min_param=min_gates, + max_param=max_gates, + min_timeout=min_timeout, + max_timeout=max_timeout, + ) + if res is None: + return None + reduced_checks_and_logicals, cnots = res + cnots = cnots[::-1] + + return _build_css_encoder_from_cnot_list(n_checks, reduced_checks_and_logicals, cnots, use_x_checks) + + +def depth_optimal_encoding_circuit( + code: CSSCode, + min_depth: int = 1, + max_depth: int = 10, + min_timeout: int = 1, + max_timeout: int = 3600, +) -> QuantumCircuit: + """Synthesize an encoding circuit for the given CSS code using minimal depth. + + Args: + code: The CSS code to synthesize the encoding circuit for. + min_depth: The minimum number of gates to use in the circuit. + max_depth: The maximum number of gates to use in the circuit. + min_timeout: The minimum time to spend on the synthesis. + max_timeout: The maximum time to spend on the synthesis. + + Returns: + The synthesized encoding circuit and the qubits that are used to encode the logical qubits. + """ + logging.info("Starting optimal encoding circuit synthesis.") + checks, logicals, use_x_checks = _get_matrix_with_fewest_checks(code) + assert checks is not None + n_checks = checks.shape[0] + checks_and_logicals = np.vstack((checks, logicals)) + termination_criteria = functools.partial( + _final_matrix_constraint_partially_full_reduction, + full_reduction_rows=list(range(checks.shape[0], checks.shape[0] + logicals.shape[0])), + ) + res = optimal_elimination( + checks_and_logicals, + termination_criteria, + "parallel_ops", + min_param=min_depth, + max_param=max_depth, + min_timeout=min_timeout, + max_timeout=max_timeout, + ) + if res is None: + return None + reduced_checks_and_logicals, cnots = res + cnots = cnots[::-1] + + return _build_css_encoder_from_cnot_list(n_checks, reduced_checks_and_logicals, cnots, use_x_checks) + + +def _get_matrix_with_fewest_checks(code: CSSCode) -> tuple[npt.NDArray[np.int8], npt.NDArray[np.int8], bool]: + """Return the stabilizer matrix with the fewest checks, the corresponding logicals and a bool indicating whether X- or Z-checks have been returned.""" + if code.Hx is None or code.Hz is None: + msg = "The code must have both X and Z stabilizers defined." + raise InvalidCSSCodeError(msg) + + use_x_checks = code.Hx.shape[0] < code.Hz.shape[0] + checks = code.Hx if use_x_checks else code.Hz + logicals = code.Lx if use_x_checks else code.Lz + return checks, logicals, use_x_checks + + +def _final_matrix_constraint_partially_full_reduction( + columns: npt.NDArray[z3.BoolRef | bool], full_reduction_rows: list[int] +) -> z3.BoolRef: + assert len(columns.shape) == 3 + + at_least_n_row_columns = z3.PbEq( + [(z3.Or(list(columns[-1, full_reduction_rows, col])), 1) for col in range(columns.shape[2])], + len(full_reduction_rows), + ) + + fully_reduced = z3.And(at_least_n_row_columns) + + partial_reduction_rows = list(set(range(columns.shape[1])) - set(full_reduction_rows)) + + # assert that the partial_reduction_rows are partially reduced, i.e. there are at least columns.shape[2] - (columns.shape[1] - len(full_reduction_rows)) non-zero columns + partially_reduced = z3.PbEq( + [(z3.Not(z3.Or(list(columns[-1, partial_reduction_rows, col]))), 1) for col in range(columns.shape[2])], + columns.shape[2] - (columns.shape[1] - len(full_reduction_rows)), + ) + + # assert that there is no overlap between the full_reduction_rows and the partial_reduction_rows + overlap_constraints = [True] + for col in range(columns.shape[2]): + has_entry_partial = z3.Or(list(columns[-1, partial_reduction_rows, col])) + has_entry_full = z3.Or(list(columns[-1, full_reduction_rows, col])) + overlap_constraints.append(z3.Not(z3.And(has_entry_partial, has_entry_full))) + + return z3.And(fully_reduced, partially_reduced, z3.And(overlap_constraints)) + + +def _build_css_encoder_from_cnot_list( + n_checks: int, checks_and_logicals: npt.NDArray[np.int8], cnots: list[tuple[int, int]], use_x_checks: bool +) -> tuple[QuantumCircuit, list[int]]: + encoding_qubits = np.where(checks_and_logicals[n_checks:, :].sum(axis=0) != 0)[0] + if use_x_checks: + hadamards = np.where(checks_and_logicals[:n_checks, :].sum(axis=0) != 0)[0] + else: + hadamards = np.where(checks_and_logicals[:n_checks, :].sum(axis=0) == 0)[0] + cnots = [(j, i) for i, j in cnots] + + hadamards = np.setdiff1d(hadamards, encoding_qubits) + circ = build_css_circuit_from_cnot_list(checks_and_logicals.shape[1], cnots, list(hadamards)) + return circ, encoding_qubits + + +def _balance_matrix(m: npt.NDArray[np.int8]) -> None: + """Balance the columns of the matrix. + + Try to balance the number of 1's in each column via row operations without increasing the row-weight. + """ + variance = np.var(m.sum(axis=0)) + reduced = False + + while not reduced: + reduced = True + # compute row operations that do not increase the row-weights + row_ops = [] + for i, row_1 in enumerate(m): + for j, row_2 in enumerate(m): + if i == j: + continue + s = (row_1 + row_2) % 2 + if s.sum() > row_1.sum() or s.sum() > row_2.sum(): + continue + # compute associated column weights + m[j] = s # noqa: B909 + + new_variance = np.var(m.sum(axis=0)) + if new_variance < variance: + row_ops.append((i, j, new_variance)) + + m[j] = row_2 # noqa: B909 + # sort by lowest variance + row_ops.sort(key=operator.itemgetter(2)) + # apply best row operation + if row_ops: + i, j = row_ops[0][:2] + m[i] = (m[i] + m[j]) % 2 + reduced = False + variance = row_ops[0][2] diff --git a/src/mqt/qecc/circuit_synthesis/encoding_circuits/10_1_2.qasm b/src/mqt/qecc/circuit_synthesis/encoding_circuits/10_1_2.qasm new file mode 100644 index 00000000..7e973f46 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/encoding_circuits/10_1_2.qasm @@ -0,0 +1,21 @@ +# Encoding qubits: 6 + +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[10]; +h q[0]; +h q[1]; +h q[2]; +cx q[1],q[8]; +cx q[0],q[7]; +cx q[6],q[0]; +cx q[2],q[5]; +cx q[1],q[4]; +cx q[6],q[4]; +cx q[5],q[9]; +cx q[2],q[3]; +cx q[0],q[1]; +cx q[9],q[6]; +cx q[4],q[5]; +cx q[0],q[3]; +cx q[1],q[2]; diff --git a/src/mqt/qecc/circuit_synthesis/encoding_circuits/4_2_2.qasm b/src/mqt/qecc/circuit_synthesis/encoding_circuits/4_2_2.qasm new file mode 100644 index 00000000..b05e691c --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/encoding_circuits/4_2_2.qasm @@ -0,0 +1,10 @@ +# Encoding qubits: 0, 1 + +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[4]; +h q[2]; +cx q[1],q[3]; +cx q[2],q[0]; +cx q[2],q[3]; +cx q[0],q[1]; diff --git a/src/mqt/qecc/circuit_synthesis/encoding_circuits/6_2_2.qasm b/src/mqt/qecc/circuit_synthesis/encoding_circuits/6_2_2.qasm new file mode 100644 index 00000000..1c6f15f7 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/encoding_circuits/6_2_2.qasm @@ -0,0 +1,14 @@ +# Encoding qubits: 0, 1 + +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[6]; +h q[2]; +h q[4]; +cx q[1],q[5]; +cx q[4],q[0]; +cx q[1],q[3]; +cx q[2],q[0]; +cx q[4],q[5]; +cx q[2],q[3]; +cx q[0],q[1]; diff --git a/src/mqt/qecc/circuit_synthesis/encoding_circuits/carbon.qasm b/src/mqt/qecc/circuit_synthesis/encoding_circuits/carbon.qasm new file mode 100644 index 00000000..679757e2 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/encoding_circuits/carbon.qasm @@ -0,0 +1,31 @@ +# Encoding Qubits: 0,4 +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[12]; +h q[5]; +h q[8]; +h q[9]; +h q[10]; +h q[11]; +cx q[9],q[2]; +cx q[5],q[2]; +cx q[11],q[1]; +cx q[8],q[7]; +cx q[5],q[4]; +cx q[10],q[3]; +cx q[9],q[1]; +cx q[2],q[0]; +cx q[11],q[7]; +cx q[0],q[6]; +cx q[1],q[4]; +cx q[8],q[3]; +cx q[4],q[7]; +cx q[10],q[6]; +cx q[3],q[2]; +cx q[1],q[0]; +cx q[6],q[11]; +cx q[5],q[10]; +cx q[7],q[9]; +cx q[0],q[8]; +cx q[2],q[1]; +cx q[4],q[3]; diff --git a/src/mqt/qecc/circuit_synthesis/encoding_circuits/hamming.qasm b/src/mqt/qecc/circuit_synthesis/encoding_circuits/hamming.qasm new file mode 100644 index 00000000..d702f7d5 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/encoding_circuits/hamming.qasm @@ -0,0 +1,43 @@ +# Encoding Qubits: 0,1,2,3,4,6,12 +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +h q[7]; +h q[10]; +h q[11]; +h q[13]; +cx q[13],q[8]; +cx q[7],q[1]; +cx q[7],q[8]; +cx q[1],q[6]; +cx q[13],q[9]; +cx q[6],q[8]; +cx q[8],q[12]; +cx q[2],q[9]; +cx q[1],q[9]; +cx q[12],q[5]; +cx q[11],q[4]; +cx q[10],q[5]; +cx q[8],q[4]; +cx q[9],q[0]; +cx q[11],q[14]; +cx q[2],q[10]; +cx q[5],q[4]; +cx q[1],q[3]; +cx q[7],q[0]; +cx q[6],q[14]; +cx q[10],q[13]; +cx q[4],q[12]; +cx q[3],q[11]; +cx q[0],q[5]; +cx q[13],q[14]; +cx q[6],q[10]; +cx q[11],q[8]; +cx q[5],q[3]; +cx q[4],q[2]; +cx q[12],q[11]; +cx q[9],q[7]; +cx q[5],q[2]; +cx q[8],q[0]; +cx q[4],q[6]; +cx q[14],q[10]; diff --git a/src/mqt/qecc/circuit_synthesis/encoding_circuits/shor.qasm b/src/mqt/qecc/circuit_synthesis/encoding_circuits/shor.qasm new file mode 100644 index 00000000..84b5f4dc --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/encoding_circuits/shor.qasm @@ -0,0 +1,15 @@ +# Encoding Qubits: 2 +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +h q[0]; +h q[6]; +cx q[6],q[2]; +cx q[0],q[3]; +cx q[6],q[8]; +cx q[3],q[4]; +cx q[2],q[0]; +cx q[6],q[7]; +cx q[4],q[5]; +cx q[3],q[2]; +cx q[0],q[1]; diff --git a/src/mqt/qecc/circuit_synthesis/encoding_circuits/steane.qasm b/src/mqt/qecc/circuit_synthesis/encoding_circuits/steane.qasm new file mode 100644 index 00000000..c6cf7b66 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/encoding_circuits/steane.qasm @@ -0,0 +1,16 @@ +# Encoding Qubits: 2 +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[7]; +h q[4]; +h q[5]; +h q[6]; +cx q[5],q[1]; +cx q[1],q[2]; +cx q[4],q[0]; +cx q[6],q[4]; +cx q[5],q[3]; +cx q[2],q[0]; +cx q[6],q[3]; +cx q[4],q[5]; +cx q[0],q[1]; diff --git a/src/mqt/qecc/circuit_synthesis/encoding_circuits/surface.qasm b/src/mqt/qecc/circuit_synthesis/encoding_circuits/surface.qasm new file mode 100644 index 00000000..77243e3d --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/encoding_circuits/surface.qasm @@ -0,0 +1,17 @@ +# Encoding Qubits: 0 +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +h q[3]; +h q[5]; +h q[6]; +h q[7]; +cx q[7],q[4]; +cx q[3],q[0]; +cx q[3],q[4]; +cx q[5],q[2]; +cx q[0],q[1]; +cx q[7],q[8]; +cx q[4],q[5]; +cx q[1],q[2]; +cx q[6],q[3]; diff --git a/src/mqt/qecc/circuit_synthesis/encoding_circuits/tetrahedral.qasm b/src/mqt/qecc/circuit_synthesis/encoding_circuits/tetrahedral.qasm new file mode 100644 index 00000000..3efd4a0a --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/encoding_circuits/tetrahedral.qasm @@ -0,0 +1,32 @@ +# Encoding Qubits: 8 +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +h q[0]; +h q[1]; +h q[2]; +h q[14]; +cx q[8],q[10]; +cx q[2],q[9]; +cx q[1],q[12]; +cx q[0],q[7]; +cx q[14],q[7]; +cx q[12],q[8]; +cx q[10],q[0]; +cx q[9],q[11]; +cx q[2],q[5]; +cx q[1],q[4]; +cx q[14],q[12]; +cx q[11],q[13]; +cx q[9],q[10]; +cx q[5],q[6]; +cx q[2],q[3]; +cx q[7],q[4]; +cx q[0],q[1]; +cx q[14],q[13]; +cx q[12],q[11]; +cx q[8],q[9]; +cx q[7],q[6]; +cx q[0],q[3]; +cx q[4],q[5]; +cx q[1],q[2]; diff --git a/src/mqt/qecc/circuit_synthesis/examples/Encoding_Circuit.ipynb b/src/mqt/qecc/circuit_synthesis/examples/Encoding_Circuit.ipynb new file mode 100644 index 00000000..72cd4c54 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/examples/Encoding_Circuit.ipynb @@ -0,0 +1,148 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "3d318f66-d757-4fb9-a0cd-71a6c9c33dd4", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "from mqt.qecc import CSSCode\n", + "from mqt.qecc.circuit_synthesis import gate_optimal_encoding_circuit, heuristic_encoding_circuit" + ] + }, + { + "cell_type": "markdown", + "id": "a5953bc9-95c7-4282-b1b3-ec51cf5cb94c", + "metadata": {}, + "source": [ + "# Synthesizing Encoding Circuits using Greedy Heuristic" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3365e1a7-45cf-463e-bbd7-5cc368b079f3", + "metadata": {}, + "outputs": [], + "source": [ + "# 4, 2, 2 code\n", + "css_4_2_2 = CSSCode(2, np.array([[1] * 4]), np.array([[1] * 4]))\n", + "encoder_4_2_2, encoding_qubits = heuristic_encoding_circuit(css_4_2_2)\n", + "\n", + "encoder_4_2_2.draw(output=\"mpl\", scale=0.7)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8e073e5b-9242-4de5-be6e-84cf43b4ad77", + "metadata": {}, + "outputs": [], + "source": [ + "# 6, 2, 2 code\n", + "css_6_2_2 = CSSCode(\n", + " 2, np.array([[1, 1, 1, 1, 0, 0], [1, 1, 0, 0, 1, 1]]), np.array([[1, 1, 1, 1, 0, 0], [1, 1, 0, 0, 1, 1]])\n", + ")\n", + "encoder_6_2_2, encoding_qubits = heuristic_encoding_circuit(css_6_2_2)\n", + "\n", + "encoder_6_2_2.draw(output=\"mpl\", scale=0.7)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55e058d6-e6bb-4987-932c-d414f5a4ac83", + "metadata": {}, + "outputs": [], + "source": [ + "Hz_10_1_2 = np.zeros((6, 10), dtype=np.int8)\n", + "Hx_10_1_2 = np.zeros((3, 10), dtype=np.int8)\n", + "\n", + "Hz_10_1_2[0][[0, 1, 2, 3]] = 1\n", + "Hz_10_1_2[1][[2, 3, 5, 6]] = 1\n", + "Hz_10_1_2[2][[1, 2, 4, 5]] = 1\n", + "Hz_10_1_2[3][[2, 5, 7]] = 1\n", + "Hz_10_1_2[4][[1, 2, 9]] = 1\n", + "Hz_10_1_2[5][[2, 3, 8]] = 1\n", + "\n", + "Hx_10_1_2[0][[0, 1, 2, 3, 7]] = 1\n", + "Hx_10_1_2[1][[2, 3, 5, 6, 9]] = 1\n", + "Hx_10_1_2[2][[1, 2, 4, 5, 8]] = 1\n", + "\n", + "css_10_1_2 = CSSCode(2, Hx_10_1_2, Hz_10_1_2)\n", + "\n", + "encoder_10_1_2, encoding_qubits = heuristic_encoding_circuit(css_10_1_2)\n", + "\n", + "encoder_10_1_2.draw(output=\"mpl\", scale=0.7)" + ] + }, + { + "cell_type": "markdown", + "id": "82d013ec-c28e-4c65-8bc2-91eac64be2fb", + "metadata": {}, + "source": [ + "# Synthesizing Optimal Encoding Circuits " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7c68ef1-7134-41cb-ab93-10c0ae614c3a", + "metadata": {}, + "outputs": [], + "source": [ + "encoder_4_2_2_opt, encoding_qubits = gate_optimal_encoding_circuit(css_4_2_2)\n", + "\n", + "encoder_4_2_2_opt.draw(output=\"mpl\", scale=0.7)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0edefbf-442c-4ee3-8467-3268a0969f18", + "metadata": {}, + "outputs": [], + "source": [ + "encoder_6_2_2_opt, encoding_qubits = gate_optimal_encoding_circuit(css_6_2_2)\n", + "\n", + "encoder_6_2_2_opt.draw(output=\"mpl\", scale=0.7)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26f0cd04-08b1-45fb-9796-36038530f7fd", + "metadata": {}, + "outputs": [], + "source": [ + "# This will time out because no circuit with 12 CNOT gates exists.\n", + "# Increase timeout if you need the proof\n", + "result = gate_optimal_encoding_circuit(css_10_1_2, min_gates=5, max_gates=12, max_timeout=60)\n", + "assert result is None" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "python11", + "language": "python", + "name": "python11" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/src/mqt/qecc/circuit_synthesis/examples/Non_CSS_Ancillas.ipynb b/src/mqt/qecc/circuit_synthesis/examples/Non_CSS_Ancillas.ipynb new file mode 100644 index 00000000..195d51d8 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/examples/Non_CSS_Ancillas.ipynb @@ -0,0 +1,119 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "2677b854-20a2-48da-a3fb-e2f5de015279", + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit import QuantumCircuit\n", + "\n", + "from mqt.qecc import CSSCode, StabilizerCode\n", + "from mqt.qecc.circuit_synthesis import gate_optimal_verification_circuit, heuristic_prep_circuit" + ] + }, + { + "cell_type": "markdown", + "id": "aa4e1c0c-2e18-4c87-ba43-160c7fabb790", + "metadata": {}, + "source": [ + "For a $[[n,k,d]]$ stabilizer code we can check for X- and Z-errors with transversal CNOTs using a single $2n$ ancilla state. Half the qubits are then used as the control in a transversal CNOT and the other half as the target of another transversal CNOT. To ensure that these applications of CNOTs don't disturb the logical state we have to make sure the stabilizers propagate correctly from the state to the ancilla and vice-versa. \n", + "\n", + "Let $S$ be the stabilizer generators of an $[[n, k, d]]$ stabilizer code and $H_S = (H_X \\mid H_Z) \\in \\mathbb{Z}_2^{(n-k)\\times 2n}$ be symplectic representation of $S$. Furthermore, let $S_X = \\{X^{\\otimes H_X[i, :]} \\mid 1 \\leq i \\leq (n-k)$ where $X^{\\otimes v}$ is the stabilizer that acts as a Pauli $X$ on qubit $j$ if $v[j] = 1$ and as identity otherwise. $S_Z$ is defined analogous.\n", + "\n", + "Then we define the $2n$-qubit state $\\ket{\\psi}$ as the state stabilized by $S_\\mathit{anc} = \\{s_X\\otimes (H^{\\otimes n} s_Z H^{\\otimes n}) \\mid s_X \\in S_X, s_Z \\in S_Z\\}$ and $2n-|S|$ $Z$-stabilizers that commute with all stabilizers in $S_\\mathit{anc}$. This is a maximal CSS code (a code without any logicals). We can synthesize such states using `qecc`.\n", + "\n", + "Let's synthesize this state for the five-qubit code:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85257dd4-01f0-4be0-8755-acad68b9c109", + "metadata": {}, + "outputs": [], + "source": [ + "# Define the code:\n", + "five_qubit_code = StabilizerCode([\"XZZXI\", \"IXZZX\", \"XIXZZ\", \"ZXIXZ\"])\n", + "\n", + "# Construct the maximal CSS code. No Z-stabilizers need to be given since they are uniquely determined.\n", + "combined = CSSCode(3, Hx=five_qubit_code.symplectic_matrix)\n", + "\n", + "# Synthesize the state prep circuit.\n", + "qc_prep = heuristic_prep_circuit(combined)\n", + "\n", + "qc_prep.circ.draw(output=\"mpl\", scale=0.5, initial_state=\"zero\")" + ] + }, + { + "cell_type": "markdown", + "id": "71544907-bde5-4ab7-9993-d395fb3f6f72", + "metadata": {}, + "source": [ + "This ancilla state can be used for syndrome extraction using the following construction:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66292149-46eb-4d83-a528-654a82e8766f", + "metadata": {}, + "outputs": [], + "source": [ + "qc = QuantumCircuit(5)\n", + "\n", + "qc = qc_prep.circ.tensor(qc)\n", + "qc.barrier()\n", + "qc.cx(range(5, 10), range(5))\n", + "qc.barrier()\n", + "qc.h(range(10, 15))\n", + "qc.cx(range(5), range(10, 15))\n", + "\n", + "qc.draw(output=\"mpl\", scale=0.5, fold=False)" + ] + }, + { + "cell_type": "markdown", + "id": "c5387a79-56c4-4154-87d7-ea0d03a36129", + "metadata": {}, + "source": [ + "One can verify that, by construction, the stabilizers propagate correctly. For example, the stabilizer $XXZIZ$ on the data qubits propagates to $XXIII|IIZIZ$ on the ancilla state, which is a stabilizer by construction of $S_\\mathit{anc}$. The other stabilizers of the ancilla state are all Z-type stabilizers, which do not propagate at all (the Hadamards on the last 5 qubits turn the Zs into X which commute through the target of the CNOTs).\n", + "\n", + "Before using such an ancilla state for syndrome extraction, one might want to verify that no errors have propageted through the CNOTs during preparation. `qecc` has functionality for this as well." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9736b7cb-f3ec-46ee-8db2-56c0c5496f99", + "metadata": {}, + "outputs": [], + "source": [ + "qc_prep_ver = gate_optimal_verification_circuit(qc_prep)\n", + "\n", + "qc_prep_ver.draw(output=\"mpl\", scale=0.5, fold=False)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "python11", + "language": "python", + "name": "python11" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/src/mqt/qecc/circuit_synthesis/non_css_ancillas/five_qubit_code.qasm b/src/mqt/qecc/circuit_synthesis/non_css_ancillas/five_qubit_code.qasm new file mode 100644 index 00000000..d99ef304 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/non_css_ancillas/five_qubit_code.qasm @@ -0,0 +1,19 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[10]; +h q[0]; +h q[1]; +h q[2]; +h q[4]; +cx q[2],q[9]; +cx q[4],q[8]; +cx q[1],q[9]; +cx q[0],q[6]; +cx q[4],q[7]; +cx q[2],q[8]; +cx q[1],q[5]; +cx q[0],q[3]; +cx q[6],q[7]; +cx q[5],q[3]; +cx q[4],q[1]; +cx q[2],q[0]; diff --git a/src/mqt/qecc/circuit_synthesis/non_css_ancillas/five_qubit_code_verified.qasm b/src/mqt/qecc/circuit_synthesis/non_css_ancillas/five_qubit_code_verified.qasm new file mode 100644 index 00000000..821bc082 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/non_css_ancillas/five_qubit_code_verified.qasm @@ -0,0 +1,27 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[10]; +qreg z_anc[1]; +creg z_c[1]; +h q[0]; +h q[1]; +h q[2]; +h q[4]; +cx q[2],q[9]; +cx q[4],q[8]; +cx q[1],q[9]; +cx q[0],q[6]; +cx q[4],q[7]; +cx q[2],q[8]; +cx q[1],q[5]; +cx q[0],q[3]; +cx q[6],q[7]; +cx q[5],q[3]; +cx q[4],q[1]; +cx q[2],q[0]; +cx q[2],z_anc[0]; +cx q[3],z_anc[0]; +cx q[4],z_anc[0]; +cx q[7],z_anc[0]; +cx q[9],z_anc[0]; +measure z_anc[0] -> z_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/non_css_ancillas/gottesman_8_3_3.qasm b/src/mqt/qecc/circuit_synthesis/non_css_ancillas/gottesman_8_3_3.qasm new file mode 100644 index 00000000..5fa60640 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/non_css_ancillas/gottesman_8_3_3.qasm @@ -0,0 +1,33 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[16]; +h q[0]; +h q[1]; +h q[3]; +h q[5]; +h q[8]; +cx q[5],q[10]; +cx q[3],q[12]; +cx q[1],q[9]; +cx q[12],q[14]; +cx q[10],q[11]; +cx q[8],q[9]; +cx q[3],q[4]; +cx q[1],q[2]; +cx q[0],q[5]; +cx q[14],q[15]; +cx q[12],q[13]; +cx q[8],q[10]; +cx q[4],q[6]; +cx q[1],q[7]; +cx q[0],q[2]; +cx q[9],q[11]; +cx q[5],q[3]; +cx q[8],q[12]; +cx q[0],q[6]; +cx q[10],q[14]; +cx q[9],q[13]; +cx q[5],q[7]; +cx q[2],q[4]; +cx q[11],q[15]; +cx q[3],q[1]; diff --git a/src/mqt/qecc/circuit_synthesis/non_css_ancillas/gottesman_8_3_3_verified.qasm b/src/mqt/qecc/circuit_synthesis/non_css_ancillas/gottesman_8_3_3_verified.qasm new file mode 100644 index 00000000..d2dffdd1 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/non_css_ancillas/gottesman_8_3_3_verified.qasm @@ -0,0 +1,63 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[16]; +qreg z_anc[2]; +qreg x_anc[1]; +qreg a7[1]; +creg z_c[2]; +creg x_c[1]; +creg c7[1]; +h q[0]; +h q[1]; +h q[3]; +h q[5]; +h q[8]; +cx q[5],q[10]; +cx q[3],q[12]; +cx q[1],q[9]; +cx q[12],q[14]; +cx q[10],q[11]; +cx q[8],q[9]; +cx q[3],q[4]; +cx q[1],q[2]; +cx q[0],q[5]; +cx q[14],q[15]; +cx q[12],q[13]; +cx q[8],q[10]; +cx q[4],q[6]; +cx q[1],q[7]; +cx q[0],q[2]; +cx q[9],q[11]; +cx q[5],q[3]; +cx q[8],q[12]; +cx q[0],q[6]; +cx q[10],q[14]; +cx q[9],q[13]; +cx q[5],q[7]; +cx q[2],q[4]; +cx q[11],q[15]; +cx q[3],q[1]; +cx q[6],z_anc[0]; +cx q[7],z_anc[0]; +cx q[9],z_anc[0]; +cx q[14],z_anc[0]; +cx q[3],z_anc[1]; +cx q[4],z_anc[1]; +cx q[12],z_anc[1]; +cx q[15],z_anc[1]; +measure z_anc[0] -> z_c[0]; +measure z_anc[1] -> z_c[1]; +h x_anc[0]; +cx x_anc[0],q[1]; +cx x_anc[0],a7[0]; +cx x_anc[0],q[2]; +cx x_anc[0],q[5]; +cx x_anc[0],q[6]; +cx x_anc[0],q[9]; +cx x_anc[0],q[10]; +cx x_anc[0],q[12]; +cx x_anc[0],a7[0]; +measure a7[0] -> c7[0]; +cx x_anc[0],q[15]; +h x_anc[0]; +measure x_anc[0] -> x_c[0]; diff --git a/src/mqt/qecc/ft_stateprep/simulation.py b/src/mqt/qecc/circuit_synthesis/simulation.py similarity index 100% rename from src/mqt/qecc/ft_stateprep/simulation.py rename to src/mqt/qecc/circuit_synthesis/simulation.py diff --git a/src/mqt/qecc/ft_stateprep/simulation_det.py b/src/mqt/qecc/circuit_synthesis/simulation_det.py similarity index 100% rename from src/mqt/qecc/ft_stateprep/simulation_det.py rename to src/mqt/qecc/circuit_synthesis/simulation_det.py diff --git a/src/mqt/qecc/ft_stateprep/state_prep.py b/src/mqt/qecc/circuit_synthesis/state_prep.py similarity index 60% rename from src/mqt/qecc/ft_stateprep/state_prep.py rename to src/mqt/qecc/circuit_synthesis/state_prep.py index 64e4717c..862bf090 100644 --- a/src/mqt/qecc/ft_stateprep/state_prep.py +++ b/src/mqt/qecc/circuit_synthesis/state_prep.py @@ -4,9 +4,8 @@ import logging from collections import defaultdict -from typing import TYPE_CHECKING, Any, TypeVar, cast +from typing import TYPE_CHECKING -import multiprocess import numpy as np import z3 from ldpc import mod2 @@ -14,14 +13,26 @@ from qiskit.converters import circuit_to_dag from ..codes import InvalidCSSCodeError +from .synthesis_utils import ( + build_css_circuit_from_cnot_list, + heuristic_gaussian_elimination, + iterative_search_with_timeout, + measure_flagged, + odd_overlap, + optimal_elimination, + run_with_timeout, + symbolic_scalar_mult, + symbolic_vector_add, + symbolic_vector_eq, +) logger = logging.getLogger(__name__) if TYPE_CHECKING: # pragma: no cover - from collections.abc import Callable, Iterable + from collections.abc import Callable import numpy.typing as npt - from qiskit import AncillaQubit, ClBit, DAGNode, Qubit + from qiskit import DAGNode from qiskit.quantum_info import PauliList from ..codes import CSSCode @@ -194,6 +205,19 @@ def _set_max_errors(self) -> None: self.z_fault_sets_unreduced: list[npt.NDArray[np.int8] | None] = [None for _ in range(self.max_errors + 1)] +def _build_state_prep_circuit_from_back( + checks: npt.NDArray[np.int8], cnots: list[tuple[int, int]], zero_state: bool = True +) -> QuantumCircuit: + cnots.reverse() + if zero_state: + hadamards = np.where(np.sum(checks, axis=0) != 0)[0] + else: + hadamards = np.where(np.sum(checks, axis=0) == 0)[0] + cnots = [(j, i) for i, j in cnots] + + return build_css_circuit_from_cnot_list(checks.shape[1], cnots, list(hadamards)) + + def heuristic_prep_circuit(code: CSSCode, optimize_depth: bool = True, zero_state: bool = True) -> StatePrepCircuit: """Return a circuit that prepares the +1 eigenstate of the code w.r.t. the Z or X basis. @@ -206,232 +230,12 @@ def heuristic_prep_circuit(code: CSSCode, optimize_depth: bool = True, zero_stat if code.Hx is None or code.Hz is None: msg = "The code must have both X and Z stabilizers defined." raise InvalidCSSCodeError(msg) - checks = code.Hx.copy() if zero_state else code.Hz.copy() - rank = mod2.rank(checks) - - def is_reduced() -> bool: - return bool(len(np.where(np.all(checks == 0, axis=0))[0]) == checks.shape[1] - rank) - - costs = np.array([ - [np.sum((checks[:, i] + checks[:, j]) % 2) for j in range(checks.shape[1])] for i in range(checks.shape[1]) - ]) - costs -= np.sum(checks, axis=0) - np.fill_diagonal(costs, 1) - - used_qubits: list[np.int_] = [] - cnots: list[tuple[int, int]] = [] - while not is_reduced(): - m = np.zeros((checks.shape[1], checks.shape[1]), dtype=bool) - m[used_qubits, :] = True - m[:, used_qubits] = True - - costs_unused = np.ma.array(costs, mask=m) # type: ignore[no-untyped-call] - if np.all(costs_unused >= 0) or len(used_qubits) == checks.shape[1]: # no more reductions possible - if not used_qubits: # local minimum => get out by making matrix triangular - logging.warning("Local minimum reached. Making matrix triangular.") - checks = mod2.reduced_row_echelon(checks)[0] - costs = np.array([ - [np.sum((checks[:, i] + checks[:, j]) % 2) for j in range(checks.shape[1])] - for i in range(checks.shape[1]) - ]) - costs -= np.sum(checks, axis=0) - np.fill_diagonal(costs, 1) - else: # try to move onto the next layer - used_qubits = [] - continue - - i, j = np.unravel_index(np.argmin(costs_unused), costs.shape) - cnots.append((int(i), int(j))) - - if optimize_depth: - used_qubits.append(i) - used_qubits.append(j) - - # update checks - checks[:, j] = (checks[:, i] + checks[:, j]) % 2 - # update costs - new_weights = np.sum((checks[:, j][:, np.newaxis] + checks) % 2, axis=0) - costs[j, :] = new_weights - np.sum(checks, axis=0) - costs[:, j] = new_weights - np.sum(checks[:, j]) - np.fill_diagonal(costs, 1) - - circ = _build_circuit_from_list_and_checks(cnots, checks, zero_state) - return StatePrepCircuit(circ, code, zero_state) - - -def _generate_circ_with_bounded_depth( - checks: npt.NDArray[np.int8], max_depth: int, zero_state: bool = True -) -> QuantumCircuit | None: - assert max_depth > 0, "max_depth should be greater than 0" - columns = np.array([ - [[z3.Bool(f"x_{d}_{i}_{j}") for j in range(checks.shape[1])] for i in range(checks.shape[0])] - for d in range(max_depth + 1) - ]) - - additions = np.array([ - [[z3.Bool(f"add_{d}_{i}_{j}") for j in range(checks.shape[1])] for i in range(checks.shape[1])] - for d in range(max_depth) - ]) - n_cols = checks.shape[1] - s = z3.Solver() - - # create initial matrix - columns[0, :, :] = checks.astype(bool) - - s.add(_column_addition_constraint(columns, additions)) - - # qubit can be involved in at most one addition at each depth - for d in range(max_depth): - for col in range(n_cols): - s.add( - z3.PbLe( - [(additions[d, col_1, col], 1) for col_1 in range(n_cols) if col != col_1] - + [(additions[d, col, col_2], 1) for col_2 in range(n_cols) if col != col_2], - 1, - ) - ) - - # if column is not involved in any addition at certain depth, it is the same as the previous column - for d in range(1, max_depth + 1): - for col in range(n_cols): - s.add( - z3.Implies( - z3.Not( - z3.Or( - list(np.delete(additions[d - 1, :, col], [col])) - + list(np.delete(additions[d - 1, col, :], [col])) - ) - ), - symbolic_vector_eq(columns[d, :, col], columns[d - 1, :, col]), - ) - ) - - s.add(_final_matrix_constraint(columns)) - - if s.check() == z3.sat: - m = s.model() - cnots = [ - (i, j) - for d in range(max_depth) - for j in range(checks.shape[1]) - for i in range(checks.shape[1]) - if m[additions[d, i, j]] - ] - - checks = np.array([ - [bool(m[columns[max_depth, i, j]]) for j in range(checks.shape[1])] for i in range(checks.shape[0]) - ]) - - return _build_circuit_from_list_and_checks(cnots, checks, zero_state=zero_state) - - return None - -def _generate_circ_with_bounded_gates( - checks: npt.NDArray[np.int8], max_cnots: int, zero_state: bool = True -) -> QuantumCircuit | None: - """Find the gate optimal circuit for a given check matrix and maximum depth.""" - n = checks.shape[1] - columns = np.array([ - [[z3.Bool(f"x_{d}_{i}_{j}") for j in range(n)] for i in range(checks.shape[0])] for d in range(max_cnots + 1) - ]) - n_bits = int(np.ceil(np.log2(n))) - targets = [z3.BitVec(f"target_{d}", n_bits) for d in range(max_cnots)] - controls = [z3.BitVec(f"control_{d}", n_bits) for d in range(max_cnots)] - s = z3.Solver() - - additions = np.array([ - [[z3.And(controls[d] == col_1, targets[d] == col_2) for col_2 in range(n)] for col_1 in range(n)] - for d in range(max_cnots) - ]) - - # create initial matrix - columns[0, :, :] = checks.astype(bool) - s.add(_column_addition_constraint(columns, additions)) - - for d in range(1, max_cnots + 1): - # qubit cannot be control and target at the same time - s.add(controls[d - 1] != targets[d - 1]) - - # control and target must be valid qubits - - if n and (n - 1) != 0 and not ((n & (n - 1) == 0) and n != 0): # check if n is a power of 2 or 1 or 0 - s.add(z3.ULT(controls[d - 1], n)) - s.add(z3.ULT(targets[d - 1], n)) - - # if column is not involved in any addition at certain depth, it is the same as the previous column - for d in range(1, max_cnots + 1): - for col in range(n): - s.add(z3.Implies(targets[d - 1] != col, symbolic_vector_eq(columns[d, :, col], columns[d - 1, :, col]))) - - # assert that final check matrix has n-checks.shape[0] zero columns - s.add(_final_matrix_constraint(columns)) - - if s.check() == z3.sat: - m = s.model() - cnots = [(m[controls[d]].as_long(), m[targets[d]].as_long()) for d in range(max_cnots)] - checks = np.array([ - [bool(m[columns[max_cnots][i][j]]) for j in range(n)] for i in range(checks.shape[0]) - ]).astype(int) - return _build_circuit_from_list_and_checks(cnots, checks, zero_state=zero_state) - - return None - - -def _optimal_circuit( - code: CSSCode, - prep_func: Callable[[npt.NDArray[np.int8], int, bool], QuantumCircuit | None], - zero_state: bool = True, - min_param: int = 1, - max_param: int = 10, - min_timeout: int = 1, - max_timeout: int = 3600, -) -> StatePrepCircuit | None: - """Synthesize a state preparation circuit for a CSS code that minimizes the circuit w.r.t. some metric param according to prep_func. - - Args: - code: The CSS code to prepare the state for. - zero_state: If True, prepare the +1 eigenstate of the Z basis. If False, prepare the +1 eigenstate of the X basis. - prep_func: The function to optimize the circuit with respect to. - min_param: minimum parameter to start with - max_param: maximum parameter to reach - min_timeout: minimum timeout to start with - max_timeout: maximum timeout to reach - """ - if code.Hx is None or code.Hz is None: - msg = "Code must have both X and Z stabilizers defined." - raise ValueError(msg) checks = code.Hx if zero_state else code.Hz + assert checks is not None + checks, cnots = heuristic_gaussian_elimination(checks, parallel_elimination=optimize_depth) - def fun(param: int) -> QuantumCircuit | None: - return prep_func(checks, param, zero_state) - - res = iterative_search_with_timeout( - fun, - min_param, - max_param, - min_timeout, - max_timeout, - ) - - circ, curr_param = res - if circ is None: - return None - - logging.info(f"Solution found with param {curr_param}") - # Solving a SAT instance is much faster than proving unsat in this case - # so we iterate backwards until we find an unsat instance or hit a timeout - logging.info("Trying to minimize param") - while True: - logging.info(f"Trying param {curr_param - 1}") - opt_res: QuantumCircuit | str | None = run_with_timeout(fun, curr_param - 1, timeout=max_timeout) - if opt_res and not (isinstance(opt_res, str) and opt_res == "timeout"): - circ = opt_res - curr_param -= 1 - else: - break - - logging.info(f"Optimal param: {curr_param}") + circ = _build_state_prep_circuit_from_back(checks, cnots, zero_state) return StatePrepCircuit(circ, code, zero_state) @@ -453,9 +257,23 @@ def depth_optimal_prep_circuit( min_timeout: minimum timeout to start with max_timeout: maximum timeout to reach """ - return _optimal_circuit( - code, _generate_circ_with_bounded_depth, zero_state, min_depth, max_depth, min_timeout, max_timeout + checks = code.Hx if zero_state else code.Hz + assert checks is not None + rank = mod2.rank(checks) + res = optimal_elimination( + checks, + lambda checks: final_matrix_constraint(checks, rank), + "parallel_ops", + min_param=min_depth, + max_param=max_depth, + min_timeout=min_timeout, + max_timeout=max_timeout, ) + if res is None: + return None + checks, cnots = res + circ = _build_state_prep_circuit_from_back(checks, cnots, zero_state) + return StatePrepCircuit(circ, code, zero_state) def gate_optimal_prep_circuit( @@ -476,102 +294,23 @@ def gate_optimal_prep_circuit( min_timeout: minimum timeout to start with max_timeout: maximum timeout to reach """ - return _optimal_circuit( - code, _generate_circ_with_bounded_gates, zero_state, min_gates, max_gates, min_timeout, max_timeout + checks = code.Hx if zero_state else code.Hz + assert checks is not None + rank = mod2.rank(checks) + res = optimal_elimination( + checks, + lambda checks: final_matrix_constraint(checks, rank), + "column_ops", + min_param=min_gates, + max_param=max_gates, + min_timeout=min_timeout, + max_timeout=max_timeout, ) - - -def _build_circuit_from_list_and_checks( - cnots: list[tuple[int, int]], checks: npt.NDArray[np.int8], zero_state: bool = True -) -> QuantumCircuit: - # Build circuit - n = checks.shape[1] - circ = QuantumCircuit(n) - - controls = [i for i in range(n) if np.sum(checks[:, i]) >= 1] - if zero_state: - for control in controls: - circ.h(control) - else: - for i in range(n): - if i not in controls: - circ.h(i) - - for i, j in reversed(cnots): - if zero_state: - ctrl, tar = i, j - else: - ctrl, tar = j, i - circ.cx(ctrl, tar) - return circ - - -S = TypeVar("S") - - -def run_with_timeout(func: Callable[[Any], S | None], *args: Any, timeout: int = 10) -> S | str | None: # noqa: ANN401 - """Run a function with a timeout. - - If the function does not complete within the timeout, return None. - - Args: - func: The function to run. - args: The arguments to pass to the function. - timeout: The maximum time to allow the function to run for in seconds. - """ - manager = multiprocess.Manager() - return_list = manager.list() - p = multiprocess.Process(target=lambda: return_list.append(func(*args))) - p.start() - p.join(timeout) - if p.is_alive(): - p.terminate() - return "timeout" - if return_list[0] is None: + if res is None: return None - return cast(S, return_list[0]) - - -T = TypeVar("T") - - -def iterative_search_with_timeout( - fun: Callable[[int], T], - min_param: int, - max_param: int, - min_timeout: int, - max_timeout: int, - param_factor: float = 2, - timeout_factor: float = 2, -) -> tuple[T | None, int]: - """Geometrically increases the parameter and timeout until a result is found or the maximum timeout is reached. - - Args: - fun: function to run with increasing parameters and timeouts - min_param: minimum parameter to start with - max_param: maximum parameter to reach - min_timeout: minimum timeout to start with - max_timeout: maximum timeout to reach - param_factor: factor to increase the parameter by at each iteration - timeout_factor: factor to increase the timeout by at each iteration - """ - curr_timeout = min_timeout - curr_param = min_param - while curr_timeout <= max_timeout: - while curr_param <= max_param: - logging.info(f"Running iterative search with param={curr_param} and timeout={curr_timeout}") - res = run_with_timeout(fun, curr_param, timeout=curr_timeout) - if res is not None and (not isinstance(res, str) or res != "timeout"): - return cast(T, res), curr_param - if curr_param == max_param: - break - - curr_param = int(curr_param * param_factor) - curr_param = min(curr_param, max_param) - - curr_timeout = int(curr_timeout * timeout_factor) - curr_param = min_param - return None, max_param + checks, cnots = res + circ = _build_state_prep_circuit_from_back(checks, cnots, zero_state) + return StatePrepCircuit(circ, code, zero_state) def gate_optimal_verification_stabilizers( @@ -682,7 +421,11 @@ def fun(num_cnots: int) -> list[npt.NDArray[np.int8]] | None: max_timeout, ) - measurements, num_cnots = res + if res is not None: + measurements, num_cnots = res + else: + measurements = None + if measurements is None: logging.info(f"No verification stabilizers found for {num_errors} errors") return [] # No solution found @@ -1062,9 +805,9 @@ def vars_to_stab( measurement: list[z3.BoolRef | bool], generators: npt.NDArray[np.int8] ) -> npt.NDArray[z3.BoolRef | bool]: """Compute the stabilizer measured giving the generators and the measurement variables.""" - measurement_stab = _symbolic_scalar_mult(generators[0], measurement[0]) + measurement_stab = symbolic_scalar_mult(generators[0], measurement[0]) for i, scalar in enumerate(measurement[1:]): - measurement_stab = _symbolic_vector_add(measurement_stab, _symbolic_scalar_mult(generators[i + 1], scalar)) + measurement_stab = symbolic_vector_add(measurement_stab, symbolic_scalar_mult(generators[i + 1], scalar)) return measurement_stab @@ -1166,7 +909,7 @@ def coset_leader(error: npt.NDArray[np.int8], generators: npt.NDArray[np.int8]) g = vars_to_stab(coeff, generators) - s.add(symbolic_vector_eq(np.array(leader), _symbolic_vector_add(error.astype(bool), g))) + s.add(symbolic_vector_eq(np.array(leader), symbolic_vector_add(error.astype(bool), g))) s.minimize(z3.Sum(leader)) s.check() # always SAT @@ -1174,124 +917,6 @@ def coset_leader(error: npt.NDArray[np.int8], generators: npt.NDArray[np.int8]) return np.array([bool(m[leader[i]]) for i in range(len(error))]).astype(int) -def _symbolic_scalar_mult(v: npt.NDArray[np.int8], a: z3.BoolRef | bool) -> npt.NDArray[z3.BoolRef]: - """Multiply a concrete vector by a symbolic scalar.""" - return np.array([a if s == 1 else False for s in v]) - - -def _symbolic_vector_add( - v1: npt.NDArray[z3.BoolRef | bool], v2: npt.NDArray[z3.BoolRef | bool] -) -> npt.NDArray[z3.BoolRef | bool]: - """Add two symbolic vectors.""" - v_new = [False for _ in range(len(v1))] - for i in range(len(v1)): - # If one of the elements is a bool, we can simplify the expression - v1_i_is_bool = isinstance(v1[i], (bool, np.bool_)) - v2_i_is_bool = isinstance(v2[i], (bool, np.bool_)) - if v1_i_is_bool: - v1[i] = bool(v1[i]) - if v1[i]: - v_new[i] = z3.Not(v2[i]) if not v2_i_is_bool else not v2[i] - else: - v_new[i] = v2[i] - - elif v2_i_is_bool: - v2[i] = bool(v2[i]) - if v2[i]: - v_new[i] = z3.Not(v1[i]) - else: - v_new[i] = v1[i] - - else: - v_new[i] = z3.Xor(v1[i], v2[i]) - - return np.array(v_new) - - -def odd_overlap(v_sym: npt.NDArray[z3.BoolRef | bool], v_con: npt.NDArray[np.int8]) -> z3.BoolRef: - """Return True if the overlap of symbolic vector with constant vector is odd.""" - if np.array_equal(v_con, np.zeros(len(v_con), dtype=np.int8)): - return z3.BoolVal(False) - return z3.PbEq([(v_sym[i], 1) for i, c in enumerate(v_con) if c == 1], 1) - - -def symbolic_vector_eq(v1: npt.NDArray[z3.BoolRef | bool], v2: npt.NDArray[z3.BoolRef | bool]) -> z3.BoolRef: - """Return assertion that two symbolic vectors should be equal.""" - constraints = [False for _ in v1] - - def convert_bools(vector: Iterable[z3.BoolRef | bool | np.bool_]) -> list[z3.BoolRef | bool]: - return [ - True if z3.is_true(v) else False if z3.is_false(v) else v if isinstance(v, z3.BoolRef) else bool(v) - for v in vector - ] - - v1 = convert_bools(v1) - v2 = convert_bools(v2) - - for i in range(len(v1)): - # If one of the elements is a bool, we can simplify the expression - if isinstance(v1[i], bool): - v1[i] = bool(v1[i]) - if v1[i]: - constraints[i] = v2[i] - else: - constraints[i] = z3.Not(v2[i]) if not isinstance(v2[i], bool) else not v2[i] - elif isinstance(v2[i], bool): - v2[i] = bool(v2[i]) - if v2[i]: - constraints[i] = v1[i] - else: - constraints[i] = z3.Not(v1[i]) - else: - constraints[i] = v1[i] == v2[i] - return z3.And(constraints) - - -def _column_addition_constraint( - columns: npt.NDArray[z3.BoolRef | bool], - col_add_vars: npt.NDArray[z3.BoolRef], -) -> z3.BoolRef: - assert len(columns.shape) == 3 - max_depth = col_add_vars.shape[0] - n_cols = col_add_vars.shape[2] - - constraints = [] - for d in range(1, max_depth + 1): - for col_1 in range(n_cols): - for col_2 in range(col_1 + 1, n_cols): - col_sum = _symbolic_vector_add(columns[d - 1, :, col_1], columns[d - 1, :, col_2]) - - # encode col_2 += col_1 - add_col1_to_col2 = z3.Implies( - col_add_vars[d - 1, col_1, col_2], - z3.And( - symbolic_vector_eq(columns[d, :, col_2], col_sum), - symbolic_vector_eq(columns[d, :, col_1], columns[d - 1, :, col_1]), - ), - ) - - # encode col_1 += col_2 - add_col2_to_col1 = z3.Implies( - col_add_vars[d - 1, col_2, col_1], - z3.And( - symbolic_vector_eq(columns[d, :, col_1], col_sum), - symbolic_vector_eq(columns[d, :, col_2], columns[d - 1, :, col_2]), - ), - ) - - constraints.extend([add_col1_to_col2, add_col2_to_col1]) - - return z3.And(constraints) - - -def _final_matrix_constraint(columns: npt.NDArray[z3.BoolRef | bool]) -> z3.BoolRef: - assert len(columns.shape) == 3 - return z3.PbEq( - [(z3.Not(z3.Or(list(columns[-1, :, col]))), 1) for col in range(columns.shape[2])], - columns.shape[2] - columns.shape[1], - ) - - def _propagate_error(nodes: list[DAGNode], n_qubits: int, x_errors: bool = True) -> PauliList: """Propagates a Pauli error through a circuit beginning from first node. @@ -1374,348 +999,6 @@ def naive_verification_circuit(sp_circ: StatePrepCircuit) -> QuantumCircuit: return _measure_ft_stabs(sp_circ, z_measurements * reps, x_measurements * reps) -def w_flag_pattern(w: int) -> list[int]: - """Return the w-flag construction from https://arxiv.org/abs/1708.02246. - - Args: - w: The number of w-flags to construct. - - Returns: - The w-flag pattern. - """ - s1 = [2 * j + 2 for j in reversed(range((w - 4) // 2))] - s2 = [w - 3, 0] - s3 = [2 * j + 1 for j in reversed(range((w - 4) // 2))] - return s1 + s2 + s3 + [w - 2] - - -def _ancilla_cnot(qc: QuantumCircuit, qubit: Qubit | AncillaQubit, ancilla: AncillaQubit, z_measurement: bool) -> None: - if z_measurement: - qc.cx(qubit, ancilla) - else: - qc.cx(ancilla, qubit) - - -def _flag_measure(qc: QuantumCircuit, flag: AncillaQubit, meas_bit: ClBit, z_measurement: bool) -> None: - if z_measurement: - qc.h(flag) - qc.measure(flag, meas_bit) - - -def _flag_reset(qc: QuantumCircuit, flag: AncillaQubit, z_measurement: bool) -> None: - qc.reset(flag) - if z_measurement: - qc.h(flag) - - -def _flag_init(qc: QuantumCircuit, flag: AncillaQubit, z_measurement: bool) -> None: - if z_measurement: - qc.h(flag) - - -def _measure_stab_unflagged( - qc: QuantumCircuit, - stab: list[Qubit] | npt.NDArray[np.int_], - ancilla: AncillaQubit, - measurement_bit: ClBit, - z_measurement: bool = True, -) -> None: - if not z_measurement: - qc.h(ancilla) - qc.cx([ancilla] * len(stab), stab) - qc.h(ancilla) - else: - qc.cx(stab, [ancilla] * len(stab)) - qc.measure(ancilla, measurement_bit) - - -def measure_flagged( - qc: QuantumCircuit, - stab: list[Qubit] | npt.NDArray[np.int_], - ancilla: AncillaQubit, - measurement_bit: ClBit, - t: int, - z_measurement: bool = True, -) -> None: - """Measure a w-flagged stabilizer with the general scheme. - - The measurement is done in place. - - Args: - qc: The quantum circuit to add the measurement to. - stab: The qubits to measure. - ancilla: The ancilla qubit to use for the measurement. - measurement_bit: The classical bit to store the measurement result of the ancilla. - t: The number of errors to protect from. - z_measurement: Whether to measure an X (False) or Z (True) stabilizer. - """ - w = len(stab) - if t == 1: - _measure_stab_one_flagged(qc, stab, ancilla, measurement_bit, z_measurement) - return - - if w < 3 and t == 2: - _measure_stab_unflagged(qc, stab, ancilla, measurement_bit, z_measurement) - return - - if w == 4 and t == 2: - measure_flagged_4(qc, stab, ancilla, measurement_bit, z_measurement) - return - - if w == 6 and t == 2: - measure_flagged_6(qc, stab, ancilla, measurement_bit, z_measurement) - return - - if w == 8 and t == 2: - measure_flagged_8(qc, stab, ancilla, measurement_bit, z_measurement) - return - - if t == 2: - measure_stab_two_flagged(qc, stab, ancilla, measurement_bit, z_measurement) - return - - msg = f"Flagged measurement for w={w} and t={t} not implemented." - raise NotImplementedError(msg) - - -def _measure_stab_one_flagged( - qc: QuantumCircuit, - stab: list[Qubit] | npt.NDArray[np.int_], - ancilla: AncillaQubit, - measurement_bit: ClBit, - z_measurement: bool = True, -) -> None: - """Measure a 1-flagged stabilizer using an optimized scheme.""" - flag_reg = AncillaRegister(1) - meas_reg = ClassicalRegister(1) - qc.add_register(flag_reg) - qc.add_register(meas_reg) - flag = flag_reg[0] - flag_meas = meas_reg[0] - if not z_measurement: - qc.h(ancilla) - - _ancilla_cnot(qc, stab[0], ancilla, z_measurement) - _flag_init(qc, flag, z_measurement) - - _ancilla_cnot(qc, flag, ancilla, z_measurement) - - for q in stab[1:-1]: - _ancilla_cnot(qc, q, ancilla, z_measurement) - - _ancilla_cnot(qc, flag, ancilla, z_measurement) - _flag_measure(qc, flag, flag_meas, z_measurement) - - _ancilla_cnot(qc, stab[-1], ancilla, z_measurement) - - if not z_measurement: - qc.h(ancilla) - qc.measure(ancilla, measurement_bit) - - -def measure_stab_two_flagged( - qc: QuantumCircuit, - stab: list[Qubit] | npt.NDArray[np.int_], - ancilla: AncillaQubit, - measurement_bit: ClBit, - z_measurement: bool = True, -) -> None: - """Measure a 2-flagged stabilizer using the scheme of https://arxiv.org/abs/1708.02246 (page 13).""" - assert len(stab) > 4 - n_flags = (len(stab) + 1) // 2 - 1 - flag_reg = AncillaRegister(n_flags) - meas_reg = ClassicalRegister(n_flags) - - qc.add_register(flag_reg) - qc.add_register(meas_reg) - - if not z_measurement: - qc.h(ancilla) - - _ancilla_cnot(qc, stab[0], ancilla, z_measurement) - - _flag_init(qc, flag_reg[0], z_measurement) - _ancilla_cnot(qc, flag_reg[0], ancilla, z_measurement) - - _ancilla_cnot(qc, stab[1], ancilla, z_measurement) - _flag_init(qc, flag_reg[1], z_measurement) - _ancilla_cnot(qc, flag_reg[1], ancilla, z_measurement) - - cnots = 2 - flags = 2 - for q in stab[2:-2]: - _ancilla_cnot(qc, q, ancilla, z_measurement) - cnots += 1 - if cnots % 2 == 0 and cnots < len(stab) - 2: - _flag_init(qc, flag_reg[flags], z_measurement) - _ancilla_cnot(qc, flag_reg[flags], ancilla, z_measurement) - if cnots >= 7 and cnots % 2 == 1: - _ancilla_cnot(qc, flag_reg[flags - 1], ancilla, z_measurement) - _flag_measure(qc, flag_reg[flags - 1], meas_reg[flags - 1], z_measurement) - flags += 1 - - _ancilla_cnot(qc, flag_reg[0], ancilla, z_measurement) - _flag_measure(qc, flag_reg[0], meas_reg[0], z_measurement) - - _ancilla_cnot(qc, stab[-2], ancilla, z_measurement) - - cnots += 1 - if cnots >= 7 and cnots % 2 == 1: - _ancilla_cnot(qc, flag_reg[flags - 1], ancilla, z_measurement) - _flag_measure(qc, flag_reg[flags - 1], meas_reg[flags - 1], z_measurement) - - _ancilla_cnot(qc, flag_reg[1], ancilla, z_measurement) - _flag_measure(qc, flag_reg[1], meas_reg[1], z_measurement) - - _ancilla_cnot(qc, stab[-1], ancilla, z_measurement) - - cnots += 1 - if cnots >= 7 and cnots % 2 == 1: - _ancilla_cnot(qc, flag_reg[flags - 1], ancilla, z_measurement) - _flag_measure(qc, flag_reg[flags - 1], meas_reg[flags - 1], z_measurement) - if not z_measurement: - qc.h(ancilla) - - qc.measure(ancilla, measurement_bit) - - -def measure_flagged_4( - qc: QuantumCircuit, - stab: list[Qubit] | npt.NDArray[np.int_], - ancilla: AncillaQubit, - measurement_bit: ClBit, - z_measurement: bool = True, -) -> None: - """Measure a 4-flagged stabilizer using an optimized scheme.""" - assert len(stab) == 4 - flag_reg = AncillaRegister(1) - meas_reg = ClassicalRegister(1) - qc.add_register(flag_reg) - qc.add_register(meas_reg) - flag = flag_reg[0] - flag_meas = meas_reg[0] - - if not z_measurement: - qc.h(ancilla) - - _ancilla_cnot(qc, stab[0], ancilla, z_measurement) - _flag_init(qc, flag, z_measurement) - - _ancilla_cnot(qc, flag, ancilla, z_measurement) - - _ancilla_cnot(qc, stab[1], ancilla, z_measurement) - _ancilla_cnot(qc, stab[2], ancilla, z_measurement) - - _ancilla_cnot(qc, flag, ancilla, z_measurement) - _flag_measure(qc, flag, flag_meas, z_measurement) - - _ancilla_cnot(qc, stab[3], ancilla, z_measurement) - - if not z_measurement: - qc.h(ancilla) - qc.measure(ancilla, measurement_bit) - - -def measure_flagged_6( - qc: QuantumCircuit, - stab: list[Qubit] | npt.NDArray[np.int_], - ancilla: AncillaQubit, - measurement_bit: ClBit, - z_measurement: bool = True, -) -> None: - """Measure a 6-flagged stabilizer using an optimized scheme.""" - assert len(stab) == 6 - flag = AncillaRegister(2) - meas = ClassicalRegister(2) - - qc.add_register(flag) - qc.add_register(meas) - - if not z_measurement: - qc.h(ancilla) - - _ancilla_cnot(qc, stab[0], ancilla, z_measurement) - - _flag_init(qc, flag[0], z_measurement) - _ancilla_cnot(qc, flag[0], ancilla, z_measurement) - - _ancilla_cnot(qc, stab[1], ancilla, z_measurement) - - _flag_init(qc, flag[1], z_measurement) - _ancilla_cnot(qc, flag[1], ancilla, z_measurement) - - _ancilla_cnot(qc, stab[2], ancilla, z_measurement) - _ancilla_cnot(qc, stab[3], ancilla, z_measurement) - - _ancilla_cnot(qc, flag[0], ancilla, z_measurement) - _flag_measure(qc, flag[0], meas[0], z_measurement) - - _ancilla_cnot(qc, stab[4], ancilla, z_measurement) - - _ancilla_cnot(qc, flag[1], ancilla, z_measurement) - _flag_measure(qc, flag[1], meas[1], z_measurement) - - _ancilla_cnot(qc, stab[5], ancilla, z_measurement) - - if not z_measurement: - qc.h(ancilla) - qc.measure(ancilla, measurement_bit) - - -def measure_flagged_8( - qc: QuantumCircuit, - stab: list[Qubit] | npt.NDArray[np.int_], - ancilla: AncillaQubit, - measurement_bit: ClBit, - z_measurement: bool = True, -) -> None: - """Measure an 8-flagged stabilizer using an optimized scheme.""" - assert len(stab) == 8 - flag = AncillaRegister(3) - meas = ClassicalRegister(3) - qc.add_register(flag) - qc.add_register(meas) - - if not z_measurement: - qc.h(ancilla) - - _ancilla_cnot(qc, stab[0], ancilla, z_measurement) - - _flag_init(qc, flag[0], z_measurement) - _ancilla_cnot(qc, flag[0], ancilla, z_measurement) - - _ancilla_cnot(qc, stab[1], ancilla, z_measurement) - - _flag_init(qc, flag[1], z_measurement) - _ancilla_cnot(qc, flag[1], ancilla, z_measurement) - - _ancilla_cnot(qc, stab[2], ancilla, z_measurement) - _ancilla_cnot(qc, stab[3], ancilla, z_measurement) - - _flag_init(qc, flag[2], z_measurement) - _ancilla_cnot(qc, flag[2], ancilla, z_measurement) - - _ancilla_cnot(qc, stab[4], ancilla, z_measurement) - _ancilla_cnot(qc, stab[5], ancilla, z_measurement) - - _ancilla_cnot(qc, flag[0], ancilla, z_measurement) - _flag_measure(qc, flag[0], meas[0], z_measurement) - - _ancilla_cnot(qc, stab[6], ancilla, z_measurement) - - _ancilla_cnot(qc, flag[2], ancilla, z_measurement) - _flag_measure(qc, flag[2], meas[2], z_measurement) - - _ancilla_cnot(qc, flag[1], ancilla, z_measurement) - _flag_measure(qc, flag[1], meas[1], z_measurement) - - _ancilla_cnot(qc, stab[7], ancilla, z_measurement) - - if not z_measurement: - qc.h(ancilla) - qc.measure(ancilla, measurement_bit) - - def get_hook_errors(measurements: list[npt.NDArray[np.int8]]) -> npt.NDArray[np.int8]: """Assuming CNOTs are executed in ascending order of qubit index, this function gives all the hook errors of the given stabilizer measurements.""" errors = [] @@ -1727,3 +1010,12 @@ def get_hook_errors(measurements: list[npt.NDArray[np.int8]]) -> npt.NDArray[np. errors.append(error.copy()) return np.array(errors) + + +def final_matrix_constraint(columns: npt.NDArray[z3.BoolRef | bool], rank: int) -> z3.BoolRef: + """Return a z3 constraint that the final matrix has exactly rank non-zero columns.""" + assert len(columns.shape) == 3 + return z3.PbEq( + [(z3.Not(z3.Or(list(columns[-1, :, col]))), 1) for col in range(columns.shape[2])], + columns.shape[2] - rank, + ) diff --git a/src/mqt/qecc/ft_stateprep/state_prep_det.py b/src/mqt/qecc/circuit_synthesis/state_prep_det.py similarity index 99% rename from src/mqt/qecc/ft_stateprep/state_prep_det.py rename to src/mqt/qecc/circuit_synthesis/state_prep_det.py index 76b55ade..69c834df 100644 --- a/src/mqt/qecc/ft_stateprep/state_prep_det.py +++ b/src/mqt/qecc/circuit_synthesis/state_prep_det.py @@ -16,11 +16,13 @@ coset_leader, get_hook_errors, heuristic_verification_stabilizers, + vars_to_stab, +) +from .synthesis_utils import ( iterative_search_with_timeout, odd_overlap, run_with_timeout, symbolic_vector_eq, - vars_to_stab, ) logger = logging.getLogger(__name__) @@ -678,6 +680,8 @@ def _func(num_anc: int) -> Recovery | None: return correction_stabilizers(sp_circ, fault_set, num_anc, num_anc * num_qubits, x_errors=zero_state) res = iterative_search_with_timeout(_func, num_anc, max_ancillas, min_timeout, max_timeout) + + assert res is not None, "No deterministic verification found." assert res[0], "No deterministic verification found." optimal_det_verify: Recovery = res[0] diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/README.md b/src/mqt/qecc/circuit_synthesis/stateprep_eval/README.md new file mode 100644 index 00000000..063154fe --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/README.md @@ -0,0 +1,11 @@ +If you want to run evaluations on the example circuits in this directory, do the following. + +To estimate the logical error rate for a physical error rate p_err, run + +`python estimate_logical_error_rate CODE -p p_err` + +The script prints 4 numbers: logical error rate per qubit, acceptance rate (if using post-selection), number of logical errors, total number of shots + +The python script has further options with which you can select which circuits to construct, how many logical errors should occur before stopping and more. + +To generate these values for a circuit for a range between p_err = 0.5 and p_err = 0.00005, the script `run_eval_on_code FILENAME ARGS` can be used. It runs multiple instances of `estimate_logical_error_rate` in parallel (using GNU Parallel) and stores the results in `FILENAME.csv`. diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_heuristic_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_heuristic_heuristic.qasm new file mode 100644 index 00000000..72ab7dfb --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_heuristic_heuristic.qasm @@ -0,0 +1,55 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[12]; +qreg z_anc[2]; +qreg x_anc[1]; +qreg a47[1]; +creg z_c[2]; +creg x_c[1]; +creg c47[1]; +h q[0]; +h q[1]; +h q[2]; +h q[4]; +h q[7]; +cx q[7],q[11]; +cx q[1],q[5]; +cx q[7],q[9]; +cx q[4],q[10]; +cx q[2],q[8]; +cx q[1],q[3]; +cx q[0],q[6]; +cx q[10],q[9]; +cx q[8],q[7]; +cx q[6],q[11]; +cx q[4],q[3]; +cx q[2],q[1]; +cx q[0],q[5]; +cx q[11],q[10]; +cx q[9],q[8]; +cx q[7],q[6]; +cx q[5],q[4]; +cx q[3],q[2]; +cx q[1],q[0]; +cx q[1],z_anc[0]; +cx q[4],z_anc[0]; +cx q[7],z_anc[0]; +cx q[10],z_anc[0]; +cx q[1],z_anc[1]; +cx q[2],z_anc[1]; +cx q[7],z_anc[1]; +cx q[8],z_anc[1]; +measure z_anc[0] -> z_c[0]; +measure z_anc[1] -> z_c[1]; +h x_anc[0]; +cx x_anc[0],q[0]; +cx x_anc[0],a47[0]; +cx x_anc[0],q[2]; +cx x_anc[0],q[4]; +cx x_anc[0],q[6]; +cx x_anc[0],q[8]; +cx x_anc[0],a47[0]; +measure a47[0] -> c47[0]; +cx x_anc[0],q[10]; +h x_anc[0]; +measure x_anc[0] -> x_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_heuristic_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_heuristic_heuristic.stim new file mode 100644 index 00000000..e4dbf3bf --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_heuristic_heuristic.stim @@ -0,0 +1,9 @@ +H 0 1 2 4 7 +CX 7 11 1 5 7 9 4 10 2 8 1 3 0 6 10 9 8 7 6 11 4 3 2 1 0 5 11 10 9 8 7 6 5 4 3 2 1 0 1 12 4 12 7 12 10 12 1 13 2 13 7 13 8 13 +MR 12 13 +H 14 +CX 14 0 14 15 14 2 14 4 14 6 14 8 14 15 +MR 15 +CX 14 10 +H 14 +MR 14 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_heuristic_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_heuristic_opt.qasm new file mode 100644 index 00000000..de2641bf --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_heuristic_opt.qasm @@ -0,0 +1,57 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[12]; +qreg z_anc[1]; +qreg a9[1]; +qreg x_anc[1]; +qreg a10[1]; +creg z_c[1]; +creg c9[1]; +creg x_c[1]; +creg c10[1]; +h q[1]; +h q[2]; +h q[4]; +h q[6]; +h q[8]; +cx q[1],q[7]; +cx q[6],q[9]; +cx q[2],q[5]; +cx q[7],q[0]; +cx q[7],q[6]; +cx q[4],q[10]; +cx q[5],q[11]; +cx q[9],q[3]; +cx q[10],q[1]; +cx q[8],q[5]; +cx q[7],q[2]; +cx q[8],q[4]; +cx q[8],q[9]; +cx q[2],q[8]; +cx q[9],q[0]; +cx q[4],q[7]; +cx q[0],z_anc[0]; +h a9[0]; +cx a9[0],z_anc[0]; +cx q[2],z_anc[0]; +cx q[3],z_anc[0]; +cx q[4],z_anc[0]; +cx q[10],z_anc[0]; +cx a9[0],z_anc[0]; +h a9[0]; +measure a9[0] -> c9[0]; +cx q[11],z_anc[0]; +measure z_anc[0] -> z_c[0]; +measure z_anc[0] -> z_c[0]; +h x_anc[0]; +cx x_anc[0],q[0]; +cx x_anc[0],a10[0]; +cx x_anc[0],q[3]; +cx x_anc[0],q[7]; +cx x_anc[0],q[8]; +cx x_anc[0],q[10]; +cx x_anc[0],a10[0]; +measure a10[0] -> c10[0]; +cx x_anc[0],q[11]; +h x_anc[0]; +measure x_anc[0] -> x_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_heuristic_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_heuristic_opt.stim new file mode 100644 index 00000000..81c947ea --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_heuristic_opt.stim @@ -0,0 +1,14 @@ +H 1 2 4 6 8 +CX 1 7 6 9 2 5 7 0 7 6 4 10 5 11 9 3 10 1 8 5 7 2 8 4 8 9 2 8 9 0 4 7 0 12 +H 13 +CX 13 12 2 12 3 12 4 12 10 12 13 12 +H 13 +MR 13 +CX 11 12 +MR 12 12 +H 14 +CX 14 0 14 15 14 3 14 7 14 8 14 10 14 15 +MR 15 +CX 14 11 +H 14 +MR 14 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_opt_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_opt_opt.qasm new file mode 100644 index 00000000..56728faa --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_opt_opt.qasm @@ -0,0 +1,49 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[12]; +qreg z_anc[1]; +qreg x_anc[1]; +qreg a62[1]; +creg z_c[1]; +creg x_c[1]; +creg c62[1]; +h q[1]; +h q[2]; +h q[4]; +h q[6]; +h q[8]; +cx q[1],q[7]; +cx q[6],q[9]; +cx q[2],q[5]; +cx q[7],q[0]; +cx q[7],q[6]; +cx q[4],q[10]; +cx q[5],q[11]; +cx q[9],q[3]; +cx q[10],q[1]; +cx q[8],q[5]; +cx q[7],q[2]; +cx q[8],q[4]; +cx q[8],q[9]; +cx q[2],q[8]; +cx q[9],q[0]; +cx q[4],q[7]; +cx q[0],z_anc[0]; +cx q[2],z_anc[0]; +cx q[3],z_anc[0]; +cx q[4],z_anc[0]; +cx q[10],z_anc[0]; +cx q[11],z_anc[0]; +measure z_anc[0] -> z_c[0]; +h x_anc[0]; +cx x_anc[0],q[0]; +cx x_anc[0],a62[0]; +cx x_anc[0],q[1]; +cx x_anc[0],q[5]; +cx x_anc[0],q[6]; +cx x_anc[0],q[7]; +cx x_anc[0],a62[0]; +measure a62[0] -> c62[0]; +cx x_anc[0],q[11]; +h x_anc[0]; +measure x_anc[0] -> x_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_opt_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_opt_opt.stim new file mode 100644 index 00000000..1bfb8af5 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_ft_opt_opt.stim @@ -0,0 +1,9 @@ +H 1 2 4 6 8 +CX 1 7 6 9 2 5 7 0 7 6 4 10 5 11 9 3 10 1 8 5 7 2 8 4 8 9 2 8 9 0 4 7 0 12 2 12 3 12 4 12 10 12 11 12 +MR 12 +H 13 +CX 13 0 13 14 13 1 13 5 13 6 13 7 13 14 +MR 14 +CX 13 11 +H 13 +MR 13 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_non_ft_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_non_ft_heuristic.qasm new file mode 100644 index 00000000..7cbb7eec --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_non_ft_heuristic.qasm @@ -0,0 +1,24 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[12]; +h q[1]; +h q[2]; +h q[4]; +h q[6]; +h q[8]; +cx q[1],q[7]; +cx q[6],q[9]; +cx q[2],q[5]; +cx q[7],q[0]; +cx q[7],q[6]; +cx q[4],q[10]; +cx q[5],q[11]; +cx q[9],q[3]; +cx q[10],q[1]; +cx q[8],q[5]; +cx q[7],q[2]; +cx q[8],q[4]; +cx q[8],q[9]; +cx q[2],q[8]; +cx q[9],q[0]; +cx q[4],q[7]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_non_ft_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_non_ft_heuristic.stim new file mode 100644 index 00000000..a4ce9bda --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_non_ft_heuristic.stim @@ -0,0 +1,2 @@ +H 1 2 4 6 8 +CX 1 7 6 9 2 5 7 0 7 6 4 10 5 11 9 3 10 1 8 5 7 2 8 4 8 9 2 8 9 0 4 7 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_non_ft_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_non_ft_opt.qasm new file mode 100644 index 00000000..7cbb7eec --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_non_ft_opt.qasm @@ -0,0 +1,24 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[12]; +h q[1]; +h q[2]; +h q[4]; +h q[6]; +h q[8]; +cx q[1],q[7]; +cx q[6],q[9]; +cx q[2],q[5]; +cx q[7],q[0]; +cx q[7],q[6]; +cx q[4],q[10]; +cx q[5],q[11]; +cx q[9],q[3]; +cx q[10],q[1]; +cx q[8],q[5]; +cx q[7],q[2]; +cx q[8],q[4]; +cx q[8],q[9]; +cx q[2],q[8]; +cx q[9],q[0]; +cx q[4],q[7]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_non_ft_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_non_ft_opt.stim new file mode 100644 index 00000000..a4ce9bda --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/carbon/zero_non_ft_opt.stim @@ -0,0 +1,2 @@ +H 1 2 4 6 8 +CX 1 7 6 9 2 5 7 0 7 6 4 10 5 11 9 3 10 1 8 5 7 2 8 4 8 9 2 8 9 0 4 7 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_4_8_8/zero_ft_heuristic_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_4_8_8/zero_ft_heuristic_opt.qasm new file mode 100644 index 00000000..2d1a8358 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_4_8_8/zero_ft_heuristic_opt.qasm @@ -0,0 +1,111 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[17]; +qreg z_anc[5]; +qreg x_anc[3]; +qreg a12[3]; +qreg a13[1]; +qreg a14[1]; +creg z_c[5]; +creg x_c[3]; +creg c12[3]; +creg c13[1]; +creg c14[1]; +h q[0]; +h q[1]; +h q[2]; +h q[3]; +h q[4]; +h q[5]; +h q[9]; +h q[10]; +cx q[4],q[8]; +cx q[10],q[15]; +cx q[4],q[6]; +cx q[9],q[15]; +cx q[5],q[12]; +cx q[4],q[7]; +cx q[3],q[14]; +cx q[2],q[6]; +cx q[14],q[16]; +cx q[10],q[13]; +cx q[9],q[11]; +cx q[8],q[5]; +cx q[3],q[7]; +cx q[1],q[4]; +cx q[0],q[2]; +cx q[12],q[9]; +cx q[1],q[13]; +cx q[0],q[3]; +cx q[15],q[8]; +cx q[6],q[16]; +cx q[5],q[11]; +cx q[4],q[10]; +cx q[2],q[14]; +cx q[1],z_anc[0]; +cx q[5],z_anc[0]; +cx q[9],z_anc[0]; +cx q[10],z_anc[0]; +cx q[15],z_anc[0]; +cx q[0],z_anc[1]; +cx q[2],z_anc[1]; +cx q[7],z_anc[1]; +cx q[16],z_anc[1]; +cx q[0],z_anc[2]; +cx q[2],z_anc[2]; +cx q[7],z_anc[2]; +cx q[16],z_anc[2]; +cx q[1],z_anc[3]; +cx q[3],z_anc[3]; +cx q[4],z_anc[3]; +cx q[6],z_anc[3]; +cx q[14],z_anc[3]; +cx q[1],z_anc[4]; +cx q[4],z_anc[4]; +cx q[9],z_anc[4]; +cx q[11],z_anc[4]; +measure z_anc[0] -> z_c[0]; +measure z_anc[1] -> z_c[1]; +measure z_anc[2] -> z_c[2]; +measure z_anc[3] -> z_c[3]; +measure z_anc[4] -> z_c[4]; +h x_anc[0]; +cx x_anc[0],q[0]; +cx x_anc[0],a12[0]; +cx x_anc[0],q[1]; +cx x_anc[0],a12[1]; +cx x_anc[0],q[8]; +cx x_anc[0],q[10]; +cx x_anc[0],a12[2]; +cx x_anc[0],q[11]; +cx x_anc[0],q[12]; +cx x_anc[0],a12[0]; +measure a12[0] -> c12[0]; +cx x_anc[0],q[14]; +cx x_anc[0],a12[2]; +measure a12[2] -> c12[2]; +cx x_anc[0],a12[1]; +measure a12[1] -> c12[1]; +cx x_anc[0],q[16]; +h x_anc[0]; +measure x_anc[0] -> x_c[0]; +h x_anc[1]; +cx x_anc[1],q[5]; +cx x_anc[1],a13[0]; +cx x_anc[1],q[10]; +cx x_anc[1],q[12]; +cx x_anc[1],a13[0]; +measure a13[0] -> c13[0]; +cx x_anc[1],q[13]; +h x_anc[1]; +measure x_anc[1] -> x_c[1]; +h x_anc[2]; +cx x_anc[2],q[1]; +cx x_anc[2],a14[0]; +cx x_anc[2],q[4]; +cx x_anc[2],q[10]; +cx x_anc[2],a14[0]; +measure a14[0] -> c14[0]; +cx x_anc[2],q[13]; +h x_anc[2]; +measure x_anc[2] -> x_c[2]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_4_8_8/zero_ft_heuristic_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_4_8_8/zero_ft_heuristic_opt.stim new file mode 100644 index 00000000..743ad4d7 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_4_8_8/zero_ft_heuristic_opt.stim @@ -0,0 +1,25 @@ +H 0 1 2 3 4 5 9 10 +CX 4 8 10 15 4 6 9 15 5 12 4 7 3 14 2 6 14 16 10 13 9 11 8 5 3 7 1 4 0 2 12 9 1 13 0 3 15 8 6 16 5 11 4 10 2 14 1 17 5 17 9 17 10 17 15 17 0 18 2 18 7 18 16 18 0 19 2 19 7 19 16 19 1 20 3 20 4 20 6 20 14 20 1 21 4 21 9 21 11 21 +MR 17 18 19 20 21 +H 22 +CX 22 0 22 25 22 1 22 26 22 8 22 10 22 27 22 11 22 12 22 25 +MR 25 +CX 22 14 22 27 +MR 27 +CX 22 26 +MR 26 +CX 22 16 +H 22 +MR 22 +H 23 +CX 23 5 23 28 23 10 23 12 23 28 +MR 28 +CX 23 13 +H 23 +MR 23 +H 24 +CX 24 1 24 29 24 4 24 10 24 29 +MR 29 +CX 24 13 +H 24 +MR 24 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_4_8_8/zero_non_ft_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_4_8_8/zero_non_ft_heuristic.qasm new file mode 100644 index 00000000..f5eed9e6 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_4_8_8/zero_non_ft_heuristic.qasm @@ -0,0 +1,34 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[17]; +h q[0]; +h q[1]; +h q[2]; +h q[3]; +h q[4]; +h q[5]; +h q[9]; +h q[10]; +cx q[4],q[8]; +cx q[10],q[15]; +cx q[4],q[6]; +cx q[9],q[15]; +cx q[5],q[12]; +cx q[4],q[7]; +cx q[3],q[14]; +cx q[2],q[6]; +cx q[14],q[16]; +cx q[10],q[13]; +cx q[9],q[11]; +cx q[8],q[5]; +cx q[3],q[7]; +cx q[1],q[4]; +cx q[0],q[2]; +cx q[12],q[9]; +cx q[1],q[13]; +cx q[0],q[3]; +cx q[15],q[8]; +cx q[6],q[16]; +cx q[5],q[11]; +cx q[4],q[10]; +cx q[2],q[14]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_4_8_8/zero_non_ft_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_4_8_8/zero_non_ft_heuristic.stim new file mode 100644 index 00000000..ab3b38c6 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_4_8_8/zero_non_ft_heuristic.stim @@ -0,0 +1,2 @@ +H 0 1 2 3 4 5 9 10 +CX 4 8 10 15 4 6 9 15 5 12 4 7 3 14 2 6 14 16 10 13 9 11 8 5 3 7 1 4 0 2 12 9 1 13 0 3 15 8 6 16 5 11 4 10 2 14 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_6_6_6/zero_ft_heuristic_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_6_6_6/zero_ft_heuristic_opt.qasm new file mode 100644 index 00000000..d66d97cf --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_6_6_6/zero_ft_heuristic_opt.qasm @@ -0,0 +1,184 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[19]; +qreg z_anc[6]; +qreg x_anc[6]; +qreg a6[3]; +qreg a7[2]; +qreg a8[1]; +qreg a9[2]; +qreg a10[2]; +qreg a11[2]; +creg z_c[6]; +creg x_c[6]; +creg c6[3]; +creg c7[2]; +creg c8[1]; +creg c9[2]; +creg c10[2]; +creg c11[2]; +h q[0]; +h q[1]; +h q[2]; +h q[3]; +h q[4]; +h q[5]; +h q[6]; +h q[10]; +h q[12]; +cx q[6],q[16]; +cx q[4],q[13]; +cx q[3],q[7]; +cx q[12],q[17]; +cx q[10],q[18]; +cx q[7],q[11]; +cx q[6],q[3]; +cx q[4],q[8]; +cx q[2],q[16]; +cx q[1],q[15]; +cx q[0],q[14]; +cx q[11],q[12]; +cx q[10],q[13]; +cx q[8],q[9]; +cx q[6],q[0]; +cx q[5],q[2]; +cx q[4],q[3]; +cx q[1],q[7]; +cx q[17],q[18]; +cx q[14],q[15]; +cx q[5],q[9]; +cx q[16],q[4]; +cx q[13],q[11]; +cx q[12],q[10]; +cx q[7],q[6]; +cx q[2],q[8]; +cx q[0],q[1]; +cx q[0],z_anc[0]; +cx q[5],z_anc[0]; +cx q[6],z_anc[0]; +cx q[9],z_anc[0]; +cx q[12],z_anc[0]; +cx q[13],z_anc[0]; +cx q[15],z_anc[0]; +cx q[18],z_anc[0]; +cx q[4],z_anc[1]; +cx q[5],z_anc[1]; +cx q[6],z_anc[1]; +cx q[7],z_anc[1]; +cx q[8],z_anc[1]; +cx q[0],z_anc[2]; +cx q[2],z_anc[2]; +cx q[3],z_anc[2]; +cx q[7],z_anc[2]; +cx q[8],z_anc[2]; +cx q[15],z_anc[2]; +cx q[1],z_anc[3]; +cx q[6],z_anc[3]; +cx q[11],z_anc[3]; +cx q[13],z_anc[3]; +cx q[14],z_anc[3]; +cx q[1],z_anc[4]; +cx q[2],z_anc[4]; +cx q[5],z_anc[4]; +cx q[15],z_anc[4]; +cx q[16],z_anc[4]; +cx q[4],z_anc[5]; +cx q[5],z_anc[5]; +cx q[9],z_anc[5]; +cx q[16],z_anc[5]; +measure z_anc[0] -> z_c[0]; +measure z_anc[1] -> z_c[1]; +measure z_anc[2] -> z_c[2]; +measure z_anc[3] -> z_c[3]; +measure z_anc[4] -> z_c[4]; +measure z_anc[5] -> z_c[5]; +h x_anc[0]; +cx x_anc[0],q[1]; +cx x_anc[0],a6[0]; +cx x_anc[0],q[2]; +cx x_anc[0],a6[1]; +cx x_anc[0],q[4]; +cx x_anc[0],q[5]; +cx x_anc[0],a6[2]; +cx x_anc[0],q[10]; +cx x_anc[0],q[11]; +cx x_anc[0],a6[0]; +measure a6[0] -> c6[0]; +cx x_anc[0],q[15]; +cx x_anc[0],a6[2]; +measure a6[2] -> c6[2]; +cx x_anc[0],a6[1]; +measure a6[1] -> c6[1]; +cx x_anc[0],q[17]; +h x_anc[0]; +measure x_anc[0] -> x_c[0]; +h x_anc[1]; +cx x_anc[1],q[1]; +cx x_anc[1],a7[0]; +cx x_anc[1],q[3]; +cx x_anc[1],a7[1]; +cx x_anc[1],q[5]; +cx x_anc[1],q[7]; +cx x_anc[1],a7[0]; +measure a7[0] -> c7[0]; +cx x_anc[1],q[9]; +cx x_anc[1],a7[1]; +measure a7[1] -> c7[1]; +cx x_anc[1],q[14]; +h x_anc[1]; +measure x_anc[1] -> x_c[1]; +h x_anc[2]; +cx x_anc[2],q[0]; +cx x_anc[2],a8[0]; +cx x_anc[2],q[1]; +cx x_anc[2],q[14]; +cx x_anc[2],a8[0]; +measure a8[0] -> c8[0]; +cx x_anc[2],q[15]; +h x_anc[2]; +measure x_anc[2] -> x_c[2]; +h x_anc[3]; +cx x_anc[3],q[1]; +cx x_anc[3],a9[0]; +cx x_anc[3],q[3]; +cx x_anc[3],a9[1]; +cx x_anc[3],q[12]; +cx x_anc[3],q[13]; +cx x_anc[3],a9[0]; +measure a9[0] -> c9[0]; +cx x_anc[3],q[15]; +cx x_anc[3],a9[1]; +measure a9[1] -> c9[1]; +cx x_anc[3],q[18]; +h x_anc[3]; +measure x_anc[3] -> x_c[3]; +h x_anc[4]; +cx x_anc[4],q[2]; +cx x_anc[4],a10[0]; +cx x_anc[4],q[3]; +cx x_anc[4],a10[1]; +cx x_anc[4],q[9]; +cx x_anc[4],q[12]; +cx x_anc[4],a10[0]; +measure a10[0] -> c10[0]; +cx x_anc[4],q[16]; +cx x_anc[4],a10[1]; +measure a10[1] -> c10[1]; +cx x_anc[4],q[17]; +h x_anc[4]; +measure x_anc[4] -> x_c[4]; +h x_anc[5]; +cx x_anc[5],q[0]; +cx x_anc[5],a11[0]; +cx x_anc[5],q[3]; +cx x_anc[5],a11[1]; +cx x_anc[5],q[5]; +cx x_anc[5],q[7]; +cx x_anc[5],a11[0]; +measure a11[0] -> c11[0]; +cx x_anc[5],q[9]; +cx x_anc[5],a11[1]; +measure a11[1] -> c11[1]; +cx x_anc[5],q[15]; +h x_anc[5]; +measure x_anc[5] -> x_c[5]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_6_6_6/zero_ft_heuristic_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_6_6_6/zero_ft_heuristic_opt.stim new file mode 100644 index 00000000..97e23c24 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_6_6_6/zero_ft_heuristic_opt.stim @@ -0,0 +1,51 @@ +H 0 1 2 3 4 5 6 10 12 +CX 6 16 4 13 3 7 12 17 10 18 7 11 6 3 4 8 2 16 1 15 0 14 11 12 10 13 8 9 6 0 5 2 4 3 1 7 17 18 14 15 5 9 16 4 13 11 12 10 7 6 2 8 0 1 0 19 5 19 6 19 9 19 12 19 13 19 15 19 18 19 4 20 5 20 6 20 7 20 8 20 0 21 2 21 3 21 7 21 8 21 15 21 1 22 6 22 11 22 13 22 14 22 1 23 2 23 5 23 15 23 16 23 4 24 5 24 9 24 16 24 +MR 19 20 21 22 23 24 +H 25 +CX 25 1 25 31 25 2 25 32 25 4 25 5 25 33 25 10 25 11 25 31 +MR 31 +CX 25 15 25 33 +MR 33 +CX 25 32 +MR 32 +CX 25 17 +H 25 +MR 25 +H 26 +CX 26 1 26 34 26 3 26 35 26 5 26 7 26 34 +MR 34 +CX 26 9 26 35 +MR 35 +CX 26 14 +H 26 +MR 26 +H 27 +CX 27 0 27 36 27 1 27 14 27 36 +MR 36 +CX 27 15 +H 27 +MR 27 +H 28 +CX 28 1 28 37 28 3 28 38 28 12 28 13 28 37 +MR 37 +CX 28 15 28 38 +MR 38 +CX 28 18 +H 28 +MR 28 +H 29 +CX 29 2 29 39 29 3 29 40 29 9 29 12 29 39 +MR 39 +CX 29 16 29 40 +MR 40 +CX 29 17 +H 29 +MR 29 +H 30 +CX 30 0 30 41 30 3 30 42 30 5 30 7 30 41 +MR 41 +CX 30 9 30 42 +MR 42 +CX 30 15 +H 30 +MR 30 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_6_6_6/zero_non_ft_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_6_6_6/zero_non_ft_heuristic.qasm new file mode 100644 index 00000000..c7bfbf84 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_6_6_6/zero_non_ft_heuristic.qasm @@ -0,0 +1,39 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[19]; +h q[0]; +h q[1]; +h q[2]; +h q[3]; +h q[4]; +h q[5]; +h q[6]; +h q[10]; +h q[12]; +cx q[6],q[16]; +cx q[4],q[13]; +cx q[3],q[7]; +cx q[12],q[17]; +cx q[10],q[18]; +cx q[7],q[11]; +cx q[6],q[3]; +cx q[4],q[8]; +cx q[2],q[16]; +cx q[1],q[15]; +cx q[0],q[14]; +cx q[11],q[12]; +cx q[10],q[13]; +cx q[8],q[9]; +cx q[6],q[0]; +cx q[5],q[2]; +cx q[4],q[3]; +cx q[1],q[7]; +cx q[17],q[18]; +cx q[14],q[15]; +cx q[5],q[9]; +cx q[16],q[4]; +cx q[13],q[11]; +cx q[12],q[10]; +cx q[7],q[6]; +cx q[2],q[8]; +cx q[0],q[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_6_6_6/zero_non_ft_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_6_6_6/zero_non_ft_heuristic.stim new file mode 100644 index 00000000..e54faf79 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/cc_6_6_6/zero_non_ft_heuristic.stim @@ -0,0 +1,2 @@ +H 0 1 2 3 4 5 6 10 12 +CX 6 16 4 13 3 7 12 17 10 18 7 11 6 3 4 8 2 16 1 15 0 14 11 12 10 13 8 9 6 0 5 2 4 3 1 7 17 18 14 15 5 9 16 4 13 11 12 10 7 6 2 8 0 1 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_heuristic_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_heuristic_heuristic.qasm new file mode 100644 index 00000000..99728fb0 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_heuristic_heuristic.qasm @@ -0,0 +1,57 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +qreg x_anc[2]; +creg x_c[2]; +h q[2]; +h q[4]; +h q[5]; +h q[6]; +h q[8]; +h q[9]; +h q[10]; +h q[11]; +h q[12]; +h q[13]; +h q[14]; +cx q[11],q[7]; +cx q[5],q[3]; +cx q[2],q[1]; +cx q[13],q[11]; +cx q[9],q[7]; +cx q[6],q[5]; +cx q[4],q[3]; +cx q[2],q[0]; +cx q[14],q[13]; +cx q[12],q[11]; +cx q[10],q[9]; +cx q[8],q[7]; +cx q[5],q[1]; +cx q[4],q[0]; +cx q[6],q[2]; +cx q[11],q[3]; +cx q[9],q[1]; +cx q[8],q[0]; +cx q[13],q[5]; +cx q[12],q[4]; +cx q[10],q[2]; +cx q[14],q[6]; +h x_anc[0]; +cx x_anc[0],q[0]; +cx x_anc[0],q[2]; +cx x_anc[0],q[4]; +cx x_anc[0],q[6]; +cx x_anc[0],q[7]; +cx x_anc[0],q[9]; +cx x_anc[0],q[11]; +cx x_anc[0],q[13]; +h x_anc[0]; +h x_anc[1]; +cx x_anc[1],q[5]; +cx x_anc[1],q[9]; +cx x_anc[1],q[12]; +cx x_anc[1],q[13]; +cx x_anc[1],q[14]; +h x_anc[1]; +measure x_anc[0] -> x_c[0]; +measure x_anc[1] -> x_c[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_heuristic_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_heuristic_heuristic.stim new file mode 100644 index 00000000..cd14b363 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_heuristic_heuristic.stim @@ -0,0 +1,8 @@ +H 2 4 5 6 8 9 10 11 12 13 14 +CX 11 7 5 3 2 1 13 11 9 7 6 5 4 3 2 0 14 13 12 11 10 9 8 7 5 1 4 0 6 2 11 3 9 1 8 0 13 5 12 4 10 2 14 6 +H 15 +CX 15 0 15 2 15 4 15 6 15 7 15 9 15 11 15 13 +H 15 16 +CX 16 5 16 9 16 12 16 13 16 14 +H 16 +MR 15 16 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_heuristic_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_heuristic_opt.qasm new file mode 100644 index 00000000..19cae239 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_heuristic_opt.qasm @@ -0,0 +1,51 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +qreg x_anc[2]; +creg x_c[2]; +h q[2]; +h q[4]; +h q[5]; +h q[6]; +h q[8]; +h q[9]; +h q[10]; +h q[11]; +h q[12]; +h q[13]; +h q[14]; +cx q[11],q[7]; +cx q[5],q[3]; +cx q[2],q[1]; +cx q[13],q[11]; +cx q[9],q[7]; +cx q[6],q[5]; +cx q[4],q[3]; +cx q[2],q[0]; +cx q[14],q[13]; +cx q[12],q[11]; +cx q[10],q[9]; +cx q[8],q[7]; +cx q[5],q[1]; +cx q[4],q[0]; +cx q[6],q[2]; +cx q[11],q[3]; +cx q[9],q[1]; +cx q[8],q[0]; +cx q[13],q[5]; +cx q[12],q[4]; +cx q[10],q[2]; +cx q[14],q[6]; +h x_anc[0]; +cx x_anc[0],q[5]; +cx x_anc[0],q[10]; +cx x_anc[0],q[12]; +cx x_anc[1],q[1]; +h x_anc[0]; +h x_anc[1]; +cx x_anc[1],q[3]; +cx x_anc[1],q[8]; +cx x_anc[1],q[14]; +h x_anc[1]; +measure x_anc[0] -> x_c[0]; +measure x_anc[1] -> x_c[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_heuristic_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_heuristic_opt.stim new file mode 100644 index 00000000..ded024c7 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_heuristic_opt.stim @@ -0,0 +1,8 @@ +H 2 4 5 6 8 9 10 11 12 13 14 +CX 11 7 5 3 2 1 13 11 9 7 6 5 4 3 2 0 14 13 12 11 10 9 8 7 5 1 4 0 6 2 11 3 9 1 8 0 13 5 12 4 10 2 14 6 +H 15 +CX 15 5 15 10 15 12 16 1 +H 15 16 +CX 16 3 16 8 16 14 +H 16 +MR 15 16 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_opt_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_opt_opt.qasm new file mode 100644 index 00000000..4943ee79 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_opt_opt.qasm @@ -0,0 +1,50 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +qreg x_anc[2]; +creg x_c[2]; +h q[2]; +h q[3]; +h q[4]; +h q[5]; +h q[6]; +h q[7]; +h q[8]; +h q[9]; +h q[10]; +h q[13]; +h q[14]; +cx q[10],q[0]; +cx q[0],q[1]; +cx q[7],q[1]; +cx q[3],q[12]; +cx q[6],q[10]; +cx q[8],q[1]; +cx q[4],q[11]; +cx q[11],q[3]; +cx q[13],q[11]; +cx q[9],q[8]; +cx q[14],q[0]; +cx q[10],q[12]; +cx q[3],q[1]; +cx q[5],q[6]; +cx q[0],q[11]; +cx q[6],q[0]; +cx q[7],q[0]; +cx q[1],q[10]; +cx q[11],q[1]; +cx q[9],q[4]; +cx q[2],q[4]; +cx q[4],q[5]; +h x_anc[0]; +cx x_anc[0],q[0]; +cx x_anc[0],q[9]; +cx x_anc[0],q[10]; +h x_anc[0]; +measure x_anc[0] -> x_c[0]; +h x_anc[1]; +cx x_anc[1],q[4]; +cx x_anc[1],q[8]; +cx x_anc[1],q[11]; +h x_anc[1]; +measure x_anc[1] -> x_c[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_opt_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_opt_opt.stim new file mode 100644 index 00000000..05f8679f --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_ft_opt_opt.stim @@ -0,0 +1,10 @@ +H 2 3 4 5 6 7 8 9 10 13 14 +CX 10 0 0 1 7 1 3 12 6 10 8 1 4 11 11 3 13 11 9 8 14 0 10 12 3 1 5 6 0 11 6 0 7 0 1 10 11 1 9 4 2 4 4 5 +H 15 +CX 15 0 15 9 15 10 +H 15 +MR 15 +H 16 +CX 16 4 16 8 16 11 +H 16 +MR 16 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_non_ft_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_non_ft_heuristic.qasm new file mode 100644 index 00000000..49c2993c --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_non_ft_heuristic.qasm @@ -0,0 +1,36 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +h q[2]; +h q[4]; +h q[5]; +h q[6]; +h q[8]; +h q[9]; +h q[10]; +h q[11]; +h q[12]; +h q[13]; +h q[14]; +cx q[11],q[7]; +cx q[5],q[3]; +cx q[2],q[1]; +cx q[13],q[11]; +cx q[9],q[7]; +cx q[6],q[5]; +cx q[4],q[3]; +cx q[2],q[0]; +cx q[14],q[13]; +cx q[12],q[11]; +cx q[10],q[9]; +cx q[8],q[7]; +cx q[5],q[1]; +cx q[4],q[0]; +cx q[6],q[2]; +cx q[11],q[3]; +cx q[9],q[1]; +cx q[8],q[0]; +cx q[13],q[5]; +cx q[12],q[4]; +cx q[10],q[2]; +cx q[14],q[6]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_non_ft_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_non_ft_heuristic.stim new file mode 100644 index 00000000..4482ea25 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_non_ft_heuristic.stim @@ -0,0 +1,2 @@ +H 2 4 5 6 8 9 10 11 12 13 14 +CX 11 7 5 3 2 1 13 11 9 7 6 5 4 3 2 0 14 13 12 11 10 9 8 7 5 1 4 0 6 2 11 3 9 1 8 0 13 5 12 4 10 2 14 6 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_non_ft_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_non_ft_opt.qasm new file mode 100644 index 00000000..94c55277 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_non_ft_opt.qasm @@ -0,0 +1,36 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +h q[0]; +h q[1]; +h q[2]; +h q[4]; +h q[5]; +h q[6]; +h q[7]; +h q[8]; +h q[9]; +h q[12]; +h q[13]; +cx q[4],q[3]; +cx q[2],q[11]; +cx q[1],q[2]; +cx q[3],q[10]; +cx q[9],q[14]; +cx q[14],q[4]; +cx q[12],q[3]; +cx q[11],q[9]; +cx q[7],q[14]; +cx q[0],q[12]; +cx q[5],q[4]; +cx q[2],q[3]; +cx q[4],q[2]; +cx q[8],q[4]; +cx q[13],q[9]; +cx q[3],q[8]; +cx q[12],q[11]; +cx q[8],q[11]; +cx q[14],q[10]; +cx q[6],q[10]; +cx q[9],q[3]; +cx q[10],q[11]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_non_ft_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_non_ft_opt.stim new file mode 100644 index 00000000..c8e14509 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/plus_non_ft_opt.stim @@ -0,0 +1,2 @@ +H 0 1 2 4 5 6 7 8 9 12 13 +CX 4 3 2 11 1 2 3 10 9 14 14 4 12 3 11 9 7 14 0 12 5 4 2 3 4 2 8 4 13 9 3 8 12 11 8 11 14 10 6 10 9 3 10 11 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_heuristic_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_heuristic_heuristic.qasm new file mode 100644 index 00000000..67383fb4 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_heuristic_heuristic.qasm @@ -0,0 +1,46 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +qreg z_anc[2]; +creg z_c[2]; +h q[0]; +h q[1]; +h q[3]; +h q[7]; +cx q[7],q[11]; +cx q[3],q[5]; +cx q[1],q[2]; +cx q[11],q[13]; +cx q[7],q[9]; +cx q[5],q[6]; +cx q[3],q[4]; +cx q[0],q[2]; +cx q[13],q[14]; +cx q[11],q[12]; +cx q[9],q[10]; +cx q[7],q[8]; +cx q[1],q[5]; +cx q[0],q[4]; +cx q[2],q[6]; +cx q[3],q[11]; +cx q[1],q[9]; +cx q[0],q[8]; +cx q[5],q[13]; +cx q[4],q[12]; +cx q[2],q[10]; +cx q[6],q[14]; +cx q[0],z_anc[0]; +cx q[2],z_anc[0]; +cx q[4],z_anc[0]; +cx q[6],z_anc[0]; +cx q[7],z_anc[0]; +cx q[9],z_anc[0]; +cx q[11],z_anc[0]; +cx q[13],z_anc[0]; +cx q[5],z_anc[1]; +cx q[9],z_anc[1]; +cx q[12],z_anc[1]; +cx q[13],z_anc[1]; +cx q[14],z_anc[1]; +measure z_anc[0] -> z_c[0]; +measure z_anc[1] -> z_c[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_heuristic_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_heuristic_heuristic.stim new file mode 100644 index 00000000..ed71a2e7 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_heuristic_heuristic.stim @@ -0,0 +1,3 @@ +H 0 1 3 7 +CX 7 11 3 5 1 2 11 13 7 9 5 6 3 4 0 2 13 14 11 12 9 10 7 8 1 5 0 4 2 6 3 11 1 9 0 8 5 13 4 12 2 10 6 14 0 15 2 15 4 15 6 15 7 15 9 15 11 15 13 15 5 16 9 16 12 16 13 16 14 16 +MR 15 16 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_heuristic_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_heuristic_opt.qasm new file mode 100644 index 00000000..c6462666 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_heuristic_opt.qasm @@ -0,0 +1,40 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +qreg z_anc[2]; +creg z_c[2]; +h q[0]; +h q[1]; +h q[3]; +h q[7]; +cx q[7],q[11]; +cx q[3],q[5]; +cx q[1],q[2]; +cx q[11],q[13]; +cx q[7],q[9]; +cx q[5],q[6]; +cx q[3],q[4]; +cx q[0],q[2]; +cx q[13],q[14]; +cx q[11],q[12]; +cx q[9],q[10]; +cx q[7],q[8]; +cx q[1],q[5]; +cx q[0],q[4]; +cx q[2],q[6]; +cx q[3],q[11]; +cx q[1],q[9]; +cx q[0],q[8]; +cx q[5],q[13]; +cx q[4],q[12]; +cx q[2],q[10]; +cx q[6],q[14]; +cx q[5],z_anc[0]; +cx q[10],z_anc[0]; +cx q[12],z_anc[0]; +cx q[1],z_anc[1]; +cx q[3],z_anc[1]; +cx q[8],z_anc[1]; +cx q[14],z_anc[1]; +measure z_anc[0] -> z_c[0]; +measure z_anc[1] -> z_c[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_heuristic_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_heuristic_opt.stim new file mode 100644 index 00000000..29a56c36 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_heuristic_opt.stim @@ -0,0 +1,3 @@ +H 0 1 3 7 +CX 7 11 3 5 1 2 11 13 7 9 5 6 3 4 0 2 13 14 11 12 9 10 7 8 1 5 0 4 2 6 3 11 1 9 0 8 5 13 4 12 2 10 6 14 5 15 10 15 12 15 1 16 3 16 8 16 14 16 +MR 15 16 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_opt_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_opt_opt.qasm new file mode 100644 index 00000000..ecaee76a --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_opt_opt.qasm @@ -0,0 +1,39 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +qreg z_anc[2]; +creg z_c[2]; +h q[0]; +h q[1]; +h q[11]; +h q[12]; +cx q[0],q[10]; +cx q[1],q[0]; +cx q[1],q[7]; +cx q[12],q[3]; +cx q[10],q[6]; +cx q[1],q[8]; +cx q[11],q[4]; +cx q[3],q[11]; +cx q[11],q[13]; +cx q[8],q[9]; +cx q[0],q[14]; +cx q[12],q[10]; +cx q[1],q[3]; +cx q[6],q[5]; +cx q[11],q[0]; +cx q[0],q[6]; +cx q[0],q[7]; +cx q[10],q[1]; +cx q[1],q[11]; +cx q[4],q[9]; +cx q[4],q[2]; +cx q[5],q[4]; +cx q[0],z_anc[0]; +cx q[9],z_anc[0]; +cx q[10],z_anc[0]; +cx q[4],z_anc[1]; +cx q[8],z_anc[1]; +cx q[11],z_anc[1]; +measure z_anc[0] -> z_c[0]; +measure z_anc[1] -> z_c[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_opt_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_opt_opt.stim new file mode 100644 index 00000000..d95f54e3 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_ft_opt_opt.stim @@ -0,0 +1,3 @@ +H 0 1 11 12 +CX 0 10 1 0 1 7 12 3 10 6 1 8 11 4 3 11 11 13 8 9 0 14 12 10 1 3 6 5 11 0 0 6 0 7 10 1 1 11 4 9 4 2 5 4 0 15 9 15 10 15 4 16 8 16 11 16 +MR 15 16 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_non_ft_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_non_ft_heuristic.qasm new file mode 100644 index 00000000..67383fb4 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_non_ft_heuristic.qasm @@ -0,0 +1,46 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +qreg z_anc[2]; +creg z_c[2]; +h q[0]; +h q[1]; +h q[3]; +h q[7]; +cx q[7],q[11]; +cx q[3],q[5]; +cx q[1],q[2]; +cx q[11],q[13]; +cx q[7],q[9]; +cx q[5],q[6]; +cx q[3],q[4]; +cx q[0],q[2]; +cx q[13],q[14]; +cx q[11],q[12]; +cx q[9],q[10]; +cx q[7],q[8]; +cx q[1],q[5]; +cx q[0],q[4]; +cx q[2],q[6]; +cx q[3],q[11]; +cx q[1],q[9]; +cx q[0],q[8]; +cx q[5],q[13]; +cx q[4],q[12]; +cx q[2],q[10]; +cx q[6],q[14]; +cx q[0],z_anc[0]; +cx q[2],z_anc[0]; +cx q[4],z_anc[0]; +cx q[6],z_anc[0]; +cx q[7],z_anc[0]; +cx q[9],z_anc[0]; +cx q[11],z_anc[0]; +cx q[13],z_anc[0]; +cx q[5],z_anc[1]; +cx q[9],z_anc[1]; +cx q[12],z_anc[1]; +cx q[13],z_anc[1]; +cx q[14],z_anc[1]; +measure z_anc[0] -> z_c[0]; +measure z_anc[1] -> z_c[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_non_ft_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_non_ft_heuristic.stim new file mode 100644 index 00000000..ed71a2e7 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_non_ft_heuristic.stim @@ -0,0 +1,3 @@ +H 0 1 3 7 +CX 7 11 3 5 1 2 11 13 7 9 5 6 3 4 0 2 13 14 11 12 9 10 7 8 1 5 0 4 2 6 3 11 1 9 0 8 5 13 4 12 2 10 6 14 0 15 2 15 4 15 6 15 7 15 9 15 11 15 13 15 5 16 9 16 12 16 13 16 14 16 +MR 15 16 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_non_ft_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_non_ft_opt.qasm new file mode 100644 index 00000000..cf586641 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_non_ft_opt.qasm @@ -0,0 +1,29 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +h q[0]; +h q[1]; +h q[11]; +h q[12]; +cx q[0],q[10]; +cx q[1],q[0]; +cx q[1],q[7]; +cx q[12],q[3]; +cx q[10],q[6]; +cx q[1],q[8]; +cx q[11],q[4]; +cx q[3],q[11]; +cx q[11],q[13]; +cx q[8],q[9]; +cx q[0],q[14]; +cx q[12],q[10]; +cx q[1],q[3]; +cx q[6],q[5]; +cx q[11],q[0]; +cx q[0],q[6]; +cx q[0],q[7]; +cx q[10],q[1]; +cx q[1],q[11]; +cx q[4],q[9]; +cx q[4],q[2]; +cx q[5],q[4]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_non_ft_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_non_ft_opt.stim new file mode 100644 index 00000000..b43c481f --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/hamming/zero_non_ft_opt.stim @@ -0,0 +1,2 @@ +H 0 1 11 12 +CX 0 10 1 0 1 7 12 3 10 6 1 8 11 4 3 11 11 13 8 9 0 14 12 10 1 3 6 5 11 0 0 6 0 7 10 1 1 11 4 9 4 2 5 4 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_heuristic_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_heuristic_heuristic.qasm new file mode 100644 index 00000000..d1e48edf --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_heuristic_heuristic.qasm @@ -0,0 +1,23 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +qreg x_anc[1]; +creg x_c[1]; +h q[2]; +h q[4]; +h q[5]; +h q[6]; +h q[7]; +cx q[7],q[3]; +cx q[5],q[1]; +cx q[4],q[3]; +cx q[2],q[1]; +cx q[7],q[8]; +cx q[6],q[3]; +cx q[4],q[2]; +cx q[1],q[0]; +h x_anc[0]; +cx x_anc[0],q[2]; +cx x_anc[0],q[5]; +h x_anc[0]; +measure x_anc[0] -> x_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_heuristic_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_heuristic_heuristic.stim new file mode 100644 index 00000000..d71788b1 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_heuristic_heuristic.stim @@ -0,0 +1,6 @@ +H 2 4 5 6 7 +CX 7 3 5 1 4 3 2 1 7 8 6 3 4 2 1 0 +H 9 +CX 9 2 9 5 +H 9 +MR 9 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_heuristic_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_heuristic_opt.qasm new file mode 100644 index 00000000..d1e48edf --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_heuristic_opt.qasm @@ -0,0 +1,23 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +qreg x_anc[1]; +creg x_c[1]; +h q[2]; +h q[4]; +h q[5]; +h q[6]; +h q[7]; +cx q[7],q[3]; +cx q[5],q[1]; +cx q[4],q[3]; +cx q[2],q[1]; +cx q[7],q[8]; +cx q[6],q[3]; +cx q[4],q[2]; +cx q[1],q[0]; +h x_anc[0]; +cx x_anc[0],q[2]; +cx x_anc[0],q[5]; +h x_anc[0]; +measure x_anc[0] -> x_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_heuristic_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_heuristic_opt.stim new file mode 100644 index 00000000..d71788b1 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_heuristic_opt.stim @@ -0,0 +1,6 @@ +H 2 4 5 6 7 +CX 7 3 5 1 4 3 2 1 7 8 6 3 4 2 1 0 +H 9 +CX 9 2 9 5 +H 9 +MR 9 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_opt_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_opt_opt.qasm new file mode 100644 index 00000000..c18af139 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_opt_opt.qasm @@ -0,0 +1,24 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +qreg x_anc[1]; +creg x_c[1]; +h q[0]; +h q[3]; +h q[4]; +h q[5]; +h q[7]; +cx q[0],q[1]; +cx q[4],q[2]; +cx q[7],q[8]; +cx q[3],q[6]; +cx q[1],q[2]; +cx q[5],q[4]; +cx q[8],q[3]; +cx q[4],q[6]; +h x_anc[0]; +cx x_anc[0],q[2]; +cx x_anc[0],q[3]; +cx x_anc[0],q[4]; +h x_anc[0]; +measure x_anc[0] -> x_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_opt_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_opt_opt.stim new file mode 100644 index 00000000..62f249c3 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_ft_opt_opt.stim @@ -0,0 +1,6 @@ +H 0 3 4 5 7 +CX 0 1 4 2 7 8 3 6 1 2 5 4 8 3 4 6 +H 9 +CX 9 2 9 3 9 4 +H 9 +MR 9 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_non_ft_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_non_ft_heuristic.qasm new file mode 100644 index 00000000..7106b8c2 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_non_ft_heuristic.qasm @@ -0,0 +1,16 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +h q[2]; +h q[4]; +h q[5]; +h q[6]; +h q[7]; +cx q[7],q[3]; +cx q[5],q[1]; +cx q[4],q[3]; +cx q[2],q[1]; +cx q[7],q[8]; +cx q[6],q[3]; +cx q[4],q[2]; +cx q[1],q[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_non_ft_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_non_ft_heuristic.stim new file mode 100644 index 00000000..fcd3946b --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_non_ft_heuristic.stim @@ -0,0 +1,2 @@ +H 2 4 5 6 7 +CX 5 1 7 3 2 1 4 3 7 8 1 0 4 2 6 3 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_non_ft_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_non_ft_opt.qasm new file mode 100644 index 00000000..f90ec699 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_non_ft_opt.qasm @@ -0,0 +1,16 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +h q[0]; +h q[3]; +h q[4]; +h q[5]; +h q[7]; +cx q[0],q[1]; +cx q[4],q[2]; +cx q[7],q[8]; +cx q[3],q[6]; +cx q[1],q[2]; +cx q[5],q[4]; +cx q[8],q[3]; +cx q[4],q[6]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_non_ft_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_non_ft_opt.stim new file mode 100644 index 00000000..dfb41b1f --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/plus_non_ft_opt.stim @@ -0,0 +1,2 @@ +H 0 3 4 5 7 +CX 0 1 4 2 7 8 3 6 1 2 5 4 8 3 4 6 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_heuristic_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_heuristic_heuristic.qasm new file mode 100644 index 00000000..3ad9d0b8 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_heuristic_heuristic.qasm @@ -0,0 +1,22 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +qreg z_anc[1]; +creg z_c[1]; +h q[0]; +h q[2]; +h q[5]; +h q[6]; +cx q[5],q[8]; +cx q[0],q[4]; +cx q[5],q[7]; +cx q[0],q[3]; +cx q[7],q[4]; +cx q[6],q[3]; +cx q[2],q[5]; +cx q[0],q[1]; +cx q[0],z_anc[0]; +cx q[2],z_anc[0]; +cx q[4],z_anc[0]; +cx q[5],z_anc[0]; +measure z_anc[0] -> z_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_heuristic_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_heuristic_heuristic.stim new file mode 100644 index 00000000..d9d9582b --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_heuristic_heuristic.stim @@ -0,0 +1,3 @@ +H 0 2 5 6 +CX 5 8 0 4 5 7 0 3 7 4 6 3 2 5 0 1 0 9 2 9 4 9 5 9 +MR 9 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_heuristic_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_heuristic_opt.qasm new file mode 100644 index 00000000..dbf6c5d1 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_heuristic_opt.qasm @@ -0,0 +1,21 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +qreg z_anc[1]; +creg z_c[1]; +h q[0]; +h q[2]; +h q[5]; +h q[6]; +cx q[5],q[8]; +cx q[0],q[4]; +cx q[5],q[7]; +cx q[0],q[3]; +cx q[7],q[4]; +cx q[6],q[3]; +cx q[2],q[5]; +cx q[0],q[1]; +cx q[0],z_anc[0]; +cx q[4],z_anc[0]; +cx q[8],z_anc[0]; +measure z_anc[0] -> z_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_heuristic_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_heuristic_opt.stim new file mode 100644 index 00000000..32e60560 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_heuristic_opt.stim @@ -0,0 +1,3 @@ +H 0 2 5 6 +CX 5 8 0 4 5 7 0 3 7 4 6 3 2 5 0 1 0 9 4 9 8 9 +MR 9 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_opt_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_opt_opt.qasm new file mode 100644 index 00000000..8d587369 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_opt_opt.qasm @@ -0,0 +1,21 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +qreg z_anc[1]; +creg z_c[1]; +h q[3]; +h q[4]; +h q[5]; +h q[8]; +cx q[8],q[0]; +cx q[0],q[1]; +cx q[3],q[6]; +cx q[5],q[2]; +cx q[4],q[8]; +cx q[8],q[5]; +cx q[1],q[3]; +cx q[8],q[7]; +cx q[1],z_anc[0]; +cx q[4],z_anc[0]; +cx q[7],z_anc[0]; +measure z_anc[0] -> z_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_opt_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_opt_opt.stim new file mode 100644 index 00000000..ac2c400c --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_ft_opt_opt.stim @@ -0,0 +1,3 @@ +H 3 4 5 8 +CX 8 0 0 1 3 6 5 2 4 8 8 5 1 3 8 7 1 9 4 9 7 9 +MR 9 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_non_ft_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_non_ft_heuristic.qasm new file mode 100644 index 00000000..201bb889 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_non_ft_heuristic.qasm @@ -0,0 +1,19 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +h q[0]; +h q[2]; +h q[5]; +h q[6]; +cx q[5],q[8]; +cx q[0],q[4]; +cx q[5],q[7]; +cx q[0],q[3]; +cx q[7],q[4]; +cx q[6],q[3]; +cx q[2],q[5]; +cx q[0],q[1]; +cx q[0],z_anc[0]; +cx q[2],z_anc[0]; +cx q[4],z_anc[0]; +cx q[5],z_anc[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_non_ft_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_non_ft_heuristic.stim new file mode 100644 index 00000000..21c90bf5 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_non_ft_heuristic.stim @@ -0,0 +1,2 @@ +H 0 2 5 6 +CX 0 4 5 8 0 3 5 7 0 1 2 5 6 3 7 4 0 9 2 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_non_ft_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_non_ft_opt.qasm new file mode 100644 index 00000000..0d8395c8 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_non_ft_opt.qasm @@ -0,0 +1,15 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +h q[3]; +h q[4]; +h q[5]; +h q[8]; +cx q[8],q[0]; +cx q[0],q[1]; +cx q[3],q[6]; +cx q[5],q[2]; +cx q[4],q[8]; +cx q[8],q[5]; +cx q[1],q[3]; +cx q[8],q[7]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_non_ft_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_non_ft_opt.stim new file mode 100644 index 00000000..c785ef18 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d3/zero_non_ft_opt.stim @@ -0,0 +1,2 @@ +H 3 4 5 8 +CX 8 0 0 1 3 6 5 2 4 8 8 5 1 3 8 7 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_ft_heuristic_naive.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_ft_heuristic_naive.qasm new file mode 100644 index 00000000..4990070a --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_ft_heuristic_naive.qasm @@ -0,0 +1,383 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[25]; +qreg z_anc[24]; +qreg x_anc[24]; +qreg a0[1]; +qreg a1[1]; +qreg a2[1]; +qreg a3[1]; +qreg a4[1]; +qreg a5[1]; +qreg a6[1]; +qreg a7[1]; +qreg a8[1]; +qreg a9[1]; +qreg a10[1]; +qreg a11[1]; +qreg a12[1]; +qreg a13[1]; +qreg a14[1]; +qreg a15[1]; +creg z_c[24]; +creg x_c[24]; +creg c0[1]; +creg c1[1]; +creg c2[1]; +creg c3[1]; +creg c4[1]; +creg c5[1]; +creg c6[1]; +creg c7[1]; +creg c8[1]; +creg c9[1]; +creg c10[1]; +creg c11[1]; +creg c12[1]; +creg c13[1]; +creg c14[1]; +creg c15[1]; +h q[0]; +h q[1]; +h q[2]; +h q[4]; +h q[5]; +h q[7]; +h q[11]; +h q[14]; +h q[15]; +h q[18]; +h q[21]; +h q[24]; +cx q[18],q[23]; +cx q[11],q[17]; +cx q[7],q[13]; +cx q[18],q[22]; +cx q[11],q[12]; +cx q[7],q[8]; +cx q[2],q[3]; +cx q[1],q[6]; +cx q[21],q[22]; +cx q[18],q[17]; +cx q[15],q[20]; +cx q[14],q[19]; +cx q[11],q[16]; +cx q[8],q[12]; +cx q[6],q[7]; +cx q[5],q[10]; +cx q[4],q[9]; +cx q[1],q[2]; +cx q[24],q[23]; +cx q[20],q[21]; +cx q[19],q[18]; +cx q[15],q[16]; +cx q[14],q[13]; +cx q[10],q[11]; +cx q[9],q[8]; +cx q[5],q[6]; +cx q[4],q[3]; +cx q[0],q[1]; +cx q[0],z_anc[0]; +cx q[1],z_anc[0]; +cx q[5],z_anc[0]; +cx q[6],z_anc[0]; +cx q[2],z_anc[1]; +cx q[3],z_anc[1]; +cx q[7],z_anc[1]; +cx q[8],z_anc[1]; +cx q[4],z_anc[2]; +cx q[9],z_anc[2]; +cx q[5],z_anc[3]; +cx q[10],z_anc[3]; +cx q[6],z_anc[4]; +cx q[7],z_anc[4]; +cx q[11],z_anc[4]; +cx q[12],z_anc[4]; +cx q[8],z_anc[5]; +cx q[9],z_anc[5]; +cx q[13],z_anc[5]; +cx q[14],z_anc[5]; +cx q[10],z_anc[6]; +cx q[11],z_anc[6]; +cx q[15],z_anc[6]; +cx q[16],z_anc[6]; +cx q[12],z_anc[7]; +cx q[13],z_anc[7]; +cx q[17],z_anc[7]; +cx q[18],z_anc[7]; +cx q[14],z_anc[8]; +cx q[19],z_anc[8]; +cx q[15],z_anc[9]; +cx q[20],z_anc[9]; +cx q[16],z_anc[10]; +cx q[17],z_anc[10]; +cx q[21],z_anc[10]; +cx q[22],z_anc[10]; +cx q[18],z_anc[11]; +cx q[19],z_anc[11]; +cx q[23],z_anc[11]; +cx q[24],z_anc[11]; +cx q[0],z_anc[12]; +cx q[1],z_anc[12]; +cx q[5],z_anc[12]; +cx q[6],z_anc[12]; +cx q[2],z_anc[13]; +cx q[3],z_anc[13]; +cx q[7],z_anc[13]; +cx q[8],z_anc[13]; +cx q[4],z_anc[14]; +cx q[9],z_anc[14]; +cx q[5],z_anc[15]; +cx q[10],z_anc[15]; +cx q[6],z_anc[16]; +cx q[7],z_anc[16]; +cx q[11],z_anc[16]; +cx q[12],z_anc[16]; +cx q[8],z_anc[17]; +cx q[9],z_anc[17]; +cx q[13],z_anc[17]; +cx q[14],z_anc[17]; +cx q[10],z_anc[18]; +cx q[11],z_anc[18]; +cx q[15],z_anc[18]; +cx q[16],z_anc[18]; +cx q[12],z_anc[19]; +cx q[13],z_anc[19]; +cx q[17],z_anc[19]; +cx q[18],z_anc[19]; +cx q[14],z_anc[20]; +cx q[19],z_anc[20]; +cx q[15],z_anc[21]; +cx q[20],z_anc[21]; +cx q[16],z_anc[22]; +cx q[17],z_anc[22]; +cx q[21],z_anc[22]; +cx q[22],z_anc[22]; +cx q[18],z_anc[23]; +cx q[19],z_anc[23]; +cx q[23],z_anc[23]; +cx q[24],z_anc[23]; +measure z_anc[0] -> z_c[0]; +measure z_anc[1] -> z_c[1]; +measure z_anc[2] -> z_c[2]; +measure z_anc[3] -> z_c[3]; +measure z_anc[4] -> z_c[4]; +measure z_anc[5] -> z_c[5]; +measure z_anc[6] -> z_c[6]; +measure z_anc[7] -> z_c[7]; +measure z_anc[8] -> z_c[8]; +measure z_anc[9] -> z_c[9]; +measure z_anc[10] -> z_c[10]; +measure z_anc[11] -> z_c[11]; +measure z_anc[12] -> z_c[12]; +measure z_anc[13] -> z_c[13]; +measure z_anc[14] -> z_c[14]; +measure z_anc[15] -> z_c[15]; +measure z_anc[16] -> z_c[16]; +measure z_anc[17] -> z_c[17]; +measure z_anc[18] -> z_c[18]; +measure z_anc[19] -> z_c[19]; +measure z_anc[20] -> z_c[20]; +measure z_anc[21] -> z_c[21]; +measure z_anc[22] -> z_c[22]; +measure z_anc[23] -> z_c[23]; +h x_anc[0]; +cx x_anc[0],q[0]; +cx x_anc[0],q[1]; +h x_anc[0]; +measure x_anc[0] -> x_c[0]; +h x_anc[1]; +cx x_anc[1],q[1]; +cx x_anc[1],a0[0]; +cx x_anc[1],q[2]; +cx x_anc[1],q[6]; +cx x_anc[1],a0[0]; +measure a0[0] -> c0[0]; +cx x_anc[1],q[7]; +h x_anc[1]; +measure x_anc[1] -> x_c[1]; +h x_anc[2]; +cx x_anc[2],q[2]; +cx x_anc[2],q[3]; +h x_anc[2]; +measure x_anc[2] -> x_c[2]; +h x_anc[3]; +cx x_anc[3],q[3]; +cx x_anc[3],a1[0]; +cx x_anc[3],q[4]; +cx x_anc[3],q[8]; +cx x_anc[3],a1[0]; +measure a1[0] -> c1[0]; +cx x_anc[3],q[9]; +h x_anc[3]; +measure x_anc[3] -> x_c[3]; +h x_anc[4]; +cx x_anc[4],q[5]; +cx x_anc[4],a2[0]; +cx x_anc[4],q[6]; +cx x_anc[4],q[10]; +cx x_anc[4],a2[0]; +measure a2[0] -> c2[0]; +cx x_anc[4],q[11]; +h x_anc[4]; +measure x_anc[4] -> x_c[4]; +h x_anc[5]; +cx x_anc[5],q[7]; +cx x_anc[5],a3[0]; +cx x_anc[5],q[8]; +cx x_anc[5],q[12]; +cx x_anc[5],a3[0]; +measure a3[0] -> c3[0]; +cx x_anc[5],q[13]; +h x_anc[5]; +measure x_anc[5] -> x_c[5]; +h x_anc[6]; +cx x_anc[6],q[11]; +cx x_anc[6],a4[0]; +cx x_anc[6],q[12]; +cx x_anc[6],q[16]; +cx x_anc[6],a4[0]; +measure a4[0] -> c4[0]; +cx x_anc[6],q[17]; +h x_anc[6]; +measure x_anc[6] -> x_c[6]; +h x_anc[7]; +cx x_anc[7],q[13]; +cx x_anc[7],a5[0]; +cx x_anc[7],q[14]; +cx x_anc[7],q[18]; +cx x_anc[7],a5[0]; +measure a5[0] -> c5[0]; +cx x_anc[7],q[19]; +h x_anc[7]; +measure x_anc[7] -> x_c[7]; +h x_anc[8]; +cx x_anc[8],q[15]; +cx x_anc[8],a6[0]; +cx x_anc[8],q[16]; +cx x_anc[8],q[20]; +cx x_anc[8],a6[0]; +measure a6[0] -> c6[0]; +cx x_anc[8],q[21]; +h x_anc[8]; +measure x_anc[8] -> x_c[8]; +h x_anc[9]; +cx x_anc[9],q[17]; +cx x_anc[9],a7[0]; +cx x_anc[9],q[18]; +cx x_anc[9],q[22]; +cx x_anc[9],a7[0]; +measure a7[0] -> c7[0]; +cx x_anc[9],q[23]; +h x_anc[9]; +measure x_anc[9] -> x_c[9]; +h x_anc[10]; +cx x_anc[10],q[21]; +cx x_anc[10],q[22]; +h x_anc[10]; +measure x_anc[10] -> x_c[10]; +h x_anc[11]; +cx x_anc[11],q[23]; +cx x_anc[11],q[24]; +h x_anc[11]; +measure x_anc[11] -> x_c[11]; +h x_anc[12]; +cx x_anc[12],q[0]; +cx x_anc[12],q[1]; +h x_anc[12]; +measure x_anc[12] -> x_c[12]; +h x_anc[13]; +cx x_anc[13],q[1]; +cx x_anc[13],a8[0]; +cx x_anc[13],q[2]; +cx x_anc[13],q[6]; +cx x_anc[13],a8[0]; +measure a8[0] -> c8[0]; +cx x_anc[13],q[7]; +h x_anc[13]; +measure x_anc[13] -> x_c[13]; +h x_anc[14]; +cx x_anc[14],q[2]; +cx x_anc[14],q[3]; +h x_anc[14]; +measure x_anc[14] -> x_c[14]; +h x_anc[15]; +cx x_anc[15],q[3]; +cx x_anc[15],a9[0]; +cx x_anc[15],q[4]; +cx x_anc[15],q[8]; +cx x_anc[15],a9[0]; +measure a9[0] -> c9[0]; +cx x_anc[15],q[9]; +h x_anc[15]; +measure x_anc[15] -> x_c[15]; +h x_anc[16]; +cx x_anc[16],q[5]; +cx x_anc[16],a10[0]; +cx x_anc[16],q[6]; +cx x_anc[16],q[10]; +cx x_anc[16],a10[0]; +measure a10[0] -> c10[0]; +cx x_anc[16],q[11]; +h x_anc[16]; +measure x_anc[16] -> x_c[16]; +h x_anc[17]; +cx x_anc[17],q[7]; +cx x_anc[17],a11[0]; +cx x_anc[17],q[8]; +cx x_anc[17],q[12]; +cx x_anc[17],a11[0]; +measure a11[0] -> c11[0]; +cx x_anc[17],q[13]; +h x_anc[17]; +measure x_anc[17] -> x_c[17]; +h x_anc[18]; +cx x_anc[18],q[11]; +cx x_anc[18],a12[0]; +cx x_anc[18],q[12]; +cx x_anc[18],q[16]; +cx x_anc[18],a12[0]; +measure a12[0] -> c12[0]; +cx x_anc[18],q[17]; +h x_anc[18]; +measure x_anc[18] -> x_c[18]; +h x_anc[19]; +cx x_anc[19],q[13]; +cx x_anc[19],a13[0]; +cx x_anc[19],q[14]; +cx x_anc[19],q[18]; +cx x_anc[19],a13[0]; +measure a13[0] -> c13[0]; +cx x_anc[19],q[19]; +h x_anc[19]; +measure x_anc[19] -> x_c[19]; +h x_anc[20]; +cx x_anc[20],q[15]; +cx x_anc[20],a14[0]; +cx x_anc[20],q[16]; +cx x_anc[20],q[20]; +cx x_anc[20],a14[0]; +measure a14[0] -> c14[0]; +cx x_anc[20],q[21]; +h x_anc[20]; +measure x_anc[20] -> x_c[20]; +h x_anc[21]; +cx x_anc[21],q[17]; +cx x_anc[21],a15[0]; +cx x_anc[21],q[18]; +cx x_anc[21],q[22]; +cx x_anc[21],a15[0]; +measure a15[0] -> c15[0]; +cx x_anc[21],q[23]; +h x_anc[21]; +measure x_anc[21] -> x_c[21]; +h x_anc[22]; +cx x_anc[22],q[21]; +cx x_anc[22],q[22]; +h x_anc[22]; +measure x_anc[22] -> x_c[22]; +h x_anc[23]; +cx x_anc[23],q[23]; +cx x_anc[23],q[24]; +h x_anc[23]; +measure x_anc[23] -> x_c[23]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_ft_heuristic_naive.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_ft_heuristic_naive.stim new file mode 100644 index 00000000..9d2ee9b5 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_ft_heuristic_naive.stim @@ -0,0 +1,87 @@ +H 0 1 2 4 5 7 11 14 15 18 21 24 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 +CX 2 3 1 6 4 9 5 10 7 13 11 17 14 19 15 20 18 23 1 2 4 3 7 8 11 12 14 13 18 22 24 23 0 1 6 7 8 12 11 16 18 17 21 22 2 26 4 27 5 6 9 8 10 11 15 16 19 18 20 21 0 25 3 26 2 38 4 39 1 25 7 26 9 27 0 37 3 38 5 25 8 26 1 37 49 0 +MR 27 +CX 6 25 5 28 8 30 49 1 61 0 +MR 26 +CX 10 28 6 29 9 30 5 37 +H 49 +CX 50 1 +MR 25 +CX 7 29 13 30 10 31 6 37 9 39 5 40 61 1 50 73 +MR 28 49 +CX 11 29 14 30 7 38 10 40 6 41 50 2 53 5 +H 61 +CX 62 1 +MR 37 39 +CX 12 29 11 31 14 33 8 38 7 41 10 43 50 6 51 2 65 5 53 75 62 81 +MR 30 40 61 +CX 15 31 12 32 19 33 11 41 8 42 51 3 53 6 62 2 50 73 65 83 +MR 29 38 +CX 16 31 13 32 15 34 12 41 9 42 11 43 50 7 +H 51 +CX 52 3 53 10 62 6 63 2 +MR 33 73 +CX 17 32 20 34 16 35 13 42 15 43 12 44 +H 50 +CX 54 7 63 3 65 6 52 74 53 75 62 81 +MR 31 41 51 +CX 18 32 17 35 14 42 16 43 13 44 15 46 52 4 53 11 62 7 +H 63 +CX 64 3 65 10 54 76 +MR 34 50 75 81 +CX 21 35 18 36 17 44 14 45 20 46 16 47 52 8 +H 53 +CX 55 11 57 15 +H 62 +CX 66 7 64 82 65 83 +MR 32 42 43 63 +CX 22 35 19 36 18 44 17 47 54 8 64 4 65 11 69 15 52 74 55 77 57 79 66 84 +MR 46 53 62 83 +CX 23 36 19 45 21 47 18 48 52 9 54 12 64 8 +H 65 +CX 67 11 69 87 +MR 35 44 74 +CX 24 36 22 47 19 48 +H 52 +CX 55 12 66 8 54 76 64 82 67 85 +MR 45 65 +CX 23 48 54 13 55 16 64 9 66 12 +MR 36 47 52 76 82 +CX 24 48 +H 54 +CX 56 13 57 16 +H 64 +CX 67 12 55 77 66 84 55 17 57 20 66 13 67 16 56 78 +MR 48 54 64 77 84 +H 55 +CX 56 14 58 17 +H 66 +CX 68 13 69 16 57 79 67 85 56 18 57 21 67 17 69 20 58 80 68 86 +MR 55 66 79 85 +H 57 +CX 58 18 59 21 +H 67 +CX 68 14 70 17 56 78 69 87 56 19 58 22 68 18 69 21 70 88 +MR 57 67 78 87 +H 56 +CX 59 22 +H 69 +CX 70 18 71 21 58 80 68 86 58 23 +H 59 +CX 68 19 70 22 +MR 56 69 80 86 +H 58 +CX 60 23 +H 68 +CX 71 22 70 88 +MR 59 +CX 60 24 70 23 +H 71 +MR 58 68 88 +H 60 70 +CX 72 23 +MR 71 +CX 72 24 +MR 60 70 +H 72 +MR 72 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_ft_heuristic_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_ft_heuristic_opt.qasm new file mode 100644 index 00000000..b1f1200a --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_ft_heuristic_opt.qasm @@ -0,0 +1,195 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[25]; +qreg z_anc[5]; +qreg x_anc[6]; +qreg a0[3]; +qreg a1[3]; +qreg a2[2]; +qreg a3[2]; +qreg a4[2]; +qreg a5[2]; +creg z_c[5]; +creg x_c[6]; +creg c0[3]; +creg c1[3]; +creg c2[2]; +creg c3[2]; +creg c4[2]; +creg c5[2]; +h q[0]; +h q[1]; +h q[2]; +h q[4]; +h q[5]; +h q[7]; +h q[11]; +h q[14]; +h q[15]; +h q[18]; +h q[21]; +h q[24]; +cx q[18],q[23]; +cx q[11],q[17]; +cx q[7],q[13]; +cx q[18],q[22]; +cx q[11],q[12]; +cx q[7],q[8]; +cx q[2],q[3]; +cx q[1],q[6]; +cx q[21],q[22]; +cx q[18],q[17]; +cx q[15],q[20]; +cx q[14],q[19]; +cx q[11],q[16]; +cx q[8],q[12]; +cx q[6],q[7]; +cx q[5],q[10]; +cx q[4],q[9]; +cx q[1],q[2]; +cx q[24],q[23]; +cx q[20],q[21]; +cx q[19],q[18]; +cx q[15],q[16]; +cx q[14],q[13]; +cx q[10],q[11]; +cx q[9],q[8]; +cx q[5],q[6]; +cx q[4],q[3]; +cx q[0],q[1]; +cx q[2],z_anc[0]; +cx q[3],z_anc[0]; +cx q[6],z_anc[0]; +cx q[9],z_anc[0]; +cx q[10],z_anc[0]; +cx q[12],z_anc[0]; +cx q[13],z_anc[0]; +cx q[16],z_anc[0]; +cx q[18],z_anc[0]; +cx q[21],z_anc[0]; +cx q[22],z_anc[0]; +cx q[4],z_anc[1]; +cx q[8],z_anc[1]; +cx q[13],z_anc[1]; +cx q[19],z_anc[1]; +cx q[16],z_anc[2]; +cx q[17],z_anc[2]; +cx q[20],z_anc[2]; +cx q[23],z_anc[2]; +cx q[24],z_anc[2]; +cx q[0],z_anc[3]; +cx q[1],z_anc[3]; +cx q[7],z_anc[3]; +cx q[12],z_anc[3]; +cx q[16],z_anc[3]; +cx q[20],z_anc[3]; +cx q[4],z_anc[4]; +cx q[5],z_anc[4]; +cx q[8],z_anc[4]; +cx q[11],z_anc[4]; +cx q[12],z_anc[4]; +measure z_anc[0] -> z_c[0]; +measure z_anc[1] -> z_c[1]; +measure z_anc[2] -> z_c[2]; +measure z_anc[3] -> z_c[3]; +measure z_anc[4] -> z_c[4]; +h x_anc[0]; +cx x_anc[0],q[5]; +cx x_anc[0],a0[0]; +cx x_anc[0],q[6]; +cx x_anc[0],a0[1]; +cx x_anc[0],q[10]; +cx x_anc[0],q[12]; +cx x_anc[0],a0[2]; +cx x_anc[0],q[16]; +cx x_anc[0],q[18]; +cx x_anc[0],a0[0]; +measure a0[0] -> c0[0]; +cx x_anc[0],q[21]; +cx x_anc[0],a0[2]; +measure a0[2] -> c0[2]; +cx x_anc[0],a0[1]; +measure a0[1] -> c0[1]; +cx x_anc[0],q[23]; +h x_anc[0]; +measure x_anc[0] -> x_c[0]; +h x_anc[1]; +cx x_anc[1],q[1]; +cx x_anc[1],a1[0]; +cx x_anc[1],q[3]; +cx x_anc[1],a1[1]; +cx x_anc[1],q[6]; +cx x_anc[1],q[8]; +cx x_anc[1],a1[2]; +cx x_anc[1],q[12]; +cx x_anc[1],q[14]; +cx x_anc[1],a1[0]; +measure a1[0] -> c1[0]; +cx x_anc[1],q[18]; +cx x_anc[1],a1[2]; +measure a1[2] -> c1[2]; +cx x_anc[1],a1[1]; +measure a1[1] -> c1[1]; +cx x_anc[1],q[19]; +h x_anc[1]; +measure x_anc[1] -> x_c[1]; +h x_anc[2]; +cx x_anc[2],q[0]; +cx x_anc[2],a2[0]; +cx x_anc[2],q[4]; +cx x_anc[2],a2[1]; +cx x_anc[2],q[6]; +cx x_anc[2],q[9]; +cx x_anc[2],a2[0]; +measure a2[0] -> c2[0]; +cx x_anc[2],q[12]; +cx x_anc[2],a2[1]; +measure a2[1] -> c2[1]; +cx x_anc[2],q[13]; +h x_anc[2]; +measure x_anc[2] -> x_c[2]; +h x_anc[3]; +cx x_anc[3],q[13]; +cx x_anc[3],a3[0]; +cx x_anc[3],q[14]; +cx x_anc[3],a3[1]; +cx x_anc[3],q[17]; +cx x_anc[3],q[19]; +cx x_anc[3],a3[0]; +measure a3[0] -> c3[0]; +cx x_anc[3],q[21]; +cx x_anc[3],a3[1]; +measure a3[1] -> c3[1]; +cx x_anc[3],q[23]; +h x_anc[3]; +measure x_anc[3] -> x_c[3]; +h x_anc[4]; +cx x_anc[4],q[11]; +cx x_anc[4],a4[0]; +cx x_anc[4],q[12]; +cx x_anc[4],a4[1]; +cx x_anc[4],q[16]; +cx x_anc[4],q[17]; +cx x_anc[4],a4[0]; +measure a4[0] -> c4[0]; +cx x_anc[4],q[23]; +cx x_anc[4],a4[1]; +measure a4[1] -> c4[1]; +cx x_anc[4],q[24]; +h x_anc[4]; +measure x_anc[4] -> x_c[4]; +h x_anc[5]; +cx x_anc[5],q[0]; +cx x_anc[5],a5[0]; +cx x_anc[5],q[3]; +cx x_anc[5],a5[1]; +cx x_anc[5],q[6]; +cx x_anc[5],q[7]; +cx x_anc[5],a5[0]; +measure a5[0] -> c5[0]; +cx x_anc[5],q[23]; +cx x_anc[5],a5[1]; +measure a5[1] -> c5[1]; +cx x_anc[5],q[24]; +h x_anc[5]; +measure x_anc[5] -> x_c[5]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_ft_heuristic_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_ft_heuristic_opt.stim new file mode 100644 index 00000000..ce0f64db --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_ft_heuristic_opt.stim @@ -0,0 +1,32 @@ +H 0 1 2 4 5 7 11 14 15 18 21 24 30 31 32 33 +CX 2 3 1 6 4 9 5 10 7 13 11 17 14 19 15 20 18 23 1 2 4 3 7 8 11 12 14 13 18 22 24 23 0 1 6 7 8 12 11 16 18 17 21 22 2 25 5 6 9 8 10 11 15 16 19 18 20 21 3 25 2 27 30 1 6 25 3 27 31 1 30 34 8 25 7 27 6 28 30 3 31 38 10 25 8 26 7 28 31 3 30 35 13 25 9 26 8 27 11 28 30 6 16 25 13 26 30 8 31 6 +MR 27 +CX 17 25 15 26 13 28 30 36 31 38 19 25 16 26 30 11 31 7 +MR 38 +CX 21 25 17 26 16 29 30 13 +H 31 +CX 32 7 22 25 18 26 17 28 30 37 32 39 +MR 31 +CX 18 28 17 29 30 16 32 8 +MR 25 26 +CX 21 29 30 36 32 40 +MR 28 +CX 22 29 30 18 32 11 +MR 36 +CX 32 13 30 34 +MR 29 +CX 30 21 32 39 +MR 34 +CX 32 16 30 37 +MR 39 +CX 30 35 32 40 +MR 37 +CX 30 23 32 17 +MR 35 40 +H 30 32 +CX 33 17 33 41 +MR 30 32 +CX 33 18 33 21 33 41 33 23 +MR 41 +H 33 +MR 33 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_non_ft_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_non_ft_heuristic.qasm new file mode 100644 index 00000000..22a93105 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_non_ft_heuristic.qasm @@ -0,0 +1,43 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[25]; +h q[0]; +h q[1]; +h q[2]; +h q[4]; +h q[5]; +h q[7]; +h q[11]; +h q[14]; +h q[15]; +h q[18]; +h q[21]; +h q[24]; +cx q[18],q[23]; +cx q[11],q[17]; +cx q[7],q[13]; +cx q[18],q[22]; +cx q[11],q[12]; +cx q[7],q[8]; +cx q[2],q[3]; +cx q[1],q[6]; +cx q[21],q[22]; +cx q[18],q[17]; +cx q[15],q[20]; +cx q[14],q[19]; +cx q[11],q[16]; +cx q[8],q[12]; +cx q[6],q[7]; +cx q[5],q[10]; +cx q[4],q[9]; +cx q[1],q[2]; +cx q[24],q[23]; +cx q[20],q[21]; +cx q[19],q[18]; +cx q[15],q[16]; +cx q[14],q[13]; +cx q[10],q[11]; +cx q[9],q[8]; +cx q[5],q[6]; +cx q[4],q[3]; +cx q[0],q[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_non_ft_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_non_ft_heuristic.stim new file mode 100644 index 00000000..07dca05b --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/rotated_surface_d5/zero_non_ft_heuristic.stim @@ -0,0 +1,2 @@ +H 0 1 2 4 5 7 11 14 15 18 21 24 +CX 2 3 1 6 4 9 5 10 7 13 11 17 14 19 15 20 18 23 1 2 4 3 7 8 11 12 14 13 18 22 24 23 0 1 6 7 8 12 11 16 18 17 21 22 5 6 9 8 10 11 15 16 19 18 20 21 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_heuristic_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_heuristic_heuristic.qasm new file mode 100644 index 00000000..aacb3313 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_heuristic_heuristic.qasm @@ -0,0 +1,12 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +h q[2]; +h q[5]; +h q[8]; +cx q[8],q[6]; +cx q[5],q[3]; +cx q[2],q[0]; +cx q[6],q[7]; +cx q[3],q[4]; +cx q[0],q[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_heuristic_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_heuristic_heuristic.stim new file mode 100644 index 00000000..4f9f83fe --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_heuristic_heuristic.stim @@ -0,0 +1,2 @@ +H 2 5 8 +CX 2 0 5 3 8 6 0 1 3 4 6 7 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_heuristic_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_heuristic_opt.qasm new file mode 100644 index 00000000..aacb3313 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_heuristic_opt.qasm @@ -0,0 +1,12 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +h q[2]; +h q[5]; +h q[8]; +cx q[8],q[6]; +cx q[5],q[3]; +cx q[2],q[0]; +cx q[6],q[7]; +cx q[3],q[4]; +cx q[0],q[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_heuristic_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_heuristic_opt.stim new file mode 100644 index 00000000..4f9f83fe --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_heuristic_opt.stim @@ -0,0 +1,2 @@ +H 2 5 8 +CX 2 0 5 3 8 6 0 1 3 4 6 7 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_opt_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_opt_opt.qasm new file mode 100644 index 00000000..b066baa8 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_opt_opt.qasm @@ -0,0 +1,12 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +h q[2]; +h q[4]; +h q[6]; +cx q[2],q[0]; +cx q[4],q[5]; +cx q[6],q[7]; +cx q[5],q[3]; +cx q[7],q[8]; +cx q[2],q[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_opt_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_opt_opt.stim new file mode 100644 index 00000000..fafa67e4 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_ft_opt_opt.stim @@ -0,0 +1,2 @@ +H 2 4 6 +CX 2 0 4 5 6 7 2 1 5 3 7 8 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_non_ft_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_non_ft_heuristic.qasm new file mode 100644 index 00000000..aacb3313 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_non_ft_heuristic.qasm @@ -0,0 +1,12 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +h q[2]; +h q[5]; +h q[8]; +cx q[8],q[6]; +cx q[5],q[3]; +cx q[2],q[0]; +cx q[6],q[7]; +cx q[3],q[4]; +cx q[0],q[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_non_ft_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_non_ft_heuristic.stim new file mode 100644 index 00000000..4f9f83fe --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_non_ft_heuristic.stim @@ -0,0 +1,2 @@ +H 2 5 8 +CX 2 0 5 3 8 6 0 1 3 4 6 7 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_non_ft_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_non_ft_opt.qasm new file mode 100644 index 00000000..b066baa8 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_non_ft_opt.qasm @@ -0,0 +1,12 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +h q[2]; +h q[4]; +h q[6]; +cx q[2],q[0]; +cx q[4],q[5]; +cx q[6],q[7]; +cx q[5],q[3]; +cx q[7],q[8]; +cx q[2],q[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_non_ft_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_non_ft_opt.stim new file mode 100644 index 00000000..fafa67e4 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/plus_non_ft_opt.stim @@ -0,0 +1,2 @@ +H 2 4 6 +CX 2 0 4 5 6 7 2 1 5 3 7 8 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_heuristic_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_heuristic_heuristic.qasm new file mode 100644 index 00000000..80e691a8 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_heuristic_heuristic.qasm @@ -0,0 +1,23 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +qreg z_anc[2]; +creg z_c[2]; +h q[0]; +h q[2]; +cx q[2],q[6]; +cx q[0],q[3]; +cx q[6],q[8]; +cx q[3],q[4]; +cx q[2],q[0]; +cx q[6],q[7]; +cx q[4],q[5]; +cx q[3],q[2]; +cx q[0],q[1]; +cx q[3],z_anc[0]; +cx q[4],z_anc[0]; +cx q[1],z_anc[1]; +cx q[3],z_anc[1]; +cx q[7],z_anc[1]; +measure z_anc[0] -> z_c[0]; +measure z_anc[1] -> z_c[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_heuristic_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_heuristic_heuristic.stim new file mode 100644 index 00000000..b75f4cec --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_heuristic_heuristic.stim @@ -0,0 +1,3 @@ +H 0 2 +CX 0 3 2 6 2 0 3 4 6 8 0 1 3 2 4 5 6 7 3 9 1 10 4 9 3 10 7 10 +MR 9 10 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_heuristic_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_heuristic_opt.qasm new file mode 100644 index 00000000..1fe4367e --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_heuristic_opt.qasm @@ -0,0 +1,23 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +qreg z_anc[2]; +creg z_c[2]; +h q[0]; +h q[2]; +cx q[2],q[6]; +cx q[0],q[3]; +cx q[6],q[8]; +cx q[3],q[4]; +cx q[2],q[0]; +cx q[6],q[7]; +cx q[4],q[5]; +cx q[3],q[2]; +cx q[0],q[1]; +cx q[1],z_anc[0]; +cx q[2],z_anc[0]; +cx q[2],z_anc[1]; +cx q[5],z_anc[1]; +cx q[7],z_anc[1]; +measure z_anc[0] -> z_c[0]; +measure z_anc[1] -> z_c[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_heuristic_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_heuristic_opt.stim new file mode 100644 index 00000000..b48f6482 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_heuristic_opt.stim @@ -0,0 +1,5 @@ +H 0 2 +CX 0 3 2 6 2 0 3 4 6 8 0 1 3 2 4 5 6 7 1 9 2 9 2 10 +MR 9 +CX 5 10 7 10 +MR 10 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_opt_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_opt_opt.qasm new file mode 100644 index 00000000..47f966ea --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_opt_opt.qasm @@ -0,0 +1,19 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +qreg z_anc[1]; +creg z_c[1]; +h q[2]; +h q[7]; +cx q[7],q[4]; +cx q[2],q[7]; +cx q[2],q[0]; +cx q[4],q[5]; +cx q[7],q[8]; +cx q[4],q[3]; +cx q[7],q[6]; +cx q[0],q[1]; +cx q[1],z_anc[0]; +cx q[4],z_anc[0]; +cx q[7],z_anc[0]; +measure z_anc[0] -> z_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_opt_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_opt_opt.stim new file mode 100644 index 00000000..0625ecde --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_ft_opt_opt.stim @@ -0,0 +1,3 @@ +H 2 7 +CX 7 4 4 5 2 7 2 0 4 3 7 8 0 1 7 6 1 9 4 9 7 9 +MR 9 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_non_ft_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_non_ft_heuristic.qasm new file mode 100644 index 00000000..90622fb2 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_non_ft_heuristic.qasm @@ -0,0 +1,14 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +h q[0]; +h q[2]; +cx q[2],q[6]; +cx q[0],q[3]; +cx q[6],q[8]; +cx q[3],q[4]; +cx q[2],q[0]; +cx q[6],q[7]; +cx q[4],q[5]; +cx q[3],q[2]; +cx q[0],q[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_non_ft_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_non_ft_heuristic.stim new file mode 100644 index 00000000..8f6d8df0 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_non_ft_heuristic.stim @@ -0,0 +1,2 @@ +H 0 2 +CX 0 3 2 6 2 0 3 4 6 8 0 1 3 2 4 5 6 7 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_non_ft_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_non_ft_opt.qasm new file mode 100644 index 00000000..004bf475 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_non_ft_opt.qasm @@ -0,0 +1,13 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[9]; +h q[2]; +h q[7]; +cx q[7],q[4]; +cx q[2],q[7]; +cx q[2],q[0]; +cx q[4],q[5]; +cx q[7],q[8]; +cx q[4],q[3]; +cx q[7],q[6]; +cx q[0],q[1]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_non_ft_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_non_ft_opt.stim new file mode 100644 index 00000000..88ec58c4 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/shor/zero_non_ft_opt.stim @@ -0,0 +1,2 @@ +H 2 7 +CX 7 4 4 5 2 7 2 0 4 3 7 8 0 1 7 6 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_heuristic_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_heuristic_heuristic.qasm new file mode 100644 index 00000000..1a169853 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_heuristic_heuristic.qasm @@ -0,0 +1,23 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[7]; +qreg x_anc[1]; +creg x_c[1]; +h q[2]; +h q[4]; +h q[5]; +h q[6]; +cx q[5],q[3]; +cx q[2],q[0]; +cx q[6],q[5]; +cx q[4],q[3]; +cx q[0],q[1]; +cx q[6],q[2]; +cx q[5],q[1]; +cx q[4],q[0]; +h x_anc[0]; +cx x_anc[0],q[2]; +cx x_anc[0],q[4]; +cx x_anc[0],q[5]; +h x_anc[0]; +measure x_anc[0] -> x_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_heuristic_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_heuristic_heuristic.stim new file mode 100644 index 00000000..0c05ffc5 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_heuristic_heuristic.stim @@ -0,0 +1,6 @@ +H 2 4 5 6 +CX 5 3 2 0 6 5 4 3 0 1 6 2 5 1 4 0 +H 7 +CX 7 2 7 4 7 5 +H 7 +MR 7 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_heuristic_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_heuristic_opt.qasm new file mode 100644 index 00000000..1a169853 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_heuristic_opt.qasm @@ -0,0 +1,23 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[7]; +qreg x_anc[1]; +creg x_c[1]; +h q[2]; +h q[4]; +h q[5]; +h q[6]; +cx q[5],q[3]; +cx q[2],q[0]; +cx q[6],q[5]; +cx q[4],q[3]; +cx q[0],q[1]; +cx q[6],q[2]; +cx q[5],q[1]; +cx q[4],q[0]; +h x_anc[0]; +cx x_anc[0],q[2]; +cx x_anc[0],q[4]; +cx x_anc[0],q[5]; +h x_anc[0]; +measure x_anc[0] -> x_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_heuristic_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_heuristic_opt.stim new file mode 100644 index 00000000..0c05ffc5 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_heuristic_opt.stim @@ -0,0 +1,6 @@ +H 2 4 5 6 +CX 5 3 2 0 6 5 4 3 0 1 6 2 5 1 4 0 +H 7 +CX 7 2 7 4 7 5 +H 7 +MR 7 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_opt_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_opt_opt.qasm new file mode 100644 index 00000000..e7328e13 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_opt_opt.qasm @@ -0,0 +1,23 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[7]; +qreg x_anc[1]; +creg x_c[1]; +h q[0]; +h q[3]; +h q[4]; +h q[5]; +cx q[3],q[1]; +cx q[4],q[3]; +cx q[4],q[6]; +cx q[0],q[2]; +cx q[5],q[0]; +cx q[5],q[6]; +cx q[2],q[3]; +cx q[3],q[5]; +h x_anc[0]; +cx x_anc[0],q[2]; +cx x_anc[0],q[4]; +cx x_anc[0],q[5]; +h x_anc[0]; +measure x_anc[0] -> x_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_opt_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_opt_opt.stim new file mode 100644 index 00000000..0fd858a0 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_ft_opt_opt.stim @@ -0,0 +1,6 @@ +H 0 3 4 5 +CX 3 1 4 3 4 6 0 2 5 0 5 6 2 3 3 5 +H 7 +CX 7 2 7 4 7 5 +H 7 +MR 7 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_non_ft_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_non_ft_heuristic.qasm new file mode 100644 index 00000000..94c3eb1b --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_non_ft_heuristic.qasm @@ -0,0 +1,15 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[7]; +h q[2]; +h q[4]; +h q[5]; +h q[6]; +cx q[5],q[3]; +cx q[2],q[0]; +cx q[6],q[5]; +cx q[4],q[3]; +cx q[0],q[1]; +cx q[6],q[2]; +cx q[5],q[1]; +cx q[4],q[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_non_ft_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_non_ft_heuristic.stim new file mode 100644 index 00000000..f523ac72 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_non_ft_heuristic.stim @@ -0,0 +1,2 @@ +H 2 4 5 6 +CX 5 3 2 0 6 5 4 3 0 1 6 2 5 1 4 0 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_non_ft_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_non_ft_opt.qasm new file mode 100644 index 00000000..4c399cf7 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_non_ft_opt.qasm @@ -0,0 +1,15 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[7]; +h q[0]; +h q[3]; +h q[4]; +h q[5]; +cx q[3],q[1]; +cx q[4],q[3]; +cx q[4],q[6]; +cx q[0],q[2]; +cx q[5],q[0]; +cx q[5],q[6]; +cx q[2],q[3]; +cx q[3],q[5]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_non_ft_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_non_ft_opt.stim new file mode 100644 index 00000000..c16a858d --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/plus_non_ft_opt.stim @@ -0,0 +1,2 @@ +H 0 3 4 5 +CX 3 1 4 3 4 6 0 2 5 0 5 6 2 3 3 5 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_heuristic_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_heuristic_heuristic.qasm new file mode 100644 index 00000000..85824798 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_heuristic_heuristic.qasm @@ -0,0 +1,20 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[7]; +qreg z_anc[1]; +creg z_c[1]; +h q[0]; +h q[1]; +h q[3]; +cx q[3],q[5]; +cx q[0],q[2]; +cx q[5],q[6]; +cx q[3],q[4]; +cx q[1],q[0]; +cx q[2],q[6]; +cx q[1],q[5]; +cx q[0],q[4]; +cx q[2],z_anc[0]; +cx q[4],z_anc[0]; +cx q[5],z_anc[0]; +measure z_anc[0] -> z_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_heuristic_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_heuristic_heuristic.stim new file mode 100644 index 00000000..6b9eeffc --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_heuristic_heuristic.stim @@ -0,0 +1,3 @@ +H 0 1 3 +CX 3 5 0 2 5 6 3 4 1 0 2 6 1 5 0 4 2 7 4 7 5 7 +MR 7 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_heuristic_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_heuristic_opt.qasm new file mode 100644 index 00000000..4d1ee2e8 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_heuristic_opt.qasm @@ -0,0 +1,20 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[7]; +qreg z_anc[1]; +creg z_c[1]; +h q[0]; +h q[1]; +h q[3]; +cx q[3],q[5]; +cx q[0],q[2]; +cx q[5],q[6]; +cx q[3],q[4]; +cx q[1],q[0]; +cx q[2],q[6]; +cx q[1],q[5]; +cx q[0],q[4]; +cx q[1],z_anc[0]; +cx q[4],z_anc[0]; +cx q[6],z_anc[0]; +measure z_anc[0] -> z_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_heuristic_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_heuristic_opt.stim new file mode 100644 index 00000000..7c5ece53 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_heuristic_opt.stim @@ -0,0 +1,3 @@ +H 0 1 3 +CX 3 5 0 2 5 6 3 4 1 0 2 6 1 5 0 4 1 7 4 7 6 7 +MR 7 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_opt_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_opt_opt.qasm new file mode 100644 index 00000000..4c6bc49b --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_opt_opt.qasm @@ -0,0 +1,20 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[7]; +qreg z_anc[1]; +creg z_c[1]; +h q[0]; +h q[3]; +h q[5]; +cx q[3],q[1]; +cx q[5],q[4]; +cx q[0],q[2]; +cx q[4],q[3]; +cx q[1],q[0]; +cx q[1],q[6]; +cx q[2],q[4]; +cx q[4],q[6]; +cx q[2],z_anc[0]; +cx q[3],z_anc[0]; +cx q[6],z_anc[0]; +measure z_anc[0] -> z_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_opt_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_opt_opt.stim new file mode 100644 index 00000000..35cf936a --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_ft_opt_opt.stim @@ -0,0 +1,3 @@ +H 0 3 5 +CX 3 1 5 4 0 2 4 3 1 0 1 6 2 4 4 6 2 7 3 7 6 7 +MR 7 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_non_ft_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_non_ft_heuristic.qasm new file mode 100644 index 00000000..2df628f2 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_non_ft_heuristic.qasm @@ -0,0 +1,14 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[7]; +h q[0]; +h q[1]; +h q[3]; +cx q[3],q[5]; +cx q[0],q[2]; +cx q[5],q[6]; +cx q[3],q[4]; +cx q[1],q[0]; +cx q[2],q[6]; +cx q[1],q[5]; +cx q[0],q[4]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_non_ft_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_non_ft_heuristic.stim new file mode 100644 index 00000000..ad3af05a --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_non_ft_heuristic.stim @@ -0,0 +1,2 @@ +H 0 1 3 +CX 3 5 0 2 5 6 3 4 1 0 2 6 1 5 0 4 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_non_ft_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_non_ft_opt.qasm new file mode 100644 index 00000000..9d04cd08 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_non_ft_opt.qasm @@ -0,0 +1,14 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[7]; +h q[0]; +h q[3]; +h q[5]; +cx q[3],q[1]; +cx q[5],q[4]; +cx q[0],q[2]; +cx q[4],q[3]; +cx q[1],q[0]; +cx q[1],q[6]; +cx q[2],q[4]; +cx q[4],q[6]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_non_ft_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_non_ft_opt.stim new file mode 100644 index 00000000..d632eeb6 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/steane/zero_non_ft_opt.stim @@ -0,0 +1,2 @@ +H 0 3 5 +CX 3 1 5 4 0 2 4 3 1 0 1 6 2 4 4 6 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_ft_heuristic_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_ft_heuristic_heuristic.qasm new file mode 100644 index 00000000..f8522b65 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_ft_heuristic_heuristic.qasm @@ -0,0 +1,43 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +qreg x_anc[1]; +creg x_c[1]; +h q[2]; +h q[4]; +h q[6]; +h q[10]; +h q[13]; +cx q[13],q[11]; +cx q[11],q[12]; +cx q[6],q[5]; +cx q[10],q[3]; +cx q[4],q[1]; +cx q[11],q[9]; +cx q[12],q[8]; +cx q[4],q[7]; +cx q[3],q[5]; +cx q[2],q[1]; +cx q[7],q[14]; +cx q[6],q[13]; +cx q[2],q[9]; +cx q[1],q[8]; +cx q[3],q[0]; +cx q[5],q[4]; +cx q[13],q[14]; +cx q[9],q[10]; +cx q[1],q[0]; +cx q[4],q[12]; +cx q[6],q[7]; +cx q[5],q[11]; +cx q[2],q[3]; +h x_anc[0]; +cx x_anc[0],q[1]; +cx x_anc[0],q[3]; +cx x_anc[0],q[5]; +cx x_anc[0],q[7]; +cx x_anc[0],q[9]; +cx x_anc[0],q[12]; +cx x_anc[0],q[13]; +h x_anc[0]; +measure x_anc[0] -> x_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_ft_heuristic_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_ft_heuristic_heuristic.stim new file mode 100644 index 00000000..2e982f66 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_ft_heuristic_heuristic.stim @@ -0,0 +1,4 @@ +H 2 4 6 10 13 15 +CX 4 1 6 5 10 3 13 11 2 1 3 5 4 7 11 12 6 13 3 0 5 4 11 9 12 8 7 14 6 7 1 8 2 9 5 11 4 12 13 14 1 0 2 3 9 10 15 1 15 3 15 5 15 7 15 9 15 12 15 13 +H 15 +MR 15 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_ft_heuristic_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_ft_heuristic_opt.qasm new file mode 100644 index 00000000..f8522b65 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_ft_heuristic_opt.qasm @@ -0,0 +1,43 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +qreg x_anc[1]; +creg x_c[1]; +h q[2]; +h q[4]; +h q[6]; +h q[10]; +h q[13]; +cx q[13],q[11]; +cx q[11],q[12]; +cx q[6],q[5]; +cx q[10],q[3]; +cx q[4],q[1]; +cx q[11],q[9]; +cx q[12],q[8]; +cx q[4],q[7]; +cx q[3],q[5]; +cx q[2],q[1]; +cx q[7],q[14]; +cx q[6],q[13]; +cx q[2],q[9]; +cx q[1],q[8]; +cx q[3],q[0]; +cx q[5],q[4]; +cx q[13],q[14]; +cx q[9],q[10]; +cx q[1],q[0]; +cx q[4],q[12]; +cx q[6],q[7]; +cx q[5],q[11]; +cx q[2],q[3]; +h x_anc[0]; +cx x_anc[0],q[1]; +cx x_anc[0],q[3]; +cx x_anc[0],q[5]; +cx x_anc[0],q[7]; +cx x_anc[0],q[9]; +cx x_anc[0],q[12]; +cx x_anc[0],q[13]; +h x_anc[0]; +measure x_anc[0] -> x_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_ft_heuristic_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_ft_heuristic_opt.stim new file mode 100644 index 00000000..2e982f66 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_ft_heuristic_opt.stim @@ -0,0 +1,4 @@ +H 2 4 6 10 13 15 +CX 4 1 6 5 10 3 13 11 2 1 3 5 4 7 11 12 6 13 3 0 5 4 11 9 12 8 7 14 6 7 1 8 2 9 5 11 4 12 13 14 1 0 2 3 9 10 15 1 15 3 15 5 15 7 15 9 15 12 15 13 +H 15 +MR 15 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_non_ft_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_non_ft_heuristic.qasm new file mode 100644 index 00000000..3a9cec96 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_non_ft_heuristic.qasm @@ -0,0 +1,31 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +h q[2]; +h q[4]; +h q[6]; +h q[10]; +h q[13]; +cx q[13],q[11]; +cx q[11],q[12]; +cx q[6],q[5]; +cx q[10],q[3]; +cx q[4],q[1]; +cx q[11],q[9]; +cx q[12],q[8]; +cx q[4],q[7]; +cx q[3],q[5]; +cx q[2],q[1]; +cx q[7],q[14]; +cx q[6],q[13]; +cx q[2],q[9]; +cx q[1],q[8]; +cx q[3],q[0]; +cx q[5],q[4]; +cx q[13],q[14]; +cx q[9],q[10]; +cx q[1],q[0]; +cx q[4],q[12]; +cx q[6],q[7]; +cx q[5],q[11]; +cx q[2],q[3]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_non_ft_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_non_ft_heuristic.stim new file mode 100644 index 00000000..79cca637 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/plus_non_ft_heuristic.stim @@ -0,0 +1,2 @@ +H 2 4 6 10 13 +CX 4 1 6 5 10 3 13 11 2 1 3 5 4 7 11 12 6 13 3 0 5 4 11 9 12 8 7 14 6 7 1 8 2 9 5 11 4 12 13 14 1 0 2 3 9 10 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_heuristic_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_heuristic_heuristic.qasm new file mode 100644 index 00000000..570bdce2 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_heuristic_heuristic.qasm @@ -0,0 +1,35 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +qreg z_anc[1]; +creg z_c[1]; +h q[0]; +h q[1]; +h q[2]; +h q[4]; +cx q[4],q[11]; +cx q[2],q[9]; +cx q[1],q[8]; +cx q[11],q[13]; +cx q[9],q[10]; +cx q[4],q[6]; +cx q[2],q[3]; +cx q[0],q[1]; +cx q[13],q[14]; +cx q[11],q[12]; +cx q[8],q[9]; +cx q[6],q[7]; +cx q[4],q[5]; +cx q[0],q[3]; +cx q[1],q[2]; +cx q[10],q[13]; +cx q[8],q[12]; +cx q[0],q[7]; +cx q[9],q[11]; +cx q[3],q[6]; +cx q[1],q[4]; +cx q[2],q[5]; +cx q[3],z_anc[0]; +cx q[4],z_anc[0]; +cx q[11],z_anc[0]; +measure z_anc[0] -> z_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_heuristic_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_heuristic_heuristic.stim new file mode 100644 index 00000000..1cc4f107 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_heuristic_heuristic.stim @@ -0,0 +1,3 @@ +H 0 1 2 4 +CX 1 8 2 9 4 11 0 1 2 3 4 6 9 10 11 13 1 2 0 3 4 5 6 7 8 9 11 12 13 14 1 4 2 5 3 6 0 7 9 11 8 12 10 13 3 15 4 15 11 15 +MR 15 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_heuristic_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_heuristic_opt.qasm new file mode 100644 index 00000000..ca1d1de3 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_heuristic_opt.qasm @@ -0,0 +1,35 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +qreg z_anc[1]; +creg z_c[1]; +h q[0]; +h q[1]; +h q[2]; +h q[4]; +cx q[4],q[11]; +cx q[2],q[9]; +cx q[1],q[8]; +cx q[11],q[13]; +cx q[9],q[10]; +cx q[4],q[6]; +cx q[2],q[3]; +cx q[0],q[1]; +cx q[13],q[14]; +cx q[11],q[12]; +cx q[8],q[9]; +cx q[6],q[7]; +cx q[4],q[5]; +cx q[0],q[3]; +cx q[1],q[2]; +cx q[10],q[13]; +cx q[8],q[12]; +cx q[0],q[7]; +cx q[9],q[11]; +cx q[3],q[6]; +cx q[1],q[4]; +cx q[2],q[5]; +cx q[0],z_anc[0]; +cx q[5],z_anc[0]; +cx q[11],z_anc[0]; +measure z_anc[0] -> z_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_heuristic_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_heuristic_opt.stim new file mode 100644 index 00000000..712b9d52 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_heuristic_opt.stim @@ -0,0 +1,3 @@ +H 0 1 2 4 +CX 1 8 2 9 4 11 0 1 2 3 4 6 9 10 11 13 1 2 0 3 4 5 6 7 8 9 11 12 13 14 1 4 2 5 3 6 0 7 9 11 8 12 10 13 0 15 5 15 11 15 +MR 15 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_opt_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_opt_opt.qasm new file mode 100644 index 00000000..c73e013d --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_opt_opt.qasm @@ -0,0 +1,35 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +qreg z_anc[1]; +creg z_c[1]; +h q[2]; +h q[6]; +h q[7]; +h q[14]; +cx q[6],q[9]; +cx q[7],q[11]; +cx q[2],q[11]; +cx q[14],q[3]; +cx q[3],q[1]; +cx q[11],q[6]; +cx q[7],q[12]; +cx q[9],q[1]; +cx q[14],q[7]; +cx q[2],q[0]; +cx q[7],q[13]; +cx q[0],q[8]; +cx q[6],q[14]; +cx q[11],q[7]; +cx q[13],q[5]; +cx q[1],q[13]; +cx q[7],q[10]; +cx q[6],q[7]; +cx q[11],q[4]; +cx q[3],q[11]; +cx q[9],q[2]; +cx q[1],q[8]; +cx q[1],z_anc[0]; +cx q[2],z_anc[0]; +cx q[10],z_anc[0]; +measure z_anc[0] -> z_c[0]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_opt_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_opt_opt.stim new file mode 100644 index 00000000..100e7cd3 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_ft_opt_opt.stim @@ -0,0 +1,3 @@ +H 2 6 7 14 +CX 6 9 7 11 14 3 3 1 2 11 7 12 2 0 9 1 11 6 14 7 0 8 9 2 7 13 6 14 11 7 13 5 7 10 11 4 1 13 6 7 1 8 3 11 1 15 2 15 10 15 +MR 15 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_non_ft_heuristic.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_non_ft_heuristic.qasm new file mode 100644 index 00000000..fb826706 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_non_ft_heuristic.qasm @@ -0,0 +1,29 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +h q[2]; +h q[6]; +h q[7]; +h q[14]; +cx q[6],q[9]; +cx q[7],q[11]; +cx q[2],q[11]; +cx q[14],q[3]; +cx q[3],q[1]; +cx q[11],q[6]; +cx q[7],q[12]; +cx q[9],q[1]; +cx q[14],q[7]; +cx q[2],q[0]; +cx q[7],q[13]; +cx q[0],q[8]; +cx q[6],q[14]; +cx q[11],q[7]; +cx q[13],q[5]; +cx q[1],q[13]; +cx q[7],q[10]; +cx q[6],q[7]; +cx q[11],q[4]; +cx q[3],q[11]; +cx q[9],q[2]; +cx q[1],q[8]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_non_ft_heuristic.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_non_ft_heuristic.stim new file mode 100644 index 00000000..4a6f21af --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_non_ft_heuristic.stim @@ -0,0 +1,2 @@ +H 2 6 7 14 +CX 6 9 7 11 14 3 3 1 2 11 7 12 2 0 9 1 11 6 14 7 0 8 9 2 7 13 6 14 11 7 13 5 7 10 11 4 1 13 6 7 1 8 3 11 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_non_ft_opt.qasm b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_non_ft_opt.qasm new file mode 100644 index 00000000..fb826706 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_non_ft_opt.qasm @@ -0,0 +1,29 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[15]; +h q[2]; +h q[6]; +h q[7]; +h q[14]; +cx q[6],q[9]; +cx q[7],q[11]; +cx q[2],q[11]; +cx q[14],q[3]; +cx q[3],q[1]; +cx q[11],q[6]; +cx q[7],q[12]; +cx q[9],q[1]; +cx q[14],q[7]; +cx q[2],q[0]; +cx q[7],q[13]; +cx q[0],q[8]; +cx q[6],q[14]; +cx q[11],q[7]; +cx q[13],q[5]; +cx q[1],q[13]; +cx q[7],q[10]; +cx q[6],q[7]; +cx q[11],q[4]; +cx q[3],q[11]; +cx q[9],q[2]; +cx q[1],q[8]; diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_non_ft_opt.stim b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_non_ft_opt.stim new file mode 100644 index 00000000..4a6f21af --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/circuits/tetrahedral/zero_non_ft_opt.stim @@ -0,0 +1,2 @@ +H 2 6 7 14 +CX 6 9 7 11 14 3 3 1 2 11 7 12 2 0 9 1 11 6 14 7 0 8 9 2 7 13 6 14 11 7 13 5 7 10 11 4 1 13 6 7 1 8 3 11 diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/estimate_logical_error_rate.py b/src/mqt/qecc/circuit_synthesis/stateprep_eval/estimate_logical_error_rate.py new file mode 100644 index 00000000..b6b13bde --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/estimate_logical_error_rate.py @@ -0,0 +1,100 @@ +"""Estimate logical error rate for CSS state preparation circuits for a given code and physical error rate.""" + +from __future__ import annotations + +import argparse +from pathlib import Path + +from qiskit import QuantumCircuit + +from mqt.qecc import CSSCode +from mqt.qecc.circuit_synthesis import ( + NoisyNDFTStatePrepSimulator, + gate_optimal_prep_circuit, + gate_optimal_verification_circuit, + heuristic_prep_circuit, + heuristic_verification_circuit, + naive_verification_circuit, +) +from mqt.qecc.codes import HexagonalColorCode, SquareOctagonColorCode + + +def main() -> None: + """Run the logical error rate estimation for a given code and physical error rate.""" + available_codes = ["steane", "tetrahedral", "shor", "surface", "cc_4_8_8", "cc_6_6_6", "hamming", "carbon"] + parser = argparse.ArgumentParser(description="Estimate logical error rate for CSS state preparation circuits") + parser.add_argument( + "code", + type=str, + help="Code for which to estimate logical error rate. Available codes: " + ", ".join(available_codes), + ) + parser.add_argument("-p", "--p_error", type=float, help="Physical error rate") + parser.add_argument("--zero_state", default=True, action="store_true", help="Synthesize logical |0> state.") + parser.add_argument( + "--plus_state", default=False, dest="zero_state", action="store_false", help="Synthesize logical |+> state." + ) + parser.add_argument("-n", "--n_errors", type=int, default=500, help="Number of errors to sample") + parser.add_argument("--exact_circ", default=False, action="store_true", help="Use exact synthesis") + parser.add_argument("--heuristic_circ", dest="exact_circ", action="store_false", help="Use heuristic synthesis") + parser.add_argument("--exact_ver", default=True, action="store_true", help="Use exact verification") + parser.add_argument("--heuristic_ver", dest="exact_ver", action="store_false", help="Use heuristic verification") + parser.add_argument("--naive_ver", default=False, action="store_true", help="Use naive verification") + parser.add_argument("--no_ver", action="store_true", help="Use no verification") + parser.add_argument( + "-d", "--distance", type=int, default=3, help="Code Distance (only required for surface and color codes)" + ) + parser.add_argument("--no_parallel_gates", default=False, action="store_true") + + args = parser.parse_args() + code_name = args.code + if "surface" in code_name: + d = args.distance + code = CSSCode.from_code_name("surface", d) + code_name = f"rotated_surface_d{d}" + elif "cc_4_8_8" in code_name: + d = 5 + code = SquareOctagonColorCode(d) + elif "cc_6_6_6" in code_name: + d = 5 + code = HexagonalColorCode(d) + elif code_name in available_codes: + code = CSSCode.from_code_name(code_name) + else: + raise ValueError("Code " + code_name + " not available. Available codes: " + ", ".join(available_codes)) + + prefix = (Path(__file__) / "../circuits/").resolve() + sp_circ_name = "opt" if args.exact_circ else "heuristic" + ver_circ_name = ("opt" if args.exact_ver else "heuristic") if not args.naive_ver else "naive" + + state_name = "zero" if args.zero_state else "plus" + ft_name = "non_ft" if args.no_ver else "ft" + circ_file = f"{state_name}_{ft_name}_{sp_circ_name}_{ver_circ_name}.qasm" + + # check if file exists + if not (prefix / code_name / circ_file).exists(): + # create circuit + circ = None + if args.exact_circ: + circ = gate_optimal_prep_circuit(code, zero_state=args.zero_state, max_timeout=600) + else: + circ = heuristic_prep_circuit(code, zero_state=args.zero_state) + + assert circ is not None + if args.naive_ver: + qc = naive_verification_circuit(circ) + elif args.exact_ver: + qc = gate_optimal_verification_circuit(circ, max_timeout=600) + else: + qc = heuristic_verification_circuit(circ) + else: + # load circuit from file + qc = QuantumCircuit.from_qasm_file(prefix / code_name / circ_file) + + sim = NoisyNDFTStatePrepSimulator( + qc, code=code, p=args.p_error, zero_state=args.zero_state, parallel_gates=not args.no_parallel_gates + ) + sim.logical_error_rate(min_errors=args.n_errors) + + +if __name__ == "__main__": + main() diff --git a/src/mqt/qecc/circuit_synthesis/stateprep_eval/run_eval_on_code.sh b/src/mqt/qecc/circuit_synthesis/stateprep_eval/run_eval_on_code.sh new file mode 100755 index 00000000..c56aa315 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/stateprep_eval/run_eval_on_code.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# Description: Estimate logical error rates for given code in parallel. Results are saved in a csv file described by the first argument. All other arguments are passed to the python script. + +declare -a p=("0.00005" "0.00006" "0.00007" "0.00008" "0.00009" "0.0001" "0.0002" "0.0003" "0.0004" "0.0005" "0.0006" "0.0007" "0.0008" "0.0009" "0.001" "0.002" "0.003" "0.004" "0.005" "0.006" "0.007" "0.008" "0.009" "0.01" "0.02" "0.03" "0.04" "0.05" "0.06" "0.07" "0.08" "0.09" "0.1" "0.2" "0.3" "0.4" "0.5") + +echo "p p_l acceptance errors runs" > "$1.csv" + +run_and_write() { + local res=$(python estimate_logical_error_rate.py ${@:2:$#-2} "-p" "${@: -1}") + local line="${@: -1} ${res}" + (flock -e 200 echo $line >> "$1.csv") 200>lock +} + +export -f run_and_write + +parallel --load 16 --link run_and_write $@ ::: ${p[@]} diff --git a/src/mqt/qecc/circuit_synthesis/synthesis_utils.py b/src/mqt/qecc/circuit_synthesis/synthesis_utils.py new file mode 100644 index 00000000..0aaac546 --- /dev/null +++ b/src/mqt/qecc/circuit_synthesis/synthesis_utils.py @@ -0,0 +1,877 @@ +"""Utility functions for synthesizing circuits.""" + +from __future__ import annotations + +import functools +import logging +from typing import TYPE_CHECKING, Any + +import multiprocess +import numpy as np +import z3 +from ldpc import mod2 +from qiskit import AncillaRegister, ClassicalRegister, QuantumCircuit +from stim import Circuit + +if TYPE_CHECKING: # pragma: no cover + from collections.abc import Callable + + import numpy.typing as npt + from qiskit import AncillaQubit, ClBit, Qubit + + +logger = logging.getLogger(__name__) + + +def run_with_timeout(func: Callable[[Any], Any], *args: Any, timeout: int = 10) -> Any | str | None: # noqa: ANN401 + """Run a function with a timeout. + + If the function does not complete within the timeout, return None. + + Args: + func: The function to run. + args: The arguments to pass to the function. + timeout: The maximum time to allow the function to run for in seconds. + """ + manager = multiprocess.Manager() + return_list = manager.list() + p = multiprocess.Process(target=lambda: return_list.append(func(*args))) + p.start() + p.join(timeout) + if p.is_alive(): + p.terminate() + return "timeout" + return return_list[0] + + +def iterative_search_with_timeout( + fun: Callable[[int], QuantumCircuit], + min_param: int, + max_param: int, + min_timeout: int, + max_timeout: int, + param_factor: float = 2, + timeout_factor: float = 2, +) -> None | tuple[None | QuantumCircuit, int]: + """Geometrically increases the parameter and timeout until a result is found or the maximum timeout is reached. + + Args: + fun: function to run with increasing parameters and timeouts + min_param: minimum parameter to start with + max_param: maximum parameter to reach + min_timeout: minimum timeout to start with + max_timeout: maximum timeout to reach + param_factor: factor to increase the parameter by at each iteration + timeout_factor: factor to increase the timeout by at each iteration + """ + curr_timeout = min_timeout + curr_param = min_param + while curr_timeout <= max_timeout: + while curr_param <= max_param: + logging.info(f"Running iterative search with param={curr_param} and timeout={curr_timeout}") + res = run_with_timeout(fun, curr_param, timeout=curr_timeout) + if res is not None and (not isinstance(res, str) or res != "timeout"): + return res, curr_param + if curr_param == max_param: + break + + curr_param = int(curr_param * param_factor) + curr_param = min(curr_param, max_param) + + curr_timeout = int(curr_timeout * timeout_factor) + curr_param = min_param + return None, max_param + + +def heuristic_gaussian_elimination( + matrix: npt.NDArray[np.int8], parallel_elimination: bool = True +) -> tuple[npt.NDArray[np.int8], list[tuple[int, int]]]: + """Perform Gaussian elimination on the column space of a matrix using as few eliminations as possible. + + The algorithm utilizes a greedy heuristic to select the columns to eliminate in order to minimize the number of eliminations required. + + The matrix is reduced until there are exactly rnk(matrix) columns with non-zero entries. + + Args: + matrix: The matrix to perform Gaussian elimination on. + parallel_elimination: Whether to prioritize elimination steps that act on disjoint columns. + + returns: + The reduced matrix and a list of the elimination steps taken. The elimination steps are represented as tuples of the form (i, j) where i is the column being eliminated with and j is the column being eliminated. + """ + matrix = matrix.copy() + rank = mod2.rank(matrix) + + def is_reduced() -> bool: + return bool(len(np.where(np.all(matrix == 0, axis=0))[0]) == matrix.shape[1] - rank) + + costs = np.array([ + [np.sum((matrix[:, i] + matrix[:, j]) % 2) for j in range(matrix.shape[1])] for i in range(matrix.shape[1]) + ]) + + costs -= np.sum(matrix, axis=0) + np.fill_diagonal(costs, 1) + + used_columns = [] # type: list[np.int_] + eliminations = [] # type: list[tuple[int, int]] + while not is_reduced(): + m = np.zeros((matrix.shape[1], matrix.shape[1]), dtype=bool) # type: npt.NDArray[np.bool_] + m[used_columns, :] = True + m[:, used_columns] = True + + costs_unused = np.ma.array(costs, mask=m) # type: ignore[no-untyped-call] + if np.all(costs_unused >= 0) or len(used_columns) == matrix.shape[1]: # no more reductions possible + if used_columns == []: # local minimum => get out by making matrix triangular + logging.warning("Local minimum reached. Making matrix triangular.") + matrix = mod2.row_echelon(matrix, full=True)[0] + costs = np.array([ + [np.sum((matrix[:, i] + matrix[:, j]) % 2) for j in range(matrix.shape[1])] + for i in range(matrix.shape[1]) + ]) + costs -= np.sum(matrix, axis=0) + np.fill_diagonal(costs, 1) + else: # try to move onto the next layer + used_columns = [] + continue + + i, j = np.unravel_index(np.argmin(costs_unused), costs.shape) + eliminations.append((int(i), int(j))) + + if parallel_elimination: + used_columns.append(i) + used_columns.append(j) + + # update matrix + matrix[:, j] = (matrix[:, i] + matrix[:, j]) % 2 + # update costs + new_weights = np.sum((matrix[:, j][:, np.newaxis] + matrix) % 2, axis=0) + costs[j, :] = new_weights - np.sum(matrix, axis=0) + costs[:, j] = new_weights - np.sum(matrix[:, j]) + np.fill_diagonal(costs, 1) + + return matrix, eliminations + + +def gaussian_elimination_min_column_ops( + matrix: npt.NDArray[np.int8], + termination_criteria: Callable[[Any], z3.BoolRef], + max_eliminations: int, +) -> tuple[npt.NDArray[np.int8], list[tuple[int, int]]] | None: + """Perform Gaussian elimination on the column space of a matrix using at most `max_eliminations` eliminations. + + The algorithm encodes the elimination into an SMT problem and uses Z3 to find the optimal solution. + + Args: + matrix: The matrix to perform Gaussian elimination on. + termination_criteria: A function that takes a boolean matrix as input and returns a Z3 boolean expression that is true if the matrix is considered reduced. + max_eliminations: The maximum number of eliminations to perform. + + returns: + The reduced matrix and a list of the elimination steps taken. The elimination steps are represented as tuples of the form (i, j) where i is the column being eliminated with and j is the column being eliminated. + """ + n = matrix.shape[1] + columns = np.array([ + [[z3.Bool(f"x_{d}_{i}_{j}") for j in range(n)] for i in range(matrix.shape[0])] + for d in range(max_eliminations + 1) + ]) + + n_bits = int(np.ceil(np.log2(n))) + targets = [z3.BitVec(f"target_{d}", n_bits) for d in range(max_eliminations)] + controls = [z3.BitVec(f"control_{d}", n_bits) for d in range(max_eliminations)] + s = z3.Solver() + + additions = np.array([ + [[z3.And(controls[d] == col_1, targets[d] == col_2) for col_2 in range(n)] for col_1 in range(n)] + for d in range(max_eliminations) + ]) + + # create initial matrix + columns[0, :, :] = matrix.astype(bool) + + if max_eliminations != 0: + s.add(_column_addition_constraint(columns, additions)) + + for d in range(1, max_eliminations + 1): + # two columns cannot be in two elimination steps at the same time + s.add(controls[d - 1] != targets[d - 1]) + + # control and target must be valid qubits + + if n and (n - 1) != 0 and not ((n & (n - 1) == 0) and n != 0): # check if n is a power of 2 or 1 or 0 + s.add(z3.ULT(controls[d - 1], n)) + s.add(z3.ULT(targets[d - 1], n)) + + # if column is not involved in any addition at certain depth, it is the same as the previous column + for d in range(1, max_eliminations + 1): + for col in range(n): + s.add(z3.Implies(targets[d - 1] != col, symbolic_vector_eq(columns[d, :, col], columns[d - 1, :, col]))) + + # assert that final check matrix has n-checks.shape[0] zero columns + s.add(termination_criteria(columns)) + + if s.check() == z3.sat: + if max_eliminations == 0: + return matrix, [] + + m = s.model() + eliminations = [(m[controls[d]].as_long(), m[targets[d]].as_long()) for d in range(max_eliminations)] + reduced = np.array([ + [bool(m[columns[max_eliminations][i][j]]) for j in range(n)] for i in range(matrix.shape[0]) + ]).astype(np.int8) # type: npt.NDArray[np.int8] + return reduced, eliminations + + return None + + +def gaussian_elimination_min_parallel_eliminations( + matrix: npt.NDArray[np.int8], termination_criteria: Callable[[Any], z3.BoolRef], max_parallel_steps: int +) -> tuple[npt.NDArray[np.int8], list[tuple[int, int]]] | None: + """Perform Gaussian elimination on the column space of a matrix using at most `max_parallel_steps` parallel column elimination steps. + + The algorithm encodes the elimination into a SAT problem and uses Z3 to find the optimal solution. + + Args: + matrix: The matrix to perform Gaussian elimination on. + termination_criteria: A function that takes a boolean matrix as input and returns a Z3 boolean expression that is true if the matrix is considered reduced. + max_parallel_steps: The maximum number of parallel elimination steps to perform. + + returns: + The reduced matrix and a list of the elimination steps taken. The elimination steps are represented as tuples of the form (i, j) where i is the column being eliminated with and j is the column being eliminated. + """ + columns = np.array([ + [[z3.Bool(f"x_{d}_{i}_{j}") for j in range(matrix.shape[1])] for i in range(matrix.shape[0])] + for d in range(max_parallel_steps + 1) + ]) + + additions = np.array([ + [[z3.Bool(f"add_{d}_{i}_{j}") for j in range(matrix.shape[1])] for i in range(matrix.shape[1])] + for d in range(max_parallel_steps) + ]) + n_cols = matrix.shape[1] + s = z3.Solver() + + # create initial matrix + columns[0, :, :] = matrix.astype(bool) + + if max_parallel_steps != 0: + s.add(_column_addition_constraint(columns, additions)) + + # qubit can be involved in at most one addition at each depth + for d in range(max_parallel_steps): + for col in range(n_cols): + s.add( + z3.PbLe( + [(additions[d, col_1, col], 1) for col_1 in range(n_cols) if col != col_1] + + [(additions[d, col, col_2], 1) for col_2 in range(n_cols) if col != col_2], + 1, + ) + ) + + # if column is not involved in any addition at certain depth, it is the same as the previous column + for d in range(1, max_parallel_steps + 1): + for col in range(n_cols): + s.add( + z3.Implies( + z3.Not( + z3.Or( + list(np.delete(additions[d - 1, :, col], [col])) + + list(np.delete(additions[d - 1, col, :], [col])) + ) + ), + symbolic_vector_eq(columns[d, :, col], columns[d - 1, :, col]), + ) + ) + + s.add(termination_criteria(columns)) + + if s.check() == z3.sat: + if max_parallel_steps == 0: + return matrix, [] + m = s.model() + eliminations = [ + (i, j) + for d in range(max_parallel_steps) + for j in range(matrix.shape[1]) + for i in range(matrix.shape[1]) + if m[additions[d, i, j]] + ] + reduced = np.array([ + [bool(m[columns[max_parallel_steps, i, j]]) for j in range(matrix.shape[1])] for i in range(matrix.shape[0]) + ]).astype(np.int8) # type: npt.NDArray[np.int8] + return reduced, eliminations + + return None + + +def build_css_circuit_from_cnot_list(n: int, cnots: list[tuple[int, int]], hadamards: list[int]) -> QuantumCircuit: + """Build a quantum circuit consisting of Hadamards followed by a layer of CNOTs from a list of CNOTs and a list of checks. + + Args: + n: Number of qubits in the circuit. + cnots: List of CNOTs to apply. Each CNOT is a tuple of the form (control, target). + hadamards: List of qubits to apply Hadamards to. + + Returns: + The quantum circuit. + """ + circ = QuantumCircuit(n) + circ.h(hadamards) + for i, j in cnots: + circ.cx(i, j) + return circ + + +def _column_addition_constraint( + columns: npt.NDArray[z3.BoolRef | bool], + col_add_vars: npt.NDArray[z3.BoolRef], +) -> z3.BoolRef: + assert len(columns.shape) == 3 + max_parallel_steps = col_add_vars.shape[0] + n_cols = col_add_vars.shape[2] + + constraints = [] + for d in range(1, max_parallel_steps + 1): + for col_1 in range(n_cols): + for col_2 in range(col_1 + 1, n_cols): + col_sum = symbolic_vector_add(columns[d - 1, :, col_1], columns[d - 1, :, col_2]) + + # encode col_2 += col_1 + add_col1_to_col2 = z3.Implies( + col_add_vars[d - 1, col_1, col_2], + z3.And( + symbolic_vector_eq(columns[d, :, col_2], col_sum), + symbolic_vector_eq(columns[d, :, col_1], columns[d - 1, :, col_1]), + ), + ) + + # encode col_1 += col_2 + add_col2_to_col1 = z3.Implies( + col_add_vars[d - 1, col_2, col_1], + z3.And( + symbolic_vector_eq(columns[d, :, col_1], col_sum), + symbolic_vector_eq(columns[d, :, col_2], columns[d - 1, :, col_2]), + ), + ) + + constraints.extend([add_col1_to_col2, add_col2_to_col1]) + + return z3.And(constraints) + + +def symbolic_vector_eq(v1: npt.NDArray[z3.BoolRef | bool], v2: npt.NDArray[z3.BoolRef | bool]) -> z3.BoolRef: + """Return assertion that two symbolic vectors should be equal.""" + constraints = [False for _ in v1] + for i in range(len(v1)): + # If one of the elements is a bool, we can simplify the expression + v1_i_is_bool = isinstance(v1[i], (bool, np.bool_)) + v2_i_is_bool = isinstance(v2[i], (bool, np.bool_)) + if v1_i_is_bool: + v1[i] = bool(v1[i]) + if v1[i]: + constraints[i] = v2[i] + else: + constraints[i] = z3.Not(v2[i]) if not v2_i_is_bool else not v2[i] + + elif v2_i_is_bool: + v2[i] = bool(v2[i]) + if v2[i]: + constraints[i] = v1[i] + else: + constraints[i] = z3.Not(v1[i]) + else: + constraints[i] = v1[i] == v2[i] + return z3.And(constraints) + + +def odd_overlap(v_sym: npt.NDArray[z3.BoolRef | bool], v_con: npt.NDArray[np.int8]) -> z3.BoolRef: + """Return True if the overlap of symbolic vector with constant vector is odd.""" + if np.array_equal(v_con, np.zeros(len(v_con), dtype=np.int8)): + return z3.BoolVal(False) + return z3.PbEq([(v_sym[i], 1) for i, c in enumerate(v_con) if c == 1], 1) + + +def symbolic_scalar_mult(v: npt.NDArray[np.int8], a: z3.BoolRef | bool) -> npt.NDArray[z3.BoolRef]: + """Multiply a concrete vector by a symbolic scalar.""" + return np.array([a if s == 1 else False for s in v]) + + +def symbolic_vector_add( + v1: npt.NDArray[z3.BoolRef | bool], v2: npt.NDArray[z3.BoolRef | bool] +) -> npt.NDArray[z3.BoolRef | bool]: + """Add two symbolic vectors.""" + v_new = [False for _ in range(len(v1))] + for i in range(len(v1)): + # If one of the elements is a bool, we can simplify the expression + v1_i_is_bool = isinstance(v1[i], (bool, np.bool_)) + v2_i_is_bool = isinstance(v2[i], (bool, np.bool_)) + if v1_i_is_bool: + v1[i] = bool(v1[i]) + if v1[i]: + v_new[i] = z3.Not(v2[i]) if not v2_i_is_bool else not v2[i] + else: + v_new[i] = v2[i] + + elif v2_i_is_bool: + v2[i] = bool(v2[i]) + if v2[i]: + v_new[i] = z3.Not(v1[i]) + else: + v_new[i] = v1[i] + + else: + v_new[i] = z3.Xor(v1[i], v2[i]) + + return np.array(v_new) + + +def optimal_elimination( + matrix: npt.NDArray[np.int8], + termination_criteria: Callable[[Any], z3.BoolRef], + optimization_metric: str = "column_ops", + min_param: int = 1, + max_param: int = 10, + min_timeout: int = 1, + max_timeout: int = 3600, +) -> tuple[npt.NDArray[np.int8], list[tuple[int, int]]] | None: + """Synthesize a state preparation circuit for a CSS code that minimizes the circuit w.r.t. some metric param according to prep_func. + + Args: + matrix: The stabilizer matrix of the CSS code. + termination_criteria: The termination criteria for when the matrix is considered reduced. + optimization_metric: The metric to optimize the circuit w.r.t. to. Can be either "column_ops" or "parallel_ops". + zero_state: Whether to start from the zero state. + min_param: The minimum value of the metric parameter. + max_param: The maximum value of the metric parameter. + min_timeout: The minimum time to run one search iteration for. + max_timeout: The maximum time to run one search iteration for. + """ + if optimization_metric not in {"column_ops", "parallel_ops"}: + msg = "Invalid optimization metric" + raise ValueError(msg) + + opt_fun = { + "column_ops": gaussian_elimination_min_column_ops, + "parallel_ops": gaussian_elimination_min_parallel_eliminations, + }[optimization_metric] + + fun = functools.partial( + opt_fun, + matrix, + termination_criteria, + ) + + res = iterative_search_with_timeout( + fun, + min_param, + max_param, + min_timeout, + max_timeout, + ) + + if res is None: + return None + reduced = res[0] + if reduced is None: + return None + reduced, eliminations = reduced + curr_param = res[1] + + logging.info(f"Solution found with param {curr_param}") + # Solving a SAT instance is much faster than proving unsat in this case + # so we iterate backwards until we find an unsat instance or hit a timeout + logging.info("Trying to minimize param") + while True: + logging.info(f"Trying param {curr_param - 1}") + opt_res = run_with_timeout(fun, curr_param - 1, timeout=max_timeout) + if opt_res is None or (isinstance(opt_res, str) and opt_res == "timeout"): + break + assert not isinstance(opt_res, str) + reduced, eliminations = opt_res + curr_param -= 1 + + logging.info(f"Optimal param: {curr_param}") + return reduced, eliminations + + +def _ancilla_cnot(qc: QuantumCircuit, qubit: Qubit | AncillaQubit, ancilla: AncillaQubit, z_measurement: bool) -> None: + if z_measurement: + qc.cx(qubit, ancilla) + else: + qc.cx(ancilla, qubit) + + +def _flag_measure(qc: QuantumCircuit, flag: AncillaQubit, meas_bit: ClBit, z_measurement: bool) -> None: + if z_measurement: + qc.h(flag) + qc.measure(flag, meas_bit) + + +def _flag_reset(qc: QuantumCircuit, flag: AncillaQubit, z_measurement: bool) -> None: + qc.reset(flag) + if z_measurement: + qc.h(flag) + + +def _flag_init(qc: QuantumCircuit, flag: AncillaQubit, z_measurement: bool) -> None: + if z_measurement: + qc.h(flag) + + +def measure_stab_unflagged( + qc: QuantumCircuit, + stab: list[Qubit] | npt.NDArray[np.int_], + ancilla: AncillaQubit, + measurement_bit: ClBit, + z_measurement: bool = True, +) -> None: + """Measure a stabilizer without flags. The measurement is done in place. + + Args: + qc: The quantum circuit to add the measurement to. + stab: The qubits to measure. + ancilla: The ancilla qubit to use for the measurement. + measurement_bit: The classical bit to store the measurement result of the ancilla. + z_measurement: Whether to measure the ancilla in the Z basis. + """ + if not z_measurement: + qc.h(ancilla) + qc.cx([ancilla] * len(stab), stab) + qc.h(ancilla) + else: + qc.cx(stab, [ancilla] * len(stab)) + qc.measure(ancilla, measurement_bit) + + +def measure_flagged( + qc: QuantumCircuit, + stab: list[Qubit] | npt.NDArray[np.int_], + ancilla: AncillaQubit, + measurement_bit: ClBit, + t: int, + z_measurement: bool = True, +) -> None: + """Measure a w-flagged stabilizer with the general scheme. + + The measurement is done in place. + + Args: + qc: The quantum circuit to add the measurement to. + stab: The qubits to measure. + ancilla: The ancilla qubit to use for the measurement. + measurement_bit: The classical bit to store the measurement result of the ancilla. + t: The number of errors to protect against. + z_measurement: Whether to measure an X (False) or Z (True) stabilizer. + """ + w = len(stab) + if w < 3: + measure_stab_unflagged(qc, stab, ancilla, measurement_bit, z_measurement) + return + + if t == 1: + measure_one_flagged(qc, stab, ancilla, measurement_bit, z_measurement) + return + + if w == 4 and t >= 2: + measure_two_flagged_4(qc, stab, ancilla, measurement_bit, z_measurement) + return + + if w == 6 and t == 2: + measure_flagged_6(qc, stab, ancilla, measurement_bit, z_measurement) + return + + if w == 8 and t == 2: + measure_flagged_8(qc, stab, ancilla, measurement_bit, z_measurement) + return + + if t == 2: + measure_two_flagged(qc, stab, ancilla, measurement_bit, z_measurement) + return + + msg = f"Flagged measurement for w={w} and t={t} not implemented." + raise NotImplementedError(msg) + + +def measure_one_flagged( + qc: QuantumCircuit, + stab: list[Qubit] | npt.NDArray[np.int_], + ancilla: AncillaQubit, + measurement_bit: ClBit, + z_measurement: bool = True, +) -> None: + """Measure a 1-flagged stabilizer. + + In this case only one flag is required. + """ + flag_reg = AncillaRegister(1) + meas_reg = ClassicalRegister(1) + qc.add_register(flag_reg) + qc.add_register(meas_reg) + flag = flag_reg[0] + flag_meas = meas_reg[0] + if not z_measurement: + qc.h(ancilla) + + _ancilla_cnot(qc, stab[0], ancilla, z_measurement) + _flag_init(qc, flag, z_measurement) + + _ancilla_cnot(qc, flag, ancilla, z_measurement) + + for q in stab[1:-1]: + _ancilla_cnot(qc, q, ancilla, z_measurement) + + _ancilla_cnot(qc, flag, ancilla, z_measurement) + _flag_measure(qc, flag, flag_meas, z_measurement) + + _ancilla_cnot(qc, stab[-1], ancilla, z_measurement) + + if not z_measurement: + qc.h(ancilla) + qc.measure(ancilla, measurement_bit) + + +def measure_two_flagged( + qc: QuantumCircuit, + stab: list[Qubit] | npt.NDArray[np.int_], + ancilla: AncillaQubit, + measurement_bit: ClBit, + z_measurement: bool = True, +) -> None: + """Measure a 2-flagged stabilizer using the scheme of https://arxiv.org/abs/1708.02246 (page 13).""" + if len(stab) <= 4: + measure_one_flagged(qc, stab, ancilla, measurement_bit, z_measurement) + return + if len(stab) == 6: + measure_flagged_6(qc, stab, ancilla, measurement_bit, z_measurement) + return + if len(stab) == 8: + measure_flagged_8(qc, stab, ancilla, measurement_bit, z_measurement) + return + + n_flags = (len(stab) + 1) // 2 - 1 + flag_reg = AncillaRegister(n_flags) + meas_reg = ClassicalRegister(n_flags) + + qc.add_register(flag_reg) + qc.add_register(meas_reg) + + if not z_measurement: + qc.h(ancilla) + + _ancilla_cnot(qc, stab[0], ancilla, z_measurement) + + _flag_init(qc, flag_reg[0], z_measurement) + _ancilla_cnot(qc, flag_reg[0], ancilla, z_measurement) + + _ancilla_cnot(qc, stab[1], ancilla, z_measurement) + _flag_init(qc, flag_reg[1], z_measurement) + _ancilla_cnot(qc, flag_reg[1], ancilla, z_measurement) + + cnots = 2 + flags = 2 + for q in stab[2:-2]: + _ancilla_cnot(qc, q, ancilla, z_measurement) + cnots += 1 + if cnots % 2 == 0 and cnots < len(stab) - 2: + _flag_init(qc, flag_reg[flags], z_measurement) + _ancilla_cnot(qc, flag_reg[flags], ancilla, z_measurement) + if cnots >= 7 and cnots % 2 == 1: + _ancilla_cnot(qc, flag_reg[flags - 2], ancilla, z_measurement) + _flag_measure(qc, flag_reg[flags - 2], meas_reg[flags - 2], z_measurement) + if cnots % 2 == 0 and cnots < len(stab) - 2: + flags += 1 + + _ancilla_cnot(qc, flag_reg[0], ancilla, z_measurement) + _flag_measure(qc, flag_reg[0], meas_reg[0], z_measurement) + + _ancilla_cnot(qc, stab[-2], ancilla, z_measurement) + + cnots += 1 + if cnots >= 7 and cnots % 2 == 1: + _ancilla_cnot(qc, flag_reg[flags - 1], ancilla, z_measurement) + _flag_measure(qc, flag_reg[flags - 1], meas_reg[flags - 1], z_measurement) + + _ancilla_cnot(qc, flag_reg[1], ancilla, z_measurement) + _flag_measure(qc, flag_reg[1], meas_reg[1], z_measurement) + + _ancilla_cnot(qc, stab[-1], ancilla, z_measurement) + + cnots += 1 + if cnots >= 7 and cnots % 2 == 1: + _ancilla_cnot(qc, flag_reg[flags - 1], ancilla, z_measurement) + _flag_measure(qc, flag_reg[flags - 1], meas_reg[flags - 1], z_measurement) + if not z_measurement: + qc.h(ancilla) + + qc.measure(ancilla, measurement_bit) + + +def measure_two_flagged_4( + qc: QuantumCircuit, + stab: list[Qubit] | npt.NDArray[np.int_], + ancilla: AncillaQubit, + measurement_bit: ClBit, + z_measurement: bool = True, +) -> None: + """Measure a 2-flagged weight 4 stabilizer. In this case only one flag is required. + + Args: + qc: QuantumCircuit + stab: list[Qubit] | npt.NDArray[np.int_] + ancilla: AncillaQubit + measurement_bit: ClBit + z_measurement: bool = True + """ + assert len(stab) == 4 + flag_reg = AncillaRegister(1) + meas_reg = ClassicalRegister(1) + qc.add_register(flag_reg) + qc.add_register(meas_reg) + flag = flag_reg[0] + flag_meas = meas_reg[0] + + if not z_measurement: + qc.h(ancilla) + + _ancilla_cnot(qc, stab[0], ancilla, z_measurement) + _flag_init(qc, flag, z_measurement) + + _ancilla_cnot(qc, flag, ancilla, z_measurement) + + _ancilla_cnot(qc, stab[1], ancilla, z_measurement) + _ancilla_cnot(qc, stab[2], ancilla, z_measurement) + + _ancilla_cnot(qc, flag, ancilla, z_measurement) + _flag_measure(qc, flag, flag_meas, z_measurement) + + _ancilla_cnot(qc, stab[3], ancilla, z_measurement) + + if not z_measurement: + qc.h(ancilla) + qc.measure(ancilla, measurement_bit) + + +def measure_flagged_6( + qc: QuantumCircuit, + stab: list[Qubit] | npt.NDArray[np.int_], + ancilla: AncillaQubit, + measurement_bit: ClBit, + z_measurement: bool = True, +) -> None: + """Measure a 6-flagged stabilizer using an optimized scheme.""" + assert len(stab) == 6 + flag = AncillaRegister(2) + meas = ClassicalRegister(2) + + qc.add_register(flag) + qc.add_register(meas) + + if not z_measurement: + qc.h(ancilla) + + _ancilla_cnot(qc, stab[0], ancilla, z_measurement) + + _flag_init(qc, flag[0], z_measurement) + _ancilla_cnot(qc, flag[0], ancilla, z_measurement) + + _ancilla_cnot(qc, stab[1], ancilla, z_measurement) + + _flag_init(qc, flag[1], z_measurement) + _ancilla_cnot(qc, flag[1], ancilla, z_measurement) + + _ancilla_cnot(qc, stab[2], ancilla, z_measurement) + _ancilla_cnot(qc, stab[3], ancilla, z_measurement) + + _ancilla_cnot(qc, flag[0], ancilla, z_measurement) + _flag_measure(qc, flag[0], meas[0], z_measurement) + + _ancilla_cnot(qc, stab[4], ancilla, z_measurement) + + _ancilla_cnot(qc, flag[1], ancilla, z_measurement) + _flag_measure(qc, flag[1], meas[1], z_measurement) + + _ancilla_cnot(qc, stab[5], ancilla, z_measurement) + + if not z_measurement: + qc.h(ancilla) + qc.measure(ancilla, measurement_bit) + + +def measure_flagged_8( + qc: QuantumCircuit, + stab: list[Qubit] | npt.NDArray[np.int_], + ancilla: AncillaQubit, + measurement_bit: ClBit, + z_measurement: bool = True, +) -> None: + """Measure an 8-flagged stabilizer using an optimized scheme.""" + assert len(stab) == 8 + flag = AncillaRegister(3) + meas = ClassicalRegister(3) + qc.add_register(flag) + qc.add_register(meas) + + if not z_measurement: + qc.h(ancilla) + + _ancilla_cnot(qc, stab[0], ancilla, z_measurement) + + _flag_init(qc, flag[0], z_measurement) + _ancilla_cnot(qc, flag[0], ancilla, z_measurement) + + _ancilla_cnot(qc, stab[1], ancilla, z_measurement) + + _flag_init(qc, flag[1], z_measurement) + _ancilla_cnot(qc, flag[1], ancilla, z_measurement) + + _ancilla_cnot(qc, stab[2], ancilla, z_measurement) + _ancilla_cnot(qc, stab[3], ancilla, z_measurement) + + _flag_init(qc, flag[2], z_measurement) + _ancilla_cnot(qc, flag[2], ancilla, z_measurement) + + _ancilla_cnot(qc, stab[4], ancilla, z_measurement) + _ancilla_cnot(qc, stab[5], ancilla, z_measurement) + + _ancilla_cnot(qc, flag[0], ancilla, z_measurement) + _flag_measure(qc, flag[0], meas[0], z_measurement) + + _ancilla_cnot(qc, stab[6], ancilla, z_measurement) + + _ancilla_cnot(qc, flag[2], ancilla, z_measurement) + _flag_measure(qc, flag[2], meas[2], z_measurement) + + _ancilla_cnot(qc, flag[1], ancilla, z_measurement) + _flag_measure(qc, flag[1], meas[1], z_measurement) + + _ancilla_cnot(qc, stab[7], ancilla, z_measurement) + + if not z_measurement: + qc.h(ancilla) + qc.measure(ancilla, measurement_bit) + + +def qiskit_to_stim_circuit(qc: QuantumCircuit) -> Circuit: + """Convert a Qiskit circuit to a Stim circuit.""" + single_qubit_gate_map = { + "h": "H", + "x": "X", + "y": "Y", + "z": "Z", + "s": "S", + "sdg": "S_DAG", + "sx": "SQRT_X", + "measure": "MR", + } + stim_circuit = Circuit() + for gate in qc: + op = gate.operation.name + qubit = qc.find_bit(gate.qubits[0])[0] + if op in single_qubit_gate_map: + stim_circuit.append_operation(single_qubit_gate_map[op], [qubit]) + elif op == "cx": + target = qc.find_bit(gate.qubits[1])[0] + stim_circuit.append_operation("CX", [qubit, target]) + else: + msg = f"Unsupported gate: {op}" + raise ValueError(msg) + return stim_circuit diff --git a/test/python/circuit_synthesis/__init__.py b/test/python/circuit_synthesis/__init__.py new file mode 100644 index 00000000..dc422b45 --- /dev/null +++ b/test/python/circuit_synthesis/__init__.py @@ -0,0 +1 @@ +"""Needed for imports in tests.""" diff --git a/test/python/ft_stateprep/test_deterministic.py b/test/python/circuit_synthesis/test_deterministic.py similarity index 96% rename from test/python/ft_stateprep/test_deterministic.py rename to test/python/circuit_synthesis/test_deterministic.py index 7d487a30..968998c4 100644 --- a/test/python/ft_stateprep/test_deterministic.py +++ b/test/python/circuit_synthesis/test_deterministic.py @@ -10,12 +10,16 @@ from qsample import noise from mqt.qecc import CSSCode -from mqt.qecc.ft_stateprep import DeterministicVerificationHelper, NoisyDFTStatePrepSimulator, heuristic_prep_circuit +from mqt.qecc.circuit_synthesis import ( + DeterministicVerificationHelper, + NoisyDFTStatePrepSimulator, + heuristic_prep_circuit, +) if TYPE_CHECKING: import numpy.typing as npt - from mqt.qecc.ft_stateprep import DeterministicVerification, StatePrepCircuit + from mqt.qecc.circuit_synthesis import DeterministicVerification, StatePrepCircuit # Simulation parameters err_params = {"q": [1e-4, 5e-4, 1e-3, 5e-3, 1e-2, 5e-2, 1e-1, 5e-1]} diff --git a/test/python/circuit_synthesis/test_encoder_synthesis.py b/test/python/circuit_synthesis/test_encoder_synthesis.py new file mode 100644 index 00000000..2bba61f4 --- /dev/null +++ b/test/python/circuit_synthesis/test_encoder_synthesis.py @@ -0,0 +1,132 @@ +"""Test synthesis of encoding circuit synthesis.""" + +from __future__ import annotations + +import os +import sys +from typing import TYPE_CHECKING + +import numpy as np +import pytest + +from mqt.qecc import CSSCode +from mqt.qecc.circuit_synthesis import ( + depth_optimal_encoding_circuit, + gate_optimal_encoding_circuit, + heuristic_encoding_circuit, +) + +from .utils import eq_span, get_stabs_css_with_indices, in_span + +if TYPE_CHECKING: # pragma: no cover + from qiskit import QuantumCircuit + + +@pytest.fixture +def steane_code() -> CSSCode: + """Return the Steane code.""" + return CSSCode.from_code_name("Steane") + + +@pytest.fixture +def surface_3() -> CSSCode: + """Return the surface code.""" + return CSSCode.from_code_name("surface", 3) + + +@pytest.fixture +def tetrahedral() -> CSSCode: + """Return the tetrahedral code.""" + return CSSCode.from_code_name("tetrahedral") + + +@pytest.fixture +def hamming() -> CSSCode: + """Return the Hamming code.""" + return CSSCode.from_code_name("Hamming") + + +@pytest.fixture +def shor() -> CSSCode: + """Return the Shor code.""" + return CSSCode.from_code_name("Shor") + + +@pytest.fixture +def css_4_2_2_code() -> CSSCode: + """Return the 4,2,2 code.""" + return CSSCode(2, np.array([[1] * 4]), np.array([[1] * 4])) + + +@pytest.fixture +def css_6_2_2_code() -> CSSCode: + """Return the 4,2,2 code.""" + return CSSCode( + 2, np.array([[1, 1, 1, 1, 0, 0], [1, 1, 0, 0, 1, 1]]), np.array([[1, 1, 1, 1, 0, 0], [1, 1, 0, 0, 1, 1]]) + ) + + +def _assert_correct_encoding_circuit(encoder: QuantumCircuit, encoding_qubits: list[int], code: CSSCode) -> None: + assert encoder.num_qubits == code.n + + x_stabs, z_stabs_tmp, x_qubits, z_qubits = get_stabs_css_with_indices(encoder) + + # Since no gate is applied to the encoding qubits at the beginning of the circuit, the propagation of Z-logicals through the circuit can be read off from the Z-stabilizers. + z_logical_indices = [z_qubits[i] for i in encoding_qubits] + z_logicals = z_stabs_tmp[z_logical_indices] + + # To get propagation we need to apply a Hadamard to the encoding qubits and propagate again. + encoder_h = encoder.inverse() + encoder_h.h(encoding_qubits) + encoder_h = encoder_h.inverse() + x_stabs_tmp, z_stabs, x_qubits, _ = get_stabs_css_with_indices(encoder_h) + print(x_stabs_tmp, x_qubits) + x_logicals = x_stabs_tmp[[x_qubits[i] for i in encoding_qubits]] + + # assert correct propagation of stabilizers + assert eq_span(code.Hx, x_stabs) + assert eq_span(code.Hz, z_stabs) + + # assert correct propagation of logicals + for logical in z_logicals: + assert in_span(np.vstack((code.Hz, code.Lz)), logical) + + for logical in x_logicals: + assert in_span(np.vstack((code.Hx, code.Lx)), logical) + + +@pytest.mark.parametrize( + "code", ["steane_code", "css_4_2_2_code", "css_6_2_2_code", "tetrahedral", "surface_3", "hamming", "shor"] +) +def test_heuristic_encoding_consistent(code: CSSCode, request) -> None: # type: ignore[no-untyped-def] + """Check that heuristic_encoding_circuit returns a valid circuit with the correct stabilizers.""" + code = request.getfixturevalue(code) + + encoder, encoding_qubits = heuristic_encoding_circuit(code) + assert encoder.num_qubits == code.n + + _assert_correct_encoding_circuit(encoder, encoding_qubits, code) + + +@pytest.mark.skipif(os.environ.get("CI", False) and sys.platform == "win32", reason="Too slow for CI on Windows") +@pytest.mark.parametrize("code", ["steane_code", "css_4_2_2_code", "css_6_2_2_code"]) +def test_gate_optimal_encoding_consistent(code: CSSCode, request) -> None: # type: ignore[no-untyped-def] + """Check that `gate_optimal_encoding_circuit` returns a valid circuit with the correct stabilizers.""" + code = request.getfixturevalue(code) + + encoder, encoding_qubits = gate_optimal_encoding_circuit(code, max_timeout=5, min_gates=3, max_gates=10) + assert encoder.num_qubits == code.n + + _assert_correct_encoding_circuit(encoder, encoding_qubits, code) + + +@pytest.mark.skipif(os.environ.get("CI", False) and sys.platform == "win32", reason="Too slow for CI on Windows") +@pytest.mark.parametrize("code", ["steane_code", "css_4_2_2_code", "css_6_2_2_code"]) +def test_depth_optimal_encoding_consistent(code: CSSCode, request) -> None: # type: ignore[no-untyped-def] + """Check that `gate_optimal_encoding_circuit` returns a valid circuit with the correct stabilizers.""" + code = request.getfixturevalue(code) + + encoder, encoding_qubits = depth_optimal_encoding_circuit(code, max_timeout=5) + assert encoder.num_qubits == code.n + + _assert_correct_encoding_circuit(encoder, encoding_qubits, code) diff --git a/test/python/ft_stateprep/test_simulation.py b/test/python/circuit_synthesis/test_simulation.py similarity index 99% rename from test/python/ft_stateprep/test_simulation.py rename to test/python/circuit_synthesis/test_simulation.py index 06af59ea..2946815f 100644 --- a/test/python/ft_stateprep/test_simulation.py +++ b/test/python/circuit_synthesis/test_simulation.py @@ -10,7 +10,7 @@ import pytest from mqt.qecc import CSSCode -from mqt.qecc.ft_stateprep import ( +from mqt.qecc.circuit_synthesis import ( LutDecoder, NoisyNDFTStatePrepSimulator, gate_optimal_verification_circuit, diff --git a/test/python/ft_stateprep/test_stateprep.py b/test/python/circuit_synthesis/test_stateprep.py similarity index 90% rename from test/python/ft_stateprep/test_stateprep.py rename to test/python/circuit_synthesis/test_stateprep.py index 33367dea..a285ee5b 100644 --- a/test/python/ft_stateprep/test_stateprep.py +++ b/test/python/circuit_synthesis/test_stateprep.py @@ -8,12 +8,9 @@ import numpy as np import pytest -from ldpc import mod2 -from qiskit.quantum_info import Clifford from mqt.qecc import CSSCode -from mqt.qecc.codes import SquareOctagonColorCode -from mqt.qecc.ft_stateprep import ( +from mqt.qecc.circuit_synthesis import ( depth_optimal_prep_circuit, gate_optimal_prep_circuit, gate_optimal_verification_circuit, @@ -22,12 +19,12 @@ heuristic_verification_circuit, heuristic_verification_stabilizers, ) +from mqt.qecc.codes import SquareOctagonColorCode -if TYPE_CHECKING: # pragma: no cover - import numpy.typing as npt - from qiskit import QuantumCircuit +from .utils import eq_span, get_stabs_css, in_span - from mqt.qecc.ft_stateprep import StatePrepCircuit +if TYPE_CHECKING: # pragma: no cover + from mqt.qecc.circuit_synthesis import StatePrepCircuit @pytest.fixture @@ -43,8 +40,8 @@ def css_4_2_2_code() -> CSSCode: @pytest.fixture -def css_6_4_2_code() -> CSSCode: - """Return the 6,4,2 code.""" +def css_6_2_2_code() -> CSSCode: + """Return the 4,2,2 code.""" return CSSCode(2, np.array([[1] * 6]), np.array([[1] * 6])) @@ -90,28 +87,18 @@ def color_code_d5_sp(cc_4_8_8_code: CSSCode) -> StatePrepCircuit: return sp_circ -def eq_span(a: npt.NDArray[np.int_], b: npt.NDArray[np.int_]) -> bool: - """Check if two matrices have the same row space.""" - return (a.shape == b.shape) and (int(mod2.rank(np.vstack((a, b)))) == int(mod2.rank(a)) == int(mod2.rank(b))) - - -def in_span(m: npt.NDArray[np.int_], v: npt.NDArray[np.int_]) -> bool: - """Check if a vector is in the row space of a matrix.""" - return bool(mod2.rank(np.vstack((m, v))) == mod2.rank(m)) - - -def get_stabs(qc: QuantumCircuit) -> tuple[npt.NDArray[np.int_], npt.NDArray[np.int_]]: - """Return the stabilizers of a quantum circuit.""" - cliff = Clifford(qc) - x = cliff.stab_x.astype(int) - x = x[np.where(np.logical_not(np.all(x == 0, axis=1)))[0]] - z = cliff.stab_z.astype(int) - z = z[np.where(np.logical_not(np.all(z == 0, axis=1)))[0]] - return x, z +def test_heuristic_overcomplete_stabilizers() -> None: + """Check that synthesis also works for overcomplete stabilizers.""" + code = CSSCode(2, np.array([[1, 1, 1, 1], [1, 1, 1, 1]]), np.array([[1, 1, 1, 1], [1, 1, 1, 1]])) + sp_circ = heuristic_prep_circuit(code) + circ = sp_circ.circ + x, z = get_stabs_css(circ) + assert eq_span(code.Hx, x) + assert eq_span(np.vstack((code.Hz, code.Lz)), z) @pytest.mark.parametrize( - "code", ["steane_code", "css_4_2_2_code", "css_6_4_2_code", "tetrahedral_code", "surface_code"] + "code", ["steane_code", "css_4_2_2_code", "css_6_2_2_code", "tetrahedral_code", "surface_code"] ) def test_heuristic_prep_consistent(code: CSSCode, request) -> None: # type: ignore[no-untyped-def] """Check that heuristic_prep_circuit returns a valid circuit with the correct stabilizers.""" @@ -124,13 +111,13 @@ def test_heuristic_prep_consistent(code: CSSCode, request) -> None: # type: ign assert circ.num_qubits == code.n assert circ.num_nonlocal_gates() <= max_cnots - x, z = get_stabs(circ) + x, z = get_stabs_css(circ) assert eq_span(code.Hx, x) assert eq_span(np.vstack((code.Hz, code.Lz)), z) @pytest.mark.skipif(os.environ.get("CI", False) and sys.platform == "win32", reason="Too slow for CI on Windows") -@pytest.mark.parametrize("code", ["steane_code", "css_4_2_2_code", "css_6_4_2_code"]) +@pytest.mark.parametrize("code", ["steane_code", "css_4_2_2_code", "css_6_2_2_code"]) def test_gate_optimal_prep_consistent(code: CSSCode, request) -> None: # type: ignore[no-untyped-def] """Check that gate_optimal_prep_circuit returns a valid circuit with the correct stabilizers.""" code = request.getfixturevalue(code) @@ -144,13 +131,13 @@ def test_gate_optimal_prep_consistent(code: CSSCode, request) -> None: # type: assert circ.num_qubits == code.n assert circ.num_nonlocal_gates() <= max_cnots - x, z = get_stabs(circ) + x, z = get_stabs_css(circ) assert eq_span(code.Hx, x) assert eq_span(np.vstack((code.Hz, code.Lz)), z) @pytest.mark.skipif(os.environ.get("CI", False) and sys.platform == "win32", reason="Too slow for CI on Windows") -@pytest.mark.parametrize("code", ["steane_code", "css_4_2_2_code", "css_6_4_2_code"]) +@pytest.mark.parametrize("code", ["steane_code", "css_4_2_2_code", "css_6_2_2_code"]) def test_depth_optimal_prep_consistent(code: CSSCode, request) -> None: # type: ignore[no-untyped-def] """Check that depth_optimal_prep_circuit returns a valid circuit with the correct stabilizers.""" code = request.getfixturevalue(code) @@ -163,13 +150,13 @@ def test_depth_optimal_prep_consistent(code: CSSCode, request) -> None: # type: assert circ.num_qubits == code.n assert circ.num_nonlocal_gates() <= max_cnots - x, z = get_stabs(circ) + x, z = get_stabs_css(circ) assert eq_span(code.Hx, x) assert eq_span(np.vstack((code.Hz, code.Lz)), z) @pytest.mark.skipif(os.environ.get("CI", False) and sys.platform == "win32", reason="Too slow for CI on Windows") -@pytest.mark.parametrize("code", ["steane_code", "css_4_2_2_code", "css_6_4_2_code"]) +@pytest.mark.parametrize("code", ["steane_code", "css_4_2_2_code", "css_6_2_2_code"]) def test_plus_state_gate_optimal(code: CSSCode, request) -> None: # type: ignore[no-untyped-def] """Test synthesis of the plus state.""" code = request.getfixturevalue(code) @@ -184,7 +171,7 @@ def test_plus_state_gate_optimal(code: CSSCode, request) -> None: # type: ignor assert circ_plus.num_qubits == code.n assert circ_plus.num_nonlocal_gates() <= max_cnots - x, z = get_stabs(circ_plus) + x, z = get_stabs_css(circ_plus) assert eq_span(code.Hz, z) assert eq_span(np.vstack((code.Hx, code.Lx)), x) @@ -193,7 +180,7 @@ def test_plus_state_gate_optimal(code: CSSCode, request) -> None: # type: ignor assert sp_circ_zero is not None circ_zero = sp_circ_zero.circ - x_zero, z_zero = get_stabs(circ_zero) + x_zero, z_zero = get_stabs_css(circ_zero) if code.is_self_dual(): assert np.array_equal(x, z_zero) @@ -204,7 +191,7 @@ def test_plus_state_gate_optimal(code: CSSCode, request) -> None: # type: ignor @pytest.mark.parametrize( - "code", ["steane_code", "css_4_2_2_code", "css_6_4_2_code", "surface_code", "tetrahedral_code"] + "code", ["steane_code", "css_4_2_2_code", "css_6_2_2_code", "surface_code", "tetrahedral_code"] ) def test_plus_state_heuristic(code: CSSCode, request) -> None: # type: ignore[no-untyped-def] """Test synthesis of the plus state.""" @@ -220,13 +207,13 @@ def test_plus_state_heuristic(code: CSSCode, request) -> None: # type: ignore[n assert circ_plus.num_qubits == code.n assert circ_plus.num_nonlocal_gates() <= max_cnots - x, z = get_stabs(circ_plus) + x, z = get_stabs_css(circ_plus) assert eq_span(code.Hz, z) assert eq_span(np.vstack((code.Hx, code.Lx)), x) sp_circ_zero = heuristic_prep_circuit(code, zero_state=True) circ_zero = sp_circ_zero.circ - x_zero, z_zero = get_stabs(circ_zero) + x_zero, z_zero = get_stabs_css(circ_zero) if code.is_self_dual(): assert np.array_equal(x, z_zero) diff --git a/test/python/circuit_synthesis/test_utils.py b/test/python/circuit_synthesis/test_utils.py new file mode 100644 index 00000000..3f10e4ca --- /dev/null +++ b/test/python/circuit_synthesis/test_utils.py @@ -0,0 +1,276 @@ +"""Test utility functions for the circuit synthesis module.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, NamedTuple + +import numpy as np +import pytest +from ldpc import mod2 +from qiskit import AncillaRegister, ClassicalRegister, QuantumCircuit, QuantumRegister +from stim import Flow, PauliString + +from mqt.qecc.circuit_synthesis.state_prep import final_matrix_constraint +from mqt.qecc.circuit_synthesis.synthesis_utils import ( + gaussian_elimination_min_column_ops, + gaussian_elimination_min_parallel_eliminations, + measure_flagged, + measure_one_flagged, + measure_stab_unflagged, + measure_two_flagged, + qiskit_to_stim_circuit, +) + +if TYPE_CHECKING: + import numpy.typing as npt + from qiskit import AncillaQubit, ClBit, Qubit + + +class MatrixTest(NamedTuple): + """Test matrix and expected results.""" + + matrix: npt.NDArray[np.int8] + min_col_ops: int + max_parallel_steps: int + + +def check_correct_elimination( + matrix: npt.NDArray[np.int8], final_matrix: npt.NDArray[np.int8], col_ops: list[tuple[int, int]] +) -> bool: + """Check if the matrix is correctly eliminated.""" + matrix = matrix.copy() + for op in col_ops: + matrix[:, op[1]] = (matrix[:, op[0]] + matrix[:, op[1]]) % 2 + return np.array_equal(matrix, final_matrix) + + +def get_n_parallel_layers(ops: list[tuple[int, int]]) -> int: + """Get the number of parallel layers in the elimination.""" + used_cols: set[int] = set() + layer = 0 + for op in ops: + if op[0] in used_cols or op[1] in used_cols: + layer += 1 + used_cols = set() + used_cols.add(op[0]) + used_cols.add(op[1]) + return layer + + +@pytest.fixture +def identity_matrix() -> MatrixTest: + """Return a 4x4 identity matrix.""" + return MatrixTest(np.eye(4, dtype=np.int8), 0, 0) + + +@pytest.fixture +def full_matrix() -> MatrixTest: + """Return a 4x4 matrix with all ones.""" + return MatrixTest(np.array([[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], dtype=np.int8), 3, 2) + + +class MeasurementTest(NamedTuple): + """Class containing all information for a measurement test.""" + + qc: QuantumCircuit + stab: list[Qubit] + ancilla: AncillaQubit + measurement_bit: ClBit + t: int + z_measurement: bool + + +def _make_measurement_test(n: int, stab: list[int], t: int, z_measurements: bool) -> MeasurementTest: + q = QuantumRegister(n, "q") + c = ClassicalRegister(1, "c") + anc = AncillaRegister(1, "anc") + qc = QuantumCircuit(q, c, anc) + stab_qubits = [q[i] for i in stab] + ancilla = anc[0] + measurement_bit = c[0] + return MeasurementTest(qc, stab_qubits, ancilla, measurement_bit, t, z_measurements) + + +@pytest.fixture +def weight_4_z() -> MeasurementTest: + """Return a measurement test for a weight 4 stabilizer.""" + return _make_measurement_test(4, [0, 1, 2, 3], 1, True) + + +@pytest.fixture +def weight_4_z_6q() -> MeasurementTest: + """Return a measurement test for a weight 4 stabilizer.""" + return _make_measurement_test(6, [0, 1, 2, 3], 1, True) + + +@pytest.fixture +def weight_6_z_measurement() -> MeasurementTest: + """Return a measurement test for a weight 6 stabilizer.""" + return _make_measurement_test(6, [0, 1, 2, 3, 4, 5], 1, True) + + +@pytest.fixture +def weight_4_x() -> MeasurementTest: + """Return a measurement test for a weight 4 stabilizer.""" + return _make_measurement_test(4, [3, 2, 1, 0], 1, False) + + +@pytest.fixture +def weight_8_x_measurement() -> MeasurementTest: + """Return a measurement test for a weight 8 stabilizer.""" + return _make_measurement_test(8, [7, 6, 5, 4, 3, 2, 1, 0], 1, False) + + +@pytest.fixture +def weight_9_z_measurement() -> MeasurementTest: + """Return a measurement test for a weight 8 stabilizer.""" + return _make_measurement_test(100, [7, 6, 5, 4, 3, 2, 1, 0], 2, True) + + +@pytest.fixture +def weight_16_x_measurement() -> MeasurementTest: + """Return a measurement test for a weight 16 stabilizer.""" + return _make_measurement_test(16, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], 2, False) + + +@pytest.mark.parametrize("test_vals", ["identity_matrix", "full_matrix"]) +def test_min_column_ops(test_vals: MatrixTest, request) -> None: # type: ignore[no-untyped-def] + """Check correct number of column operations are returned.""" + fixture = request.getfixturevalue(test_vals) + matrix = fixture.matrix + min_col_ops = fixture.min_col_ops + rank = mod2.rank(matrix) + res = gaussian_elimination_min_column_ops( + matrix, lambda checks: final_matrix_constraint(checks, rank), max_eliminations=fixture.min_col_ops + ) + assert res is not None + reduced, ops = res + assert len(ops) == min_col_ops + assert check_correct_elimination(matrix, reduced, ops) + + +@pytest.mark.parametrize("test_vals", ["identity_matrix", "full_matrix"]) +def test_min_parallel_eliminations(test_vals: MatrixTest, request) -> None: # type: ignore[no-untyped-def] + """Check correct number of parallel eliminations are returned.""" + fixture = request.getfixturevalue(test_vals) + matrix = fixture.matrix + rank = mod2.rank(matrix) + max_parallel_steps = fixture.max_parallel_steps + res = gaussian_elimination_min_parallel_eliminations( + matrix, lambda checks: final_matrix_constraint(checks, rank), max_parallel_steps=fixture.max_parallel_steps + ) + assert res is not None + reduced, ops = res + + assert check_correct_elimination(matrix, reduced, ops) + + n_parallel_layers = get_n_parallel_layers(ops) + assert n_parallel_layers <= max_parallel_steps + + +def correct_stabilizer_propagation( + qc: QuantumCircuit, stab: list[Qubit], ancilla: AncillaQubit, z_measurement: bool +) -> bool: + """Check that the stabilizer is propagated correctly.""" + circ = qiskit_to_stim_circuit(qc) + pauli = "Z" if z_measurement else "X" + anc_idx = qc.find_bit(ancilla).index + initial_pauli = PauliString("_" * (anc_idx) + "Z" + "_" * (len(qc.qubits) - anc_idx - 1)) + final_pauli = PauliString( + "".join([pauli if q in stab else "_" for q in qc.qubits]) + "_" * (len(qc.qubits) - anc_idx - 1) + ) + f = Flow(input=initial_pauli, output=final_pauli, measurements=[qc.num_ancillas - 1]) + return bool(circ.has_flow(f)) + + +@pytest.mark.parametrize( + "test", ["weight_4_z", "weight_4_z_6q", "weight_4_x", "weight_6_z_measurement", "weight_8_x_measurement"] +) +def test_one_flag_measurements(test: MeasurementTest, request): # type: ignore[no-untyped-def] + """Test measurement circuits.""" + fixture = request.getfixturevalue(test) + qc = fixture.qc + stab = fixture.stab + ancilla = fixture.ancilla + measurement_bit = fixture.measurement_bit + z_measurement = fixture.z_measurement + + measure_one_flagged(qc, stab, ancilla, measurement_bit, z_measurement) + assert qc.depth() == len(stab) + 3 + 2 * int(not z_measurement) # 6 CNOTs + Measurement + 2 possible hadamards + assert qc.count_ops().get("cx", 0) == len(stab) + 2 # CNOTs from measurement + 2 flagging CNOTs + assert correct_stabilizer_propagation(qc, stab, ancilla, z_measurement) + + +@pytest.mark.parametrize( + "test", + [ + "weight_4_z", + "weight_4_z_6q", + "weight_4_x", + "weight_6_z_measurement", + "weight_8_x_measurement", + "weight_9_z_measurement", + "weight_16_x_measurement", + ], +) +def test_two_flag(test: MeasurementTest, request): # type: ignore[no-untyped-def] + """Test two flag measurement circuits.""" + fixture = request.getfixturevalue(test) + qc = fixture.qc + stab = fixture.stab + ancilla = fixture.ancilla + measurement_bit = fixture.measurement_bit + z_measurement = fixture.z_measurement + + measure_two_flagged(qc, stab, ancilla, measurement_bit, z_measurement) + print(qc.draw()) + assert correct_stabilizer_propagation(qc, stab, ancilla, z_measurement) + + +@pytest.mark.parametrize( + "test", + [ + "weight_4_z", + "weight_4_z_6q", + "weight_4_x", + "weight_6_z_measurement", + "weight_8_x_measurement", + "weight_9_z_measurement", + ], +) +def test_flag_measurements(test: MeasurementTest, request) -> None: # type: ignore[no-untyped-def] + """Test flag measurement circuits.""" + fixture = request.getfixturevalue(test) + qc = fixture.qc + stab = fixture.stab + ancilla = fixture.ancilla + t = fixture.t + measurement_bit = fixture.measurement_bit + z_measurement = fixture.z_measurement + + measure_flagged(qc, stab, ancilla, measurement_bit, t, z_measurement) + assert correct_stabilizer_propagation(qc, stab, ancilla, z_measurement) + + +@pytest.mark.parametrize( + "test", + [ + "weight_4_z", + "weight_4_z_6q", + "weight_4_x", + "weight_6_z_measurement", + "weight_8_x_measurement", + "weight_9_z_measurement", + ], +) +def test_unflagged_measurements(test: MeasurementTest, request) -> None: # type: ignore[no-untyped-def] + """Test flag measurement circuits.""" + fixture = request.getfixturevalue(test) + qc = fixture.qc + stab = fixture.stab + ancilla = fixture.ancilla + measurement_bit = fixture.measurement_bit + z_measurement = fixture.z_measurement + + measure_stab_unflagged(qc, stab, ancilla, measurement_bit, z_measurement) + assert correct_stabilizer_propagation(qc, stab, ancilla, z_measurement) diff --git a/test/python/circuit_synthesis/utils.py b/test/python/circuit_synthesis/utils.py new file mode 100644 index 00000000..b44d4e4c --- /dev/null +++ b/test/python/circuit_synthesis/utils.py @@ -0,0 +1,76 @@ +"""Utilities for the circuit synthesis unit tests.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import numpy as np +from ldpc import mod2 +from qiskit.quantum_info import Clifford + +if TYPE_CHECKING: # pragma: no cover + import numpy.typing as npt + from qiskit import QuantumCircuit + + +def eq_span(a: npt.NDArray[np.int_], b: npt.NDArray[np.int_]) -> bool: + """Check if two matrices have the same row space.""" + return (a.shape[1] == b.shape[1]) and (int(mod2.rank(np.vstack((a, b)))) == int(mod2.rank(a)) == int(mod2.rank(b))) + + +def in_span(m: npt.NDArray[np.int_], v: npt.NDArray[np.int_]) -> bool: + """Check if a vector is in the row space of a matrix over GF(2).""" + return bool(mod2.rank(np.vstack((m, v))) == mod2.rank(m)) + + +def get_stabs_css_with_indices( + qc: QuantumCircuit, +) -> tuple[npt.NDArray[np.int_], npt.NDArray[np.int_], dict[int, int], dict[int, int]]: + """Return the stabilizers of a quantum circuit. + + Assumes that stabilizers are CSS. + + Args: + qc: The quantum circuit. + returns: + x: The X stabilizers. + z: The Z stabilizers. + x_indices: The indices of the X stabilizers. + z_indices: The indices of the Z stabilizers. + """ + cliff = Clifford(qc) + x = cliff.stab_x.astype(int) + x_indices = np.where(np.logical_not(np.all(x == 0, axis=1)))[0] + qubit_to_x_pos = {x_indices[i]: i for i in range(len(x_indices))} + x = x[x_indices] + z = cliff.stab_z.astype(int) + z_indices = np.where(np.logical_not(np.all(z == 0, axis=1)))[0] + qubit_to_z_pos = {z_indices[i]: i for i in range(len(z_indices))} + z = z[z_indices] + + return x, z, qubit_to_x_pos, qubit_to_z_pos + + +def get_stabs_css(qc: QuantumCircuit) -> tuple[npt.NDArray[np.int_], npt.NDArray[np.int_]]: + """Return the stabilizers of a quantum circuit. + + Assumes that stabilizers are CSS. + + Args: + qc: The quantum circuit. + + returns: + x: The X stabilizers. + z: The Z stabilizers. + + """ + cliff = Clifford(qc) + x = cliff.stab_x.astype(int) + x_indices = np.where(np.logical_not(np.all(x == 0, axis=1)))[0] + + x = x[x_indices] + z = cliff.stab_z.astype(int) + z_indices = np.where(np.logical_not(np.all(z == 0, axis=1)))[0] + + z = z[z_indices] + return x, z