Sari la conținutul principal

Construiește modele de zgomot

Versiuni de pachete

Codul de pe această pagină a fost dezvoltat folosind următoarele cerințe. Recomandăm utilizarea acestor versiuni sau a unora mai noi.

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

Această pagină arată cum să folosești modulul noise din Qiskit Aer pentru a construi modele de zgomot pentru simularea Circuit-urilor cuantice în prezența erorilor. Aceasta este utilă pentru emularea procesoarelor cuantice cu zgomot și pentru studierea efectelor zgomotului asupra execuției algoritmilor cuantici.

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

Modulul noise din Qiskit Aer

Modulul noise din Qiskit Aer conține clase Python pentru a construi modele de zgomot personalizate pentru simulare. Există trei clase cheie:

  1. Clasa NoiseModel, care stochează un model de zgomot folosit pentru simularea cu zgomot.

  2. Clasa QuantumError, care descrie erori de Gate-uri CPTP. Acestea pot fi aplicate:

    • După instrucțiuni de tip gate sau reset
    • Înainte de instrucțiuni de tip measure.
  3. Clasa ReadoutError, care descrie erorile clasice de citire.

Inițializarea unui model de zgomot dintr-un Backend

Poți inițializa un model de zgomot cu parametri setați din cele mai recente date de calibrare pentru un Backend fizic:

from qiskit_ibm_runtime import QiskitRuntimeService

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

Aceasta va produce un model de zgomot care aproximează în linii mari erorile pe care le-ai întâlni când folosești acel Backend. Dacă dorești să ai un control mai detaliat asupra parametrilor modelului de zgomot, va trebui să îți creezi propriul model de zgomot, după cum este descris în restul acestei pagini.

Erori cuantice

În loc să lucrezi direct cu obiectul QuantumError, există multe funcții ajutătoare care generează automat un tip specific de eroare cuantică parametrizată. Acestea sunt conținute în modulul noise și includ funcții pentru multe tipuri comune de erori folosite în cercetarea computației cuantice. Numele funcțiilor și tipul de eroare pe care îl returnează sunt:

Funcție de eroare standardDetalii
kraus_errorun canal de eroare CPTP general pe n-Qubiți dat ca o listă de matrice Kraus [K0,...][K_0, ...].
mixed_unitary_erroro eroare unitară mixtă pe n-Qubiți dată ca o listă de matrice unitare și probabilități [(U0,p0),...][(U_0, p_0),...].
coherent_unitary_erroro eroare unitară coerentă pe n-Qubiți dată ca o singură matrice unitară UU.
pauli_errorun canal de eroare Pauli pe n-Qubiți (unitar mixt) dat ca o listă de operatori Pauli și probabilități [(P0,p0),...][(P_0, p_0),...]
depolarizing_errorun canal de eroare de depolarizare pe n-Qubiți parametrizat de o probabilitate de depolarizare pp.
reset_erroro eroare de reset pe un singur Qubit parametrizată de probabilitățile p0,p1p_0, p_1 de resetare la starea 0\vert0\rangle, 1\vert1\rangle.
thermal_relaxation_errorun canal de relaxare termică pe un singur Qubit parametrizat de constantele de timp de relaxare T1T_1, T2T_2, timpul de Gate tt și populația termică a stării excitate p1p_1.
phase_amplitude_damping_errorUn canal de eroare generalizat de amortizare combinată a fazei și amplitudinii pe un singur Qubit dat de un parametru de amortizare a amplitudinii λ\lambda, un parametru de amortizare a fazei γ\gamma și o populație termică a stării excitate p1p_1.
amplitude_damping_errorUn canal de eroare generalizat de amortizare a amplitudinii pe un singur Qubit dat de un parametru de amortizare a amplitudinii λ\lambda și o populație termică a stării excitate p1p_1.
phase_damping_errorUn canal de eroare de amortizare a fazei pe un singur Qubit dat de un parametru de amortizare a fazei γ\gamma.

Combinarea erorilor cuantice

Instanțele QuantumError pot fi combinate folosind compoziția, produsul tensorial și expansiunea tensorială (produsul tensorial în ordine inversă) pentru a produce noi QuantumError-uri astfel:

  • Compoziție: E(ρ)=E2(E1(ρ))\cal{E}(\rho)=\cal{E_2}(\cal{E_1}(\rho)) ca error = error1.compose(error2)
  • Produs tensorial: E(ρ)=(E1E2)(ρ)\cal{E}(\rho) =(\cal{E_1}\otimes\cal{E_2})(\rho) ca error = error1.tensor(error2)
  • Produs de expansiune: E(ρ)=(E2E1)(ρ)\cal{E}(\rho) =(\cal{E_2}\otimes\cal{E_1})(\rho) ca error = error1.expand(error2)

Exemplu

Pentru a construi o eroare de bit-flip de 5% pe un singur 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 ├
└───┘

Conversia către și de la operatori QuantumChannel

Putem, de asemenea, converti înainte și înapoi între obiectele QuantumError din Qiskit Aer și obiectele QuantumChannel din 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

Eroare de citire

Erorile clasice de citire sunt specificate printr-o listă de vectori de probabilitate de atribuire P(AB)P(A|B):

  • AA este valoarea înregistrată a bitului clasic
  • BB este valoarea reală a bitului returnată din măsurătoare

De exemplu, pentru un 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 ]])

Erorile de citire pot fi, de asemenea, combinate folosind compose, tensor și expand, la fel ca în cazul erorilor cuantice.

Adaugă erori într-un noise model

Când adaugi o eroare cuantică într-un noise model, trebuie să specifici tipul de instrucțiune asupra căreia acționează și ce Qubiți să îi aplice. Există două cazuri de erori cuantice:

  1. Eroare cuantică pentru toți Qubiții
  2. Eroare cuantică pentru Qubiți specifici

1. Eroare cuantică pentru toți Qubiții

Aceasta aplică aceeași eroare oricărei apariții a unei instrucțiuni, indiferent de Qubiții asupra cărora acționează.

Se adaugă cu 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. Eroare cuantică pentru Qubiți specifici

Aceasta aplică eroarea oricărei apariții a unei instrucțiuni care acționează pe o listă specificată de Qubiți. Reține că ordinea Qubiților contează: de exemplu, o eroare aplicată Qubiților [0, 1] pentru un Gate cu doi Qubiți diferă de una aplicată Qubiților [1, 0].

Se adaugă cu 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,))]

Notă despre eroarea cuantică pe Qubiți non-locali

NoiseModel nu suportă adăugarea de erori cuantice pe Qubiți non-locali. Acestea ar trebui gestionate în afara NoiseModel. Aceasta sugerează că ar trebui să scrii propriul tău pass de Transpiler (TransformationPass) și să rulezi pass-ul imediat înainte de a rula simulatorul, dacă trebuie să inserezi erorile cuantice în Circuit-ul tău în condiții proprii.

Execută o simulare cu zgomot folosind un noise model

Comanda AerSimulator(noise_model=noise_model) returnează un simulator configurat conform noise model-ului dat. Pe lângă setarea noise model-ului simulatorului, aceasta suprascrie și porțile de bază ale simulatorului, conform Gate-urilor din noise model.

Exemple de noise model

Vom prezenta acum câteva exemple de noise model-uri. Pentru demonstrațiile noastre, folosim un Circuit de test simplu care generează o stare GHZ de n Qubiți:

# 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

Simulare ideală

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

Output of the previous code cell

Exemplu de zgomot 1: Noise model simplu cu eroare de bit-flip

Să considerăm un exemplu simplu de noise model, comun în cercetarea din teoria informației cuantice:

  • Când se aplică un Gate pe un singur Qubit, starea Qubitului se inversează cu probabilitatea p_gate1.
  • Când se aplică un Gate pe doi Qubiți, se aplică erori pe un singur Qubit fiecărui Qubit.
  • Când se resetează un Qubit, acesta se resetează la 1 în loc de 0 cu probabilitatea p_reset.
  • Când se măsoară un Qubit, starea Qubitului se inversează cu probabilitatea 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']

Execută simularea cu zgomot

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

Example 2: Relaxare termică T1/T2

Acum să considerăm un model de erori mai realist, bazat pe relaxarea termică a qubitului cu mediul:

  • Fiecare Qubit este parametrizat printr-o constantă de timp de relaxare termică T1T_1 și o constantă de timp de defazare T2T_2.
  • Rețineți că trebuie să avem T22T1T_2 \le 2 T_1.
  • Ratele de eroare pentru instrucțiuni sunt determinate de timpii Gate-urilor și de valorile T1T_1, T2T_2 ale qubiților.
# 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))]

Executarea simulării cu zgomot

# 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

Pași următori

Recomandări