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