Przejdź do głównej treści

Kody repetycyjne

Szacowane zużycie zasobów: mniej niż 1 minuta na procesorze Heron (UWAGA: to jedynie szacunek. Rzeczywisty czas wykonania może się różnić.)

Tło

Aby umożliwić kwantową korekcję błędów (QEC) w czasie rzeczywistym, musisz być w stanie dynamicznie sterować przepływem programu kwantowego podczas wykonywania, tak aby bramki kwantowe mogły być warunkowane na wynikach pomiarów. Ten samouczek uruchamia kod odwrócenia bitu, który jest bardzo prostą formą QEC. Demonstruje dynamiczny obwód kwantowy, który może chronić zakodowany Qubit przed pojedynczym błędem odwrócenia bitu, a następnie ocenia wydajność kodu odwrócenia bitu.

Możesz wykorzystać dodatkowe kubity pomocnicze i splątanie do pomiaru stabilizatorów, które nie transformują zakodowanej informacji kwantowej, jednocześnie informując cię o pewnych klasach błędów, które mogły wystąpić. Kwantowy kod stabilizatora koduje kk logicznych kubitów w nn fizycznych kubitach. Kody stabilizatora skupiają się przede wszystkim na korygowaniu dyskretnego zbioru błędów z wsparciem grupy Pauliego Πn\Pi^n.

Więcej informacji o QEC znajdziesz w Quantum Error Correction for Beginners.

Wymagania

Przed rozpoczęciem tego samouczka upewnij się, że masz zainstalowane:

  • Qiskit SDK v2.0 lub nowszy, z obsługą wizualizacji
  • Qiskit Runtime v0.40 lub nowszy (pip install qiskit-ibm-runtime)

Konfiguracja

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
# 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()

Krok 1. Mapowanie klasycznych danych wejściowych na problem kwantowy

Budowanie obwodu stabilizatora odwrócenia bitu

Kod odwrócenia bitu jest jednym z najprostszych przykładów kodu stabilizatora. Chroni stan przed pojedynczym błędem odwrócenia bitu (X) na dowolnym z kubitów kodujących. Rozważ działanie błędu odwrócenia bitu XX, który odwzorowuje 01|0\rangle \rightarrow |1\rangle oraz 10|1\rangle \rightarrow |0\rangle na dowolnym z naszych kubitów; wtedy mamy ϵ={E0,E1,E2}={IIX,IXI,XII}\epsilon = \{E_0, E_1, E_2 \} = \{IIX, IXI, XII\}. Kod wymaga pięciu kubitów: trzy są używane do kodowania chronionego stanu, a pozostałe dwa służą jako kubity pomocnicze do pomiaru stabilizatora.

# 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

Krok 2. Optymalizacja problemu pod kątem wykonania kwantowego

Aby skrócić całkowity czas wykonania zadania, prymitywy Qiskit akceptują tylko obwody i obserwable zgodne z instrukcjami i połączeniami obsługiwanymi przez system docelowy (zwane obwodami i obserwablami ISA). Dowiedz się więcej o transpilacji.

Generowanie obwodów ISA

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)

Krok 3. Wykonanie przy użyciu prymitywów Qiskit

Uruchom wersję z zastosowaną korekcją oraz wersję bez korekcji.

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}

Krok 4. Post-processing, zwrot wyniku w formacie klasycznym

Widać, że kod odwrócenia bitu wykrył i skorygował wiele błędów, co skutkuje mniejszą liczbą błędów ogółem.

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.

Ankieta dotycząca samouczka

Wypełnij tę krótką ankietę, aby przekazać opinię na temat tego samouczka. Twoje spostrzeżenia pomogą nam ulepszyć ofertę treści i doświadczenie użytkownika.

Link do ankiety

Note: This survey is provided by IBM Quantum and relates to the original English content. To give feedback on doQumentation's website, translations, or code execution, please open a GitHub issue.