การเทเลพอร์ตเทชันควอนตัมและการเข้ารหัสแบบซูเปอร์เดนส์
Kifumi Numata (26 Apr 2024)
ดาวน์โหลด PDF ของการบรรยายต้นฉบับ โปรดทราบว่าโค้ดบางส่วนอาจล้าสมัยแล้ว เนื่องจากเป็นภาพนิ่ง
เวลา QPU โดยประมาณในการรันการทดลองนี้คือ 10 วินาที
1. บทนำ
ในการแก้ปัญหาควอนตัมระดับ utility-scale ใด ๆ เราจำเป็นต้องย้ายข้อมูลภายในคอมพิวเตอร์ควอนตัมจาก Qubit หนึ่งไปยังอีก Qubit หนึ่ง มีโปรโตคอลที่เป็นที่รู้จักดีสำหรับเรื่องนี้ แต่บางโปรโตคอลพื้นฐานที่สุดถูกพัฒนาขึ้นในบริบทของการส่งข้อมูลระหว่างผู้ส่งและผู้รับที่อยู่ห่างไกลกัน ตลอดบทเรียนนี้ บางครั้งเราจะใช้ภาษาที่สอดคล้องกับบริบทนี้ เช่น "เพื่อนที่อยู่ห่างไกลส่งข้อมูลถึงกัน" แต่โปรดจำไว้ว่าโปรโตคอลเหล่านี้มีความสำคัญกว้างกว่านั้นในการคำนวณควอนตัม ในบทเรียนนี้เราพิจารณาโปรโตคอลการสื่อสารควอนตัมต่อไปนี้:
- การเทเลพอร์ตเทชันควอนตัม การใช้สถานะ entangled ที่แบ่งปันกัน (บางครั้งเรียกว่า e-bit) เพื่อส่งสถานะควอนตัมที่ไม่ทราบค่าไปยังเพื่อนที่อยู่ห่างไกล โดยต้องใช้การสื่อสารแบบคลาสสิกเพิ่มเติม
- การเข้ารหัสแบบซูเปอร์เดนส์ควอนตัม วิธีการส่งข้อมูลสองบิตโดยการส่ง Qubit เดียวไปยังเพื่อนที่อยู่ห่างไกล (โดยใช้ Qubit ที่ entangle กันไว้ล่วงหน้าเช่นกัน)
สำหรับพื้นฐานเพิ่มเติมที่เกี่ยวข้องกับหัวข้อเหล่านี้ แนะนำให้ดูบทเรียนที่ 4 ใน Basics of Quantum Information เรื่อง Entanglement in action
ในคำอธิบายข้างต้น "สถานะควอนตัมที่ไม่ทราบค่า" หมายถึงสถานะในรูปแบบที่อธิบายไว้ในบทเรียนก่อนหน้า:
โดยที่ และ เป็นจำนวนเชิงซ้อนที่ ทำให้เราเขียนสถานะควอนตัมได้ว่า
เนื่องจากเราต้องการสามารถถ่ายโอนข้อมูลในสถานะควอนตัมสุ่มใด ๆ ได้ การสร้างสถานะดังกล่าวจึงเป็นจุดเริ่มต้นของบทเรียนนี้
2. เมทริกซ์ความหนาแน่น
เราสามารถเขียนสถานะควอนตัม ในรูปของเมทริกซ์ความหนาแน่นได้เช่นกัน รูปแบบนี้มีประโยชน์สำหรับการแทนส่วนผสมเชิงความน่าจะเป็นของสถานะควอนตัมบริสุทธิ์ สำหรับ Qubit เดียว เราเขียนได้ว่า
สังเกตว่าเมทริกซ์ความหนาแน่น เป็นผลรวมเชิงเส้นของเมทริกซ์ Pauli ดังนี้
หรือในรูปทั่วไป
โดยที่
และ Bloch vector คือ
ตอนนี้ มาสร้างสถานะควอนตัมสุ่มโดยใช้ตัวเลขสุ่ม
# 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)
เราสามารถแสดง Bloch vector นี้บน Bloch sphere ได้
from qiskit.visualization import plot_bloch_vector
r = [rx, ry, rz]
plot_bloch_vector(r)
3. การทำ quantum state tomography
ถ้าวัดสถานะควอนตัมในฐาน computational ( และ ) เท่านั้น ข้อมูลเฟส (ข้อมูลจำนวนเชิงซ้อน) จะสูญหาย แต่ถ้าเรามีสำเนาของ หลายชุดโดยการทำซ้ำกระบวนการเตรียม (เราไม่สามารถ clone สถานะได้ แต่สามารถทำซ้ำกระบวนการเตรียมได้) เราสามารถประมาณค่า ได้โดยการทำ quantum state tomography สำหรับเมทริกซ์ความหนาแน่น เมื่อให้รูปแบบ:
จะได้ว่า
ในกรณีของ ,
การแปลงสมการขั้นสุดท้ายเป็นสำหรับ ดังนั้น เราสามารถหา ได้จาก ความน่าจะเป็นของ ลบ ความน่าจะเป็นของ
ประมาณค่า
ในการประมาณค่า เราสร้างสถานะควอนตัมแล้ววัดผล จากนั้นทำซ้ำกระบวนการเตรียมและวัดผลหลายครั้ง สุดท้ายใช้สถิติการวัดเพื่อประมาณความน่าจะเป็นข้างต้นและประมาณค่า
สำหรับการสร้างสถานะควอนตัมสุ่ม เราจะใช้ Gate unitary ทั่วไป ที่มีพารามิเตอร์ (ดูข้อมูลเพิ่มเติมได้ที่ U-gate)
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")
การใช้ AerSimulator เราจะวัดใน computational basis เพื่อประมาณค่า
# 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}
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
ด้วยวิธี quantum state tomography เราประมาณค่า ได้แล้ว ในกรณีนี้ เนื่องจากเราเลือกพารามิเตอร์สำหรับสถานะ "สุ่ม" เอง เราจึงรู้ค่าของ และสามารถตรวจสอบผลลัพธ์ได้ แต่โดยธรรมชาติแล้ว งานระดับ utility-scale ไม่ได้ตรวจสอบง่ายขนาดนั้นเสมอไป เราจะพูดถึงการตรวจสอบผลลัพธ์ควอนตัมเพิ่มเติมในภายหลังในหลักสูตรนี้ ตอนนี้ขอให้สังเกตว่าการประมาณของเราค่อนข้างแม่นยำ
แบบฝึกหัดที่ 1: ประมาณค่า
ระลึกว่าคอมพิวเตอร์ควอนตัม IBM® วัดตามแกน (บางครั้งเรียกว่า "ใน basis" หรือ "ใน computational basis") อย่างไรก็ตาม โดยการใช้การหมุนก่อนการวัด เราสามารถวัดการฉายของสถานะควอนตัมบนแกน x ได้ด้วย พูดให้ชัดเจนขึ้น ถ้าเราหมุนระบบเพื่อให้สิ่งที่เคยชี้ไปตามแนว มาชี้ตามแนว แทน เราก็สามารถคงฮาร์ดแวร์วัดแบบเดิมตามแนว ไว้ได้ แต่เรียนรู้เกี่ยวกับสถานะที่เพิ่งชี้ตามแนว เมื่อครู่นี้ นี่คือวิธีที่คอมพิวเตอร์ควอนตัมส่วนใหญ่ (และคอมพิวเตอร์ควอนตัม IBM ทั้งหมด) วัดตามหลายแกน
ด้วยความเข้าใจนี้ ลองเขียนโค้ดเพื่อประมาณค่า โดยใช้ quantum state tomography
วิธีแก้:
# 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")
# 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}
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: ประมาณค่า
ด้วยหลักการทางตรรกะเดียวกัน เราสามารถหมุนระบบก่อนการวัดเพื่อเรียนรู้เกี่ยวกับ
ลองเขียนโค้ดด้วยตัวเองเพื่อประมาณค่า โดยใช้ quantum state tomography คุณอาจเริ่มจากตัวอย่างก่อนหน้า แต่ทำการหมุนที่แตกต่างกัน (สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ Gate ต่าง ๆ รวมถึง sdg ดู API reference)
วิธีแก้:
# 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")
# 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}
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
ตอนนี้เราประมาณองค์ประกอบทั้งหมดของ ได้แล้ว และสามารถเขียนเวกเตอร์เต็มได้
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).
คุณได้รับการประมาณเวกเตอร์สุ่มต้นฉบับที่ค่อนข้างแม่นยำโดยใช้วิธี quantum state tomography นี้
4. การเทเลพอร์ตเทชันควอนตัม
ลองพิจารณาสถานการณ์ที่ Alice ต้องการส่งสถานะควอนตัมที่ไม่ทราบค่า ไปยัง Bob เพื่อนของเธอที่อยู่ห่างไกล สมมติว่าพวกเขาสื่อสารได้เฉพาะทางคลาสสิกเท่านั้น (เช่น อีเมลหรือโทรศัพท์) Alice ไม่สามารถคัดลอกสถานะควอนตัมได้ (เพราะทฤษฎีบท no-cloning) ถ้าเธอทำซ้ำกระบวนการเตรียมหลาย ๆ ครั้ง เธอสามารถสร้างสถิติเหมือนที่เราเพิ่งทำได้ แต่ถ้ามีสถานะที่ไม่ทราบค่าเพียงชุดเดียว? สถานะนี้อาจเกิดขึ้นจากกระบวนการทางฟิสิกส์ที่คุณต้องการศึกษา หรืออาจเป็นส่วนหนึ่งของการคำนวณควอนตัมขนาดใหญ่ ในกรณีนั้น Alice จะส่งสถานะไปยัง Bob ได้อย่างไร? เธอทำได้ ถ้าเธอและ Bob แบ่งปันทรัพยากรควอนตัมอันมีค่า: สถานะ entangled ที่แบ่งปันกัน เช่น Bell state ที่แนะนำในบทเรียนก่อนหน้า: บางครั้งคุณอาจเห็นสิ่งนี้เรียกว่า "EPR pair" หรือ "e-bit" (หน่วยพื้นฐานของ entanglement) ถ้า Alice แบ่งปันสถานะ entangled ดังกล่าวกับ Bob เธอสามารถ teleport สถานะควอนตัมที่ไม่ทราบค่าไปยัง Bob ได้ โดยการทำการดำเนินการควอนตัมหลายชุดและส่งข้อมูลคลาสสิกสองบิตให้เขา
4.1 โปรโตคอลของการเทเลพอร์ตเทชันควอนตัม
สมมติฐาน: Alice มีสถานะควอนตัมที่ไม่ทราบค่า ที่จะส่งไปยัง Bob Alice และ Bob แบ่งปันสถานะ entangled 2 Qubit หรือ e-bit โดยแต่ละคนมี Qubit หนึ่งอยู่ที่ตำแหน่งของตนเอง
ต่อไปนี้คือโครงร่างขั้นตอนโดยไม่มีคำอธิบาย ซึ่งจะมีการนำไปใช้อย่างละเอียดด้านล่าง
- Alice ทำ entangle กับส่วนของ e-bit ที่เธอถือด้วย CNOT Gate
- Alice ใช้ Hadamard Gate กับ แล้ววัด Qubit ทั้งสองของเธอใน computational basis
- Alice ส่งผลการวัดให้ Bob (ไม่ว่าจะเป็น "00", "01", "10" หรือ "11")
- Bob ทำการดำเนินการ correction ตามข้อมูลสองบิตของ Alice บนส่วน e-bit ของเขา
- ถ้า "00", Bob ไม่ทำอะไร
- ถ้า "01", Bob ใช้ X Gate
- ถ้า "10", Bob ใช้ Z Gate
- ถ้า "11", Bob ใช้ iY = ZX Gate
- ส่วน e-bit ของ Bob กลายเป็น
เรื่องนี้ยังมีรายละเอียดเพิ่มเติมใน Basics of Quantum Information แต่สถานการณ์จะชัดเจนขึ้นเมื่อเราสร้างมันใน Qiskit
4.2 Circuit ควอนตัมที่จำลองการเทเลพอร์ตเทชันควอนตัม
เช่นเคย เราจะใช้กรอบงาน Qiskit patterns ส่วนนี้จะมุ่งเน้นเฉพาะการ mapping เท่านั้น
ขั้นตอนที่ 1: จับคู่ปัญหากับ Circuit ควอนตัมและ Operator
เพื่ออธิบายสถานการณ์ข้างต้น เราต้องการ Circuit ที่มีสาม Qubit: สองอันสำหรับคู่ entangled ที่ Alice และ Bob แบ่งปันกัน และหนึ่งอันสำหรับสถานะควอนตัมที่ไม่ทราบค่า
from qiskit import QuantumCircuit
import numpy as np
# create 3-qubits circuit
qc = QuantumCircuit(3, 3)
qc.draw(output="mpl")
ในตอนเริ่มต้น Alice มีสถานะควอนตัมที่ไม่ทราบค่า เราจะสร้างสิ่งนี้โดยใช้ Gate
# 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")
เราสามารถแสดงภาพสถานะที่สร้างขึ้นได้ แต่เฉพาะเพราะเราทราบพารามิเตอร์ที่ใช้ใน Gate ถ้าสถานะนี้เกิดขึ้นจากกระบวนการควอนตัมที่ซับซ้อน สถานะนั้นจะไม่สามารถทราบได้หากไม่รันกระบวนการเพื่อสร้างสถานะหลาย ๆ ครั้งและรวบรวมสถิติเหมือนใน tomography
# 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)

ก่อนที่โปรโตคอลนี้จะเริ่มต้น เราสมมติว่า Alice และ Bob มีคู่ entangled ที่แบ่งปันกันอยู่แล้ว ถ้า Alice และ Bob อยู่คนละที่จริง ๆ พวกเขาอาจตั้งค่าสถานะที่แบ่งปันกัน ก่อน ที่สถานะที่ไม่ทราบค่า จะถูกสร้างขึ้น เนื่องจากสิ่งเหล่านั้นเกิดขึ้นบน Qubit ต่างกัน ลำดับที่นี่จึงไม่สำคัญ และลำดับนี้สะดวกสำหรับการแสดงภาพ
# 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")
ต่อมา Alice ทำ entangle กับส่วน e-bit ของเธอโดยใช้ Gate และ Gate แล้ววัดพวกมันใน computational basis
# 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")
Alice ส่งผลการวัดให้ Bob (ไม่ว่าจะเป็น "00", "01", "10" หรือ "11") แล้ว Bob ทำการดำเนินการ correction ตามข้อมูลสองบิตของ Alice บนส่วน e-bit ที่แบ่งปันกัน จากนั้น ส่วนของ Bob กลายเป็น
# 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")
คุณสร้าง Circuit การเทเลพอร์ตเทชันควอนตัมสำเร็จแล้ว! มาดูสถานะผลลัพธ์ของ Circuit นี้โดยใช้ statevector simulator
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)

คุณจะเห็นว่าสถานะควอนตัมที่สร้างโดย Gate ของ Qubit 0 (Qubit ที่ถือ secret state เดิม) ได้ถูกถ่ายโอนไปยัง Qubit 2 (Qubit ของ Bob) แล้ว
คุณสามารถรันเซลล์ข้างต้นหลาย ๆ ครั้งเพื่อตรวจสอบ คุณอาจสังเกตว่า Qubit 0 และ 1 เปลี่ยนสถานะ แต่ Qubit 2 อยู่ในสถานะ เสมอ
4.3 รันและยืนยันผลลัพธ์โดยการใช้ U inverse
ข้างต้น เราตรวจสอบด้วยสายตาว่าสถานะที่ teleport ดูถูกต้อง อีกวิธีหนึ่งในการตรวจสอบว่าสถานะควอนตัมถูก teleport อย่างถูกต้องหรือไม่ คือการใช้ inverse ของ Gate กับ Qubit ของ Bob เพื่อให้เราวัดได้ '0' นั่นคือ เนื่องจาก เป็น identity ถ้า Qubit ของ Bob อยู่ในสถานะที่สร้างจาก การใช้ inverse ควรให้
# 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")
เราจะรัน Circuit ด้วย 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}
ระลึกว่าในสัญกรณ์ little endian Qubit 2 คือ Qubit ซ้ายสุด (หรือล่างสุด ในป้ายกำกับคอลัมน์) สังเกตว่า Qubit ซ้ายและล่างสุดในป้ายกำกับคอลัมน์เป็น 0 สำหรับทุกผลลัพธ์ที่เป็นไปได้ ซึ่งแสดงว่าเรามีโอกาส 100% ที่จะวัด ในสถานะ นี่คือผลลัพธ์ที่คาดหวัง และบ่งชี้ว่าโปรโตคอลการเทเลพอร์ตเทชันทำงานได้อย่างถูกต้อง
4.4 การเทเลพอร์ตเทชันบนคอมพิวเตอร์ควอนตัมจริง
ต่อไป เราจะทำการเทเลพอร์ตเทชันบนคอมพิวเตอร์ควอนตัมจริง โดยใช้ฟังก์ชัน dynamic circuit เราสามารถดำเนินการกลางวงจรโดยใช้ผลการวัด ซึ่งนำการดำเนินการแบบมีเงื่อนไขใน Circuit การเทเลพอร์ตเทชันมาใช้แบบ real-time สำหรับการแก้ปัญหากับคอมพิวเตอร์ควอนตัมจริง เราจะทำตามสี่ขั้นตอนของ Qiskit patterns
- จับคู่ปัญหากับ Circuit ควอนตัมและ Operator
- ปรับแต่งสำหรับฮาร์ดแวร์เป้าหมาย
- รันบนฮาร์ดแวร์เป้าหมาย
- ประมวลผลผลลัพธ์
แบบฝึกหัดที่ 3: สร้าง Circuit การเทเลพอร์ตเทชัน
ลองสร้าง Circuit การเทเลพอร์ตเทชันทั้งหมดตั้งแต่ต้นเพื่อทดสอบความเข้าใจของคุณ เลื่อนกลับขึ้นถ้าต้องการทบทวน
วิธีแก้:
# 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")
เป็นการเตือนความจำ การใช้ inverse ของ Gate เป็นเพียงเพื่อให้เราสามารถยืนยันพฤติกรรมที่คาดหวัง มันไม่ใช่ส่วนหนึ่งของการส่งสถานะไปยัง Bob และเราจะไม่ใช้ Gate inverse นั้นถ้าเป้าหมายเดียวคือถ่ายโอนข้อมูลควอนตัม
ขั้นตอนที่ 2: ปรับแต่งสำหรับฮาร์ดแวร์เป้าหมาย
ในการรันบนฮาร์ดแวร์ ให้ import QiskitRuntimeService และโหลด credentials ที่บันทึกไว้ เลือก 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')
มาดู coupling map ของอุปกรณ์ที่คุณเลือก
from qiskit.visualization import plot_gate_map
plot_gate_map(backend)

อุปกรณ์ต่าง ๆ อาจมี coupling map ที่แตกต่างกัน และแต่ละอุปกรณ์มี Qubit และ coupler บางตัวที่มีประสิทธิภาพดีกว่า ท้ายที่สุด คอมพิวเตอร์ควอนตัมต่าง ๆ อาจมี native gates ที่แตกต่างกัน (Gate ที่ฮาร์ดแวร์สามารถรันได้) การ Transpile Circuit จะเขียน Circuit ควอนตัมนามธรรมใหม่โดยใช้ Gate ที่คอมพิวเตอร์ควอนตัมเป้าหมายสามารถรันได้ และเลือก mapping ที่เหมาะสมที่สุดไปยัง physical Qubit (รวมถึงสิ่งอื่น ๆ) การ Transpilation เป็นหัวข้อที่ซับซ้อนมาก ดูข้อมูลเพิ่มเติมเกี่ยวกับการ Transpilation ได้ที่ API reference
# 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)
ขั้นตอนที่ 3: รัน Circuit
โดยใช้ Runtime primitive Sampler เราจะรัน Circuit เป้าหมาย
# 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® dashboard
# 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())
คุณสามารถตีความผลลัพธ์ข้างต้นได้โดยตรง หรือใช้ marginal_count เพื่อตรวจสอบผลลัพธ์ของ Bob บน Qubit 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)
จากที่เห็น มีผลลัพธ์บางส่วนที่เราวัดได้ ซึ่งเกิดจาก noise และ errors โดยเฉพาะอย่างยิ่ง dynamic circuit มีอัตราข้อผิดพลาดสูงกว่าเนื่องจากการวัดกลางวงจรที่ใช้เวลานาน
4.5 บทสรุปสำคัญเกี่ยวกับการเทเลพอร์ตเทชันควอนตัม
เราสามารถส่งสถานะควอนตัมไปยังเพื่อนที่อยู่ห่างไกลได้โดยการแบ่งปันคู่ Qubit ที่ entangle กัน (e-bit)
-
การเทเลพอร์ตเทชันควอนตัมสามารถส่งสถานะควอนตัมได้เร็วกว่าแสงได้หรือไม่? ไม่ได้ เพราะ Alice ต้องบอก Bob เกี่ยวกับผลการวัดในแบบคลาสสิก
-
การเทเลพอร์ตเทชันควอนตัมจะละเมิด "ทฤษฎีบท no-cloning" ที่ห้ามการคัดลอกสถานะควอนตัมหรือไม่? ไม่ เพราะสถานะควอนตัมดั้งเดิมที่ให้กับ Alice บน Qubit หนึ่งของเธอสูญหายไปในการวัด มันยุบตัวเป็น หรือ
5. Superdense coding
การตั้งค่าเกือบเดียวกันสามารถใช้เพื่อจุดประสงค์ที่แตกต่างกัน สมมติว่า Alice ต้องการส่ง Bob ข้อมูลคลาสสิกสองบิต แต่เธอไม่มีช่องทางสื่อสารคลาสสิกกับ Bob อย่างไรก็ตาม เธอแบ่งปันคู่ entangled กับ Bob และได้รับอนุญาตให้ส่ง Qubit ของเธอไปยังตำแหน่งของ Bob สังเกตความแตกต่างกับโปรโตคอลการเทเลพอร์ตเทชันควอนตัม ในการเทเลพอร์ตเทชัน การสื่อสารคลาสสิก มีให้ กับเพื่อน ๆ และเป้าหมายคือการส่งสถานะควอนตัม ที่นี่ การสื่อสารคลาสสิกไม่มี และพวกเขาใช้การถ่ายโอน Qubit เพื่อแบ่งปันข้อมูลคลาสสิกสองบิต
5.1 โปรโตคอลของ superdense coding
สมมติฐาน: Alice มีข้อมูลสองบิต เช่น Alice และ Bob แบ่งปันคู่ entangled (e-bit) แต่พวกเขาไม่สามารถสื่อสารแบบคลาสสิกได้
- Alice ทำการดำเนินการหนึ่งในต่อไปนี้กับส่วน e-bit ของเธอ
- ถ้า , เธอไม่ทำอะไร
- ถ้า , เธอใช้ Z Gate
- ถ้า , เธอใช้ X Gate
- ถ้า , เธอใช้ Z Gate และ X Gate
- Alice ส่งส่วน e-bit ของเธอไปยังตำแหน่งของ Bob
- Bob ใช้ CNOT Gate โดยให้ Qubit จาก Alice เป็น control และ Qubit ของเขาเป็น target จากนั้นใช้ H Gate กับ Qubit จาก Alice แล้ววัด Qubit ทั้งสอง สถานะเริ่มต้นที่เป็นไปได้และผลลัพธ์จากการดำเนินการของ Bob คือ:
สังเกตว่าเครื่องหมายลบของ เป็น global phase ดังนั้นจึงวัดไม่ได้
5.2 Circuit ควอนตัมที่จำลอง superdense coding
ตามโปรโตคอลของ superdense coding คุณสามารถสร้าง Circuit superdense coding ได้ดังนี้ ลองเปลี่ยน msg ซึ่งเป็นข้อความที่ Alice ต้องการส่งไปยัง Bob
from qiskit import QuantumCircuit
ขั้นตอน Qiskit patterns ถูกระบุไว้ใน comments ของโค้ด
# 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")
# 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)
คุณจะเห็นว่า Bob ได้รับข้อความที่ Alice ต้องการส่งให้เขา
ต่อไป มาทดลองกับคอมพิวเตอร์ควอนตัมจริง
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)
# 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())
ผลลัพธ์เป็นไปตามที่คาดหวัง สังเกตว่า superdense coding บนคอมพิวเตอร์ควอนตัมจริงแสดงข้อผิดพลาดน้อยกว่าในกรณีการเทเลพอร์ตเทชันควอนตัมบนคอมพิวเตอร์ควอนตัมจริง เหตุผลหนึ่งอาจเป็นเพราะการเทเลพอร์ตเทชันควอนตัมใช้ dynamic circuit และ superdense coding ไม่ใช้ เราจะเรียนรู้เพิ่มเติมเกี่ยวกับข้อผิดพลาดใน Circuit ควอนตัมในบทเรียนต่อ ๆ ไป
6. สรุป
ในบทเรียนนี้ เราได้นำโปรโตคอลควอนตัมสองอย่างไปใช้ แม้ว่าสถานการณ์สำหรับทั้งสองที่เกี่ยวข้องกับเพื่อนที่อยู่ห่างไกลจะค่อนข้างห่างจากการคำนวณควอนตัมบน QPU เครื่องเดียว แต่มีการประยุกต์ใช้ในการคำนวณควอนตัม และช่วยให้เราเข้าใจการถ่ายโอนข้อมูลควอนตัมได้ดีขึ้น
- การเทเลพอร์ตเทชันควอนตัม: แม้เราไม่สามารถคัดลอกสถานะควอนตัมได้ เราสามารถ teleport สถานะควอนตัมที่ไม่ทราบค่าได้โดยมี entanglement ที่แบ่งปันกัน
- Quantum superdense coding: คู่ entangled ที่แบ่งปันกันและการถ่ายโอน Qubit หนึ่งอัน ทำให้สามารถสื่อสารข้อมูลคลาสสิกสองบิตได้
# See the version of Qiskit
import qiskit
qiskit.__version__
'2.0.2'