Repetitioonskoden
Verbruuksschätzing: weniger as 1 Minuut op en Heron-Prozessor (ANMERKUNG: Dat is blooß en Schätzing. Jo Loptied kann verscheden ween.)
Achtergrund
För echttiedige Quantenfehlerkorektur (QEC) bruukt man de Möglichkeit, den Programmfluss dynamisch to stüern, dormit Quantengaten op Messresultaten betingt ween köönt. Dit Tutorial föhrt den Bit-Flip-Code ut, wat en sehr eenfache Form vun QEC is. Dat wiist en dynamischen Quantenschaltkreis, de en kodeerten Qubit vör en enkeld Bit-Flip-Fehler schützen kann, un dorna warrt de Leisten vun den Bit-Flip-Code utwertet.
Man kann extra Ancilla-Qubits un Verschränkung bruken, üm Stabilisators to meten, de de kodeerden Quanteninformatschoon nich verännert, aver trotzdem Bescheed geven över bestimmte Fehlerklassen, de optreden köönt. En Quantenstabilisatorcode kodeert logische Qubits in physikalische Qubits. Stabilisatorkoden konzentreert sik vör allem op de Korektur vun en diskret Fehlermenge, de vun de Pauli-Gruppe ünnerstütt warrt.
Mehr Informatschoon över QEC findt ji bi Quantum Error Correction for Beginners.
Vöruttseringen
Vör de Start vun dit Tutorial stellt seker, dat ji dat Folgendet installeert hebbt:
- Qiskit SDK v2.0 oder later, mit Visualiseering-Ünnerstüttung
- Qiskit Runtime v0.40 oder later (
pip install qiskit-ibm-runtime)
Inrichtung
# 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()
Stapp 1. Klassische Ingaven op en Quantenproblem ümtekenen
Einen Bit-Flip-Stabilisatorschaltkreis bouen
Den Bit-Flip-Code is een vun de eenfachsten Bispele vun en Stabilisatorcode. He schützt den Tostand vör en enkeld Bit-Flip-(X-)Fehler op een vun de Koderungsqubits. Betrachtet man de Wirkung vun den Bit-Flip-Fehler , de un op een vun ünsen Qubits afbillt, denn kriegen wi . De Code bruukt fief Qubits: dree warrt bruukt, üm den schützten Tostand to koderen, un de beiden annern warrt as Stabilisatormessungs-Ancillas innsett.
# 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)
Stapp 2. Dat Problem för de Quantenutföhrung optimeren
Üm de Gesamttied vun de Jobutföhrung to verkürten, neemt Qiskit-Primitiven bloots Schaltkreise un Observables an, de to de Befehlen un de Konnektivität vun dat Zielsystem passt (bekannt as ISA-Schaltkreise un -Observables — ISA steiht för Instruction Set Architecture). Mehr över Transpilation lehren.
ISA-Schaltkreise genereren
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)
Stapp 3. Mit Qiskit-Primitiven utföhren
Föhrt de Verschoon mit Korektur un en Verschoon ahn Korektur ut.
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}
Stapp 4. Naoberbeitung: Resultat in klassisches Format ümsetten
Man kann sehn, dat de Bit-Flip-Code veel Fehler opdeckt un korrigert hett, sodass insgesamt weniger Fehlers överblievt.
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-Ümmfrog
Nimmt an disse körte Ümmfrog deel, üm Feedback to dit Tutorial to geven. Jo Anmerkungen helpt uns, ünsen Inholt un de Brukerorfahrung to verbettern.