Guida rapida
Questa guida mostra un esempio minimo funzionante del pacchetto qiskit-addon-pna. Usiamo l'assorbimento del rumore propagato (PNA) per costruire un'osservabile che mitiga il rumore. Dati un circuito e un modello di rumore di Pauli-Lindblad, la PNA propaga classicamente l'osservabile attraverso il canale di rumore inverso. Misurare l'osservabile risultante sulla QPU rumorosa mitiga il rumore di gate appreso.
Per vedere come costruire un flusso di lavoro realistico ed eseguirlo su hardware quantistico con il modello di esecuzione diretta, compreso l'apprendimento del modello di rumore con NoiseLearnerV3, consulta il tutorial PNA su IBM Quantum Platform.
1. Prepara gli input per la PNA
La PNA accetta in input un circuito, un modello di rumore e un'osservabile. Qui costruiamo un modello di Ising a campo trasverso con Trotterizzazione a 10 qubit su una catena 1D. Generiamo un modello di rumore di Pauli-Lindblad 2-locale casuale per ogni gate di entanglement e lo incorporiamo come istruzione PauliLindbladError di Qiskit Aer subito prima di quel gate. Scegliamo da misurare un'osservabile Pauli-Z di peso 4.
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"matplotlib": "matplotlib", "numpy": "numpy", "qiskit": "qiskit", "qiskit_addon_pna": "qiskit-addon-pna", "qiskit_aer": "qiskit-aer"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp, pauli_basis
from qiskit_aer.noise import PauliLindbladError
def random_pauli_lindblad_noise(generators, seed, noise_scale=2e-3):
rates = np.random.default_rng(seed).random(len(generators)) * noise_scale
return PauliLindbladError(generators, rates)
def ising_circuit(
num_qubits,
layers,
edge_noise=None,
*,
num_steps=3,
rx_angle=np.pi / 8,
rzz_angle=-np.pi / 2,
):
"""Trotterized transverse-field Ising model; edge_noise=None gives the noiseless circuit."""
qc = QuantumCircuit(num_qubits)
for _ in range(num_steps):
qc.rx(rx_angle, range(num_qubits))
for layer in layers:
for edge in layer:
if edge_noise is not None:
qc.append(
edge_noise[edge], edge
) # inject synthetic gate noise
qc.rzz(rzz_angle, *edge)
return qc
num_qubits = 10
# Two entangling layers per Trotter step: even and odd bonds of a 1D chain
layers = [
[(i, i + 1) for i in range(0, num_qubits - 1, 2)],
[(i, i + 1) for i in range(1, num_qubits - 1, 2)],
]
edges = [edge for layer in layers for edge in layer]
# Random 2-local Pauli-Lindblad noise, one instance per entangling gate
two_qubit_paulis = SparsePauliOp(
[p for p in pauli_basis(2) if np.sum(p.x + p.z)]
).paulis
edge_noise = {
edge: random_pauli_lindblad_noise(two_qubit_paulis, seed=1234 + j)
for j, edge in enumerate(edges)
}
noisy_circuit = ising_circuit(num_qubits, layers, edge_noise)
# A single weight-4 observable: <Z3 Z4 Z5 Z6>
observable = SparsePauliOp.from_sparse_list(
[("ZZZZ", [3, 4, 5, 6], 1.0)], num_qubits=num_qubits
)
noisy_circuit.draw("mpl", fold=-1, scale=0.6)

2. Genera l'osservabile che mitiga il rumore
generate_noise_mitigating_observable propaga in avanti fino alla fine del circuito ogni generatore di Pauli del canale di rumore inverso. L'osservabile viene poi retropropagata attraverso il canale di rumore inverso, restituendo una nuova osservabile . Tre parametri chiave influenzano il costo di calcolo:
-
max_err_terms: il numero di termini mantenuti in ciascun generatore di anti-rumore mentre viene propagato in avanti. -
max_obs_terms: il numero di termini mantenuti in . -
atol: i termini con coefficiente di modulo inferiore a questa soglia vengono scartati.
Per questo piccolo circuito quasi-Clifford impostiamo limiti elevati sui termini e usiamo un atol modesto, così resta piccola e possiamo misurare tutti i suoi termini.
Nota: questa funzione usa il multiprocessing di Python. Quando viene eseguita come script, chiamala all'interno di una guardia if __name__ == "__main__":.
from qiskit_addon_pna import generate_noise_mitigating_observable
mitigating_observable = generate_noise_mitigating_observable(
noisy_circuit,
observable,
max_err_terms=100_000,
max_obs_terms=100_000,
atol=1e-5,
num_processes=4,
)
print(f"Original observable: {len(observable)} term")
print(f"Noise-mitigating observable: {len(mitigating_observable)} terms")
Original observable: 1 term
Noise-mitigating observable: 207 terms
3. Mitiga gli errori di gate misurando l'osservabile che mitiga il rumore
Qui vediamo che la nuova osservabile mitiga efficacemente il rumore di gate che affligge l'esperimento.
import matplotlib.pyplot as plt
from qiskit_aer.primitives import EstimatorV2
noiseless_circuit = ising_circuit(num_qubits, layers)
# density_matrix method at zero precision -> exact expectation values (no shot noise)
estimator = EstimatorV2(
options={
"backend_options": {"method": "density_matrix"},
"default_precision": 0.0,
}
)
ideal, noisy, mitigated = (
result.data.evs
for result in estimator.run(
[
(noiseless_circuit, observable),
(noisy_circuit, observable),
(noisy_circuit, mitigating_observable),
]
).result()
)
print(f"Ideal (noiseless): {ideal:.4f}")
print(f"Noisy (unmitigated): {noisy:.4f}")
print(f"Mitigated (PNA): {mitigated:.4f}")
fig, ax = plt.subplots()
ax.bar(
["Noisy", "Mitigated"],
[noisy, mitigated],
width=0.6,
color=["#b0b0b0", "#4c4c4c"],
)
ax.axhline(ideal, color="green", linestyle="--", label="Ideal (noiseless)")
ax.set_ylabel(r"$\langle Z_3 Z_4 Z_5 Z_6 \rangle$")
ax.legend()
plt.show()
Ideal (noiseless): 0.8073
Noisy (unmitigated): 0.6431
Mitigated (PNA): 0.8071