Cara menginterpretasikan visualisasi shaded lightcone
Paket ini menyediakan dua cara untuk melihat shaded lightcone:
-
draw_shaded_lightconemenumpangkan bound ke diagram circuit. Ini paling cocok untuk circuit pada rantai qubit 1D, di mana diagram circuit dan layout fisik sejalan. -
animate_shaded_lightconememproyeksikan bound ke coupling map QPU dan melangkah melalui circuit layer demi layer. Ini paling cocok ketika konektivitas qubit lebih dari garis 1D, di mana diagram circuit tidak lagi menunjukkan qubit mana yang bertetangga.
Kedua visualisasi menampilkan angka dasar yang sama. Panduan ini membahas arti angka-angka itu, dan menjelaskan detail yang gampang salah dibaca.
Penyiapan
Pakai circuit Ising hasil Trotterisasi dan observable yang sama dengan panduan quickstart.
# 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, PauliLindbladMap, QubitSparsePauliList
from qiskit_addon_slc.bounds import (
compute_backward_bounds,
compute_forward_bounds,
merge_bounds,
)
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
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
)
observable = Pauli("I" * num_qubits).compose("Z", [num_qubits // 2])
boxing_pass = generate_boxing_pass_manager(
inject_noise_targets="all",
inject_noise_strategy="individual_modification",
inject_noise_site="after",
twirling_strategy="active",
remove_barriers="never",
)
boxed_circuit = boxing_pass.run(circuit)
noise_model_paulis = generate_noise_model_paulis(
find_unique_box_instructions(boxed_circuit)
)
forward_bounds = compute_forward_bounds(
boxed_circuit, noise_model_paulis, observable
)
backward_bounds = compute_backward_bounds(boxed_circuit, noise_model_paulis)
rng = np.random.default_rng(42)
noise_rates = {
layer: PauliLindbladMap.from_components(
rng.random(len(terms)) * 5e-3,
QubitSparsePauliList.from_sparse_list(
terms.to_sparse_list(), terms.num_qubits
),
)
for layer, terms in noise_model_paulis.items()
}
merged_bounds = merge_bounds(
boxed_circuit, forward_bounds, backward_bounds, noise_rates
)
print(f"observable: Z on qubit {num_qubits // 2}")
Optimal spacetime partitioning not implemented! Just partitioning list of noisy boxes.
observable: Z on qubit 5
draw_shaded_lightcone
Setiap box yang noisy diberi bayangan sesuai bound error yang terjadi di sana: terang berarti bound besar, dan box yang memudar ke latar berarti error-nya berpengaruh kecil pada observable. Box yang memudar itu adalah kandidat untuk dibuang dari model noise yang dimitigasi.
from qiskit_addon_slc.visualization import draw_shaded_lightcone
draw_shaded_lightcone(
boxed_circuit, merged_bounds, noise_model_paulis, fold=-1, scale=0.5
)

Catatan penting
1. Setiap angka adalah jumlah dari suku error yang berbagi support yang sama. Tanpa filter, bound dari
setiap suku error yang bekerja pada qubit yang sama, atau pada pasangan qubit yang sama, dijumlahkan menjadi satu nilai:
ketiga tipe Pauli pada satu qubit, dan kesembilannya pada sepasang qubit. Ini punya dua konsekuensi. Sebuah nilai bisa
melebihi 2.0, padahal bound satu suku saja tidak mungkin (box berlabel 4.5 adalah beberapa suku yang dijumlahkan,
bukan bound yang dilanggar). Gambarnya juga tidak bisa memberi tahu apakah nilai besar berasal dari satu tipe
Pauli atau dari beberapa yang sebanding; bagian berikutnya menunjukkan cara memisahkannya.
2. Skala warna dimulai dari 2.0 dan tumbuh mengikuti data. Skalanya berjalan dari 0 sampai entri
"max_bound" di metadata circuit yang ditumpangi, yaitu yang lebih besar antara 2.0 dan nilai
terbesar yang ditampilkan. Jumlah tanpa filter sering melebihi 2.0, jadi skala melebar untuk menampungnya, dan warna
yang sama bisa mewakili nilai berbeda di gambar yang berbeda. Ketika semua nilai kecil,
skala tetap di 2.0 dan semuanya tampak gelap seragam (itu skala yang mencerminkan ukuran
absolut, bukan kesalahan render).
Memisahkan tipe Pauli
Pakai pauli_filter untuk melihat satu tipe pada satu waktu. Bilangan bulat memilih bobot Pauli; string memilih
Pauli tertentu, yang dicocokkan dengan setiap suku noise yang direduksi ke support non-identity miliknya sendiri. Jadi
"X" memilih setiap error satu-qubit, apa pun qubit tempatnya bekerja, dan "XX" memilih yang
berbobot 2 (label selebar penuh seperti "XII" tidak cocok dengan apa pun).
from qiskit_addon_slc.visualization import accumulate_filtered_bounds
box_id = next(iter(merged_bounds))
print(f"single-qubit supports of box {box_id!r}:\n")
print(f"{'filter':>8} bounds per qubit")
for pauli_filter in (None, 1, "X", "Y", "Z"):
filtered = accumulate_filtered_bounds(
boxed_circuit, merged_bounds, noise_model_paulis, pauli_filter
)
per_qubit = {
support[0]: round(float(bound), 3)
for support, bound in sorted(filtered[box_id].items())
if len(support) == 1
}
print(f"{pauli_filter!s:>8} {per_qubit}")
single-qubit supports of box 'm0':
filter bounds per qubit
None {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.312, 4: 1.355, 5: 5.111, 6: 1.506, 7: 0.124, 8: 0.019, 9: 0.0}
1 {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.312, 4: 1.355, 5: 5.111, 6: 1.506, 7: 0.124, 8: 0.019, 9: 0.0}
X {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.153, 4: 0.577, 5: 2.0, 6: 0.702, 7: 0.056, 8: 0.01, 9: 0.0}
Y {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.148, 4: 0.607, 5: 2.0, 6: 0.631, 7: 0.057, 8: 0.01, 9: 0.0}
Z {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.011, 4: 0.172, 5: 1.111, 6: 0.172, 7: 0.011, 8: 0.0, 9: 0.0}
Baris tanpa filter adalah jumlah dari ketiga tipe Pauli di bawahnya. Memfilter adalah satu-satunya cara untuk mengetahui apakah nilai besar tanpa filter berasal dari satu tipe error yang dominan atau dari beberapa yang sebanding. Itu penting, karena mitigasi bekerja per suku, bukan per site.
Memberikan filter yang sama ke draw_shaded_lightcone mencatatnya di judul gambar, sehingga gambar
yang difilter tidak bisa tertukar dengan yang tanpa filter:
draw_shaded_lightcone(
boxed_circuit,
merged_bounds,
noise_model_paulis,
pauli_filter="X",
fold=-1,
scale=0.5,
)

Gambar ini tampak cukup berbeda dari yang tanpa filter di atas, dan bukan hanya karena menampilkan
lebih sedikit nilai. Setiap placeholder di gambar-gambar ini mewakili satu support: satu qubit, atau sepasang
qubit. Tanpa filter, sebuah box menampilkan placeholder di setiap qubit dan di setiap pasangan qubit
bertetangga, jadi ia melebar ke beberapa kolom. Dengan "X", hanya support satu-qubit yang tersisa, dan
setiap box menyusut menjadi satu kolom.
Tapi kedua gambar itu tidak menunjukkan apa yang sebenarnya diterapkan PEC. Placeholder-nya hanyalah cara untuk menampilkan batas (bound), bukan gate anti-noise. Selama eksperimen, setiap kotak yang suku error-nya dimitigasi diperlakukan sebagai satu layer gate dua qubit, dan Pauli anti-noise yang disampel untuk suku error-nya digabung menjadi satu Pauli yang diterapkan ke layer tersebut secara keseluruhan.
animate_shaded_lightcone
Pada perangkat yang konektivitasnya bukan garis 1D, diagram circuit tidak lagi menunjukkan qubit mana yang bertetangga, sehingga sebaran spasial lightcone jadi mustahil dibaca. animate_shaded_lightcone justru menggambar coupling map QPU dan menganimasikan bound di atasnya, satu kotak berisik (noisy box) per frame.
Fungsi ini membutuhkan CouplingMap, yang ditata di atas grid dengan cara menanamkan graf perangkat, sehingga bisa menangani konektivitas heavy-hex maupun persegi.
Catatan: Di dokumentasi yang sudah dirender ini, animasinya statis. Slider dan tombol play hanya berfungsi saat notebook dijalankan secara interaktif, misalnya di Jupyter.
from qiskit import transpile
from qiskit.transpiler import CouplingMap
from qiskit_addon_slc.visualization import animate_shaded_lightcone
# A small square-lattice device stands in for a real backend here.
coupling_map = CouplingMap.from_grid(3, 4)
# Lay the chain onto a connected path of physical qubits, snaking through the grid, so the
# transpiler inserts no SWAPs: a SWAP-laden circuit is far more expensive to bound and harder to
# read.
initial_layout = [0, 1, 2, 3, 7, 6, 5, 4, 8, 9]
device_circuit = transpile(
circuit,
coupling_map=coupling_map,
initial_layout=initial_layout,
optimization_level=0,
)
boxed_device_circuit = boxing_pass.run(device_circuit)
device_noise_paulis = generate_noise_model_paulis(
find_unique_box_instructions(boxed_device_circuit),
coupling_map=coupling_map,
circuit=boxed_device_circuit,
)
# The same observable, on the physical qubit the middle of the chain was laid onto.
device_observable = Pauli("I" * device_circuit.num_qubits).compose(
"Z", [initial_layout[num_qubits // 2]]
)
device_bounds = compute_forward_bounds(
boxed_device_circuit, device_noise_paulis, device_observable
)
animate_shaded_lightcone(boxed_device_circuit, device_bounds, coupling_map)

Membaca animasi
Setiap qubit adalah diagram pai, satu irisan per jenis Pauli. Penanda sebuah qubit dibagi menjadi tiga irisan untuk error , , dan -nya, masing-masing diberi warna sesuai bound-nya sendiri. Ini adalah penyaringan dari bagian sebelumnya yang sudah tertanam di dalam gambar (tidak perlu pauli_filter untuk membedakan jenisnya).
Edge membawa bound error dua qubit. Garis di antara dua qubit yang terhubung diberi warna sesuai bound untuk error berbobot 2 yang bekerja pada pasangan tersebut.
Abu-abu muda berarti tidak ada data, bukan bound yang kecil. Sebuah irisan atau edge digambar abu-abu muda ketika model noise kotak tersebut tidak punya suku error untuknya, misalnya pada qubit yang tidak dikenai operasi oleh kotak itu. Warnanya abu-abu, bukan gelap, supaya tidak tertukar dengan bound nol. Kotak di luar batas max_num_boxes berbeda: kotak-kotak itu membawa bound trivial 2.0, jadi digambar di ujung terang skala.
Slider melangkah per kotak, bukan per waktu secara seragam. Ada satu frame per noisy box, sesuai urutan circuit (atau urutan terbalik dengan reverse=True, yang menelusuri lightcone mundur dari observable). Menontonnya dalam urutan terbalik biasanya arah yang lebih intuitif: kerucutnya melebar keluar dari qubit yang diukur. Setiap frame diberi label identifier kotaknya, yaitu kunci yang sama yang dipakai dictionary bound untuk menyimpan kotak itu, jadi slider juga bisa dipakai untuk melompat ke kotak tertentu dan melihat angkanya.
Catatan: Tata letak qubit dipulihkan dari graf coupling map dengan menanamkannya ke dalam kisi persegi. Coupling map yang tidak bisa ditanamkan (karena terputus, atau terlalu padat terhubung untuk sebuah grid) akan memunculkan ValueError daripada menggambar gambar yang menyesatkan.
Mana yang dipakai
draw_shaded_lightcone | animate_shaded_lightcone | |
|---|---|---|
| geometri | diagram circuit | coupling map QPU |
| paling cocok untuk | rantai 1D | konektivitas apa pun |
| jenis Pauli | dijumlahkan, kecuali difilter | selalu dipisah, sebagai irisan pai |
| waktu | semua layer sekaligus | satu layer per frame |
| output | figure matplotlib | figure plotly |
Untuk rantai 1D, gambar statis lebih mudah dipahami sekilas dan bisa direproduksi di makalah. Di luar 1D, animasi adalah satu-satunya dari kedua opsi yang menampilkan struktur spasial dengan setia.