Saltar al contenido principal

Códigos de repetición

Estimación de uso: menos de 1 minuto en un procesador Heron (NOTA: Esta es solo una estimación. Su tiempo de ejecución puede variar.)

Antecedentes

Para habilitar la corrección de errores cuánticos (QEC) en tiempo real, necesitas poder controlar dinámicamente el flujo del programa cuántico durante la ejecución para que los gates cuánticos puedan estar condicionados a los resultados de medición. Este tutorial ejecuta el código de bit-flip, que es una forma muy simple de QEC. Demuestra un circuito cuántico dinámico que puede proteger un qubit codificado de un solo error de bit-flip, y luego evalúa el rendimiento del código de bit-flip.

Puedes explotar qubits ancilla adicionales y entrelazamiento para medir estabilizadores que no transforman información cuántica codificada, mientras aún te informan sobre algunas clases de errores que podrían haber ocurrido. Un código estabilizador cuántico codifica kk qubits lógicos en nn qubits físicos. Los códigos estabilizadores se enfocan críticamente en corregir un conjunto discreto de errores con soporte del grupo de Pauli Πn\Pi^n.

Para más información sobre QEC, consulta Quantum Error Correction for Beginners.

Requisitos

Antes de comenzar este tutorial, asegúrate de tener instalado lo siguiente:

  • Qiskit SDK v2.0 o posterior, con soporte de visualización
  • Qiskit Runtime v0.40 o posterior (pip install qiskit-ibm-runtime)

Configuración

# 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()

Paso 1. Mapear entradas clásicas a un problema cuántico

Construir un circuito estabilizador de bit-flip

El código de bit-flip está entre los ejemplos más simples de un código estabilizador. Protege el estado contra un solo error de bit-flip (X) en cualquiera de los qubits de codificación. Considera la acción del error de bit-flip XX, que mapea 01|0\rangle \rightarrow |1\rangle y 10|1\rangle \rightarrow |0\rangle en cualquiera de nuestros qubits, entonces tenemos ϵ={E0,E1,E2}={IIX,IXI,XII}\epsilon = \{E_0, E_1, E_2 \} = \{IIX, IXI, XII\}. El código requiere cinco qubits: tres se usan para codificar el estado protegido, y los dos restantes se usan como ancillas de medición de estabilizador.

# 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

Paso 2. Optimizar el problema para la ejecución cuántica

Para reducir el tiempo total de ejecución del trabajo, las primitivas de Qiskit solo aceptan circuitos y observables que se ajustan a las instrucciones y conectividad compatibles con el sistema objetivo (denominados circuitos y observables de arquitectura de conjunto de instrucciones (ISA)). Aprenda más sobre transpilación.

Generar circuitos 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)

Paso 3. Ejecutar usando primitivas de Qiskit

Ejecuta la versión con corrección aplicada y una sin corrección.

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}

Paso 4. Post-procesar, devolver resultado en formato clásico

Puedes ver que el código de bit-flip detectó y corrigió muchos errores, resultando en menos errores en general.

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.

Encuesta del tutorial

Por favor, responda esta breve encuesta para proporcionar comentarios sobre este tutorial. Sus opiniones nos ayudarán a mejorar nuestras ofertas de contenido y experiencia de usuario.

Enlaza a la encuesta