Zum Hauptinhalt springe

Wiederholungscodes

Nutzungsschätzung: weniger als 1 Minute uf eim Heron-Prozessor (HINWEIS: Des isch bloß e Schätzung. Dini Laufzeit ka variiere.)

Hintergrund

Um Echtzeit-Quantenfehlerkorrektur (QEC) z'ermögliche, müsse mir in dr Lage sei, den Quantenprogrammfluss während dr Ausführung dynamisch z'steuere, sodass Quantengates von Messergebnisse abhängig gmacht werde könne. Des Tutorial führt den Bit-Flip-Code us, der e sehr eifachi Form von QEC isch. Es zeigt e dynamische Quantenschaltkreis, der e kodiertes Qubit vor eim einzelne Bit-Flip-Fehler schütze ka, un bewertet dann d'Leistung vom Bit-Flip-Code.

Mir könne zusätzliche Hilfs-Qubits un Verschränkung nutze, um Stabilisatoren z'messe, die kodierte Quanteninformation nit transformiere, während se uns dennoch über etliche Fehlerklasse informiere, die vielleicht aufgträtte sin. E Quanten-Stabilisator-Code kodiert kk logische Qubits in nn physische Qubits. Stabilisator-Codes konzentriere sich vor allem uf d'Korrektur von eim diskreten Fehlersatz mit Unterstützung us dr Pauli-Gruppe Πn\Pi^n.

Für weitere Informatione über QEC lueg bi Quantum Error Correction for Beginners nei.

Anforderungen

Stell sicher, bevor's losgeht, dass des Folgende installiert isch:

  • 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 Eingabe uf e Quanteproblem abbilden

En Bit-Flip-Stabilisator-Schaltkreis erstelle

D'r Bit-Flip-Code isch ois von de eifachste Beispiele von eim Stabilisator-Code. Er schützt den Zustand vor eim einzelne Bit-Flip (X)-Fehler uf eim von de Kodierungs-Qubits. Betrachte mir d'Wirkung vom Bit-Flip-Fehler XX, der 01|0\rangle \rightarrow |1\rangle un 10|1\rangle \rightarrow |0\rangle uf eim von unsere Qubits abbildet, dann hän mir ϵ={E0,E1,E2}={IIX,IXI,XII}\epsilon = \{E_0, E_1, E_2 \} = \{IIX, IXI, XII\}. D'r Code bruucht fünf Qubits: Drei werde verwendet, um den geschützten Zustand z'kodiere, un d'verbleibende zwei werde 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)

Output of the previous code cell

Output of the previous code cell

Schritt 2. Problem für d'Quanteausführung optimiere

Um d'Gesamtausführungszeit vom Job z'reduziere, akzeptiere Qiskit-Primitive bloß Schaltkreise un Observablen, die de vom Zielsystem unterstützte Anweisunge un d'Konnektivität entspreche (bezeichnet als Instruction Set Architecture (ISA)-Schaltkreise un -Observablen). Erfahre meh über Transpilation.

ISA-Schaltkreise 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. Usführe mit Qiskit-Primitive

Führe d'Version mit angewendeter Korrektur un eine ohne 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. Nachbearbeitung, Rückgabe vom Ergebnis im klassische Format

Mir könne sehe, dass d'r Bit-Flip-Code vieli Fehler erkannt un korrigiert hat, was zu insgesamt weniger Fehler 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 mach bi dere kurze Umfrage mit, um Feedback z'dem Tutorial z'gehe. Dini Erkenntnisse helfe uns, unseri Inhaltsangebote un d'Benutzererfahrung z'verbessere.

Link zur Umfrage