Zum Hauptinhalt springen

Repetition Codes

Schätzung für'n Ressourcenaufwand: wenija als 'ne Minute uff'm Heron-Prozessa (ACHTUNG: Det is nur 'ne Schätzung. Deine tatsächliche Laufzeit kann abweicha.)

Hintergrund

Um echtzeitliche Quantenfehlerkorrektion (QEC) hinzukriegn, musste den Programmfluss während da Ausführung dynamisch steuern können, damit Quantengates von Messergebnissen abhängig jemacht wern können. Dit Tutorial führt den Bit-Flip-Code aus — 'ne sehr einfache Form von QEC. Et demonstriert 'nen dynamischn Quantenschaltkreis, der'n kodierten Qubit vor 'nem einzelnen Bit-Flip-Fehla schützn kann, un bewertet dann die Leistung vom Bit-Flip-Code.

Du kannst zusätzliche Ancilla-Qubits un Verschränkung nutzn, um Stabilisatorn zu messn, die die kodierte Quanteninformation nicht verändern, die dir aba trotzdem über bestimmte Fehlerklaasn Auskunft jebn, die eventuell aufjetreten sind. 'n Quanten-Stabilisator-Code kodiert kk logische Qubits in nn physikalische Qubits. Stabilisator-Codes konzentriern sich entscheidend uff dit Korrektion von 'nem diskreten Fehlerset, unterstützt von da Pauli-Gruppe Πn\Pi^n.

Mehr Infos zu QEC findste bei Quantum Error Correction for Beginners.

Voraussetzungen

Bevor de mit dittm Tutorial anfängst, stell sicher, datte folgendes installiert hast:

  • Qiskit SDK v2.0 oda neeja, mit Unterstützung für Visualisierung
  • Qiskit Runtime v0.40 oda neeja (pip install qiskit-ibm-runtime)

Einrichtung

# 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 uff'n Quantenproblem abbildn

Bit-Flip-Stabilisator-Schaltkreis bauhn

Da Bit-Flip-Code jehört zu den einfachsten Beispieln für 'nen Stabilisator-Code. Er schützt den Zustand vor 'nem einzelnen Bit-Flip-(X-)Fehla uff einem da Kodierungs-Qubits. Wenn ma den Bit-Flip-Fehler XX betrachtet — der 01|0\rangle \rightarrow |1\rangle un 10|1\rangle \rightarrow |0\rangle mappt — dann jibt et für jeden unsern Qubits: ϵ={E0,E1,E2}={IIX,IXI,XII}\epsilon = \{E_0, E_1, E_2 \} = \{IIX, IXI, XII\}. Da Code braucht fünf Qubits: drei zum Kodieren vom jeschützten Zustand, un die restlichn zwei als Stabilisatormess-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. Det Problem für die Quantenausführung optimiern

Um die Jesamtausführungszeit vom Job zu vakürzen, akzeptiern Qiskit-Primitives nur Schaltkreise un Observablen, die zu den Anweisungen un da Konnektivität vom Zielsystem passn (bezeichnet als ISA-Schaltkreise un -Observablen). Mehr über Transpilation erfahn.

ISA-Schaltkreise erzeugen

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 ausführn

Führ die Version mit Korrektion un eine ohne Korrektion 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 — Ergebnis im klassischn Format zurückjebn

Du kannst sehn, dass da Bit-Flip-Code viele Fehla erkannt un korrigiert hat, wodurch insjesamt wenija Fehla übrig bleibn.

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.

Umfrage zum Tutorial

Mach bitte diese kurze Umfrage un jib uns Rückmeldung zu dittm Tutorial. Deine Anmerkungen helfn uns, unsre Inhalte un Benutzererfahrung zu vabessern.

Link zur Umfrage