Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
308 commits
Select commit Hold shift + click to select a range
3505a18
Fix first-layer Hadamards in non-CSS encoding synthesis.
pehamTom Feb 11, 2025
7eb63b7
Merge remote-tracking branch 'origin/encoding-circuits' into encoding…
pehamTom Feb 11, 2025
71411bf
Symmetry Breaking and Maximum two-qubit gates.
pehamTom Feb 11, 2025
9435197
Circuits
pehamTom Feb 18, 2025
e58e6ba
Gottesmann circuit with only 13 CNOTs.
pehamTom Feb 18, 2025
86fae22
Comments and barriers.
pehamTom Feb 20, 2025
ea18e7a
cz gate
pehamTom Feb 20, 2025
00d2f98
Try to fix Gottesmann ancilla circuit.
pehamTom Feb 21, 2025
97be176
Updated Gottesmann Circuit
pehamTom Feb 25, 2025
97045ec
Fixed Hamming code circuit and comment syntax.
pehamTom Feb 25, 2025
3d2aa1a
Add stabilizer and logical information to hamming code circuit
pehamTom Feb 25, 2025
61e66dc
Added 5_1_3 encoding circuit
pehamTom Feb 25, 2025
02a2550
Script for synthesizing depth-optimal hamming code circuit.
pehamTom Feb 25, 2025
87e7bba
Changed script parameters.
pehamTom Feb 25, 2025
7ea428a
Added [[16,6,4]] encoding circuit.
pehamTom Feb 25, 2025
34f07ac
Add script to synthesize depth-optimal 16_6_4.
pehamTom Feb 25, 2025
18205f1
Fix synthesis script.
pehamTom Feb 25, 2025
3e7ce14
Scripts.
pehamTom Feb 26, 2025
680afe8
Automated synthesis of correction networks.
pehamTom Mar 7, 2025
53b999c
Example notebook for correction network synthesis.
pehamTom Mar 7, 2025
97ebe2c
Merge branch 'main' into encoding-circuits
pehamTom Sep 22, 2025
c2e402b
Fix tests.
pehamTom Sep 22, 2025
fc0f9f6
Working depth-optimal encoding.
pehamTom Oct 6, 2025
418daa2
Improved encoding.
pehamTom Oct 6, 2025
4885442
GPT conversion to google or tools.
pehamTom Oct 7, 2025
61b50b2
Trying to port to or tools.
pehamTom Oct 8, 2025
629d18f
Revert "Trying to port to or tools."
pehamTom Oct 17, 2025
f58574a
Improved CNOT circuit synthesis using lookahead scheme.
pehamTom Oct 22, 2025
757c25c
Fix bug in level-two lookahead.
pehamTom Oct 22, 2025
57aa6d2
Normalize logicals.
pehamTom Oct 27, 2025
f441551
Reduce checks.
pehamTom Nov 10, 2025
a54884b
Allow omitting phase.
pehamTom Nov 10, 2025
b7bac1c
Arbitrary lookahead.
pehamTom Nov 10, 2025
78d7d08
Compute logicals for `StabilizerCode`.
pehamTom Nov 10, 2025
9326734
Take circuit logicals when getting code from circuit.
pehamTom Nov 10, 2025
ee21eba
Rough draft Clifford Synthesis.
pehamTom Jan 13, 2026
6ed4561
Merge branch 'main' into encoding-circuits
pehamTom Jan 13, 2026
c6f50aa
Seemingly correct vibe coded version.
pehamTom Jan 13, 2026
d04b5ce
Fix bug from merge.
pehamTom Jan 14, 2026
f4f33c9
Fix mod2 usage.
pehamTom Jan 14, 2026
ac5a6eb
Second attempt, add tests.
pehamTom Jan 14, 2026
f5d9fd9
Corrected circuit synthesis.
pehamTom Jan 14, 2026
f39fa81
chore: remove commented-out encoding circuit functions
pehamTom Jan 15, 2026
737cdf6
`refactor: integrate StabilizerTableau for symplectic operations`
pehamTom Jan 15, 2026
d738a2c
fix: define missing bin2set and r2_matrix functions in encoding.py
pehamTom Jan 15, 2026
6cce287
feat: implement from_matrix method for StabilizerTableau class
pehamTom Jan 15, 2026
2377ad5
fix: remove unreachable code causing undefined name errors in pauli.py
pehamTom Jan 15, 2026
833ec89
feat: add __eq__ method to StabilizerTableau for equality comparison
pehamTom Jan 15, 2026
81e6e8f
Remove unnecessary import.
pehamTom Jan 15, 2026
269f9da
fix: replace incorrect attribute 'num_qubits' with 'n' in encoding.py
pehamTom Jan 15, 2026
0363ca2
refactor: Move compute_r1_matrix and compute_r2_matrix outside Stabil…
pehamTom Jan 15, 2026
22a95f9
fix: replace incorrect method call with standalone function for R2 ca…
pehamTom Jan 15, 2026
17af0ae
refactor: consolidate repetitive Volanto tests using parameterized te…
pehamTom Jan 15, 2026
277c6e0
Restore compact_stim_circuit method
pehamTom Jan 15, 2026
8c104bf
Use `StabilizerTableau` as input for Volanto synthesis.
pehamTom Jan 15, 2026
9261c40
Move Stim to Tableau conversion to `StabilizerTableau`.
pehamTom Jan 15, 2026
494d67d
Adapt tests to new interface.
pehamTom Jan 15, 2026
ee926cf
Add ortools to dependencies.
pehamTom Jan 19, 2026
a216279
Add `from_stim_tableau` method.
pehamTom Jan 19, 2026
4eac53d
Fix doc string
pehamTom Jan 19, 2026
f1b88d5
Add protobuf
pehamTom Jan 19, 2026
846364c
Add lookahead synthesis for stabilizer tableaus.
pehamTom Jan 19, 2026
2aa9db6
Make lookahead work for lookahead depth=0.
pehamTom Jan 19, 2026
0a5874a
Remove comment.
pehamTom Jan 20, 2026
f2826c6
Use lookahead in synthesis.
pehamTom Jan 20, 2026
61224cc
Fix sign fix method.
pehamTom Jan 20, 2026
f0399ac
Correct sign fix in synthesis method.
pehamTom Jan 20, 2026
1091026
Added method for counting two-qubit gates in stim circuits.
pehamTom Jan 20, 2026
83aff22
Fix test for resynthesis method.
pehamTom Jan 20, 2026
9463a45
uv
pehamTom Jan 20, 2026
2dc3457
Linting errors.
pehamTom Jan 20, 2026
99e40bb
Clean up synthesis function.
pehamTom Jan 21, 2026
84043fb
Only choose k best candidates for lookahead.
pehamTom Jan 21, 2026
6f9b980
Functionality for checking whether a tableau is css.
pehamTom Jan 21, 2026
de1635c
Separate file for elimination functionality.
pehamTom Jan 21, 2026
6f64681
Start Refactor of elimination.
pehamTom Jan 21, 2026
2dd6632
Abstract filtering of operations.
pehamTom Jan 22, 2026
0e0086e
Start: Add postprocessing to elimination.
pehamTom Jan 22, 2026
c2121f0
Elimination works for non-CSS.
pehamTom Jan 22, 2026
51c9d19
Add missing docstrings.
pehamTom Jan 22, 2026
c0fc59b
Add elimination for non-css tableaus.
pehamTom Jan 23, 2026
7130e8d
Lookahead elimination.
pehamTom Jan 23, 2026
3eccdd6
Add early termination criterion.
pehamTom Jan 23, 2026
9e803ff
Remove unused argument.
pehamTom Jan 23, 2026
55e6452
Abstract elimination to allow for check matrices.
pehamTom Jan 23, 2026
fde0d22
Non-css elimination.
pehamTom Jan 23, 2026
7cde544
Restructure search parameters.
pehamTom Jan 26, 2026
3deadf6
Refactor.
pehamTom Jan 26, 2026
cc7e79a
Add missing docstrings.
pehamTom Jan 26, 2026
0922977
Refactor more.
pehamTom Jan 26, 2026
4909d7d
Different configurations for CNOT synthesis.
pehamTom Jan 26, 2026
07e86b0
Start restructure encoder.py
pehamTom Jan 26, 2026
9864637
Fix wrong circuit for transvection.
pehamTom Jan 29, 2026
512389e
Hash for CheckMatrix class.
pehamTom Feb 2, 2026
2d9828e
Fix elimination.
pehamTom Feb 2, 2026
1de868c
Docstrings.
pehamTom Feb 2, 2026
becbe33
Use bitwise ops for tableau operations.
pehamTom Feb 2, 2026
5ac678a
Test up to depth 2 for lookup.
pehamTom Feb 2, 2026
59aba2c
Define class representing a Clifford isomety.
pehamTom Feb 2, 2026
12c6a32
Convert isometry to code.
pehamTom Feb 2, 2026
ed58ab6
Iterators for EliminationSequence
pehamTom Feb 2, 2026
6156ebe
Attributes for `CheckMatrix`.
pehamTom Feb 2, 2026
f76983d
Refactor CSS elimination.
pehamTom Feb 2, 2026
130ff78
Refactor: combine cnot and non-css synthesis.
pehamTom Feb 2, 2026
34c8026
Combine Isometries.
pehamTom Feb 2, 2026
9158d08
Fix tests.
pehamTom Feb 2, 2026
2c6ded4
Adapt `state_prep.py`.
pehamTom Feb 2, 2026
f0adcec
Adapt Gottesman encoding circuit synthesis.
pehamTom Feb 2, 2026
de06d1e
Add option for not counting swaps.
pehamTom Feb 4, 2026
d6df7a3
Avoid mod operations.
pehamTom Feb 4, 2026
a8ec4af
Attempt improved non-CSS synthesis for states.
pehamTom Feb 4, 2026
96623bd
Improve performance.
pehamTom Feb 4, 2026
f2ea627
Count correct gates.
pehamTom Feb 4, 2026
513791f
Volanto synthesis directly from tableau.
pehamTom Feb 4, 2026
44e914c
Fix stabilizer tableau completion.
pehamTom Feb 12, 2026
4708a5b
Optimize tableau before synthesis.
pehamTom Feb 12, 2026
839872a
Fix order of destabilizer additions.
pehamTom Feb 13, 2026
71cdbf7
Pass through of synthesis parameters.
pehamTom Feb 16, 2026
8ecc236
Also optimize logical representation.
pehamTom Feb 16, 2026
ac71332
Fix depth heuristic for CSS Codes.
pehamTom Feb 24, 2026
c268007
Different number of candidates per lookahead layer.
pehamTom Feb 24, 2026
bf739fd
Incorporate filtering into candidate generation.
pehamTom Feb 24, 2026
5beef23
Fix lookahead depth synthesis.
pehamTom Feb 24, 2026
d0c51e7
Experimenting with settings.
pehamTom Feb 26, 2026
3f90df7
Fix filtering logic.
pehamTom Feb 26, 2026
5e97720
Early termination in lookahead.
pehamTom Feb 26, 2026
51bcaee
Add early termination as optional parameter.
pehamTom Feb 26, 2026
2dfffba
Optional early termination.
pehamTom Feb 27, 2026
1dab88a
Refactor cnot synthesis into seperate file.
pehamTom Feb 27, 2026
8233ee3
Refactor transvection synthesis.
pehamTom Feb 27, 2026
3e2a271
Refactor operations out of elimination.
pehamTom Feb 27, 2026
e605068
Extract types.
pehamTom Feb 27, 2026
b5ed2ce
Refactor lookahead and config.
pehamTom Feb 27, 2026
09ff03e
Rename EliminationConfig to EliminationStrategy.
pehamTom Feb 27, 2026
b15e5cd
Renamed config.py to strategy.py.
pehamTom Feb 27, 2026
769ee33
Break cyclic imports by moving synthesis functions.
pehamTom Feb 27, 2026
ee1c8c1
Refactor lookahead synthesis.
pehamTom Feb 27, 2026
e4d527f
Revert "Refactor lookahead synthesis."
pehamTom Feb 27, 2026
cea9dc4
Start refactor config.
pehamTom Feb 27, 2026
08f5cfa
Refactor parameters for synthesis into config.
pehamTom Feb 27, 2026
b50861e
Adapt stateprep circuit.
pehamTom Feb 27, 2026
1afd709
Filter before computing scores.
pehamTom Mar 4, 2026
1af5b4d
Fix function call for cnot encoding circuit.
pehamTom Mar 4, 2026
d05aea1
Fix wrong order of logical "fixup" circuit.
pehamTom Mar 4, 2026
d920fbd
Depth and gate count of isometry.
pehamTom Mar 4, 2026
09d79ed
Track depth online to speed up depth optimization.
pehamTom Mar 4, 2026
dd690fb
Avoid costly type check in hot path.
pehamTom Mar 4, 2026
8c5d44b
Remove filter for gate optimization
pehamTom Mar 4, 2026
f1cb9f2
Add css info to apply call.
pehamTom Mar 4, 2026
249f8ef
Fix encoder synthesis for non-CSS code.
pehamTom Mar 4, 2026
1f2c271
Minor refactors.
pehamTom Mar 4, 2026
e18284d
Filter before scoring.
pehamTom Mar 4, 2026
4710193
Allow other file formats for reading codes from files.
pehamTom Mar 4, 2026
799878b
Add configs to tests.
pehamTom Mar 4, 2026
c4d1443
Test elimination sequence.
pehamTom Mar 4, 2026
df2d76c
Fix filtering.
pehamTom Mar 4, 2026
0e52dc0
Fix infinite loop.
pehamTom Mar 4, 2026
3e51044
Fix loading stabilizer code from file.
pehamTom Mar 5, 2026
9409646
Remove commented code.
pehamTom Mar 5, 2026
4d882e3
types
pehamTom Mar 5, 2026
cb023ca
Fix tests.
pehamTom Mar 5, 2026
80489fc
Linter fixes.
pehamTom Mar 5, 2026
5d7fd28
Linter
pehamTom Mar 5, 2026
7427721
Remove abstractmethod declaration from non-abstract method.
pehamTom Mar 5, 2026
b5ecb35
Move cnot encoding synthesis to encoding.py.
pehamTom Mar 5, 2026
add18a9
More linter fixes.
pehamTom Mar 5, 2026
2de8d64
Unify interface of CliffordIsometry and CNOTCircuit.
pehamTom Mar 5, 2026
0c16b08
Linter errors
pehamTom Mar 5, 2026
9f108a0
Mypy.
pehamTom Mar 6, 2026
5012694
Merge branch 'main' into encoding-circuits
pehamTom Mar 6, 2026
3f921cf
🎨 pre-commit fixes
pre-commit-ci[bot] Mar 6, 2026
eaafcf2
Improve Filtering.
pehamTom Mar 6, 2026
6fccf5e
Merge remote-tracking branch 'origin/encoding-circuits' into encoding…
pehamTom Mar 6, 2026
eee7e7b
Docs.
pehamTom Mar 6, 2026
cb70af9
Unnecessary "$" signs in doc.
pehamTom Mar 6, 2026
1a5791c
Wrong inputs in encoder in docs.
pehamTom Mar 6, 2026
48a6d33
Bump ortools version.
pehamTom Mar 6, 2026
f7de95e
Jit compile hot path.
pehamTom Mar 6, 2026
38be431
Fix type error.
pehamTom Mar 6, 2026
bb27abf
Define numba loop for different types.
pehamTom Mar 6, 2026
5d4b682
Fix bug in CNOT encoding circuit synthesis.
pehamTom Mar 6, 2026
9daafb1
Simplify encoding circuit synthesis for cnots.
pehamTom Mar 6, 2026
150827a
Fix Synthesisconfig.
pehamTom Mar 6, 2026
c72b71a
Speed up termination criterion check for cnot synthesis.
pehamTom Mar 6, 2026
88cbb50
Apply filter after reset.
pehamTom Mar 6, 2026
377010a
Fix parallel filter again.
pehamTom Mar 6, 2026
663dd00
Debug logging.
pehamTom Mar 6, 2026
4d9af6f
Info logging.
pehamTom Mar 6, 2026
0e14172
Log tableau.
pehamTom Mar 6, 2026
9dbc6c4
Actually print matrix.
pehamTom Mar 6, 2026
400ac1b
Test differnt termination criterion.
pehamTom Mar 6, 2026
86a6e79
More logging.
pehamTom Mar 6, 2026
9e3eef9
Faster termination check.
pehamTom Mar 6, 2026
5d9127d
Info logging of ops.
pehamTom Mar 6, 2026
320b9b4
Log filter.
pehamTom Mar 7, 2026
f3e066f
Log candidate generation.
pehamTom Mar 7, 2026
d1543be
Log cache.
pehamTom Mar 7, 2026
776acdf
Possible cache invalidation.
pehamTom Mar 7, 2026
c7d2129
Let generator handle cache.
pehamTom Mar 7, 2026
a784ab5
Hard-code stateprep circuit in tests.
pehamTom Mar 9, 2026
bc3da14
Merge branch 'main' into encoding-circuits
pehamTom Mar 9, 2026
51e7878
Inline single-qubit gates in transvection application.
pehamTom Mar 9, 2026
e48e6f8
More compact transvection computation.
pehamTom Mar 9, 2026
2ff9a9f
JIT compilation for transvections.
pehamTom Mar 9, 2026
f5c99f9
Speed up transvection scoring.
pehamTom Mar 9, 2026
ee5bcac
Speed up transvection synthesis.
pehamTom Mar 9, 2026
f4ec53c
Fix phase.
pehamTom Mar 9, 2026
351354e
Relax constraints on deterministic verification.
pehamTom Mar 10, 2026
cbe8cce
Add type signature for failing windows CI.
pehamTom Mar 10, 2026
855829a
Changed private _input field to list.
pehamTom Mar 10, 2026
ce8e6e9
Fix equality test of stabilizer codes.
pehamTom Mar 10, 2026
74cbed4
Utility for checking equality and mappings of logicals.
pehamTom Mar 10, 2026
ea7933d
Add functionality to get logical to physical mapping.
pehamTom Mar 10, 2026
4fb5a95
Less strict tests for deterministic verification.
pehamTom Mar 10, 2026
5999e38
Numba types for windows.
pehamTom Mar 10, 2026
c3b6489
Handle case of no logical operators in CSSCode init.
pehamTom Mar 10, 2026
cba4551
Handle case of no logical operators in CSSCode init.
pehamTom Mar 10, 2026
26f66bd
Merge remote-tracking branch 'origin/encoding-circuits' into encoding…
pehamTom Mar 10, 2026
f705642
Further relax determinist verification.
pehamTom Mar 10, 2026
9acdbfd
Continue with non-det fix.
pehamTom Mar 10, 2026
3df8c2e
Make test even less strict.
pehamTom Mar 10, 2026
faecab9
Row operations on logicals.
pehamTom Mar 12, 2026
4021005
Attempt at caching for lookahead.
pehamTom Mar 13, 2026
ca13544
Rename synthesis to rollout.
pehamTom Mar 13, 2026
25c87e1
Rename cache.
pehamTom Mar 13, 2026
c1c7330
Clear cache after synthesis.
pehamTom Mar 13, 2026
2c2218b
Fix early termination.
pehamTom Mar 13, 2026
eeacb42
Hotfix to early termination.
pehamTom Mar 13, 2026
c92e567
Hack to fix early termination.
pehamTom Mar 13, 2026
5e3505f
Fix and simplify rollout.
pehamTom Mar 16, 2026
b254c34
Add Caching back in.
pehamTom Mar 17, 2026
e70f9f3
Fix hashing of Operations.
pehamTom Mar 17, 2026
45adf96
Early termination is back.
pehamTom Mar 17, 2026
d53cfee
Fix depth optimization by passing filter state.
pehamTom Mar 17, 2026
5b6609a
Escape local minima.
pehamTom Mar 17, 2026
8bd3dd4
Fix local minimum escape.
pehamTom Mar 18, 2026
263136f
Triples for local minimum
pehamTom Mar 18, 2026
3bf4e39
Refactor elimination.
pehamTom Mar 18, 2026
27da023
Generalize local minima escape.
pehamTom Mar 18, 2026
3f9faf6
Set logicals.
pehamTom Mar 19, 2026
0f0b888
Merge branch 'main' into encoding-circuits
pehamTom Mar 19, 2026
2372451
Disable 11,1,3 deterministic test.
pehamTom Mar 19, 2026
f6f4c48
Don't cache entire tail.
pehamTom Mar 20, 2026
2ce4dbe
LRU Caching.
pehamTom Mar 20, 2026
045801d
Improve cache handling.
pehamTom Mar 20, 2026
cd91c45
Remove unused clear_cache method.
pehamTom Mar 20, 2026
4a21b19
Remove redundant stabilizers before encoder synthesis.
pehamTom Mar 31, 2026
8557b8f
Merge branch 'main' into encoding-circuits
pehamTom Apr 7, 2026
1ac6bd3
🎨 pre-commit fixes
pre-commit-ci[bot] Apr 7, 2026
cdea4f2
Lockfile.
pehamTom Apr 7, 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
157 changes: 90 additions & 67 deletions docs/Encoders.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,15 @@ mystnb:

# Encoder Circuit Synthesis for CSS Codes

QECC provides functionality for synthesizing encoding circuits of arbitrary CSS codes. An encoder for an $[[n,k,d]]$ code is an isometry that encodes $k$ logical qubits into $n$ physical qubits.
QECC provides functionality for synthesizing encoding circuits of arbitrary Stabilizer codes. An encoder for an $[[n,k,d]]$ code is an isometry that encodes $k$ logical qubits into $n$ physical qubits.

Let's consider the synthesis of the encoding circuit of the $[[7,1,3]]$ Steane code.

```{code-cell} ipython3
from mqt.qecc import CSSCode
from mqt.qecc.circuit_synthesis import (
depth_optimal_encoding_circuit,
gate_optimal_encoding_circuit,
heuristic_encoding_circuit,
gate_optimal_encoding_circuit
)

steane_code = CSSCode.from_code_name("steane")
Expand All @@ -31,14 +30,15 @@ print("Stabilizers:\n")
print(steane_code.stabs_as_pauli_strings())
print("\nLogicals:\n")
print(steane_code.x_logicals_as_pauli_strings())
print(steane_code.z_logicals_as_pauli_strings())
```

There is not a unique encoding circuit but usually we would like to obtain an encoding circuit that is optimal with respect to some metric. QECC has functionality for synthesizing gate- or depth-optimal encoding circuits.

Under the hood, this uses the SMT solver [z3](https://github.com/Z3Prover/z3). Of course this method scales only up to a few qubits. Synthesizing depth-optimal circuits is usually faster than synthesizing gate-optimal circuits.

```{code-cell} ipython3
depth_opt = depth_optimal_encoding_circuit(steane_code, max_timeout=5)
depth_opt = depth_optimal_encoding_circuit(steane_code, max_timeout=2)
q_enc = depth_opt.get_uninitialized()

print(f"Encoding qubits are qubits {q_enc}.")
Expand All @@ -49,7 +49,7 @@ depth_opt.draw('mpl')
```

```{code-cell} ipython3
gate_opt = gate_optimal_encoding_circuit(steane_code, max_timeout=5)
gate_opt = gate_optimal_encoding_circuit(steane_code, max_timeout=2)
q_enc = gate_opt.get_uninitialized()

print(f"Encoding qubits are qubits {q_enc}.")
Expand All @@ -66,106 +66,129 @@ In addition to the circuit, the synthesis methods also return the encoding qubit
For larger codes, synthesizing optimal circuits is not feasible. In this case, QECC provides a heuristic synthesis method that tries to use as few CNOTs with the lowest depth as possible.

```{code-cell} ipython3
heuristic_circ = heuristic_encoding_circuit(steane_code)
q_enc = heuristic_circ.get_uninitialized()
from mqt.qecc.circuit_synthesis import (
synthesize_encoding_circuit,
)

print(f"Encoding qubits are qubits {q_enc}.")
heuristic_circ = synthesize_encoding_circuit(steane_code)
q_enc = heuristic_circ.inputs()

print(f"Messaging (logical input) qubits: {q_enc}")
print(f"Circuit has depth {heuristic_circ.depth()}.")
print(f"Circuit has {heuristic_circ.num_cnots()} CNOTs.")

heuristic_circ.draw('mpl')
```

## Synthesizing Encoders for Concatenated Codes
By default the heuristic synthesis tries to optimize for two-qubit gate count. We can also tell the synthesis to optimize for depth.

Encoders for concatenated codes can be constructed by concatenating encoding circuits. We can concatenate the $[[4,2,2]]$ code (with stabilizer generators $XXXX$ and $ZZZZ$) with itself by encoding $4$ qubits into two blocks of the code and then encoding these qubits one more time. This gives an $[[8,4,2]]$ code. The distance is still $2$ but if done the right way, some minimal-weight logicals have weight $4$.
```{code-cell} ipython3
from mqt.qecc.circuit_synthesis import (
SynthesisConfig
)

As an exercise, let's construct the concatenated circuit.
config = SynthesisConfig(optimization_criterion="depth")
heuristic_circ = synthesize_encoding_circuit(steane_code)
q_enc = heuristic_circ.inputs()

We start off by defining the code:
print(f"Messaging (logical input) qubits: {q_enc}")
print(f"Circuit has depth {heuristic_circ.depth()}.")
print(f"Circuit has {heuristic_circ.num_cnots()} CNOTs.")

```{code-cell} ipython3
import numpy as np
heuristic_circ.draw('mpl')
```

d = 2
x_stabs = np.ones((1, 4), dtype=np.int8)
z_stabs = x_stabs
code = CSSCode(x_stabs, z_stabs, d)
The `inputs()` method returns a list of physical qubit indices representing the encoded logical information. All other qubits are ancillas initialized in the $|0\rangle$ or $|+\rangle$ state.

print("Stabilizers:\n")
print(code.stabs_as_pauli_strings())
print("\nLogicals:\n")
print(code.x_logicals_as_pauli_strings())
print(code.z_logicals_as_pauli_strings())
```
# Encoder Circuit Synthesis for non-CSS Stabilizer Codes

We have to be careful with the logicals. Each _anticommuting_ pair of logicals defines one logical qubit.
QECC also supports encoding circuit synthesis for non-CSS stabilizer codes. For these codes, encoding circuits are built from two-qubit transvections (see arXiv:2503.14660 for details).

As before, we synthesize the encoding circuit:
Let's consider the $[[5,1,3]]$ code.

```{code-cell} ipython3
encoder = depth_optimal_encoding_circuit(code, max_timeout=5)
q_enc = encoder.get_uninitialized()
from mqt.qecc import StabilizerCode
from mqt.qecc.circuit_synthesis import synthesize_encoding_circuit

stabs = ["XZZXI", "IXZZX", "XIXZZ", "ZXIXZ"]
x_logicals = ["XXXXX"]
z_logicals = ["ZZZZZ"]
five_qubit_code = StabilizerCode(stabs, x_logicals=x_logicals, z_logicals=z_logicals)

print("Stabilizers:")
for stab in stabs:
print(f" {stab}")
print("\nX Logical:")
print(f" {x_logicals[0]}")
print("Z Logical:")
print(f" {z_logicals[0]}")
```

print(f"Encoding qubits are qubits {q_enc}.")
print(f"Circuit has depth {encoder.depth()}.")
print(f"Circuit has {encoder.num_cnots()} CNOTs.")
The same `synthesize_encoding_circuit` function works for non-CSS codes. This method returns a `CliffordIsometry` object.

encoder.draw('mpl')
```{code-cell} ipython3
encoder = synthesize_encoding_circuit(five_qubit_code)
message_qubits = encoder.inputs()

print(f"Message qubits (logical to physical mapping): {message_qubits}")
print(f"Circuit has two-qubit depth {encoder.depth()}.")
print(f"Circuit has {encoder.num_two_qubit_gates()} two-qubit gates.")

encoder.draw(output='mpl', fold=False)
```

Propagating Paulis from the encoding qubits at the input to the output will not necessarily yield the exact logicals given above. But the logical operators will be stabilizer equivalent.
For displaying the circuit, the transvections are decomposed into CZ and single-qubit Clifford gates.

Concatenating the circuits can be done as follows with qiskit:
For non-CSS codes, depth-optimal synthesis is also available:

```{code-cell} ipython3
from mqt.qecc.circuit_synthesis.circuits import compose_cnot_circuits
from mqt.qecc.circuit_synthesis import depth_optimal_encoding_circuit_non_css

n = 4
for d in range(3, 9):
result = depth_optimal_encoding_circuit_non_css(five_qubit_code, max_depth=d, exact_two_qubit_count=True, max_two_qubit_gates=6)

first_layer = encoder
second_layer, mapping1, mapping2 = compose_cnot_circuits(encoder, encoder) # vertically composes circuits
if result == "UNSAT":
print(f"No solution for max_depth={d}")
else:
encoder = result
break
print(f"Message qubits (logical to physical mapping): {message_qubits}")
print(f"Circuit has two-qubit depth {encoder.depth()}.")
print(f"Circuit has {encoder.num_two_qubit_gates()} two-qubit gates.")

wiring = {0: mapping1[q_enc[0]], 1: mapping1[q_enc[1]], 2: mapping2[q_enc[0]], 3: mapping2[q_enc[1]]}
concatenated, _, _ = compose_cnot_circuits(first_layer, second_layer, wiring)

q_enc = concatenated.get_uninitialized()
print(f"Encoding qubits are qubits {q_enc}.")
print(f"Circuit has depth {concatenated.depth()}.")
print(f"Circuit has {concatenated.num_cnots()} CNOTs.")

concatenated.draw('mpl')
encoder.draw(output='mpl', fold=False)
```

Qubits $1$ and $2$ are still the encoding qubits and if we propagate Pauli $X$ and $Z$ to the output, we find that this is indeed the encoder for an $[[8,2,2]]$ code.
This method uses SMT-based synthesis to find a depth-optimal encoding circuit, similar to the CSS case. The `max_depth` parameter limits the search depth. If no solution is found, it returns `"UNSAT"`.

## Tweaking Parameters for Heuristic Synthesis

This circuit has $3$ times as many CNOT gates as the encoder for the unconcatenated code because we needed to encode 3 times. Instead of concatenating the encoder circuits we can synthesize the encoders directly from the stabilizers of the concatenated code.
We can obtain the code defined by the circuit directly from the circuit object.
Let's consider a slightly larger example, the $[[23,1,7]]$ [Golay code](https://errorcorrectionzoo.org/c/qubit_golay).

```{code-cell} ipython3
concatenated_code = concatenated.get_code()
code = CSSCode.from_code_name("golay")

print("Stabilizers:\n")
print(concatenated_code.stabs_as_pauli_strings())
encoder = synthesize_encoding_circuit(code)
print(f"Messaging (logical input) qubits: {encoder.inputs()}")
print(f"Circuit has depth {encoder.depth()}.")
print(f"Circuit has {encoder.num_cnots()} CNOTs.")

print("\nLogicals:\n")
print(concatenated_code.x_logicals_as_pauli_strings())
print(concatenated_code.z_logicals_as_pauli_strings())
encoder.draw(output='mpl', fold=False, scale=0.5)
```

Now we can directly synthesize the encoder:
The way the greedy synthesis works in QECC is by trying to reduce the check matrix (or stabilizer tableau) of the code in question using as few elementary matrix operations (gates) as possible. The synthesis is greedily guided by some metric computed on the check matrix - the number of remaining entries in the check matrix, for example. Since the synthesis algorithm makes local choices, the search might go down branches of the search-tree leading to sub-optimal solution. QECC also provides a costlier search procedure which tries to look ahead which candidates in the search will lead to good results by completing the entire greedy synthesis for these candidates and making a choice based on the resulting circuits (as opposed to using the check matrix as a proxy for estimating).

This search is generally costlier, but can lead to significantly better results. We can tell the synthesis to perform rollout-based synthesis by setting the appropriate flags in the config. `rollout` is an int parameter that determines for how many layers the search should perform the rollout. If it is set to `0`, no rollout is performed (default). If it is set to `1`, the `num_rollout_candidates` parameter determines for how many candidates per gate in the search the rollout is performed. This determines how many complete circuits are synthesized before the single gate is chosen leading to the locally best circuit. If `enable_early_termination` rollout is only performed until no better solutions are found. In that case, the search returns whatever the current best circuit is. If it is set to `False`, rollout will be performed until the last gate of the search is placed. This will take longer but leads to better results in general:

```{code-cell} ipython3
encoder_concat_direct = depth_optimal_encoding_circuit(
concatenated_code, max_timeout=5
)
q_enc = encoder_concat_direct.get_uninitialized()
from mqt.qecc.circuit_synthesis import SynthesisConfig

print(f"Encoding qubits are qubits {q_enc}.")
print(f"Circuit has depth {encoder_concat_direct.depth()}.")
print(f"Circuit has {encoder_concat_direct.num_cnots()} CNOTs.")
config = SynthesisConfig(rollout=1, num_rollout_candidates=5, optimization_criterion="gates", enable_early_termination=False)

encoder_concat_direct.draw('mpl')
```
encoder = synthesize_encoding_circuit(code, config=config)
print(f"Messaging (logical input) qubits: {encoder.inputs()}")
print(f"Circuit has depth {encoder.depth()}.")
print(f"Circuit has {encoder.num_cnots()} CNOTs.")

We see that the circuit is more compact then the naively concatenated one. This is because the synthesis method exploits redundancy in the check matrix of the concatenated code.
encoder.draw(output='mpl', fold=False, scale=0.5)
```
86 changes: 86 additions & 0 deletions notebooks/Correction Network.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "9f21998a-6ce6-4d08-a967-6cb687b9dea0",
"metadata": {},
"outputs": [],
"source": [
"from mqt.qecc.circuit_synthesis import correction_network"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1ce0e5d2-d7dc-414a-ad41-fae660d866fc",
"metadata": {},
"outputs": [],
"source": [
"# remap qubits to be contiguous and store inverse maps\n",
"flip_index_map = {2: 0, 7: 1, 11: 2, 14: 3}\n",
"flip_index_map_inverse = {i: j for j, i in flip_index_map.items()}\n",
"correction_index_map = {0: 0, 3: 1, 4: 2, 6: 3, 8: 4, 10: 5, 12: 6}\n",
"correction_index_map_inverse = {i: j for j, i in correction_index_map.items()}\n",
"\n",
"# map from flipped qubits to wanted corrections\n",
"correction_map = {\n",
" (11,): [0, 3, 4, 6, 8, 10, 12],\n",
" (2,): [3, 4, 6, 10],\n",
" (14,): [0, 3, 12],\n",
" (7,): [3, 8],\n",
" (11, 14): [4],\n",
" (2, 14): [0, 10],\n",
" (7, 11): [0, 6],\n",
" (2, 7): [0, 4, 8],\n",
" (7, 14): [4, 12],\n",
" (2, 11, 14): [6, 12],\n",
" (2, 7, 11): [10],\n",
" (7, 11, 14): [6, 8],\n",
" (2, 7, 14): [8, 10, 12],\n",
" (2, 7, 11, 14): [3],\n",
" (2, 11): [],\n",
"}\n",
"\n",
"correction_map_mapped = {}\n",
"for pattern, correction in correction_map.items():\n",
" pattern_mapped = tuple(flip_index_map[q] for q in pattern)\n",
" correction_mapped = [correction_index_map[q] for q in correction]\n",
" correction_map_mapped[pattern_mapped] = correction_mapped\n",
"\n",
"n_data = 7\n",
"n_flips = 4\n",
"\n",
"network = correction_network(n_data, n_flips, correction_map_mapped)\n",
"\n",
"network_remapped = {}\n",
"for pattern, correction in network.items():\n",
" pattern_mapped = tuple(flip_index_map_inverse[q] for q in pattern)\n",
" correction_mapped = [correction_index_map_inverse[q] for q in correction]\n",
" network_remapped[pattern_mapped] = correction_mapped\n",
"\n",
"network_remapped"
]
}
],
"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
}
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ dependencies = [
"qecsim>=1.0b9",
"sinter>=1.14.0",
"tqdm>=4.66.2",
"ortools>=9.14.2151",
"protobuf==6.31.1",
"networkx>=3.4.2",
]
dynamic = ["version"]
Expand Down Expand Up @@ -151,7 +153,7 @@ exclude = [

[[tool.mypy.overrides]]
module = ["qiskit.*", "qecsim.*", "qiskit_aer.*", "matplotlib.*", "scipy.*", "ldpc.*", "pytest_console_scripts.*",
"z3.*", "bposd.*", "numba.*", "pymatching.*", "stim.*", "multiprocess.*", "sinter.*", "qsample.*", "pandas.*", "tqdm.*", "networkx.*"]
"z3.*", "bposd.*", "numba.*", "pymatching.*", "stim.*", "multiprocess.*", "sinter.*", "qsample.*", "pandas.*", "tqdm.*", "ortools.*", "ortools.sat.python","networkx.*"]
ignore_missing_imports = true


Expand Down Expand Up @@ -249,6 +251,7 @@ aer = "aer"
anc = "anc"
arange = "arange"
nd = "nd"
strat = "strat"
iz = "iz"


Expand Down
Loading
Loading