تنفيذ الدوائر الديناميكية
الدوائر الديناميكية هي أدوات قوية تتيح لك قياس الـ qubits في منتصف تنفيذ دائرة كمية ثم تنفيذ عمليات منطقية كلاسيكية داخل الدائرة بناءً على نتائج تلك القياسات الوسطى. وتُعرف هذه العملية أيضًا بـ التغذية الأمامية الكلاسيكية. وعلى الرغم من أن مجتمع أبحاث الكم لا يزال في مراحله الأولى لفهم أفضل طريقة للاستفادة من الدوائر الديناميكية، فقد رصد بالفعل عددًا من حالات الاستخدام، مثل:
-
التحضير الفعّال للحالات الكمية، كـ حالة GHZ، وحالة W-state (لمزيد من المعلومات حول W-state، راجع أيضًا "تحضير الحالة بدوائر سطحية باستخدام التغذية الأمامية")، وفئة واسعة من حالات ناتج المصفوفات
-
التشابك الفعّال بعيد المدى بين الـ qubits على نفس الشريحة باستخدام دوائر سطحية
غير أن هذه التحسينات التي تجلبها الدوائر الديناميكية تنطوي على مقايضات. فالقياسات الوسطى والعمليات الكلاسيكية عادةً ما تستغرق وقت تنفيذ أطول من البوابات ثنائية الـ Qubit، وقد يُلغي هذا الوقت الإضافي فوائد تقليل عمق الدائرة. لذا، يُعدّ تقليل مدة قياس منتصف الدائرة من أبرز محاور التحسين في الإصدار الجديد من الدوائر الديناميكية التي تُصدرها IBM Quantum®. للاطلاع على القيود الأخرى عند استخدام الدوائر الديناميكية، راجع جدول توافق الميزات الخاص بـ Estimator أو Sampler.
يُعرِّف مواصفات OpenQASM 3 عددًا من هياكل التحكم في التدفق، لكن IBM Quantum Compute Service يدعم حاليًا فقط تعليمة if الشرطية. في Qiskit SDK، يتوافق ذلك مع طريقة if_test في QuantumCircuit. تُعيد هذه الطريقة مدير سياق وتُستخدم عادةً في عبارة with. يصف هذا الدليل كيفية استخدام هذه التعليمة الشرطية.
تستخدم أمثلة الكود في هذا الدليل تعليمة القياس القياسية للقياسات الوسطى. غير أنه يُوصى باستخدام تعليمة MidCircuitMeasure بدلًا من ذلك إذا كان Backend يدعمها. راجع قسم القياسات الوسطى للتفاصيل.
إصدارات الحزم
تم تطوير الكود في هذه الصفحة باستخدام المتطلبات التالية. نوصي باستخدام هذه الإصدارات أو أحدث.
qiskit[all]~=2.6.1
qiskit-ibm-runtime~=0.50.0
البحث عن Backends تدعم الدوائر الديناميكية
للعثور على جميع الـ Backends التي يمكن لحسابك الوصول إليها وتدعم الدوائر الديناميكية، شغِّل كودًا مشابهًا لما يلي. يفترض هذا المثال أنك حفظت بيانات تسجيل الدخول. يمكنك أيضًا تحديد البيانات الاعتمادية صراحةً عند تهيئة حساب IBM Quantum Compute Service، مما يتيح لك عرض الـ Backends المتاحة لمثيل (instance) معين أو نوع خطة محدد، على سبيل المثال.
- تعتمد الـ Backends المتاحة للحساب على المثيل (instance) المحدد في بيانات الاعتماد.
- الإصدار الجديد من الدوائر الديناميكية متاح الآن لجميع المستخدمين على جميع الـ Backends. راجع الإعلان للمزيد من التفاصيل.
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"qiskit": "qiskit", "qiskit_ibm_runtime": "qiskit-ibm-runtime"}
_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")
# 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_boston')>, <IBMBackend('ibm_fez')>, <IBMBackend('ibm_kingston')>, <IBMBackend('ibm_marrakesh')>, <IBMBackend('ibm_phoenix')>, <IBMBackend('ibm_pittsburgh')>]
القياسات الوسطى
قبل 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 QiskitRuntimeService
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.transpiler import generate_preset_pass_manager
# Legacy server-side primitive before qiskit-ibm-runtime v0.50.0
# from qiskit_ibm_runtime import Sampler
# Client-side primitive introduced in qiskit-ibm-runtime v0.50.0
from qiskit_ibm_runtime.executor_sampler import Sampler
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 = Sampler(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: dbjeaj0nceqs73ajs65g (DONE)
قيود Quantum Compute
انتبه للقيود التالية عند تشغيل الدوائر الديناميكية في Quantum Compute.
-
بسبب محدودية الذاكرة الفيزيائية في أجهزة التحكم الإلكترونية، هناك حد لعدد تعليمات
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كاملًا، يجب أن يكون حجم ذلكClassicalRegister32 بت أو أقل. أما إذا كنت تقارن بت واحد فقط منClassicalRegister، فيمكن أن يكون ذلكClassicalRegisterمن أي حجم (لأن المُعامل هو بت واحد فقط).على سبيل المثال، كتلة "غير صالح" لا تعمل لأن
crأكبر من 32 بتًا. غير أنه يمكنك استخدام سجل كلاسيكي أوسع من 32 بتًا إذا كنت تختبر بتًا واحدًا فقط، كما هو موضح في كتلة "صالح".- غير صالح
- Valid
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آخر:- غير صالح
- Valid
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 وQuantum Compute.
-
عند استخدام OpenQASM 3 (بدلًا من
QuantumCircuit) كتنسيق إدخال لتمرير الدوائر إلى IBM Quantum primitives، يُدعم فقط ما يمكن تحميله في Qiskit. على سبيل المثال، العمليات الكلاسيكية غير مدعومة لأنه لا يمكن تحميلها في Qiskit. راجع استيراد برنامج OpenQASM 3 إلى Qiskit للمزيد من المعلومات. -
تعليمات
forوwhileوswitchغير مدعومة.
استخدام الدوائر الديناميكية مع Estimator
بما أن Estimator لا يدعم الدوائر الديناميكية، يمكنك استخدام Sampler وبناء دوائر قياس خاصة بك.
لمحاكاة سلوك Estimator، اتبع هذه الخطوات:
- قسِّم حدود جميع المرصودات (observables) إلى مجموعات. يمكن تحقيق ذلك باستخدام واجهة برمجة تطبيقات
PauliListمثلًا.ملاحظةيمكنك استخدام خاصية الـ primitive
BitArrayلحساب قيم التوقع للمرصودات المُقدَّمة. - نفِّذ Circuit تغيير أساس واحدة لكل قسم (أيًّا كان تغيير الأساس المطلوب لكل قسم). راجع وحدة
measurement_basesفي أداة إضافات القياس للمزيد من المعلومات. راجع أيضًا وثائق حزمة أدوات Qiskit addon. - اجمع نتائج كل قسم معًا.
القيود
راجع أي جدول توافق الميزات لفهم القيود عند استخدام الدوائر الديناميكية. لاحظ أن توافق الميزات لا يعتمد على نوع الـ primitive.
الخطوات التالية
- تعلَّم كيفية تطبيق فك الاقتران الديناميكي الدقيق باستخدام stretch.
- راجع دليل التغذية الأمامية الكلاسيكية والتحكم في التدفق.
- استخدم تصور توقيت الدائرة لتصحيح الأخطاء وتحسين الدوائر الديناميكية.
- ليست جميع الوظائف متوافقة مع الدوائر الديناميكية. راجع قسم توافق الميزات في Sampler للتفاصيل.