تجربتك الكمومية الأولى
مقدمة
في الفيديو التالي، تأخذك أوليفيا لينز عبر محتوى هذا الدرس. بدلاً من ذلك، يمكنك فتح فيديو يوتيوب الخاص بهذا الدرس في نافذة منفصلة.
بحلول هذه المرحلة، شغّلت دائرتك الكمومية الأولى وتعلّمت أساسيات الحوسبة الكمومية: كيف تُمثَّل الحالات الكمية، وكيف تعمل البوابات على تلك الحالات، وكيف تنخرط الميزات الكمومية كالتراكب والتشابك في ذلك. الآن حان وقت تطبيق كل هذا وحل أول مسألة على حاسوب كمومي.
سنستكشف المشهد الأوسع للمسائل الملائمة للحوسبة الكمومية في درس لاحق. في الوقت الحالي، سنركز على مسألة في مجال محاكاة الطبيعة: استخدام حاسوب كمومي كبديل أنظف وأكثر قابلية للتحكم عن نظام كمومي طبيعي. في الواقع، هذا كان أول تطبيق تصوّره ريتشارد فاينمان للحواسيب الكمومية في ثمانينيات القرن الماضي. كما قال بشكل مشهور: «الطبيعة ليست كلاسيكية يا رجل، وإذا أردت محاكاة الطبيعة، من الأفضل أن تجعلها ميكانيكية كمومية...»
في هذا الدرس، سنتّبع هذا المبدأ لمحاكاة التفاعل بين غزلَين، يمكنك التفكير فيهما كمغناطيسين صغيرَين. واعتماداً على إشارة تفاعلهما، قد يُفضّلان التوافق والإشارة في نفس الاتجاه، أو التعاكس والإشارة في اتجاهَين متعاكسَين. سنركز على الحالة الأخيرة لأنها كثيراً ما تؤدي إلى سلوك أكثر إثارة — وأكثر تحدياً. بمجرد أن نفهم هذا النظام الصغير ثنائي الـ Qubit، سنُظهر كيف تتوسع نفس الأفكار لتمكين الحواسيب الكمومية من الاستفادة من تكاملها الأسي عند محاكاة أنظمة الغزل الكبيرة.
مغناطيسان متفاعلان
في هذه المسألة، سنستخدم Qubitين، واحدة لكل غزل في نموذجنا. يمكن لكل غزل أن يشير إلى الأعلى (حالة الـ Qubit )، أو إلى الأسفل (حالة الـ Qubit )، أو في تراكب من الحالتين.
إذا كان للغزلَين تفاعل مغناطيسي مضاد، فهذا يعني أنهما يريدان التعاكس، لذا حين يشير أحدهما إلى الأعلى، يريد الآخر أن يشير إلى الأسفل، والعكس صحيح.
لنفترض أن هناك أيضاً مجالاً مغناطيسياً يشير من اليسار إلى اليمين في نظامنا. لأن هذا المجال يشير عبر الاتجاه المعتاد لأعلى-أسفل للغزول، يُسمى مجالاً مستعرضاً. يمكن لهذا المجال قلب الغزول، مما يجعل تهيئة أدنى طاقة تراكباً محدداً من ترتيبات الغزل أعلى-أسفل بدلاً من أي نمط غزل محدد.
يمكننا وصف كل هذه التأثيرات باستخدام كائن رياضي يُسمى الهاميلتوني. يخبرنا الهاميلتوني بطاقة النظام لتهيئة معينة من الغزول:
حيث معامل يتحكم في قوة التفاعل بين الغزول و معامل لقوة المجال المغناطيسي الخارجي. يُكافئ أو يُعاقب الغزول بناءً على ما إذا كانت متوافقة أو متعاكسة، ويمثّل و تأثير قلب الغزل للمجال المغناطيسي.
في الفيزياء، تميل الأنظمة إلى الاستقرار في الحالة ذات أدنى طاقة ممكنة، وتُسمى الحالة الأرضية. إيجاد هذه الحالة ذات الطاقة الدنيا مسألة شائعة، لكنها تتطلب أساليب تحسين تتجاوز نطاق هذا الدرس.
بدلاً من ذلك، سنطرح سؤالاً أبسط: إذا هيّأنا الغزول في حالة معينة، فما طاقة تلك الحالة؟
للإجابة على هذا، سنقوم بـ:
- تهيئة الغزول في حالة من اختيارنا
- قياس طاقة تلك الحالة باستخدام الهاميلتوني أعلاه
هذا بالضبط نوع الحساب الذي يظهر داخل خوارزميات كمومية أكبر، كالخوارزميات التغايرية، التي يمكنك استكشافها في دورات لاحقة.
التنفيذ بـ Qiskit
قبل الشروع في كتابة الكود، نحتاج إلى بعض السياق. حين نشغّل دائرة كمومية، ننتهي دائماً بقياس الـ Qubits. لكن ثمة نوعان مختلفان من الأسئلة التي قد نريد طرحها حول نتيجة ذلك القياس: أحياناً نريد فقط معرفة ما هي حالة الـ Qubit. وفي أحيان أخرى نريد معرفة، بالنظر إ لى الحالة الكمومية، ما قيمة كمية فيزيائية معينة، كالطاقة؟
في Qiskit، يُعالَج هذان النوعان من الأسئلة بأداتَين مختلفتَين تُسميان العناصر الأساسية (primitives).
يجيب Sampler على النوع الأول من الأسئلة. يشغّل الدائرة عدة مرات ويخبرنا بمدى تكرار قياس كل نتيجة محتملة، مثل 00 أو 01 أو 10 أو 11. النتيجة رسم بياني يُظهر احتمال كل نتيجة قياس.
يجيب Estimator على النوع الثاني من الأسئلة. بدلاً من إعطائنا رسماً بيانياً، يجمع قياسات كثيرة خلف الكواليس لحساب عدد واحد، كطاقة الحالة وفق الهاميلتوني الذي نوفره.
لمساعدتك على فهم متى ولماذا نستخدم كل من هذه الأدوات، سنمر عبر سيرَي عمل كاملَين (يُسميان «أنماط Qiskit») مُطبَّقَين على النظام ثنائي الـ Qubit ذاته.
سير عمل أنماط Qiskit
سير عمل أنماط Qiskit إطار عام نستخدمه لحل المسائل الكمومية بـ Qiskit. يُقسّم مهمة الحوسبة الكمومية إلى أربع خطوات:
- تعيين المسألة إلى نموذج يمكن تمثيله بدوائر كمومية
- تحسين الدائرة للتشغيل على Backend محدد
- تنفيذ الدائرة المحسّنة على الـ Backend المختار
- المعالجة اللاحقة لبيانات القياس الخام
التجربة 1: استخدام Sampler لقياس الحالة
التعيين
بشكل عام، خطوة التعيين هي التي نحدد فيها كيفية تمثيل مسألة واقعية من حيث الـ Qubits والمؤثرات والقياسات. في كثير من التطبيقات، هذه هي الجزء الأصعب والأكثر تعقيداً من سير العمل — حتى الأسئلة البسيطة، كـ «ماذا يمثّل كل Qubit؟»، ليست دائماً لها إجابات مباشرة.
لكن في هذه التجربة، التعيين بسيط متعمَّداً. كل درجة حرية فيزيائية تُعيَّن مباشرة إلى Qubit واحدة. بسبب هذا التطابق الواحد-لواحد، تُختزل خطوة التعيين إلى اختيار الحالة الكمومية التي نريد تهيئتها وكتابة دائرة تُهيّئ تلك الحالة وتقيسها.
هنا، سنهيّئ حالة Bell متشابكة، مشابهة للتي صنعناها في الدرس الأول من هذه الدورة:
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
# Import Qiskit primitives
from qiskit import QuantumCircuit
# Make state
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.x(1)
qc.z(0)
# Measure state
qc.measure_all()
# Draw circuit
qc.draw("mpl")
التحسين
قبل تشغيل دائرتنا على حاسوب كمومي (أو محاكٍ إذا استنفدت وقتك المجاني على الحواسيب الكمومية الحقيقية للشهر)، نحتاج إلى تحضيرها للتنفيذ. تُسمى هذه الخطوة التحسين. (ملاحظة: قد يكون هذا الاستخدام لكلمة «التحسين» مربكاً. في الحوسبة الكمومية، تشير مسائل التحسين إلى فئة محددة من المسائل. هنا نستخدم التحسين لوصف خطوة تحضير مطلوبة يمر بها كل Circuit كمومية قبل أن يمكن تشغيله بكفاءة على الأجهزة.)
خلال التحسين:
- نختار الـ Backend — إما حاسوب كمومي حقيقي أو محاكٍ.
- نُسنِد Qubits الدائرة إلى Qubits فيزيائية على الجهاز.
- نُعيد كتابة الدائرة باستخدام البوابات التي يستطيع الحاسوب الكمومي تنفيذها فعلياً.
- اختيارياً تطبيق تقنيات تخفيف الأخطاء وكبتها لتقليل تأثيرات الضوضاء.
في Qiskit، يتم ذلك تلقائياً بواسطة Transpiler. بمجرد اختيار الـ Backend، يقوم Transpiler بكل العمل لجعل دائرتك جاهزة للتنفيذ، لذا لا يتعين عليك ضبط البوابات أو إسنادات الـ Qubit يدوياً. يوفر Transpiler أيضاً مستويات تحسين مختلفة يمكنها المساعدة في تقليل الأخطاء عند الحاجة. يُنجز التحسين في مراحل تُسمى «المرورات». لذا سيتولى هذا التحسين pass_manager في الكود أدناه. لمعرفة المزيد حول الأخطاء وتخفيفها، اطلع على دورة الحوسبة الكمومية في الممارسة لأوليفيا لينز.
# Load the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService
## Load the Qiskit Runtime service
# QiskitRuntimeService.save_account(
# channel="ibm_quantum_platform",
# token="YOUR_TOKEN_HERE",
# overwrite=True,
# set_as_default=True,
# )
# service = QiskitRuntimeService(channel="ibm_quantum_platform")
# Or 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_fez
# Transpile the circuit and optimize for running on the quantum computer selected
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
qc_isa.draw("mpl")
التنفيذ
الآن نحن مستعدون للتنفيذ! سنحمّل Sampler ثم نرسل المهمة إلى الـ Backend.
# Load the Runtime primitive and session
from qiskit_ibm_runtime import SamplerV2 as Sampler
sampler = Sampler(mode=backend)
أو، إذا كنت تستخدم محاكياً، يمكنك إلغاء التعليق وتشغيل هذه الخلية بدلاً من ذلك:
## Load the backend sampler
# from qiskit.primitives import BackendSamplerV2
## 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
# noise_model = NoiseModel.from_backend(backend)
## Define a simulator using Aer, and use it in Sampler.
# backend_sim = AerSimulator(noise_model=noise_model)
# sampler_sim = BackendSamplerV2(backend=backend_sim)
## Alternatively, load a fake backend with generic properties and define a simulator.
## backend_gen = GenericBackendV2(num_qubits=18)
## sampler_gen = BackendSamplerV2(backend=backend_gen)
job = sampler.run([qc_isa], shots=100)
# job = sampler_sim.run([qc_isa]) # uncomment if you want to run on a simulator
res = job.result()
counts = res[0].data.meas.get_counts()
المعالجة اللاحقة
from qiskit.visualization import plot_histogram
print("counts = ", counts)
plot_histogram(counts)
counts = {'10': 49, '01': 50, '11': 1}
نرى أن غالبية الأعداد إما في 01 أو 10، مما يعني أنه حين قيست إحدى الـ Qubits على أنها 0، كانت الأخرى 1، والعكس صحيح. هذا متسق مع حالة Bell التي هيّأناها.
التجربة 2: استخدام Estimator لقياس الطاقة
الآن بعد أن رأينا كيف نأخذ عيّنة من حالة كمومية، لنستخدم Estimator لحساب طاقة حالة Bell لدينا .