การใช้งาน Qiskit
ในส่วนนี้ เราจะดูการใช้งาน Qiskit บางส่วนของแนวคิดที่แนะนำในบทเรียนนี้ ถ้าต้องการรันการใช้งานเหล่านี้เอง ซึ่งแนะนำอย่างยิ่ง ให้ดูหน้า Install Qiskit ใน IBM Quantum Documentation สำหรับรายละเอียดวิธีตั้งค่า Qiskit
ควรเข้าใจว่า Qiskit อยู่ภายใต้การพัฒนาอย่างต่อเนื่อง และมุ่งเน้นหลักในการเพิ่มประสิทธิภาพของคอมพิวเตอร์ควอนตัมที่ใช้งาน ซึ่งตัวคอมพิวเตอร์เองก็ยังคงพัฒนาต่อไป ด้วยเหตุนี้ Qiskit จึงอาจมีการเปลี่ยนแปลงที่อาจทำให้โค้ดล้าสมัยได้เป็นครั้งคราว โดยคำนึงถึงสิ่งนี้ เราจะรันคำสั่งต่อไปนี้เสมอก่อนนำเสนอตัวอย่างโค้ด Qiskit ในคอร์สนี้ เพื่อให้ชัดเจนว่าใช้ Qiskit เวอร์ชันใด เริ่มต้นจาก Qiskit v1.0 นี่เป็นวิธีง่ายๆ ในการดูว่าติดตั้ง Qiskit เวอร์ชันใดอยู่ในปัจจุบัน
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit
from qiskit import __version__
print(__version__)
2.2.3
ถ้ารันสิ่งนี้ในสภาพแวดล้อม Python บนคลาวด์ อาจต้องติดตั้งแพ็คเกจต่อไปนี้บางส่วน:
#!pip install qiskit
#!pip install jupyter
#!pip install sympy
#!pip install matplotlib
#!pip install pylatexenc
เวกเตอร์และเมทริกซ์ใน Python
Qiskit ใช้ภาษาโปรแกรม Python ดังนั้นก่อนที่จะพูดถึง Qiskit โดยเฉพาะ อาจเป็นประโยชน์ที่จะพูดถึงการคำนวณเมทริกซ์และเวกเตอร์ใน Python สั้นๆ
ใน Python การคำนวณเมทริกซ์และเวกเตอร์สามารถทำได้โดยใช้คลาส array จากไลบรารี NumPy ซึ่งมีฟังก์ชันสำหรับการคำนวณเชิงตัวเลขและวิทยาศาสตร์หลายอย่าง
โค้ดต่อไปนี้โหลดไลบรารีนี้ กำหนดเวกเตอร์คอลัมน์สองอัน ket0 และ ket1 ที่สอดคล้องกับเวกเตอร์สถานะ Qubit และ แล้วพิมพ์ค่าเฉลี่ยของพวกมัน
import numpy as np
ket0 = np.array([[1], [0]])
ket1 = np.array([[0], [1]])
print(ket0 / 2 + ket1 / 2)
[[0.5]
[0.5]]
เราสามารถใช้ array เพื่อสร้างเมทริกซ์ที่แทนการดำเนินการได้ด้วย
M1 = np.array([[1, 1], [0, 0]])
M2 = np.array([[1, 0], [0, 1]])
M = M1 / 2 + M2 / 2
print(M)
[[1. 0.5]
[0. 0.5]]
โปรดทราบว่าโค้ดทั้งหมดที่ปรากฏในบทเรียนที่กำหนดในคอร์สนี้คาดว่าจะรันตามลำดับ
ดังนั้น เราไม่จำเป็นต้องนำเข้า NumPy อีกที่นี่ เพราะนำเข้าแล้ว
การคูณเมทริกซ์ รวมถึงการคูณเมทริกซ์-เวกเตอร์เป็นกรณีพิเศษ สามารถทำได้โดยใช้ฟังก์ชัน matmul จาก NumPy
print(M1 @ ket1)
print(M1 @ M2)
print(M @ M)
[[1]
[0]]
[[1 1]
[0 0]]
[[1. 0.75]
[0. 0.25]]
รูปแบบ output นี้ยังมีข้อบกพร่องในแง่ภาพ
ทางออกหนึ่ง สำหรับสถานการณ์ที่ต้องการความสวยงามมากกว่า คือใช้ฟังก์ชัน array_to_latex ใน Qiskit จากโมดูล qiskit.visualization
สังเกตว่าในโค้ดที่ตามมา เราใช้ฟังก์ชัน display ทั่วไปของ Python
ในทางตรงกันข้าม พฤติกรรมเฉพาะของ print อาจขึ้นอยู่กับสิ่งที่พิมพ์ เช่น เป็นกรณีของ array ที่กำหนดโดย NumPy
from qiskit.visualization import array_to_latex
display(array_to_latex(M1 @ ket1))
display(array_to_latex(M1 @ M2))
display(array_to_latex(M @ M))
สถานะ การวัด และการดำเนินการ
Qiskit รวมคลาสหลายอย่างที่ช่วยให้สร้างและจัดการสถานะ การวัด และการดำเนินการได้ — ดังนั้นไม่จำเป็นต้องเขียนโปรแกรมทุกอย่างที่จำเป็นสำหรับการจำลองสถานะ การวัด และการดำเนินการเชิงควอนตัมใน Python เอง ตัวอย่างเพื่อช่วยให้เริ่มต้นได้มีด้านล่าง
กำหนดและแสดงเวกเตอร์สถานะ
คลาส Statevector ใน Qiskit ให้ฟังก์ชันสำหรับการกำหนดและจัดการเวกเตอร์สถานะควอนตัม
ในโค้ดที่ตามมา คลาส Statevector ถูกนำเข้าและกำหนดเวกเตอร์ไม่กี่อัน
(เราก็นำเข้าฟังก์ชัน sqrt จากไลบรารี NumPy เพื่อคำนวณรากที่สองด้วย
ฟังก์ชันนี้สามารถเรียกใช้เป็น np.sqrt ได้เช่นกัน หาก NumPy ถูกนำเข้าแล้วดังเช่นด้านบน นี่เป็นเพียงวิธีที่แตกต่างในการนำเข้าและใช้ฟังก์ชันเฉพาะนี้)
from qiskit.quantum_info import Statevector
from numpy import sqrt
u = Statevector([1 / sqrt(2), 1 / sqrt(2)])
v = Statevector([(1 + 2.0j) / 3, -2 / 3])
w = Statevector([1 / 3, 2 / 3])
คลาส Statevector มีเมธอด draw สำหรับแสดงเวกเตอร์สถานะในหลายวิธี รวมถึง
text สำหรับข้อความธรรมดา latex สำหรับ LaTeX ที่ render แล้ว และ latex_source สำหรับโค้ด LaTeX ซึ่งสะดวกสำหรับการตัดและวางลงในเอกสาร
(ใช้ print แทน display เพื่อแสดงโค้ด LaTeX ให้ได้ผลลัพธ์ที่ดีที่สุด)
display(u.draw("text"))
display(u.draw("latex"))
print(u.draw("latex_source"))
[0.70710678+0.j,0.70710678+0.j]
\frac{\sqrt{2}}{2} |0\rangle+\frac{\sqrt{2}}{2} |1\rangle
คลาส Statevector ยังมีเมธอด is_valid ซึ่งตรวจสอบว่าเวกเตอร์ที่กำหนดเป็นเวกเตอร์สถานะควอนตัมที่ถูกต้องหรือไม่ (กล่าวคือมี Euclidean norm เท่ากับ 1):
display(u.is_valid())
display(w.is_valid())
True
False
การจำลองการวัดโดยใช้ Statevector
ต่อไปเราจะเห็นวิธีหนึ่งที่การวัดสถานะควอนตัมสามารถจำลองได้ใน Qiskit โดยใช้เมธอด measure จากคลาส Statevector
มาใช้เวกเตอร์สถานะ Qubit v เดิมที่กำหนดไว้ก่อนหน้า
display(v.draw("latex"))
การรันเมธอด measure จำลองการวัดฐานมาตรฐาน
มันคืนผลลัพธ์ของการวัดนั้น รวมถึงเวกเตอร์สถานะควอนตัมใหม่ของระบบหลังการวัด
(ที่นี่เราใช้ฟังก์ชัน print ของ Python ที่มีคำนำหน้า f สำหรับการพิมพ์แบบจัดรูปแบบพร้อมนิพจน์ที่ฝังอยู่)
outcome, state = v.measure()
print(f"Measured: {outcome}\nPost-measurement state:")
display(state.draw("latex"))
Measured: 1
Post-measurement state:
ผลลัพธ์การวัดเป็นแบบความน่าจะเป็น ดังนั้นเมธอดนี้สามารถคืนผลลัพธ์ที่แตกต่างกันเมื่อรันหลายครั้ง
สำหรับตัวอย่างเฉพาะของเวกเตอร์ v ที่กำหนดไว้ด้านบน เมธอด measure กำหนดเวกเตอร์สถานะควอนตัมหลังการวัดเป็น
(แทนที่จะเป็น ) หรือ
(แทนที่จะเป็น ) ขึ้นอยู่กับผลการวัด ในทั้งสองกรณี ทางเลือกแทน และ นั้น ที่จริงแล้วเทียบเท่ากับเวกเตอร์สถานะเหล่านี้ พวกมันถูกกล่าวว่า เทียบเท่าจนถึง global phase เพราะอันหนึ่งเท่ากับอีกอันคูณด้วยจำนวนเชิงซ้อนบนวงกลมหน่วย ประเด็นนี้ถูกกล่าวถึงในรายละเอียดเพิ่มเติมในบทเรียน Quantum circuits และสามารถละเลยได้ก่อนในตอนนี้
Statevector จะโยน error หากใช้เมธอด measure กับเวกเตอร์สถานะควอนตัมที่ไม่ถูกต้อง
Statevector ยังมีเมธอด sample_counts ที่ช่วยให้จำลองการวัดจำนวนใดก็ได้บนระบบ โดยแต่ละครั้งเริ่มต้นด้วยสำเนาใหม่ของสถานะ ตัวอย่างเช่น โค้ดต่อไปนี้แสดงผลลัพธ์ของการวัดเวกเตอร์ v ครั้ง ซึ่ง (ด้วยความน่าจะเป็นสูง) ส่งผลให้ผลลัพธ์ ประมาณ ใน ครั้ง (หรือประมาณ จาก ครั้ง) และผลลัพธ์ ประมาณ ใน ครั้ง (หรือประมาณ จาก ครั้ง)
โค้ดที่ตามมายังแสดงฟังก์ชัน plot_histogram จากโมดูล qiskit.visualization สำหรับการแสดงผลลัพธ์
from qiskit.visualization import plot_histogram
statistics = v.sample_counts(1000)
plot_histogram(statistics)
การรันโค้ดนี้หลายครั้งด้วยตัวเอง โดยใช้จำนวนตัวอย่างต่างๆ แทน อาจช่วยสร้างสัญชาตญาณว่าจำนวนครั้งส่งผลต่อจำนวนครั้งที่ผลลัพธ์แต่ละอย่างปรากฏอย่างไร ยิ่งมีตัวอย่างมากขึ้นเรื่อยๆ สัดส่วนของตัวอย่างสำหรับแต่ละความเป็นไปได้น่าจะใกล้เคียงกับความน่าจะเป็นที่สอดคล้องกันมากขึ้นเรื่อยๆ ปรากฏการณ์นี้ โดยทั่วไปแล้ว เรียกว่า กฎของจำนวนมาก ในทฤษฎีความน่าจะเป็น
ทำการดำเนินการด้วย Operator และ Statevector
การดำเนินการ unitary สามารถกำหนดใน Qiskit โดยใช้คลาส Operator ดังในตัวอย่างที่ตามมา
คลาสนี้มีเมธอด draw ที่มี argument คล้ายกับ Statevector
สังเกตว่าตัวเลือก latex ให้ผลลัพธ์ที่เทียบเท่ากับ array_from_latex
from qiskit.quantum_info import Operator
Y = Operator([[0, -1.0j], [1.0j, 0]])
H = Operator([[1 / sqrt(2), 1 / sqrt(2)], [1 / sqrt(2), -1 / sqrt(2)]])
S = Operator([[1, 0], [0, 1.0j]])
T = Operator([[1, 0], [0, (1 + 1.0j) / sqrt(2)]])
display(T.draw("latex"))
เราสามารถใช้การดำเนินการ unitary กับเวกเตอร์สถานะโดยใช้เมธอด evolve
v = Statevector([1, 0])
v = v.evolve(H)
v = v.evolve(T)
v = v.evolve(H)
v = v.evolve(S)
v = v.evolve(Y)
display(v.draw("latex"))
ตัวอย่างเบื้องต้นของ Circuit ควอนตัม
Circuit ควอนตัมจะไม่ถูกแนะนำอย่างเป็นทางการจนถึงบทเรียน Quantum circuits ซึ่งเป็นบทเรียนที่สามในคอร์สนี้ แต่เราสามารถทดลองการเรียงลำดับการดำเนินการ unitary ของ Qubit โดยใช้คลาส QuantumCircuit ใน Qiskit ได้
โดยเฉพาะอย่างยิ่ง เราอาจกำหนด Circuit ควอนตัม (ซึ่งในกรณีนี้จะเป็นเพียงลำดับของการดำเนินการ unitary บน Qubit เดี่ยว) ดังนี้
from qiskit import QuantumCircuit
circuit = QuantumCircuit(1)
circuit.h(0)
circuit.t(0)
circuit.h(0)
circuit.s(0)
circuit.y(0)
display(circuit.draw(output="mpl"))
ที่นี่เราใช้เมธอด draw จากคลาส QuantumCircuit กับ renderer mpl (ย่อมาจาก Matplotlib ไลบรารีการแสดงผลของ Python)
นี่เป็น renderer เดียวที่เราจะใช้สำหรับ Circuit ควอนตัมในคอร์สนี้ แต่มีตัวเลือกอื่นรวมถึง renderer แบบข้อความและ LaTeX
การดำเนินการถูกใช้ตามลำดับ เริ่มจากซ้ายและสิ้นสุดที่ขวาในแผนภาพ
วิธีที่สะดวกในการได้เมทริกซ์ unitary ที่สอดคล้องกับ Circuit นี้คือใช้เมธอด from_circuit จากคลาส Operator
display(Operator.from_circuit(circuit).draw("latex"))
เราสามารถเริ่มต้นเวกเตอร์สถานะควอนตัมเริ่มต้นแล้ว evolve สถานะนั้นตามลำดับการดำเนินการที่อธิบายโดย Circuit ได้ด้วย
ket0 = Statevector([1, 0])
v = ket0.evolve(circuit)
display(v.draw("latex"))
โค้ดต่อไปนี้จำลองการทดลองที่สถานะที่ได้จาก Circuit ด้านบนถูกวัดด้วยการวัดฐานมาตรฐาน 4000 ครั้ง (โดยใช้สำเนาใหม่ของสถานะแต่ละครั้ง)
statistics = v.sample_counts(4000)
display(plot_histogram(statistics))