Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
4200ef1
Added main.py
emilkanic0909 May 9, 2026
5a700a0
added code
SalehAlsherif May 9, 2026
38aa1f8
added entrying points
emilkanic0909 May 9, 2026
df2affd
changed the name of the argument to encoding to match the project des…
SalehAlsherif May 13, 2026
e3295e6
Shorcode Transpiler excluding S gates
SalehAlsherif May 16, 2026
6e08c7e
✨ Adding Steane for Clifford set
emilkanic0909 May 22, 2026
ac7b9ea
♻️ Refactoring
emilkanic0909 May 23, 2026
b0e5c8c
Shor_Code_Transpiler completed with tests anf T gate to be tested
SalehAlsherif May 23, 2026
3e211cb
change to statevector
emilkanic0909 May 23, 2026
1fa57c3
used reduced density matrix
SalehAlsherif May 23, 2026
5cf108d
✨ Implementing T Gate as in exercise decription
emilkanic0909 May 27, 2026
e9cc159
updated encoding parameter to make main.py run
May 29, 2026
fba7a1f
added various testing utilities
May 29, 2026
0dec02a
Added test outputs to gitignore
Felix-Gundlach May 29, 2026
b6978c4
Merged Shor Transpiler into Verification
Felix-Gundlach May 29, 2026
8e189f1
added barrier to decoding
Felix-Gundlach May 29, 2026
e041878
first attempts at unification
Felix-Gundlach May 29, 2026
0410fed
✨ Add syndromes control flag
emilkanic0909 May 30, 2026
574db9a
More Ways to test :)
May 30, 2026
d80afea
Merge remote-tracking branch 'origin/feature/ErrorCorrection_SteaneCo…
May 30, 2026
569bc68
More changes
May 30, 2026
ba98eaf
improved circuit simulation and data processing
May 30, 2026
bd58ad5
✨ Adding Decode All
emilkanic0909 May 30, 2026
f3fbac1
small modifications to structure
May 30, 2026
73317f7
merged changes
May 30, 2026
997d7d1
streamlined testing utilities
May 30, 2026
1e3b44c
more changes
May 30, 2026
4a26c64
Improved testing methodologies
May 30, 2026
8bf47d6
+ Enabled Algorithmic Equality testing
Felix-Gundlach May 31, 2026
3832fe8
Refactored to OpenClose Principle
SalehAlsherif Jun 6, 2026
49bd55a
+ logging
Jun 6, 2026
a65972d
+ cx & cz gate testing
Jun 6, 2026
6f765f0
🚧 Working with tests
emilkanic0909 Jun 6, 2026
739084b
Merge branch 'feature/ErrorCorrection_Verification' of https://github…
emilkanic0909 Jun 6, 2026
69e98a7
Merge branch 'feature/ErrorCorrection_ShorCode' into feature/ErrorCor…
emilkanic0909 Jun 6, 2026
a470a35
Merge branch 'feature/ErrorCorrection_Verification' of github.com:emi…
Jun 6, 2026
1ace3c5
Merge branch 'feature/ErrorCorrection_Verification' into feature/Erro…
Jun 6, 2026
02d1ac2
Addind Steane transpiler
emilkanic0909 Jun 6, 2026
86d2c36
Merge branch 'feature/ErrorCorrection_SubMain' of https://github.com/…
emilkanic0909 Jun 6, 2026
b0c175e
removed wrong tests and unneccessay outputs
Jun 6, 2026
9c71e3a
correcting tests
SalehAlsherif Jun 6, 2026
735cebb
added measurement testcase
Jun 6, 2026
45a1721
Merge branch 'feature/ErrorCorrection_SubMain' of github.com:emilkani…
Jun 6, 2026
135d7b1
Refactoring
SalehAlsherif Jun 6, 2026
db68e10
added decode before measurements
SalehAlsherif Jun 6, 2026
b57e5cc
Merge branch 'feature/ErrorCorrection_SubMain' of github.com:emilkani…
Jun 6, 2026
bcb06ad
✅ Add Steane components
emilkanic0909 Jun 6, 2026
2265c5a
Movedcircuit running
Jun 11, 2026
624ed2a
Merge branch 'feature/ErrorCorrection_SubMain' of github.com:emilkani…
Jun 11, 2026
d3517db
+ Added funcionality to create gate_counts.json
Jun 11, 2026
6d79032
+ Added test for circuit structure
Jun 11, 2026
9700a88
✨ Adding QFT gate support
emilkanic0909 Jun 12, 2026
6c4b74b
Fixed logical Measurement on shor code transpiler
SalehAlsherif Jun 12, 2026
4866c88
new gate counts
Jun 13, 2026
78a8d6b
more qft :)
Jun 13, 2026
ba31cba
fixed measurement removal
Jun 13, 2026
5bfd6c2
more fixes
Jun 13, 2026
2b19794
Adding QFT gate to shor transpiler
SalehAlsherif Jun 13, 2026
9432119
Fix Measurements
emilkanic0909 Jun 13, 2026
2ef22f2
fixed circuit structure tests to work with dynamic numbers of classic…
Jun 13, 2026
2fa6380
added support for qft structural tests
Jun 13, 2026
31216cc
switched to custom measurement logic
Jun 13, 2026
5f29699
✨ Fixing Tests
emilkanic0909 Jun 13, 2026
21c9fd7
✨ Removing QFT Test
emilkanic0909 Jun 13, 2026
956006e
various improvements to code quality
Jun 13, 2026
d98c80a
Merge branch 'feature/ErrorCorrection_SubMain' of github.com:emilkani…
Jun 13, 2026
7853e8d
more fixes to resolve the bungled up merge conflict
Jun 13, 2026
b3e2c8b
automatic nox lint changes
Jun 13, 2026
22f71bf
added dependencies for testing
Jun 13, 2026
5553b37
removed finished TODOs
Jun 13, 2026
f5ba739
removed unused file
Jun 13, 2026
221eb86
more linting changes
Jun 13, 2026
bb53875
greatly improved readability of documentation
Jun 13, 2026
137fb83
Merge branch 'munich-quantum-toolkit:main' into main
Felix-Gundlach Jun 13, 2026
ceb55da
Merge remote-tracking branch 'origin/main' into feature/ErrorCorrecti…
Jun 13, 2026
08463e3
Added module docstring
Jun 13, 2026
33b24ce
updated uv.lock to reflect added dependencies
Jun 13, 2026
80f347f
fixed wrong import location
Jun 16, 2026
1d0e8de
Added explicit type checking to syndrome extraction
Jun 16, 2026
9576b21
Moved testing dependencies to appropriate pytest groups
Jun 16, 2026
5823f63
Varios little improvements to code quality
Jun 16, 2026
75df4d6
Corrected module docstring
Jun 16, 2026
bc6c18b
Corrected module docstring
Jun 16, 2026
fe66b60
Enabled Solovay-Kitaev synthesis on steanes qft decomposition
Jun 16, 2026
b1fc4c1
added debug message regarding qiskit version
Jun 16, 2026
af74ee5
Switched to 2-pass transpilation for Steane's
Jun 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,6 @@ pyrightconfig.json

# setuptools_scm
src/**/_version.py
.idea/
# Test Output
tests/circuit_drawings/*
7 changes: 7 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ dependencies = [
"numpy>=2.3.2; python_version >= '3.14'",
"scikit-learn>=1.5.2",
"scikit-learn>=1.7.2; python_version >= '3.14'",
"mqt-qcec>=3.6.1",
"qiskit-aer>=0.17.2",
Comment thread
Felix-Gundlach marked this conversation as resolved.
]

classifiers = [
Expand Down Expand Up @@ -81,6 +83,10 @@ dev = [
"prek>=0.2.27",
"ty==0.0.40",
]
pytest = [
"mqt-qcec>=3.6.1",
"qiskit-aer>=0.17.2",
]

[project.scripts]
"create_mqt_bench_zip" = "mqt.bench.utils:create_zip_file"
Expand Down Expand Up @@ -250,6 +256,7 @@ aer = "aer"
fom = "fom"
bench = "bench"
benchs = "benchs"
ket = "ket"


[tool.repo-review.ignore]
Expand Down
22 changes: 22 additions & 0 deletions src/mqt/bench/benchmark_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
from qiskit.transpiler import Layout, Target
from typing_extensions import assert_never

from .error_correction.shor_transpiler import ShorTranspiler
from .error_correction.steane_transpiler import SteaneTranspiler

if sys.version_info >= (3, 11):
from typing import Unpack
else:
Expand Down Expand Up @@ -198,6 +201,7 @@ def get_benchmark_alg(
def get_benchmark_alg(
benchmark: str | QuantumCircuit,
circuit_size: int | None = None,
encoding: str = "",
*,
generate_mirror_circuit: bool = False,
random_parameters: bool = True,
Expand All @@ -208,6 +212,7 @@ def get_benchmark_alg(
Arguments:
benchmark: QuantumCircuit or name of the benchmark to be generated
circuit_size: Input for the benchmark creation, in most cases this is equal to the qubit number
encoding: Error correction code to be used (currently unused).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Docstrings incorrectly state encoding is "currently unused".

Both get_benchmark_alg and get_benchmark docstrings describe the encoding parameter as "currently unused", but the parameter is actively used to route circuits through ShorTranspiler or SteaneTranspiler.

  • src/mqt/bench/benchmark_generation.py#L215-L215: Update get_benchmark_alg docstring to describe actual behavior.
  • src/mqt/bench/benchmark_generation.py#L556-L556: Update get_benchmark docstring to describe actual behavior.
📍 Affects 1 file
  • src/mqt/bench/benchmark_generation.py#L215-L215 (this comment)
  • src/mqt/bench/benchmark_generation.py#L556-L556
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mqt/bench/benchmark_generation.py` at line 215, Update the docstrings for
get_benchmark_alg (src/mqt/bench/benchmark_generation.py lines 215-215) and
get_benchmark (src/mqt/bench/benchmark_generation.py lines 556-556) to remove
the incorrect "currently unused" note for the encoding parameter and instead
document that encoding selects the error-correction code used to transpile
circuits (e.g., routing to ShorTranspiler when encoding == "shor" and to
SteaneTranspiler when encoding == "steane"), describe accepted encoding values
and their effect on circuit transpilation/output, and keep other parameter
descriptions unchanged; both locations require the same corrected description.

generate_mirror_circuit: If True, generates the mirror version (U @ U.inverse()) of the benchmark.
random_parameters: If True, assigns random parameters to the circuit's parameters if they exist.
kwargs: Additional keyword arguments passed to the circuit creation.
Expand All @@ -216,8 +221,19 @@ def get_benchmark_alg(
Qiskit::QuantumCircuit representing the raw benchmark circuit without any hardware-specific compilation or mapping.
"""
qc = _get_circuit(benchmark, circuit_size, random_parameters, **kwargs)
# Todo: Make it combined with error code
if generate_mirror_circuit:
return _create_mirror_circuit(qc, inplace=True)

if encoding == "shor":
transpiler = ShorTranspiler(qc, add_syndromes=True)
transpiler.transpile()
return transpiler.transpiled_qc
if encoding == "steane":
transpiler = SteaneTranspiler(qc, add_syndromes=True)
transpiler.transpile()
return transpiler.transpiled_qc

return qc
Comment on lines +228 to 237

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Invalid encoding values silently fall through to return the unencoded circuit.

If a user passes an invalid encoding like encoding="shore" (typo), the function silently returns the raw circuit without any warning. Consider validating the parameter or documenting accepted values explicitly.

Proposed validation
+    valid_encodings = {"", "shor", "steane"}
+    if encoding not in valid_encodings:
+        msg = f"Invalid `encoding` '{encoding}'. Must be one of {valid_encodings}."
+        raise ValueError(msg)
+
     if encoding == "shor":
         transpiler = ShorTranspiler(qc, add_syndromes=True)
         transpiler.transpile()
         return transpiler.transpiled_qc
     if encoding == "steane":
         transpiler = SteaneTranspiler(qc, add_syndromes=True)
         transpiler.transpile()
         return transpiler.transpiled_qc

     return qc
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if encoding == "shor":
transpiler = ShorTranspiler(qc, add_syndromes=True)
transpiler.transpile()
return transpiler.transpiled_qc
if encoding == "steane":
transpiler = SteaneTranspiler(qc, add_syndromes=True)
transpiler.transpile()
return transpiler.transpiled_qc
return qc
valid_encodings = {"", "shor", "steane"}
if encoding not in valid_encodings:
msg = f"Invalid `encoding` '{encoding}'. Must be one of {valid_encodings}."
raise ValueError(msg)
if encoding == "shor":
transpiler = ShorTranspiler(qc, add_syndromes=True)
transpiler.transpile()
return transpiler.transpiled_qc
if encoding == "steane":
transpiler = SteaneTranspiler(qc, add_syndromes=True)
transpiler.transpile()
return transpiler.transpiled_qc
return qc
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mqt/bench/benchmark_generation.py` around lines 228 - 237, The code
silently returns the raw circuit when an invalid encoding is passed; update the
logic that checks the encoding variable (the branch using ShorTranspiler and
SteaneTranspiler) to explicitly validate allowed values ("shor", "steane") and
raise a clear exception (e.g., ValueError) or log an error if an unsupported
encoding is provided, rather than falling through to return qc; ensure the error
message references the invalid encoding value and the accepted options and keep
returning transpiler.transpiled_qc for valid cases (use the existing
ShorTranspiler, SteaneTranspiler, transpile(), and transpiled_qc symbols).



Expand Down Expand Up @@ -478,6 +494,7 @@ def get_benchmark(
circuit_size: int,
target: Target | None = None,
opt_level: int = 2,
encoding: str = "",
*,
generate_mirror_circuit: bool = False,
random_parameters: bool = True,
Expand All @@ -492,6 +509,7 @@ def get_benchmark(
circuit_size: None,
target: Target | None = None,
opt_level: int = 2,
encoding: str = "",
*,
generate_mirror_circuit: bool = False,
random_parameters: bool = True,
Expand All @@ -506,6 +524,7 @@ def get_benchmark(
circuit_size: int | None = None,
target: Target | None = None,
opt_level: int = 2,
encoding: str = "",
*,
generate_mirror_circuit: bool = False,
random_parameters: bool = True,
Expand All @@ -519,6 +538,7 @@ def get_benchmark(
circuit_size: int | None = None,
target: Target | None = None,
opt_level: int = 2,
encoding: str = "",
*,
generate_mirror_circuit: bool = False,
random_parameters: bool = True,
Expand All @@ -533,6 +553,7 @@ def get_benchmark(
target: `~qiskit.transpiler.target.Target` for the benchmark generation
(only used for "nativegates" and "mapped" level)
opt_level: Optimization level to be used by the transpiler.
encoding: Error correction code to be used (currently unused).
generate_mirror_circuit: If True, generates the mirror version (U @ U.inverse()) of the benchmark.
random_parameters: If True, assigns random parameters to the circuit's parameters if they exist.
kwargs: Additional keyword arguments passed to the circuit creation.
Expand All @@ -546,6 +567,7 @@ def get_benchmark(
circuit_size=circuit_size,
generate_mirror_circuit=generate_mirror_circuit,
random_parameters=random_parameters,
encoding=encoding,
**kwargs,
)

Expand Down
135 changes: 11 additions & 124 deletions src/mqt/bench/benchmarks/seven_qubit_steane_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,127 +13,14 @@
from qiskit import ClassicalRegister
from qiskit.circuit import AncillaRegister, QuantumCircuit, QuantumRegister

from ._registry import register_benchmark


def _get_seven_qubit_steane_code_encoding_circuit() -> QuantumCircuit:
"""Create the 7-qubit Steane code encoding circuit.

Encodes qubit 0 into the 7-qubit Steane code logical state:
- |0> -> (|0000000> + |1010101> + |0110011> + |1100110> + |0001111> + |1011010> + |0111100> + |1101001>)
- |1> -> (|1111111> + |0101010> + |1001100> + |0011001> + |1110000> + |0100101> + |1000011> + |0010110>).

Returns:
QuantumCircuit: 7-qubit encoding circuit.
"""
out = QuantumCircuit(7)
# H
out.h(4)
out.h(5)
out.h(6)
# CNOT from 0
out.cx(0, 1)
out.cx(0, 2)
# CNOT from 6
out.cx(6, 3)
out.cx(6, 1)
out.cx(6, 0)
# CNOT from 5
out.cx(5, 3)
out.cx(5, 2)
out.cx(5, 0)
# CNOT from 4
out.cx(4, 3)
out.cx(4, 2)
out.cx(4, 1)
return out


def _get_seven_qubit_steane_code_decoding_circuit() -> QuantumCircuit:
"""Create the 7-qubit Steane code decoding circuit.

Reverses the encoding operation to extract the logical qubit back to qubit 0.

Returns:
QuantumCircuit: 7-qubit decoding circuit (qubit 0 is the output qubit).
"""
return _get_seven_qubit_steane_code_encoding_circuit().inverse()

from mqt.bench.components.steane_circuit_components import (
apply_seven_qubit_steane_code_correction,
get_seven_qubit_steane_code_decoding_circuit,
get_seven_qubit_steane_code_encoding_circuit,
get_seven_qubit_steane_code_syndrome_extraction_circuit,
)

def _get_seven_qubit_steane_code_syndrome_extraction_circuit() -> QuantumCircuit:
"""Create the syndrome extraction circuit for the 7-qubit Steane code.

Extracts bit-flip and phase-flip syndromes using 6 ancilla qubits (3 for each type).

Bit-flip syndrome extraction:
Syndrome bits measure the parity of specific qubit subsets corresponding to
the X-stabilizer generators.

Phase-flip syndrome extraction:
Uses Hadamard gates to convert from Z to X basis, and control/target swapped
CNOTs to extract the phase-flip syndrome

Syndrome mapping: The 3-bit syndrome value (1-7) directly identifies which
data qubit experienced an error. Syndrome 0 indicates no error.

Returns:
QuantumCircuit: 13-qubit circuit (qubits 0-6 are data, 7-9 are bit-flip
syndrome ancillas, 10-12 are phase-flip syndrome ancillas).
"""
logical_qubit, bit_flip_syndrome, phase_flip_syndrome = QuantumRegister(7), AncillaRegister(3), AncillaRegister(3)
out = QuantumCircuit(logical_qubit, bit_flip_syndrome, phase_flip_syndrome)
# Bit-flip
for ctrl in (0, 2, 4, 6):
out.cx(logical_qubit[ctrl], bit_flip_syndrome[0])
for ctrl in (1, 2, 5, 6):
out.cx(logical_qubit[ctrl], bit_flip_syndrome[1])
for ctrl in (3, 4, 5, 6):
out.cx(logical_qubit[ctrl], bit_flip_syndrome[2])
# Phase-flip
for i in range(3):
out.h(phase_flip_syndrome[i])
for targ in (0, 2, 4, 6):
out.cx(phase_flip_syndrome[0], logical_qubit[targ])
for targ in (1, 2, 5, 6):
out.cx(phase_flip_syndrome[1], logical_qubit[targ])
for targ in (3, 4, 5, 6):
out.cx(phase_flip_syndrome[2], logical_qubit[targ])
for i in range(3):
out.h(phase_flip_syndrome[i])
return out


def _apply_seven_qubit_steane_code_correction(
qc: QuantumCircuit,
logical_qubit: QuantumRegister,
bit_flip_syndrome: AncillaRegister,
phase_flip_syndrome: AncillaRegister,
bit_flip_syndrome_measurement: ClassicalRegister,
phase_flip_syndrome_measurement: ClassicalRegister,
) -> None:
"""Apply error correction based on syndrome measurements.

Measures the 6 syndrome qubits and conditionally applies X/Z gates to correct
single-qubit errors on any of the 7 data qubits.

Arguments:
qc: The quantum circuit to modify.
logical_qubit: Register containing the 7 data qubits.
bit_flip_syndrome: Register containing the 3 bit-flip syndrome qubits.
phase_flip_syndrome: Register containing the 3 phase-flip syndrome qubits.
bit_flip_syndrome_measurement: Classical register for bit-flip syndrome results.
phase_flip_syndrome_measurement: Classical register for phase-flip syndrome results.
"""
qc.measure(bit_flip_syndrome, bit_flip_syndrome_measurement)
qc.measure(phase_flip_syndrome, phase_flip_syndrome_measurement)
# Bit-flip correction: syndrome value directly indicates which qubit to correct
for i in range(7):
with qc.if_test((bit_flip_syndrome_measurement, i + 1)):
qc.x(logical_qubit[i])
# Phase-flip correction: syndrome value directly indicates which qubit to correct
for i in range(7):
with qc.if_test((phase_flip_syndrome_measurement, i + 1)):
qc.z(logical_qubit[i])
from ._registry import register_benchmark


def _create_single_logical_qubit_circuit(index: int) -> QuantumCircuit:
Expand Down Expand Up @@ -164,20 +51,20 @@ def _create_single_logical_qubit_circuit(index: int) -> QuantumCircuit:
)
# == Encoding ==
qc.compose(
_get_seven_qubit_steane_code_encoding_circuit(),
get_seven_qubit_steane_code_encoding_circuit(),
qubits=logical_qubit[:],
inplace=True,
)
qc.barrier()
# == Syndrome extraction ==
qc.compose(
_get_seven_qubit_steane_code_syndrome_extraction_circuit(),
get_seven_qubit_steane_code_syndrome_extraction_circuit(),
qubits=logical_qubit[:] + bit_flip_syndrome[:] + phase_flip_syndrome[:],
inplace=True,
)
qc.barrier()
# == Error correction ==
_apply_seven_qubit_steane_code_correction(
apply_seven_qubit_steane_code_correction(
qc,
logical_qubit,
bit_flip_syndrome,
Expand All @@ -188,7 +75,7 @@ def _create_single_logical_qubit_circuit(index: int) -> QuantumCircuit:
qc.barrier()
# == Decoding ==
qc.compose(
_get_seven_qubit_steane_code_decoding_circuit(),
get_seven_qubit_steane_code_decoding_circuit(),
qubits=logical_qubit[:],
inplace=True,
)
Expand Down
Loading
Loading