วิธีตีความภาพแสดงผล shaded lightcone
แพ็กเกจมีสองวิธีในการดู shaded lightcone:
-
draw_shaded_lightconeวางขอบเขตทับบนแผนภาพ circuit เหมาะที่สุดสำหรับ circuit บนโซ่ qubit 1 มิติ ที่แผนภาพ circuit และเลย์เอาต์ทางกายภาพตรงกัน -
animate_shaded_lightconeฉายขอบเขตลงบน coupling map ของ QPU และไล่ดูทีละ เลเยอร์ของ circuit เหมาะที่สุดเมื่อการเชื่อมต่อของ qubit มากกว่าเส้น 1 มิติ ที่แผนภาพ circuit บอกไม่ได้ว่า qubit ใดเป็นเพื่อนบ้านกัน
ภาพแสดงผลทั้งสองแสดงตัวเลขเบื้องหลังชุดเดียวกัน คู่มือนี้อธิบายความหมายของตัวเลขเหล่านั้น และอธิบายรายละเอียด ที่อ่านผิดได้ง่าย
การตั้งค่า
ใช้ circuit Ising แบบ Trotter และ observable เดียวกับคู่มือเริ่มต้นอย่างรวดเร็ว
# 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
แต่ละ box ที่มีสัญญาณรบกวนถูกแรเงาตามขอบเขตของความคลาดเคลื่อนที่เกิดขึ้นตรงนั้น: สว่างหมายถึงขอบเขตใหญ่ และ box ที่จางหายไปในพื้นหลังหมายถึงความคลาดเคลื่อนของมันมีผลต่อ observable น้อย box ที่จาง เหล่านั้นคือตัวเลือกที่จะถูกตัดออกจากโมเดลสัญญาณรบกวนที่ผ่านการลดผลกระทบ
from qiskit_addon_slc.visualization import draw_shaded_lightcone
draw_shaded_lightcone(
boxed_circuit, merged_bounds, noise_model_paulis, fold=-1, scale=0.5
)

หมายเหตุสำคัญ
1. แต่ละตัวเลขคือผลรวมของเทอมความคลาดเคลื่อนที่ใช้ support ร่วมกัน หากไม่มีตัวกรอง ขอบเขตของ
ทุกเทอมความคลาดเคลื่อนที่กระทำกับ qubit เดียวกัน หรือคู่ qubit เดียวกัน จะถูกบวกรวมเป็นค่าเดียว:
ทั้งสามชนิด Pauli บน qubit หนึ่ง และทั้งเก้าบนหนึ่งคู่ ซึ่งมีผลสองอย่าง ค่าหนึ่งอาจ
เกิน 2.0 แม้ขอบเขตของเทอมเดี่ยวจะเกินไม่ได้ (box ที่ติดป้าย 4.5 คือหลายเทอมบวกกัน
ไม่ใช่ขอบเขตที่ถูกละเมิด) และภาพบอกคุณไม่ได้ว่าค่าที่ใหญ่มาจาก Pauli ชนิดเดียว
หรือจากหลายชนิดที่เทียบเคียงกัน ส่วนถัดไปแสดงวิธีแยกพวกมัน
2. สเกลสีเริ่มที่ 2.0 และโตตามข้อมูล สเกลวิ่งจาก 0 ถึงรายการ
"max_bound" ในเมทาดาทาของ circuit ที่วางทับ ซึ่งเป็นค่าที่มากกว่าระหว่าง 2.0 กับ
ค่าที่แสดงมากที่สุด ผลรวมที่ไม่กรองมักเกิน 2.0 สเกลจึงยืดให้พอดี และสีเดียวกัน
อาจแทนค่าต่างกันในภาพต่างกัน เมื่อทุกค่าเล็ก
สเกลจะอยู่ที่ 2.0 และทุกอย่างดูมืดสม่ำเสมอ (นั่นคือสเกลที่สะท้อนขนาดสัมบูรณ์
ไม่ใช่ข้อบกพร่องในการแสดงผล)
การแยกชนิด Pauli
ใช้ pauli_filter เพื่อดูทีละชนิด จำนวนเต็มเลือกน้ำหนัก Pauli สตริงเลือก
Pauli เฉพาะ โดยจับคู่กับแต่ละเทอมสัญญาณรบกวน ที่ลดเหลือ support ที่ไม่ใช่เอกลักษณ์ของมันเอง ดังนั้น
"X" เลือกทุกความคลาดเคลื่อน แบบ qubit เดียว ไม่ว่ากระทำกับ qubit ใด และ "XX" เลือก
ตัวที่มีน้ำหนัก 2 (ป้ายความกว้างเต็มอย่าง "XII" ไม่ตรงกับอะไรเลย)
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}
แถวที่ไม่กรองคือผลรวมของ Pauli สามชนิดด้านล่างมัน การกรองเป็นวิธีเดียวที่จะบอกได้ ว่าค่าที่ไม่กรองที่ใหญ่มาจากความคลาดเคลื่อนชนิดเด่นเพียงชนิดเดียว หรือจากหลายชนิดที่เทียบเคียงกัน ซึ่งสำคัญ เพราะการลดผลกระทบทำงานต่อเทอม ไม่ใช่ต่อตำแหน่ง
การส่งตัวกรองเดียวกันให้ draw_shaded_lightcone จะบันทึกมันไว้ในชื่อภาพ ภาพที่กรอง
จึงไม่ถูกเข้าใจผิดว่าเป็นภาพที่ไม่กรอง:
draw_shaded_lightcone(
boxed_circuit,
merged_bounds,
noise_model_paulis,
pauli_filter="X",
fold=-1,
scale=0.5,
)

ภาพนี้ดูต่างจากภาพที่ไม่กรองข้างบนมาก และไม่ใช่เพียงเพราะแสดงค่าน้อยกว่า แต่ละ placeholder ในภาพเหล่านี้
แทนหนึ่ง support: qubit เดียว หรือคู่ qubit หนึ่งคู่ หากไม่มีตัวกรอง box จะแสดง placeholder บนทุก qubit และทุกคู่
ของ qubit ที่อยู่ติดกัน จึงกระจายหลายคอลัมน์ เมื่อใช้ "X" จะเหลือเฉพาะ support แบบ qubit เดียว และ
แต่ละ box หดเหลือคอลัมน์เดียว
แต่ภาพทั้งสองไม่ได้แสดงสิ่งที่ PEC ใช้จริง ๆ ตัวแทนเหล่านี้เป็นเพียงวิธีแสดงค่าขอบเขต ไม่ใช่ anti-noise gate ระหว่างการทดลอง กล่องทุกกล่องที่มีการลดข้อผิดพลาดของ error term จะถูกมองเป็น layer ของ two-qubit gate เพียงชั้นเดียว และ anti-noise Pauli ที่สุ่มมาสำหรับ error term ของกล่องนั้นจะถูกรวมเป็น Pauli ตัวเดียวที่ใช้กับ layer นั้นทั้งชั้น
animate_shaded_lightcone
บนอุปกรณ์ที่ connectivity ไม่ใช่เส้น 1D แผนภาพ circuit จะไม่แสดงอีกต่อไปว่า qubit ตัวไหนอยู่ติดกัน ทำให้อ่านการแผ่ขยายเชิงพื้นที่ของ lightcone ไม่ได้
animate_shaded_lightcone จึงวาด coupling map ของ QPU แล้วทำแอนิเมชันค่าขอบเขตบนแผนที่นั้น
โดยแสดงหนึ่ง noisy box ต่อหนึ่งเฟรม
ฟังก์ชันนี้ต้องใช้ CouplingMap ซึ่งมันจะจัดวางบนกริดโดยการฝัง graph ของอุปกรณ์ จึงรองรับได้ทั้ง
heavy-hex และ square connectivity
หมายเหตุ: ในเอกสารที่เรนเดอร์นี้ แอนิเมชันเป็นภาพนิ่ง สไลเดอร์และปุ่มเล่นจะใช้งานได้ เฉพาะตอนรัน notebook แบบโต้ตอบ เช่นใน 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)

วิธีอ่านแอนิเมชัน
qubit แต่ละตัวคือ pie chart หนึ่งชิ้นต่อหนึ่งชนิดของ Pauli เครื่องหมายของ qubit แบ่งเป็นสามชิ้นสำหรับข้อผิดพลาด , และ โดยแต่ละชิ้นถูกแรเงาตามค่าขอบเขตของตัวเอง นี่คือการกรองจากหัวข้อก่อนหน้าที่ฝังอยู่ในภาพเลย (ไม่ต้องใช้ pauli_filter เพื่อแยกชนิด)
เส้นเชื่อมแสดงค่าขอบเขตข้อผิดพลาดแบบ two-qubit เส้นระหว่าง qubit สองตัวที่เชื่อมต่อกันจะถูกแรเงาตาม ค่าขอบเขตของข้อผิดพลาด weight-2 ที่เกิดกับคู่นั้น
สีเทาอ่อนหมายถึงไม่มีข้อมูล ไม่ใช่ค่าขอบเขตที่เล็ก ชิ้นหรือเส้นเชื่อมจะเป็นสีเทาอ่อนเมื่อ
noise model ของกล่องไม่มี error term สำหรับมัน เช่นบน qubit ที่กล่องไม่ได้ทำงานด้วย ที่ใช้สีเทา
แทนสีเข้มก็เพื่อไม่ให้สับสนกับค่าขอบเขตที่เป็นศูนย์ ส่วนกล่องที่เกินขีดจำกัด
max_num_boxes จะต่างออกไป: กล่องเหล่านั้นมีค่าขอบเขตแบบ trivial เท่ากับ 2.0 จึงถูกวาดที่
ปลายสว่างของสเกล
สไลเดอร์เดินทีละกล่อง ไม่ได้เดินตามเวลาอย่างสม่ำเสมอ มีหนึ่งเฟรมต่อหนึ่ง noisy box ตามลำดับของ
circuit (หรือลำดับย้อนกลับด้วย reverse=True ซึ่งไล่ lightcone ย้อนจาก
observable) การดูแบบย้อนกลับมักเป็นทิศทางที่เข้าใจง่ายกว่า: กรวยจะขยายออก
จาก qubit ที่ถูกวัด แต่ละเฟรมมีป้ายระบุตัวระบุของกล่อง ซึ่งเป็นคีย์เดียวกับที่
พจนานุกรมค่าขอบเขตใช้เก็บกล่องนั้น ดังนั้นจึงใช้สไลเดอร์เพื่อกระโดดไปยัง
กล่องที่ต้องการและดูตัวเลขของมันได้ด้วย
หมายเหตุ: การจัดวาง qubit ถูกกู้คืนจาก graph ของ coupling map โดยฝังลงใน square
lattice ถ้า coupling map ฝังไม่ได้ (เพราะไม่เชื่อมต่อกัน หรือเชื่อมต่อหนาแน่นเกินไป
สำหรับกริด) จะเกิด ValueError แทนที่จะวาดภาพที่ทำให้เข้าใจผิด
เลือกใช้แบบไหน
draw_shaded_lightcone | animate_shaded_lightcone | |
|---|---|---|
| รูปทรงเรขาคณิต | แผนภาพ circuit | coupling map ของ QPU |
| เหมาะที่สุดสำหรับ | chain 1D | connectivity แบบใดก็ได้ |
| ชนิด Pauli | รวมกัน เว้นแต่จะกรอง | แยกเสมอ เป็นชิ้น pie |
| เวลา | ทุก layer พร้อมกัน | หนึ่ง layer ต่อเฟรม |
| เอาต์พุต | figure ของ matplotlib | figure ของ plotly |
สำหรับ chain 1D ภาพนิ่งดูเข้าใจได้ง่ายในพริบตาและนำไปใช้ในบทความได้ เมื่อเกิน 1D แอนิเมชันคือสองแบบที่แสดงโครงสร้างเชิงพื้นที่ได้อย่างถูกต้องเพียงแบบเดียว