اشتغل مع الدوائر الفرميونية
المفاهيم في هذا الدليل متاحة حاليًا في واجهة Python البرمجية فقط. هتتوفر وظائف مكافئة في واجهة C البرمجية في إصدار قادم.
الدليل ده بيشرح إزاي تستخدم FermionicCircuit عشان تنفّذ الخوارزميات الكمّية مباشرةً في الفضاء الفرميوني، بدل ما تحوّلها لكيوبتات الأول.
ليه تستخدم الدوائر الفرميونية
خلّينا نبص على سير العمل التقليدي لتنفيذ التطور الزمني لهاميلتوني فرميوني على معمارية قائمة على الكيوبتات:
-
عرّف الهاميلتوني الفرميوني (مثلًا، ).
-
حوّله لمُشغّل كيوبتات (مثلًا باستخدام تحويل Jordan-Wigner).
-
نفّذ التطور الزمني في فضاء الكيوبتات (باستخدام Trotterization أو طرق تانية).
الطريقة دي فيها قيد أساسي؛ التحويل المبكر للكيوبتات بيتخلى عن المعرفة الخاصة بالمسألة عن البنية الفرميونية. تمريرات التحسين القياسية مش بتقدر تستغل التماثلات الفرميونية أو إعادة ترتيب الحدود المسموح بها، وده بيطلّع دوائر غير مثالية بعمق وعدد بوابات أكبر من اللازم.
الـ FermionicCircuit بيوفّر سير عمل أفضل:
-
عرّف الهاميلتوني الفرميوني (مثلًا، ).
-
نفّذ التطور الزمني مباشرةً في الفضاء الفرميوني باستخدام بوابات فرميونية.
-
حوّل لفضاء الكيوبتات كجزء من عملية الترجمة (transpilation).
الطريقة دي بتحل القيد عن طريق الاحتفاظ بالمعرفة الخاصة بالمسألة في الفضاء الفرميوني، حيث تقدر تمريرات التحسين تستغل البنية الفرميونية وعلاقات التبديل لتقليل عمق الدائرة. الدائرة الفرميونية بتوصف الحساب المطلوب تنفيذه، بينما الترجمة (transpilation) بتتعامل مع طريقة تحويله لكيوبتات، وده بيوفّر فصل أنظف بين المسؤوليات.
الفهرسة العامة للأنماط
كل من وحدة operators والـ FermionicCircuit بيستخدموا فهرسة عامة قائمة على الأنماط (modes) من غير أي افتراضات عن طبيعة الأنماط. النمط هو مجرد فهرس مجرّد بيسمّي درجة حرية فرميونية، من غير دلالات خاصة. الاختيار ده بيعكس تصميم وحدة operators وبيضمن أقصى مرونة. مثلًا، تقدر تنفّذ التطور الزمني لأي مُشغّل بيطبّق بروتوكول OperatorTrait، بغض النظر عن تمثيله الرياضي.
ابنِ دائرة فرميونية
المثال التالي بينفّذ التطور الزمني الموصوف في القسم السابق. بيبني FermionicCircuit بتحديد عدد الأنماط الفرميونية، وبعدين بيضيف بوابات فرميونية من qiskit_fermions.circuit.library لتنفيذ التطور الزمني.
المثال كمان بيوضّح إزاي تدمج معرفة المجال في المُشغّل باستخدام تجميع حدود المُشغّل. بتعيين فهارس المجموعات لحدود الهاميلتوني، بتحافظ على المعلومات البنيوية اللي تقدر تمريرات التحسين تستغلها على امتداد حزمة الترجمة.
>>> from qiskit_fermions.circuit import FermionicCircuit
>>> from qiskit_fermions.circuit.library import Evolution
>>> from qiskit_fermions.operators import FermionOperator, cre, ann
>>>
>>> # Create a circuit with 4 fermionic modes
>>> circuit = FermionicCircuit(4)
>>>
>>> # Define a simple fermionic Hamiltonian
>>> hamiltonian = FermionOperator.from_terms([
... ([cre(0), ann(2)], 0.5),
... ([cre(2), ann(0)], 0.5),
... ([cre(1), ann(3)], 0.5),
... ([cre(3), ann(1)], 0.5),
... ])
>>> # Add some problem structure by grouping our Hamiltonian terms
>>> hamiltonian.groups = [0, 0, 1, 1]
>>>
>>> # Add an evolution gate to implement exp(-i * t * H)
>>> evolution = Evolution(4, hamiltonian, time=1.0)
>>> circuit.append(evolution, circuit.register)
لاحظ إزاي تجميع حدود المُشغّل بيتحافظ عليه حتى في عمليات بسيطة زي التحليل (decomposition). ده بيوضّح إزاي المعلومات البنيوية بتنتقل عبر حزمة الدائرة. لفهم الترجمة الكاملة للكيوبتات، ارجع لدليل ترجمة الدوائر الفرميونية.
افصل البوابات عن بعض بحاجز
تمريرات التحسين بتدمج البوابات المتجاورة لما تقدر. مثلًا، MergeOrbitalRotations بيدمج سلسلة من بوابات OrbitalRotation المتتالية في بوابة واحدة، وMergeSlaterDeterminantPreparation بيدمج InitializeModes في الدوران اللي بييجي بعده.
استخدم FermionicCircuit.barrier() لما تحب تمنع ده. الحاجز مالوش أي تأثير وحدوي، فمش بيغيّر الحالة اللي دائرتك بتحضّرها؛ هو بس بيحدد نقطة التمريرات مش بتدمج عبرها. استدعيه من غير معاملات عشان يشمل كل الأنماط، أو مرّر الأنماط عشان تقصره عليها:
>>> from qiskit_fermions.circuit.library import OrbitalRotation
>>> import numpy as np
>>>
>>> rotations = FermionicCircuit(4)
>>> rotations.append(OrbitalRotation(np.eye(4, dtype=complex)), rotations.register)
>>> rotations.barrier()
>>> rotations.append(OrbitalRotation(np.eye(4, dtype=complex)), rotations.register)
الحواجز بتفضل موجودة بعد ترجمة الفرميونات للكيوبتات، فبتقيّد كمان تحسين مستوى الكيوبتات اللي بييجي بعدها. دليل ترجمة الدوائر الفرميونية بيغطي المرحلة دي.
كرّر دائرة
خوارزميات كتير بتطبّق نفس كتلة البوابات مرات كتيرة. التطور الزمني هو الحالة الشائعة: خطوة Trotter بتتبني مرة واحدة، وبعدين بتتكرر للوصول للزمن المستهدف. استخدم repeat() لبناء الدائرة المتكررة، وcompose() لربطها ببادئة تحضير الحالة.
المثال التالي بيبني خطوة Trotter من الرتبة التانية لنموذج Fermi-Hubbard. الخطوة متماثلة: بتقسم حد القفز لبوابتين OrbitalRotation بنص المدة، بيحيطوا بالتفاعل الموضعي.
>>> import scipy.linalg
>>> from qiskit_fermions.circuit.library import InitializeModes, OrbitalRotation
>>>
>>> norb, reps, time = 2, 3, 1.0
>>> num_modes = 2 * norb
>>> dt = time / reps
>>>
>>> hopping = np.zeros((norb, norb))
>>> hopping[0, 1] = hopping[1, 0] = -1.0
>>> interaction = FermionOperator.from_dict(
... {(cre(p), ann(p), cre(p + norb), ann(p + norb)): 2.0 for p in range(norb)}
... )
>>>
>>> def rotation(duration):
... propagator = scipy.linalg.expm(-1j * duration * hopping)
... # the same rotation acts on the alpha and beta halves of the register
... return scipy.linalg.block_diag(propagator, propagator)
>>>
>>> trotter_step = FermionicCircuit(num_modes)
>>> trotter_step.append(OrbitalRotation(rotation(dt / 2)), trotter_step.modes)
>>> trotter_step.append(
... Evolution(num_modes, interaction, dt, atomic=True), trotter_step.modes
... )
>>> trotter_step.append(OrbitalRotation(rotation(dt / 2)), trotter_step.modes)
تكرار الخطوة وتركيبها على مرجع Hartree-Fock بيدّي التطور الكامل:
>>> evolution = FermionicCircuit(num_modes)
>>> evolution.append(InitializeModes([True, False, True, False]), evolution.modes)
>>> evolution.compose(trotter_step.repeat(reps), inplace=True)
>>> evolution.count_ops()["OrbitalRotation"]
6
التكرارات بتتسطّح جوه الدائرة المرجعة بدل ما تتغلف في بوابة واحدة، عشان كده count_ops() بيعدّ دورانين لكل خطوة. التسطيح ده هو اللي بيخلّي التكرار الزائد عند حدود الخطوات ظاهر للـ transpiler: دوران نص المدة الأخير في خطوة والأول في اللي بعدها متجاورين، فـ MergeOrbitalRotations بيدمجهم في دوران واحد.
>>> from qiskit_fermions.transpiler import FermionicPassManager
>>> from qiskit_fermions.transpiler.passes import MergeOrbitalRotations
>>>
>>> merged = FermionicPassManager([MergeOrbitalRotations()]).run(evolution)
>>> merged.count_ops()["OrbitalRotation"]
4
النتيجة بتكلّف دوران واحد لكل خطوة زائد واحد، وده اللي هتحصل عليه لو دمجت أنصاف الخطوات دي بإيدك. كتابة الخطوة في شكلها المتماثل الطبيعي وتكرارها بيطلّع نفس الدائرة، فالدمج بيتساب لمرحلة التحسين.
لما تحتاج التكرارات تفضل منفصلة، مرّر insert_barriers=True عشان تحط barrier() بينهم. تمريرات التحسين مش بتدمج البوابات عبر حاجز، فكل دوران بيفضل موجود:
>>> separated = trotter_step.repeat(reps, insert_barriers=True)
>>> FermionicPassManager([MergeOrbitalRotations()]).run(separated).count_ops()[
... "OrbitalRotation"
... ]
6
معامل reps في FermionicSuzukiTrotter مفهوم مختلف. هو بيقسّم بوابة Evolution واحدة لعوامل أكتر وأقصر، بينما repeat() بيكرر دوائر كاملة. تكرار دائرة فيها Evolution واحدة بيضاعف بس زمن التطور الإجمالي لها.
قِس الأنماط الفرميونية
measure_all() بيقرأ كل نمط في بت كلاسيكي خاص بيه، بيقرن النمط i بالبت i. استخدم measure() مع ClassicalRegister بتاعك عشان تقرأ بس بعض الأنماط.
>>> measured = trotter_step.measure_all(inplace=False)
>>> measured.count_ops()["measure"]
4
تمرير inplace=False بيرجّع نسخة مقيسة وبيسيب الأصل زي ما هو، وده مهم لأن القياس مش وحدوي: الدائرة اللي فيها قياس مش هينفع تتطبّق على متجه حالة بعد كده، فاحتفظ بدائرة من غير قياس لو عايز تحاكيها كمان.
القياس هنا، بدل ما يكون على QuantumCircuit المترجمة، هو اللي بيخلّي سلاسل البتات المعيّنة سهلة القراءة. القياس الفرميوني بيسمّي النمط اللي بيقرأه، فكل مرحلة بتحرّك الأنماط (RelabelModes على المستوى الفرميوني، والتخطيط والتوجيه على مستوى الكيوبتات) بتاخد القياس معاها، وسلسلة البتات بتفضل مفهرسة حسب النمط اللي سألت عنه.
عكس measure_all()، مفيش barrier() بيتحط قبل القياسات. استدعي barrier() بنفسك الأول لو عايز واحد هناك.
إذا كان البت المقيس معناه زي ما بتتوقع ولا لأ بيعتمد على ترميز الفرميون-للكيوبت، اللي بيتحدد أثناء الترجمة مش هنا. في الترميزات القائمة على أساس الإشغال زي Jordan-Wigner كل نمط بيتحمل على كيوبت واحد والبت هو إشغال النمط ده؛ شوف FermionicMeasure.
ترجم الدوائر الفرميونية
لتنفيذ الخوارزمية الكمّية اللي بتمثلها FermionicCircuit بتاعتك لازم تتترجم (transpile) لـ QuantumCircuit. تقدر تعرف إزاي تعمل ده في دليل ترجمة الدوائر الفرميونية.
الخطوات الجاية
-
اتعرف على البوابات الفرميونية المتاحة في توثيق
qiskit_fermions.circuit.library. -
استكشف دليل شرح المُشغّلات عشان تفهم إزاي تبني هاميلتونيات فرميونية تقدر تستخدمها مع الدوائر الفرميونية.
-
راجع دليل البداية SQDRIFT لمثال عملي متكامل.
-
اقرأ دليل علاقة ffsim عشان تفهم إزاي تقدر
FermionicCircuitتتحاكى مباشرةً، وإزاي فهارس الأنماط العامة دي بتاخد دلالات السبين وقت المحاكاة بس.

