Алгоритм Дойча
Алгоритм Дойча розв'язує задачу перевірки парності для окремого випадку У контексті квантових обчислень ця задача іноді називається задачею Дойча, і в цьому уроці ми будемо дотримуватися такої термінології.
Точніше кажучи, вхідними даними є функція з одного біта в один біт. Існують чотири такі функції:
Перша і остання з цих функцій є константними, а дві середні — збалансованими, тобто обидва можливі значення функції зустрічаються однакову кількість разів при перегляді всіх вхідних даних. Задача Дойча полягає в тому, щоб визначити, до якої з цих двох категорій належить вхідна функція: константної чи збалансованої.
Якщо розглядати вхідну функцію у задачі Дойча як доступ до рядка, ми маємо справу з дворозрядним рядком:
Розглядаючи задачу в такому ракурсі, задача Дойча — це обчислення парності (або, еквівалентно, виключного АБО) двох бітів.
Кожен класичний алгоритм запитів, що правильно розв'язує цю задачу, повинен звертатися до обох бітів: і Якщо ми дізнаємось, що відповідь все одно може бути або залежно від того, чи або відповідно. Усі інші випадки аналогічні: знання лише одного з двох бітів не дає жодної інформації про їхню парність. Отже, булева схема, описана в попередньому розділі, є найкращим, чого ми можемо досягти з точки зору кількості запитів, необхідних для розв'язання цієї задачі.
Опис квантової схеми
Алгоритм Дойча розв'язує задачу Дойча за допомогою одного запиту, забезпечуючи тим самим вимірювану перевагу квантових обчислень над класичними. Це може здатися скромною перевагою — один запит проти двох — але з чогось треба починати. Наукові досягнення іноді мають, здавалось би, скромне походження.
Ось квантова схема, що описує алгоритм Дойча:
Аналіз
Щоб проаналізувати алгоритм Дойча, простежимо дію наведеної вище схеми та визначимо стани кубітів у моменти, позначені на цьому рисунку:
Початковий стан — і дві операції Адамара з лівого боку схеми перетворюють цей стан на
(Як завжди, ми дотримуємось конвенції Qiskit щодо порядку кубітів, де верхній кубіт стоїть праворуч, а нижній — ліворуч.) Може здатися неінтуїтивним записувати цей добуток стану частково в розгорнутій формі (залишаючи стани кубіта 1 у вигляді множника), але це зробить подальші вирази компактнішими.
Далі виконується гейт Відповідно до визначення гейта значення функції для класичного стану верхнього/правого кубіта накладається за допомогою XOR на нижній/лівий кубіт, що перетворює на стан
Цей вираз можна спростити, зауваживши, що формула
справджується для обох можливих значень Більш явно, два випадки такі:
Таким чином, можна виразити інакше:
Щойно трапилось щось цікаве! Хоча дія гейта на стани стандартного базису залишає верхній/правий кубіт незміненим і накладає значення функції на нижній/лівий кубіт за допомогою XOR, тут ми бачимо, що стан верхнього/правого кубіта змінився (в загальному випадку), тоді як стан нижнього/лівого кубіта залишився незмінним — а саме, перебуває у стані до і після виконання гейта Це явище відоме як відбій фази, і ми скажемо про нього більше дещо пізніше.
З одним остаточним спрощенням — виносячи множник за дужки суми — отримуємо такий вираз для стану :
Зауважимо, що в цьому виразі маємо у показнику степеня на відміну від чого можна було б очікувати з чисто алгебраїчної точки зору, проте результат у обох випадках однаковий. Це пояснюється тим, що значення для будь-якого цілого числа залежить лише від того, чи парне, чи непарне.
Застосування останнього гейта Адамара до верхнього кубіта дає стан
що призводить до правильного результату з імовірністю при вимірюванні правого/верхнього кубіта.
Додаткові зауваження про відбій фази
Перш ніж рухатися далі, розглянемо наведений вище аналіз під дещо іншим кутом, що може пролити світло на явище відбою фази.
По-перше, зауважимо, що наступна формула справджується для всіх можливих значень бітів
Це можна перевірити, підставивши два можливих значення і :
Використовуючи цю формулу, бачимо, що
для будь-яких значень бітів Оскільки ця формула справджується при і з лінійності бачимо, що
для будь-яких векторів стану кубіта і тому
Ключем до цього є те, що Математично кажучи, вектор є власним вектором матриці з власним значенням
Ми детальніше розглянемо власні вектори та власні значення в майбутньому уроці про оцінку фази та факторизацію, де явище відбою фази узагальнюється на інші унітарні операції.
Пам'ятаючи, що скаляри вільно проходять через тензорні добутки, знаходимо альтернативний спосіб пояснення того, як операція перетворює на у наведеному вище аналізі:
Реалізація в Qiskit
Тепер подивимось, як реалізувати алгоритм Дойча в Qiskit. Починаємо з перевірки версії та виконання імпортів, необхідних лише для цієї реалізації. Для реалізацій інших алгоритмів, що слідують далі, ми будемо виконувати потрібні імпорти окремо для більшої модульності.
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-aer
from qiskit import __version__
print(__version__)
2.1.1
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
Спочатку визначимо квантову схему, яка реалізує гейт запиту для однієї з чотирьох функцій або з одного біта в один біт, описаних раніше. Як вже зазначалося, реалізація гейтів запиту насправді не є частиною самого алгоритму Дойча; тут ми, по суті, просто показуємо один спосіб підготувати вхідні дані у вигляді схемної реалізації гейта запиту.
def deutsch_function(case: int):
# This function generates a quantum circuit for one of the 4 functions
# from one bit to one bit
if case not in [1, 2, 3, 4]:
raise ValueError("`case` must be 1, 2, 3, or 4.")
f = QuantumCircuit(2)
if case in [2, 3]:
f.cx(0, 1)
if case in [3, 4]:
f.x(1)
return f
Побачити, як виглядає кожна схема, можна за допомогою методу draw. Ось схема для функції
display(deutsch_function(3).draw(output="mpl"))
Далі створимо власне квантову схему для алгоритму Дойча, замінивши гейт запиту на реалізацію у вигляді квантової схеми, переданої як аргумент. Незабаром ми підставимо одну з чотирьох схем, визначених функцією deutsch_function.
Бар'єри включені для наочного розділення реалізації гейта запиту і решти схеми.
def compile_circuit(function: QuantumCircuit):
# Compiles a circuit for use in Deutsch's algorithm.
n = function.num_qubits - 1
qc = QuantumCircuit(n + 1, n)
qc.x(n)
qc.h(range(n + 1))
qc.barrier()
qc.compose(function, inplace=True)
qc.barrier()
qc.h(range(n))
qc.measure(range(n), range(n))
return qc
Знову можна побачити, як виглядає схема, за допомогою методу draw.
display(compile_circuit(deutsch_function(3)).draw(output="mpl"))
Нарешті, створимо функцію, яка запускає попередньо визначену схему один раз і виводить відповідний результат: «constant» або «balanced».
def deutsch_algorithm(function: QuantumCircuit):
# Determine if a one-bit function is constant or balanced.
qc = compile_circuit(function)
result = AerSimulator().run(qc, shots=1, memory=True).result()
measurements = result.get_memory()
if measurements[0] == "0":
return "constant"
return "balanced"
Тепер можна запустити алгоритм Дойча для будь-якої з чотирьох функцій, визначених вище.
f = deutsch_function(3)
display(deutsch_algorithm(f))
'balanced'