حلّال القيمة الذاتية الكمّي التغايري (VQE)
لهذه الوحدة، يحتاج الطلاب إلى بيئة Python تعمل بشكل صحيح، مع أحدث إصدارات الحزم التالية مثبّتة:
qiskitqiskit_ibm_runtimeqiskit-aerqiskit.visualizationnumpypylatexenc
لإعداد هذه الحزم وتثبيتها، راجع دليل تثبيت Qiskit. لتشغيل المهام على حواسيب كمّية حقيقية، يحتاج الطلاب إلى إعداد حساب IBM Cloud باتباع الخطوات الواردة في دليل إعداد حساب IBM Cloud.
تم اختبار هذه الوحدة واستخدمت ما يقارب 8 دقائق من وقت وحدة معالجة الكم (QPU). هذا تقدير تقريبي، وقد يختلف الاستخدام الفعلي.
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-aer qiskit-ibm-runtime scipy
# Uncomment and modify this line as needed to install dependencies
#!pip install 'qiskit>=2.1.0' 'qiskit-ibm-runtime>=0.40.1' 'qiskit-aer>=0.17.0' 'numpy' 'pylatexenc'
مقدمة
منذ تطوير النموذج الميكانيكي الكمّي في مطلع القرن العشرين، أدرك العلماء أن الإلكترونات لا تسير في مسارات ثابتة حول نواة الذرة، بل توجد في مناطق احتمالية تُعرف بالمدارات. تقابل هذه المدارات مستويات طاقة محددة ومتقطعة يمكن للإلكترونات أن تشغلها. تستقر الإلكترونات بطبيعتها في أدنى مستويات الطاقة المتاحة، وهو ما يُعرف بالحالة الأساسية. غير أن الإلكترون إذا امتص طاقة كافية، يمكنه الانتقال إلى مستوى طاقة أعلى، فيدخل في حالة مثارة. هذه الحالة المثارة مؤقتة، وسيعود الإلكترون في نهاية المطاف إلى مستوى طاقة أدنى، محرراً الطاقة الممتصة، في الغالب على شكل ضوء. هذه العملية الأساسية لامتصاص الطاقة وإطلاقها ضرورية لفهم كيفية تفاعل الذرات وتكوين الروابط.
عندما تتقارب الذرات لتكوّن جزيئات، تتحد مداراتها الذرية لتشكّل مدارات جزيئية. يحدد ترتيب الإلكترونات ومستويات طاقتها داخل هذه المدارات الجزيئية خصائص الجزيء الناتج وقوة الروابط الكيميائية. فمثلاً، في تكوّن جزيء الهيدروجين () من ذرتَي هيدروجين منفصلتين، يشغل إلكترون كل ذرة مدارات ذرية. وحين تقترب الذرتان من بعضهما، تتداخل هذه المدارات الذرية وتتحد لتشكّل مدارات جزيئية جديدة — إحداها ذات طاقة منخفضة (مدار رابط) والأخرى ذات طاقة أعلى (مدار مضاد للرابط). يُفضّل الإلكترونان، أحدهما من كل ذرة هيدروجين، شغل المدار الرابط منخفض الطاقة، مما يؤدي إلى تكوين رابطة تساهمية مستقرة تُمسك جزيء معاً. يحدد فرق الطاقة بين الذرتين المنفصلتين والجزيء المتشكّل — ولا سيما طاقة الإلكترونات في المدارات الجزيئية — استقرار الرابطة وخصائصها.
في الأقسام التالية، سنستكشف عملية التكوّن الجزيئي هذه مع التركيز على جزيء . سنستخدم حاسوباً كمّياً حقيقياً مقروناً بتقنيات التحسين الكلاسيكي لإيجاد طاق ة هذه العملية البسيطة والأساسية في آنٍ معاً. سيقدم هذا التجريب عرضاً عملياً لكيفية تطبيق الحوسبة الكمّية على حل مشكلات الكيمياء الحسابية، مع إلقاء الضوء على دور طاقة الإلكترونات.
VQE - خوارزمية كمّية تغايرية لمسائل القيمة الذاتية
تقنيات التقريب في الكيمياء - المبدأ التغايري ومجموعة الأساس
لا تقتصر إسهامات إيرفين شرودنغر في ميكانيكا الكم على تقديم نموذج إلكتروني جديد؛ فقد أسّس في جوهره ميكانيكا الموجات بتطويره معادلة شرودنغر الزمنية الشهيرة:
هنا، هو عامل هاملتون الذي يمثّل الطاقة الكلية للنظام، و هي دالة الموجة التي تحمل كل المعلومات عن الحالة الكمّية للنظام. (ملاحظة: هو المشتق الكلي بالنسبة للزمن، ولا نضمّن هنا بصريح العبارة قيمة القيمة الذاتية للطاقة .)
غير أنه في كثير من التطبيقات العملية — كتحديد مستويات الطاقة المسموح بها في الذرات والجزيئات — نلجأ بدلاً من ذلك إلى معادلة شرودنغر المستقلة عن الزمن (معادلة القيمة الذاتية للطاقة)، المشتقة من الصيغة الزمنية بافتراض حالة ساكنة. الحالة الساكنة هي حالة كمّية لا تتغير فيها كثافة الاحتمال لإيجاد الجسيم عند نقطة معينة في الفضاء بمرور الزمن.
في هذه الصيغة، تمثّل قيمة القيمة الذاتية للطاقة المقابلة للحالة الكمّية . يتضمن هاملتون مساهمات طاقوية متنوعة، كالطاقة الحركية للإلكترونات والنوى، والقوى الجاذبة بين الإلكترونات والنوى، والقوى الطاردة بين الإلكترونات.
يتيح لنا حل معادلة القيمة الذاتية للطاقة حساب مستويات الطاقة المكمّمة للأنظمة الذرية والجزيئية. إلا أن حلّها بدقة تامة أمر عسير بالنسبة للجزيئات، لأن دالة الموجة التي تصف التوزيع المكاني للإلكترونات معقدة وعالية الأبعاد.
لذلك، يلجأ العلماء إلى تقنيات التقريب للحصول على حلول عملية ودقيقة. سنركز في هذا العمل على أسلوبين رئيسيين:
-
المبدأ التغايري
يقرّب هذا الأسلوب دالة الموجة ويضبطها للاقتراب قدر الإمكان من الطاقة المستهدفة، وهي عادةً طاقة الحالة الأساسية للنظام. الفكرة المحورية وراء المبدأ التغايري بسيطة:
- إذا خمّنا دالة موجة (دالة "تجريبية")، فإن الطاقة المحسوبة منها ستكون دائماً مساوية أو أعلى من طاقة الحالة الأساسية () للنظام.
- بضبط المعاملات في الدالة التجريبية، ، يمكننا الحصول على تقريب أفضل فأفضل لطاقة الحالة الأساسية.
- تعتمد دقته بشكل كبير على اختيار دالة الموجة التجريبية . فالدالة التجريبية المختارة بعشوائية قد تعطي تقديراً للطاقة بعيداً عن الدقة.
-
تقريب مجموعة الأساس
يأتي الأسلوب التقريبي الثاني في مرحلة بناء دالة الموجة — وهو نهج مجموعة الأساس. في الكيمياء الكمّية، يكاد يكون من المستحيل حل معادلة شرودنغر بدقة تامة للجزيئات. بدلاً من ذلك، نقرّب دالة الموجة متعددة الإلكترونات المعقدة بتركيبها من دوال رياضية أبسط ومحددة مسبقاً. مجموعة الأساس في جوهرها مجموعة من هذه الدوال الرياضية المعروفة، المتمركزة عادةً حول الذرات في الجزيء، وتُستخدم كوحدات بناء لتمثيل شكل الإلكترونات وسلوكها في النظام. تخيّل الأمر كمحاولة إعادة إنشاء منحوتة مفصّلة باستخدام مجموعة من قطع LEGO القياسية فحسب — كلما توفرت لديك أنواع وأحجام أكثر من القطع (أي كلما كانت مجموعة الأساس أكبر)، كل ما كان بإمكانك تقريب الشكل الأصلي بدقة أكبر.
كثيراً ما تستلهم دوال الأساس هذه من الحلول التحليلية لأنظمة بسيطة كذرة الهيدروجين، آخذةً أشكالاً كدوال غاوس أو دوال نوع سلاتر، وإن كانت لا تزال تقريبات. وعوضاً عن العمل مع المدارات الجزيئية الكاملة "الدقيقة" نظرياً لكنها غير قابلة للحل عملياً، نعبّر عنها بوصفها تركيبة خطية (مجموعاً بمعاملات) من دوال الأساس هذه. يُعرف هذا الأسلوب بنهج التركيبة الخطية للمدارات الذرية (LCAO) حين تشبه دوال الأساس المدارات الذرية. بتحسين المعاملات في هذه التركيبة الخطية، يمكننا إيجاد أفضل دالة موجة تقريبية وطاقة ممكنتين ضمن حدود مجموعة الأساس المختارة.
- كلما زاد عدد الدوال المدرجة في مجموعة الأساس، كان التقريب أدق، لكن ذلك يأتي على حساب جهد حسابي أعلى.
- تعطي مجموعة الأساس الصغيرة تقديراً تقريبياً، بينما تعطي مجموعة الأساس الكبيرة نتائج أدق مع الحاجة إلى موارد حسابية أكثر.
خلاصة القول، لجعل الحسابات قابلة للتنفيذ وتقليل التكلفة الحسابية، نستخدم المبدأ التغايري بتقريب دالة الموجة، مما يقلص التعقيد الحسابي ويتيح التحسين التكراري لتقليل الطاقة. في المقابل، يبسّط نهج مجموعة الأساس الحسابات بتمثيل المدارات الذرية بوصفها تركيبة من دوال محددة مسبق اً، عوضاً عن حل دالة موجة مستمرة مباشرةً.
تحقق من فهمك
تأمّل دالة الموجة التجريبية حيث ثابت تسوية و معامل قابل للضبط.
(a) سوّ دالة الموجة التجريبية بإيجاد بحيث
.
(b) احسب القيمة المتوقعة لعامل هاملتون المعطى بـ:
حيث ، وهو ما يقابل كمون المذبذب التوافقي البسيط.
(c) استخدم المبدأ التغايري لإيجاد الأمثل بتصغير
الإجابة:
(a) لتسوية دالة الموجة التجريبية المعطاة:
استخدم تكامل غاوس:
ضع فتحصل على:
(b) هاملتون المذبذب التوافقي هو:
- القيمة المتوقعة للطاقة الحركية
بأخذ المشتق الثاني:
وبذلك:
باستخدام نتائج تكامل غاو س القياسية:
- القيمة المتوقعة للطاقة الكامنة
باستخدام:
نحصل على:
- القيمة المتوقعة للطاقة الكلية
(c) تحسين للحصول على الطاقة الدنيا
الاشتقاق:
بالحل:
بتعويض في :
وهو ما يطابق طاقة الحالة الأساسية الدقيقة للمذبذب التوافقي الكمّي.
VQE (حلّال القيمة الذاتية الكمّي التغايري)
حلّال القيمة الذاتية الكمّي التغايري (VQE) هو الأسلوب الرئيسي الذي سنستخدمه لاستكشاف عملية ، وسنلقي هنا نظرة على ماهية VQE وآلية عمله. لكن لنتوقف أولاً ونستعرض أمراً بالغ الأهمية من خلال سؤال التحقق التالي.
تحقق من فهمك
إذا كان لدينا بالفعل هذا الكم من الاستراتيجيات لمسائل الكيمياء، فلماذا نحتاج إلى حاسوب كمّي؟ وما الغرض من استخدام الحواسيب الكمّية والكلاسيكية معاً؟
الإجابة:
تملك الحوسبة الكمّية فرصة لإحداث ثورة في الكيمياء من خلال معالجة المسائل التي تعجز الحواسيب الكلاسيكية عنها بسبب التمدد الأسي لحالات الكم. أشار ريتشارد فاينمان بعبارته الشهيرة إلى أن محاكاة الطبيعة تستلزم أن تكون الحسابات بدورها كمّية [مرجع 1].
فمثلاً، محاكاة مادة الكافيين بأبسط مجموعة أساس (STO-3G) تتطلب بت، وهو عدد أكبر بكثير من إجمالي عدد النجوم في الكون المرئي () [مرجع 2]. أما الحاسوب الكمّي فبإمكانه وصف المدارات الإلكترونية للكافيين بـ160 كيوبت فحسب.
تعالج الحواسيب الكمّية التفاعلات الكمّية بطبيعتها مستخدمةً التراكب والتشابك الكمّي، مما يوفر سبيلاً واعداً لتمكين محاكاة جزيئية دقيقة. فضلاً عن ذلك، يمكننا الجمع بين مزايا الحواسيب الكمّية (محاكاة الإلكترونات) والحواسيب الكلاسيكية (المعالجة المسبقة واللاحقة للبيانات، وإدارة عمليات الخوارزميات، والتحسين، وغير ذلك). ومن المتوقع أن يعزز هذا التكامل اكتشاف المواد، وتصميم الأدوية، والتنبؤ بالتفاعلات، مما يقلص التجارب المكلفة بالمحاولة والخطأ. [مرجع 3][مرجع 4]
إذا أردت معرفة لماذا تُحتاج الحواسيب الكمّية لمسائل الكيمياء ولماذا نستخدم الحوسبة الكمّية والكلاسيكية معاً، فاطّلع على المقالات التالية:
لنعد الآن إلى VQE.
يجمع VQE بين قدرة الحواسيب الكمّية والكلاسيكية، مستخدماً في جوهره المبادئ التغايرية لإيجاد طاقة الحالة الأساسية للنظام. لفهم VQE، قسّمه أولاً إلى ثلاثة أجزاء:

(الجزء الكمّي) المقياس: هاملتون الجزيء (طاقة الجزيء)
في VQE، يُعدّ هاملتون الجزيء / الذرة مقياساً قابلاً للقياس، أي يمكننا قياس قيمته تجريبياً. هدفنا إيجاد أدنى طاقة ممكنة (طاقة الحالة الأساسية) للجزيء. لتحقيق ذلك، نستخدم حالة كمّية تجريبية يولّدها دائرة كمّية ذات معاملات (ansatz)، ونقيس المقياس ونحسّن الحالة الكمّية حتى نصل إلى أدنى طاقة ممكنة.
تحدد مجموعة الأساس المستخدمة لهاملتون الجزيء عدد الكيوبتات المطلوبة وتؤثر مباشرة على دقة VQE. يعدّ اختيار مجموعة الأساس المناسبة أمراً حاسماً لتحقيق التوازن بين الكفاءة والدقة. لتبسيط الحسابات دون تغيير مجموعة الأساس، يمكننا اللجوء إلى استراتيجيات كفرض التماثل وتقليص الفضاء النشط. كثير من الجزيئات ذات أشكال متماثلة (كالفراشة أو ندفة الثلج)، مما يعني أن بعض أجزائها تتصرف بالطريقة ذاتها. بدلاً من حساب كل جزء على حدة، يمكننا التركيز على الأجزاء الفريدة فحسب، مما يوفر موارد الكم ويستثمر التماثل. أما في تقليص الفضاء النشط، فنأخذ بعين الاعتبار المدارات المهمة فقط، إذ ليس لجميع الإلكترونات تأثير يُذكر على طاقة الجزيء؛ فالإلكترونات القريبة من النواة تبقى في معظمها دون تغيير، بينما يؤثر غيرها على الترابط. بتطبيق هذه الأساليب، يمكننا جعل VQE أكثر كفاءة مع الحفاظ على الدقة.
بمجرد الحصول على هاملتون جزيئي بمجموعة الأساس المناسبة والاستراتيجيات المذكورة أعلاه، نحتاج إلى تحويل هذا الهاملتون إلى صيغة مناسبة للحواسيب الكمّية. قد يكون رسم خرائط المسائل على عوامل باولي أمراً بالغ التعقيد. وهذا صحيح بشكل خاص في الكيمياء الكمّية التي تتعامل مع جسيمات غير قابلة للتمييز (الإلكترونات)، في حين أن الكيوبتات قابلة للتمييز. لن نتناول هنا تفاصيل رسم الخرائط، لكننا نحيلك إلى المصادر التالية. يمكنك العثور على نقاش عام حول رسم خريطة مسألة على العوامل الكمّية في الحوسبة الكمّية في التطبيق. ونقاش أكثر تفصيلاً حول رسم خرائط مسائل الكيمياء على العوامل الكمّية في الكيمياء الكمّية مع VQE.
في هذه الوحدة، سنزودك بهاملتونات (أحادية الكيوبت) مناسبة لـ و كي نتمكن من التركيز على استخدام الحاسوب الكمّي. هذه الهاملتونات أحادية الكيوبت مُعدّة باستخدام مجموعة الأساس STO-6G ورسم الخريطة Jordan-Wigner، وهو أبسط رسم خريطة بأوضح تفسير فيزيائي، إذ يربط إشغال دوران-مدار واحد بإشغال كيوبت واحد. كما استخدمنا تقنية تقليص الكيوبتات باستغلال تماثل الهاملتون، التي تستخدم الأنماط في سلوك إشغالات الدوران لتقليل عدد الكيوبتات. لجزيء ، نفترض أن المسافة بين ذرتَي الهيدروجين هي 0.735 .
(الجزء الكمّي) الـ Ansatz: دالة الموجة التجريبية (كيفية بناء حالة كمّية بسيطة بدائرة كمّية)
في VQE، يتكوّن الـ ansatz (الجمع: ansätze) من مكوّنين رئيسيين. الأول هو تحضير الحالة الابتدائية، الذي يُهيئ حالة الكيوبت بتطبيق بوابات كمّية بدون معاملات تغايرية. أما المكوّن الثاني فهو الدائرة الكمّية ذات المعاملات، وهي دائرة كمّية خاصة بمعاملات قابلة للضبط، شبيهة بأقراص ضبط الراديو. ستُستخدم هذه المعاملات في الجزء الأخير — المحسّن الكلاسيكي — لمساعدتنا على الوصول إلى أفضل حالة أساسية ممكنة.
في قسم المبدأ التغايري، تعلمنا أن جودة الحالة التجريبية تؤثر على جودة نتائج الخوارزمية التغايرية. هذا يعني أن اختيار ansatz جيد أمر مهم في VQE. مرة أخرى، هذا موضوع غني ومعقد. لن نتناول هنا أنواع الـ ansatz المختلفة أو أصولها. إن كنت مهتماً بمعرفة المزيد عن الدوائر الكمّية ذات المعاملات والـ ansatz، يمكنك استكشاف درس الـ Ansatz والصيغة التغايرية من دورة تصميم الخوارزميات التغايرية، الذي يقدم شروحات وأمثلة تفصيلية عن ansätze.
بما أننا سنستخدم هاملتون أحادي الكيوبت في هذه الوحدة، نحتاج إلى دائرة كمّية أحادية الكيوبت ذات معاملات بوصفها ansatz. سنستعرض في القسم التالي ثلاثة أنواع من ansätze أحادية الكيوبت، ونقارن بينها ونناقش الاعتبارات الرئيسية في اختيار الـ ansatz.
(الجزء الكلاسيكي) المحسّن: الضبط الدقيق للدائرة الكمّية
بمجرد أن يقيس الحاسوب الكمّي طاقة المقياس من الـ ansatz، تُرسل معاملات الـ ansatz وقيمة الطاقة إلى المحسّن الكلاسيكي للضبط. تُنفَّذ عملية التحسين هذه على حاسوب كلاسيكي، وعادةً باستخدام حزم علمية متعددة الأغراض كـSciPy.
يتعامل المحسّن الكلاسيكي مع الطاقة المقاسة بوصفها دالة تكلفة. في مسائل التحسين، دالة التكلفة (التي تُسمى أحياناً الدالة الهدف) هي دالة رياضية تقيس مدى "جودة" حل معين. هدف المحسّن إيجاد مجموعة المعاملات التي تُصغّر هذه الدالة. في سياق إيجاد طاقة الحالة الأساسية لجزيء، تُشكّل الطاقة ذاتها دالة التكلفة — نريد إيجاد المعاملات لدائرتنا الكمّية (حلنا) التي تعطي أدنى طاقة ممكنة. يستخدم المحسّن الكلاسيكي قيمة الطاقة المقاسة (التكلفة) ويحدد مجموعة المعاملات المحسّنة التالية للـ ansatz الكمّي. ثم تُرسَل هذه المعاملات المحدّثة إلى الدائرة الكمّية، وتتكرر العملية. مع كل تكرار، يضبط المحسّن الكلاسيكي المعاملات في محاولة لتقليص الطاقة (تصغير دالة التكلفة) حتى يتحقق معيار تقارب محدد مسبقاً، مع السعي للتأكد من إيجاد أدنى طاقة ممكنة (المقابلة للحالة الأساسية للجزيء عند مسافة الرابط ومجموعة الأساس المحددتين).
تتوفر كثير من استراتيجيات التحسين في الحزم العلمية كـSciPy. يمكنك الاطلاع على المزيد في درس حلقات التحسين من دورة تصميم الخوارزميات التغايرية. سنستخدم هنا COBYLA (التحسين المقيّد بالتقريبات الخطية)، وهو خوارزمية تحسين مناسبة لمناظر الطاقة المعقدة. تحديداً، لا يحاول COBYLA حساب مشتق الدالة المدروسة؛ وهذا ما يُعرف بالمحسّن الخالي من التدرج. تخيّل أنك تحاول إيجاد أعلى قمة في سلسلة جبال وعيناك مغمضتان. بما أنك لا ترى المشهد بأكمله، تخطو خطوات صغيرة في اتجاهات مختلفة مع التحقق إذا كنت تصعد أم تنزل. يعمل COBYLA بطريقة مماثلة — يتنقل في فضاء المعاملات مختبراً قيماً مختلفة، محسّناً النتيجة تدريجياً حتى يجد أفضل قيمة.
الآن أنت مستعد لإجراء حساب VQE. لذا، جرّب سؤال التحقق أدناه الذي يلخص العملية الكاملة.
تحقق من فهمك
املأ الفراغات بالمصطلحات الصحيحة لإكمال ملخص عملية VQE.
VQE هو خوارزمية كمّية تغايرية تجمع بين قدرة (1) ________ وال حوسبة الكلاسيكية، وتُستخدم لإيجاد (2) __________ لجزيء ما. تبدأ العملية بتعريف (3) __________، الذي يمثّل الطاقة الكلية للنظام ويعمل بوصفه مقياساً في القياسات الكمّية. بعدها نُعدّ (4) __________، وهو دائرة كمّية بمعاملات قابلة للضبط تمثّل دالة الموجة التجريبية للجزيء. تُحسَّن هذه المعاملات باستخدام (5) __________، وهو خوارزمية كلاسيكية تضبط المعاملات بصورة تكرارية لتصغير الطاقة المقاسة. في النقاش أعلاه استخدمنا محسّن (6) __________، الذي يُعدّل معاملات الـ ansatz دون الحاجة إلى حسابات تفاضلية. تستمر العملية حتى نصل إلى (7) __________، أي إيجاد أدنى طاقة ممكنة للجزيء.
بنك الكلمات:
- classical optimizer (المحسّن الكلاسيكي)
- ground state energy (طاقة الحالة الأساسية)
- hardware-efficient (كفء للعتاد)
- ansatz
- molecular Hamiltonian (هاملتون الجزيء)
- COBYLA
- quantum computing (الحوسبة الكمّية)
- convergence (التقارب)
الإجابة:
1 → quantum computing (الحوسبة الكمّية)
2 → ground state energy (طاقة الحالة الأساسية)
3 → molecular Hamiltonian (هاملتون الجزيء)
4 → ansatz
5 → classical optimizer (المحسّن الكلاسيكي)
6 → COBYLA
7 → convergence (التقارب)
احسب ط اقة الحالة الأساسية لذرة الهيدروجين باستخدام VQE
الآن، لنطبّق ما تعلّمناه لحساب طاقة الحالة الأساسية لذرة الهيدروجين. على مدار هذا الموديول، سنستخدم إطار عمل للحوسبة الكمومية يُعرف بـ "أنماط Qiskit"، الذي يقسّم سير العمل إلى الخطوات التالية:
- الخطوة 1: تحويل المدخلات الكلاسيكية إلى مسألة كمومية
- الخطوة 2: تحسين المسألة لتناسب التنفيذ الكمومي
- الخطوة 3: التنفيذ باستخدام أوليّات Qiskit Runtime
- الخطوة 4: المعالجة اللاحقة والتحليل الكلاسيكي
سنتبع هذه الخطوات بشكل عام.
لنبدأ بتحميل بعض الحزم الضرورية، بما فيها أوليّات Qiskit Runtime. كما سنختار أقل جهاز حوسبة كمومية انشغالاً متاح لنا.
يوجد أدناه كود لحفظ بيانات اعتمادك عند الاستخدام الأول. تأكد من حذف هذه المعلومات من الدفتر بعد حفظها في بيئتك، حتى لا تُشارَك بيانات اعتمادك بشكل غير مقصود عند مشاركة الدفتر. راجع إعداد حسابك في IBM Cloud وتهيئة الخدمة في بيئة غير موثوقة للحصول على مزيد من التوجيهات.
# Load the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService
# Load the Runtime primitive and session
from qiskit_ibm_runtime import EstimatorV2 as Estimator
# Syntax for first saving your token. Delete these lines after saving your credentials.
# QiskitRuntimeService.save_account(channel='ibm_quantum_platform', instance = '<YOUR_IBM_INSTANCE_CRN>', token='<YOUR-API_KEY>', overwrite=True, set_as_default=True)
# service = QiskitRuntimeService(channel='ibm_quantum_platform')
# Load saved credentials
service = QiskitRuntimeService()
# Use the least busy backend, or uncomment the loading of a specific backend like "ibm_brisbane".
backend = service.least_busy(operational=True, simulator=False, min_num_qubits=127)
# backend = service.backend("ibm_brisbane")
print(backend.name)
ibm_brisbane
الخلية التالية ستتيح لك التبديل بين استخدام المحاكي أو العتاد الفعلي على مدار الدفتر. نوصي بتشغيلها الآن:
# Load the Aer simulator and generate a noise model based on the currently-selected backend.
from qiskit_aer import AerSimulator
from qiskit_aer.noise import NoiseModel
# Alternatively, load a fake backend with generic properties and define a simulator.
noise_model = NoiseModel.from_backend(backend)
# Define a simulator using Aer, and use it in Sampler.
backend_sim = AerSimulator(noise_model=noise_model)
الخطوة 1: تحويل المسألة إلى دوائر كمومية ومؤثرات
نبدأ حساب VQE بتعريف هاملتونيان جزيئة الهيدروجين () عند مسافة ربط محددة. يمثّل هذا الهاملتونيان الطاقة الكلية للنظام من حيث مؤثرات الكيوبت، وقد جرى اشتقاقه وتحويله من النظام الجزيئي باتباع إجراء قياسي: 1) استخدام مجموعة الأساس STO-6G (مجموعة محددة من الدوال الرياضية تُستخدم لتقريب المدارات الإلكترونية)، 2) تطبيق تحويل جوردان-ويغنر (تقنية لترجمة المؤثرات الفيرميونية التي تصف الإلكترونات إلى مؤثرات كيوبت)، 3) إجراء تقليل الكيوبت باستخدام تماثلات الهاملتونيان لتبسيط المسألة.
كما أوضحنا سابقاً، تعتمد طاقات الحالة الأساسية المحسوبة اعتماداً كبيراً على اختيار مجموعة الأساس والشكل الهندسي للجزيء (كمسافة الربط). لهذا التهيئة المحددة وبعد هذه التحويلات، يكون الهاملتونيان الكيوبتي الناتج بسيطاً:
هنا، يمثّل مؤثر الهوية ويمثّل مؤثر باولي-Z، ويعملان على كيوبت واحد. تُشتق المعاملات من التكاملات المحسوبة باستخدام مجموعة الأساس STO-6G عند مسافة الربط هذه مع التحويل المناسب.
بعد تعريف هذا الهاملتونيان، يمكننا الآن استخدام VQE لحساب طاقة حالته الأساسية. من المفيد مقارنة طاقة الحالة الأساسية المحسوبة لدينا بالقيم المتوقعة. لذرة هيدروجين واحدة معزولة (H)، تكون طاقة الحالة الأساسية تساوي تماماً -0.5 هارتري (في غياب التأثيرات النسبية). لنحسب طاقة الحالة الأساسية الدقيقة لهاملتونياننا الكيوبتي المحدد كما هو معرّف أعلاه ونقارنه بالقيم المعروفة ذات الصلة.
from qiskit.quantum_info import SparsePauliOp
import numpy as np
# Qubit Hamiltonian of the hydrogen atom generated by using STO-3G basis set and parity mapping
Hamiltonian = SparsePauliOp.from_list([("I", -0.2355), ("Z", 0.2355)])
# exact ground state energy of Hamiltonian
A = np.array(Hamiltonian)
eigenvalues, eigenvectors = np.linalg.eig(A)
print(
"The exact ground state energy of the Hamiltonian is ",
min(eigenvalues).real,
"hartree",
)
h = min(eigenvalues.real)
The exact ground state energy of the Hamiltonian is -0.471 hartree
بعد ذلك، نحتاج إلى دائرة كمومية ذات معاملات، أي أنساتز، لتهيئة دالة موجة تجريبية للحالة الأساسية. الهدف هو إيجاد المعاملات التي تقلّل قيمة توقع الطاقة . يُعدّ اختيار الأنساتز أمراً بالغ الأهمية لأنه يحدد مجموعة الحالات الكمومية الممكنة التي يمكن لدائرتنا إعدادها. الأنساتز "الجيد" هو الذي يكون مرناً بما يكفي لتمثيل حالة قريبة جداً من الحالة الأساسية الحقيقية للهاملتونيان الذي ندرسه، لكن ليس بالغ التعقيد بحيث يتطلب معاملات كثيرة أو دائرة عميقة جداً لأجهزة الحوسبة الكمومية الحالية.
هنا، سنجرّب ثلاثة أنساتزات مختلفة أحادية الكيوبت لنرى أيّها يوفر "تغطية" أفضل للحالات الكمومية الممكنة لكيوبت واحد. تشير "التغطية" إلى نطاق الحالات الكمومية التي يمكن لدائرة الأنساتز إنتاجها عن طريق تغيير معاملاتها.
سنستخدم ثلاثة أنساتزات مستندة إلى مجموعات مختلفة من بوابات الدوران أحادية الكيوبت:
- أنساتز بوابة دوران حول محور واحد: يستخدم هذا الأنساتز الدورانات حول محور واحد فقط (). على كرة بلوخ، يقابل هذا التحرك على طول دائرة محددة فقط. وهو الأقل مرونة ويغطي مجموعة محدودة من الحالات.
- أنساتزان ببوابتَي دوران حول محورَين: يجمع هذان الأنساتزان الدورانات حول محورين مختلفين ( و ). يتيح هذا الوصول إلى جزء أكبر من كرة بلوخ مقارنةً بالدوران حول محور واحد.
من خلال مقارنة نتائج VQE التي نحصل عليها مع هذه الأنساتزات الثلاثة، يمكننا رؤية كيف تؤثر مرونة الأنساتز وتغطيته لفضاء الحالات على قدرتنا في إيجاد طاقة الحالة الأساسية الحقيقية لهاملتونياننا المبسّط. الأنساتز الأكثر مرونة لديه القدرة المحتملة على إيجاد تقريب أفضل، لكنه قد يكون أصعب على المحسّن الكلاسيكي.
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
from qiskit.quantum_info import Statevector, DensityMatrix, Pauli
theta = Parameter("θ")
phi = Parameter("φ")
lam = Parameter("λ")
ansatz1 = QuantumCircuit(1)
ansatz1.rx(theta, 0)
ansatz2 = QuantumCircuit(1)
ansatz2.rx(theta, 0)
ansatz2.rz(phi, 0)
ansatz3 = QuantumCircuit(1)
ansatz3.rx(theta, 0)
ansatz3.rz(phi, 0)
ansatz3.rx(lam, 0)
<qiskit.circuit.instructionset.InstructionSet at 0x1059def80>
الآن، لنولّد 5000 رقم عشوائي لكل معامل ونرسم توزيع الحالات الكمومية العشوائية التي تولّدها الأنساتزات الثلاثة بهذه المعاملات العشوائية. يمكنك التفكير في هذه المعاملات كدورانات حول محاور مختلفة على سطح كروي. لرؤية توزيع الحالة ال كمومية، سنستخدم كرة بلوخ، وهي كرة ثلاثية الأبعاد تُظهر حالة كيوبت واحد. أي نقطة على الكرة تمثل حالة ممكنة للكيوبت، حيث يشبه القطبان الشمالي والجنوبي الحالتين الكلاسيكيتين "0" و"1"، لكن يمكن للكيوبت أن يكون في أي مكان بينهما، مما يُظهر خصائص كمومية خاصة كالتراكب. أولاً، جهّز الدوال اللازمة لرسم كرة بلوخ ثلاثية الأبعاد وأعدّ 5000 معامل عشوائي.
import matplotlib.pyplot as plt
def plot_bloch(bloch_vectors):
# Extract X, Y, Z coordinates for 3D projection
X_coords = bloch_vectors[:, 0]
Z_coords = bloch_vectors[:, 2]
# Compute Y coordinates from X and Z to approximate the full Bloch sphere projection
Y_coords = bloch_vectors[:, 1]
# Create 3D plot
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(111, projection="3d")
ax.scatter(X_coords, Y_coords, Z_coords, color="blue", alpha=0.6)
# Labels and title
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_title("Parameterized 1-Qubit Circuit on 3D Bloch Sphere")
# Set axis limits and make them equal
ax.set_xlim([-1, 1])
ax.set_ylim([-1, 1])
ax.set_zlim([-1, 1])
# Ensure equal aspect ratio for all axes
ax.set_box_aspect([1, 1, 1]) # Equal scaling for x, y, z axes
# Show grid
ax.grid(True)
plt.show()
num_samples = 5000 # Number of random states
theta_vals = np.random.uniform(0, 2 * np.pi, num_samples)
phi_vals = np.random.uniform(0, 2 * np.pi, num_samples)
lam_vals = np.random.uniform(0, 2 * np.pi, num_samples)
لنرَ كيف يعمل أنساتزنا الأول.
# List to store Bloch Sphere XZ coordinates
bloch_vectors = []
# Generate quantum states and extract Bloch vectors
for i in range(num_samples):
# Create a circuit and bind parameters
qc = ansatz1
bound_qc = qc.assign_parameters({theta: theta_vals[i]}) # , lam: lam_vals[i]})
state = Statevector.from_instruction(bound_qc)
rho = DensityMatrix(state)
X = rho.expectation_value(Pauli("X")).real
Y = rho.expectation_value(Pauli("Y")).real
Z = rho.expectation_value(Pauli("Z")).real
bloch_vectors.append([X, Y, Z]) # Store X, Z components
# Convert to a numpy array for plotting
bloch_vectors = np.array(bloch_vectors)
plot_bloch(bloch_vectors)

يمكننا أن نرى أن أنساتزنا الأول يُعيد حالات كمومية موزّعة على شكل حلقة على كرة بلوخ. وهذا منطقي، لأننا أعطينا الأنساتز معاملاً دورانياً واحداً فقط، فلا يمكنه إذن إلا إنتاج حالات تُشكّل دورانات حول محور واحد. الانطلاق من النقطة والدوران حول محور واحد سينتج دائماً حلقة. ثم لنتحقق من أنساتزنا الثاني الذي يحتوي على بوابتَي دوران متعامدتَين - Rx و Rz.
bloch_vectors = []
# Generate quantum states and extract Bloch vectors
for i in range(num_samples):
# Create circuit and bind parameters
qc = ansatz2
bound_qc = qc.assign_parameters(
{theta: theta_vals[i], phi: phi_vals[i]}
) # , lam: lam_vals[i]})
state = Statevector.from_instruction(bound_qc)
rho = DensityMatrix(state)
X = rho.expectation_value(Pauli("X")).real
Y = rho.expectation_value(Pauli("Y")).real
Z = rho.expectation_value(Pauli("Z")).real
bloch_vectors.append([X, Y, Z]) # Store X, Z components
# Convert to numpy array for plotting
bloch_vectors = np.array(bloch_vectors)
plot_bloch(bloch_vectors)

هنا يمكننا أن نرى أن أنساتزنا الثاني يغطي جزءاً أكبر من كرة بلوخ - لكن لاحظ أن النقاط تتمركز أكثر عند القطبين وتنتشر أكثر عند خط الاستواء. حان الآن وقت التحقق من أنساتز نا الأخير.
bloch_vectors = []
# Generate quantum states and extract Bloch vectors
for i in range(num_samples):
# Create circuit and bind parameters
qc = ansatz3
bound_qc = qc.assign_parameters(
{theta: theta_vals[i], phi: phi_vals[i], lam: lam_vals[i]}
)
state = Statevector.from_instruction(bound_qc)
rho = DensityMatrix(state)
X = rho.expectation_value(Pauli("X")).real
Y = rho.expectation_value(Pauli("Y")).real
Z = rho.expectation_value(Pauli("Z")).real
bloch_vectors.append([X, Y, Z]) # Store X, Z components
# Convert to numpy array for plotting
bloch_vectors = np.array(bloch_vectors)
plot_bloch(bloch_vectors)

هنا يمكنك رؤية الحالات الكمومية الأكثر انتظاماً في التوزيع التي يولّدها أنساتزنا الأخير.
كما ذكرنا، أفضل ما يمكن فعله هو اكتساب معرفة بالحالة الأساسية التي تبحث عنها واختيار أنساتز مناسب لاستكشاف الحالات القريبة من تلك الحالة الأساسية. مثلاً، لو علمنا أن حالتنا الأساسية قريبة من أحد القطبين، ربما كنا نختار الأنساتز 2. للتبسيط، سنبقى مع الأنساتز 3، الذي يستكشف كرة بلوخ بالكامل بشكل منتظم.
الآن بعد أن اخترنا أنساتزنا، لنرسم الدائرة.
# Pre-defined ansatz circuit and operator class for Hamiltonian
ansatz = ansatz3
num_params = ansatz.num_parameters
print("This circuit has ", num_params, "parameters")
ansatz.draw("mpl", style="iqp")
This circuit has 3 parameters
الخطوة 2: التحسين لعتاد الهدف
عند تشغيل حساب على جهاز حوسبة كمومية حقيقي، لا نهتم فقط بمنطق الدائرة الكمومية. بل نهتم أيضاً بأشياء مثل العمليات التي يمكن لذلك الجهاز الكمومي تنفيذها، وأين على الجهاز تقع الكيوبتات التي نستخدمها - هل هي متجاورة أم متباعدة؟ لذلك، الخطوة التالية هي إعادة كتابة دائرتنا باستخدام بوابات طبيعية لجهاز الحوسبة الكمومية الذي سنستخدمه، مع مراعاة تخطيط الكيوبتات. يمكن تحقيق ذلك عبر الترجمة (transpilation) - بعد هذه العملية، يمكنك رؤية أنساتزنا البسيط وقد تحوّل إلى مجموعة مختلفة من البوابات، وستُعيَّن كيوبتاتنا المجردة إلى كيوبتات فيزيائية على جهاز كمومي حقيقي.
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
config = backend.configuration()
print("Backend: {config.backend_name}")
print("Native gates: ", config.supported_instructions, ",")
target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
ansatz_isa = pm.run(ansatz)
ansatz_isa.draw(output="mpl", idle_wires=False, style="iqp")
Backend: {config.backend_name}
Native gates: ['ecr', 'id', 'delay', 'measure', 'reset', 'rz', 'sx', 'x'] ,
يمكنك ملاحظة أن بوابتَي rx, rz في أنساتزنا تحوّلتا إلى سلسلة من بوابات rz, sx، وهي البوابات الأصيلة لواجهتنا الخلفية. كذلك يمكنك رؤية أن q0 لدينا أصبح مُعيَّناً إلى الكيوبت الفيزيائي الخامس. نحتاج أيضاً إلى تحويل هاملتونياننا وفقاً لهذه التغييرات، كما في الكود التالي:
Hamiltonian_isa = Hamiltonian.apply_layout(layout=ansatz_isa.layout)
الخطوة 3: التنفيذ على عتاد الهدف
حان الآن وقت تشغيل VQE على وحدة معالجة كمومية حقيقية. لهذا، نحتاج أولاً إلى دالة تكلفة لعملية التحسين، تحسب قيمة توقع الهاملتونيان لحالة كمومية يولّدها الأنساتز. لا تقلق! لا تحتاج إلى كتابة كل شيء بنفسك. لقد أعددنا لك دالة لذلك، وكل ما عليك فعله هو تشغيل الخلية أدناه.
def cost_func(params, ansatz, hamiltonian, estimator):
"""Return estimate of energy from estimator
Parameters:
params (ndarray): Array of ansatz parameters
ansatz (QuantumCircuit): Parameterized ansatz circuit
hamiltonian (SparsePauliOp): Operator representation of Hamiltonian
estimator (EstimatorV2): Estimator primitive instance
cost_history_dict: Dictionary for storing intermediate results
Returns:
float: Energy estimate
"""
pub = (ansatz, [hamiltonian], [params])
result = estimator.run(pubs=[pub]).result()
energy = result[0].data.evs[0]
cost_history_dict["iters"] += 1
cost_history_dict["prev_vector"] = params
cost_history_dict["cost_history"].append(energy)
print(f"Iters. done: {cost_history_dict['iters']} [Current cost: {energy}]")
return energy
أخيراً، نجهّز المعاملات الأولية لأنساتزنا وعملية تحسينه. يمكنك ببساطة استخدام أصفار أو قيم عشوائية. اخترنا المعاملات الأولية أدناه، لكن لا تتردد في تعليق أو إلغاء تعليق الأسطر في الخلية لأخذ عينة من المعاملات بشكل عشوائي وبشكل منتظم من 0 إلى .
# x0 = np.random.uniform(0, 2*pi, 3)
x0 = [1, 1, 0]
# QPU Est. 2min for ibm_brisbane
from scipy.optimize import minimize
from qiskit_ibm_runtime import Batch
batch = Batch(backend=backend)
cost_history_dict = {
"prev_vector": None,
"iters": 0,
"cost_history": [],
}
estimator = Estimator(mode=batch)
estimator.options.default_shots = 10000
res = minimize(
cost_func,
x0,
args=(ansatz_isa, Hamiltonian_isa, estimator),
method="cobyla",
options={"maxiter": 10, "tol": 0.01},
)
batch.close()
Iters. done: 1 [Current cost: -0.3361517318448143]
Iters. done: 2 [Current cost: -0.4682546422099432]
Iters. done: 3 [Current cost: -0.38985802144149584]
Iters. done: 4 [Current cost: -0.38319217316749354]
Iters. done: 5 [Current cost: -0.4628720756579032]
Iters. done: 6 [Current cost: -0.4683301936226905]
Iters. done: 7 [Current cost: -0.45480498699294747]
Iters. done: 8 [Current cost: -0.4690533242050814]
Iters. done: 9 [Current cost: -0.465867415110354]
Iters. done: 10 [Current cost: -0.4606882723137227]
h_vqe = res.fun
print("The reference ground state energy is ", min(eigenvalues))
print("The computed ground state energy is ", h_vqe)
The reference ground state energy is (-0.471+0j)
The computed ground state energy is -0.4690533242050814
تهانينا! لقد أتممت للتو أول تجربة لك في الكيمياء الكمومية بنجاح. يمكننا رؤية فارق بين طاقة الحالة الأساسية الدقيقة للهاملتونيان وطاقتنا المحسوبة، لكن لأننا استخدمنا تقنية افتراضية للتخفيف من الأخطاء (التي تصحح أخطاء القراءة)، يبقى الفارق طفيفاً. هذه بداية ممتازة!
ملاحظة: يمكنك الحصول على نتيجة أفضل بضبط مستوى تخفيف الأخطاء باستخدام resilience_level. القيمة الافتراضية هي 1، وإذا ضبطت قيمة أعلى، سيستغرق ذلك وقتاً أطول من وحدة المعالجة الكمومية لكنه قد يُعيد نتيجة أفضل.
الخطوة 4: المعالجة اللاحقة
حان الوقت للنظر في كيفية عمل محسّننا الكلاسيكي. شغّل الخلية أدناه وشاهد نمط التقارب.
fig, ax = plt.subplots()
x = np.linspace(0, 10, 10)
# Define the constant function
y_constant = np.full_like(x, h)
ax.plot(
range(cost_history_dict["iters"]), cost_history_dict["cost_history"], label="VQE"
)
ax.set_xlabel("Iterations")
ax.set_ylabel("Cost (Hartree)")
ax.plot(y_constant, label="Target")
plt.legend()
plt.draw()
بدأنا بقيمة أولية جيدة إلى حد ما، لذا حصلنا على قيمة نهائية جيدة في 10 خطوات فقط. يمكنك رؤية قمم كبيرة وصغيرة، وهذه السمة النموذجية للمحسّن COBYLA - يستكشف الفضاء كأنه لا يستطيع رؤية المشهد ويضبط حجم الخطوة مع كل قياس.
اختبر فهمك
ما ملاحظتك؟ أي جزء من العملية أعلاه يمكن تحسينه للحصول على نتائج أقرب إلى القيم النظرية، أو أقرب إلى طاقة الحالة الأساسية الدقيقة للهاملتونيان؟ ما الأمور التي ينبغي مراعاتها في هذا الشأن؟
الجواب:
أول ما ينبغي مراعاته هو تغيير مجموعة الأسس المستخدمة في حساب هاملتونيان الجزيئات. كما ذكرنا سابقاً، طاقة الحالة الأساسية لذرة H هي -0.5 هارتري كما هو معروف جيداً، وأساس STO-6G الذي اخترناه لا يكفي لاشتقاق هذه القيمة بدقة.
اختيار نوع أساس أكثر تعقيداً يزيد من عدد الكيوبتات التي يستخدمها الهاملتونيان؛ لذلك نحتاج إلى اختيار أنساتز أكثر تعقيداً وملاءمةً لمسائل الكيمياء.
التالي الذي ينبغي تحسينه هو إدارة الضوضاء في وحدة المع الجة الكمومية. تقنيات تخفيف الأخطاء الأكثر تقدماً تُعطي نتائج أفضل لكنها قد تستغرق وقتاً أطول. كذلك، ضع في اعتبارك كيف يؤثر shot_number على النتائج.
أخيراً، يمكن تحقيق أداء تقارب أفضل بتجربة محسّنات مختلفة.
احسب طاقة الحالة الأساسية لجزيء الهيدروجين باستخدام VQE
الآن بعد أن استعرضنا العملية الكاملة لـ VQE باستخدام ذرات ، سنحسب طاقة الحالة الأساسية لجزيء بصورة أسرع.
الخطوة 1: تعيين المسألة إلى دوائر كمومية ومؤثرات
نوفر لك هنا هاميلتوني أحادي الكيوبت يستخدم قاعدة STO-6G وتحويل جوردان-وينر، مع تقليل عدد الكيوبتات بالاستفادة من تماثل الهاميلتوني. لاحظ أننا استخدمنا مسافة ذرية بين ذرتَي الهيدروجين تساوي 0.735 .
على خلاف حساب ذرة الهيدروجين المفردة ()، فإن حساب الحالة الأساسية لجزيء الهيدروجين () يستلزم أيضاً أخذ قوة التنافر بين نواتَي ذرتَي الهيدروجين في الاعتبار، إضافةً إلى الطاقة المرتبطة بالمدارات الإلكترونية. في هذه الخطوة سنعطي هذه القيمة كثابت، وسنحسبها فعلياً في مسألة التحقق.
h2_hamiltonian = SparsePauliOp.from_list(
[("I", -1.04886087), ("Z", -0.7967368), ("X", 0.18121804)]
)
# exact ground state energy of hamiltonian
nuclear_repulsion = 0.71997
A = np.array(h2_hamiltonian)
eigenvalues, eigenvectors = np.linalg.eig(A)
print("Electronic ground state energy (Hartree): ", min(eigenvalues).real)
print("Nuclear repulsion energy (Hartree): ", nuclear_repulsion)
print(
"Total ground state energy (Hartree): ", min(eigenvalues).real + nuclear_repulsion
)
h2 = min(eigenvalues).real + nuclear_repulsion
Electronic ground state energy (Hartree): -1.8659468547627318
Nuclear repulsion energy (Hartree): 0.71997
Total ground state energy (Hartree): -1.1459768547627318