انتقل إلى المحتوى الرئيسي

تمثيل أجهزة الحوسبة الكمومية للمترجم

إصدارات الحزم

تم تطوير الكود في هذه الصفحة باستخدام المتطلبات التالية. نوصي باستخدام هذه الإصدارات أو أحدث منها.

qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1

لتحويل دائرة مجردة إلى دائرة ISA قادرة على التشغيل على وحدة معالجة كمومية (QPU) محددة، يحتاج المترجم إلى معلومات معينة عن تلك الوحدة. هذه المعلومات موجودة في مكانين: كائن BackendV2 (أو النسخة القديمة BackendV1) الذي تخطط لإرسال المهام إليه، وخاصية Target الخاصة بالـ backend.

  • يحتوي Target على جميع القيود ذات الصلة بالجهاز، مثل بوابات الأساس الأصلية، وترابط الكيوبتات، ومعلومات النبضات أو التوقيت.
  • يمتلك Backend Target افتراضيًا، ويحتوي على معلومات إضافية — مثل InstructionScheduleMap، ويوفر الواجهة لإرسال مهام الدوائر الكمومية.

يمكنك أيضًا تقديم المعلومات صراحةً للمترجم، مثلًا إذا كان لديك حالة استخدام خاصة، أو إذا كنت تعتقد أن هذه المعلومات ستساعد المترجم في توليد دائرة أكثر تحسينًا.

تعتمد دقة المترجم في إنتاج الدائرة الأنسب لجهاز معين على قدر المعلومات التي يملكها Target أو Backend عن قيوده.

ملاحظة

بما أن كثيرًا من خوارزميات الترجمة الأساسية عشوائية الطابع، لا يوجد ضمان بالعثور على دائرة أفضل.

تعرض هذه الصفحة عدة أمثلة على تمرير معلومات QPU إلى المترجم. تستخدم هذه الأمثلة الـ target من الـ backend الوهمي FakeSherbrooke.

الإعداد الافتراضي

أبسط طريقة لاستخدام المترجم هي تقديم جميع معلومات QPU عبر توفير Backend أو Target. لفهم كيفية عمل المترجم بشكل أفضل، شيّد دائرة وترجمها بمعلومات مختلفة على النحو التالي.

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

يعرض هذا الموضوع عدة أمثلة على تمرير المعلومات إلى المترجم. تستخدم هذه الأمثلة الـ target من الـ backend الوهمي FakeSherbrooke.

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

backend = FakeSherbrooke()
target = backend.target

تستخدم الدائرة في المثال مثيلًا من efficient_su2 من مكتبة دوائر Qiskit.

from qiskit.circuit.library import efficient_su2

qc = efficient_su2(12, entanglement="circular", reps=1)

qc.draw("mpl")

Output of the previous code cell

يستخدم هذا المثال الإعدادات الافتراضية للترجمة إلى target الخاص بـ backend، الذي يوفر كافة المعلومات اللازمة لتحويل الدائرة إلى دائرة قابلة للتشغيل على الـ backend.

from qiskit.transpiler import generate_preset_pass_manager

pass_manager = generate_preset_pass_manager(
optimization_level=1, target=target, seed_transpiler=12345
)
qc_t_target = pass_manager.run(qc)
qc_t_target.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

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

خريطة الاقتران

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

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

ملاحظة

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

مرّر وسيطة الكلمة المفتاحية coupling_map لمشاهدة تأثيرها على المترجم:

coupling_map = target.build_coupling_map()

pass_manager = generate_preset_pass_manager(
optimization_level=0, coupling_map=coupling_map, seed_transpiler=12345
)
qc_t_cm_lv0 = pass_manager.run(qc)
qc_t_cm_lv0.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

كما هو موضح أعلاه، تم إدراج عدة بوابات SWAP (تتكون كل منها من ثلاث بوابات CX)، مما سيتسبب في أخطاء كثيرة على الأجهزة الحالية. لمعرفة الكيوبتات المختارة على طوبولوجيا الكيوبتات الفعلية، استخدم plot_circuit_layout من أدوات التصور في Qiskit:

from qiskit.visualization import plot_circuit_layout

plot_circuit_layout(qc_t_cm_lv0, backend, view="physical")

Output of the previous code cell

هذا يُظهر أن الكيوبتات الافتراضية 0-11 تم تعيينها مباشرةً إلى سلسلة الكيوبتات الفيزيائية 0-11. لنعد إلى الإعداد الافتراضي (optimization_level=1)، الذي يستخدم VF2Layout إذا كان أي توجيه مطلوبًا.

pass_manager = generate_preset_pass_manager(
optimization_level=1, coupling_map=coupling_map, seed_transpiler=12345
)
qc_t_cm_lv1 = pass_manager.run(qc)
qc_t_cm_lv1.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

الآن لم يتم إدراج أي بوابات SWAP، والكيوبتات الفيزيائية المختارة هي نفسها عند استخدام كلاس target.

from qiskit.visualization import plot_circuit_layout

plot_circuit_layout(qc_t_cm_lv1, backend, view="physical")

Output of the previous code cell

أصبح التخطيط الآن على شكل حلقة. ولأن هذا التخطيط يحترم ترابط الدائرة، لا توجد بوابات SWAP، مما يوفر دائرة أفضل بكثير للتنفيذ.

بوابات الأساس

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

basis_gates = list(target.operation_names)
print(basis_gates)
['sx', 'switch_case', 'x', 'if_else', 'measure', 'for_loop', 'delay', 'ecr', 'id', 'reset', 'rz']

البوابات الافتراضية أحادية الكيوبت على ibm_sherbrooke هي rz وx وsx، والبوابة الافتراضية ثنائية الكيوبت هي ecr (الرنين المتقاطع المتردد). تُبنى بوابات CX من بوابات ecr، لذا على بعض وحدات QPU يُحدَّد ecr كبوابة أساس ثنائية الكيوبت، بينما cx هي الافتراضية على أخرى. بوابة ecr هي الجزء المتشابك من بوابة cx. إضافةً إلى بوابات التحكم، توجد أيضًا تعليمات delay وmeasurement.

ملاحظة

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

pass_manager = generate_preset_pass_manager(
optimization_level=1,
coupling_map=coupling_map,
basis_gates=basis_gates,
seed_transpiler=12345,
)
qc_t_cm_bg = pass_manager.run(qc)
qc_t_cm_bg.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

لاحظ أن كائنات CXGate قد تم تحليلها إلى بوابات ecr وبوابات الأساس أحادية الكيوبت.

معدلات أخطاء الجهاز

يمكن أن تحتوي كلاس Target على معلومات عن معدلات الأخطاء للعمليات على الجهاز. فمثلًا، يسترد الكود التالي خصائص بوابة الرنين المتقاطع المتردد (ECR) بين الكيوبت 1 والكيوبت 0 (لاحظ أن بوابة ECR موجهة):

target["ecr"][(1, 0)]
InstructionProperties(duration=5.333333333333332e-07, error=0.007494257741828603)

يعرض الناتج مدة البوابة (بالثواني) ومعدل خطئها. لكشف معلومات الأخطاء للمترجم، ابنِ نموذج target مع basis_gates وcoupling_map من الأعلى واملأه بقيم الأخطاء من الـ backend FakeSherbrooke.

from qiskit.transpiler import Target
from qiskit.circuit.controlflow import IfElseOp, SwitchCaseOp, ForLoopOp

err_targ = Target.from_configuration(
basis_gates=basis_gates,
coupling_map=coupling_map,
num_qubits=target.num_qubits,
custom_name_mapping={
"if_else": IfElseOp,
"switch_case": SwitchCaseOp,
"for_loop": ForLoopOp,
},
)

for i, (op, qargs) in enumerate(target.instructions):
if op.name in basis_gates:
err_targ[op.name][qargs] = target.instruction_properties(i)

ترجم باستخدام الـ target الجديد err_targ:

pass_manager = generate_preset_pass_manager(
optimization_level=1, target=err_targ, seed_transpiler=12345
)
qc_t_cm_bg_et = pass_manager.run(qc)
qc_t_cm_bg_et.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

لأن الـ target يتضمن معلومات الأخطاء، يحاول تمرير VF2PostLayout إيجاد الكيوبتات المثلى للاستخدام، مما ينتج عنه نفس الدائرة التي وُجدت في الأصل مع نفس الكيوبتات الفيزيائية.

الخطوات التالية