انتقل إلى المحتوى الرئيسي

الإرسال الكمومي عن بُعد والترميز فائق الكثافة

ملاحظة

Kifumi Numata (26 Apr 2024)

تنزيل ملف PDF للمحاضرة الأصلية. لاحظ أن بعض مقاطع الكود قد تصبح غير متوافقة مع الإصدارات الحديثة لأنها صور ثابتة.

الوقت التقريبي للتشغيل على وحدة المعالجة الكمومية هو 10 ثوانٍ.

1. المقدمة

لحل أي مشكلة كمومية على نطاق واسع، نحتاج إلى نقل المعلومات داخل الحاسوب الكمومي من كيوبت إلى آخر. هناك بروتوكولات معروفة للقيام بذلك، وبعض أكثرها أساسية نشأت في سياق إرسال المعلومات بين أطراف بعيدة. في هذا الدرس، سنستخدم أحيانًا لغة متسقة مع هذا السياق مثل "أصدقاء بعيدون يتبادلون المعلومات"، لكن ضع في اعتبارك أن هذه البروتوكولات لها أهمية أوسع في الحوسبة الكمومية. في هذا الدرس نتناول بروتوكولَي التواصل الكمومي التاليين:

  • الإرسال الكمومي عن بُعد (Quantum teleportation) استخدام حالة متشابكة مشتركة (تُسمى أحيانًا e-bit) لإرسال حالة كمومية مجهولة إلى صديق بعيد، مع الحاجة إلى تواصل كلاسيكي مكمِّل.
  • الترميز الكمومي فائق الكثافة (Quantum superdense coding) كيفية إرسال بتَّين من المعلومات بإرسال كيوبت واحد إلى صديق بعيد (باستخدام كيوبتات متشابكة مشتركة مسبقًا).

للمزيد من الخلفية حول هذه المواضيع، نوصي بالدرس الرابع في أساسيات المعلومات الكمومية بعنوان التشابك في التطبيق.

في الوصف أعلاه، "الحالة الكمومية المجهولة" تشير ببساطة إلى حالة بالشكل الموضَّح في الدرس السابق:

ψ=α0+β1|\psi\rangle =\alpha|0\rangle+\beta|1\rangle

حيث α\alpha وβ\beta أعداد مركبة بحيث α2+β2=1|\alpha|^2+|\beta|^2 = 1. يتيح لنا ذلك كتابة الحالة الكمومية على النحو:

ψ=cosθ20+eiφsinθ21=(cosθ2eiφsinθ2)|\psi\rangle =\cos\frac{\theta}{2}|0\rangle+e^{i\varphi}\sin\frac{\theta}{2}|1\rangle= \left( \begin{matrix} \cos\frac{\theta}{2}\\ e^{i\varphi}\sin\frac{\theta}{2} \end{matrix} \right)

بما أننا نريد أن نكون قادرين على نقل المعلومات في أي حالة كمومية عشوائية، فإن توليد مثل هذه الحالة هو ما سنبدأ به هذا الدرس.

2. مصفوفات الكثافة

يمكننا أيضًا كتابة الحالة الكمومية ψ|\psi \rangle على هيئة مصفوفة كثافتها. هذا الشكل مفيد للتعبير عن المزيج الاحتمالي من الحالات الكمومية النقية. في حالة كيوبت واحد يمكن كتابة:

ψψρ=((cosθ2eiφsinθ2))((cosθ2eiφsinθ2))=12((1+cosθeiφsinθeiφsinθ1cosθ))|\psi \rangle \langle \psi| \equiv \rho = \left( \begin{pmatrix} \cos\frac{\theta}{2}\\ e^{i\varphi}\sin\frac{\theta}{2} \end{pmatrix} \right) \left( \begin{pmatrix} \cos\frac{\theta}{2} & e^{-i\varphi}\sin\frac{\theta}{2} \end{pmatrix} \right) =\frac{1}{2}\left(\begin{pmatrix} 1+\cos\theta & e^{-i\varphi}\sin\theta\\ e^{-i\varphi}\sin\theta & 1-\cos\theta \end{pmatrix}\right)

لاحظ أن مصفوفة الكثافة ρ\rho هي مجموع خطي لمصفوفات باولي، كما يلي:

ρ=12(I+(sinθcosφ)X+(sinθsinφ)Y+(cosθ)Z)\rho = \frac{1}{2}\bigl( \textbf{I} + (\sin{\theta}\cos{\varphi})\textbf{X}+ (\sin{\theta}\sin{\varphi})\textbf{Y} + (\cos{\theta})\textbf{Z} \bigr)

أو بشكل عام:

ρ=12(I+rxX+ryY+rzZ)\rho = \frac{1}{2}(\textbf{I} + r_{x}\textbf{X}+ r_{y}\textbf{Y} + r_{z}\textbf{Z})

حيث rx2+ry2+rz2=1r_{x}^2+r_{y}^2+r_{z}^2=1.

وشعاع بلوخ هو r=(rx,ry,rz)\textbf{r} = (r_{x}, r_{y}, r_{z}).

الآن، لنُنشئ حالة كمومية عشوائية باستخدام أرقام عشوائية.

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer qiskit-ibm-runtime
import numpy as np

# create a random 1-qubit state from a random (theta, varphi) to define r vector
np.random.seed(1) # fixing seed for repeatibility

theta = np.random.uniform(0.0, 1.0) * np.pi # from 0 to pi
varphi = np.random.uniform(0.0, 2.0) * np.pi # from 0 to 2*pi

def get_r_vec(theta, varphi):
rx = np.sin(theta) * np.cos(varphi)
ry = np.sin(theta) * np.sin(varphi)
rz = np.cos(theta)
return (rx, ry, rz)

# get r vector
rx, ry, rz = get_r_vec(theta, varphi)

print("theta=" + str(theta), ",varphi=" + str(varphi))
print("(rx, ry, rz) = (" + str(rx) + ", " + str(ry) + ", " + str(rz) + ")")
theta=1.3101132663588946 ,varphi=4.525932273597346
(rx, ry, rz) = (-0.1791150283307452, -0.9494670044331133, 0.2577405946274022)

يمكننا عرض شعاع بلوخ هذا على كرة بلوخ.

from qiskit.visualization import plot_bloch_vector

r = [rx, ry, rz]
plot_bloch_vector(r)

Output of the previous code cell

3. التوصيف الكمومي للحالة

إذا قِست الحالة الكمومية في الأساس الحسابي (0|0 \rangle و1|1 \rangle) فحسب، فستضيع معلومات الطور (معلومات الأعداد المركبة). لكن إذا توفرت لديك نسخ كثيرة من ψ|\psi \rangle عبر تكرار عملية التحضير (لا يمكننا نسخ الحالات، لكن يمكننا تكرار عمليات التحضير)، فيمكننا تقدير قيم rx,ry,rzr_{x}, r_{y}, r_{z} عبر إجراء توصيف الحالة الكمومية لمصفوفة الكثافة ρ\rho. بالنظر إلى الشكل:

ρ=12(I+rxX+ryY+rzZ)\rho = \frac{1}{2}(\textbf{I} + r_{x}\textbf{X}+ r_{y}\textbf{Y} + r_{z}\textbf{Z})

يتحقق ما يلي:

Tr(Xρ)=rx,Tr(Yρ)=ry,Tr(Zρ)=rzTr(\textbf{X} \rho) = r_{x}, \quad Tr(\textbf{Y} \rho) = r_{y}, \quad Tr(\textbf{Z} \rho) = r_{z}

في حالة rzr_{z}:

Tr(Zρ)=0Zρ0+1Zρ1Tr(\textbf{Z} \rho) = \langle 0|\textbf{Z} \rho|0 \rangle + \langle 1|\textbf{Z} \rho|1 \rangle =0(0011)ρ0+1(0011)ρ1= \langle 0|(|0 \rangle\langle 0|-|1 \rangle\langle 1|) \rho|0 \rangle +\langle 1|(|0 \rangle\langle 0|-|1 \rangle\langle 1|) \rho|1 \rangle =0ρ01ρ1=\langle 0|\rho|0 \rangle- \langle 1| \rho|1 \rangle =0ψψ01ψψ1=\langle 0|\psi\rangle\langle \psi|0 \rangle - \langle 1| \psi\rangle\langle \psi|1 \rangle =α2β2=|\alpha|^2-|\beta|^2

التحويل الأخير في المعادلة يخص ψ=α0+β1|\psi \rangle =\alpha|0\rangle+\beta|1\rangle. وبالتالي، يمكننا الحصول على rzr_{z} عبر احتمال 0|0 \rangle ناقص احتمال 1|1 \rangle.

تقدير قيمة rzr_z

لتقدير rzr_z، ننشئ حالة كمومية ونقيسها، ثم نكرر عملية التحضير والقياس مرات عديدة. وأخيرًا نستخدم إحصاءات القياس لتقدير الاحتمالات السابقة ومن ثَمَّ تقدير rzr_z.

لإنشاء الحالة الكمومية العشوائية، سنستخدم بوابة الوحدة العامة UU مع المعاملات θ,φ\theta, \varphi. (راجع بوابة U للمزيد من المعلومات.)

from qiskit import QuantumCircuit

# create a 1-qubit quantum state psi from theta, varphi parameters
qc = QuantumCircuit(1, 1)
qc.u(theta, varphi, 0.0, 0)

# measure in computational basis
qc.measure(0, 0)

qc.draw(output="mpl")

Output of the previous code cell

باستخدام AerSimulator، سنقيس في الأساس الحسابي لتقدير rzr_z.

# see if the expected value of measuring in the computational basis
# approaches the limit of rz
from qiskit_aer import AerSimulator
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import Sampler
from qiskit.visualization import plot_histogram

# Define backend
backend = AerSimulator()
nshots = 1000 # or 10000
# nshots = 10000

# Transpile to backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)

# Run the job
sampler = Sampler(mode=backend)
job = sampler.run([isa_qc], shots=nshots)
result = job.result()

# Extract counts data
counts = result[0].data.c.get_counts()
print(counts)

# Plot the counts in a histogram

plot_histogram(counts)
{'1': 375, '0': 625}

Output of the previous code cell

rz_approx = (counts["0"] - counts["1"]) / nshots

print("rz = ", rz, " and approx of rz = ", rz_approx)
rz =  0.2577405946274022  and approx of rz =  0.25

باستخدام طريقة توصيف الحالة الكمومية، قدَّرنا قيمة rzr_z. في هذه الحالة، بما أننا اخترنا معاملات الحالة "العشوائية"، نعرف قيمة rzr_z ويمكننا التحقق من نتائجنا. لكن بطبيعة الأمور، العمل على النطاق الواسع ليس دائمًا بهذه البساطة للتحقق منه. سنناقش المزيد حول التحقق من النتائج الكمومية لاحقًا في هذه الدورة. في الوقت الحالي، لاحظ فقط أن تقديرنا كان دقيقًا بشكل معقول.

التمرين 1: تقدير قيمة rxr_x

تذكر أن أجهزة الكمبيوتر الكمومية من IBM® تقيس على طول المحور zz (يُعبَّر عنه أحيانًا بـ"في الأساس zz" أو "في الأساس الحسابي"). لكن باستخدام الدورانات قبل القياس، يمكننا قياس إسقاط الحالة الكمومية على المحور x أيضًا. بدقة أكبر، إذا دوَّرنا نظامنا بحيث ما كان يشير نحو xx يصبح الآن يشير نحو zz، فيمكننا الإبقاء على نفس أجهزة القياس على طول zz، لكن نتعلم عن الحالة التي كانت تشير للتو على طول xx لحظة قبل. هكذا تُجري معظم أجهزة الكمبيوتر الكمومية (وجميع أجهزة IBM الكمومية) القياسات على محاور متعددة.

بهذا الفهم، حاول كتابة كود لتقدير قيمة rxr_x باستخدام توصيف الحالة الكمومية.

الحل:

# create a 1-qubit quantum state psi from theta, varphi parameters
qc = QuantumCircuit(1, 1)
qc.u(theta, varphi, 0.0, 0)

qc.h(0)
qc.measure(0, 0)

qc.draw(output="mpl")

Output of the previous code cell

# Define backend
backend = AerSimulator()
nshots = 10000

# Transpile to backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)

# Run the job
sampler = Sampler(mode=backend)
job = sampler.run([isa_qc], shots=nshots)
result = job.result()

# Extract counts data
counts = result[0].data.c.get_counts()
print(counts)

# Plot the counts in a histogram
plot_histogram(counts)
{'1': 5925, '0': 4075}

Output of the previous code cell

rx_approx = (counts["0"] - counts["1"]) / nshots

print("rx = ", rx, " and approx of rx = ", rx_approx)
rx =  -0.1791150283307452  and approx of rx =  -0.185

التمرين 2: تقدير قيمة ryr_y

باستخدام نفس المنطق السابق، يمكننا تدوير النظام قبل القياس لمعرفة ryr_y. حاول كتابة الكود بنفسك لتقدير قيمة ryr_y باستخدام توصيف الحالة الكمومية. يمكنك البدء من المثال السابق مع إجراء دورانات مختلفة. (لمزيد من المعلومات عن البوابات المستخدمة بما فيها sdg، راجع مرجع API.)

الحل:

# create a 1-qubit quantum state psi from theta, varphi parameters
qc = QuantumCircuit(1, 1)
qc.u(theta, varphi, 0.0, 0)

qc.sdg(0)
qc.h(0)
qc.measure(0, 0)

qc.draw(output="mpl")

Output of the previous code cell

# Define backend
backend = AerSimulator()
nshots = 10000

# Transpile to backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)

# Run the job
sampler = Sampler(mode=backend)
job = sampler.run([isa_qc], shots=nshots)
result = job.result()

# Extract counts data
counts = result[0].data.c.get_counts()
print(counts)

# Plot the counts in a histogram
plot_histogram(counts)
{'1': 9759, '0': 241}

Output of the previous code cell

ry_approx = (counts["0"] - counts["1"]) / nshots

print("ry = ", ry, " and approx of ry = ", ry_approx)
ry =  -0.9494670044331133  and approx of ry =  -0.9518

لقد قدَّرنا الآن جميع مكونات r\vec{r} ويمكننا كتابة الشعاع الكامل.

print("Estimated vector is (", rx_approx, ",", ry_approx, ",", rz_approx, ").")
print("Original random vector was (" + str(rx) + ", " + str(ry) + ", " + str(rz) + ").")
Estimated vector is ( -0.185 , -0.9518 , 0.25 ).
Original random vector was (-0.1791150283307452, -0.9494670044331133, 0.2577405946274022).

حصلت على تقدير دقيق إلى حد معقول للشعاع العشوائي الأصلي باستخدام طريقة توصيف الحالة الكمومية هذه.

4. الإرسال الكمومي عن بُعد

لنفكر في الموقف الذي تريد فيه شخصية اسمها أليس إرسال حالة كمومية مجهولة ψ|\psi \rangle إلى صديقها بوب البعيد. افترض أنهما لا يستطيعان التواصل إلا بالتواصل الكلاسيكي (مثل البريد الإلكتروني أو الهاتف). لا تستطيع أليس نسخ الحالة الكمومية (بسبب نظرية عدم الاستنساخ). لو كررت نفس عملية التحضير مرات عديدة، لاستطاعت جمع الإحصاءات كما فعلنا للتو. لكن ماذا لو كانت هناك حالة مجهولة واحدة فقط؟ ربما نشأت هذه الحالة من عملية فيزيائية تريد دراستها، أو ربما كانت جزءًا من عملية حسابية كمومية أكبر. في هذه الحالة، كيف يمكن لأليس إرسال الحالة إلى بوب؟ يمكنها فعل ذلك إذا تقاسمت هي وبوب مصدرًا كموميًا ثمينًا: حالة متشابكة مشتركة، مثل حالة بيل التي عُرِّفت في الدرس السابق: 00+112\frac {|00\rangle + |11\rangle}{\sqrt 2}. قد تجد هذا أحيانًا مشار إليه بـ"زوج EPR" أو "e-bit" (وحدة أساسية من التشابك). إذا تقاسمت أليس مثل هذه الحالة المتشابكة مع بوب، فيمكنها إرسال الحالة الكمومية المجهولة إلى بوب عن بُعد عبر تنفيذ سلسلة من العمليات الكمومية وإرسال بتَّين من المعلومات الكلاسيكية إليه.

4.1 بروتوكول الإرسال الكمومي عن بُعد

الافتراض: لدى أليس حالة كمومية مجهولة ψ|\psi \rangle تريد إرسالها إلى بوب. تتقاسم أليس وبوب حالة متشابكة من كيوبتَّين (e-bit)، ويمتلك كل منهما أحد الكيوبتَّين فعليًا في موقعه.

فيما يلي نوضح الإجراء دون شرح. سيُطبَّق بالتفصيل أدناه.

  1. تتشابك أليس ψ|\psi \rangle مع جزئها من الـ e-bit باستخدام بوابة CNOT.
  2. تطبّق أليس بوابة هادامار على ψ|\psi \rangle، وتقيس كلا الكيوبتَّين في الأساس الحسابي.
  3. ترسل أليس إلى بوب نتائج قياسها (إما "00" أو "01" أو "10" أو "11").
  4. يُنفّذ بوب عملية تصحيح بناءً على بتَّي معلومات أليس على جزئه من زوج الـ e-bit.
    • إذا كانت "00"، لا يفعل بوب شيئًا
    • إذا كانت "01"، يطبّق بوب بوابة X
    • إذا كانت "10"، يطبّق بوب بوابة Z
    • إذا كانت "11"، يطبّق بوب iY = ZX
  5. يصبح جزء بوب من الـ e-bit هو ψ|\psi \rangle.

هذا مشروح أيضًا بمزيد من التفصيل في أساسيات المعلومات الكمومية. لكن الصورة ستتضح أكثر حين نطبّق ذلك في Qiskit.

4.2 الدائرة الكمومية التي تحاكي الإرسال الكمومي عن بُعد

كالمعتاد، سنطبّق إطار أنماط Qiskit. سيُركّز هذا القسم الفرعي على الخطوة الأولى من الخرائط فقط.

الخطوة 1: تعيين المسألة على دوائر وعمليات كمومية

لوصف السيناريو أعلاه، نحتاج إلى دائرة من ثلاثة كيوبتات: اثنان لزوج المتشابكات المشتركة بين أليس وبوب، وواحد للحالة الكمومية المجهولة ψ|\psi\rangle.

from qiskit import QuantumCircuit
import numpy as np
# create 3-qubits circuit
qc = QuantumCircuit(3, 3)

qc.draw(output="mpl")

Output of the previous code cell

في البداية، لدى أليس حالة كمومية مجهولة ψ|\psi \rangle. سننشئها باستخدام بوابة UU.

# Create the unknown quantum state using the u-gate. Alice has this.
qc.u(theta, varphi, 0.0, 0)
qc.barrier() # for visual separation

qc.draw(output="mpl")

Output of the previous code cell

يمكننا تصوّر الحالة التي أنشأناها، لكن فقط لأننا نعرف المعاملات المستخدمة في بوابة UU. لو نشأت هذه الحالة من عملية كمومية معقدة، لما كانت الحالة معروفة دون تشغيل العملية مرات عديدة وجمع الإحصاءات كما في التوصيف.

# show the quantum state on bloch sphere
from qiskit.quantum_info import Statevector
from qiskit.visualization import plot_bloch_multivector

out_vector = Statevector(qc)

plot_bloch_multivector(out_vector)

Output of the previous code cell

قبل أن يبدأ هذا البروتوكول، نفترض أن أليس وبوب يمتلكان زوجًا متشابكًا مشتركًا. إذا كان أليس وبوب في مواقع مختلفة حقًا، فربما أعدّا الحالة المشتركة قبل إنشاء الحالة المجهولة ψ|\psi\rangle. بما أن تلك العمليات تجري على كيوبتات مختلفة، فإن الترتيب هنا لن يكون مهمًا، وهذا الترتيب مناسب للتصوير البصري.

# Alice and Bob are together in the same place and set up an entangled pair.
qc.h(1)
qc.cx(1, 2)
qc.barrier() # for visual separation.
# We can consider that Alice and Bob might move their qubits to different physical locations, now.

qc.draw(output="mpl")

Output of the previous code cell

بعد ذلك، تتشابك أليس ψ|\psi \rangle مع جزئها من الـ e-bit المشترك، باستخدام بوابة CXCX وبوابة HH، وتقيسهما في الأساس الحسابي.

# Alice entangles the unknown state with her part of the e-bit, using the CNOT gate and H gate.
qc.cx(0, 1)
qc.h(0)
qc.barrier()

# Alice measures the two qubits.
qc.measure(0, 0)
qc.measure(1, 1)

qc.draw(output="mpl")

Output of the previous code cell

ترسل أليس إلى بوب نتائج قياسها (إما "00" أو "01" أو "10" أو "11")، ويُنفّذ بوب عملية تصحيح بناءً على بتَّي معلومات أليس على جزئه من الـ e-bit المشترك. ثم يصبح جزء بوب ψ|\psi \rangle.

# Alice sent the results to Bob. Bob applies correction
with qc.if_test((0, 1)):
qc.z(2)
with qc.if_test((1, 1)):
qc.x(2)
qc.barrier()

qc.draw(output="mpl")

Output of the previous code cell

لقد أكملت دائرة الإرسال الكمومي عن بُعد! لنرَ حالة إخراج هذه الدائرة باستخدام محاكي متجه الحالة.

from qiskit_aer import StatevectorSimulator

backend = StatevectorSimulator()
out_vector = backend.run(qc, shots=1).result().get_statevector() # set shots = 1

plot_bloch_multivector(out_vector)

Output of the previous code cell

يمكنك رؤية أن الحالة الكمومية التي أنشأتها بوابة UU للكيوبت 0 (الكيوبت الذي كان يحمل الحالة السرية في الأصل) قد انتقلت إلى الكيوبت 2 (كيوبت بوب).

يمكنك تشغيل الخلية أعلاه بضع مرات للتأكد. قد تلاحظ أن الكيوبتَّين 0 و1 يغيران حالتيهما، لكن الكيوبت 2 يكون دائمًا في الحالة ψ|\psi\rangle.

4.3 تنفيذه والتحقق من النتيجة بتطبيق معكوس U

في الأعلى، تحققنا بصريًا من أن الحالة المُرسَلة كانت صحيحة. طريقة أخرى للتحقق من أن الحالة الكمومية قد أُرسلت بشكل صحيح هي تطبيق معكوس بوابة UU على كيوبت بوب حتى نتمكن من قياس '0'. أي، بما أن U1UU^{-1}U هي محايد الهوية، إذا كان كيوبت بوب في الحالة التي أنشأها U0U|0\rangle، فإن تطبيق المعكوس يُعطي U1U0=0U^{-1}U|0\rangle=|0\rangle.

# Apply the inverse of u-gate to measure |0>
qc.u(theta, varphi, 0.0, 2).inverse() # inverse of u(theta,varphi,0.0)
qc.measure(2, 2) # add measurement gate

qc.draw(output="mpl")

Output of the previous code cell

سننفّذ الدائرة أولًا باستخدام AerSimulator قبل الانتقال إلى حاسوب كمومي حقيقي.

from qiskit_aer import AerSimulator
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import Sampler
from qiskit.visualization import plot_histogram

# Define backend
backend = AerSimulator()

# Transpile to backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)

# Run the job
sampler = Sampler(mode=backend)
job = sampler.run([isa_qc], shots=nshots)
result = job.result()

# Extract counts data
counts = result[0].data.c.get_counts()
print(counts)

# Plot the counts in a histogram
plot_histogram(counts)
{'011': 2510, '010': 2417, '000': 2635, '001': 2438}

Output of the previous code cell

تذكر أنه في ترميز little endian، الكيوبت 2 هو الكيوبت الموجود في أقصى اليسار (أو في أسفل، في تسميات الأعمدة). لاحظ أن الكيوبت الأيسر والأسفل في تسميات الأعمدة هو 0 لجميع النتائج المحتملة. هذا يُظهر أن احتمال قياس q2q_2 في الحالة 0|0\rangle هو 100%. هذه هي النتيجة المتوقعة وتدل على أن بروتوكول الإرسال عمل بشكل صحيح.

4.4 الإرسال الكمومي عن بُعد على حاسوب كمومي حقيقي

بعد ذلك، سننفّذ الإرسال عن بُعد على حاسوب كمومي حقيقي. باستخدام وظيفة الدائرة الديناميكية، يمكننا تشغيل عمليات في منتصف الدائرة بناءً على نتائج القياس، مطبِّقين في الوقت الحقيقي العمليات الشرطية في دائرة الإرسال. لحل المشكلات بأجهزة الكمبيوتر الكمومية الحقيقية، سنتبع الخطوات الأربع لأنماط Qiskit.

  1. تعيين المسألة على دوائر وعمليات كمومية
  2. التحسين للعتاد المستهدف
  3. التنفيذ على العتاد المستهدف
  4. معالجة النتائج

التمرين 3: بناء دائرة الإرسال الكمومي عن بُعد

حاول بناء دائرة الإرسال الكامل من الصفر لاختبار فهمك. ارجع إلى الأعلى إذا احتجت تذكيرًا.

الحل:

# Step 1: Map problem to quantum circuits and operators
# Create the circuit with 3-qubits and 1-bit
qc = QuantumCircuit(3, 3)

# Alice creates an unknown quantum state using the u-gate.
qc.u(theta, varphi, 0.0, 0)
qc.barrier() # for visual separation

# Eve creates EPR pair and sends q1 to Alice and q2 to Bob
##your code goes here##
qc.h(1)
qc.cx(1, 2)
qc.barrier()

# Alice entangles the unknown state with her EPR part, using the CNOT gate and H gate.
##your code goes here##
qc.cx(0, 1)
qc.h(0)
qc.barrier()

# Alice measures the two qubits.
##your code goes here##
qc.measure(0, 0)
qc.measure(1, 1)

# Alice sent the results to Bob. Now, Bob applies correction
##your code goes here##
with qc.if_test((0, 1)):
qc.z(2)
with qc.if_test((1, 1)):
qc.x(2)
qc.barrier()

# Apply the inverse of u-gate to measure |0>
qc.u(theta, varphi, 0.0, 2).inverse()
qc.measure(2, 2)

qc.draw(output="mpl")

Output of the previous code cell

كتذكير، تطبيق معكوس بوابة UU يُستخدم فقط للتحقق من السلوك المتوقع، وليس جزءًا من إرسال الحالة إلى بوب. لن نستخدم بوابة UU المعكوسة تلك إذا كان الهدف الوحيد هو نقل المعلومات الكمومية.

الخطوة 2: التحسين للعتاد المستهدف

للتشغيل على العتاد، استورد QiskitRuntimeService وحمِّل بيانات الاعتماد المحفوظة. اختر الجهاز الخلفي (backend) الذي يملك أقل عدد من الوظائف في قائمة الانتظار.

from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()
service.backends()
[<IBMBackend('ibm_brisbane')>,
<IBMBackend('ibm_torino')>]
# You can also identify the least busy device
backend = service.least_busy(operational=True)
print("The least busy device is ", backend)
The least busy device is  <IBMBackend('ibm_brisbane')>
# You can specify the device
# backend = service.backend('ibm_brisbane')

لنرَ خريطة الاقتران للجهاز الذي اخترته.

from qiskit.visualization import plot_gate_map

plot_gate_map(backend)

Output of the previous code cell

قد تمتلك الأجهزة المختلفة خرائط اقتران مختلفة، ولكل جهاز بعض الكيوبتات والقنوات التي تُعطي أداءً أفضل من غيرها. أيضًا، قد تمتلك أجهزة الكمبيوتر الكمومية المختلفة بوابات أصلية مختلفة (البوابات التي يستطيع العتاد تنفيذها). يعيد التحويل البرمجي (transpilation) كتابة الدائرة الكمومية المجردة باستخدام بوابات يستطيع الحاسوب الكمومي المستهدف تنفيذها، ويختار التعيين الأمثل للكيوبتات الفيزيائية (من بين أمور أخرى). التحويل البرمجي موضوع غني ومعقد. لمزيد من المعلومات عن التحويل البرمجي، راجع مرجع API.

# Step 2: Optimize for target hardware
# Transpile the circuit into basis gates executable on the hardware
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

pm = generate_preset_pass_manager(backend=backend, optimization_level=2)
qc_compiled = pm.run(qc)

qc_compiled.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

الخطوة 3: تنفيذ الدائرة

باستخدام العنصر الأساسي لوقت التشغيل Sampler، سننفّذ الدائرة المستهدفة.

# Step 3: Execute the target circuit
sampler = Sampler(backend)
job = sampler.run([qc_compiled])
job_id = job.job_id()
print("job id:", job_id)
job id: d13nkhpn2txg008jt0d0
# Check the job status
job.status()
'DONE'

يمكنك أيضًا التحقق من حالة الوظيفة من لوحة تحكم IBM Quantum®.

# If the Notebook session got disconnected you can also check your job status by running the following code
from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()
job_real = service.job(job.job_id()) # Input your job-id between the quotations
job_real.status()
'DONE'

إذا رأيت 'DONE' معروضًا، يمكنك الحصول على النتيجة بتنفيذ الخلية أدناه.

# Execute after 'DONE' is displayed
result_real = job_real.result()
print(result_real[0].data.c.get_counts())
{'001': 992, '110': 430, '011': 579, '010': 605, '111': 402, '000': 925, '100': 57, '101': 106}

الخطوة 4: معالجة النتائج

# Step 4: Post-process the results
from qiskit.visualization import plot_histogram

plot_histogram(result_real[0].data.c.get_counts())

Output of the previous code cell

يمكنك تفسير النتائج أعلاه مباشرة. أو، باستخدام marginal_count، يمكنك استخلاص نتائج بوب على الكيوبت 2.

# trace out Bob's results on qubit 2
from qiskit.result import marginal_counts

bobs_qubit = 2
real_counts = result_real[0].data.c.get_counts()
bobs_counts = marginal_counts(real_counts, [bobs_qubit])
plot_histogram(bobs_counts)

Output of the previous code cell

كما نرى هنا، هناك بعض النتائج التي قِسنا فيها 1|1 \rangle. هذه تحدث بسبب الضوضاء والأخطاء. على وجه الخصوص، تميل الدوائر الديناميكية إلى امتلاك معدل خطأ أعلى بسبب القياس الذي يستغرق وقتًا في منتصف الدائرة.

4.5 النقاط الرئيسية حول الإرسال الكمومي عن بُعد

يمكننا نقل حالة كمومية إلى صديق بعيد عبر تبادل زوج من الكيوبتات المتشابكة (e-bit).

  1. هل يمكن للإرسال الكمومي عن بُعد نقل الحالة الكمومية بسرعة أسرع من الضوء؟ لا، لأن على أليس إخبار بوب بنتائج القياس بطريقة كلاسيكية.

  2. هل يُخرق الإرسال الكمومي عن بُعد "نظرية عدم الاستنساخ" التي تحظر نسخ الحالة الكمومية؟ لا، لأن الحالة الكمومية الأصلية التي أعطيت لأليس على أحد كيوبتاتها ضاعت في القياس، إذ انهارت إلى 0|0\rangle أو 1|1\rangle.

5. الترميز فائق الكثافة

يمكن استخدام نفس الإعداد تقريبًا لغرض مختلف. افترض أن أليس تريد إرسال بتَّين من المعلومات الكلاسيكية إلى بوب، لكنها لا تمتلك وسيلة تواصل كلاسيكية معه. غير أنها تتشارك زوجًا متشابكًا مع بوب ويُسمح لها بإرسال كيوبتها إلى موقع بوب. لاحظ التناقض مع بروتوكول الإرسال الكمومي عن بُعد. في الإرسال عن بُعد، كان التواصل الكلاسيكي متاحًا للصديقين، وكان الهدف إرسال حالة كمومية. أما هنا، فالتواصل الكلاسيكي غير متاح ويستخدمان نقل كيوبت لمشاركة بتَّين من المعلومات الكلاسيكية.

5.1 بروتوكول الترميز فائق الكثافة

الافتراض: لدى أليس بتَّان من المعلومات، مثلًا a1a2{00,01,10,11}a_1a_2 \in \{00, 01, 10, 11\}. تتقاسم أليس وبوب زوجًا متشابكًا (e-bit)، لكنهما لا يستطيعان التواصل كلاسيكيًا.

  1. تُنفّذ أليس إحدى العمليات التالية على جزئها من الـ e-bit.
    • إذا كانت a1a2=00a_1a_2 = 00، لا تفعل شيئًا
    • إذا كانت a1a2=01a_1a_2 = 01، تطبّق بوابة Z
    • إذا كانت a1a2=10a_1a_2 = 10، تطبّق بوابة X
    • إذا كانت a1a2=11a_1a_2 = 11، تطبّق بوابة Z ثم بوابة X.
  2. ترسل أليس جزءها من الـ e-bit إلى موقع بوب.
  3. يطبّق بوب بوابة CNOT مع الكيوبت الآتي من أليس كعنصر تحكم وكيوبته كهدف، ثم يطبّق بوابة H على الكيوبت الآتي من أليس، ويقيس الكيوبتَّين. الحالات الابتدائية الممكنة ونتائج عمليات بوب هي:
00+112CX01H000\frac {|00\rangle + |11\rangle}{\sqrt 2} \rightarrow CX_{01}\otimes H_0 \rightarrow |00\rangle 00112CX01H001\frac {|00\rangle - |11\rangle}{\sqrt 2} \rightarrow CX_{01}\otimes H_0 \rightarrow |01\rangle 10+012CX01H010\frac {|10\rangle + |01\rangle}{\sqrt 2} \rightarrow CX_{01}\otimes H_0 \rightarrow |10\rangle 10012CX01H011\frac {|10\rangle - |01\rangle}{\sqrt 2} \rightarrow CX_{01}\otimes H_0 \rightarrow -|11\rangle

لاحظ أن الإشارة السالبة في 11-|11\rangle هي طور كوني، ومن ثَمَّ لا يمكن قياسها.

5.2 الدائرة الكمومية التي تحاكي الترميز فائق الكثافة

بناءً على بروتوكول الترميز فائق الكثافة، يمكنك بناء دائرته كما يلي. حاول تغيير الرسالة msg التي تريد أليس إرسالها إلى بوب.

from qiskit import QuantumCircuit

خطوات نمط Qiskit مُحددة في تعليقات الكود.

# Step 1: Map problem to quantum circuits and operators
# Create 2-qubits circuit
qc = QuantumCircuit(2, 2)

# Eve creates EPR pair and send q0 to Alice and q1 to Bob
qc.h(0)
qc.cx(0, 1)
qc.barrier()

# set message which Alice wants to transform to Bob
msg = "11" # You can change the message

if msg == "00":
pass
elif msg == "10":
qc.x(0)
elif msg == "01":
qc.z(0)
elif msg == "11":
qc.z(0)
qc.x(0)

qc.barrier()
# Bob receives EPR qubit from Alice and performs unitary operations
qc.cx(0, 1)
qc.h(0)
qc.barrier()

# Bob measures q0 and q1
qc.measure(0, 0)
qc.measure(1, 1)

qc.draw(output="mpl")

Output of the previous code cell

# We will execute on a simulator first
from qiskit_aer import AerSimulator
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import Sampler

# Define backend
backend = AerSimulator()
shots = 1000

# Transpile to backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)

# Run the job
sampler = Sampler(mode=backend)
job_sim = sampler.run([isa_qc], shots=shots)
result_sim = job_sim.result()

# Extract counts data
counts = result_sim[0].data.c.get_counts()
print(counts)
{'11': 1000}
# Visualize the results
from qiskit.visualization import plot_histogram

plot_histogram(counts)

Output of the previous code cell

يمكنك رؤية أن بوب استقبل الرسالة التي أرادت أليس إرسالها إليه.

بعد ذلك، لنجرب ذلك على حاسوب كمومي حقيقي.

from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()
backend = service.least_busy(operational=True)
print("The least busy device is ", backend)
The least busy device is  <IBMBackend('ibm_brisbane')>
# Step 1 was already completed before the simulator job above.
# Step 2: Optimize for target hardware
# Transpile the circuit into basis gates executable on the hardware
pm = generate_preset_pass_manager(backend=backend, optimization_level=2)
qc_compiled = pm.run(qc)

qc_compiled.draw("mpl", idle_wires=False)

Output of the previous code cell

# Step 3:Execute the target circuit
sampler = Sampler(backend)
job = sampler.run([qc_compiled])
job_id = job.job_id()
print("job id:", job_id)
job id: d13nnyq3grvg008j0zag
# Check the job status
job.status()
'DONE'
# If the Notebook session got disconnected you can also check your job status by running the following code
# from qiskit_ibm_runtime import QiskitRuntimeService
# service = QiskitRuntimeService()
job = service.job(job_id) # Input your job-id between the quotations
job.status()
'DONE'
# Execute after job has successfully run
real_result = job.result()
print(real_result[0].data.c.get_counts())
{'11': 3942, '01': 107, '10': 41, '00': 6}
# Step 4: post-process the results
from qiskit.visualization import plot_histogram

plot_histogram(real_result[0].data.c.get_counts())

Output of the previous code cell

النتيجة هي ما توقعناه. لاحظ أن الترميز فائق الكثافة على حاسوب كمومي حقيقي أظهر أخطاء أقل مقارنةً بحالة الإرسال الكمومي عن بُعد على حاسوب كمومي حقيقي. أحد أسباب ذلك قد يكون أن الإرسال الكمومي عن بُعد يستخدم دوائر ديناميكية بينما الترميز فائق الكثافة لا يستخدمها. سنتعلم المزيد عن الأخطاء في الدوائر الكمومية في دروس لاحقة.

6. الخلاصة

في هذه الجلسة، طبّقنا بروتوكولَين كموميَّين. رغم أن سيناريو الأصدقاء البعيدين في كليهما بعيد بعض الشيء عن الحوسبة الكمومية على وحدة معالجة كمومية واحدة، إلا أن لهما تطبيقات في الحوسبة الكمومية وتُساعداننا على فهم نقل المعلومات الكمومية بشكل أفضل.

  • الإرسال الكمومي عن بُعد (Quantum teleportation): رغم أننا لا نستطيع نسخ الحالات الكمومية، يمكننا إرسال حالات كمومية مجهولة عن بُعد بوجود تشابك مشترك.
  • الترميز الكمومي فائق الكثافة (Quantum superdense coding): زوج متشابك مشترك ونقل كيوبت واحد يُمكِّنان من التواصل ببتَّين من المعلومات الكلاسيكية.
# See the version of Qiskit
import qiskit

qiskit.__version__
'2.0.2'