Wiederholungscodes
Nutzungsschätzung: weniger als 1 Minute auf an Heron-Prozessor (HINWEIS: Des is nur a Schätzung. Ihre Laufzeit kann variieren.)
Hintergrund
Um Echtzeit-Quantenfehlerkorrektur (QEC) z'ermöglichen, müssen mia in da Lage sei, den Quantenprogrammfluss während da Ausführung dynamisch z'steuern, sodass Quantengates von Messergebnissen abhängig gmacht wern können. Des Tutorial führt den Bit-Flip-Code aus, der a sehr einfache Form von QEC is. Es zeigt an dynamischen Quantenschaltkreis, der a kodiertes Qubit vor eim einzelnen Bit-Flip-Fehler schützen kann, und bewertet dann de Leistung vom Bit-Flip-Code.
Mia können zusätzliche Hilfs-Qubits und Verschränkung nutzen, um Stabilisatoren zu messen, de de kodierte Quanteninformation ned transformiern, während's uns dennoch über etliche Fehlerklassen informiern, de vielleicht aufgtreten san. A Quanten-Stabilisator-Code kodiert logische Qubits in physische Qubits. Stabilisator-Codes konzentriern sich hauptsächlich auf de Korrektur von eim diskreten Fehlersatz mit Unterstützung aus da Pauli-Gruppe .
Für weitere Informationen über QEC schaugts bei Quantum Error Correction for Beginners nei.
Anforderungen
Stellt's sicher, bevor mia mit dem Tutorial anfangen, dass folgendes installiert is:
- Qiskit SDK v2.0 oder neuer, mit visualization-Unterstützung
- 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. Klassische Eingaben auf a Quantenproblem abbilden
An Bit-Flip-Stabilisator-Schaltkreis erstellen
Da Bit-Flip-Code is oas von de einfachsten Beispui von am Stabilisator-Code. Er schützt den Zustand vor eim einzelnen Bit-Flip (X)-Fehler auf oam von de Kodierungs-Qubits. Schaugt mia uns de Wirkung vom Bit-Flip-Fehler an, der und auf oam von unserne Qubits abbildet, dann ham mia . Da Code braucht fünf Qubits: Drei wern verwendet, um den gschützten Zustand z'kodieren, und de verbleibenden zwoa wern als Stabilisatormessungs-Ancillas verwendet.
# 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)
Schritt 2. Problem für de Quantenausführung optimieren
Um de Gesamtausführungszeit vom Job z'reduzieren, akzeptiern Qiskit-Primitive nur Schaltkreise und Observablen, de de vom Zielsystem unterstützten Anweisungen und de Konnektivität entsprechn (bezeichnet als Instruction Set Architecture (ISA)-Schaltkreise und -Observablen). Erfahrt's mehr über Transpilation.
ISA-Schaltkreise generieren
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)


no_correction_circuit = build_error_correction_sequence(
apply_correction=False
)
isa_no_correction_circuit = pm.run(no_correction_circuit)
Schritt 3. Ausführen mit Qiskit-Primitiven
Führt's de Version mit angewendeter Korrektur und oane ohne Korrektur aus.
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. Nachbearbeitung, Rückgabe vom Ergebnis im klassischen Format
Mia können sehn, dass da Bit-Flip-Code viele Fehler erkannt und korrigiert hat, was insgesamt zu weniger Fehlern gführt hat.
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-Umfrage
Bitte macht's bei derer kurzen Umfrage mit, um Feedback zu dem Tutorial z'geben. Eure Erkenntnisse helfn uns, unsere Inhaltsangebote und de Benutzererfahrung z'verbessern.