Skip to main content
IBM Quantum Platform

Lärmmodelle erstellen

  • Der Code auf dieser Seite wurde unter Berücksichtigung der folgenden Anforderungen entwickelt. Wir empfehlen die Verwendung dieser oder neuerer Versionen.

    qiskit[all]~=2.5.2
    qiskit-ibm-runtime~=0.47.0
    qiskit-aer~=0.17
    

Diese Seite zeigt, wie man mit dem Qiskit Aer noise modul zur Erstellung von Rauschmodellen für die Simulation von Quantenschaltungen in Anwesenheit von Fehlern. Dies ist nützlich für die Emulation verrauschter Quantenprozessoren und für die Untersuchung der Auswirkungen von Rauschen auf die Ausführung von Quantenalgorithmen.

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,
)

Qiskit noise Aer-Modul

Das Modul Qiskit Aer noise enthält Python Klassen, um maßgeschneiderte Geräuschmodelle für die Simulation zu erstellen. Es gibt drei Schlüsselklassen:

  1. Die Klasse NoiseModel speichert ein Rauschmodell, das für die Rauschsimulation verwendet wird.

  2. Die Klasse QuantumError , die CPTP-Gate-Fehler beschreibt. Diese können angewendet werden:

    • Nach Tor- oder Reset-Anweisungen
    • Anweisungen vor der Messung.
  3. Die Klasse ReadoutError , die klassische Auslesefehler beschreibt.


Ein Rauschmodell aus einem Backend initialisieren

Sie können ein Rauschmodell mit Parametern initialisieren, die auf der Grundlage der aktuellsten Kalibrierungsdaten für ein physikalisches Backend festgelegt wurden.

Note

In diesen Beispielen wird das FakeSherbrooke``qiskit_ibm_runtime Mock-Backend von verwendet, Sie können es jedoch mit jedem Qiskit-kompatiblen echten oder simulierten Backend ausprobieren.

from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

backend = FakeSherbrooke()
noise_model = NoiseModel.from_backend(backend)

Dies führt zu einem Rauschmodell, das die Fehler, die bei der Verwendung dieses Backends auftreten würden, annähernd wiedergibt. Wenn Sie eine detailliertere Kontrolle über die Parameter des Rauschmodells haben möchten, müssen Sie Ihr eigenes Rauschmodell erstellen, wie im Rest dieser Seite beschrieben.


Quantenfehler

Anstatt direkt mit dem QuantumError Objekt zu arbeiten, gibt es viele Hilfsfunktionen, die automatisch einen bestimmten Typ von parametrisiertem Quantenfehler generieren. Diese sind im noise Modul enthalten und umfassen Funktionen für viele gängige Fehlertypen, die in der Quantencomputerforschung verwendet werden. Die Funktionsnamen und die Art der Fehler, die sie zurückgeben, sind:

Standardfehlerfunktion
Details zu
kraus_erroreinen allgemeinen n-Qubit-CPTP-Fehlerkanal in Form einer Liste von Kraus-Matrizen [K0,...][K_0, ...].
mixed_unitary_erroreinen n-qubit gemischten unitären Fehler, der als eine Liste von unitären Matrizen und Wahrscheinlichkeiten angegeben wird [(U0,p0),...][(U_0, p_0),...].
coherent_unitary_errorein n-Qubit kohärenter unitärer Fehler, der als eine einzige unitäre Matrix UU gegeben ist.
pauli_errorein n-Qubit-Pauli-Fehlerkanal (gemischt unitär), der als Liste von Pauli und Wahrscheinlichkeiten angegeben ist [(P0,p0),...][(P_0, p_0),...]
depolarizing_erroreinen n-qubit depolarisierenden Fehlerkanal, der durch eine Depolarisationswahrscheinlichkeit pp parametrisiert ist.
reset_errorein Einzelqubit-Reset-Fehler, parametrisiert durch die Wahrscheinlichkeiten p0,p1p_0, p_1 eines Resets in den Zustand ∣0⟩\vert0\rangle ∣1⟩\vert1\rangle.
thermal_relaxation_errorein thermischer Relaxationskanal für ein einzelnes Qubit, parametrisiert durch die Relaxationszeitkonstanten T1T_1, T2T_2, die Torzeit tt und die thermische Population im angeregten Zustand p1p_1.
phase_amplitude_damping_errorEin verallgemeinerter kombinierter Phasen- und Amplitudendämpfungs-Fehlerkanal, der durch einen Amplitudendämpfungsparameter λ\lambda, einen Phasendämpfungsparameter γ\gamma und eine thermische Population im angeregten Zustand p1p_1 gegeben ist.
amplitude_damping_errorEin verallgemeinerter Amplitudendämpfungs-Fehlerkanal, der durch einen Amplitudendämpfungsparameter λ\lambda und eine thermische Population im angeregten Zustand p1p_1 gegeben ist.
phase_damping_errorEin Einzelqubit-Phasendämpfungsfehlerkanal, der durch einen Phasendämpfungs-Parameter γ\gamma gegeben ist.

Quantenfehler kombinieren

QuantumError instanzen können mit Hilfe von Komposition, Tensorprodukt und Tensorexpansion (Tensorprodukt umgekehrter Ordnung) kombiniert werden, um neue QuantumErrors zu erzeugen:

  • Zusammensetzung: E(ρ)=E2(E1(ρ))\cal{E}(\rho)=\cal{E_2}(\cal{E_1}(\rho)) als error = error1.compose(error2)
  • Tensorprodukt: E(ρ)=(E1⊗E2)(ρ)\cal{E}(\rho) =(\cal{E_1}\otimes\cal{E_2})(\rho) als error = error1.tensor(error2)
  • Produkt erweitern: E(ρ)=(E2⊗E1)(ρ)\cal{E}(\rho) =(\cal{E_2}\otimes\cal{E_1})(\rho) als error = error1.expand(error2)

Beispiel

Konstruktion eines 5%igen Ein-Qubit-Bitflip-Fehlers:

# 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 ├
     └───┘

In und aus Operatoren des „ QuantumChannel “ konvertieren

Wir können auch zwischen QuantumError Objekten in Qiskit Aer und QuantumChannel Objekten in Qiskit hin und her konvertieren.

# Convert to Kraus operator
bit_flip_kraus = Kraus(bit_flip)
print(bit_flip_kraus)

Output:

Kraus([[[-9.74679434e-01+1.19363805e-16j,
          0.00000000e+00+0.00000000e+00j],
        [ 0.00000000e+00+0.00000000e+00j,
         -9.74679434e-01+0.00000000e+00j]],

       [[ 0.00000000e+00+0.00000000e+00j,
          4.69834045e-18-2.23606798e-01j],
        [-2.26855945e-17-2.23606798e-01j,
          5.03721386e-33+4.96506831e-17j]]],
      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_flip

Output:

QuantumError on 1 qubits. Noise circuits:
  P(0) = 1.0, Circuit = 
   ┌───────┐
q: ┤ kraus ├
   └───────┘
True

Auslesungsfehler

Klassische Auslesungsfehler werden durch eine Liste von Zuordnungswahrscheinlichkeitsvektoren angegeben P(A∣B)P(A|B) :

  • AA ist der aufgezeichnete klassische Bitwert
  • BB ist der wahre Bitwert, der von der Messung zurückgegeben wird

Zum Beispiel für ein Qubit: P(A∣B)=[P(A∣0),P(A∣1)] P(A|B) = [P(A|0), P(A|1)].

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

Auslesefehler können auch mit compose, tensor und expand kombiniert werden, wie bei Quantenfehlern.


Fehler zu einem Rauschmodell hinzufügen

Wenn man einen Quantenfehler zu einem Rauschmodell hinzufügt, muss man angeben, auf welche Art von Anweisung er wirkt und auf welche Qubits er angewendet werden soll. Es gibt zwei Fälle von Quantenfehlern:

  1. All-Qubit-Quantenfehler
  2. Spezifischer Qubit-Quantenfehler

1. All-Qubit-Quantenfehler

Dadurch wird bei jedem Auftreten eines Befehls derselbe Fehler verursacht, unabhängig davon, auf welche Qubits er wirkt.

Sie wird als noise_model.add_all_qubit_quantum_error(error, instructions) hinzugefügt:

# 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', 'u3', 'u1']
  All-qubits errors: ['u1', 'u2', 'u3']

2. Spezifischer Qubit-Quantenfehler

Damit wird der Fehler auf jedes Vorkommen eines Befehls angewendet, der auf eine bestimmte Liste von Qubits wirkt. Man beachte, dass die Reihenfolge der Qubits eine Rolle spielt: Ein Fehler, der bei einem Zwei-Qubit-Tor auf die Qubits [0 und 1] angewendet wird, ist anders als ein Fehler, der auf die Qubits [1 und 0] angewendet wird.

Sie wird als noise_model.add_quantum_error(error, instructions, qubits) hinzugefügt:

# 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', 'u3', 'u1']
  Qubits with noise: [0]
  Specific qubit errors: [('u1', (0,)), ('u2', (0,)), ('u3', (0,))]

Hinweis zu nicht-lokalen Qubit-Quantenfehlern

NoiseModel unterstützt keine Hinzufügung von nicht-lokalen Quantenfehlern bei Qubits. Sie sollten außerhalb von NoiseModel. behandelt werden. Das bedeutet, dass Sie Ihren eigenen Transpiler-Pass (TransformationPass) schreiben und diesen unmittelbar vor dem Start des Simulators ausführen sollten, wenn Sie Ihre Quantenfehler unter Ihren eigenen Bedingungen in Ihre Schaltung einfügen möchten.

Führen Sie eine Geräuschsimulation mit einem Geräuschmodell durch

Der Befehl AerSimulator(noise_model=noise_model) gibt einen für das angegebene Rauschmodell konfigurierten Simulator zurück. Neben der Einstellung des Rauschmodells des Simulators werden auch die Basis-Gates des Simulators entsprechend den Gates des Rauschmodells überschrieben.


Beispiele für Geräuschmodelle

Wir werden nun einige Beispiele für Rauschmodelle geben. Für unsere Demonstrationen verwenden wir eine einfache Testschaltung, die einen n-Qubit-GHZ-Zustand erzeugt:

# 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 

Ideale Simulation

# Ideal simulator and execution
sim_ideal = AerSimulator()
result_ideal = sim_ideal.run(circ).result()
plot_histogram(result_ideal.get_counts(0))

Output:

Output of the previous code cell

Rauschbeispiel 1: Einfaches Bit-Flip-Fehler-Rauschmodell

Betrachten wir ein einfaches Beispiel für ein Spielzeug-Rauschmodell, das in der Forschung zur Quanteninformationstheorie üblich ist:

  • Bei der Anwendung eines Ein-Qubit-Gatters wird der Zustand des Qubits mit der Wahrscheinlichkeit p_gate1 umgedreht.
  • Bei der Anwendung eines Zwei-Qubit-Gatters sind auf jedes Qubit Einzel-Qubit-Fehler anzuwenden.
  • Beim Zurücksetzen eines Qubits wird es mit der Wahrscheinlichkeit p_reset auf 1 statt auf 0 zurückgesetzt.
  • Bei der Messung eines Qubits wird der Zustand des Qubits mit der Wahrscheinlichkeit p_meas umgedreht.
# 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', 'reset', 'cx', 'measure', 'u3']
  All-qubits errors: ['reset', 'measure', 'u1', 'u2', 'u3', 'cx']

Führen Sie die laute Simulation aus

# 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:

Output of the previous code cell

Beispiel 2: Thermische Relaxation von T1/T2

Betrachten wir nun ein realistischeres Fehlermodell, das auf thermischer Relaxation mit der Qubit-Umgebung beruht:

  • Jedes Qubit ist durch eine thermische Relaxationszeitkonstante T1T_1 und eine Dephasierungszeitkonstante T2T_2 parametrisiert.
  • Beachten Sie, dass wir T2≤2T1T_2 \le 2 T_1 haben müssen.
  • Die Fehlerquoten bei Befehlen werden durch die Gatterzeiten und die Qubit-Werte T1T_1, T2T_2 bestimmt.
# 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', 'reset', 'cx', 'measure', 'u3']
  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))]

Führen Sie die laute Simulation aus

# 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:

Output of the previous code cell

Nächste Schritte

Empfehlungen
War diese Seite hilfreich?
Melden Sie auf GitHub einen Fehler, einen Tippfehler oder fordern Sie Inhalte an.