انتقل إلى المحتوى الرئيسي
هذا المشروع في مرحلة تجريبية. وجدت خطأ؟ افتح مشكلة على GitHub. لديك سؤال أو فكرة؟ اسأل في Discussions — نحب سماع ملاحظاتك!
كيف جودة الترجمة في هذه الصفحة؟

كيفية تفسير تصورات shaded lightcone

الحزمة توفر طريقتين للنظر إلى shaded lightcone:

  • draw_shaded_lightcone يرسم الحدود فوق مخطط الدائرة. وهو الأفضل للدوائر على سلسلة أحادية البعد من الكيوبتات، حيث يتطابق مخطط الدائرة مع التخطيط الفيزيائي.

  • animate_shaded_lightcone يسقط الحدود على خريطة الربط (coupling map) الخاصة بـ QPU ويمرّ على الدائرة طبقة بطبقة. وهو الأفضل عندما يكون ربط الكيوبتات أكثر من خط أحادي البعد، حيث لا يعود مخطط الدائرة ينقل أي الكيوبتات جيران.

كلا التصورين يعرضان نفس الأرقام الأساسية. هذا الدليل يغطي معنى هذه الأرقام، ويشرح التفاصيل التي يسهل إساءة قراءتها.

الإعداد​

استخدم نفس دائرة Ising المقسّمة بطريقة Trotter ونفس المرصودة المستخدمة في دليل البدء السريع.

# 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​

كل صندوق ضوضائي يُظلَّل حسب الحد على الأخطاء الحاصلة فيه: السطوع يعني حدًا كبيرًا، والصندوق الذي يبهت في الخلفية يعني أن أخطاءه لها أثر قليل على المرصودة. هذه الصناديق الباهتة هي المرشحة للإسقاط من نموذج الضوضاء المخفَّف.

from qiskit_addon_slc.visualization import draw_shaded_lightcone

draw_shaded_lightcone(
boxed_circuit, merged_bounds, noise_model_paulis, fold=-1, scale=0.5
)

Output of the previous code cell

ملاحظات مهمة​

1. كل رقم هو مجموع على حدود الخطأ التي تتشارك نفس الدعم. بدون مرشّح، تُجمع حدود كل حد خطأ يعمل على نفس الكيوبت، أو على نفس زوج الكيوبتات، في قيمة واحدة: كل أنواع باولي الثلاثة على كيوبت، وكل التسعة على زوج. وهذا له نتيجتان. القيمة يمكن أن تتجاوز 2.0، رغم أن حد أي حد واحد لا يمكن أن يتجاوزها (صندوق عليه 4.5 هو عدة حدود مجموعة، وليس حدًا منتهكًا). والشكل لا يقدر يخبرك إذا كانت القيمة الكبيرة جاية من نوع باولي واحد أو من عدة أنواع متقاربة؛ القسم التالي يوضح كيف تفصل بينها.

2. مقياس الألوان يبدأ من 2.0 ويكبر مع البيانات. المقياس يمتد من 0 إلى مدخل "max_bound" في بيانات وصفية للدائرة المغطاة، وهو الأكبر بين 2.0 وأكبر قيمة معروضة. المجاميع غير المرشّحة كثيرًا ما تتجاوز 2.0، فيتمدد المقياس ليستوعبها، ونفس اللون قد يمثل قيمًا مختلفة في أشكال مختلفة. وعندما تكون كل القيم صغيرة، يبقى المقياس عند 2.0 ويبدو كل شيء داكنًا بشكل موحد (هذا هو المقياس يعكس الحجم المطلق، وليس خللًا في الرسم).

فصل أنواع باولي​

استخدم pauli_filter لترى نوعًا واحدًا كل مرة. العدد الصحيح يختار وزن باولي؛ والسلسلة النصية تختار مصفوفة باولي محددة، تُطابَق مع كل حد ضوضاء مختزل إلى دعمه غير الهوية الخاص به. فـ "X" يختار كل أخطاء XX أحادية الكيوبت، بغض النظر عن الكيوبت الذي تعمل عليه، و"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}

الصف غير المرشّح هو مجموع أنواع باولي الثلاثة تحته. التصفية هي الطريقة الوحيدة لمعرفة إذا كانت قيمة كبيرة غير مرشّحة جاية من نوع خطأ مهيمن واحد أو من عدة أنواع متقاربة. وهذا مهم، لأن التخفيف يعمل لكل حد، وليس لكل موقع.

تمرير نفس المرشّح إلى draw_shaded_lightcone يسجّله في عنوان الشكل، فلا يمكن الخلط بين شكل مرشّح وشكل غير مرشّح:

draw_shaded_lightcone(
boxed_circuit,
merged_bounds,
noise_model_paulis,
pauli_filter="X",
fold=-1,
scale=0.5,
)

Output of the previous code cell

هذا الشكل يبدو مختلفًا كثيرًا عن الشكل غير المرشّح أعلاه، وليس فقط لأنه يعرض قيمًا أقل. كل عنصر نائب في هذه الأشكال يمثل دعمًا واحدًا: كيوبتًا واحدًا، أو زوجًا من الكيوبتات. بدون مرشّح، يعرض الصندوق عنصرًا نائبًا على كل كيوبت وعلى كل زوج من الكيوبتات المتجاورة، فيمتد على عدة أعمدة. ومع "X"، لا تبقى إلا الدعامات أحادية الكيوبت، ويتقلص كل صندوق إلى عمود واحد.

ومع ذلك، لا تُظهر أي من الصورتين ما تطبّقه PEC فعلاً. العناصر النائبة مجرد طريقة لعرض الحدود، وليست بوابات مضادة للضوضاء. أثناء التجربة، يُعامَل كل صندوق تم تخفيف حدود الخطأ فيه على أنه طبقة واحدة من البوابات ثنائية الكيوبت، وتُركَّب عمليات باولي المضادة للضوضاء التي أُخذت عيّنات منها لحدود الخطأ فيه في عملية باولي واحدة تُطبَّق على تلك الطبقة ككل.

animate_shaded_lightcone​

على جهاز لا يكون ترابطه خطاً أحادي البُعد، لا يعود مخطط الدارة يُظهر أي الكيوبتات متجاورة، فيصبح من المستحيل قراءة الانتشار المكاني لمخروط الضوء. لذلك يرسم animate_shaded_lightcone خريطة الاقتران الخاصة بـ QPU ويحرّك الحدود عبرها، بمعدل صندوق ضوضاء واحد لكل إطار.

يحتاج إلى CouplingMap، ويرتّبها على شبكة عن طريق تضمين رسم الجهاز البياني، لذا يتعامل مع الترابط السداسي الثقيل والمربّع على حد سواء.

ملاحظة: في هذا التوثيق المعروض يكون الرسم المتحرك ثابتاً. لا يعمل شريط التمرير وزر التشغيل إلا عند تشغيل الدفتر بشكل تفاعلي، مثلاً في 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)

Output of the previous code cell

قراءة الرسم المتحرك​

كل كيوبت عبارة عن مخطط دائري، بشريحة واحدة لكل نوع باولي. يُقسَّم رمز الكيوبت إلى ثلاث شرائح لأخطاء XX وYY وZZ، وكل شريحة مظلَّلة وفق حدّها الخاص. هذا هو الترشيح من القسم السابق مدمجاً في الشكل (لا حاجة إلى pauli_filter للتمييز بين الأنواع).

الحواف تحمل حدود الأخطاء ثنائية الكيوبت. الخط بين كيوبتين مقترنين مظلَّل وفق الحد الأعلى لأخطاء الوزن 2 المؤثرة على ذلك الزوج.

الرمادي الفاتح يعني عدم وجود بيانات، وليس حداً صغيراً. تُرسم الشريحة أو الحافة بالرمادي الفاتح عندما لا يحتوي نموذج ضوضاء الصندوق على حد خطأ لها، مثلاً على الكيوبتات التي لا يعمل عليها الصندوق. تُرسم رمادية وليست داكنة كي لا تُلتبس بحد يساوي صفراً. أما الصناديق التي تتجاوز حد max_num_boxes فهي مختلفة: فهي تحمل الحد التافه 2.0، لذلك تُرسم عند الطرف الساطع من المقياس.

شريط التمرير يتنقّل بين الصناديق، وليس عبر الزمن بانتظام. يوجد إطار واحد لكل صندوق ضوضاء، بترتيب الدارة (أو بالترتيب العكسي مع reverse=True، الذي يتتبع مخروط الضوء عكسياً من المرصود). مشاهدته بالعكس هي عادةً الاتجاه الأكثر بداهة: يتّسع المخروط نحو الخارج من الكيوبتات المقيسة. يحمل كل إطار معرّف صندوقه، وهو المفتاح نفسه الذي يخزّن به قاموس الحدود ذلك الصندوق، لذا يمكن أيضاً استخدام شريط التمرير للقفز إلى صندوق معيّن والاطلاع على أرقامه.

ملاحظة: يُستعاد ترتيب الكيوبتات من الرسم البياني لخريطة الاقتران بتضمينه في شبكة مربعة. خريطة الاقتران التي لا يمكن تضمينها (لأنها غير متصلة، أو لأن ترابطها كثيف جداً بالنسبة إلى شبكة) تُطلق ValueError بدلاً من رسم صورة مضلِّلة.

أيهما تستخدم​

draw_shaded_lightconeanimate_shaded_lightcone
الهندسةمخطط الدارةخريطة اقتران QPU
الأنسب لـالسلاسل أحادية البُعدأي ترابط
أنواع باوليمجمّعة، ما لم تُرشَّحمفصولة دائماً، على شكل شرائح دائرية
الزمنكل الطبقات دفعة واحدةطبقة واحدة لكل إطار
المخرجاتشكل matplotlibشكل plotly

بالنسبة إلى سلسلة أحادية البُعد، الشكل الثابت أسهل استيعاباً بنظرة واحدة ويمكن إعادة إنتاجه في ورقة بحثية. أما فيما يتجاوز البُعد الواحد فالرسم المتحرك هو الوحيد من الاثنين الذي يُظهر البنية المكانية بدقة.