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

العمل مع الدوائر البوزونية

BosonicCircuit تعبّر عن حساب مباشرة على الأنماط البوزونية. ما فيها اقتطاع ولا ترميز ولا عدد كيوبتات: هذه تدخل لاحقًا، أثناء الـ Transpile، وهكذا ممكن تخفيض دائرة واحدة تحت عدة ترميزات وعدة اقتطاعات بدون إعادة بنائها.

هي تعرض عمدًا واجهة برمجية مخفَّضة مقارنة بـ QuantumCircuit في Qiskit، حتى ما تقدر تطبّق بوابات كيوبتات على نمط بوزوني، لأن هذه عملية غير معرّفة جيدًا. هذا الدليل يغطي العمليات التي هي معروضة لتجميع دوائر أكبر من دوائر أصغر.

لماذا تستخدم الدوائر البوزونية​

تخيّل سير العمل التقليدي لوضع التطور الزمني لهاملتوني بوزوني على معمارية قائمة على الكيوبتات:

  1. عرّف الهاملتوني البوزوني، مثلًا H=−∑ijbi†bjH = -\sum_{ij} b^\dagger_i b_j.

  2. اختر اقتطاعًا وترميزًا، وعيّن الهاملتوني إلى مؤثر كيوبتات بهما.

  3. نفّذ التطور الزمني في فضاء الكيوبتات، بطريقة Trotter أو بطريقة أخرى.

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

BosonicCircuit تنقل هذه القرارات إلى النهاية:

  1. عرّف الهاملتوني البوزوني.

  2. عبّر عن التطور الزمني مباشرة على الأنماط البوزونية، ببوابات بوزونية.

  3. اختر الاقتطاع والترميز كجزء من الـ Transpile.

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

ترقيم الأنماط العام​

وحدة operators والدائرة يتشاركان اصطلاحًا واحدًا للأنماط. النمط مجرد فهرس يسمّي درجة حرية بوزونية، وليس له معنى بحد ذاته. لذلك ممكن تطوّر أي مؤثر ينفّذ بروتوكول OperatorTrait، مهما كان يمثّل، والدائرة ما تحتاج أبدًا تعرف ماذا يعني النمط 2. ونفس الشيء ينطبق على حجم النمط: الدائرة ما فيها حد قطع للإشغال، فما في شيء هنا يقول كم مستوى عند النمط.

أضِف البوابات​

البوابات تُضاف على الأنماط. فقط نسخ BosonicGate مقبولة:

>>> from qiskit_bosons.circuit import BosonicCircuit
>>> from qiskit_bosons.circuit.library import Evolution, InitializeModes
>>> from qiskit_bosons.operators import BosonOperator, ann, cre
>>>
>>> hopping = BosonOperator.from_dict({(cre(0), ann(1)): -1.0, (cre(1), ann(0)): -1.0})
>>> hopping.groups = [0] * len(hopping) # the pair is Hermitian, its terms alone are not
>>>
>>> prepare = BosonicCircuit(2)
>>> prepare.append(InitializeModes([2, 0]), prepare.modes)
>>> step = BosonicCircuit(2)
>>> step.append(Evolution(2, hopping, time=0.1), step.modes)

أي شيء ثاني يُرفض، والخطأ يسمّي النوع المخالف:

>>> from qiskit.circuit.library import HGate
>>> try:
... prepare.append(HGate(), [0])
... except ValueError as error:
... print(error)
Unsupported instruction type: <class '...HGate'>

ركّب الدوائر​

compose() يضع تعليمات دائرة على دائرة ثانية. تُدرَج داخل الدائرة، وليس بتغليفها في بوابة واحدة، فالنتيجة دائرة عادية تقدر تكمل تفكيكها وعمل Transpile لها.

>>> program = prepare.compose(step)
>>> program.draw("mpl", fold=-1)
<Figure size ... with 1 Axes>

A composed BosonicCircuit.

افتراضيًا تُرجَع دائرة جديدة ويُترك المعاملان كما هما. مرّر inplace=True لتعديل الأولى بدل ذلك، وfront=True لوضع المعامل قبل التعليمات الموجودة:

>>> step.compose(prepare, front=True)._inner.data == program._inner.data
True

ممكن وضع دائرة أضيق على مجموعة فرعية مختارة من الأنماط:

>>> single = BosonicCircuit(1)
>>> single.append(Evolution(1, BosonOperator.from_dict({(cre(0), ann(0)): 1.0}), 0.1), single.modes)
>>> wide = BosonicCircuit(3).compose(single, [2])
>>> wide.draw("mpl", fold=-1)
<Figure size ... with 1 Axes>

A narrow-composed BosonicCircuit.

فقط BosonicCircuit ثانية مقبولة كمعامل، لأن compose الخاصة بـ Qiskit كانت ستدرج بوابات الكيوبتات وتتجاوز الفحص الذي تفرضه append.

كرّر دائرة​

repeat() تكرّر دائرة من الطرف إلى الطرف. التكرارات مسطَّحة: النتيجة تحمل التعليمات reps مرة بالتسلسل بدل بوابة واحدة تغلّف الدائرة. لذلك أعداد العمليات تتناسب مع reps، وdecompose يعمل على الجسم المكرَّر بدل ما يزيل تكرارًا واحدًا.

>>> len(step.repeat(0)._inner.data) # zero repetitions is the identity
0
>>> step.repeat(5).draw("mpl", fold=-1)
<Figure size ... with 1 Axes>

A repeated BosonicCircuit.

هذه هي الطريقة على مستوى الدائرة لعمل Trotter: تطوّر لزمن قصير وتكرّر. شوف توليف بوابة Evolution في الفضاء البوزوني للبديل وهو اختيار صيغة ضرب على البوابة نفسها، ولماذا الاثنان شيئان مختلفان صدف أنهما يتشاركان كلمة «التكرارات».

افصل الخطوات بحواجز​

الحاجز يعلّم نقطة مزامنة لا تدمج تمريرات التحسين البوابات عبرها. barrier() يضع واحدًا على كل الأنماط، أو على الأنماط التي تسمّيها:

>>> program = BosonicCircuit(2)
>>> program.append(InitializeModes([2, 0]), program.modes)
>>> program.barrier()
>>> program.barrier(program.modes[0], label="zero")
>>> program.draw("mpl", fold=-1)
<Figure size ... with 1 Axes>

A BosonicCircuit with barriers.

repeat(..., insert_barriers=True) يضع واحدًا بين كل تكرارين متتاليين، وما في بعد الأخير:

>>> step.repeat(3, insert_barriers=True).draw("mpl", fold=-1)
<Figure size ... with 1 Axes>

A repeated BosonicCircuit with barriers.

الحواجز والترميز​

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

>>> from qiskit_bosons.mappers import LevelSpec
>>> from qiskit_bosons.transpiler.presets import generate_preset_occupation_pass_manager
>>> lowered = generate_preset_occupation_pass_manager(LevelSpec(2, "unary_projected")).run(program)
>>> lowered.draw("mpl", fold=-1)
<Figure size ... with 1 Axes>

A QuantumCircuit showing the expansion of barrier to cover the entire qubit register.

اقرأ نتائج دائرة بوزونية​

BosonicCircuit ما فيها measure ولا measure_all. معنى البت المقاس يعتمد على الترميز. تحت الترميز الأحادي إشغال النمط موزَّع على عدة كيوبتات ولازم يُقرأ من نمط من البتات، وتحت المدمج هو عدد ثنائي، فالقياس الذي يسمّي نمطًا لازم يعرف الترميز، وهذا ما لا تعرفه الدائرة البوزونية عمدًا. قِس الـ QuantumCircuit بعد الـ Transpile بدل ذلك، وفك ترميز سلاسل البتات باستخدام LevelEncoding.level_to_bits() والإزاحات الخاصة بـ LevelSpec اللي خفّضت بها. محاكاة ديناميكيات Bose-Hubbard مع اختيار الترميز يفعل هذا لنموذج كامل.

>>> hasattr(BosonicCircuit, "measure_all")
False

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