تأجيل حل التوقيت باستخدام stretch
تحتوي مواصفة لغة OpenQASM 3 على نوع stretch يتيح لك تحديد التوقيت النسبي للعمليات بدلاً من التوقيت المطلق. أُضيف دعم stretch كمدد للتعليمة Delay في Qiskit v2.0.0. يُحسم الحجم الفعلي لمدة stretch في وقت الترجمة، بعد معرفة المدة الدقيقة للبوابات المعايَرة. يسعى المترجم إلى تقليل مدة stretch إلى الحد الأدنى، مع مراعاة قيود التوقيت على qubit واحد أو أكثر. يمكنك بذلك التعبير عن تصميمات البوابات كتباعد البوابات بالتساوي (مثلاً لتنفيذ تسلسل فك ارتباط صدى عالي الرتبة)، أو محاذاة تسلسل بوابات إلى اليسار، أو تطبيق بوابة طوال مدة دائرة فرعية معينة، وذلك دون معرفة التوقيت الدقيق.
أمثلة
الفصل الديناميكي
من أكثر حالات استخدام stretch شيوعاً تطبيق الفصل الديناميكي على qubit في حالة خمول بينما يخضع qubit آخر لعمليات شرطية.
على سبيل المثال، يمكننا استخدام stretch لتطبيق تسلسل فصل ديناميكي XX على qubit 1، طوال مدة الكتلة الشرطية المطبقة على qubit 0، كما يوضح الرسم التالي:
ستبدو الدائرة المقابلة كما يلي. لاحظ أن زوجاً من الحواجز ضروري لتحديد حدود هذا التوقيت النسبي.
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.circuit.classical import expr
qubits = QuantumRegister(2)
clbits = ClassicalRegister(2)
circuit = QuantumCircuit(qubits, clbits)
(q0, q1) = qubits
(c0, c1) = clbits
# Add barriers to define the boundaries
circuit.barrier()
circuit.h(q0)
circuit.measure(q0, c0)
with circuit.if_test((c0, 1)) as else_:
circuit.h(q0)
with else_:
circuit.x(q0)
# Apply an XX DD sequence with stretch on qubit 1
s = circuit.add_stretch("s")
circuit.delay(s, q1)
circuit.x(q1)
circuit.delay(expr.mul(s, 2), q1)
circuit.x(q1)
circuit.delay(s, q1)
circuit.barrier()
محاذاة الجدولة
يستخدم هذا المثال stretch لضمان محاذاة تسلسل البوابات بين حاجزين إلى اليسار، بصرف النظر عن مددها الفعلية:
from qiskit import QuantumCircuit
from numpy import pi
qc = QuantumCircuit(5)
qc.barrier()
qc.cx(0, 1)
qc.u(pi/4, 0, pi/2, 2)
qc.cx(3, 4)
a = qc.add_stretch("a")
b = qc.add_stretch("b")
c = qc.add_stretch("c")
# Use the stretches as Delay duration.
qc.delay(a, [0, 1])
qc.delay(b, 2)
qc.delay(c, [3, 4])
qc.barrier()
عند استخدام stretch مع Qiskit Runtime، يُضاف أي باقٍ ناتج عن حل stretch إلى أول تأخير يستخدم stretch.
مثال:
a = circuit.add_stretch("a")
circuit.barrier(q0, q1)
circuit.delay(100, q0)
circuit.delay(a, q1) # resolve to 26
circuit.x(q1) # duration: 8
circuit.delay(a, q1) # resolve to 25
circuit.x(q1) # duration: 8
circuit.delay(a, q1) # resolve to 25
circuit.x(q1) # duration: 8
circuit.barrier(q0, q1)
يُحسم الكود أعلاه إلى قيمة 25 مع باقٍ مقداره 1. سيُضاف الباقي إلى أول تأخير[a].
معادلة حل stretch:
عرض قيم stretch في Qiskit Runtime
تُحسم القيمة الفعلية لمدة stretch في وقت الترجمة، بعد جدولة الدائرة. عند تشغيل مهمة Sampler في Qiskit Runtime، يمكنك عرض قيم stretch المحسومة في بيانات التعريف لنتيجة المهمة. دعم stretch في Qiskit Runtime تجريبي حالياً، لذا تحتاج أولاً إلى تعيين خيار تجريبي لتفعيل استرجاعه، ثم الوصول إلى البيانات مباشرةً من بيانات التعريف كما يلي:
# Enable stretch value retrieval.
sampler.options.experimental = {
"execution": {
"stretch_values": True,
"scheduler_timing": True,
},
}
# Access the stretch values from the metadata.
job_result = job.result()
circuit_stretch_values = job_result[0].metadata["compilation"]["stretch_values"]
# Visualize the timing.
# Use the sliders at the bottom, the controls at the top, and the legend on the side
# of the output to customize the view.
draw_circuit_schedule_timing(ob.result()[0].metadata['compilation']['scheduler_timing']['timing'])
على الرغم من أن إجمالي وقت الدائرة يُعاد في بيانات التعريف "compilation"، إلا أن هذا ليس الوقت المستخدم في الفوترة (الوقت الكمي).
فهم مخرجات بيانات التعريف
تُعيد بيانات التعريف stretch_values المعلومات التالية:
- الاسم: اسم stretch المطبّق.
- القيمة: القيمة الهدف المطلوبة.
- الباقي: الباقي من حل stretch، والذي يُضاف إلى أول تأخير يستخدم stretch.
- القيم الموسّعة: مجموعات من القيم تحدد بداية stretch ومدته.
مثال
# Define the circuit
circuit = QuantumCircuit(4)
foo = circuit.add_stretch("foo")
bar = circuit.add_stretch("bar")
circuit.barrier()
circuit.cz(0, 1)
circuit.cz(0, 1)
circuit.cz(0, 1)
circuit.cz(0, 1)
circuit.delay(foo, 2)
circuit.x(2)
# 3*foo
circuit.delay(expr.mul(3, foo), 2)
circuit.x(2)
# 2*foo
circuit.delay(expr.mul(2, foo), 2)
circuit.delay(bar, 3)
circuit.x(3)
circuit.delay(bar, 3)
circuit.measure_all()
مخرجات بيانات التعريف
[{'name': 'bar',
'value': 29,
'remainder': 1,
'expanded_values': [[1365, 30], [1404, 29]]},
{'name': 'foo',
'value': 8,
'remainder': 2,
'expanded_values': [[1365, 10], [1384, 24], [1417, 16]]}
]
تعتمد قيم المدة المُعادة على القيمة الهدف والباقي المحسوب. على سبيل المثال، هذه هي المدد المُعادة لـ foo:
foo value+remainder(8+2 = 10)foo value* 3 (8 x 3 = 24)foo value* 2 (8 x 2 = 16)
يمكنك استخدام التصور المرئي للمساعدة في فهم التوقيت والتحقق منه.
draw_circuit_schedule_timing(job.result()[0].metadata['compilation']['scheduler_timing']['timing'])
في الصورة التالية، استناداً إلى مخرج المثال، يقابل foo التمددات على Qubit 2. يبدأ أول تأخير تمدد يستخدم foo عند نهاية init_play (1365). مدة التمدد هي 10، لذا ينتهي هذا التأخير عندما تبدأ بوابة x (1365+10=1375). يمكنك تفسير التمددين الثاني والثالث بالمثل.

استخدم أشرطة التمرير في الأسفل، وعناصر التحكم في الأعلى (مرر المؤشر فوق صورة الناتج للكشف عنها)، والتسمية التوضيحية على جانب الناتج لتخصيص العرض. مرر المؤشر فوق الصورة لعرض البيانات الدقيقة.
للاطلاع على التفاصيل الكاملة، راجع موضوع تصور توقيت الدائرة.
قيود Qiskit Runtime
دعم stretch في Qiskit Runtime تجريبي حالياً وله القيود التالية:
-
متغير stretch واحد على الأكثر لكل مجموعة qubits بين الحواجز (الضمنية والصريحة). مجموعة الـ qubits هي qubit واحد أو أكثر؛ ويجب أن تكون هذه المجموعات غير متداخلة.
- غير صالح
- صالح
a = circuit.add_stretch("a")
b = circuit.add_stretch("b")
circuit.delay(a, (q0, q1))
circuit.delay(b, q0) # Invalid because 2 stretches are applied on q0a = circuit.add_stretch("a")
b = circuit.add_stretch("b")
circuit.delay(a, (q0, q1))
circuit.delay(b, q2) -
المنطقة المحاطة بمجموعة من الحواجز تُسمى منطقة الحاجز. لا يمكن استخدام متغير stretch في مناطق حاجز متعددة.
- غير صالح
- صالح
# Stretch a is used in two barrier regions
a = circuit.add_stretch("a")
circuit.barrier((q0, q1))
circuit.delay(a, q0)
circuit.barrier((q0, q1))
circuit.delay(a, q0)
circuit.barrier((q0, q1))
# Stretch a is used inside a barrier region that is on q0 and q1
a = circuit.add_stretch("a")
circuit.barrier((q0, q1))
circuit.delay(a, q0)
circuit.barrier(q2)
circuit.delay(a, q0)
circuit.barrier((q0, q1))
-
تعابير stretch مقتصرة على الصيغة
X*stretch + YحيثXوYثوابت من نوع عشري أو صحيح.- غير صالح
- صالح
a = circuit.add_stretch("a")
b = circuit.add_stretch("b")
c = circuit.add_stretch("c")
# (a / b) * c is not supported
circuit.delay(expr.mul(expr.div(a, b), c), q1)from qiskit.circuit import Duration
a = circuit.add_stretch("a")
circuit.delay(expr.add(expr.mul(a, 2), Duration.dt(3)), 0) -
تعابير stretch لا يمكن أن تتضمن إلا متغير stretch واحداً.
- غير صالح
- صالح
a = circuit.add_stretch("a")
b = circuit.add_stretch("b")
circuit.delay(expr.add(a, b), 0)a = circuit.add_stretch("a")
circuit.delay(expr.add(a, a), 0) -
لا يمكن أن تُحسم تعابير stretch إلى قيم تأخير سالبة. لا يستنتج المحلل الحالي قيود عدم السلبية.
- غير صالح
- صالح
from qiskit.circuit import Duration
circuit.barrier((q0, q1))
circuit.delay(20, q1)
# The length of this barrier region is 20dt, meaning the
# equation for solving stretch 'a' is a + 40dt = 20dt, giving a = -20dt.
circuit.delay(expr.add(a, Duration.dt(40)), q0)
circuit.barrier((q0, q1))circuit.barrier((q0, q1))
circuit.delay(20, q1)
circuit.delay(a, q0)
circuit.barrier((q0, q1))