Deutschs Algorithmus
Der Algorithmus von Deutsch löst das Paritätsproblem für den Sonderfall, dass gilt. Im Zusammenhang mit dem Quantencomputing wird dieses Problem manchmal als „Deutsch-Problem“ bezeichnet, und wir werden uns in dieser Lektion an diese Bezeichnung halten.
Um genau zu sein, wird die Eingabe durch eine Funktion von einem Bit zu einem Bit dargestellt. Es gibt vier solcher Funktionen:
Die erste und die letzte dieser Funktionen sind konstant, und die beiden mittleren sind ausgeglichen, d. h. die beiden möglichen Ausgabewerte für die Funktion treten gleich oft auf, wenn wir über die Eingänge gehen. Das Problem von Deutsch besteht darin, zu bestimmen, zu welcher der beiden Kategorien die Eingangsfunktion gehört: konstant oder ausgeglichen.
Eingabe: eine Funktion \ Ausgabe: wenn konstant ist, wenn ausgeglichen ist
Wenn wir die Eingabefunktion „ “ in Deutschs Problem als zufälligen Zugriff auf eine Zeichenkette betrachten, denken wir an eine Zwei-Bit-Zeichenkette: „ “.
So gesehen besteht das Problem von Deutsch darin, die Parität (oder, äquivalent dazu, das Exklusiv-ODER) der beiden Bits zu berechnen.
Jeder klassische Abfragealgorithmus, der dieses Problem korrekt löst, muss beide Bits abfragen: und . Wenn wir beispielsweise erfahren, dass gilt, könnte die Antwort dennoch oder lauten, je nachdem, ob bzw. gilt. In allen anderen Fällen verhält es sich ähnlich: Wenn man nur eines von zwei Bits kennt, liefert dies keinerlei Informationen über deren Parität. Die im vorigen Abschnitt beschriebene Boolesche Schaltung ist also hinsichtlich der Anzahl der zur Lösung dieses Problems erforderlichen Abfragen das Beste, was wir erreichen können.
Beschreibung des Quantenschaltkreises
Der Deutsch-Algorithmus löst das Deutsch-Problem mit einer einzigen Abfrage und bietet damit einen quantifizierbaren Vorteil von Quantenberechnungen gegenüber klassischen Berechnungen. Dies mag ein bescheidener Vorteil sein - eine Abfrage im Gegensatz zu zwei - aber irgendwo müssen wir ja anfangen. Wissenschaftliche Fortschritte haben manchmal scheinbar bescheidene Ursprünge.
Hier ist eine Quantenschaltung, die den Deutsch'schen Algorithmus beschreibt:
Analyse
Um den Algorithmus von Deutsch zu analysieren, werden wir die Wirkung der obigen Schaltung nachvollziehen und die Zustände der Qubits zu den in der Abbildung angegebenen Zeitpunkten bestimmen:
Der Anfangszustand ist , und die beiden Hadamard-Operationen auf der linken Seite der Schaltung wandeln diesen Zustand um in
(Wie immer folgen wir der Qiskit-Konvention zur Anordnung der Qubits, die das oberste Qubit nach rechts und das unterste Qubit nach links setzt) Es mag sich unintuitiv anfühlen, diesen Produktzustand teilweise verteilt zu schreiben (wobei die Zustände von Qubit 1 ausgeklammert bleiben), aber das wird unsere späteren Ausdrücke kompakter machen.
Als Nächstes wird das Tor ausgeführt. Gemäß der Definition des Gatters wird der Wert der Funktion für den klassischen Zustand des oberen/rechten Qubits mit dem unteren/linken Qubit XOR-verknüpft, wodurch in den Zustand umgewandelt wird
Wir können diesen Ausdruck vereinfachen, indem wir beachten, dass die Formel
gilt für beide möglichen Werte: . Genauer gesagt stellen sich die beiden Fälle wie folgt dar.
So können wir alternativ wie folgt ausdrücken:
Es ist gerade etwas Interessantes passiert! Obwohl die Wirkung des Gatters auf Standard-Basiszustände das oberste/rechteste Qubit in Ruhe lässt und den Funktionswert mit dem untersten/linken Qubit XOR-verknüpft, sehen wir hier, dass sich der Zustand des obersten/rechtesten Qubits (im Allgemeinen) geändert hat, während der Zustand des untersten/linken Qubits derselbe bleibt - nämlich der Zustand vor und nach der Ausführung des Gatters. Dieses Phänomen wird als Phasenrückschlag bezeichnet, und wir werden in Kürze mehr dazu sagen.
Mit einer letzten Vereinfachung, die darin besteht, den Faktor aus der Summe herauszuziehen, erhalten wir diesen Ausdruck für den Zustand :
Beachten Sie, dass in diesem Ausdruck im Exponenten von die Zahl steht und nicht , wie man es aus rein algebraischer Sicht vielleicht erwarten würde; dennoch erhalten wir in beiden Fällen das gleiche Ergebnis. Das liegt daran, dass der Wert für jede ganze Zahl nur davon abhängt, ob gerade oder ungerade ist.
Wendet man das letzte Hadamard-Tor auf das obere Qubit an, so erhält man den Zustand
was zum richtigen Ergebnis mit der Wahrscheinlichkeit führt, wenn das rechte/oberste Qubit gemessen wird.
Weitere Anmerkungen zum Phasenrückstoß
Bevor wir weitermachen, wollen wir die obige Analyse aus einem etwas anderen Blickwinkel betrachten, der das Phänomen des Phasenrückpralls etwas näher beleuchten kann.
Zunächst ist zu beachten, dass die folgende Formel für alle Bitauswahlen gilt.
Dies kann überprüft werden, indem man es für die beiden möglichen Werte und überprüft:
Aus dieser Formel ergibt sich, dass
für jede Wahl der Bits . Da diese Formel für und gilt, ergibt sich aufgrund der Linearität, dass
für alle Qubit-Zustandsvektoren , und daher
Der Schlüssel zum Erfolg ist, dass gilt. Mathematisch ausgedrückt ist der Vektor ein Eigenvektor der Matrix mit dem Eigenwert .
Wir werden Eigenvektoren und Eigenwerte in der nächsten Lektion über Phasenschätzung und Faktorisierung, in der das Phänomen des Phasenrückschlags auf andere unitäre Operationen verallgemeinert wird, ausführlicher behandeln.
Wenn wir bedenken, dass Skalare frei durch Tensorprodukte fließen, finden wir in der obigen Analyse einen alternativen Weg, wie die Operation in umwandelt:
Implementierung in Qiskit
Schauen wir uns nun an, wie wir Deutschs Algorithmus in Qiskit implementieren können. Wir beginnen mit einer Versionsprüfung und führen dann die Importe durch, die ausschließlich für diese Implementierung erforderlich sind. Für die folgenden Implementierungen anderer Algorithmen werden wir die erforderlichen Importe im Interesse einer größeren Modularität separat durchführen.
from qiskit import __version__
print(__version__)Output:
2.1.1
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulatorZunächst definieren wir einen Quantenschaltkreis, der ein Abfragegatter für eine der vier zuvor beschriebenen Funktionen „ “, „ “, „ “ oder „ “ von einem Bit zu einem Bit implementiert. Wie bereits erwähnt, ist die Implementierung von Abfrage-Gates nicht wirklich Teil des Deutsch-Algorithmus selbst; hier zeigen wir im Wesentlichen nur eine Möglichkeit, die Eingabe vorzubereiten, und zwar in Form einer Schaltungsimplementierung eines Abfrage-Gates.
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 fMit dieser draw Methode können wir sehen, wie die einzelnen Schaltungen aussehen. Hier ist der Schaltplan für die Funktion „ “.
display(deutsch_function(3).draw(output="mpl"))Output:
Als Nächstes werden wir die eigentliche Quantenschaltung für den Deutsch-Algorithmus erstellen, indem wir das Abfragegatter durch eine Quantenschaltungsimplementierung ersetzen, die als Argument angegeben wird. In Kürze werden wir einen der vier Schaltkreise anschließen, die durch die zuvor definierte Funktion deutsch_function festgelegt sind.
Um die visuelle Trennung zwischen der Implementierung des Abfragegatters und dem Rest der Schaltung zu verdeutlichen, sind Barrieren eingefügt.
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 qcAuch hier können wir sehen, wie die Schaltung nach der Methode draw aussieht.
display(compile_circuit(deutsch_function(3)).draw(output="mpl"))Output:
Schließlich erstellen wir eine Funktion, die den zuvor definierten Schaltkreis einmal durchläuft und das entsprechende Ergebnis ausgibt: "konstant" oder "ausgeglichen"
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"Wir können nun den Deutsch'schen Algorithmus auf jede der vier oben definierten Funktionen anwenden.
f = deutsch_function(3)
display(deutsch_algorithm(f))Output:
'balanced'