استكشاف عدم اليقين
في هذه الوحدة ضمن مشروع Qiskit in Classrooms، يجب أن يكون لدى الطلاب بيئة Python تعمل بشكل صحيح مع الحزم التالية مثبّتة:
qiskitv2.1.0 أو أحدثqiskit-ibm-runtimev0.40.1 أو أحدثqiskit-aerv0.17.0 أو أحدثqiskit.visualizationnumpypylatexenc
لإعداد هذه الحزم وتثبيتها، راجع دليل تثبيت Qiskit. لتشغيل المهام على حواسيب كمية حقيقية، يحتاج الطلاب إلى إنشاء حساب على IBM Quantum® باتباع الخطوات في دليل إعداد حساب IBM Cloud الخاص بك.
تم اختبار هذه الوحدة واستخدمت 8 دقائق من وقت QPU. هذا تقدير فقط، وقد يختلف الاستخدام الفعلي. حسابان مكثفان تم الإشارة إليهما في تعليقات العناوين ويمكن إجراؤهما على المحاكيات إذا كان وقت QPU لدى الطلاب محدودًا. بدونهما، تتطلب الوحدة ~30 ثانية فقط من وقت QPU.
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-aer qiskit-ibm-runtime
# 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'
شاهد شرح الوحدة بواسطة الدكتورة Katie McCormick أدناه، أو اضغط هنا لمشاهدته على YouTube.
مقدمة
على الأرجح سمعت بمبدأ عدم اليقين حتى خارج مقررات الفيزياء. إعادة صياغة شائعة لعدم اليقين هي "بمجرد أن تنظر إلى شيء، تؤثر عليه." وهذا صحيح بالتأكيد. لكن الطريقة الأكثر دقة فيزيائيًا لوصف عدم اليقين هي أن هناك مشاهَدات فيزيائية معينة بينها تنافٍ يمنع معرفة كلتيهما في آنٍ واحد بأي دقة نرغبها. يصادف كثير من الطلاب لأول مرة ثنائية المتغيرات المتعارضة و، وهما الموضع على المحور والزخم الخطي في تلك الاتجاه على التوالي. وللمتغيرين معًا، يُكتب قيد عدم اليقين كالتالي: هنا، تُسمى "عدم اليقين في "، وتعريفها مطابق للانحراف المعياري في الإحصاء، وتُعرَّف بالصيغة: و تُعرَّف بنفس الطريقة. لن نشتق هذه العلاقة هنا؛ سنشير فقط إلى أنها تتسق مع فهمنا للأمواج الكلاسيكية. أي أن موجة لها تردد وطول موجي مثاليان يمتدان إلى ما لا نهاية كجيب تمام مثالي. كميًا، يقابل ذلك معرفة الزخم بدقة تامة وفق فرضية دي برولي: . لكن لكي نعرف يتواجد الجسيم الشبيه بالموجة، يجب أن تصبح الموجة التي تصفه أكثر حدةً في الفضاء، كتوزيع غاوسي ضيق جدًا مثلًا. نعرف أننا نستطيع التعبير عن أي دالة مستمرة، بما فيها دوال الموجة الحادة هذه، كمتسلسلة فورييه من دوال جيبية بأطوال موجية مختلفة. لكن كلما أصبحت دالة الموجة أكثر حدةً (وصار الموضع أكثر معرفةً)، نحتاج إلى مزيد من الحدود في متسلسلة فورييه، أي مزيج من أطوال موجية أكثر (وبالتالي، كميًا، قيم زخم أكثر).
بشكل أبسط: حالة ذات زخم محدد جيدًا (جيب تمام مثالي في الفضاء) لها موضع غير محدد جدًا. وحالة ذات موضع محدد جيدًا (كتوزيع ديراك دلتا) لها زخم غير محدد جدًا.
هناك متغيرات أخرى تُظهر هذا التعارض. على سبيل المثال، قد يكون لجسيم إسقاط محدد جيدًا على محور واحد، لكننا لا نعرف شيئًا عن إسقاطه على محور عمودي. على سبيل المثال، الحالة (لكيوبت أو جسيم ذو سبين 1/2) لها إسقاط محدد على المحور (يساوي 1 في سياق الكيوبت، و في سياق جسيم السبين 1/2). لكن هذه الحالة يمكن كتابتها كتراكب لحالتين كل منهما لها إسقاط محدد على المحور : أو بصورة مكافئة: لها إسقاط محدد على ، وكذلك . إذا حددنا إسقاط حالة ما على المحور ، فإننا لا نعرف الإسقاط على المحور . وإذا حددنا الإسقاط على المحور ، فلا نعرف الإسقاط على . هناك اختلافات طفيفة عند مناقشة هذا في سياق السبين والكيوبتات. لكن بشكل عام، للحالات الذاتية لمصفوفات باولي علاقة مثيرة للاهتمام يمكننا استكشافها. طوال هذا الدرس، سنتحقق تجريبيًا من حدسنا بشأن عدم اليقين في هذه المتغيرات المتعارضة، ونتحقق من صحة علاقات عدم اليقين على حواسيب IBM® الكمية.
اختبار بسيط للحدس
في هذه التجربة الأولى وطوال الوحدة، سنستخدم إطار العمل الخاص بالحوسبة الكمية المعروف بـ"أنماط Qiskit"، والذي يُقسّم سير العمل إلى الخطوات التالية:
- الخطوة 1: تحويل المدخلات الكلاسيكية إلى مسألة كمية
- الخطوة 2: تحسين المسألة للتنفيذ الكمي
- الخطوة 3: التنفيذ باستخدام Qiskit Runtime Primitives
- الخطوة 4: المعالجة اللاحقة والتحليل الكلاسيكي
سنتبع هذه الخطوات بشكل عام، وإن كنا لن نصنّفها صراحةً في كل مرة.
لنبدأ بتحميل بعض الحزم الضرورية بما فيها Runtime primitives. سنختار أيضًا الحاسوب الكمي الأقل انشغالًا المتاح لنا.
يوجد في الكود أدناه كود لحفظ بيانات الاعتماد عند الاستخدام الأول. تأكد من حذف هذه المعلومات من الدفتر بعد حفظها في بيئتك، حتى لا تُشارَك بيانات اعتمادك بالخطأ عند مشاركة الدفتر. راجع إعداد حساب IBM Cloud الخاص بك وتهيئة الخدمة في بيئة غير موثوقة لمزيد من التوجيهات.
from numpy import pi
# Load the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService
# 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()
# Load the Runtime primitive and session
from qiskit_ibm_runtime import (
Batch,
SamplerV2 as Sampler,
EstimatorV2 as Estimator,
)
# Use the least busy backend
backend = service.least_busy(min_num_qubits=127)
print(backend.name)
ibm_sherbrooke
إذا نفد وقت الحوسبة الكمية المتاح للطالب أثناء الدرس، يمكن إلغاء تعليق الأسطر أدناه واستخدامها لإعداد محاكٍ يحاكي جزئيًا سلوك الضوضاء للحاسوب الكمي المختار أعلاه.
# Import an estimator, this time from qiskit (we will import from Runtime for real hardware)
from qiskit_aer.primitives import SamplerV2, EstimatorV2
from qiskit_aer.noise import NoiseModel
# Generate the noise model from the backend properties
noise_model = NoiseModel.from_backend(backend)
noisy_sampler = SamplerV2(options={"backend_options": {"noise_model": noise_model}})
noisy_estimator = EstimatorV2(options={"backend_options": {"noise_model": noise_model}})
ربما تتذكر أن الحالة الذاتية لمؤثر Z ليست حالة ذاتية لمؤثر X. سنلاحظ ذلك الآن تجريبيًا عن طريق إجراء قياسات على المحورين و. للقياس على ، نستخدم ببساطة qc.measure()، لأن الحواسيب الكمية من IBM مُهيأة للقياس على . أما للقياس على ، فنحتاج إلى تدوير النظام لنقل محور إلى اتجاه القياس بفعالية. يتحقق ذلك ببوابة هادامارد. هناك خطوة مماثلة مطلوبة للقياسات على . الخطوات اللازمة مجموعة هنا للرجوع إليها:
- للقياس على :
qc.measure() - للقياس على :
qc.h()ثمqc.measure() - للقياس على :
qc.sdg()،qc.h()،qc.sثمqc.measure()
الخطوة 1: تحويل المدخلات الكلاسيكية إلى مسألة كمية
في هذه الحالة، خطوة التحويل هي ببساطة التعبير عن القياسات والتدويرات الموضحة أعلاه في دائرة كمية:
# Step 1: Map
# Import some general packages
from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
# Add a first measurement
qc.measure(qr, cr[0])
qc.barrier()
# Change basis so that measurements made on quantum computer which normally tell us about z,
# now tell us about x.
qc.h(qr)
# Add a second measurement
qc.measure(qr, cr[1])
qc.draw("mpl")
الخطوة 2: تحسين المسألة للتنفيذ الكمي
تأخذ هذه الخطوة العمليات التي نريد إجراءها وتُعبّر عنها بعبارات وظائف حاسوب كمي محدد. كما تُعيّن مسألتنا على تخطيط الحاسوب الكمي.
# 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)
الخطوة 3: التنفيذ باستخدام Qiskit Runtime primitives
يمكننا استخدام Sampler لجمع إحصائيات القياسات. سنُنشئ الـ Sampler primitive للتشغيل على حاسوب كمي حقيقي باستخدام mode = backend. هناك أوضاع أخرى لسير عمل مختلفة، وسنستخدم واحدًا منها أدناه. سيُستخدم Sampler باستدعاء الدالة run() مع قائمة من "pubs" (Primitive Unified Blocs). كل pub يحتوي على ثلاث قيم كحد أقصى تُعرّف معًا وحدة عمل حسابية للـ estimator: الدوائر، والمشاهَدات، والمعاملات. يمكنك أيضًا تقديم قائمة دوائر وقائمة مشاهَدات وقائمة معاملات. لمزيد من المعلومات، اقرأ نظرة عامة على PUBs.
نريد التشغيل على حاسوب كمي حقيقي لكي نُجري تجربة فيزياء كمية حقيقية. إذا نفد وقتك المخصص على الحواسيب الكمية الحقيقية، يمكنك التعليق على الكود أدناه الخاص بالحاسوب الكمي، وإلغاء التعليق على الكود الخاص بالتشغيل على محاكٍ.
# Step 3: Run the job on a real quantum computer
sampler = Sampler(mode=backend)
pubs = [qc_isa]
job = sampler.run(pubs)
res = job.result()
counts = res[0].data.c.get_counts()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_sampler.run([qc_isa])
# res=job.result()
# counts=res[0].data.c.get_counts()
الخطوة 4: المعالجة اللاحقة
هذه حالة بسيطة بشكل خاص من المعالجة اللاحقة، حيث نكتفي بتصوير الأعداد.
لاحظ أن Qiskit يرتّب الكيوبتات والقياسات وغيرها بوضع العنصر ذو الرقم الأصغر في الآخر/على اليمين، وهو اتفاق يُعرف بـ"little-endian". هذا يعني أن العمود أدناه المسمى "10" يشير إلى الأعداد حيث أعطى القياس الأول "0"، وأعطى القياس الثاني "1".
# Step 4: Post-process
from qiskit.visualization import plot_histogram
plot_histogram(counts)
إذا لم يُعجبك هذا الاتفاق، يمكنك استخدام marginal_counts لتصوير نتائج كل قياس على حدة:
from qiskit.result import marginal_counts
plot_histogram(
marginal_counts(counts, indices=[0]), title="Counts after first measurement"
)
plot_histogram(
marginal_counts(counts, indices=[1]), title="Counts after second measurement"
)
بشكل افتراضي، تُهيأ الحالات في Qiskit في حالة . لذا ليس من المفاجئ أن تُسفر معظم القياسات الأولى عن . لاحظ مع ذلك أن هناك انقسامًا شبه متساوٍ تقريبًا في القياس الثاني (الذي يُعطي معلومات عن إسقاطات الحالة على ). يبدو أن هذه الحالة التي تُعطينا نتيجة يمكن التنبؤ بها جدًا للقياسات على تُعطينا نتائج غير قابلة للتنبؤ تمامًا للقياسات على . دعنا نستكشف هذا.
ماذا يحدث لو أجرينا القياسات بالترتيب المعاكس؟ يمكننا البدء باستخدام بوابة هادامارد للحصول على إحصائيات حول احتمال قياس في . ثم للقياس الثاني، سنعود إلى أساس باستخدام بوابة هادامارد ثانية.
# Step 1:
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
# Change basis to measure along x.
qc.h(qr)
qc.measure(qr, cr[0])
qc.barrier()
# Change our basis back to z and make a second measurement
qc.h(qr)
qc.measure(qr, cr[1])
qc.draw("mpl")
# Step 2: Transpile the circuit for running on a quantum computer
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
# Step 3: Run the job on a real quantum computer
sampler = Sampler(mode=backend)
pubs = [qc_isa]
job = sampler.run(pubs)
res = job.result()
counts = res[0].data.c.get_counts()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_sampler.run([qc_isa])
# res=job.result()
# counts=res[0].data.c.get_counts()
# Step 4: Post-process
from qiskit.visualization import plot_histogram
plot_histogram(counts)
هنا، يبدو أن لدينا قدرًا أقل من إمكانية التنبؤ! سابقًا، كنا نعرف على الأقل ما ستكون عليه نتيجة القياس الأول، أما الآن فلدينا توزيع متساوٍ تقريبًا على جميع الحالات الممكنة. ليس من الصعب فهم سبب حدوث هذا. بدأنا في ، وهي خليط 50-50 من و، وفقًا لـ: لذا من الواضح أن يكون احتمال الحصول على الحالة + أو - (المُعيَّنة على 0 و1 في الرسم البياني) متساويًا تقريبًا للقياس الأول. يُنهار القياس على الحالة إلى إما الحالة الذاتية أو الحالة الذاتية . كل من هاتين الحالتين هي خليط 50-50 من و، وفقًا لـ: فعندما يكون النظام في حالة ذاتية من ، من الواضح أن القياسات على ستُعطي كلًا من و، وستفعل ذلك باحتمالية متساوية تقريبًا. إذن المثال الأول أظهر لنا أن بعض الحالات ستُعطي نتائج يمكن التنبؤ بها جدًا لبعض القياسات، لكن نتائج غير قابلة للتنبؤ لقياسات أخرى. أما المثال الحالي فيُظهر لنا أننا قد نُحقق نتائج أسوأ من ذلك. هناك حالات يمكن أن تُعطينا نتائج غير قابلة للتنبؤ لكلا القياسين، حتى لو اكتفينا بتبديل ترتيب القياسات. دعنا نبحث في مدى اليقين أو عدم اليقين لكمية ما لحالة معينة.
حساب عدم اليقين
يمكننا تكميم هذا باستخدام عدم اليقين، أو التباين. "عدم اليقين" غالبًا يُعرَّف على أنه الجذر التربيعي لـ"تباين" توزيع معيّن. أي أن عدم اليقين لمشاهَد ما يُرمَز له بـ ومعطى بالصيغة
في حالة مصفوفات باولي، التي فيها ، تصبح المعادلة
لنطبّق هذا على مثال ملموس. نبدأ بالحالة ونحدد عدم اليقين للمشاهَد في تلك الحالة.
تحقّق من فهمك
احسب عدم اليقين لـ في الحالة ، يدويًا.
Answer
في الحالة المعطاة، ينتج:
يمكننا إنشاء حالة ابتدائية اعتباطية باستخدام qc.initialize(). لاحظ أن صيغة الوحدة التخيلية هنا هي .
# Step 1: Map the problem into a quantum circuit
from qiskit.quantum_info import SparsePauliOp
import numpy as np
obs = SparsePauliOp("X")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Initialize the state
qc.initialize([1, 1j] / np.sqrt(2))
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs_isa = obs.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
estimator = Estimator(mode=backend)
pubs = [(qc_isa, obs_isa)]
job = estimator.run([[qc_isa, obs_isa]])
res = job.result()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([[qc_isa,obs_isa]])
# res=job.result()
# Step 4: Return the result in classical form, and analyze.
print(res[0].data.evs)
-0.02408454165642664
بناءً على معادلتنا أعلاه، لنبقَ مع نفس الحالة، لكن نوجد قيمة التوقع لـ الآن:
# Step 1: Map the problem into a quantum circuit
obs = SparsePauliOp("Z")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Initialize the state to |+>_y
qc.initialize([1, 1j] / np.sqrt(2))
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs_isa = obs.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
estimator = Estimator(mode=backend)
pubs = [(qc_isa, obs_isa)]
job = estimator.run(pubs)
res = job.result()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([[qc_isa,obs_isa]])
# res=job.result()
# Step 4: Return the result in classical form, and analyze.
print(res[0].data.evs)
0.04958271968581247
يمكننا إجراء نفس الحسابات السابقة، لكن سنرى أن التباين قريب جدًا من 1.0 مجددًا. يمكننا أن نستنتج أن . وهذا صحيح تقريبًا للحالة التي اخترناها. لكن هل يمكننا تحقيق نتيجة أفضل؟ أو أسوأ؟
تذكّر أن هناك علاقة عدم يقين بين الموضع على اتجاه معيّن، وكمية التحرك على نفس الاتجاه، بالنسبة لتلك المتغيرات، الصيغة الأكثر شهرة على الأرجح هي لو هذا كل ما نتذكره، قد يغرينا التفكير أن و يمكن أيضًا أن يكون لهما حد أدنى أساسي لعدم اليقين. ربما يستحيل أن يبلغ حاصل ضرب الصفر؟ لنجرب حالة أخرى ونرَ إذا كان هذا صحيحًا. هذه المرة، سنستخدم لنرَ ماذا يحدث. لاحظ أنه في الكود أدناه، يستطيع estimator قبول مجموعتين من الدوائر والمشاهَدات في نفس تقديم الوظيفة.
# Step 1: Map the problem into a quantum circuit
obs1 = SparsePauliOp("X")
obs2 = SparsePauliOp("Z")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Initialize the state
qc.initialize([1, 1] / np.sqrt(2))
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs1_isa = obs1.apply_layout(layout=qc_isa.layout)
obs2_isa = obs2.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
with Batch(backend=backend) as batch:
estimator = Estimator(mode=batch)
pubs = [(qc_isa, obs1_isa), (qc_isa, obs2_isa)]
job = estimator.run(pubs)
res = job.result()
batch.close()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([[qc,obs1],[qc,obs2]])
# res=job.result()
# Step 4: Return the result in classical form, and analyze.
print("The expectation value of the first observable is: ", res[0].data.evs)
print("The expectation value of the second observable is: ", res[1].data.evs)
The expectation value of the first observable is: 1.0011036174126302
The expectation value of the second observable is: 0.0029429797670141016
قيمة توقع يجب أن تكون قريبة من 1.0، لكن لا تتجاوز 1.0. لا تقلق إذا تجاوزتها بمقدار صغير جدًا. هذا يمكن إرجاعه لعوامل مثل الضوضاء و/أو خطأ القراءة. رغم أن هذا موضوع مهم جدًا، يمكننا تجاهله في الوقت الحالي.
حصلنا على قيمة توقع لـ قريبة جدًا من 1.0 (ما يقابل تباينًا منخفضًا جدًا لـ). هذا يجعل حاصل ضرب التباينين منخفضًا جدًا:
رغم أن هذا ليس صفرًا بالضبط، إلا أن هذه القيمة باتت صغيرة مقارنةً بالقيم الذاتية لمؤثرات باولي (). حسنًا، ربما تتذكر أن علاقة عدم اليقين بين الموضع الخطي وكمية التحرك يمكن كتابتها بشكل مختلف، باستخدام علاقة الإبدال بين المؤثرَين و بشكل صريح:
حيث
هو مبدّل و.
هذه هي الصيغة التي يمكن تعميمها بأسهل طريقة على مؤثرات باولي. بشكل عام، لمؤثرَين و،
وفي حالة مصفوفتَي باولي و، نحتاج لحساب
نبيّن هذا هنا، ونترك حسابات مشابهة للقارئ كتمرين:
هذا جواب مقبول تمامًا، لكن بخطوة إضافية واحدة، نرى
وبذلك تصبح علاقة عدم اليقين لدينا
تحقّق من فهمك
احسب و. استخدم هذا لكتابة علاقات عدم اليقين بين و، وبين و.
Answer
بالجمع مع علاقة عدم اليقين العامة، نحصل على
تحقّق من الاتساق
قبل المتابعة، لنتحقق أن هذا كان متسقًا مع ما وجدناه سابقًا. استخدمنا الحالة ووجدنا أن الآن نعرف أن هذا الحاصل يجب أن يكون أكبر من أو يساوي
إذن فعلًا، استخدم الأسئلة التالية لبناء حدس حول هذه النتائج:
تحقّق من فهمك
أجب على العناصر التالية معًا كمجموعة:
(أ) ما الحالات التي تتوقع أن يكون فيها عدم اليقين في صفرًا؟
(ب) ما الحالات التي تتوقع أن يكون فيها عدم اليقين في صفرًا؟
(ج) في أي حالات تحصل على قيمة توقع صفرية ؟
(د) هل إجابات الأسئلة السابقة متسقة مع الحالة ؟
(هـ) اكتب كودًا للتحقق من هذا صراحةً باستخدام estimator.
Answer
(أ) نتوقع أن الحالات الذاتية لمؤثر تعطي عدم يقين صفريًا في . فعلًا، باستخدام نحصل على
(ب) نتوقع أن الحالات الذاتية لمؤثر تعطي عدم يقين صفريًا في . فعلًا، باستخدام نحصل على
(ج) نتوقع أن نجد لأي حالات تعطي، عند قياسها، إسقاطًا موجبًا على محور بنفس تكرار الإسقاط السالب. وتشمل هذه الحالات الحالات الذاتية لـ و.
(د) نعم. يُتوقع أن تكون قيمة حاصل ضرب حالات عدم اليقين صغيرة جدًا للحالات الذاتية لـ أو : وهذا يمكن أن يتحقق لأننا نتوقع أيضًا لتلك الحالات نفسها. لذا يمكن تحقيق علاقة عدم اليقين.
(هـ) كود مثل الآتي يُثبت هذا:
obs1 = SparsePauliOp.from_list(
[("X", 1.000)]
)
obs2 = SparsePauliOp.from_list(
[("Y", 1.000)]
)
obs3 = SparsePauliOp.from_list(
[("Z", 1.000)]
)
qc = QuantumCircuit(1,1)
qc.ry(pi/2,0)
job = estimator.run([(qc, [[obs1], [obs2], [obs3]])], precision=0.001)
res=job.result()
حيث تُرجع النتائج جميع قيم التوقع. لاسترداد جميع قيم التوقع وحساب حالات عدم اليقين، يمكننا استخدام:
xs=res[0].data.evs[0]
ys=abs(res[0].data.evs[1])
zs=res[0].data.evs[2]
import math
prodxz=((1-xs[i]*xs[i])**0.5)*(1-zs[i]*zs[i])**0.5
أجب على العناصر التالية معًا كمجموعة:
(أ) هل تستطيع التفكير في حالة تكون فيها قيمة التوقع كبيرة؟
(ب) هل تتوقع أن تكون حالة عدم اليقين في كبيرة أم صغيرة في تلك الحالة نفسها؟
(ج) هل تتوقع أن تكون حالة عدم اليقين في كبيرة أم صغيرة في تلك الحالة نفسها؟
(د) هل إجابات الأسئلة السابقة متسقة مع الحالة ؟
(هـ) اكتب كودًا للتحقق من هذا صراحةً باستخدام estimator.
Answer
(أ) نتوقع أن نجد للحالة الذاتية لـ: .
(ب) نتوقع أن يكون لـ عدم يقين كبير في الحالة إذ أن قياس في تلك الحالة سيعطي نتيجة موجبة وسالبة بنفس التكرار/الاحتمالية.
(ج) نتوقع أن يكون لـ عدم يقين كبير في الحالة إذ أن قياس في تلك الحالة سيعطي نتيجة موجبة وسالبة بنفس التكرار/الاحتمالية.
(د) نعم. يُتوقع قيمة كبيرة لحاصل ضرب حالات عدم اليقين للحالات الذاتية لـ، وبالتحديد لـ. كما نتوقع لتلك الحالة نفسها. إذن كلٌّ من و كبيران نسبيًا في هذه الحالة، ومن المعقول أن تتحقق علاقة عدم اليقين مجددًا.
(هـ) كود مثل الآتي يُثبت هذا:
obs1 = SparsePauliOp.from_list(
[("X", 1.000)]
)
obs2 = SparsePauliOp.from_list(
[("Y", 1.000)]
)
obs3 = SparsePauliOp.from_list(
[("Z", 1.000)]
)
qc = QuantumCircuit(1,1)
qc.rx(-pi/2,0)
job = estimator.run([(qc, [[obs1], [obs2], [obs3]])], precision=0.001)
res=job.result()
حيث تُرجع النتائج جميع قيم التوقع. لاسترداد جميع قيم التوقع وحساب حالات عدم اليقين، يمكننا استخدام:
xs=res[0].data.evs[0]
ys=abs(res[0].data.evs[1])
zs=res[0].data.evs[2]
import math
prodxz=((1-xs[i]*xs[i])**0.5)*(1-zs[i]*zs[i])**0.5
اختبار علاقات عدم اليقين
الاختبار الذي أجريناه أعلاه يُثبت صحة علاقة عدم اليقين لاختيار واحد فقط لمتجه الحالة . لكي نقنع أنفسنا أن هذا متوافق بشكل عام مع التجارب، يجب أن نجري حسابات مشابهة باستخدام المُقدِّر لاختيارات كثيرة من متجه الحالة. لنبدأ بتدوير متجه الحالة بعيدًا عن محور ، باستخدام بوابة RY من أجل إنتاج حالات ابتدائية مختلفة باستخدام معامل .
# The calculation below uses approximately 3-4 minutes of QPU time.
# Step 1: Map the problem into a quantum circuit
from qiskit.circuit import Parameter
import numpy as np
# Specify observables
obs1 = SparsePauliOp("X")
obs2 = SparsePauliOp("Y")
obs3 = SparsePauliOp("Z")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Rotate away from |0>
theta = Parameter("θ")
qc.ry(theta, 0)
params = np.linspace(0, 2, num=21)
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs1_isa = obs1.apply_layout(layout=qc_isa.layout)
obs2_isa = obs2.apply_layout(layout=qc_isa.layout)
obs3_isa = obs3.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
with Batch(backend=backend) as batch:
estimator = Estimator(mode=batch)
pubs = [(qc_isa, [[obs1_isa], [obs2_isa], [obs3_isa]], [params])]
job = estimator.run(pubs, precision=0.01)
res = job.result()
batch.close()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([(qc, [[obs1], [obs2], [obs3]], [params])])
# res=job.result()
# Step 4: Post-processing and classical analysis.
xs = res[0].data.evs[0]
ys = abs(res[0].data.evs[1])
zs = res[0].data.evs[2]
# Calculate uncertainties
delx = []
delz = []
prodxz = []
for i in range(len(xs)):
delx.append(abs((1 - xs[i] * xs[i])) ** 0.5)
delz.append(abs((1 - zs[i] * zs[i])) ** 0.5)
prodxz.append(delx[i] * delz[i])
# Here we can plot the results from this simulation.
import matplotlib.pyplot as plt
plt.plot(params, delx, label=r"$\Delta$ X")
plt.plot(params, ys, label=r"$\langle$ Y $\rangle$")
plt.plot(params, delz, label=r"$\Delta$ Z")
plt.plot(params, prodxz, label=r"$\Delta$X $\Delta$Z")
plt.xlabel(r"$\theta$")
plt.ylabel("Expectation/Uncertainty Values")
plt.legend()
plt.show()
لاحظ أن المنحنى الأحمر دائمًا أكبر من المنحنى البرتقالي أحيانًا ينخفض حاصل ضرب عدم اليقين ويكون قريبًا قليلًا من الحد، وأحيانًا أخرى يرتفع ويبتعد عن الحد، لكنه دائمًا يُطيع علاقة عدم اليقين.
بالطبع، ربما ليس هذا أفضل اختبار لعلاقة عدم اليقين، لأن الحد الخاص بنا دائمًا قريب جدًا من الصفر. لنستخدم حالة كمومية لها إسقاط أكبر على الحالات الذاتية لـ . بالتحديد، سنستمر في تدوير للأسفل بعيدًا عن محور بزوايا متغيرة، لكن الآن سندوّر أيضًا الحالة الناتجة حول بزاوية معينة، ربما ، ونرى ما يحدث.
# The calculation below uses approximately 3-4 minutes of QPU time.
from qiskit.circuit import Parameter
import numpy as np
# Step 1: Map the problem to a quantum circuit
# Specify observables
obs1 = SparsePauliOp("X")
obs2 = SparsePauliOp("Y")
obs3 = SparsePauliOp("Z")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Rotate away from |0> along one plane, and then along a transverse direction.
theta = Parameter("θ")
qc.ry(theta, 0)
qc.rz(pi / 4, 0)
params = np.linspace(0, 2, num=21)
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs1_isa = obs1.apply_layout(layout=qc_isa.layout)
obs2_isa = obs2.apply_layout(layout=qc_isa.layout)
obs3_isa = obs3.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
with Batch(backend=backend) as batch:
estimator = Estimator(mode=batch)
pubs = [(qc_isa, [[obs1_isa], [obs2_isa], [obs3_isa]], [params])]
job = estimator.run(pubs, precision=0.01)
res = job.result()
batch.close()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([(qc, [[obs1], [obs2], [obs3]], [params])])
# res=job.result()
# Step 4: Post-processing and classical analysis.
xs = res[0].data.evs[0]
ys = abs(res[0].data.evs[1])
zs = res[0].data.evs[2]
# Calculate uncertainties
delx = []
delz = []
prodxz = []
for i in range(len(xs)):
delx.append(abs((1 - xs[i] * xs[i])) ** 0.5)
delz.append(abs((1 - zs[i] * zs[i])) ** 0.5)
prodxz.append(delx[i] * delz[i])
# Here we can plot the results from this simulation.
import matplotlib.pyplot as plt
plt.plot(params, delx, label=r"$\Delta$ X")
plt.plot(params, ys, label=r"$\langle$ Y $\rangle$")
plt.plot(params, delz, label=r"$\Delta$ Z")
plt.plot(params, prodxz, label=r"$\Delta$X $\Delta$Z")
plt.xlabel(r"$\theta$")
plt.ylabel("Expectation/Uncertainty Values")
plt.legend()
plt.show()
الآن نرى أن الحد على عدم اليقين يُتحدَّى بجدية! المنحنى الأحمر يقترب كثيرًا من المنحنى البرتقالي أكثر من قبل. في الحقيقة، لو لم تكن هناك ضوضاء، لكانت علاقة عدم اليقين قد بلغت حدها الأقصى بالضبط () في نقطة واحدة. في وجود الضوضاء وأخطاء القراءة، ليس غريبًا لو أن تشغيلة معينة أعطت أكبر قليلًا من هذا ليس انتهاكًا حقيقيًا لمبدأ عدم اليقين؛ إنه فقط نتيجة لأخطاء غير صفرية.
تحقق من فهمك
اشرح كيف يمكنك دفع هذا إلى الحد الأقصى وجعل أكبر ما يمكن.
Answer
الكود حاليًا فيه أسطر تدوّر الحالة الابتدائية الافتراضية للأسفل من محور بزاوية معاملية ثم أيضًا حول محور بزاوية التي تدوّر متجه الحالة جزءًا من الطريق نحو محور .
qc.ry(theta,0)
qc.rz(pi/4,0)
يمكن تغيير التدوير حول من إلى ، من أجل تدوير الكل إلى حالة ذاتية لـ :
qc.ry(theta,0)
qc.rz(pi/2,0)
لا نحتاج إلى أي تغييرات أخرى.
غيّر الكود أو انسخه وطبّق هذا التحقق من علاقة عدم اليقين مع تعظيم القيمة المتوقعة لـ Y. هل تتحقق علاقة عدم اليقين؟
Answer
سنستخدم بالضبط الكود من المثال الذي أعلاه، مع
qc.rz(pi/2,0)
استبدالاً لـ
qc.rz(pi/4,0).
الشكل الناتج يجب أن يشبه ما هو أدناه، ونعم، مبدأ عدم اليقين يجب أن يكون ساريًا لا يزال.

عدّل الكود الذي أعلاه من أجل إنشاء صورة مشابهة، وإثبات من القياسات على الحاسوب الكمومي أن حاصل الضرب يتصرف كما ينبغي. اختر أي مجموعة من الحالات تريدها.
Answer
سنستخدم بالضبط الكود من المثال الذي أعلاه، وفعلًا يمكننا استخدام نفس النتائج من أعلاه، لكن باستخدام القيم المتوقعة لحساب حالات عدم يقين مختلفة. مثلًا، يمكننا استخدام
xs=res[0].data.evs[0]
ys=res[0].data.evs[1]
zs=abs(res[0].data.evs[2])
import math
delx = []
dely = []
prodxy=[]
for i in range(len(xs)):
delx.append((1-xs[i]*xs[i])**0.5)
dely.append((1-ys[i]*ys[i])**0.5)
prodxy.append(((1-xs[i]*xs[i])**0.5)*(1-ys[i]*ys[i])**0.5)
ويمكننا رسم
import matplotlib.pyplot as plt
plt.plot(params, delx, label=r'$\Delta$ X')
plt.plot(params, dely, label=r'$\langle$ Y $\rangle$')
plt.plot(params, zs, label=r'$\Delta$ Z')
plt.plot(params, prodxy, label=r'$\Delta$X $\Delta$Z')
plt.xlabel(r'$\theta$')
plt.ylabel('Expectation/Uncertainty Values')
plt.legend()
plt.show()
تحدي: اكتب كودًا يمسح من خلال قيم كثيرة لـ ، كما مسحنا من خلال قيم كثيرة لـ ، وأنشئ رسمة ثلاثية الأبعاد تُثبت أن علاقة عدم اليقين لا تُنتهَك أبدًا. اختر أي مشاهَدات تريدها.
الأسئلة
يستطيع المدرّسون طلب نسخ من هذه الدفاتر مع مفاتيح الإجابات والتوجيه بشأن الوضع في المناهج الشائعة عن طريق ملء هذا الاستطلاع السريع عن طريقة استخدام الدفاتر.
المفاهيم الأساسية:
- هناك علاقات عدم يقين بين مجموعات كثيرة من المشاهَدات الفيزيائية، مثل الموضع والزخم الخطي، ومكونات السبين.
- مصفوفات باولي لا تتبادل. هذا انعكاس رياضي لحقيقة أنه ليس بالإمكان معرفة/تحديد جميع مكونات السبين في نفس الوقت.
- الحوسبة الكمومية تستخدم مؤثرات/مصفوفات باولي بشكل كبير، فمن المفيد معرفة علاقة عدم اليقين لمؤثرات باولي، وأيضًا مؤثرات السبين التي ترتبط بها ارتباطًا وثيقًا.
- الصيغة العامة لعدم يقين مؤثرَين و هي
- الحالة الذاتية لمؤثر معين تعطي عدم يقين صفريًا في المشاهَد الفيزيائي المرتبط بهذا المؤثر. حتى تجريبيًا،
- الحالة الذاتية لمؤثر معين ستعطي عدم يقين أكبر لمؤثر لا يتبادل مع .
- النتائج التجريبية باستخدام حاسوب كمومي حقيقي تؤكد الحدس الذي نكتسبه من التمثيلات المصفوفية للمؤثرات الفيزيائية.
أسئلة صح/خطأ:
- ص/خ يمكن قياس و في نفس الوقت، لكن ليس .
- ص/خ يمكن قياس و في نفس الوقت، لكن ليس .
- ص/خ مؤثرا الموضع الخطي والزخم الخطي لا يتبادلان.
- ص/خ حواسيب IBM الكمومية تقيس على طول بشكل افتراضي، فيجب إجراء تدوير من أجل القياس في أي اتجاه آخر.
- ص/خ الدائرة أدناه تقيس فعليًا ثم .
أسئلة متعددة الاختيار:
-
الرسم التخطيطي أدناه يُثبت أيًا من علاقات عدم اليقين التالية؟
- أ.
- ب.
- ج.
- د. لا شيء مما سبق

-
أي مما يلي هو التسلسل المعياري لإجراء قياس على طول ؟
- أ. فقط
qc.measure() - ب.
qc.h()ثمqc.measure() - ج.
qc.h()،qc.h()ثمqc.measure() - د.
qc.h()،qc.s،qc.h()ثمqc.measure() - هـ.
qc.sdg()،qc.h()،qc.sثمqc.measure() - و.
qc.sdg()،qc.h()،qc.s،qc.h()ثمqc.measure()
- أ. فقط
-
أي من الحالات التالية تعطي أكبر قيمة متوقعة ؟
- أ.
- ب.
- ج. المعروفة أيضًا بـ
- د. المعروفة أيضًا بـ
- هـ. المعروفة أيضًا بـ
- و. المعروفة أيضًا بـ
-
أي من الحالات التالية تعطي أكبر عدم يقين ؟
- أ.
- ب. المعروفة أيضًا بـ
- ج. المعروفة أيضًا بـ
- د. أ وب متساويتين
- هـ. ب وج متساويتين
- و. أ، ب، وج متساويات
أسئلة نقاشية:
-
هل هذا المفهوم لعدم اليقين يتعارض بأي طريقة مع فكرة السبين كسهم متجه في الفضاء الديكارتي؟ ماذا عن كرة بلوخ؟
-
افترض أنك توجّه جهاز قياس في اتجاه في المنتصف بين محوري و . ماذا يحدث؟ هل تستطيع إجراء قياس في هذا الاتجاه؟ كيف يرتبط هذا بعدم اليقين في و ؟
٣. ما التجارب الإضافية التي ترغب في إجرائها لإقناع نفسك بالنتائج التي حصلنا عليها هنا؟