Démarrage rapide
title: Démarrage rapide description: Un guide de démarrage rapide pour l'addon Qiskit Shaded lightcones (qiskit-addon-slc)
Ce guide présente un exemple minimal fonctionnel du package qiskit-addon-slc. Il calcule un cône de lumière ombré pour réduire le coût d'échantillonnage de l'annulation probabiliste des erreurs (PEC).
PEC atténue le bruit des portes en échantillonnant une décomposition en quasi-probabilités du canal de bruit inverse. Son coût d'échantillonnage croît avec chaque terme d'erreur à atténuer ; cependant, toutes les erreurs n'affectent pas l'observable de la même façon. Une erreur située en dehors du cône de lumière causal de l'observable ne peut pas influencer la valeur moyenne mesurée, et même à l'intérieur du cône de lumière, certaines erreurs sont plus néfastes que d'autres. Un cône de lumière ombré quantifie cela en bornant l'effet de chaque terme d'erreur de Pauli sur l'observable. Tronquer les termes d'erreur ayant le plus faible effet réduit le modèle de bruit que PEC doit atténuer, ce qui diminue le coût d'échantillonnage en échange d'un petit biais borné.
Pour voir comment construire un workflow réaliste et l'exécuter sur du matériel quantique, consulte le tutoriel Annulation probabiliste des erreurs avec des cônes de lumière ombrés sur IBM Quantum Platform.
1. Préparer les entrées pour SLC
Commence par construire un circuit d'Ising à champ transverse trotterisé de 10 qubits et choisis une observable à un qubit sur le qubit du milieu.
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"numpy": "numpy", "qiskit": "qiskit", "qiskit_addon_slc": "qiskit-addon-slc", "samplomatic": "samplomatic"}
_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 Pauli
def trotter_ising_circuit(num_qubits, num_steps, rx_angle, rzz_angle):
"""Trotterized transverse-field Ising evolution on a 1D chain."""
circuit = QuantumCircuit(num_qubits)
for _ in range(num_steps):
circuit.rx(rx_angle, range(num_qubits))
circuit.barrier()
for start in (0, 1): # even then odd bonds
for i in range(start, num_qubits - 1, 2):
circuit.rzz(rzz_angle, i, i + 1)
circuit.barrier()
return circuit
num_qubits = 10
circuit = trotter_ising_circuit(
num_qubits, num_steps=4, rx_angle=np.pi / 16, rzz_angle=-np.pi / 3
)
# Measure <Z> on the middle qubit
observable = Pauli("I" * num_qubits).compose("Z", [num_qubits // 2])
print(f"Observable: {observable}")
circuit.draw("mpl", fold=-1, scale=0.7)
Observable: IIIIZIIIII

SLC opère sur les couches bruitées de portes à deux qubits du circuit. Ici, nous utilisons samplomatic pour regrouper les portes en boîtes annotées et attacher une annotation d'injection de bruit à chaque couche à deux qubits. SLC exige que chaque boîte bruitée ait un modifier_ref unique, ce que fournit inject_noise_strategy="individual_modification" ; avec la stratégie par défaut de samplomatic, les bornes sont fausses ou leur calcul ne se termine jamais. generate_noise_model_paulis énumère ensuite les termes d'erreur de Pauli de chaque couche bruitée unique.
from qiskit_addon_slc.utils import generate_noise_model_paulis
from samplomatic.transpiler import generate_boxing_pass_manager
from samplomatic.utils import find_unique_box_instructions
# Group gates into boxes and annotate each two-qubit layer with a noise-injection point
boxing_pass = generate_boxing_pass_manager(
inject_noise_targets="all",
inject_noise_strategy="individual_modification", # required: one modifier_ref per box
inject_noise_site="after",
twirling_strategy="active",
remove_barriers="never",
)
boxed_circuit = boxing_pass.run(circuit)
# Enumerate the 1- and 2-weight Pauli error terms of each unique noisy layer
noise_model_paulis = generate_noise_model_paulis(
find_unique_box_instructions(boxed_circuit)
)
num_terms = sum(len(paulis) for paulis in noise_model_paulis.values())
print(f"Noisy layers: {len(noise_model_paulis)}")
print(f"Pauli error terms across all layers: {num_terms}")
Noisy layers: 2
Pauli error terms across all layers: 198
2. Calculer le cône de lumière ombré
Le cône de lumière ombré est assemblé en attribuant une échelle à chaque terme d'erreur de Pauli du modèle de bruit selon l'effet qu'il a sur la valeur moyenne de l'observable. Ces échelles sont dérivées des bornes d'erreur avant et arrière de chaque terme d'erreur (décrites ci-dessous), ainsi que de son taux d'erreur :
-
compute_forward_boundsfait évoluer chaque terme d'erreur vers l'avant jusqu'à la fin du circuit pour borner son effet sur l'observable mesurée à cet endroit. -
compute_backward_boundsfait évoluer chaque terme d'erreur vers l'arrière jusqu'au début du circuit pour borner son effet sur l'état initial.
merge_bounds combine les deux en une seule borne par terme d'erreur. Chaque borne est mise à l'échelle par le taux d'erreur du terme. Ces taux proviennent généralement d'une expérience d'apprentissage du bruit (comme NoiseLearnerV3) ; ce guide utilise des taux aléatoires pour plus de simplicité.
from qiskit.quantum_info import PauliLindbladMap, QubitSparsePauliList
from qiskit_addon_slc.bounds import (
compute_backward_bounds,
compute_forward_bounds,
merge_bounds,
)
forward_bounds = compute_forward_bounds(
boxed_circuit, noise_model_paulis, observable
)
backward_bounds = compute_backward_bounds(boxed_circuit, noise_model_paulis)
# Stand-in for rates that would be measured by a noise-learning experiment on hardware
rng = np.random.default_rng(42)
noise_rates = {
layer_id: PauliLindbladMap.from_components(
rng.random(len(paulis)) * 5e-3,
QubitSparsePauliList.from_sparse_list(
paulis.to_sparse_list(), paulis.num_qubits
),
)
for layer_id, paulis in noise_model_paulis.items()
}
merged_bounds = merge_bounds(
boxed_circuit, forward_bounds, backward_bounds, noise_rates
)
Optimal spacetime partitioning not implemented!Just partitioning list of noisy boxes.
Dans la visualisation du cône de lumière ombré ci-dessous, chaque boîte est ombrée selon la force avec laquelle les erreurs à cet endroit peuvent affecter l'observable. Les boîtes claires portent les plus grandes bornes, tandis que les boîtes qui se fondent dans l'arrière-plan contiennent des termes d'erreur ayant peu d'effet sur le calcul -- ces erreurs sont des candidates naturelles pour être retirées du modèle de bruit. Les valeurs de la visualisation ci-dessous représentent des sommes des bornes d'erreur de toutes les erreurs de Pauli à cet endroit, ce qui explique pourquoi certaines valeurs dépassent 2.0, la borne pour une seule erreur de Pauli.
from qiskit_addon_slc.visualization import draw_shaded_lightcone
draw_shaded_lightcone(
boxed_circuit, merged_bounds, noise_model_paulis, fold=-1, scale=0.5
)

3. Réduire le coût d'échantillonnage
compute_local_scales transforme le cône de lumière ombré en une configuration PEC concrète. Elle priorise les termes d'erreur selon leur effet borné sur l'observable et tronque les moins influents jusqu'à atteindre le bias_tolerance demandé. Elle renvoie des échelles pour chaque terme d'erreur : 0.0 pour les termes à ignorer pendant l'atténuation et -1.0 pour les termes à atténuer. La fonction renvoie aussi le surcoût de coût d'échantillonnage () qui en résulte et une borne sur le biais résiduel induit par la troncature.
Définir bias_tolerance=0.0 atténue tous les termes d'erreur situés dans le cône de lumière causal de l'observable et donne un coût d'échantillonnage de référence. Autoriser un petit biais permet à SLC d'abandonner les termes à faible impact et de réduire encore ce coût.
from qiskit_addon_slc.bounds import compute_local_scales
_, full_cost, full_bias = compute_local_scales(
boxed_circuit, merged_bounds, noise_rates, bias_tolerance=0.0
)
local_scales, reduced_cost, reduced_bias = compute_local_scales(
boxed_circuit, merged_bounds, noise_rates, bias_tolerance=0.05
)
print(
f"Full PEC (bias_tolerance=0.0) : sampling cost {full_cost:6.3f}, residual bias {full_bias:5.3f}"
)
print(
f"Shaded (bias_tolerance=0.05): sampling cost {reduced_cost:6.3f}, residual bias {reduced_bias:5.3f}"
)
print(
f"\nSampling-cost reduction: {(1 - reduced_cost / full_cost):.0%} for <= 0.05 bias"
)
Full PEC (bias_tolerance=0.0) : sampling cost 21.206, residual bias 0.000
Shaded (bias_tolerance=0.05): sampling cost 5.403, residual bias 0.049
Sampling-cost reduction: 75% for <= 0.05 bias