Přeskočit na hlavní obsah

Tvorba šumových modelů

Verze balíčků

Kód na této stránce byl vyvinut s použitím následujících závislostí. Doporučujeme používat tyto nebo novější verze.

qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
qiskit-aer~=0.17

Tato stránka ukazuje, jak pomocí modulu noise z Qiskit Aer vytvářet šumové modely pro simulaci kvantových obvodů v přítomnosti chyb. To je užitečné pro emulaci zašuměných kvantových procesorů a pro studium vlivu šumu na provádění kvantových algoritmů.

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

Modul noise v Qiskit Aer

Modul noise v Qiskit Aer obsahuje Python třídy pro vytváření vlastních šumových modelů pro simulaci. Existují tři klíčové třídy:

  1. Třída NoiseModel, která uchovává šumový model používaný při simulaci se šumem.

  2. Třída QuantumError, která popisuje chyby CPTP hradel. Tyto chyby lze aplikovat:

    • Za instrukcemi gate nebo reset
    • Před instrukcemi measure.
  3. Třída ReadoutError, která popisuje klasické chyby čtení.

Inicializace šumového modelu z Backend

Šumový model s parametry nastavenými z nejnovějších kalibračních dat fyzického Backend lze inicializovat takto:

from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()
backend = service.backend("ibm_fez")
noise_model = NoiseModel.from_backend(backend)

Výsledkem bude šumový model, který přibližně napodobuje chyby, s nimiž by ses setkal/a při používání daného Backend. Pokud chceš mít podrobnější kontrolu nad parametry šumového modelu, budeš si muset vytvořit vlastní šumový model, jak je popsáno ve zbytku této stránky.

Kvantové chyby

Namísto přímé práce s objektem QuantumError existuje mnoho pomocných funkcí, které automaticky generují konkrétní typ parametrizované kvantové chyby. Jsou obsaženy v modulu noise a zahrnují funkce pro mnoho běžných typů chyb používaných v kvantovém výzkumu. Názvy funkcí a typy chyb, které vrací, jsou:

Standardní chybová funkcePodrobnosti
kraus_errorobecný n-qubitový CPTP chybový kanál zadaný jako seznam Krausových matic [K0,...][K_0, ...].
mixed_unitary_errorn-qubitová smíšená unitární chyba zadaná jako seznam unitárních matic a pravděpodobností [(U0,p0),...][(U_0, p_0),...].
coherent_unitary_errorn-qubitová koherentní unitární chyba zadaná jako jedna unitární matice UU.
pauli_errorn-qubitový Pauliho chybový kanál (smíšeně unitární) zadaný jako seznam Pauliho operátorů a pravděpodobností [(P0,p0),...][(P_0, p_0),...]
depolarizing_errorn-qubitový depolarizační chybový kanál parametrizovaný depolarizační pravděpodobností pp.
reset_errorjednoqubitová chyba resetu parametrizovaná pravděpodobnostmi p0,p1p_0, p_1 resetu do stavu 0\vert0\rangle, 1\vert1\rangle.
thermal_relaxation_errorjednoqubitový kanál tepelné relaxace parametrizovaný relaxačními časovými konstantami T1T_1, T2T_2, dobou hradla tt a tepelnou populací vzbuzeného stavu p1p_1.
phase_amplitude_damping_errorJednoqubitový zobecněný kombinovaný kanál fázového a amplitudového tlumení zadaný parametrem amplitudového tlumení λ\lambda, parametrem fázového tlumení γ\gamma a tepelnou populací vzbuzeného stavu p1p_1.
amplitude_damping_errorJednoqubitový zobecněný kanál amplitudového tlumení zadaný parametrem amplitudového tlumení λ\lambda a tepelnou populací vzbuzeného stavu p1p_1.
phase_damping_errorJednoqubitový kanál fázového tlumení zadaný parametrem fázového tlumení γ\gamma.

Kombinování kvantových chyb

Instance QuantumError lze kombinovat pomocí kompozice, tenzorového součinu a tenzorového rozšíření (tenzorový součin v opačném pořadí), čímž vznikají nové QuantumErrors:

  • Kompozice: E(ρ)=E2(E1(ρ))\cal{E}(\rho)=\cal{E_2}(\cal{E_1}(\rho)) jako error = error1.compose(error2)
  • Tenzorový součin: E(ρ)=(E1E2)(ρ)\cal{E}(\rho) =(\cal{E_1}\otimes\cal{E_2})(\rho) jako error = error1.tensor(error2)
  • Rozšířený součin: E(ρ)=(E2E1)(ρ)\cal{E}(\rho) =(\cal{E_2}\otimes\cal{E_1})(\rho) jako error = error1.expand(error2)

Příklad

Pro sestavení 5% jednoqubitové chyby překlopení bitu:

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

Převod na operátory QuantumChannel a zpět

Objekty QuantumError v Qiskit Aer lze také převádět na objekty QuantumChannel v Qiskit a zpět.

# 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

Chyba čtení

Klasické chyby čtení jsou specifikovány seznamem vektorů pravděpodobnosti přiřazení P(AB)P(A|B):

  • AA je zaznamenaná hodnota klasického bitu
  • BB je skutečná hodnota bitu vrácená z měření

Například pro jeden Qubit: P(AB)=[P(A0),P(A1)] 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]])
ReadoutError([[0.95 0.05]
[0.1 0.9 ]])

Chyby čtení lze také kombinovat pomocí compose, tensor a expand, stejně jako u kvantových chyb.

Přidání chyb do modelu šumu

Při přidávání kvantové chyby do modelu šumu musíme specifikovat typ instrukce, na kterou působí, a na které Qubity ji aplikovat. Existují dva případy kvantových chyb:

  1. Kvantová chyba pro všechny Qubity
  2. Kvantová chyba pro konkrétní Qubity

1. Kvantová chyba pro všechny Qubity

Tato chyba aplikuje stejnou chybu na každý výskyt instrukce, bez ohledu na to, na které Qubity působí.

Přidává se jako 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. Kvantová chyba pro konkrétní Qubity

Tato chyba aplikuje chybu na každý výskyt instrukce působící na zadaný seznam Qubitů. Všimni si, že na pořadí Qubitů záleží: například chyba aplikovaná na Qubity [0, 1] pro dvouqubitovou Gate se liší od chyby aplikované na Qubity [1, 0].

Přidává se jako 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,))]

Poznámka k nelokální kvantové chybě Qubitů

NoiseModel nepodporuje přidávání nelokálních kvantových chyb Qubitů. Ty by měly být řešeny mimo NoiseModel. To znamená, že pokud potřebuješ vložit své kvantové chyby do Circuit za vlastních podmínek, měl(a) bys napsat vlastní transpiler pass (TransformationPass) a spustit ho těsně před spuštěním simulátoru.

Spuštění šumové simulace s modelem šumu

Příkaz AerSimulator(noise_model=noise_model) vrátí simulátor nakonfigurovaný podle daného modelu šumu. Kromě nastavení modelu šumu simulátoru také přepíše základní Gate simulátoru podle Gate modelu šumu.

Příklady šumových modelů

Nyní si ukážeme několik příkladů šumových modelů. Pro demonstraci použijeme jednoduchý testovací Circuit, který generuje n-qubitový stav GHZ:

# 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

Ideální simulace

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

Výstup předchozí buňky kódu

Příklad šumu 1: Základní šumový model s chybou překlopení bitu

Uvažujme jednoduchý ilustrativní příklad šumového modelu, který je běžný ve výzkumu teorie kvantové informace:

  • Při aplikaci jednoqubitového Gate překlopíme stav Qubitu s pravděpodobností p_gate1.
  • Při aplikaci dvouqubitového Gate aplikujeme jednoqubitové chyby na každý Qubit.
  • Při resetování Qubitu ho s pravděpodobností p_reset resetujeme do stavu 1 místo 0.
  • Při měření Qubitu překlopíme jeho stav s pravděpodobností 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']

Spuštění simulace se šumem

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

Výstup předchozí buňky kódu

Příklad 2: Tepelná relaxace T1/T2

Nyní uvažujme realističtější model chyb založený na tepelné relaxaci s prostředím qubitu:

  • Každý Qubit je parametrizován časovou konstantou tepelné relaxace T1T_1 a časovou konstantou defázování T2T_2.
  • Platí, že musí být splněno T22T1T_2 \le 2 T_1.
  • Chybové míry instrukcí jsou určeny dobami Gate a hodnotami T1T_1, T2T_2 jednotlivých 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))]

Spuštění simulace se šumem

# 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 of the previous code cell

Další kroky

Doporučení