Construire des modèles de bruit
Le code de cette page a été développé en tenant compte des exigences suivantes. Nous recommandons d'utiliser ces versions ou des versions plus récentes.
qiskit[all]~=2.5.1 qiskit-ibm-runtime~=0.47.0 qiskit-aer~=0.17
Cette page montre comment utiliser le module Qiskit Aer noise pour construire des modèles de bruit pour simuler des circuits quantiques en présence d'erreurs. Ceci est utile pour émuler des processeurs quantiques bruyants et pour étudier les effets du bruit sur l'exécution des algorithmes quantiques.
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,
)Module noise Qiskit Aer
Le module Qiskit Aer noise contient des classes Python pour construire des modèles de bruit personnalisés pour la simulation. Il existe trois catégories principales :
-
La classe
NoiseModelqui stocke un modèle de bruit utilisé pour la simulation bruyante. -
La classe
QuantumErrorqui décrit les erreurs de porte du CPTP. Ils peuvent être appliqués :- Instructions après la porte ou la réinitialisation
- Instructions avant la mesure.
-
La classe
ReadoutErrorqui décrit les erreurs de lecture classiques.
Initialiser un modèle de bruit à partir d'un backend
Vous pouvez initialiser un modèle de bruit à l'aide de paramètres définis à partir des dernières données d'étalonnage d'un backend physique.
Le backend FakeSherbrooke fictif de qiskit_ibm_runtime est utilisé dans ces exemples, mais vous pouvez l'essayer sur n'importe quel backend réel ou fictif compatible avec Qiskit.
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke
backend = FakeSherbrooke()
noise_model = NoiseModel.from_backend(backend)Cela permet d'obtenir un modèle de bruit qui correspond approximativement aux erreurs rencontrées lors de l'utilisation de ce backend. Si vous souhaitez avoir un contrôle plus détaillé sur les paramètres du modèle de bruit, vous devrez créer votre propre modèle de bruit, comme décrit dans le reste de cette page.
Erreurs quantiques
Plutôt que de traiter QuantumError l'objet directement, il existe de nombreuses fonctions d'aide permettant de générer automatiquement un type spécifique d'erreur quantique paramétrée. Ils sont contenus dans le noise module et comprennent des fonctions pour de nombreux types d'erreurs courantes utilisées dans la recherche en informatique quantique. Les noms des fonctions et le type d'erreur qu'elles renvoient sont les suivants :
Fonction d'erreur standard | Détails |
|---|---|
kraus_error | un canal d'erreur CPTP général à n qubits donné sous la forme d'une liste de matrices de Kraus . |
mixed_unitary_error | une erreur unitaire mixte à n qubits donnée sous la forme d'une liste de matrices unitaires et de probabilités . |
coherent_unitary_error | une erreur unitaire cohérente à n qubits donnée sous la forme d'une matrice unitaire unique . |
pauli_error | un canal d'erreur de Pauli à n qubits (mixte unitaire) donné sous la forme d'une liste de Pauli et de probabilités |
depolarizing_error | un canal d'erreur dépolarisant à n-qubits paramétré par une probabilité de dépolarisation . |
reset_error | erreur de réinitialisation d'un seul qubit paramétrée par les probabilités de réinitialisation à l'état . |
thermal_relaxation_error | un canal de relaxation thermique à qubit unique paramétré par les constantes de temps de relaxation , , le temps de porte , et la population thermique de l'état excité . |
phase_amplitude_damping_error | Un canal d'erreur d'amortissement de phase et d'amplitude généralisé à qubit unique donné par un paramètre d'amortissement d'amplitude , un paramètre d'amortissement de phase , et une population thermique de l'état excité . |
amplitude_damping_error | Un canal d'erreur à amortissement d'amplitude généralisé à un qubit donné par un paramètre d'amortissement d'amplitude , et une population thermique d'état excité . |
phase_damping_error | Canal d'erreur d'amortissement de phase à un seul qubit donné par un paramètre d'amortissement de phase. |
Combiner les erreurs quantiques
QuantumError peuvent être combinées en utilisant la composition, le produit tensoriel et l'expansion tensorielle (produit tensoriel d'ordre inversé) pour produire de nouveaux QuantumErrors comme :
- Composition : sous forme de
error = error1.compose(error2) - Produit tensoriel : comme
error = error1.tensor(error2) - Développer le produit : comme
error = error1.expand(error2)
Exemple
Pour construire une erreur de basculement de bit de 5 % sur un seul 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)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 vers et depuis les opérateurs d' QuantumChannel
Nous pouvons également faire des allers-retours entre les objets QuantumError dans Qiskit Aer et les objets QuantumChannel dans 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
Erreur de lecture
Les erreurs de lecture classiques sont spécifiées par une liste de vecteurs de probabilité d'affectation :
- est la valeur du bit classique enregistré
- est la vraie valeur du bit renvoyée par la mesure
Par exemple, pour 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 ]])
Les erreurs de lecture peuvent également être combinées en utilisant compose, tensor et expand, comme pour les erreurs quantiques.
Ajouter des erreurs à un modèle de bruit
Lorsqu'on ajoute une erreur quantique à un modèle de bruit, il faut spécifier le type d' instruction sur lequel elle agit et les qubits auxquels elle s'applique. Il existe deux cas d'erreurs quantiques :
- Erreur quantique globale
- Erreur quantique d'un qubit spécifique
1. Erreur quantique sur tous les qubits
La même erreur s'applique à toutes les occurrences d'une instruction, quels que soient les qubits sur lesquels elle agit.
Il est ajouté à l'adresse 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: ['u2', 'u1', 'u3']
All-qubits errors: ['u1', 'u2', 'u3']
2. Erreur quantique spécifique au qubit
L'erreur s'applique à toute occurrence d'une instruction agissant sur une liste de qubits spécifiée. Notez que l'ordre des qubits est important : par exemple, une erreur appliquée aux qubits [0, 1] pour une porte à deux qubits est différente d'une erreur appliquée aux qubits [1, 0.]
Il est ajouté à l'adresse 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: ['u2', 'u1', 'u3']
Qubits with noise: [0]
Specific qubit errors: [('u1', (0,)), ('u2', (0,)), ('u3', (0,))]
Remarque sur les erreurs quantiques non locales des qubits
NoiseModel ne prend pas en charge l'ajout d'erreurs quantiques sur des qubits non locaux. Ils devraient être traités en dehors de NoiseModel. Cela signifie que vous devriez écrire votre propre passe de transcompilation (TransformationPass) et l'exécuter juste avant de lancer le simulateur si vous souhaitez intégrer vos erreurs quantiques dans votre circuit selon vos propres paramètres.
Exécuter une simulation bruyante avec un modèle de bruit
La commande AerSimulator(noise_model=noise_model) renvoie un simulateur configuré selon le modèle de bruit donné. En plus de définir le modèle de bruit du simulateur, il remplace également les portes de la base du simulateur, en fonction des portes du modèle de bruit.
Exemples de modèles de bruit
Nous allons maintenant donner quelques exemples de modèles de bruit. Pour nos démonstrations, nous utilisons un circuit de test simple générant un état GHZ à 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
Simulation idéale
# Ideal simulator and execution
sim_ideal = AerSimulator()
result_ideal = sim_ideal.run(circ).result()
plot_histogram(result_ideal.get_counts(0))Output:
Exemple de bruit 1 : Modèle de bruit de base avec erreur de basculement de bit
Prenons un exemple simple de modèle de bruit jouet, courant dans la recherche sur la théorie de l'information quantique :
- Lors de l'application d'une porte à qubit unique, l'état du qubit est inversé avec la probabilité
p_gate1. - Lors de l'application d'une porte à deux qubits, appliquer des erreurs à un qubit à chaque qubit.
- Lors de la réinitialisation d'un qubit, le qubit est réinitialisé à 1 au lieu de 0 avec la probabilité
p_reset. - Lors de la mesure d'un qubit, inverser l'état du qubit avec la probabilité
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: ['u3', 'u1', 'u2', 'reset', 'cx', 'measure']
All-qubits errors: ['reset', 'measure', 'u1', 'u2', 'u3', 'cx']
Exécuter la simulation bruyante
# 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:
Exemple 2 : Relaxation thermique d' T1/T2
Considérons maintenant un modèle d'erreur plus réaliste basé sur la relaxation thermique avec l'environnement du qubit :
- Chaque qubit est paramétré par une constante de temps de relaxation thermique et une constante de temps de déphasage .
- Notons que nous devons avoir .
- Les taux d'erreur sur les instructions sont déterminés par les temps de porte et les valeurs des 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: ['u3', 'u2', 'reset', 'cx', 'measure']
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))]
Exécuter la simulation bruyante
# 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:
Etapes suivantes
- Pour simuler des circuits soumis à du bruit, consultez la section « Simulation exacte et avec bruit à l'aide des primitives de Qiskit Aer ».
- Consultez la référence du module de bruit Qiskit Aer.