Crear modelos de ruido
El código de esta página se ha desarrollado teniendo en cuenta los siguientes requisitos. Recomendamos utilizar estas versiones o versiones más recientes.
qiskit[all]~=2.5.0 qiskit-ibm-runtime~=0.47.0 qiskit-aer~=0.17
Esta página muestra cómo utilizar el módulo Qiskit Aer noise para construir modelos de ruido para simular circuitos cuánticos en presencia de errores. Esto resulta útil para emular procesadores cuánticos ruidosos y estudiar los efectos del ruido en la ejecución de algoritmos cuánticos.
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 Qiskit Aer
El módulo Qiskit Aer noise contiene clases Python para construir modelos de ruido personalizados para simulación. Hay tres clases principales:
-
La clase
NoiseModelque almacena un modelo de ruido utilizado para la simulación ruidosa. -
La clase
QuantumErrorque describe los errores de la puerta CPTP. Se pueden aplicar:- Después de la puerta o instrucciones de reinicio
- Instrucciones antes de medir.
-
La clase
ReadoutErrorque describe los errores clásicos de lectura.
Inicializar un modelo de ruido desde un backend
Se puede inicializar un modelo de ruido con los parámetros establecidos a partir de los datos de calibración más recientes de un backend físico.
En estos ejemplos se utiliza el backend FakeSherbrooke``qiskit_ibm_runtime simulado de, pero puedes probarlo con cualquier backend real o simulado compatible con Qiskit.
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke
backend = FakeSherbrooke()
noise_model = NoiseModel.from_backend(backend)De este modo se obtendrá un modelo de ruido que se aproxima aproximadamente a los errores que se encontrarían al utilizar ese backend. Si quieres tener un control más detallado sobre los parámetros del modelo de ruido, tendrás que crear tu propio modelo de ruido, como se describe en el resto de esta página.
Errores cuánticos
En lugar de tratar el QuantumError objeto directamente, existen muchas funciones auxiliares para generar automáticamente un tipo específico de error cuántico parametrizado. Estos se encuentran en el noise módulo e incluyen funciones para muchos tipos de errores comunes utilizados en la investigación sobre computación cuántica. Los nombres de las funciones y el tipo de error que devuelven son:
Función de error típico | Detalles |
|---|---|
kraus_error | un canal de error CPTP general de n-qubit dado como una lista de matrices de Kraus . |
mixed_unitary_error | un error unitario mixto n-qubit dado como una lista de matrices unitarias y probabilidades . |
coherent_unitary_error | un error unitario coherente n-qubit dado como una única matriz unitaria . |
pauli_error | un canal de error Pauli de n-qubit (unitario mixto) dado como una lista de Pauli y probabilidades |
depolarizing_error | un canal de error despolarizante n-qubit parametrizado por una probabilidad de despolarización . |
reset_error | un error de reinicio de un solo qubit parametrizado por probabilidades de reinicio al estado . |
thermal_relaxation_error | un canal de relajación térmica de un solo qubit parametrizado por constantes de tiempo de relajación , , tiempo de puerta , y población térmica del estado excitado . |
phase_amplitude_damping_error | Un canal de error de amortiguamiento de fase y amplitud combinado generalizado 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 de estado excitado . |
amplitude_damping_error | Un canal de error de amortiguación de amplitud generalizada single-qubit dado por un parámetro de amortiguación de amplitud , y una población térmica de estado excitado . |
phase_damping_error | Canal de error de amortiguación de fase de un solo qubit dado por un parámetro de amortiguación de fase. |
Combinar errores cuánticos
QuantumError pueden combinarse utilizando la composición, el producto tensorial y la expansión tensorial (producto tensorial de orden inverso) para producir nuevos QuantumErrors como:
- Composición: as
error = error1.compose(error2) - Producto tensorial: como
error = error1.tensor(error2) - Expandir producto: como
error = error1.expand(error2)
Ejemplo
Para construir un error de cambio de bit de un solo qubit del 5%:
# 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)Output:
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)Output:
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)Output:
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 entre los operadores de « QuantumChannel »
También podemos convertir de ida y vuelta entre QuantumError objetos en Qiskit Aer y QuantumChannel objetos en Qiskit.
# Convert to Kraus operator
bit_flip_kraus = Kraus(bit_flip)
print(bit_flip_kraus)Output:
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)Output:
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_flipOutput:
QuantumError on 1 qubits. Noise circuits:
P(0) = 1.0, Circuit =
┌───────┐
q: ┤ kraus ├
└───────┘
True
Error de lectura
Los errores de lectura clásicos se especifican mediante una lista de vectores de probabilidad de asignación:
- es el valor del bit clásico registrado
- es el valor verdadero del bit devuelto por la medición
Por ejemplo, para un qubit: .
# Measurement misassignment probabilities
p0given1 = 0.1
p1given0 = 0.05
ReadoutError([[1 - p1given0, p1given0], [p0given1, 1 - p0given1]])Output:
ReadoutError([[0.95 0.05]
[0.1 0.9 ]])
Los errores de lectura también pueden combinarse utilizando 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 el que actúa y a qué qubits aplicarlo. Hay dos casos de errores cuánticos:
- Error cuántico todo-qubit
- Error cuántico qubit específico
1. Error cuántico de todos los qubits
Esto aplica el mismo error a cualquier ocurrencia de una instrucción, independientemente de los qubits sobre los que actúe.
Se añade como 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)Output:
NoiseModel:
Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']
Instructions with noise: ['u1', 'u2', 'u3']
All-qubits errors: ['u1', 'u2', 'u3']
2. Error cuántico específico de qubit
Esto aplica el error a cualquier ocurrencia de una instrucción que actúe sobre una lista especificada de qubits. Nótese 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)Output:
NoiseModel:
Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']
Instructions with noise: ['u1', 'u2', 'u3']
Qubits with noise: [0]
Specific qubit errors: [('u1', (0,)), ('u2', (0,)), ('u3', (0,))]
Nota sobre el error cuántico de qubits no locales
NoiseModel no admite la incorporación de errores cuánticos en qubits no locales. Se deben gestionar fuera de NoiseModel. Esto significa que deberías escribir tu propia pasada de transpilador (TransformationPass) y ejecutarla justo antes de iniciar el simulador si necesitas introducir tus propios errores cuánticos en el circuito según tus propias condiciones.
Ejecutar una simulación ruidosa 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 establecer el modelo de ruido del simulador, también anula las puertas de la base del simulador, de acuerdo con las puertas del modelo de ruido.
Ejemplos de modelos de ruido
A continuación, daremos algunos ejemplos de modelos de ruido. Para nuestras demostraciones utilizamos un circuito de prueba sencillo 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)Output:
┌───┐ ░ ┌─┐
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))Output:
Ejemplo de ruido 1: Modelo básico de ruido por error de inversión de bits
Consideremos un ejemplo sencillo de modelo de ruido de juguete habitual en la investigación de la teoría cuántica de la información:
- Al aplicar una puerta de un solo qubit, invierte el estado del qubit con la probabilidad
p_gate1. - Al aplicar una puerta de dos qubits, aplique errores de un qubit a cada qubit.
- Al reiniciar un qubit, se reinicia a 1 en lugar de a 0 con la probabilidad
p_reset. - Al medir un qubit, invierte el estado del qubit con la 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)Output:
NoiseModel:
Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']
Instructions with noise: ['u2', 'u1', 'measure', 'cx', 'u3', 'reset']
All-qubits errors: ['reset', 'measure', 'u1', 'u2', 'u3', 'cx']
Ejecutar la simulación ruidosa
# 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)Output:
Ejemplo 2: relajación térmica de T1/T2
Consideremos ahora 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 desfase .
- Nótese que debemos tener .
- Las tasas de error en las instrucciones vienen determinadas por los tiempos de compuerta y los valores de los qubits , .
# 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)Output:
NoiseModel:
Basis gates: ['cx', 'id', 'rz', 'sx', 'u2', 'u3']
Instructions with noise: ['u2', 'measure', 'cx', 'u3', '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 ruidosa
# 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)Output:
Próximos pasos
- Para simular circuitos con ruido, consulta «Simulación exacta y con ruido con primitivas de Qiskit Aer ».
- Revise la referencia del módulo de ruido Qiskit Aer.