Surface-17 Rotated Surface Code QEC Demo¶
This notebook demonstrates a single QEC cycle of the distance-3 rotated surface code (9 data qubits, 4 Z-type ancillas, 4 X-type ancillas) matching the rotated planar layout.
Qubit Layout¶
(X1) [Z2-boundary]
/ \
D1 ── D2 ── D3
/ │ X2 │ Z3 │
(Z1) │ │ │
\ │ │ │
D4 ── D5 ── D6
| | | \
│ Z2 │ X3 │ (Z4)
| | | /
D7 ── D8 ── D9
\ /
(X4) [X-boundary]
Index Mapping¶
| Index | Label | Type | Connected Data Qubits |
|---|---|---|---|
| 0 | Z1 | Z ancilla | D1, D4 |
| 1 | Z2 | Z ancilla | D4, D5, D7, D8 |
| 2 | Z3 | Z ancilla | D2, D3, D5, D6 |
| 3 | Z4 | Z ancilla | D6, D9 |
| 4-12 | D1-D9 | Data qubits | Grid (D1=4, D2=5, ..., D9=12) |
| 13 | X1 | X ancilla | D2, D3 |
| 14 | X2 | X ancilla | D1, D2, D4, D5 |
| 15 | X3 | X ancilla | D5, D6, D8, D9 |
| 16 | X4 | X ancilla | D7, D8 |
In [1]:
from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator
In [2]:
def prepare_logical_zero(qc):
"""
Unitary encoding circuit preparing the 9 data qubits into logical |0>_L.
In |0>_L, all 8 stabilizers have eigenvalue +1 and Z_L = +1.
Data qubits are indices 4..12 (D1..D9).
"""
# 1. H on independent check data qubits: D4(7), D3(6), D9(12), D7(10)
qc.h(7)
qc.h(6)
qc.h(12)
qc.h(10)
# 2. CNOTs implementing the CSS generator matrix
# Row X2 (D4 -> D1, D2, D5)
qc.cx(7, 4)
qc.cx(7, 5)
qc.cx(7, 8)
# Row X1 (D3 -> D2)
qc.cx(6, 5)
# Row X3 (D9 -> D5, D6, D8)
qc.cx(12, 8)
qc.cx(12, 9)
qc.cx(12, 11)
# Row X4 (D7 -> D8)
qc.cx(10, 11)
qc.barrier()
def build_surface_code_cycle(error_qubit=None, error_type=None):
# 17 total qubits: 4 Z-ancillas + 9 Data + 4 X-ancillas
# 8 classical bits for syndrome readout
qc = QuantumCircuit(17, 8)
# Step 1: Initialize data qubits into logical |0>_L
prepare_logical_zero(qc)
# Step 2: Inject single-qubit Pauli error (if specified)
if error_qubit is not None and error_type is not None:
if error_type.upper() == 'X':
qc.x(error_qubit)
elif error_type.upper() == 'Z':
qc.z(error_qubit)
qc.barrier()
# Step 3: Measure Z-type stabilizers (Ancillas 0 to 3)
# Z-ancillas: data controls CX into ancilla
z_plaquettes = [
[0, 4, 7], # Z1: (D1, D4)
[1, 7, 8, 10, 11], # Z2: (D4, D5, D7, D8)
[2, 5, 6, 8, 9], # Z3: (D2, D3, D5, D6)
[3, 9, 12] # Z4: (D6, D9)
]
for plaquette in z_plaquettes:
anc = plaquette[0]
for d in plaquette[1:]:
qc.cx(d, anc)
qc.barrier()
# Step 4: Measure X-type stabilizers (Ancillas 13 to 16)
# X-ancillas: ancilla in |+>, controls CX into data qubits
x_plaquettes = [
[13, 5, 6], # X1: (D2, D3)
[14, 4, 5, 7, 8], # X2: (D1, D2, D4, D5)
[15, 8, 9, 11, 12], # X3: (D5, D6, D8, D9)
[16, 10, 11] # X4: (D7, D8)
]
for plaquette in x_plaquettes:
anc = plaquette[0]
qc.h(anc)
for d in plaquette[1:]:
qc.cx(anc, d)
qc.h(anc)
qc.barrier()
# Step 5: Read out ancilla qubits into classical register
# Z1-Z4 (qubits 0..3) -> classical bits 0..3
for i in range(4):
qc.measure(i, i)
# X1-X4 (qubits 13..16) -> classical bits 4..7
for idx, anc in enumerate(range(13, 17)):
qc.measure(anc, 4 + idx)
return qc
In [3]:
def run_simulation(error_qubit=None, error_type=None, shots=1000):
qc = build_surface_code_cycle(error_qubit, error_type)
simulator = AerSimulator()
transpiled_qc = transpile(qc, simulator)
job = simulator.run(transpiled_qc, shots=shots)
counts = job.result().get_counts()
# Qiskit orders bitstrings c7..c0; reverse to read c0..c7 (Z1 Z2 Z3 Z4 X1 X2 X3 X4)
formatted_counts = {k[::-1]: v for k, v in counts.items()}
print("--- Simulation Results ---")
if error_qubit is not None:
print(f"Injected Error: {error_type} on Qubit Index {error_qubit}")
else:
print("No error injected.")
print("Format: Z1 Z2 Z3 Z4 X1 X2 X3 X4\n")
for outcome, count in sorted(formatted_counts.items(), key=lambda item: item[1], reverse=True):
prob = count / shots
if prob > 0.01:
print(f" Syndrome: {outcome} | Probability: {prob:.3f}")
return formatted_counts
In [4]:
qc_no_error = build_surface_code_cycle()
print("Circuit depth:", qc_no_error.depth())
print("Number of qubits:", qc_no_error.num_qubits)
print(qc_no_error.draw(output='text', fold=60))
Circuit depth: 27
Number of qubits: 17
░ ┌───┐ »
q_0: ─────────────────────────────────────────░─┤ X ├─────»
░ └─┬─┘ »
q_1: ─────────────────────────────────────────░───┼───────»
░ │ ┌───┐»
q_2: ─────────────────────────────────────────░───┼──┤ X ├»
░ │ └─┬─┘»
q_3: ─────────────────────────────────────────░───┼────┼──»
┌───┐ ░ │ │ »
q_4: ─────┤ X ├───────────────────────────────░───■────┼──»
└─┬─┘┌───┐┌───┐ ░ │ »
q_5: ───────┼──┤ X ├┤ X ├─────────────────────░────────■──»
┌───┐ │ └─┬─┘└─┬─┘ ░ »
q_6: ┤ H ├──┼────┼────■───────────────────────░───────────»
├───┤ │ │ ░ »
q_7: ┤ H ├──■────■────■───────────────────────░───────────»
└───┘ ┌─┴─┐┌───┐ ░ »
q_8: ───────────────┤ X ├┤ X ├────────────────░───────────»
└───┘└─┬─┘┌───┐ ░ »
q_9: ──────────────────────┼──┤ X ├───────────░───────────»
┌───┐ │ └─┬─┘ ░ »
q_10: ┤ H ├─────────────────┼────┼─────────■───░───────────»
└───┘ │ │ ┌───┐┌─┴─┐ ░ »
q_11: ──────────────────────┼────┼──┤ X ├┤ X ├─░───────────»
┌───┐ │ │ └─┬─┘└───┘ ░ »
q_12: ┤ H ├─────────────────■────■────■────────░───────────»
└───┘ ░ »
q_13: ─────────────────────────────────────────░───────────»
░ »
q_14: ─────────────────────────────────────────░───────────»
░ »
q_15: ─────────────────────────────────────────░───────────»
░ »
q_16: ─────────────────────────────────────────░───────────»
░ »
c: 8/═════════════════════════════════════════════════════»
»
« ┌───┐ »
« q_0: ┤ X ├─────────────────────────────────────────────»
« └─┬─┘ ┌───┐┌───┐┌───┐ ┌───┐ »
« q_1: ──┼───────┤ X ├┤ X ├┤ X ├─────┤ X ├───────────────»
« │ ┌───┐└─┬─┘└─┬─┘└─┬─┘┌───┐└─┬─┘┌───┐ »
« q_2: ──┼──┤ X ├──┼────┼────┼──┤ X ├──┼──┤ X ├──────────»
« │ └─┬─┘ │ │ │ └─┬─┘ │ └─┬─┘┌───┐┌───┐»
« q_3: ──┼────┼────┼────┼────┼────┼────┼────┼──┤ X ├┤ X ├»
« │ │ │ │ │ │ │ │ └─┬─┘└─┬─┘»
« q_4: ──┼────┼────┼────┼────┼────┼────┼────┼────┼────┼──»
« │ │ │ │ │ │ │ │ │ │ »
« q_5: ──┼────┼────┼────┼────┼────┼────┼────┼────┼────┼──»
« │ │ │ │ │ │ │ │ │ │ »
« q_6: ──┼────■────┼────┼────┼────┼────┼────┼────┼────┼──»
« │ │ │ │ │ │ │ │ │ »
« q_7: ──■─────────■────┼────┼────┼────┼────┼────┼────┼──»
« │ │ │ │ │ │ │ »
« q_8: ─────────────────■────┼────■────┼────┼────┼────┼──»
« │ │ │ │ │ »
« q_9: ──────────────────────┼─────────┼────■────■────┼──»
« │ │ │ »
«q_10: ──────────────────────■─────────┼──────────────┼──»
« │ │ »
«q_11: ────────────────────────────────■──────────────┼──»
« │ »
«q_12: ───────────────────────────────────────────────■──»
« »
«q_13: ──────────────────────────────────────────────────»
« »
«q_14: ──────────────────────────────────────────────────»
« »
«q_15: ──────────────────────────────────────────────────»
« »
«q_16: ──────────────────────────────────────────────────»
« »
« c: 8/══════════════════════════════════════════════════»
« »
« ░ »
« q_0: ─░──────────────────────────────────────────────»
« ░ »
« q_1: ─░──────────────────────────────────────────────»
« ░ »
« q_2: ─░──────────────────────────────────────────────»
« ░ »
« q_3: ─░──────────────────────────────────────────────»
« ░ ┌───┐ »
« q_4: ─░───────────┤ X ├──────────────────────────────»
« ░ ┌───┐└─┬─┘ ┌───┐ »
« q_5: ─░──────┤ X ├──┼────────────┤ X ├───────────────»
« ░ └─┬─┘ │ ┌───┐└─┬─┘ »
« q_6: ─░────────┼────┼───────┤ X ├──┼─────────────────»
« ░ │ │ └─┬─┘ │ ┌───┐ »
« q_7: ─░────────┼────┼─────────┼────┼───────┤ X ├─────»
« ░ │ │ │ │ └─┬─┘┌───┐»
« q_8: ─░────────┼────┼─────────┼────┼─────────┼──┤ X ├»
« ░ │ │ │ │ │ └─┬─┘»
« q_9: ─░────────┼────┼─────────┼────┼─────────┼────┼──»
« ░ │ │ ┌───┐ │ │ │ │ »
«q_10: ─░────────┼────┼──┤ X ├──┼────┼─────────┼────┼──»
« ░ │ │ └─┬─┘ │ │ │ │ »
«q_11: ─░────────┼────┼────┼────┼────┼─────────┼────┼──»
« ░ │ │ │ │ │ │ │ »
«q_12: ─░────────┼────┼────┼────┼────┼─────────┼────┼──»
« ░ ┌───┐ │ │ │ │ │ ┌───┐ │ │ »
«q_13: ─░─┤ H ├──■────┼────┼────■────┼──┤ H ├──┼────┼──»
« ░ ├───┤ │ │ │ └───┘ │ │ »
«q_14: ─░─┤ H ├───────■────┼─────────■─────────■────■──»
« ░ ├───┤ │ »
«q_15: ─░─┤ H ├────────────┼───────────────────────────»
« ░ ├───┤ │ »
«q_16: ─░─┤ H ├────────────■───────────────────────────»
« ░ └───┘ »
« c: 8/════════════════════════════════════════════════»
« »
« ░ ┌─┐ »
« q_0: ────────────────────────────────────░─┤M├─────────»
« ░ └╥┘┌─┐ »
« q_1: ────────────────────────────────────░──╫─┤M├──────»
« ░ ║ └╥┘┌─┐ »
« q_2: ────────────────────────────────────░──╫──╫─┤M├───»
« ░ ║ ║ └╥┘┌─┐»
« q_3: ────────────────────────────────────░──╫──╫──╫─┤M├»
« ░ ║ ║ ║ └╥┘»
« q_4: ────────────────────────────────────░──╫──╫──╫──╫─»
« ░ ║ ║ ║ ║ »
« q_5: ────────────────────────────────────░──╫──╫──╫──╫─»
« ░ ║ ║ ║ ║ »
« q_6: ────────────────────────────────────░──╫──╫──╫──╫─»
« ░ ║ ║ ║ ║ »
« q_7: ────────────────────────────────────░──╫──╫──╫──╫─»
« ┌───┐ ░ ║ ║ ║ ║ »
« q_8: ─────┤ X ├──────────────────────────░──╫──╫──╫──╫─»
« └─┬─┘┌───┐ ░ ║ ║ ║ ║ »
« q_9: ───────┼──┤ X ├─────────────────────░──╫──╫──╫──╫─»
« │ └─┬─┘ ░ ║ ║ ║ ║ »
«q_10: ───────┼────┼───────────────────────░──╫──╫──╫──╫─»
« │ │ ┌───┐ ┌───┐ ░ ║ ║ ║ ║ »
«q_11: ───────┼────┼──┤ X ├─────┤ X ├──────░──╫──╫──╫──╫─»
« │ │ └─┬─┘┌───┐└─┬─┘ ░ ║ ║ ║ ║ »
«q_12: ───────┼────┼────┼──┤ X ├──┼────────░──╫──╫──╫──╫─»
« │ │ │ └─┬─┘ │ ░ ║ ║ ║ ║ »
«q_13: ───────┼────┼────┼────┼────┼────────░──╫──╫──╫──╫─»
« ┌───┐ │ │ │ │ │ ░ ║ ║ ║ ║ »
«q_14: ┤ H ├──┼────┼────┼────┼────┼────────░──╫──╫──╫──╫─»
« └───┘ │ │ │ │ │ ┌───┐ ░ ║ ║ ║ ║ »
«q_15: ───────■────■────■────■────┼──┤ H ├─░──╫──╫──╫──╫─»
« │ ├───┤ ░ ║ ║ ║ ║ »
«q_16: ───────────────────────────■──┤ H ├─░──╫──╫──╫──╫─»
« └───┘ ░ ║ ║ ║ ║ »
« c: 8/═══════════════════════════════════════╩══╩══╩══╩═»
« 0 1 2 3 »
«
« q_0: ────────────
«
« q_1: ────────────
«
« q_2: ────────────
«
« q_3: ────────────
«
« q_4: ────────────
«
« q_5: ────────────
«
« q_6: ────────────
«
« q_7: ────────────
«
« q_8: ────────────
«
« q_9: ────────────
«
«q_10: ────────────
«
«q_11: ────────────
«
«q_12: ────────────
« ┌─┐
«q_13: ┤M├─────────
« └╥┘┌─┐
«q_14: ─╫─┤M├──────
« ║ └╥┘┌─┐
«q_15: ─╫──╫─┤M├───
« ║ ║ └╥┘┌─┐
«q_16: ─╫──╫──╫─┤M├
« ║ ║ ║ └╥┘
« c: 8/═╩══╩══╩══╩═
« 4 5 6 7
In [5]:
counts_no_error = run_simulation()
--- Simulation Results --- No error injected. Format: Z1 Z2 Z3 Z4 X1 X2 X3 X4 Syndrome: 00000000 | Probability: 1.000
In [6]:
counts_x_error = run_simulation(error_qubit=8, error_type='X')
--- Simulation Results --- Injected Error: X on Qubit Index 8 Format: Z1 Z2 Z3 Z4 X1 X2 X3 X4 Syndrome: 01100000 | Probability: 1.000
In [7]:
counts_z_error = run_simulation(error_qubit=8, error_type='Z')
--- Simulation Results --- Injected Error: Z on Qubit Index 8 Format: Z1 Z2 Z3 Z4 X1 X2 X3 X4 Syndrome: 00000110 | Probability: 1.000