Квантові алгоритми: Оцінка фази
Kento Ueda (15 травня 2024)
Цей ноутбук містить основні концепції та реалізацію Квантового перетворення Фур'є (QFT) і Квантової оцінки фази (QPE).
Завантажити PDF оригінальної лекції. Зверни увагу, що деякі фрагменти коду можуть застаріти, оскільки це статичні зображення.
Приблизний час QPU для виконання цього експерименту становить 7 секунд.
1. Вступ
Квантове перетворення Фур'є (QFT)
Квантове перетворення Фур'є є квантовим аналогом класичного дискретного перетворення Фур'є. Це лінійне перетворення, застосоване до квантових станів, яке відображає обчислювальні базиси в їхні представлення у базисі Фур'є. QFT відіграє ключову роль у багатьох квантових алгоритмах, пропонуючи ефективний метод отримання інформації про periodичність із квантових станів. QFT можна реалізувати за допомогою операцій з квантовими Gate, такими як Gate Адамара та вентиль керованої фази для кубітів, що забезпечує експоненційне прискорення порівняно з класичним перетворенням Фур'є.
- Застосування: Він є фундаментальною складовою квантових алгоритмів, таких як алгоритм Шора для факторизації великих цілих чисел і дискретного логарифму.
Квантова оцінка фази (QPE)
Квантова оцінка фази — це квантовий алгоритм, що використовується для оцінки фази, пов'язаної з власним вектором унітарного оператора. Цей алгоритм є містком між абстрактними математичними властивостями квантових станів та їхніми обчислювальними застосуваннями.
- Застосування: Він може розв'язувати задачі на кшталт пошуку власних значень унітарних матриць та симуляції квантових систем.
Разом QFT і QPE формують основу багатьох квантових алгоритмів, що вирішують задачі, непосильні для класичних комп'ютерів. Після завершення цього ноутбука ти отримаєш розуміння того, як реалізуються ці техніки.
2. Основи Квантового перетворення Фур'є (QFT)
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer qiskit-ibm-runtime
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit_aer import AerSimulator
from qiskit.visualization import plot_histogram, plot_bloch_multivector
from qiskit.quantum_info import Statevector
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import Sampler
from numpy import pi
За аналогією з дискретним перетворенням Фур'є, QFT діє на квантовий стан для кубітів і відображає його в квантовий стан .
де .
Або у вигляді унітарної матриці:
2.1. Інтуїція
Квантове перетворення Фур'є (QFT) здійснює перехід між двома базисами: обчислювальним (Z) базисом і базисом Фур'є. Але що означає базис Фур'є в цьому контексті? Ти, мабуть, пам'ятаєш, що перетворення Фур'є функції описує згортку із синусоїдальною функцією частоти . Простіше кажучи: перетворення Фур'є — це функція, яка описує, скільки кожної частоти потрібно, щоб побудувати функцію із синусоїд (або косинусоїд). Щоб краще зрозуміти, що означає QFT у цьому контексті, розглянь покрокові зображення нижче, які показують число, закодоване у двійковому вигляді з використанням чотирьох кубітів:
В обчислювальному базисі ми зберігаємо числа у двійковому вигляді, використовуючи стани та .
Зверни увагу на частоту, з якою змінюються різні кубіти: крайній лівий кубіт перевертається при кожному збільшенні числа, наступний — кожні 2 кроки, третій — кожні 4 кроки, і так далі.
Якщо застосувати квантове перетворення Фур'є до цих станів, ми отримуємо відображення:
(Стани у базисі Фур'є ми часто позначаємо тильдою (~)).
У базисі Фур'є ми зберігаємо числа за допомогою різних обертань навколо осі Z:
IFRAME
Число, яке ми хочемо зберегти, визначає кут повороту кожного кубіта навколо осі Z. У стані всі кубіти перебувають у стані . Як видно з прикладу вище, щоб закодувати стан на 4 кубітах, ми повернули крайній лівий кубіт на повних оборотів ( радіан). Наступний кубіт повертається вдвічі більше ( радіан, або повних оборотів), цей кут подвоюється для наступного кубіта, і так далі.
Знову зверни увагу на частоту зміни кожного кубіта. Крайній лівий кубіт (qubit 0) у цьому випадку має найнижчу частоту, а крайній правий — найвищу.
2.2. Приклад: QFT для 1 кубіта
Розглянемо випадок .
Унітарну матрицю можна записати:
Ця операція є результатом застосування Gate Адамара ().
2.3. Добутне представлення QFT
Узагальнимо перетворення для , , що діє на стан .
2.4. Приклад: Побудова Circuit для QFT з 3 кубітів
З наведеного вище опису може бути незрозуміло, як побудувати Circuit для QFT. Поки що просто зверни увагу на те, що ми очікуємо, що три кубіти матимуть фази, які еволюціонують із різною «швидкістю». Розуміння того, як саме це перетворюється на Circuit, залишається вправою для читача. У PDF лекції є кілька діаграм і прикладів. Додаткові ресурси включають цей урок із курсу «Основи квантових алгоритмів».
Ми продемонструємо QFT лише з використанням симуляторів, тому не будемо використовувати фреймворк шаблонів Qiskit, поки не перейдемо до квантової оцінки фази.
# Prepare for 3 qubits circuit
qr = QuantumRegister(3)
cr = ClassicalRegister(3)
qc = QuantumCircuit(qr, cr)
qc.h(2)
qc.cp(pi / 2, 1, 2) # Controlled-phase gate from qubit 1 to qubit 2
qc.cp(pi / 4, 0, 2) # Controlled-phase gate from qubit 0 to qubit 2
qc.draw(output="mpl")
qc.h(1)
qc.cp(pi / 2, 0, 1) # Controlled-phase gate from qubit 0 to qubit 1
qc.draw(output="mpl")
qc.h(0)
qc.draw(output="mpl")
qc.swap(0, 2)
qc.draw(output="mpl")
Спробуємо застосувати QFT до як приклад.
Спочатку підтвердимо двійковий запис числа 5 і створимо Circuit, що кодує стан 5:
bin(5)
'0b101'
qc = QuantumCircuit(3)
qc.x(0)
qc.x(2)
qc.draw(output="mpl")
Перевіримо квантові стани за допомогою симулятора Aer:
statevector = Statevector(qc)
plot_bloch_multivector(statevector)

Нарешті, додамо QFT і подивимося на кінцевий стан наших кубітів:
qc.h(2)
qc.cp(pi / 2, 1, 2)
qc.cp(pi / 4, 0, 2)
qc.h(1)
qc.cp(pi / 2, 0, 1)
qc.h(0)
qc.swap(0, 2)
qc.draw(output="mpl")
statevector = Statevector(qc)
plot_bloch_multivector(statevector)

Ми бачимо, що функція QFT спрацювала правильно. Qubit 0 повернувся на повного оберту, qubit 1 — на повних оберту (що еквівалентно повного оберту), а qubit 2 — на повних оберту (що еквівалентно повного оберту).
2.5. Вправа: QFT
(1) Реалізуй QFT для 4 кубітів.
##your code goes here##
(2) Застосуй QFT до , виконай симуляцію та побудуй вектор стану на сфері Блоха.
##your code goes here##
Розв'язок вправи: QFT
(1)
qr = QuantumRegister(4)
cr = ClassicalRegister(4)
qc = QuantumCircuit(qr, cr)
qc.h(3)
qc.cp(pi / 2, 2, 3)
qc.cp(pi / 4, 1, 3)
qc.cp(pi / 8, 0, 3)
qc.h(2)
qc.cp(pi / 2, 1, 2)
qc.cp(pi / 4, 0, 2)
qc.h(1)
qc.cp(pi / 2, 0, 1)
qc.h(0)
qc.swap(0, 3)
qc.swap(1, 2)
qc.draw(output="mpl")
(2)
bin(14)
'0b1110'
qc = QuantumCircuit(4)
qc.x(1)
qc.x(2)
qc.x(3)
qc.draw("mpl")
qc.h(3)
qc.cp(pi / 2, 2, 3)
qc.cp(pi / 4, 1, 3)
qc.cp(pi / 8, 0, 3)
qc.h(2)
qc.cp(pi / 2, 1, 2)
qc.cp(pi / 4, 0, 2)
qc.h(1)
qc.cp(pi / 2, 0, 1)
qc.h(0)
qc.swap(0, 3)
qc.swap(1, 2)
qc.draw(output="mpl")
statevector = Statevector(qc)
plot_bloch_multivector(statevector)

3. Основи Квантової оцінки фази (QPE)
За наявності унітарної операції , QPE оцінює у рівнянні . Оскільки є унітарним, усі його власні значення мають норму 1.
3.1. Процедура
1. Налаштування
знаходиться в одному наборі реєстрів кубітів. Додатковий набір із кубітів утворює лічильний регістр, у якому ми зберігатимемо значення :
2. Суперпозиція
Застосуй -бітну операцію Gate Адамара до лічильного регістру:
3. Операції керованого унітарного оператора
Нам потрібно ввести керований унітарний оператор , який застосовує унітарний оператор до цільового регістру лише тоді, коли відповідний керуючий біт дорівнює . Оскільки є унітарним оператором із власним вектором таким, що , це означає:
3.2. Приклад: QPE для T-gate
Використаємо Gate як приклад QPE та оцінимо її фазу .
Очікуємо отримати:
де
Ініціалізуємо власного вектора Gate , застосовуючи Gate :
qpe = QuantumCircuit(4, 3)
qpe.x(3)
qpe.draw(output="mpl")
Далі застосовуємо Gate Адамара до лічильних кубітів:
for qubit in range(3):
qpe.h(qubit)
qpe.draw(output="mpl")
Виконуємо операції керованого унітарного оператора:
repetitions = 1
for counting_qubit in range(3):
for i in range(repetitions):
qpe.cp(pi / 4, counting_qubit, 3) # This is C-U
repetitions *= 2
qpe.draw(output="mpl")
Застосовуємо обернене квантове перетворення Фур'є для конвертації стану лічильного регістру, після чого вимірюємо лічильний регістр:
from qiskit.circuit.library import QFT
# Apply inverse QFT
qpe.append(QFT(3, inverse=True), [0, 1, 2])
qpe.draw(output="mpl")
for n in range(3):
qpe.measure(n, n)
qpe.draw(output="mpl")
Можемо виконати симуляцію за допомогою симулятора Aer:
aer_sim = AerSimulator()
shots = 2048
pm = generate_preset_pass_manager(backend=aer_sim, optimization_level=1)
t_qpe = pm.run(qpe)
sampler = Sampler(mode=aer_sim)
job = sampler.run([t_qpe], shots=shots)
result = job.result()
answer = result[0].data.c.get_counts()
plot_histogram(answer)
Ми бачимо, що з певністю отримуємо один результат (001), який у десятковому записі дорівнює: 1. Тепер потрібно поділити наш результат (1) на , щоб отримати :
Алгоритм Шора дозволяє нам факторизувати число, будуючи Circuit із невідомим та отримуючи .
3.3 Вправа
Оціни , використовуючи 3 кубіти для підрахунку і один кубіт для власного вектора.
. Оскільки ми хочемо реалізувати , потрібно встановити .
##your code goes here##
Розв'язання вправи:
# Create and set up circuit
qpe = QuantumCircuit(4, 3)
# Apply H-Gates to counting qubits:
for qubit in range(3):
qpe.h(qubit)
# Prepare our eigenstate |psi>:
qpe.x(3)
# Do the controlled-U operations:
angle = 2 * pi / 3
repetitions = 1
for counting_qubit in range(3):
for i in range(repetitions):
qpe.cp(angle, counting_qubit, 3)
repetitions *= 2
# Do the inverse QFT:
qpe.append(QFT(3, inverse=True), [0, 1, 2])
for n in range(3):
qpe.measure(n, n)
qpe.draw(output="mpl")
aer_sim = AerSimulator()
shots = 4096
pm = generate_preset_pass_manager(backend=aer_sim, optimization_level=1)
t_qpe = pm.run(qpe)
sampler = Sampler(mode=aer_sim)
job = sampler.run([t_qpe], shots=shots)
result = job.result()
answer = result[0].data.c.get_counts()
plot_histogram(answer)
4. Виконання за допомогою примітиву Sampler із Qiskit Runtime
Ми виконаємо QPE на реальному квантовому пристрої та дотримаємось 4 кроків шаблонів Qiskit.
- Відобразити задачу у квантово-нативний формат
- Оптимізувати схеми
- Виконати цільову схему
- Постобробити результати
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import Sampler
# Loading your IBM Quantum® account(s)
service = QiskitRuntimeService()
4.1 Крок 1: Відображення задачі на квантові схеми та оператори
qpe = QuantumCircuit(4, 3)
qpe.x(3)
for qubit in range(3):
qpe.h(qubit)
repetitions = 1
for counting_qubit in range(3):
for i in range(repetitions):
qpe.cp(pi / 4, counting_qubit, 3) # This is C-U
repetitions *= 2
qpe.append(QFT(3, inverse=True), [0, 1, 2])
for n in range(3):
qpe.measure(n, n)
qpe.draw(output="mpl")
backend = service.least_busy(simulator=False, operational=True, min_num_qubits=4)
print(backend)
<IBMBackend('ibm_strasbourg')>
4.2 Крок 2: Оптимізація для цільового обладнання
# Transpile the circuit into basis gates executable on the hardware
pm = generate_preset_pass_manager(backend=backend, optimization_level=2)
qc_compiled = pm.run(qpe)
qc_compiled.draw("mpl", idle_wires=False)

4.3 Крок 3: Виконання на цільовому обладнанні
real_sampler = Sampler(mode=backend)
job = real_sampler.run([qc_compiled], shots=1024)
job_id = job.job_id()
print("job id:", job_id)
job id: d13p4zb5z6q00087ag00
job = service.job(job_id) # Input your job-id between the quotations
job.status()
'DONE'
result_real = job.result()
print(result_real)
PrimitiveResult([SamplerPubResult(data=DataBin(c=BitArray(<shape=(), num_shots=1024, num_bits=3>)), metadata={'circuit_metadata': {}})], metadata={'execution': {'execution_spans': ExecutionSpans([DoubleSliceSpan(<start='2025-06-09 22:39:00', stop='2025-06-09 22:39:00', size=1024>)])}, 'version': 2})
4.4 Крок 4: Постобробка результатів
from qiskit.visualization import plot_histogram
plot_histogram(result_real[0].data.c.get_counts())
# See the version of Qiskit
import qiskit
qiskit.__version__
'2.0.2'