Construir modelos de ruido
Versiones de paquetes
El código de esta página se desarrolló utilizando los siguientes requisitos. Recomendamos usar estas versiones o más recientes.
qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
qiskit-aer~=0.17
Esta página muestra cómo usar el módulo noise de Qiskit Aer para construir modelos de ruido para simular circuitos cuánticos en presencia de errores. Esto es útil para emular procesadores cuánticos ruidosos y para estudiar los efectos del ruido en la ejecución de algoritmos cuánticos.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer qiskit-ibm-runtime
import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import Kraus, SuperOp
from qiskit.visualization import plot_histogram
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_aer import AerSimulator
# Import from Qiskit Aer noise module
from qiskit_aer.noise import (
NoiseModel,
QuantumError,
ReadoutError,
depolarizing_error,
pauli_error,
thermal_relaxation_error,
)
Módulo noise de Qiskit Aer
El módulo noise de Qiskit Aer contiene clases de Python para construir modelos de ruido personalizados para simulación. Hay tres clases clave:
-
La clase
NoiseModelque almacena un modelo de ruido usado para simulación con ruido (noisy simulation). -
La clase
QuantumErrorque describe los errores de puerta CPTP. Estos pueden aplicarse:- Después de instrucciones de puerta (gate) o reinicio (reset).
- Antes de instrucciones de medida (measure).
-
La clase
ReadoutErrorque describe los errores de lectura clásica.
Inicializar un modelo de ruido desde un backend
Puedes inicializar un modelo de ruido con parámetros configurados a partir de los datos de calibración más recientes para un backend físico:
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
backend = service.backend("ibm_fez")
noise_model = NoiseModel.from_backend(backend)
Esto generará un modelo de ruido que se aproxima vagamente a los errores que uno encontraría al usar ese backend. Si quieres tener un control más detallado sobre los parámetros del modelo de ruido, entonces necesitarás crear tu propio modelo de ruido, como se describe en el resto de esta página.
Errores cuánticos (Quantum errors)
En lugar de tratar directamente con el objeto QuantumError, existen muchas funciones auxiliares para generar automáticamente un tipo específico de error cuántico parametrizado. Estas están contenidas en el módulo noise e incluyen funciones para muchos tipos de error comunes usados en la investigación de computación cuántica. Los nombres de las funciones y el tipo de error que devuelven son:
| Función de error estándar | Detalles |
|---|---|
kraus_error | un canal de error general CPTP de n-qubits dado como una lista de matrices de Kraus . |
mixed_unitary_error | un error unitario mixto de n-qubits dado como una lista de matrices unitarias y probabilidades . |
coherent_unitary_error | un error unitario coherente de n-qubits dado como una sola matriz unitaria . |
pauli_error | un canal de error de Pauli de n-qubits (unitario mixto) dado como una lista de Paulis y probabilidades |
depolarizing_error | un canal de error despolarizante de n-qubits parametrizado por una probabilidad de despolarización . |
reset_error | un error de reinicio de un solo qubit parametrizado por probabilidades de reiniciar (reset) a los estados , . |
thermal_relaxation_error | un canal de relajación térmica de un solo qubit parametrizado por tiempos de relajación , , tiempo de puerta , y población térmica del estado excitado . |
phase_amplitude_damping_error | Un canal de error combinado generalizado de amortiguamiento de fase y amplitud (phase and amplitude damping) de un solo qubit, dado por un parámetro de amortiguamiento de amplitud , un parámetro de amortiguamiento de fase , y una población térmica del estado excitado . |
amplitude_damping_error | Un canal de error generalizado de amortiguamiento de amplitud de un solo qubit dado por un parámetro de amortiguamiento de amplitud , y una población térmica del estado excitado . |
phase_damping_error | Un canal de error de amortiguamiento de fase de un solo qubit dado por un parámetro de amortiguamiento de fase . |
Combinar errores cuánticos
Las instancias de QuantumError se pueden combinar usando composición, producto tensorial y expansión tensorial (producto tensorial en orden inverso) para producir nuevos QuantumErrors como:
- Composición: mediante
error = error1.compose(error2) - Producto tensorial: mediante
error = error1.tensor(error2) - Expandir producto: mediante
error = error1.expand(error2)
Ejemplo
Para construir un error de inversión de bit (bit-flip error) del 5% de un solo qubit:
# Construct a 1-qubit bit-flip and phase-flip errors
p_error = 0.05
bit_flip = pauli_error([("X", p_error), ("I", 1 - p_error)])
phase_flip = pauli_error([("Z", p_error), ("I", 1 - p_error)])
print(bit_flip)
print(phase_flip)
QuantumError on 1 qubits. Noise circuits:
P(0) = 0.05, Circuit =
┌───┐
q: ┤ X ├
└───┘
P(1) = 0.95, Circuit =
┌───┐
q: ┤ I ├
└───┘
QuantumError on 1 qubits. Noise circuits:
P(0) = 0.05, Circuit =
┌───┐
q: ┤ Z ├
└───┘
P(1) = 0.95, Circuit =
┌───┐
q: ┤ I ├
└───┘
# Compose two bit-flip and phase-flip errors
bitphase_flip = bit_flip.compose(phase_flip)
print(bitphase_flip)
QuantumError on 1 qubits. Noise circuits:
P(0) = 0.0025000000000000005, Circuit =
┌───┐┌───┐
q: ┤ X ├┤ Z ├
└───┘└───┘
P(1) = 0.0475, Circuit =
┌───┐┌───┐
q: ┤ X ├┤ I ├
└───┘└───┘
P(2) = 0.0475, Circuit =
┌───┐┌───┐
q: ┤ I ├┤ Z ├
└───┘└───┘
P(3) = 0.9025, Circuit =
┌───┐┌───┐
q: ┤ I ├┤ I ├
└───┘└───┘
# Tensor product two bit-flip and phase-flip errors with
# bit-flip on qubit-0, phase-flip on qubit-1
error2 = phase_flip.tensor(bit_flip)
print(error2)
QuantumError on 2 qubits. Noise circuits:
P(0) = 0.0025000000000000005, Circuit =
┌───┐
q_0: ┤ X ├
├───┤
q_1: ┤ Z ├
└───┘
P(1) = 0.0475, Circuit =
┌───┐
q_0: ┤ I ├
├───┤
q_1: ┤ Z ├
└───┘
P(2) = 0.0475, Circuit =
┌───┐
q_0: ┤ X ├
├───┤
q_1: ┤ I ├
└ ───┘
P(3) = 0.9025, Circuit =
┌───┐
q_0: ┤ I ├
├───┤
q_1: ┤ I ├
└───┘
Convertir de y hacia operadores QuantumChannel
También podemos convertir de un lado a otro entre objetos QuantumError en Qiskit Aer y objetos QuantumChannel en Qiskit.
# Convert to Kraus operator
bit_flip_kraus = Kraus(bit_flip)
print(bit_flip_kraus)
Kraus([[[-9.74679434e-01+0.j, 0.00000000e+00+0.j],
[ 0.00000000e+00+0.j, -9.74679434e-01+0.j]],
[[ 0.00000000e+00+0.j, 2.23606798e-01+0.j],
[ 2.23606798e-01+0.j, -4.96506831e-17+0.j]]],
input_dims=(2,), output_dims=(2,))
# Convert to Superoperator
phase_flip_sop = SuperOp(phase_flip)
print(phase_flip_sop)
SuperOp([[1. +0.j, 0. +0.j, 0. +0.j, 0. +0.j],
[0. +0.j, 0.9+0.j, 0. +0.j, 0. +0.j],
[0. +0.j, 0. +0.j, 0.9+0.j, 0. +0.j],
[0. +0.j, 0. +0.j, 0. +0.j, 1. +0.j]],
input_dims=(2,), output_dims=(2,))
# Convert back to a quantum error
print(QuantumError(bit_flip_kraus))
# Check conversion is equivalent to original error
QuantumError(bit_flip_kraus) == bit_flip
QuantumError on 1 qubits. Noise circuits:
P(0) = 1.0, Circuit =
┌───────┐
q: ┤ kraus ├
└───────┘
True
Error de lectura (Readout error)
Los errores de lectura clásica se especifican mediante una lista de vectores de probabilidad de asignación :
- es el valor del bit clásico registrado (recorded)
- es el valor del bit verdadero (true) devuelto por la medida
Por ejemplo, para un qubit: .
# Measurement misassignment probabilities
p0given1 = 0.1
p1given0 = 0.05
ReadoutError([[1 - p1given0, p1given0], [p0given1, 1 - p0given1]])
ReadoutError([[0.95 0.05]
[0.1 0.9 ]])
Los errores de lectura también pueden ser combinados usando compose, tensor y expand, al igual que con los errores cuánticos.
Añadir errores a un modelo de ruido
Al añadir un error cuántico a un modelo de ruido, debemos especificar el tipo de instrucción sobre la que actúa y a qué qubits aplicarlo. Hay dos casos de errores cuánticos:
- Error cuántico de todos los qubits (All-qubit quantum error)
- Error cuántico de qubit específico (Specific qubit quantum error)
1. Error cuántico de todos los qubits
Esto aplica el mismo error a cualquier aparición de una instrucción, sin importar en qué qubits actúe.
Se añade mediante noise_model.add_all_qubit_quantum_error(error, instructions):
# Create an empty noise model
noise_model = NoiseModel()
# Add depolarizing error to all single qubit u1, u2, u3 gates
error = depolarizing_error(0.05, 1)
noise_model.add_all_qubit_quantum_error(error, ["u1", "u2", "u3"])
# Print noise model info
print(noise_model)
NoiseModel:
Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']
Instructions with noise: ['u3', 'u2', 'u1']
All-qubits errors: ['u1', 'u2', 'u3']
2. Error cuántico de qubit específico
Esto aplica el error a cualquier aparición de una instrucción que actúa sobre una lista especificada de qubits. Ten en cuenta que el orden de los qubits importa: por ejemplo, un error aplicado a los qubits [0, 1] para una puerta de dos qubits es diferente a uno aplicado a los qubits [1, 0].
Se añade como noise_model.add_quantum_error(error, instructions, qubits):
# Create an empty noise model
noise_model = NoiseModel()
# Add depolarizing error to all single qubit u1, u2, u3 gates on qubit 0 only
error = depolarizing_error(0.05, 1)
noise_model.add_quantum_error(error, ["u1", "u2", "u3"], [0])
# Print noise model info
print(noise_model)
NoiseModel:
Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']
Instructions with noise: ['u3', 'u2', 'u1']
Qubits with noise: [0]
Specific qubit errors: [('u1', (0,)), ('u2', (0,)), ('u3', (0,))]
Nota sobre error cuántico de qubit no local (non-local qubit quantum error)
NoiseModel no soporta la adición de errores cuánticos de qubits no locales. Deben ser manejados fuera de NoiseModel. Eso sugiere que deberías escribir tu propio pase del transpilador (TransformationPass) para insertar estos errores en tu circuito, y ejecutarlo justo antes de usar el simulador.
Ejecutar una simulación con ruido con un modelo de ruido
El comando AerSimulator(noise_model=noise_model) devuelve un simulador configurado con el modelo de ruido dado. Además de configurar el modelo de ruido del simulador, también anula (overrides) las puertas base del simulador, de acuerdo con las puertas del modelo de ruido.
Ejemplos de modelos de ruido
Ahora daremos algunos ejemplos de modelos de ruido. Para nuestras demostraciones usamos un circuito de prueba simple que genera un estado GHZ de n qubits:
# System Specification
n_qubits = 4
circ = QuantumCircuit(n_qubits)
# Test Circuit
circ.h(0)
for qubit in range(n_qubits - 1):
circ.cx(qubit, qubit + 1)
circ.measure_all()
print(circ)
┌───┐ ░ ┌─┐
q_0: ┤ H ├──■─────────────░─┤M├─────────
└───┘┌─┴─┐ ░ └╥┘┌─┐
q_1: ─────┤ X ├──■────────░──╫─┤M├──────
└───┘┌─┴─┐ ░ ║ └╥┘┌─┐
q_2: ──────────┤ X ├──■───░──╫──╫─┤M├───
└───┘┌─┴─┐ ░ ║ ║ └╥┘┌─┐
q_3: ───────────────┤ X ├─░──╫──╫──╫─┤M├
└───┘ ░ ║ ║ ║ └╥┘
meas: 4/════════════════════════╩══╩══╩══╩═
0 1 2 3
Simulación ideal
# Ideal simulator and execution
sim_ideal = AerSimulator()
result_ideal = sim_ideal.run(circ).result()
plot_histogram(result_ideal.get_counts(0))
Ejemplo de ruido 1: Modelo de ruido de error de inversión de bit (bit-flip) básico
Consideremos un ejemplo simple de un modelo de ruido de "juguete" (toy noise model) que es común en la investigación de la teoría de la información cuántica:
- Al aplicar una puerta de un solo qubit, invierte el estado del qubit con probabilidad
p_gate1. - Al aplicar una puerta de dos qubits, aplica errores de un solo qubit a cada qubit.
- Al reiniciar (reset) un qubit, reinicia a 1 en lugar de 0 con probabilidad
p_reset. - Al medir un qubit, invierte el estado del qubit con probabilidad
p_meas.
# Example error probabilities
p_reset = 0.03
p_meas = 0.1
p_gate1 = 0.05
# QuantumError objects
error_reset = pauli_error([("X", p_reset), ("I", 1 - p_reset)])
error_meas = pauli_error([("X", p_meas), ("I", 1 - p_meas)])
error_gate1 = pauli_error([("X", p_gate1), ("I", 1 - p_gate1)])
error_gate2 = error_gate1.tensor(error_gate1)
# Add errors to noise model
noise_bit_flip = NoiseModel()
noise_bit_flip.add_all_qubit_quantum_error(error_reset, "reset")
noise_bit_flip.add_all_qubit_quantum_error(error_meas, "measure")
noise_bit_flip.add_all_qubit_quantum_error(error_gate1, ["u1", "u2", "u3"])
noise_bit_flip.add_all_qubit_quantum_error(error_gate2, ["cx"])
print(noise_bit_flip)
NoiseModel:
Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']
Instructions with noise: ['u3', 'u2', 'measure', 'cx', 'reset', 'u1']
All-qubits errors: ['reset', 'measure', 'u1', 'u2', 'u3', 'cx']
Ejecutar la simulación con ruido
# Create noisy simulator backend
sim_noise = AerSimulator(noise_model=noise_bit_flip)
# Transpile circuit for noisy basis gates
passmanager = generate_preset_pass_manager(
optimization_level=3, backend=sim_noise
)
circ_tnoise = passmanager.run(circ)
# Run and get counts
result_bit_flip = sim_noise.run(circ_tnoise).result()
counts_bit_flip = result_bit_flip.get_counts(0)
# Plot noisy output
plot_histogram(counts_bit_flip)
Ejemplo 2: Relajación térmica T1/T2
Ahora consideremos un modelo de error más realista basado en la relajación térmica con el entorno del qubit:
- Cada qubit está parametrizado por una constante de tiempo de relajación térmica y una constante de tiempo de desfasaje (dephasing) .
- Toma en cuenta que debemos tener .
- Las tasas de error en las instrucciones están determinadas por los tiempos de las puertas y los valores , del qubit.
# T1 and T2 values for qubits 0-3
T1s = np.random.normal(
50e3, 10e3, 4
) # Sampled from normal distribution mean 50 microsec
T2s = np.random.normal(
70e3, 10e3, 4
) # Sampled from normal distribution mean 50 microsec
# Truncate random T2s <= T1s
T2s = np.array([min(T2s[j], 2 * T1s[j]) for j in range(4)])
# Instruction times (in nanoseconds)
time_u1 = 0 # virtual gate
time_u2 = 50 # (single X90 pulse)
time_u3 = 100 # (two X90 pulses)
time_cx = 300
time_reset = 1000 # 1 microsecond
time_measure = 1000 # 1 microsecond
# QuantumError objects
errors_reset = [
thermal_relaxation_error(t1, t2, time_reset) for t1, t2 in zip(T1s, T2s)
]
errors_measure = [
thermal_relaxation_error(t1, t2, time_measure) for t1, t2 in zip(T1s, T2s)
]
errors_u1 = [
thermal_relaxation_error(t1, t2, time_u1) for t1, t2 in zip(T1s, T2s)
]
errors_u2 = [
thermal_relaxation_error(t1, t2, time_u2) for t1, t2 in zip(T1s, T2s)
]
errors_u3 = [
thermal_relaxation_error(t1, t2, time_u3) for t1, t2 in zip(T1s, T2s)
]
errors_cx = [
[
thermal_relaxation_error(t1a, t2a, time_cx).expand(
thermal_relaxation_error(t1b, t2b, time_cx)
)
for t1a, t2a in zip(T1s, T2s)
]
for t1b, t2b in zip(T1s, T2s)
]
# Add errors to noise model
noise_thermal = NoiseModel()
for j in range(4):
noise_thermal.add_quantum_error(errors_reset[j], "reset", [j])
noise_thermal.add_quantum_error(errors_measure[j], "measure", [j])
noise_thermal.add_quantum_error(errors_u1[j], "u1", [j])
noise_thermal.add_quantum_error(errors_u2[j], "u2", [j])
noise_thermal.add_quantum_error(errors_u3[j], "u3", [j])
for k in range(4):
noise_thermal.add_quantum_error(errors_cx[j][k], "cx", [j, k])
print(noise_thermal)
NoiseModel:
Basis gates: ['cx', 'id', 'rz', 'sx', 'u2', 'u3']
Instructions with noise: ['u3', 'u2', 'measure', 'cx', 'reset']
Qubits with noise: [0, 1, 2, 3]
Specific qubit errors: [('reset', (0,)), ('reset', (1,)), ('reset', (2,)), ('reset', (3,)), ('measure', (0,)), ('measure', (1,)), ('measure', (2,)), ('measure', (3,)), ('u2', (0,)), ('u2', (1,)), ('u2', (2,)), ('u2', (3,)), ('u3', (0,)), ('u3', (1,)), ('u3', (2,)), ('u3', (3,)), ('cx', (0, 0)), ('cx', (0, 1)), ('cx', (0, 2)), ('cx', (0, 3)), ('cx', (1, 0)), ('cx', (1, 1)), ('cx', (1, 2)), ('cx', (1, 3)), ('cx', (2, 0)), ('cx', (2, 1)), ('cx', (2, 2)), ('cx', (2, 3)), ('cx', (3, 0)), ('cx', (3, 1)), ('cx', (3, 2)), ('cx', (3, 3))]
Ejecutar la simulación con ruido
# Run the noisy simulation
sim_thermal = AerSimulator(noise_model=noise_thermal)
# Transpile circuit for noisy basis gates
passmanager = generate_preset_pass_manager(
optimization_level=3, backend=sim_thermal
)
circ_tthermal = passmanager.run(circ)
# Run and get counts
result_thermal = sim_thermal.run(circ_tthermal).result()
counts_thermal = result_thermal.get_counts(0)
# Plot noisy output
plot_histogram(counts_thermal)
Siguientes pasos
- Para simular circuitos ruidosos, consulta Simulación exacta y ruidosa con primitivas de Qiskit Aer.
- Revisa la referencia del módulo de ruido de Qiskit Aer (Qiskit Aer noise module).