تنفيذ الـ Circuits الديناميكية
إصدارات الحزم
تم تطوير الكود في هذه الصفحة باستخدام المتطلبات التالية. نوصي باستخدام هذه الإصدارات أو أحدث.
qiskit[all]~=2.4.0
qiskit-ibm-runtime~=0.46.1
الـ Circuits الديناميكية هي أدوات قوية تتيح لك قياس الـ qubits في منتصف تنفيذ دائرة كمية ثم تنفيذ عمليات منطقية كلاسيكية داخل الـ دائرة بناءً على نتائج تلك القياسات الوسطى. وتُعرف هذه العملية أيضًا بـ التغذية الراجعة الكلاسيكية. وعلى الرغم من أن مجتمع أبحاث الكم لا يزال في مراحله الأولى لفهم أفضل طريقة للاستفادة من الـ Circuits الديناميكية، فقد رصد عددًا من حالات الاستخدام، مثل:
- التحضير الفعّال للحالات الكمية، كـ حالة GHZ، وحالة W-state (لمزيد من المعلومات حول W-state، راجع أيضًا "تحضير الحالة بدوائر سطحية باستخدام التغذية الراجعة")، وفئة واسعة من حالات ناتج المصفوفات
- التشابك الفعّال بعيد المدى بين الـ qubits على نفس الشريحة باستخدام دوائر سطحية
- أخذ عينات فعّال من Circuits شبيهة بـ IQP
غير أن هذه التحسينات التي تجلبها الـ Circuits الديناميكية تأتي بتبادلات. فالقياسات الوسطى والعمليات الكلاسيكية عادةً ما تستغرق وقت تنفيذ أطول من بوابات Qubitين، وقد يُلغي هذا الوقت الإضافي فوائد تقليل عمق الـ دائرة. لذا، يُعدّ تقليل مدة قياس منتصف الـ دائرة من أبرز محاور التحسين في الإصدار الجديد من الـ Circuits الديناميكية التي تُصدرها IBM Quantum®. للاطلاع على القيود الأخرى عند استخدام الـ Circuits الديناميكية، راجع جدول توافق الميزات الخاص بـ Estimator أو Sampler.
يُعرِّف مواصفات OpenQASM 3 عددًا من هياكل التحكم في التدفق، لكن Qiskit Runtime يدعم حاليًا فقط تعليمة if الشرطية. في Qiskit SDK، يتوافق ذلك مع طريقة if_test في QuantumCircuit. تُعيد هذه الطريقة مدير سياق وتُستخدم عادةً في عبارة with. يصف هذا الدليل كيفية استخدام هذه التعليمة الشرطية.
تستخدم أمثلة الكود في هذا الدليل تعليمة القياس القياسية للقياسات الوسطى. غير أنه يُوصى باستخدام تعليمة MidCircuitMeasure بدلًا من ذلك إذا كان Backend يدعمها. راجع قسم القياسات الوسطى للتفاصيل.
البحث عن Backends تدعم الـ Circuits الديناميكية
للعثور على جميع الـ Backends التي يمكن لحسابك الوصول إليها وتدعم الـ Circuits الديناميكية، شغِّل كودًا مشابهًا لما يلي. يفترض هذا المثال أنك حفظت بيانات تسجيل الدخول. يمكنك أيضًا تحديد البيانات الاعتمادية صراحةً عند تهيئة حساب خدمة Qiskit Runtime، مما يتيح لك عرض الـ Backends المتاحة لنسخة معينة أو نوع خطة محدد، على سبيل المثال.
- تعتمد الـ Backends المتاحة للحساب على النسخة المحددة في بيانات الاعتماد.
- الإصدار الجديد من الـ Circuits الديناميكية متاح الآن لجميع المستخدمين على جميع الـ Backends. راجع الإعلان للمزيد من التفاصيل.
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
# This cell is hidden from users. It hides all those "...instance was not set..." warnings.
import warnings
warnings.filterwarnings("ignore", message=".*Instance was not set*")
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
dc_backends = service.backends(dynamic_circuits=True)
print(dc_backends)
[<IBMBackend('ibm_pittsburgh')>, <IBMBackend('ibm_kingston')>, <IBMBackend('ibm_marrakesh')>, <IBMBackend('ibm_fez')>, <IBMBackend('ibm_boston')>]
القياسات الوسطى
قبل qiskit-ibm-runtime الإصدار v0.43.0، كانت measure هي تعليمة القياس الوحيدة في Qiskit. غير أن القياسات الوسطى لها متطلبات ضبط مختلفة عن القياسات الطرفية (القياسات التي تحدث في نهاية الـ دائرة). على سبيل المثال، تحتاج إلى مراعاة مدة التعليمة عند ضبط قياس وسطي لأن التعليمات الأطول تُنتج دوائر أكثر ضوضاء. في المقابل، لا تحتاج إلى مراعاة مدة التعليمة للقياسات الطرفية لأنه لا توجد تعليمات بعدها.
تُعيَّن تعليمة MidCircuitMeasure إلى تعليمة measure_2 المُبلَّغ عنها في supported_instructions الخاص بالـ Backend. غير أن measure_2 غير مدعومة على جميع الـ Backends. استخدم service.backends(filters=lambda b: "measure_2" in b.supported_instructions) للعثور على الـ Backends التي تدعمها. قد تُضاف قياسات جديدة مستقبلًا، لكن ذلك غير مضمون.
طريقة MidCircuitMeasure
في qiskit-ibm-runtime الإصدار v0.43.0، جرى تقديم تعليمة MidCircuitMeasure. كما يوحي الاسم، هي تعليمة قياس جديدة مُحسَّنة للقياسات الوسطى على معالجات IBM® الكمية (QPUs). وبينما يمكنك استخدام QuantumCircuit.measure لقياس وسطي، يُعدّ MidCircuitMeasure خيارًا أفضل عمومًا نظرًا لتصميمه، إذ يُضيف حملًا أقل إلى دارتك مقارنةً بـ QuantumCircuit.measure.
from qiskit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime.circuit import MidCircuitMeasure
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, dynamic_circuits=True
)
circ = QuantumCircuit(2, 2)
circ.x(0)
circ.append(MidCircuitMeasure(), [0], [0])
# circ.measure([0], [0])
# circ.measure_all()
print(circ.draw(cregbundle=False))
┌───┐┌────────────┐
q_0: ┤ X ├┤0 ├
└───┘│ │
q_1: ─────┤ Measure_2 ├
│ │
c_0: ═════╡0 ╞
└────────────┘
c_1: ═══════════════════
- يجب أن يكون هناك سجل كلاسيكي واحد على الأقل لاستخدام القياسات.
- يتطلب Sampler primitive قياسات Circuit. يمكنك إضافة قياسات Circuit مع Estimator primitive، لكنها تُتجاهَل.
Store
مع qiskit-ibm-runtime الإصدار 0.47.0 أو أحدث، يمكنك استخدام تعليمة store لحفظ نتيجة تعبير كلاسيكي إذا كان سيُستخدَم بشكل متكرر. تُوازَن العمليات تلقائيًا، مما يجعل كودك أكثر كفاءة بشكل ملحوظ في وقت التشغيل.
للمزيد من المعلومات، راجع دليل التغذية الراجعة الكلاسيكية والتحكم في التدفق.
عند استخدام store لحفظ قيمة في سجل كلاسيكي على Backend حقيقي، تُحفَظ القيمة في الذاكرة أثناء التنفيذ فقط ولا تُنسَخ أو تُعاد في نتيجة المهمة.
على سبيل المثال، في الكود التالي، تحمل temp نفس قيمة creg أثناء التنفيذ، ويعمل if_test كما هو متوقع. لكن بعد انتهاء المهمة، لا تحتوي BitArray الخاص بـ temp المُعادة في نتيجة المهمة على قيمة creg. أي أن job.result()[0].data.temp تساوي 0.
creg = ClassicalRegister(3, "c")
temp = ClassicalRegister(3, "temp")
...
qc.store(temp, creg)
with circuit.if_test((temp, 0b001)):
...
مثال كامل
يُنشئ الكود التالي Circuit ديناميكية ويشغلها على معدات IBM®.
from qiskit_ibm_runtime import SamplerV2, QiskitRuntimeService
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.transpiler import generate_preset_pass_manager
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, dynamic_circuits=True
)
# Create a dynamic circuit
qubits = QuantumRegister(1)
clbits = ClassicalRegister(1)
qc = QuantumCircuit(qubits, clbits)
(q0,) = qubits
(c0,) = clbits
qc.h(q0)
qc.measure(q0, c0)
with qc.if_test((c0, 1)):
qc.x(q0)
qc.measure(q0, c0)
# Convert to an ISA circuit for the given backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(qc)
# Generate samplers for backend targets
sampler = SamplerV2(backend)
# Submit jobs
sampler_job = sampler.run([isa_circuit])
result = sampler_job.result()
print(
f">>> {' Job ID:':<10} {sampler_job.job_id()} ({sampler_job.status()})"
)
>>> Job ID: d88cakp789is7391vq0g (DONE)
قيود Qiskit Runtime
انتبه للقيود التالية عند تشغيل الـ Circuits الديناميكية في Qiskit Runtime.
-
بسبب محدودية الذاكرة الفيزيائية في أجهزة التحكم الإلكترونية، هناك حد لعدد تعليمات
ifوحجم معاملاتها. يعتمد هذا الحد على عدد عمليات البث (broadcasts) وعدد البتات المُبثَّة في المهمة (وليس في الـ دائرة).عند معالجة شرط
if، تحتاج بيانات القياس إلى النقل إلى منطق التحكم لإجراء التقييم. البث هو نقل بيانات كلاسيكية فريدة، والبتات المُبثَّة هي عدد البتات الكلاسيكية المُنقَلة. لنأخذ المثال التالي:c0 = ClassicalRegister(3)c1 = ClassicalRegister(5)...with circuit.if_test((c0, 1)) ...with circuit.if_test((c0, 3)) ...with circuit.if_test((c1[2], 1)) ...في مثال الكود السابق، يُعدّ كائنا
if_testالأوليان علىc0بثًّا واحدًا لأن محتوىc0لم يتغير ولا يحتاج إلى إعادة البث. أماif_testعلىc1فهو بث ثانٍ. يبث الأول جميع البتات الثلاث فيc0والثاني يبث بتًا واحدًا فقط، ليبلغ إجمالي البتات المُبثَّة أربع بتات.حاليًا، إذا بثّت 60 بتًا في كل مرة، يمكن للمهمة أن تحتوي على نحو 300 بث. أما إذا بثّت بتًا واحدًا في كل مرة، فيمكن أن تصل إلى 2400 بث.
-
يجب أن يكون المعامل المستخدم في عبارة
if_test32 بتًا أو أقل. وعليه، إذا كنت تقارنClassicalRegisterبأكمله، يجب أن لا يتجاوز حجمه 32 بتًا. إذا كنت تقارن بتًا واحدًا فقط منClassicalRegister، يمكن أن يكون حجمه أيًّا كان (إذ المعامل بت واحد فقط).على سبيل المثال، كتلة "غير صالح" لا تعمل لأن
crأكبر من 32 بتًا. غير أنه يمكنك استخدام سجل كلاسيكي أوسع من 32 بتًا إذا كنت تختبر بتًا واحدًا فقط، كما هو موضح في كتلة "صالح".- غير صالح
- صالح
cr = ClassicalRegister(50)qr = QuantumRegister(50)circuit = QuantumCircuit(qr, cr)...circ.measure(qr, cr)with circ.if_test((cr, 15)):...cr = ClassicalRegister(50)qr = QuantumRegister(50)circuit = QuantumCircuit(qr, cr)...circ.measure(qr, cr)with circ.if_test((cr[5], 1)):... -
الشروط المتداخلة غير مسموح بها. على سبيل المثال، كتلة الكود التالية لن تعمل لأنها تحتوي على
if_testداخلif_testآخر:- غير صالح
- صالح
c1 = ClassicalRegister(1, "c1")c2 = ClassicalRegister(2, "c2")...with circ.if_test((c1, 1)):with circ.if_test(c2, 1)):...cr = ClassicalRegister(2)...with circuit.if_test((cr, 0b11)):... -
استخدام
resetأو القياسات داخل الشروط غير مدعوم. -
العمليات الحسابية غير مدعومة.
-
راجع جدول ميزات OpenQASM 3 لتحديد ميزات OpenQASM 3 المدعومة في Qiskit وQiskit Runtime.
-
عند استخدام OpenQASM 3 (بدلًا من
QuantumCircuit) كتنسيق إدخال لتمرير الـ Circuits إلى Qiskit Runtime primitives، يُدعم فقط ما يمكن تحميله في Qiskit. على سبيل المثال، العمليات الكلاسيكية غير مدعومة لأنه لا يمكن تحميلها في Qiskit. راجع استيراد برنامج OpenQASM 3 إلى Qiskit للمزيد من المعلومات. -
تعليمات
forوwhileوswitchغير مدعومة.
استخدام الـ Circuits الديناميكية مع Estimator
بما أن Estimator لا يدعم الـ Circuits الديناميكية، يمكنك استخدام Sampler وبناء دوائر قياس خاصة بك.
لمحاكاة سلوك Estimator، اتبع هذه الخطوات:
- قسِّم حدود جميع المراقِبات إلى أقسام. يمكن تحقيق ذلك باستخدام واجهة برمجة تطبيقات
PauliListمثلًا.ملاحظةيمكنك استخدام خاصية الـ primitive
BitArrayلحساب قيم التوقع للمراقِبات المُقدَّمة. - نفِّذ Circuit تغيير أساس واحدة لكل قسم (أيًّا كان تغيير الأساس المطلوب لكل قسم). راجع وحدة
measurement_basesفي أداة إضافات القياس للمزيد من المعلومات. راجع أيضًا وثائق حزمة أدوات Qiskit addon. - اجمع نتائج كل قسم معًا.
القيود
راجع أي جدول توافق الميزات لفهم القيود عند استخدام الـ Circuits الديناميكية. لاحظ أن توافق الميزات لا يعتمد على نوع الـ primitive.
الخطوات التالية
- تعلَّم كيفية تطبيق الفصل الديناميكي الدقيق باستخدام stretch.
- راجع دليل التغذية الراجعة الكلاسيكية والتحكم في التدفق.
- استخدم تصور توقيت Circuit لتصحيح الأخطاء وتحسين الـ Circuits الديناميكية.
- ليست جميع الوظائف متوافقة مع الـ Circuits الديناميكية. راجع قسم توافق الميزات في Sampler أو Executor للتفاصيل.