Inicio rápido
Esta guía muestra un ejemplo mínimo funcional del paquete qiskit-addon-pna. Usamos la absorción de ruido propagado (PNA) para construir un observable que mitiga el ruido. Dado un circuito y un modelo de ruido de Pauli-Lindblad, PNA propaga clásicamente el observable a través del canal de ruido inverso. Medir el observable resultante en la QPU ruidosa mitiga el ruido de puertas aprendido.
Para ver cómo construir un flujo de trabajo realista y ejecutarlo en hardware cuántico con el modelo de ejecución dirigida, incluido el aprendizaje del modelo de ruido con NoiseLearnerV3, consulta el tutorial de PNA en IBM Quantum Platform.
1. Prepara las entradas para PNA
PNA toma como entrada un circuito, un modelo de ruido y un observable. Aquí construimos un modelo de Ising de campo transversal trotterizado de 10 qubits en una cadena 1D. Generamos un modelo de ruido de Pauli-Lindblad aleatorio de 2 locales para cada puerta entrelazante y lo incrustamos como una instrucción PauliLindbladError de Qiskit Aer justo antes de esa puerta. Elegimos para medir un observable de Pauli-Z de 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 el observable que mitiga el ruido
generate_noise_mitigating_observable propaga hacia delante hasta el final del circuito cada generador de Pauli del canal de ruido inverso. Después, el observable se retropropaga a través del canal de ruido inverso, lo que devuelve un nuevo observable . Tres parámetros clave afectan al coste de cálculo:
-
max_err_terms: el número de términos que se conservan en cada generador de antirruido a medida que se propaga hacia delante. -
max_obs_terms: el número de términos que se conservan en . -
atol: se descartan los términos cuya magnitud de coeficiente está por debajo de este umbral.
Para este circuito pequeño y casi Clifford, fijamos límites altos para los términos y usamos un atol modesto, de modo que se mantiene pequeño y podemos medir todos sus términos.
Nota: esta función usa multiprocessing de Python. Al ejecutarla como script, llámala dentro de una protección 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 los errores de puertas midiendo el observable que mitiga el ruido
Aquí vemos que el nuevo observable mitiga eficazmente el ruido de puertas que afecta al experimento.
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