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

تطبيق Qiskit

في الدرس السابق، ألقينا نظرة أولى على صنفَي Statevector وOperator في Qiskit، واستخدمناهما لمحاكاة العمليات والقياسات على كيوبت واحد. في هذا القسم، سنستخدم هذين الصنفين لاستكشاف سلوك كيوبتات متعددة.

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"numpy": "numpy", "qiskit": "qiskit"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
from qiskit import __version__

print(__version__)
2.1.1

سنبدأ باستيراد صنفَي Statevector وOperator، إضافةً إلى دالة الجذر التربيعي من NumPy. من الآن فصاعداً، سنحرص بشكل عام على تنفيذ جميع الاستيرادات المطلوبة في بداية كل درس.

from qiskit.quantum_info import Statevector, Operator
from numpy import sqrt

حاصل الضرب التنسوري​

يحتوي الصنف Statevector على دالة tensor، التي تُعيد حاصل الضرب التنسوري لذلك Statevector مع آخر، يُعطى كوسيط. يُفسَّر الوسيط على أنه عامل الضرب التنسوري على اليمين.

على سبيل المثال، ننشئ في الكود أدناه متجهَي حالة يمثلان ∣0⟩\vert 0\rangle و∣1⟩\vert 1\rangle، ونستخدم دالة tensor لإنشاء متجه جديد ∣ψ⟩=∣0⟩⊗∣1⟩\vert \psi\rangle = \vert 0\rangle \otimes \vert 1\rangle. لاحظ أننا نستخدم دالة from_label لتعريف الحالتين ∣0⟩\vert 0\rangle و∣1⟩\vert 1\rangle، بدلاً من تعريفهما يدوياً.

zero = Statevector.from_label("0")
one = Statevector.from_label("1")
psi = zero.tensor(one)
display(psi.draw("latex"))

∣01⟩ |01\rangle

تشمل التسميات المسموح بها أيضاً "+" و"-" للحالتين الموجبة والسالبة، وكذلك "r" و"l" (اختصاراً لـ"right" و"left") للحالتين

∣+i⟩=12∣0⟩+i2∣1⟩and∣−i⟩=12∣0⟩−i2∣1⟩.\vert {+i} \rangle = \frac{1}{\sqrt{2}} \vert 0 \rangle + \frac{i}{\sqrt{2}} \vert 1 \rangle \qquad\text{and}\qquad \vert {-i} \rangle = \frac{1}{\sqrt{2}} \vert 0 \rangle - \frac{i}{\sqrt{2}} \vert 1 \rangle.

هنا، تأتي كلمتا "+" و"-" أو "right" و"left" من سياق الدوران الكمي (spin) في الفيزياء الكمية، حيث قد يشير مركّب الدوران إلى اليسار أو اليمين في التجربة؛ ولا يقصد بها الكيوبت الأيمن أو الأيسر في أنظمة الكيوبتات المتعددة. إليك مثالاً على حاصل الضرب التنسوري لـ∣+⟩\vert {+} \rangle و∣−i⟩\vert {-i} \rangle:

plus = Statevector.from_label("+")
minus_i = Statevector.from_label("l")
phi = plus.tensor(minus_i)
display(phi.draw("latex"))

12∣00⟩−i2∣01⟩+12∣10⟩−i2∣11⟩\frac{1}{2} |00\rangle- \frac{i}{2} |01\rangle+\frac{1}{2} |10\rangle- \frac{i}{2} |11\rangle

بديل آخر هو استخدام عملية ^ للضرب التنسوري، والتي تعطي بطبيعة الحال نفس النتائج.

display((plus ^ minus_i).draw("latex"))

12∣00⟩−i2∣01⟩+12∣10⟩−i2∣11⟩\frac{1}{2} |00\rangle- \frac{i}{2} |01\rangle+\frac{1}{2} |10\rangle- \frac{i}{2} |11\rangle

يمتلك الصنف Operator أيضاً دالة tensor (إضافةً إلى دالة from_label)، كما نرى في الأمثلة التالية.

H = Operator.from_label("H")
Id = Operator.from_label("I")
X = Operator.from_label("X")
display(H.tensor(Id).draw("latex"))
display(H.tensor(Id).tensor(X).draw("latex"))
[220220022022220−2200220−22] \begin{bmatrix} \frac{\sqrt{2}}{2} & 0 & \frac{\sqrt{2}}{2} & 0 \\ 0 & \frac{\sqrt{2}}{2} & 0 & \frac{\sqrt{2}}{2} \\ \frac{\sqrt{2}}{2} & 0 & - \frac{\sqrt{2}}{2} & 0 \\ 0 & \frac{\sqrt{2}}{2} & 0 & - \frac{\sqrt{2}}{2} \\ \end{bmatrix} [0220002200220002200000022000220022000220022000−220022000−2200000022000−220022000−220] \begin{bmatrix} 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 \\ \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 \\ 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} \\ 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 \\ 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 & 0 \\ \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 & 0 & 0 \\ 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} \\ 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 \\ \end{bmatrix}

ومرة أخرى، كما في حالة المتجهات، عملية ^ مكافئة لذلك.

display((H ^ Id ^ X).draw("latex"))
[0220002200220002200000022000220022000220022000−220022000−2200000022000−220022000−220] \begin{bmatrix} 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 \\ \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 \\ 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} \\ 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 \\ 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 & 0 \\ \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 & 0 & 0 \\ 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} \\ 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 \\ \end{bmatrix}

يمكن جعل الحالات المركّبة تتطوّر بتطبيق عمليات مركّبة عليها، كما هو متوقع — تماماً كما رأينا في الأنظمة المفردة في الدرس السابق. على سبيل المثال، يحسب الكود التالي الحالة (H⊗I)∣ϕ⟩(H\otimes I)\vert\phi\rangle حيث ∣ϕ⟩=∣+⟩⊗∣−i⟩\vert\phi\rangle = \vert + \rangle \otimes \vert {-i}\rangle (والذي تم تعريفه أعلاه بالفعل).

display(phi.evolve(H ^ Id).draw("latex"))

22∣00⟩−2i2∣01⟩\frac{\sqrt{2}}{2} |00\rangle- \frac{\sqrt{2} i}{2} |01\rangle

إليك كوداً يعرّف عملية CXCX ويحسب CX∣ψ⟩CX \vert\psi\rangle للحالة ∣ψ⟩=∣+⟩⊗∣0⟩\vert\psi\rangle = \vert + \rangle \otimes \vert 0 \rangle. للتوضيح، هذه عملية CXCX يكون فيها الكيوبت الأيسر هو كيوبت التحكم والكيوبت الأيمن هو كيوبت الهدف. والنتيجة هي حالة بل ∣ϕ+⟩\vert\phi^{+}\rangle.

CX = Operator([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]])
psi = plus.tensor(zero)
display(psi.evolve(CX).draw("latex"))

22∣00⟩+22∣11⟩\frac{\sqrt{2}}{2} |00\rangle+\frac{\sqrt{2}}{2} |11\rangle

القياسات الجزئية​

في الدرس السابق، استخدمنا دالة measure لمحاكاة قياس متجه الحالة الكمية. تُعيد هذه الدالة عنصرَين: نتيجة القياس المحاكاة، والـStatevector الجديدة بعد هذا القياس.

افتراضياً، تقيس measure جميع الكيوبتات في متجه الحالة. يمكننا بدلاً من ذلك تمرير قائمة من الأعداد الصحيحة كمعامل، فلا تُقاس إلا الكيوبتات ذات تلك الفهارس. لتوضيح ذلك، ينشئ الكود أدناه الحالة

∣w⟩=∣001⟩+∣010⟩+∣100⟩3\vert w\rangle = \frac{\vert 001\rangle + \vert 010\rangle + \vert 100\rangle}{\sqrt{3}}

ويقيس الكيوبت رقم 0، وهو الكيوبت الأقصى يميناً. (يُرقّم Qiskit الكيوبتات بدءاً من 0، من اليمين إلى اليسار. سنعود إلى هذه الاتفاقية في الترقيم في الدرس القادم.)

w = Statevector([0, 1, 1, 0, 1, 0, 0, 0] / sqrt(3))
display(w.draw("latex"))

result, state = w.measure([0])
print(f"Measured: {result}\nState after measurement:")
display(state.draw("latex"))

result, state = w.measure([0, 1])
print(f"Measured: {result}\nState after measurement:")
display(state.draw("latex"))

33∣001⟩+33∣010⟩+33∣100⟩\frac{\sqrt{3}}{3} |001\rangle+\frac{\sqrt{3}}{3} |010\rangle+\frac{\sqrt{3}}{3} |100\rangle

Measured: 0
State after measurement:

22∣010⟩+22∣100⟩\frac{\sqrt{2}}{2} |010\rangle+\frac{\sqrt{2}}{2} |100\rangle

Measured: 00
State after measurement:

∣100⟩ |100\rangle