การแปลงฟูเรียเชิงควอนตัม
โมดูล Qiskit in Classrooms นี้ต้องการให้นักเรียนมี Python environment ที่ใช้งานได้พร้อมติดตั้งแพ็กเกจต่อไปนี้:
qiskitv2.1.0 หรือใหม่กว่าqiskit-ibm-runtimev0.40.1 หรือใหม่กว่าqiskit-aerv0.17.0 หรือใหม่กว่าqiskit.visualizationnumpypylatexenc
สำหรับการตั้งค่าและติดตั้งแพ็กเกจข้างต้น ดู คู่มือติดตั้ง Qiskit เพื่อรันงานบนคอมพิวเตอร์ควอนตัมจริง นักเรียนต้องสร้างบัญชี IBM Quantum® โดยทำตามขั้นตอนในคู่มือ ตั้งค่าบัญชี IBM Cloud
โมดูลนี้ผ่านการทดสอบและใช้เวลา QPU ไป 13 วินาที ตัวเลขนี้เป็นค่าประมาณ ปริมาณการใช้งานจริงของคุณอาจแตกต่างกัน
# Added by doQumentation — required packages for this notebook
!pip install -q 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'
บทนำ
การแปลง ฟูเรีย (Fourier transform) เป็นเครื่องมือที่ใช้กันทั่วไปมากในคณิตศาสตร์ ฟิสิกส์ การประมวลผลสัญญาณ การบีบอัดข้อมูล และสาขาอื่นๆ อีกมากมาย การแปลงฟูเรียเชิงควอนตัม ที่ตั้งชื่อได้ตรงไปตรงมา เป็นพื้นฐานของอัลกอริทึมควอนตัมที่สำคัญที่สุดบางตัว
วันนี้ หลังจากทบทวนการแปลงฟูเรียแบบคลาสสิก เราจะพูดถึงวิธีที่เรานำการแปลงฟูเรียเชิงควอนตัมไปใช้บนคอมพิวเตอร์ควอนตัม จากนั้นเราจะหารืออยู่กับหนึ่งในการประยุกต์ใช้การแปลงฟูเรียเชิงควอนตัมกับอัลกอริทึมที่เรียกว่า phase estimation algorithm การประมาณเฟสเชิงควอนตัมเป็นซับรูทีนในอัลกอริทึมการแยกตัวประกอบที่มีชื่อเสียงของ Shor ซึ่งบางครั้งเรียกว่า "มงกุฎแก้วของการประมวลผลเชิงควอนตัม" โมดูลนี้ก้าวไปสู่โมดูลอีกตัวเกี่ยวกับอัลกอริทึมของ Shor แต่ยังออกแบบให้ยืนหยัดได้ด้วยตัวเอง การแปลงฟูเรียเชิงควอนตัมเป็นอัลกอริทึมที่น่าสนใจและมีประโยชน์ในตัวมันเอง!
การแปลงฟูเรียแบบคลาสสิก
ก่อนที่เราจะก้าวเข้าสู่การแปลงฟูเรียเชิงควอนตัม มาทบทวนเวอร์ชันแบบคลาสสิกก่อน การแปลงฟูเรียเป็นวิธีการแปลงจาก "ฐาน" หนึ่งไปยังอีกฐานหนึ่ง คุณสามารถคิดสองฐานเป็นมุมมองที่ต่างกันของปัญหาเดียวกัน ทั้งคู่เป็นวิธีที่ถูกต้องในการแสดงฟังก์ชัน แต่อย่างใดอย่างหนึ่งอาจให้ข้อมูลเชิงลึกมากกว่าขึ้นอยู่กับปัญหาที่มี ตัวอย่างของคู่ฐานที่เชื่อมต่อด้วยการแปลงฟูเรีย ได้แก่ ตำแหน่งและโมเมนตัม และเวลาและความถี่
มาดูตัวอย่างว่าการแปลงฟูเรียอาจช่วยให้เราหาว่าเครื่องดนตรีกำลังเล่นโน ้ตใดโดยพิจารณาจาก waveform เสียง โดยทั่วไป เราเห็น waveform ที่แสดงในฐานเวลา นั่นคือ แอมพลิจูดของคลื่นแสดงเป็นฟังก์ชันของเวลา

เราสามารถแปลงฟูเรีย waveform นี้เพื่อไปจากฐานเวลาสู่ฐานความถี่:

ในฐานความถี่ เราสามารถเห็นยอดแหลมชัดเจนที่ประมาณ 260 Hz นั่นคือโน้ต C กลาง!
ตอนนี้ คุณอาจจะสามารถระบุได้ว่ากำลังเล่น C กลางโดยไม่ต้องใช้การแปลงฟูเรีย แต่ถ้าเล่นหลายโน้ตพร้อมกันล่ะ? waveform จะซับซ้อนขึ้นเมื่อเราพล็อตในฐานเวลา:

แต่สเปกตรัมความถี่ระบุยอดแหลมสามยอดอย่างชัดเจน:

นี่เป็นคอร์ด C major กำลังเล่นโน้ต C, E และ G
การวิเคราะห์ฟูเรียประเภทนี้สามารถช่วยให้เราดึงองค์ประกอบความถี่ของสัญญาณที่ซับซ้อนประเภทใดก็ได้
การแปลงฟูเรียแบบไม่ต่อเนื่อง
การแปลงฟูเรียมีประโยชน์สำหรับการประยุกต์ใช้การประมวลผลสัญญาณมากมาย แต่ในการประยุกต์ใช้งานจริงส่วนใหญ่ (รวมถึงตัวอย่างเพลงที่เราใช้ด้านบน) เราต้ องการแปลงชุดข้อมูล จุดแบบไม่ต่อเนื่อง ไม่ใช่ฟังก์ชันต่อเนื่อง ในกรณีนี้ เราใช้ การแปลงฟูเรียแบบไม่ต่อเนื่อง (DFT) DFT กระทำบน vector และแมปไปยัง vector ตามสูตร:
โดยที่เรานิยาม (สังเกตว่ามี convention อื่นที่มีเครื่องหมายลบในเลขชี้กำลัง ดังนั้นควรระวังเมื่อเห็น DFT ในที่อื่น) จำว่า เป็นฟังก์ชันคาบ ด้วยคาบ ดังนั้น โดยการคูณด้วยฟังก์ชันนี้ การแปลงฟูเรียจึงเป็นวิธีแยก (แบบไม่ต่อเนื่อง) ฟังก์ชัน ออกเป็นการรวมเชิงเส้นของฟังก์ชันคาบที่ประกอบขึ้น โดยแต่ละตัวมีคาบ
การแปลงฟูเรียเชิงควอนตัม
ตอนนี้ เราเห็นแล้วว่าการแปลงฟูเรียถูกใช้เพื่อแสดงฟังก์ชันเป็นการรวมเชิงเส้นของ ชุด "ฟังก์ชันฐาน" ใหม่ การแปลงฐานถูกทำกับสถานะ Qubit เป็นประจำเช่นกัน ตัวอย่างเช่น สถานะของ Qubit เดี่ยว สามารถแสดงในฐาน computational พร้อมสถานะฐาน และ หรือในฐาน พร้อมสถานะฐาน และ ทั้งสองถูกต้องเท่าเทียมกัน แต่อย่างใดอย่างหนึ่งอาจเป็นธรรมชาติกว่าขึ้นอยู่กับประเภทของปัญหาที่พยายามแก้
สถานะ Qubit ยังสามารถแสดงในฐานฟูเรียที่สถานะแสดงในรูปของการรวมเชิงเส้นของสถานะฐานฟูเรีย แทนสถานะฐาน computational ปกติ ในการทำเช่นนี้ คุณต้องนำการแปลงฟูเรียเชิงควอนตัม (QFT) ไปใช้:
โดยที่ ดังที่กล่าวข้างต้น และ คือจำนวนสถานะฐานในระบบควอนตัมของคุณ สังเกตว่าเนื่องจากตอนนี้เราทำงานกับ Qubit Qubit ให้ สถานะฐาน ดังนั้ น ที่นี่ สถานะฐานเขียนเป็นตัวเลขเดี่ยว โดยที่ มีค่าตั้งแต่ ถึง แต่โดยทั่วไปคุณอาจเห็นสถานะฐานแสดงเป็น , , , ..., โดยแต่ละหลักไบนารีแสดงสถานะของ Qubit 0 ถึง จากขวาไปซ้าย มีวิธีง่ายๆ ในการแปลงสถานะไบนารีเหล่านี้เป็นตัวเลขเดี่ยว: แค่ถือว่ามันเป็นเลขฐานสอง! ดังนั้น , , , และต่อเนื่องไปจนถึง
สร้างสัญชาตญาณสำหรับสถานะฐานฟูเรีย
ดังนั้น เพิ่งอธิบายไปแล้วว่าสถานะฐาน computational คืออะไรและเรียงลำดับอย่างไร: พวกมันคือชุดของสถานะที่แต่ละ Qubit อยู่ใน 0 หรือ 1 และเราเรียงลำดับจากสถานะที่ Qubit ทั้งหมดเป็น 0 ถึงสถานะที่ทั้งหมดเป็น 1
แต่เราจะเข้าใจสถานะฐาน ฟูเรีย ได้อย่างไร? สถานะฐานฟูเรียทั้งหมดเป็นซูเปอร์โพสิชันที่เท่ากันของสถานะฐาน computational ทั้งหมด แต่แต่ละสถานะต่างกันจากอื่นในความเป็นคาบของ เฟส ของส่วนประกอบ เพื่อทำความเข้าใจสิ่งนี้มากขึ้น มาดูสถานะฐานฟูเรียสี่ตัวของระบบสอง Qubit กัน สถานะฟูเรียต่ำสุดคือสถานะที่เฟสไม่เปลี่ยนแปลงเลย:
เราสามารถแสดงสถานะนี้โดยการพล็อตแอมพลิจูดเชิงซ้อนของแต่ละเทอม เส้นสีแดงช่วยให้เห็นว่าเฟสของแอมพลิจูดนี้วนรอบระนาบเชิงซ้อนอย่างไรในฐานะฟังก์ชันของสถานะฐาน computational สำหรับ เฟสคงที่:

สถานะฐานฟูเรียถัดไปคือสถานะที่เฟสของส่วนประกอบวนรอบจาก ถึง เพีย งครั้งเดียว:
และเราสามารถเห็นการวนนี้ในกราฟแอมพลิจูดเชิงซ้อนเทียบสถานะฐาน computational:

ดังนั้น แต่ละสถานะมีเฟสที่สูงกว่าสถานะก่อนหน้า เรเดียน เมื่อเรียงลำดับตามปกติ เนื่องจากในตัวอย่างนี้เรามีสี่สถานะฐาน () สถานะฐานถัดไปวนรอบจาก 0 ถึง สองครั้ง:

สุดท้าย องค์ประกอบฟูเรียสูงสุดคือสถานะที่มีเฟสแปรผันเร็วที่สุด สำหรับตัวอย่างสอง Qubit ของเรา มันคือสถานะที่เฟสวนรอบจาก 0 ถึง สามครั้ง:

โดยทั่วไป สำหรับสถานะ -Qubit จะมีสถานะฐานฟูเรีย ตัว ซึ่งความถี่ในการแปรผันของเฟสมีช่วงตั้งแต่คงที่สำหรับ ถึงแปรผันรวดเร็วสำหรับ โดยวนครบ รอบรอบ ตลอดซูเปอร์โพสิชันของสถานะ ดังนั้น เมื่อเรา QFT สถานะควอนตัม เราก็กำลังทำการวิเคราะห์พื้นฐานเดียวกับที่เราทำสำหรับ waveform เพลงในบทนำ เราระบุองค์ประกอบความถี่ฟูเรียที่มีส่วนในการสร้างสถานะควอนตัมที่สนใจ
ลอง QFT ตัวอย่าง
มาลองสร้างสัญชาตญาณสำหรับการแปลงฟูเรียเชิงควอนตัมต่อไปโดยสร้างสถานะในฐาน computational แล้วดูว ่าเกิดอะไรขึ้นเมื่อเรานำ QFT ไปใช้กับมัน สำหรับตอนนี้ เราจะถือว่า QFT เป็นกล่องดำที่เรานำมาใช้โดยใช้ QFTGate จาก ไลบรารี Circuit ของ Qiskit ในภายหลัง เราจะดูภายในเพื่อดูวิธีที่มันถูกใช้งาน
เราเริ่มต้นด้วยการโหลดแพ็กเกจที่จำเป็นและเลือกอุปกรณ์สำหรับรัน Circuit:
import numpy as np
from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram
from qiskit.circuit.library import QFTGate
# Load the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService
# Load the Runtime primitive and session
from qiskit_ibm_runtime import SamplerV2 as Sampler
service = QiskitRuntimeService()
# Use the least busy backend
# backend = service.least_busy(operational=True, simulator=False, min_num_qubits = 127)
backend = service.backend("ibm_pinguino2")
print(backend.name)
ibm_pinguino2
หากคุณไม่มีเวลาที่พร้อมใช้งานในบัญชีหรือต้องการใช้ simulator ด้วยเหตุผลใดก็ตาม คุณสามารถรันเซลล์ด้านล่างเพื่อตั้งค่า simulator ที่จำลองอุปกรณ์ควอนตัมที่เราเลือกด้านบน:
# Load the backend sampler
from qiskit.primitives import BackendSamplerV2
# Load the Aer simulator and generate a noise model based on the currently-selected backend.
from qiskit_aer import AerSimulator
from qiskit_aer.noise import NoiseModel
noise_model = NoiseModel.from_backend(backend)
# Define a simulator using Aer, and use it in Sampler.
backend_sim = AerSimulator(noise_model=noise_model)
sampler_sim = BackendSamplerV2(backend=backend_sim)
# Alternatively, load a fake backend with generic properties and define a simulator.
from qiskit.providers.fake_provider import GenericBackendV2
backend_gen = GenericBackendV2(num_qubits=18)
sampler_gen = BackendSamplerV2(backend=backend_gen)
สถานะฐาน computational เดี่ยว
ก่อนอื่น มาลองแปลงสถานะฐาน computational เดี่ยว เราจะเริ่มด้วยการสร้างสถานะ computational แบบสุ่ม:
# Step 1: Map
qubits = 4
N = 2**qubits
qc = QuantumCircuit(qubits)
# flip state of random qubits to put in a random single computational basis state
for i in range(1, qubits):
if np.random.randint(0, 2):
qc.x(i)
# make a copy of the above circuit. (to be used when we apply the QFT in next part)
qc_qft = qc.copy()
qc.measure_all()
qc.draw("mpl")
# 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)
# Step 3: Run the job on a real quantum computer OR try fake backend
sampler = Sampler(mode=backend)
pubs = [qc_isa]
# Run the job on real quantum device
job = sampler.run(pubs, shots=1000)
res = job.result()
counts = res[0].data.meas.get_counts()
# OR Run the job on the Aer simulator with noise model from real backend
# job = sampler_sim.run([qc_isa])
# res = job.result()
# counts = res[0].data.meas.get_counts()
# Step 4: Post-Process
plot_histogram(counts)
ตอนนี้ มา Fourier transform สถานะนี้ด้วย QFTGate:
# Step 1: Map
qc_qft.compose(QFTGate(qubits), inplace=True)
qc_qft.measure_all()
qc_qft.draw("mpl")
# 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_qft)
# Step 3: Run the job on a real quantum computer - try fake backend
sampler = Sampler(mode=backend)
pubs = [qc_isa]
# Run the job on real quantum device
job = sampler.run(pubs, shots=1000)
res = job.result()
counts = res[0].data.meas.get_counts()
# OR Run the job on the Aer simulator with noise model from real backend
# job = sampler_sim.run([qc_isa])
# res = job.result()
# counts = res[0].data.meas.get_counts()
# Step 4: Post-Process
plot_histogram(counts)
จะเห็นว่าเราวัดจำนวนประชากรของแต่ละสถานะให้มากหรือน้อยเท่ากัน โดยคำนึงถึง noise ในการทดลองและสถิติ ดังนั้น หากคุณนำ QFT ไปใช้กับสถานะฐาน computational เดี่ยว ผลลัพธ์คือซูเปอร์โพสิชันที่เท่ากันของสถานะทั้งหมด หากคุณคุ้นเคยกับการแปลงฟูเรีย สิ่งนี้น่าจะไม่น่าแปลกใจ หลักการพื้นฐานอย่างหนึ่งที่ช่วยให้เราสร้างการเชื่อมต่อเชิงสัญชาตญาณระหว่างฟังก์ชันและการแปลงฟูเรียคือความกว้างของฟังก์ชันแปรผกผันกับความกว้างของการแปลงฟูเรีย ดังนั้น สิ่งที่แปลมากในเวลา เช่น pulse สั้นมาก จะต้องใช้ช่วงความถี่กว้างในการสร้าง pulse นั้น สัญญาณนั้นจะกว้างมากใน Fourier space
ข้อเท็จจริงนี้จริงๆ แล้วเกี่ยวข้องกับความไม่แน่นอนเชิงควอนตัม! หลักความไม่แน่นอนของ Heisenberg มักระบุเป็น ดังนั้นหากความไม่แน่นอนใน () มีขนาดเล็ก ความไม่แน่นอนในโมเมนตัม () ต้องมีขนาดใหญ่ และในทางกลับกัน ปรากฏว่าการแปลงจากฐานตำแหน่ง ไปยังฐานโมเมนตัม ทำโดยการแปลงฟูเรีย
หมายเหตุ: โปรดจำไว้ว่าเรากำลังวัดประชากรในแต่ละสถานะฐาน ดังนั้นเราสูญเสียข้อมูลเกี่ยวกับเฟสสัมพัทธ์ระหว่างส่วนต่างๆ ของซูเปอร์โพสิชัน ดังนั้น ขณะที่ QFT ของสถานะฐาน computational เดี่ยวจะให้การกระจายประชากรสม่ำเสมอกว่าสถานะฐานทั้งหมดเช่นกัน เฟส จะไม่จำเป็นต้องเหมือนกัน
สถานะฐาน computational สอง
ตอนนี้ มาดูกันว่าเกิดอะไรขึ้นเมื่อเราเตรียมซูเปอร์โพสิชันของสถานะฐาน computational คุณคิดว่าการแปลงฟูเรียจะมีลักษณะอย่างไรในกรณีนี้?
มาเลือกซูเปอร์โพสิชัน:
# Step 1: Map
qubits = 4
N = 2**qubits
qc = QuantumCircuit(qubits)
# To make this state, we just need to apply a Hadamard to the last qubit
qc.h(qubits - 1)
qc_qft = qc.copy()
qc.measure_all()
qc.draw("mpl")
# First, let's go through steps 2-4 for the first circuit, qc
# 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)
# Step 3: Run the job on a real quantum computer - try fake backend
sampler = Sampler(mode=backend)
pubs = [qc_isa]
# Run the job on real quantum device
job = sampler.run(pubs, shots=1000)
res = job.result()
counts = res[0].data.meas.get_counts()
# OR run the job on the Aer simulator with noise model from real backend
# job = sampler_sim.run([qc_isa])
# res = job.result()
# counts = res[0].data.meas.get_counts()
# Step 4: Post-process
plot_histogram(counts)
ตอนนี้ มา Fourier transform สถานะนี้ด้วย QFTGate:
# Step 1: Map
qc_qft.compose(QFTGate(qubits), inplace=True)
qc_qft.measure_all()
qc_qft.draw("mpl")
# 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_qft)
# Step 3: Run the job on a real quantum computer OR try fake backend
sampler = Sampler(mode=backend)
pubs = [qc_isa]
# Run the job on real quantum device
job = sampler.run(pubs, shots=1000)
res = job.result()
counts = res[0].data.meas.get_counts()
# OR run the job on the Aer simulator with noise model from real backend
# job = sampler_sim.run([qc_isa])
# res = job.result()
# counts = res[0].data.meas.get_counts()
# Step 4: Post-process
plot_histogram(counts)
สิ่งนี้อาจน่าแปลกใจเล็กน้อย ดูเหมือนว่า QFT ของสถานะ เป็นซูเปอร์โพสิชันของสถาน ะฐานที่เป็นจำนวนคู่ทั้งหมด แต่ถ้าเราคิดถึงการแสดงภาพสถานะฐานแต่ละตัว และวิธีที่เฟสของแต่ละส่วนประกอบวนรอบ ครั้ง เหตุผลที่เราได้ผลลัพธ์นี้อาจชัดเจนขึ้น
ทดสอบความเข้าใจ
อ่านคำถามด้านล่าง คิดหาคำตอบ แล้วคลิกสามเหลี่ยมเพื่อดูเฉลย
ใช้คำใบ้ด้านบน อธิบายว่าทำไมผลลัพธ์ที่ได้สำหรับ QFT ของ จึงเป็นที่คาดหวัง
คำตอบ:
สถานะเดิมมีเฟสสัมพัทธ์ 0 (หรือจำนวนเต็มคูณของ ) ระหว่างสองส่วนของซูเปอร์โพสิชัน ดังนั้น เราทราบว่าสถานะนี้มีองค์ประกอบฟูเรียที่เฟสก็ตรงกันในแบบนั้นด้วย: สถานะที่มีเฟส shift 0 ระหว่างเทอม |0000> และเทอม |1000> สถานะฐานฟูเรียแต่ละตัว ประกอบด้วยเทอมที่เฟสสะสมในอัตรา หมายความว่า เมื่อเรียงลำดับตามปกติ แต่ละเทอมในซูเปอร์โพสิชันมีเฟสสูงกว่าเทอมก่อนหน้า ดังนั้น ที่จุดกึ่งกลาง เราต้องการให้เฟส เป็นจำนวนเต็มคูณของ ซึ่งเกิดขึ้นเมื่อ เป็นจำนวนคู่
ซูเปอร์โพสิชันของสถานะ computational ใดที่จะตรงกับ QFT ที่มียอดแหลมบนทุกจำนวนไบนารีคี่?
คำตอบ:
ถ้าคุณนำ QFT ไปใช้กับสถานะ คุณจะเห็นยอดแหลมบนสถานะที่มีหมายเลขไบนารีคี่ทุกตัว