Algorytm Deutscha-Jozsy
Algorytm Deutscha przewyższa wszystkie klasyczne algorytmy w pewnym problemie zapytaniowym, ale przewaga ta jest dość skromna: jedno zapytanie zamiast dwóch. Algorytm Deutsch-Jozsa rozszerza tę przewagę — a w rzeczywistości może być używany do rozwiązywania kilku różnych problemów zapytaniowych.
Oto opis algorytmu Deutsch-Jozsa w postaci obwodu kwantowego. W zależności od konkretnego rozwiązywanego problemu może być również wymagany dodatkowy klasyczny krok przetwarzania końcowego, którego nie przedstawiono na rysunku.
Oczywiście, nie omówiliśmy jeszcze, jakie problemy rozwiązuje ten algorytm; zostanie to zrobione w dwóch kolejnych sekcjach.
Problem Deutsch-Jozsa
Zaczniemy od problemu zapytaniowego, który algorytm Deutsch-Jozsa miał pierwotnie rozwiązywać, znanego jako problem Deutsch-Jozsa.
Funkcja wejściowa dla tego problemu ma postać dla dowolnej dodatniej liczby całkowitej Podobnie jak w problemie Deutscha, zadaniem jest zwrócenie wartości , jeśli jest stała, oraz , jeśli jest zrównoważona, co ponownie oznacza, że liczba ciągów wejściowych, dla których funkcja przyjmuje wartość , jest równa liczbie ciągów wejściowych, dla których funkcja przyjmuje wartość .
Zauważ, że gdy jest większe niż istnieją funkcje postaci , które nie są ani stałe, ani zrównoważone. Na przykład funkcja zdefiniowana jako
nie należy do żadnej z tych dwóch kategorii. W problemie Deutsch-Jozsa po prostu nie przejmujemy się takimi funkcjami — są one traktowane jako wejścia „nieistotne”. Oznacza to, że dla tego problemu mamy obietnicę, że jest albo stała, albo zrównoważona.
Algorytm Deutsch-Jozsa, za pomocą pojedynczego zapytania, rozwiązuje ten problem w następującym sensie: jeśli każdy z wyników pomiaru wynosi to funkcja jest stała; w przeciwnym razie, jeśli co najmniej jeden z wyników pomiaru wynosi to funkcja jest zrównoważona. Inaczej mówiąc, po opisanym powyżej obwodzie następuje klasyczny krok przetwarzania końcowego, w którym obliczana jest operacja OR wyników pomiarów w celu uzyskania wyjścia.
Analiza algorytmu
Aby przeanalizować wydajność algorytmu Deutsch-Jozsa w problemie Deutsch-Jozsa, pomocne jest zacząć od rozważenia działania pojedynczej warstwy bramek Hadamarda. Operację Hadamarda można wyrazić jako macierz w zwykły sposób,
ale możemy również wyrazić tę operację poprzez jej działanie na stanach bazy standardowej:
Te dwa równania można połączyć w jeden wzór,
który jest prawdziwy dla obu wyborów
Załóżmy teraz, że zamiast pojedynczego kubitu mamy kubitów, i na każdym z nich wykonywana jest operacja Hadamarda. Połączoną operację na kubitach opisuje iloczyn tensorowy ( razy), który dla zwięzłości i przejrzystości zapisujemy jako . Korzystając z powyższego wzoru, a następnie rozwijając i upraszczając, możemy wyrazić działanie tej połączonej operacji na stanach bazy standardowej kubitów w następujący sposób:
Przy okazji, zapisujemy tutaj ciągi binarne o długości jako oraz zgodnie z konwencją indeksowania Qiskit.
Ten wzór dostarcza nam użytecznego narzędzia do analizy powyższego obwodu kwantowego. Po wykonaniu pierwszej warstwy bramek Hadamarda stan kubitów (w tym skrajnie lewego/dolnego kubitu, który jest traktowany oddzielnie od pozostałych) wynosi
Gdy wykonywana jest operacja , stan ten zostaje przekształcony w
dokładnie poprzez to samo zjawisko odrzutu fazy (phase kick-back), które widzieliśmy w analizie algorytmu Deutscha.
Następnie wykonywana jest druga warstwa bramek Hadamarda, która (zgodnie z powyższym wzorem) przekształca ten stan w
To wyrażenie wygląda nieco skomplikowanie i nie można wiele wywnioskować na temat prawdopodobieństw uzyskania różnych wyników pomiarów bez posiadania większej wiedzy o funkcji
Na szczęście wszystko, co musimy wiedzieć, to prawdopodobieństwo, że każdy z wyników pomiarów wynosi — ponieważ jest to prawdopodobieństwo, że algorytm stwierdzi, iż jest stała. To prawdopodobieństwo ma prosty wzór.
Bardziej szczegółowo, jeśli jest stała, to albo dla każdego ciągu w którym to przypadku wartość sumy wynosi albo dla każdego ciągu w którym to przypadku wartość sumy wynosi Dzielenie przez i podniesienie wartości bezwzględnej do kwadratu daje
Jeśli natomiast jest zrównoważona, to przyjmuje wartość na połowie ciągów i wartość na drugiej połowie, więc wyrazy i w sumie się znoszą i pozostaje nam wartość
Wnioskujemy, że algorytm działa poprawnie, pod warunkiem że obietnica jest spełniona.
Trudność klasyczna
Algorytm Deutscha-Jozsy działa za każdym razem, zawsze dając nam poprawną odpowiedź, gdy obietnica jest spełniona, i wymaga jednego zapytania. Jak to wypada w porównaniu z klasycznymi algorytmami zapytań dla problemu Deutscha-Jozsy?
Po pierwsze, każdy deterministyczny klasyczny algorytm, który poprawnie rozwiązuje problem Deutscha-Jozsy, musi wykonać wykładniczo wiele zapytań: w najgorszym przypadku wymagane jest zapytań. Rozumowanie jest takie, że jeśli algorytm deterministyczny zapyta o lub mniej różnych ciągów i za każdym razem otrzyma tę samą wartość funkcji, to obie odpowiedzi są nadal możliwe. Funkcja może być stała lub może być zrównoważona, ale przez pech wszystkie zapytania zwróciły tę samą wartość funkcji.
Druga możliwość może wydawać się mało prawdopodobna — ale dla algorytmów deterministycznych nie ma losowości ani niepewności, więc będą one systematycznie zawodzić na pewnych funkcjach. Mamy zatem pod tym względem znaczącą przewagę algorytmów kwantowych nad klasycznymi.
Jest jednak pewien haczyk, a mianowicie probabilistyczne klasyczne algorytmy mogą rozwiązać problem Deutscha-Jozsy z bardzo wysokim prawdopodobieństwem, używając zaledwie kilku zapytań. W szczególności, jeśli po prostu wybierzemy kilka różnych losowych ciągów długości i zapytamy o te ciągi, jest mało prawdopodobne, że otrzymamy tę samą wartość funkcji dla wszystkich z nich, gdy jest zrównoważona.
Mówiąc konkretnie, jeśli wybierzemy ciągów wejściowych jednostajnie losowo, obliczymy i odpowiemy , jeśli wszystkie wartości funkcji są takie same, oraz w przeciwnym razie, to zawsze będziemy mieli rację, gdy jest stała, a pomylimy się w przypadku, gdy jest zrównoważona, z prawdopodobieństwem zaledwie Na przykład, jeśli weźmiemy ten algorytm odpowie poprawnie z prawdopodobieństwem większym niż %.
Z tego powodu wciąż mamy raczej skromną przewagę algorytmów kwantowych nad klasycznymi — niemniej jednak jest to wymierna przewaga stanowiąca poprawę względem algorytmu Deutscha.
Deutsch-Jozsa w Qiskit
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
import numpy as np
Aby zaimplementować algorytm Deutscha-Jozsy w Qiskit, zaczniemy od zdefiniowania funkcji dj_query, która generuje obwód kwantowy realizujący bramkę zapytania dla losowo wybranej funkcji spełniającej obietnicę problemu Deutscha-Jozsy.
Z prawdopodobieństwem 50% funkcja jest stała, a z prawdopodobieństwem 50% funkcja jest zrównoważona.
Dla każdej z tych dwóch możliwości funkcja jest wybierana jednostajnie spośród funkcji danego typu.
Argumentem jest liczba bitów wejściowych funkcji.
def dj_query(num_qubits):
# Create a circuit implementing for a query gate for a random function
# satisfying the promise for the Deutsch-Jozsa problem.
qc = QuantumCircuit(num_qubits + 1)
if np.random.randint(0, 2):
# Flip output qubit with 50% chance
qc.x(num_qubits)
if np.random.randint(0, 2):
# return constant circuit with 50% chance
return qc
# Choose half the possible input strings
on_states = np.random.choice(
range(2**num_qubits), # numbers to sample from
2**num_qubits // 2, # number of samples
replace=False, # makes sure states are only sampled once
)
def add_cx(qc, bit_string):
for qubit, bit in enumerate(reversed(bit_string)):
if bit == "1":
qc.x(qubit)
return qc
for state in on_states:
qc.barrier() # Barriers are added to help visualize how the functions are created.
qc = add_cx(qc, f"{state:0b}")
qc.mcx(list(range(num_qubits)), num_qubits)
qc = add_cx(qc, f"{state:0b}")
qc.barrier()
return qc
Implementację bramki zapytania w postaci obwodu kwantowego możemy pokazać za pomocą metody draw jak zwykle.
display(dj_query(3).draw(output="mpl"))
Następnie definiujemy funkcję, która tworzy obwód Deutscha-Jozsy, przyjmując jako argument implementację bramki zapytania w postaci obwodu kwantowego.
def compile_circuit(function: QuantumCircuit):
# Compiles a circuit for use in the Deutsch-Jozsa algorithm.
n = function.num_qubits - 1
qc = QuantumCircuit(n + 1, n)
qc.x(n)
qc.h(range(n + 1))
qc.compose(function, inplace=True)
qc.h(range(n))
qc.measure(range(n), range(n))
return qc
Na koniec definiujemy funkcję, która uruchamia obwód Deutscha-Jozsy jeden raz.
def dj_algorithm(function: QuantumCircuit):
# Determine if a function is constant or balanced.
qc = compile_circuit(function)
result = AerSimulator().run(qc, shots=1, memory=True).result()
measurements = result.get_memory()
if "1" in measurements[0]:
return "balanced"
return "constant"
Możemy przetestować naszą implementację, wybierając losowo funkcję, wyświetlając implementację bramki zapytania dla tej funkcji w postaci obwodu kwantowego, a następnie uruchamiając algorytm Deutscha-Jozsy na tej funkcji.
f = dj_query(3)
display(f.draw("mpl"))
display(dj_algorithm(f))

'balanced'
Problem Bernsteina-Vaziraniego
Następnie omówimy problem znany jako problem Bernsteina-Vaziraniego. Nazywany jest również problemem próbkowania Fouriera, choć istnieją bardziej ogólne sformułowania tego problemu, które również noszą tę nazwę.
Najpierw wprowadźmy pewną notację. Dla dowolnych dwóch łańcuchów binarnych i o długości definiujemy
Będziemy nazywać tę operację binarnym iloczynem skalarnym. Alternatywny sposób jej zdefiniowania jest następujący.
Zauważmy, że jest to operacja symetryczna, co oznacza, że wynik nie zmienia się, jeśli zamienimy i więc możemy to robić kiedy jest to wygodne. Czasem przydatne jest myślenie o binarnym iloczynie skalarnym jako o parzystości bitów na pozycjach, na których łańcuch ma lub równoważnie, parzystości bitów na pozycjach, na których łańcuch ma
Mając tę notację, możemy teraz zdefiniować problem Bernsteina-Vaziraniego.
Tak naprawdę nie potrzebujemy nowego algorytmu kwantowego do tego problemu; rozwiązuje go algorytm Deutscha-Jozsy. Dla jasności nazwijmy obwód kwantowy z góry, który nie obejmuje klasycznego etapu przetwarzania końcowego polegającego na obliczaniu OR, obwodem Deutscha-Jozsy.
Analiza algorytmu
Aby przeanalizować, jak działa obwód Deutscha-Jozsy dla funkcji spełniającej obietnicę problemu Bernsteina-Vaziraniego, zaczniemy od krótkiej obserwacji. Używając binarnego iloczynu skalarnego, możemy alternatywnie opisać działanie bramek Hadamarda na stanach bazy standardowej kubitów w następujący sposób.
Podobnie jak widzieliśmy przy analizie algorytmu Deutscha, wynika to z faktu, że wartość dla dowolnej liczby całkowitej zależy tylko od tego, czy jest parzysta czy nieparzysta.
Wracając do obwodu Deutscha-Jozsy, po wykonaniu pierwszej warstwy bramek Hadamarda stan kubitów wynosi
Następnie wykonywana jest bramka zapytania, która (poprzez zjawisko phase kickback) przekształca stan w
Korzystając z naszego wzoru na działanie warstwy bramek Hadamarda, widzimy, że druga warstwa bramek Hadamarda przekształca następnie ten stan w
Teraz możemy dokonać pewnych uproszczeń w wykładniku wewnątrz sumy. Mamy obietnicę, że dla pewnego łańcucha więc możemy wyrazić stan jako
Ponieważ i są wartościami binarnymi, możemy zastąpić dodawanie operacją exclusive-OR — znowu dlatego, że jedyne, co ma znaczenie dla liczby całkowitej w wykładniku to czy jest ona parzysta czy nieparzysta. Wykorzystując symetrię binarnego iloczynu skalarnego, otrzymujemy następujące wyrażenie dla stanu:
(Nawiasy zostały dodane dla jasności, chociaż nie są one naprawdę konieczne, ponieważ zwyczajowo traktuje się binarny iloczyn skalarny jako mający wyższy priorytet niż exclusive-OR.)
W tym momencie skorzystamy z następującego wzoru.
Możemy uzyskać ten wzór dzięki podobnemu wzorowi dla bitów,
wraz z rozwinięciem binarnego iloczynu skalarnego i bitowego exclusive-OR:
Pozwala to wyrazić stan obwodu bezpośrednio przed pomiarami w następujący sposób:
Ostatnim krokiem jest wykorzystanie jeszcze jednego wzoru, który działa dla każdego łańcucha binarnego
Używamy tu prostej notacji dla łańcuchów, której użyjemy jeszcze kilka razy w tej lekcji: to łańcuch samych zer o długości
Prostym sposobem uzasadnienia tego wzoru jest rozważenie dwóch przypadków osobno. Jeśli to