Skip to main content
IBM Quantum Platform

Deutschs Algorithmus

Der Algorithmus von Deutsch löst das Paritätsproblem für den Sonderfall, dass n=1n = 1 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 f:Σ→Σf:\Sigma \rightarrow \Sigma von einem Bit zu einem Bit dargestellt. Es gibt vier solcher Funktionen:

af1(a)0010af2(a)0011af3(a)0110af4(a)0111\rule[-10mm]{0mm}{10mm} \begin{array}{c|c} a & f_1(a)\\ \hline 0 & 0\\ 1 & 0 \end{array} \qquad \begin{array}{c|c} a & f_2(a)\\ \hline 0 & 0\\ 1 & 1 \end{array} \qquad \begin{array}{c|c} a & f_3(a)\\ \hline 0 & 1\\ 1 & 0 \end{array} \qquad \begin{array}{c|c} a & f_4(a)\\ \hline 0 & 1\\ 1 & 1 \end{array}

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.

Deutsch's problem

Eingabe: eine Funktion f:{0,1}→{0,1}f:\{0,1\}\rightarrow\{0,1\} \ Ausgabe: 00 wenn ff konstant ist, 11 wenn ff ausgeglichen ist

Wenn wir die Eingabefunktion „ ff “ in Deutschs Problem als zufälligen Zugriff auf eine Zeichenkette betrachten, denken wir an eine Zwei-Bit-Zeichenkette: „ f(0)f(1)f(0)f(1) “.

functionstringf100f201f310f411\begin{array}{cc} \mathsf{function} & \mathsf{string}\\ \hline f_1 & 00 \\ f_2 & 01 \\ f_3 & 10 \\ f_4 & 11 \end{array}

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: f(0)f(0) und f(1)f(1). Wenn wir beispielsweise erfahren, dass f(1)=1f(1) = 1 gilt, könnte die Antwort dennoch 00 oder 11 lauten, je nachdem, ob f(0)=1f(0) = 1 bzw. f(0)=0f(0) = 0 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:

Deutsch's Algorithmus

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:

Zustände bei Deutschs Algorithmus

Der Anfangszustand ist ∣1⟩∣0⟩\vert 1\rangle \vert 0 \rangle, und die beiden Hadamard-Operationen auf der linken Seite der Schaltung wandeln diesen Zustand um in

∣π1⟩=∣−⟩∣+⟩=12(∣0⟩−∣1⟩)∣0⟩+12(∣0⟩−∣1⟩)∣1⟩.\vert \pi_1 \rangle = \vert - \rangle \vert + \rangle = \frac{1}{2} \bigl( \vert 0\rangle - \vert 1\rangle \bigr) \vert 0\rangle + \frac{1}{2} \bigl( \vert 0\rangle - \vert 1\rangle \bigr) \vert 1\rangle.

(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 UfU_f ausgeführt. Gemäß der Definition des Gatters UfU_f wird der Wert der Funktion ff für den klassischen Zustand des oberen/rechten Qubits mit dem unteren/linken Qubit XOR-verknüpft, wodurch ∣π1⟩\vert \pi_1\rangle in den Zustand umgewandelt wird

∣π2⟩=12(∣0⊕f(0)⟩−∣1⊕f(0)⟩)∣0⟩+12(∣0⊕f(1)⟩−∣1⊕f(1)⟩)∣1⟩.\vert \pi_2 \rangle = \frac{1}{2} \bigl( \vert 0 \oplus f(0) \rangle - \vert 1 \oplus f(0) \rangle \bigr) \vert 0 \rangle + \frac{1}{2} \bigl( \vert 0 \oplus f(1) \rangle - \vert 1 \oplus f(1) \rangle \bigr) \vert 1 \rangle.

Wir können diesen Ausdruck vereinfachen, indem wir beachten, dass die Formel

∣0⊕a⟩−∣1⊕a⟩=(−1)a(∣0⟩−∣1⟩)\vert 0 \oplus a\rangle - \vert 1 \oplus a\rangle = (-1)^a \bigl( \vert 0\rangle - \vert 1\rangle \bigr)

gilt für beide möglichen Werte: a∈Σa\in\Sigma. Genauer gesagt stellen sich die beiden Fälle wie folgt dar.

∣0⊕0⟩−∣1⊕0⟩=∣0⟩−∣1⟩=(−1)0(∣0⟩−∣1⟩)∣0⊕1⟩−∣1⊕1⟩=∣1⟩−∣0⟩=(−1)1(∣0⟩−∣1⟩)\begin{aligned} \vert 0 \oplus 0\rangle - \vert 1 \oplus 0\rangle & = \vert 0 \rangle - \vert 1 \rangle = (-1)^0 \bigl( \vert 0\rangle - \vert 1\rangle \bigr)\\ \vert 0 \oplus 1\rangle - \vert 1 \oplus 1\rangle & = \vert 1 \rangle - \vert 0\rangle = (-1)^1 \bigl( \vert 0\rangle - \vert 1\rangle \bigr) \end{aligned}

So können wir ∣π2⟩\vert\pi_2\rangle alternativ wie folgt ausdrücken:

∣π2⟩=12(−1)f(0)(∣0⟩−∣1⟩)∣0⟩+12(−1)f(1)(∣0⟩−∣1⟩)∣1⟩=∣−⟩((−1)f(0)∣0⟩+(−1)f(1)∣1⟩2).\begin{aligned} \vert\pi_2\rangle & = \frac{1}{2} (-1)^{f(0)} \bigl( \vert 0 \rangle - \vert 1 \rangle \bigr) \vert 0 \rangle + \frac{1}{2} (-1)^{f(1)} \bigl( \vert 0 \rangle - \vert 1 \rangle \bigr) \vert 1 \rangle \\ & = \vert - \rangle \biggl( \frac{(-1)^{f(0)} \vert 0\rangle + (-1)^{f(1)} \vert 1\rangle}{\sqrt{2}}\biggr). \end{aligned}

Es ist gerade etwas Interessantes passiert! Obwohl die Wirkung des UfU_f 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 ∣−⟩\vert - \rangle vor und nach der Ausführung des UfU_f 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 (−1)f(0)(-1)^{f(0)} aus der Summe herauszuziehen, erhalten wir diesen Ausdruck für den Zustand ∣π2⟩\vert\pi_2\rangle :

∣π2⟩=(−1)f(0)∣−⟩(∣0⟩+(−1)f(0)⊕f(1)∣1⟩2)={(−1)f(0)∣−⟩∣+⟩if f(0)⊕f(1)=0(−1)f(0)∣−⟩∣−⟩if f(0)⊕f(1)=1.\begin{aligned} \vert\pi_2\rangle & = (-1)^{f(0)} \vert - \rangle \biggl( \frac{\vert 0\rangle + (-1)^{f(0) \oplus f(1)} \vert 1\rangle}{\sqrt{2}}\biggr) \\ & = \begin{cases} (-1)^{f(0)} \vert - \rangle \vert + \rangle & \text{if $f(0) \oplus f(1) = 0$}\\[1mm] (-1)^{f(0)} \vert - \rangle \vert - \rangle & \text{if $f(0) \oplus f(1) = 1$}. \end{cases} \end{aligned}

Beachten Sie, dass in diesem Ausdruck im Exponenten von −1-1 die Zahl f(0)⊕f(1)f(0) \oplus f(1) steht und nicht f(1)−f(0)f(1) - f(0), 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 (−1)k(-1)^k für jede ganze Zahl kk nur davon abhängt, ob kk gerade oder ungerade ist.

Wendet man das letzte Hadamard-Tor auf das obere Qubit an, so erhält man den Zustand

∣π3⟩={(−1)f(0)∣−⟩∣0⟩if f(0)⊕f(1)=0(−1)f(0)∣−⟩∣1⟩if f(0)⊕f(1)=1,\vert \pi_3 \rangle = \begin{cases} (-1)^{f(0)} \vert - \rangle \vert 0 \rangle & \text{if $f(0) \oplus f(1) = 0$}\\[1mm] (-1)^{f(0)} \vert - \rangle \vert 1 \rangle & \text{if $f(0) \oplus f(1) = 1$}, \end{cases}

was zum richtigen Ergebnis mit der Wahrscheinlichkeit 11 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 b,c∈Σb,c\in\Sigma gilt.

∣b⊕c⟩=Xc∣b⟩\vert b \oplus c\rangle = X^c \vert b \rangle

Dies kann überprüft werden, indem man es für die beiden möglichen Werte c=0c = 0 und c=1c = 1 überprüft:

∣b⊕0⟩=∣b⟩=I∣b⟩=X0∣b⟩∣b⊕1⟩=∣¬b⟩=X∣b⟩=X1∣b⟩.\begin{aligned} \vert b \oplus 0 \rangle & = \vert b\rangle = \mathbb{I} \vert b \rangle = X^0 \vert b \rangle\\ \vert b \oplus 1 \rangle & = \vert \neg b\rangle = X \vert b \rangle = X^1 \vert b \rangle. \end{aligned}

Aus dieser Formel ergibt sich, dass

Uf(∣b⟩∣a⟩)=∣b⊕f(a)⟩∣a⟩=(Xf(a)∣b⟩)∣a⟩U_f \bigl(\vert b\rangle \vert a \rangle\bigr) = \vert b \oplus f(a) \rangle \vert a \rangle = \bigl(X^{f(a)}\vert b \rangle\bigr) \vert a \rangle

für jede Wahl der Bits a,b∈Σa,b\in\Sigma. Da diese Formel für b=0b=0 und b=1b=1 gilt, ergibt sich aufgrund der Linearität, dass

Uf(∣ψ⟩∣a⟩)=(Xf(a)∣ψ⟩)∣a⟩U_f \bigl( \vert \psi \rangle \vert a \rangle \bigr) = \bigl(X^{f(a)}\vert \psi \rangle\bigr) \vert a \rangle

für alle Qubit-Zustandsvektoren ∣ψ⟩\vert \psi\rangle, und daher

Uf(∣−⟩∣a⟩)=(Xf(a)∣−⟩)∣a⟩=(−1)f(a)∣−⟩∣a⟩.U_f \bigl( \vert - \rangle \vert a \rangle \bigr) = \bigl(X^{f(a)} \vert - \rangle \bigr) \vert a \rangle = (-1)^{f(a)} \vert - \rangle \vert a \rangle.

Der Schlüssel zum Erfolg ist, dass X∣−⟩=−∣−⟩X\vert - \rangle = - \vert - \rangle gilt. Mathematisch ausgedrückt ist der Vektor ∣−⟩\vert - \rangle ein Eigenvektor der Matrix XX mit dem Eigenwert −1-1.

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 UfU_f ∣π1⟩\vert \pi_1\rangle in ∣π2⟩\vert \pi_2\rangle umwandelt:

∣π2⟩=Uf(∣−⟩∣+⟩)=12Uf(∣−⟩∣0⟩)+12Uf(∣−⟩∣1⟩)=∣−⟩((−1)f(0)∣0⟩+(−1)f(1)∣1⟩2).\begin{aligned} \vert \pi_2 \rangle & = U_f \bigl( \vert - \rangle \vert + \rangle \bigr)\\ & = \frac{1}{\sqrt{2}} U_f \bigl(\vert - \rangle \vert 0\rangle \bigr) + \frac{1}{\sqrt{2}} U_f \bigl(\vert - \rangle \vert 1\rangle \bigr)\\ & = \vert - \rangle \biggl( \frac{(-1)^{f(0)} \vert 0\rangle + (-1)^{f(1)} \vert 1\rangle}{\sqrt{2}}\biggr). \end{aligned}

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 AerSimulator

Zunächst definieren wir einen Quantenschaltkreis, der ein Abfragegatter für eine der vier zuvor beschriebenen Funktionen „ f1f_1 “, „ f2f_2 “, „ f3f_3 “ oder „ f4f_4 “ 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 f

Mit dieser draw Methode können wir sehen, wie die einzelnen Schaltungen aussehen. Hier ist der Schaltplan für die Funktion „ f3f_3 “.

display(deutsch_function(3).draw(output="mpl"))

Output:

Output of the previous code cell

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 qc

Auch hier können wir sehen, wie die Schaltung nach der Methode draw aussieht.

display(compile_circuit(deutsch_function(3)).draw(output="mpl"))

Output:

Output of the previous code cell

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'
War diese Seite hilfreich?
Melden Sie auf GitHub einen Fehler, einen Tippfehler oder fordern Sie Inhalte an.