Zum Hauptinhalt springe

Repetitionscodes

Verbrauchsschätzig: weniger als 1 Minüüte uf emene Heron-Prozässor (HINWIS: Das isch nur en Schätzwärt. Dini tatsächlichi Laufzyt cha variiire.)

Hintergrundinformation

Zum Ermögliche vo Echtzeit-Quantefehlerkorrektur (QEC) bruuchsch di Möglichkeit, de Programmfluss vom Quanteprogramm während de Usfüehrig dynamisch z'stüüre, sodass Quantegatters vo Mässresultate abhängig gmacht wärde chönd. Das Tutorial füehrt de Bit-Flip-Code us, was en sehr eifachi Form vo QEC isch. Es demonstriert en dynamische Quanteschaltkreis, wo en kodierts Qubit vor emene einzelne Bit-Flip-Fehler schütze cha, und bewertet dänn d'Leistig vom Bit-Flip-Code.

Du chasch zusätzlichi Ancilla-Qubits und Verschränkig nutze, um Stabilisatore z'mässe, wo d'kodierti Quanteinformation nöd transformiered, dir aber trotzdem Uschluus über gewissi Fehlerklasse gänd, wo eventuell passiert si. En Quante-Stabilisatorcode kodiert kk logischi Qubits in nn physikalischi Qubits. Stabilisatorcodes konzentriered sich vor allem druf, es diskrets Fehlerset mit Understützig vo de Pauli-Gruppe Πn\Pi^n z'korrigiere.

Mer Informazione über QEC findsch in Quantum Error Correction for Beginners.

Vorrussetzige

Bevor du mit däm Tutorial afangsch, sorg derfür, dass du Folgends installiert hesch:

  • Qiskit SDK v2.0 oder neuer, mit Visualisierigs-Understützig
  • Qiskit Runtime v0.40 oder neuer (pip install qiskit-ibm-runtime)

Setup

# Qiskit imports
from qiskit import (
QuantumCircuit,
QuantumRegister,
ClassicalRegister,
)

# Qiskit Runtime
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler

from qiskit_ibm_runtime.circuit import MidCircuitMeasure

service = QiskitRuntimeService()

Schritt 1. Klassischi Yyabe uf es Quanteproblem abbilden

En Bit-Flip-Stabilisator-Schaltkreis baue

De Bit-Flip-Code ghört zu de einfachschte Bischpiel vom Stabilisatorcode. Er schützt de Zuestand vor emene einzelne Bit-Flip-(X-)Fehler uf jedem vo de kodierungsbeteiligte Qubits. Betrachte mir d'Wirkig vom Bit-Flip-Fehler XX, wo 01|0\rangle \rightarrow |1\rangle und 10|1\rangle \rightarrow |0\rangle uf jedem unsere Qubits mappt, denn händ mir ϵ={E0,E1,E2}={IIX,IXI,XII}\epsilon = \{E_0, E_1, E_2 \} = \{IIX, IXI, XII\}. De Code bruucht fünf Qubits: drüü wärded zum Kodiere vom gschützte Zuestand verwendet, und d'übrige zwei dienend als Stabilisatormässigs-Ancillas.

# Choose the least busy backend that supports `measure_2`.

backend = service.least_busy(
filters=lambda b: "measure_2" in b.supported_instructions,
operational=True,
simulator=False,
dynamic_circuits=True,
)
qreg_data = QuantumRegister(3)
qreg_measure = QuantumRegister(2)
creg_data = ClassicalRegister(3, name="data")
creg_syndrome = ClassicalRegister(2, name="syndrome")
state_data = qreg_data[0]
ancillas_data = qreg_data[1:]

def build_qc():
"""Build a typical error correction circuit"""
return QuantumCircuit(qreg_data, qreg_measure, creg_data, creg_syndrome)

def initialize_qubits(circuit: QuantumCircuit):
"""Initialize qubit to |1>"""
circuit.x(qreg_data[0])
circuit.barrier(qreg_data)
return circuit

def encode_bit_flip(circuit, state, ancillas) -> QuantumCircuit:
"""Encode bit-flip. This is done by simply adding a cx"""
for ancilla in ancillas:
circuit.cx(state, ancilla)
circuit.barrier(state, *ancillas)
return circuit

def measure_syndrome_bit(circuit, qreg_data, qreg_measure, creg_measure):
"""
Measure the syndrome by measuring the parity.
We reset our ancilla qubits after measuring the stabilizer
so we can reuse them for repeated stabilizer measurements.
Because we have already observed the state of the qubit,
we can write the conditional reset protocol directly to
avoid another round of qubit measurement if we used
the `reset` instruction.
"""
circuit.cx(qreg_data[0], qreg_measure[0])
circuit.cx(qreg_data[1], qreg_measure[0])
circuit.cx(qreg_data[0], qreg_measure[1])
circuit.cx(qreg_data[2], qreg_measure[1])
circuit.barrier(*qreg_data, *qreg_measure)
circuit.append(MidCircuitMeasure(), [qreg_measure[0]], [creg_measure[0]])
circuit.append(MidCircuitMeasure(), [qreg_measure[1]], [creg_measure[1]])

with circuit.if_test((creg_measure[0], 1)):
circuit.x(qreg_measure[0])
with circuit.if_test((creg_measure[1], 1)):
circuit.x(qreg_measure[1])
circuit.barrier(*qreg_data, *qreg_measure)
return circuit

def apply_correction_bit(circuit, qreg_data, creg_syndrome):
"""We can detect where an error occurred and correct our state"""
with circuit.if_test((creg_syndrome, 3)):
circuit.x(qreg_data[0])
with circuit.if_test((creg_syndrome, 1)):
circuit.x(qreg_data[1])
with circuit.if_test((creg_syndrome, 2)):
circuit.x(qreg_data[2])
circuit.barrier(qreg_data)
return circuit

def apply_final_readout(circuit, qreg_data, creg_data):
"""Read out the final measurements"""
circuit.barrier(qreg_data)
circuit.measure(qreg_data, creg_data)
return circuit
def build_error_correction_sequence(apply_correction: bool) -> QuantumCircuit:
circuit = build_qc()
circuit = initialize_qubits(circuit)
circuit = encode_bit_flip(circuit, state_data, ancillas_data)
circuit = measure_syndrome_bit(
circuit, qreg_data, qreg_measure, creg_syndrome
)

if apply_correction:
circuit = apply_correction_bit(circuit, qreg_data, creg_syndrome)

circuit = apply_final_readout(circuit, qreg_data, creg_data)
return circuit

circuit = build_error_correction_sequence(apply_correction=True)
circuit.draw(output="mpl", style="iqp", cregbundle=False)

Output of the previous code cell

Output of the previous code cell

Schritt 2. Das Problem für d'Quanteusfüehrig optimiere

Zum Verringere vo de totale Job-Usfüehrizyt akzeptiert Qiskit-Primitives nur Schaltkreis und Observablen, wo de Instrukzione und de Verbindigkeitsstruktur vom Zielsystem entspräche (als ISA-Schaltkreis und -Observablen bezeichnet). Mer über Transpilation erfahre.

ISA-Schaltkreis generiere

from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(circuit)

isa_circuit.draw("mpl", style="iqp", idle_wires=False)

Output of the previous code cell

Output of the previous code cell

no_correction_circuit = build_error_correction_sequence(
apply_correction=False
)

isa_no_correction_circuit = pm.run(no_correction_circuit)

Schritt 3. Mit Qiskit-Primitives usfüehre

Füehr d'Version mit Korrektur und d'Version ohni Korrektur us.

sampler_no_correction = Sampler(backend)
job_no_correction = sampler_no_correction.run(
[isa_no_correction_circuit], shots=1000
)
result_no_correction = job_no_correction.result()[0]
sampler_with_correction = Sampler(backend)

job_with_correction = sampler_with_correction.run([isa_circuit], shots=1000)
result_with_correction = job_with_correction.result()[0]
print(f"Data (no correction):\n{result_no_correction.data.data.get_counts()}")
print(
f"Syndrome (no correction):\n{result_no_correction.data.syndrome.get_counts()}"
)
Data (no correction):
{'111': 878, '011': 42, '110': 35, '101': 40, '100': 1, '001': 2, '000': 2}
Syndrome (no correction):
{'00': 942, '10': 33, '01': 22, '11': 3}
print(f"Data (corrected):\n{result_with_correction.data.data.get_counts()}")
print(
f"Syndrome (corrected):\n{result_with_correction.data.syndrome.get_counts()}"
)
Data (corrected):
{'111': 889, '110': 25, '000': 11, '011': 45, '101': 17, '010': 10, '001': 2, '100': 1}
Syndrome (corrected):
{'00': 929, '01': 39, '10': 20, '11': 12}

Schritt 4. Nachbearbeitig und Rückgabe vom Resultat im klassische Format

Me gsiet, dass de Bit-Flip-Code vieli Fehler erkannt und korrigiert het, was insgesamt zu weniger Fehler füehrt.

def decode_result(data_counts, syndrome_counts):
shots = sum(data_counts.values())
success_trials = data_counts.get("000", 0) + data_counts.get("111", 0)
failed_trials = shots - success_trials
error_correction_events = shots - syndrome_counts.get("00", 0)
print(
f"Bit flip errors were detected/corrected on {error_correction_events}/{shots} trials."
)
print(
f"A final parity error was detected on {failed_trials}/{shots} trials."
)
# non-corrected marginalized results
data_result = result_no_correction.data.data.get_counts()
marginalized_syndrome_result = result_no_correction.data.syndrome.get_counts()

print(
f"Completed bit code experiment data measurement counts (no correction): {data_result}"
)
print(
f"Completed bit code experiment syndrome measurement counts (no correction): {marginalized_syndrome_result}"
)
decode_result(data_result, marginalized_syndrome_result)
Completed bit code experiment data measurement counts (no correction): {'111': 878, '011': 42, '110': 35, '101': 40, '100': 1, '001': 2, '000': 2}
Completed bit code experiment syndrome measurement counts (no correction): {'00': 942, '10': 33, '01': 22, '11': 3}
Bit flip errors were detected/corrected on 58/1000 trials.
A final parity error was detected on 120/1000 trials.
# corrected marginalized results
corrected_data_result = result_with_correction.data.data.get_counts()
corrected_syndrome_result = result_with_correction.data.syndrome.get_counts()

print(
f"Completed bit code experiment data measurement counts (corrected): {corrected_data_result}"
)
print(
f"Completed bit code experiment syndrome measurement counts (corrected): {corrected_syndrome_result}"
)
decode_result(corrected_data_result, corrected_syndrome_result)
Completed bit code experiment data measurement counts (corrected): {'111': 889, '110': 25, '000': 11, '011': 45, '101': 17, '010': 10, '001': 2, '100': 1}
Completed bit code experiment syndrome measurement counts (corrected): {'00': 929, '01': 39, '10': 20, '11': 12}
Bit flip errors were detected/corrected on 71/1000 trials.
A final parity error was detected on 100/1000 trials.

Tutorial-Umfrag

Bitte nimm an däre churze Umfrag teil und gib uns Feedback zu däm Tutorial. Dini Rückmäldigige helfed ois, üseri Inhält und d'Benutzererfahrig z'verbessere.

Link zur Umfrag