Códigos de repetição
Estimativa de uso: menos de 1 minuto em um processador Heron (OBSERVAÇÃO: essa é apenas uma estimativa. Seu tempo de execução pode variar)
Segundo plano
Para permitir a correção de erros quânticos (QEC) em tempo real, você precisa ser capaz de controlar dinamicamente o fluxo do programa quântico durante a execução, de modo que as portas quânticas possam ser condicionadas aos resultados da medição. Este tutorial executa o código bit-flip, que é uma forma muito simples de QEC. Ele demonstra um circuito quântico dinâmico que pode proteger um qubit codificado de um único erro de inversão de bit e, em seguida, avalia o desempenho do código de inversão de bit.
Você pode explorar qubits ancilla adicionais e emaranhamento para medir estabilizadores que não transformam as informações quânticas codificadas e, ao mesmo tempo, informá-lo sobre algumas classes de erros que podem ter ocorrido. Um código estabilizador quântico codifica qubits lógicos em qubits físicos. Os códigos estabilizadores se concentram criticamente na correção de um conjunto de erros discretos com o apoio do grupo Pauli .
Para obter mais informações sobre a QEC, consulte “Correção de erros quânticos para iniciantes”.
Requisitos
Antes de iniciar este tutorial, verifique se você tem os seguintes itens instalados:
- Qiskit SDK v2.0 ou posterior, com suporte para visualização
- Qiskit Runtime v0.40 ou posterior (
pip install qiskit-ibm-runtime)
Instalação
# 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()Etapa 1. Mapeie entradas clássicas para um problema quântico
Construa um circuito estabilizador de inversão de bits
O código bit-flip está entre os exemplos mais simples de um código estabilizador. Ele protege o estado contra um único erro de inversão de bit (X) em qualquer um dos qubits de codificação. Considere a ação do erro de inversão de bit , que mapeia e em qualquer um de nossos qubits, então temos . O código requer cinco qubits: três são usados para codificar o estado protegido e os dois restantes são usados como auxiliares de medição do 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 circuitdef 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:
Etapa 2. Otimize o problema para execução quântica
Para reduzir o tempo total de execução da tarefa, o Qiskit primitives aceita apenas circuitos e observáveis que estejam em conformidade com as instruções e a conectividade suportadas pelo sistema de destino (conhecidos como circuitos e observáveis da arquitetura de conjunto de instruções (ISA)). Saiba mais sobre transpilação.
Gerar 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:
no_correction_circuit = build_error_correction_sequence(
apply_correction=False
)
isa_no_correction_circuit = pm.run(no_correction_circuit)Etapa 3. Execute usando Qiskit primitives
Execute a versão com correção aplicada e uma sem correção.
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()}"
)Output:
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()}"
)Output:
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}
Etapa 4. Pós-processamento, retornar resultado no formato clássico
Você pode ver que o código de inversão de bits detectou e corrigiu muitos erros, resultando em menos erros em geral.
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 "
f"{error_correction_events}/{shots} trials."
)
print(
f"A final parity error was detected on "
f"{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): "
f"{data_result}"
)
print(
f"Completed bit code experiment syndrome measurement counts (no correction): "
f"{marginalized_syndrome_result}"
)
decode_result(data_result, marginalized_syndrome_result)Output:
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): "
f"{corrected_data_result}"
)
print(
f"Completed bit code experiment syndrome measurement counts (corrected): "
f"{corrected_syndrome_result}"
)
decode_result(corrected_data_result, corrected_syndrome_result)Output:
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.
Pesquisa tutorial
Responda a esta breve pesquisa para fornecer feedback sobre este tutorial. Suas percepções nos ajudarão a melhorar nossas ofertas de conteúdo e a experiência do usuário.