Zum Hauptinhalt springen

Quantenbits, Gates und Schaltkreise

hinweis

Kifumi Numata (19 Apr 2024)

Klicke hier, um das PDF der Originalvorlesung herunterzuladen. Beachte, dass einige Code-Snippets veraltet sein könnten, da es sich um statische Bilder handelt.

Ungefähre QPU-Zeit für dieses Experiment: 5 Sekunden.

1. Einführung

Bits, Gates und Schaltkreise sind die grundlegenden Bausteine des Quantencomputings. Du wirst Quantenberechnung mit dem Schaltkreismodell unter Verwendung von Quantenbits und Gates erlernen und außerdem Superposition, Messung und Verschränkung wiederholen.

In dieser Lektion lernst du:

  • Einzelne Qubit-Gates
  • Bloch-Kugel
  • Superposition
  • Messung
  • Zwei-Qubit-Gates und verschränkte Zustände

Am Ende dieser Vorlesung wirst du etwas über die Schaltkreistiefe lernen, die für Quantencomputing im Utility-Scale-Bereich entscheidend ist.

2. Berechnung als Diagramm

Wenn wir Qubits oder Bits verwenden, müssen wir sie manipulieren, um die vorhandenen Eingaben in die benötigten Ausgaben umzuwandeln. Für die einfachsten Programme mit sehr wenigen Bits ist es nützlich, diesen Prozess in einem Diagramm darzustellen, das als Schaltkreisdiagramm bekannt ist.

Die Abbildung unten links zeigt ein Beispiel eines klassischen Schaltkreises, und die Abbildung unten rechts zeigt ein Beispiel eines Quantenschaltkreises. In beiden Fällen befinden sich die Eingaben links und die Ausgaben rechts, während die Operationen durch Symbole dargestellt werden. Die für die Operationen verwendeten Symbole werden hauptsächlich aus historischen Gründen als „Gates" bezeichnet.

"classical logic and quantum circuit"

3. Einzelnes Qubit-Gate

3.1 Quantenzustand und Bloch-Kugel

Der Zustand eines Qubits wird als Superposition von 0|0\rangle und 1|1\rangle dargestellt. Ein beliebiger Quantenzustand wird geschrieben als

ψ=α0+β1|\psi\rangle =\alpha|0\rangle+ \beta|1\rangle

wobei α\alpha und β\beta komplexe Zahlen sind, sodass α2+β2=1|\alpha|^2+|\beta|^2=1.

0|0\rangle und 1|1\rangle sind Vektoren im zweidimensionalen komplexen Vektorraum:

0=(10),1=(01)|0\rangle = \begin{pmatrix} 1 \\0 \end{pmatrix}, |1\rangle = \begin{pmatrix} 0\\1 \end{pmatrix}

Daher wird ein beliebiger Quantenzustand auch dargestellt als

ψ=α(10)+β(01)=(αβ)|\psi\rangle = \alpha\begin{pmatrix} 1 \\ 0 \end{pmatrix} + \beta\begin{pmatrix}0\\ 1 \end{pmatrix} = \begin{pmatrix} \alpha \\ \beta \end{pmatrix}

Daraus können wir erkennen, dass der Zustand eines Quantenbits ein Einheitsvektor in einem zweidimensionalen komplexen Innenproduktraum mit einer orthonormalen Basis aus 0|0\rangle und 1|1\rangle ist. Er ist auf 1 normiert.

ψψ=(αβ)(αβ)=1\langle\psi|\psi\rangle = \begin{pmatrix} \alpha^* & \beta^* \end{pmatrix} \begin{pmatrix} \alpha \\ \beta \end{pmatrix} = 1

|\psi\rangle =\begin\{pmatrix\} \alpha \\ \beta \end\{pmatrix\} wird auch als Zustandsvektor (Statevector) bezeichnet.

Ein einzelner Qubit-Quantenzustand wird auch dargestellt als

ψ=cosθ20+eiφsinθ21=((cosθ2eiφsinθ2))|\psi\rangle =\cos\frac{\theta}{2}|0\rangle+e^{i\varphi}\sin\frac{\theta}{2}|1\rangle =\left( \begin{pmatrix} \cos\frac{\theta}{2}\\ e^{i\varphi}\sin\frac{\theta}{2} \end{pmatrix}\right)

wobei θ\theta und φ\varphi die Winkel der Bloch-Kugel in der folgenden Abbildung sind.

Bloch sphere In den nächsten Code-Zellen werden wir grundlegende Berechnungen aus den Bestandteilen in Qiskit aufbauen. Wir konstruieren einen leeren Schaltkreis und fügen dann Quantenoperationen hinzu, wobei wir die Gates besprechen und ihre Auswirkungen visualisieren. Du kannst die Zelle mit „Shift" + „Enter" ausführen. Importiere zuerst die Bibliotheken.

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-aer qiskit-ibm-runtime
# Import the qiskit library
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
from qiskit.quantum_info import Statevector
from qiskit.visualization import plot_bloch_multivector
from qiskit_ibm_runtime import Sampler
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.visualization import plot_histogram

Vorbereitung des Quantenschaltkreises

Wir erstellen und zeichnen einen Einzelqubit-Schaltkreis.

# Create the single-qubit quantum circuit
qc = QuantumCircuit(1)

# Draw the circuit
qc.draw("mpl")

Output of the previous code cell

X-Gate

Das X-Gate ist eine π\pi-Rotation um die xx-Achse der Bloch-Kugel. Die Anwendung des X-Gates auf 0|0\rangle ergibt 1|1\rangle, und die Anwendung des X-Gates auf 1|1\rangle ergibt 0|0\rangle, sodass es eine Operation ähnlich dem klassischen NOT-Gate ist und auch als Bit-Flip bekannt ist. Die Matrixdarstellung des X-Gates ist unten gezeigt.

X=(0110)X = \begin{pmatrix} 0 & 1 \\ 1 & 0 \\ \end{pmatrix}
qc = QuantumCircuit(1)  # Prepare the single-qubit quantum circuit

# Apply a X gate to qubit 0
qc.x(0)

# Draw the circuit
qc.draw("mpl")

Output of the previous code cell

Bei IBM Quantum® ist der Anfangszustand auf 0|0\rangle gesetzt, sodass der obige Quantenschaltkreis in Matrixdarstellung lautet

X0=(0110)(10)=(01)=1X|0\rangle= \begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix} \begin{pmatrix} 1 \\ 0 \end{pmatrix} =\begin{pmatrix} 0 \\ 1 \end{pmatrix} = |1\rangle

Als Nächstes führen wir diesen Schaltkreis mit einem Zustandsvektor-Simulator aus.

# See the statevector
out_vector = Statevector(qc)
print(out_vector)

# Draw a Bloch sphere
plot_bloch_multivector(out_vector)
Statevector([0.+0.j, 1.+0.j],
dims=(2,))

Output of the previous code cell

Der vertikale Vektor wird als Zeilenvektor angezeigt, mit komplexen Zahlen (der Imaginärteil wird durch jj indiziert).

H-Gate

Das Hadamard-Gate ist eine π\pi-Rotation um eine Achse auf halbem Weg zwischen der xx- und zz-Achse auf der Bloch-Kugel. Die Anwendung des H-Gates auf 0|0\rangle erzeugt einen Superpositionszustand wie 0+12\frac{|0\rangle + |1\rangle}{\sqrt{2}}. Die Matrixdarstellung des H-Gates ist unten gezeigt.

H=12(1111)H = \frac{1}{\sqrt{2}}\begin{pmatrix} 1 & 1 \\ 1 & -1 \\ \end{pmatrix}
qc = QuantumCircuit(1)  # Create the single-qubit quantum circuit

# Apply an Hadamard gate to qubit 0
qc.h(0)

# Draw the circuit
qc.draw(output="mpl")

Output of the previous code cell

# See the statevector
out_vector = Statevector(qc)
print(out_vector)

# Draw a Bloch sphere
plot_bloch_multivector(out_vector)
Statevector([0.70710678+0.j, 0.70710678+0.j],
dims=(2,))

Output of the previous code cell

Das ist

H0=12(1111)(10)=12(11)=(0.7070.707)=12(0+1)H|0\rangle= \frac{1}{\sqrt{2}} \begin{pmatrix} 1 & 1 \\ 1 & -1 \end{pmatrix} \begin{pmatrix} 1 \\0 \end{pmatrix} =\frac{1}{\sqrt{2}}\begin{pmatrix} 1 \\ 1 \end{pmatrix} =\begin{pmatrix} 0.707 \\ 0.707 \end{pmatrix} =\frac{1}{\sqrt{2}}(|0\rangle+|1\rangle)

Dieser Superpositionszustand ist so häufig und wichtig, dass er sein eigenes Symbol hat:

+12(0+1).|+\rangle \equiv \frac{1}{\sqrt{2}}(|0\rangle+|1\rangle).

Durch Anwendung des HH-Gates auf den 0|0\rangle haben wir eine Superposition aus 0|0\rangle und 1|1\rangle erzeugt, bei der eine Messung in der Rechenbasis (entlang z im Bloch-Kugel-Bild) jeden Zustand mit gleicher Wahrscheinlichkeit ergibt.

|-\rangle-Zustand

Du hast vielleicht vermutet, dass es einen entsprechenden |-\rangle-Zustand gibt:

012.|-\rangle \equiv \frac{|0\rangle -|1\rangle}{\sqrt{2}}.

Um diesen Zustand zu erzeugen, wende zuerst ein X-Gate an, um 1|1\rangle zu erhalten, und dann ein H-Gate.

qc = QuantumCircuit(1)  # Create the single-qubit quantum circuit

# Apply a X gate to qubit 0
qc.x(0)

# Apply an Hadamard gate to qubit 0
qc.h(0)

# draw the circuit
qc.draw(output="mpl")

Output of the previous code cell

# See the statevector
out_vector = Statevector(qc)
print(out_vector)

# Draw a Bloch sphere
plot_bloch_multivector(out_vector)
Statevector([ 0.70710678+0.j, -0.70710678+0.j],
dims=(2,))

Output of the previous code cell

Das ist

H1=12(11 11)(0 1)=12(1 1)=(0.707 0.707)=12(01)=H|1\rangle= \frac{1}{\sqrt{2}} \begin{pmatrix} 1 & 1 \\\ 1 & -1 \end{pmatrix} \begin{pmatrix} 0 \\\ 1 \end{pmatrix} =\frac{1}{\sqrt{2}}\begin{pmatrix} 1 \\\ -1 \end{pmatrix} =\begin{pmatrix} 0.707 \\\ -0.707 \end{pmatrix} =\frac{1}{\sqrt{2}}(|0\rangle-|1\rangle) = |-\rangle

Die Anwendung des HH-Gates auf 1|1\rangle ergibt eine gleichmäßige Superposition aus 0|0\rangle und 1|1\rangle, aber das Vorzeichen von 1|1\rangle ist negativ.

3.2 Einzelner Qubit-Quantenzustand und unitäre Evolution

Die Wirkungen aller Gates, die wir bisher gesehen haben, waren unitär, was bedeutet, dass sie durch einen unitären Operator dargestellt werden können. Mit anderen Worten, der Ausgabezustand kann durch Anwendung einer unitären Matrix auf den Anfangszustand erhalten werden:

ψ=Uψ|\psi^{'}\rangle = U|\psi\rangle

Eine unitäre Matrix ist eine Matrix, die folgende Bedingung erfüllt

UU=UU=I.U^{\dagger}U =U U^{\dagger} = I.

In Bezug auf den Betrieb von Quantencomputern würden wir sagen, dass die Anwendung eines Quanten-Gates auf das Qubit den Quantenzustand entwickelt. Häufige Einzelqubit-Gates umfassen die folgenden.

Pauli-Gates:

X=(0110)=01+10X = \begin{pmatrix} 0 & 1 \\ 1 & 0 \\ \end{pmatrix} = |0\rangle \langle 1|+|1\rangle \langle 0| Y=(0ii0)=i01+i10Y = \begin{pmatrix} 0 & -i \\ i & 0 \\ \end{pmatrix} = -i|0\rangle \langle 1|+i|1\rangle \langle 0| Z=(1001)=0011Z = \begin{pmatrix} 1 & 0 \\ 0 & -1 \\ \end{pmatrix} = |0\rangle \langle 0|-|1\rangle \langle 1|

wobei das äußere Produkt wie folgt berechnet wurde:

00=[10][10]=[1000],10=[01][10]=[0010],|0\rangle \langle 0|= \begin{bmatrix} 1 \\ 0 \end{bmatrix} \begin{bmatrix} 1 & 0 \end{bmatrix} =\begin{bmatrix} 1 & 0 \\ 0 & 0 \\ \end{bmatrix}, \quad |1\rangle \langle 0|= \begin{bmatrix} 0 \\ 1 \end{bmatrix} \begin{bmatrix} 1 & 0 \end{bmatrix} =\begin{bmatrix} 0 & 0 \\ 1 & 0 \\ \end{bmatrix}, \quad 01=[10][01]=[0100],11=[01][01]=[0001],|0\rangle \langle 1|= \begin{bmatrix} 1 \\ 0 \end{bmatrix} \begin{bmatrix} 0 & 1 \end{bmatrix} =\begin{bmatrix} 0 & 1 \\ 0 & 0 \\ \end{bmatrix}, \quad |1\rangle \langle 1|= \begin{bmatrix} 0 \\ 1 \end{bmatrix} \begin{bmatrix} 0 & 1 \end{bmatrix} =\begin{bmatrix} 0 & 0 \\ 0 & 1 \\ \end{bmatrix}, \quad

Weitere typische Einzelqubit-Gates:

H=12[1111],S=[100i],T=[100exp(iπ/4)]H= \frac{1}{\sqrt{2}}\begin{bmatrix} 1 & 1 \\ 1 & -1 \\ \end{bmatrix},\quad S = \begin{bmatrix} 1 & 0 \\ 0 & i \\ \end{bmatrix}, \quad T = \begin{bmatrix} 1 & 0 \\ 0 & exp(i\pi/4) \\ \end{bmatrix} Rx(θ)=eiθX/2=cosθ2Iisinθ2X=[cosθ2isinθ2isinθ2cosθ2]R_x(\theta) = e^{-i\theta X/2} = cos\frac{\theta}{2}I - i sin \frac{\theta}{2}X = \begin{bmatrix} cos\frac{\theta}{2} & -i sin \frac{\theta}{2} \\ -i sin \frac{\theta}{2} & cos\frac{\theta}{2} \\ \end{bmatrix} Ry(θ)=eiθY/2=cosθ2Iisinθ2Y=[cosθ2sinθ2sinθ2cosθ2]R_y(\theta) = e^{-i\theta Y/2} = cos\frac{\theta}{2}I - i sin \frac{\theta}{2}Y = \begin{bmatrix} cos\frac{\theta}{2} & - sin \frac{\theta}{2} \\ sin \frac{\theta}{2} & cos\frac{\theta}{2} \\ \end{bmatrix} Rz(θ)=eiθZ/2=cosθ2Iisinθ2Z=[eiθ/200eiθ/2]R_z(\theta) = e^{-i\theta Z/2} = cos\frac{\theta}{2}I - i sin \frac{\theta}{2}Z = \begin{bmatrix} e^{-i\theta /2} & 0 \\ 0 & e^{i\theta /2} \\ \end{bmatrix}

Die Bedeutung und Verwendung dieser Gates wird im Kurs Grundlagen der Quanteninformation detaillierter beschrieben.

Übung 1

Verwende Qiskit, um Quantenschaltkreise zu erstellen, die die unten beschriebenen Zustände vorbereiten. Führe dann jeden Schaltkreis mit dem Zustandsvektor-Simulator aus und zeige den resultierenden Zustand auf der Bloch-Kugel an. Als Bonus: Versuche vorherzusagen, was der Endzustand basierend auf der Intuition über die Gates und Rotationen in der Bloch-Kugel sein sollte.

(1) XX0XX|0\rangle

(2) HH0HH|0\rangle

(3) HZH0HZH|0\rangle

Tipps: Das Z-Gate kann wie folgt verwendet werden

qc.z(0)

Lösung:

### (1) XX|0> ###

# Create the single-qubit quantum circuit
qc = QuantumCircuit(1) ##your code goes here##

# Add a X gate to qubit 0
qc.x(0) ##your code goes here##

# Add a X gate to qubit 0
qc.x(0) ##your code goes here##

# Draw a circuit
qc.draw(output="mpl")

Output of the previous code cell

# See the statevector
out_vector = Statevector(qc)
print(out_vector)

# Draw a Bloch sphere
plot_bloch_multivector(out_vector)
Statevector([1.+0.j, 0.+0.j],
dims=(2,))

Output of the previous code cell

### (2) HH|0> ###
##your code goes here##
qc = QuantumCircuit(1)
qc.h(0)
qc.h(0)
qc.draw("mpl")

Output of the previous code cell

# See the statevector
out_vector = Statevector(qc)
print(out_vector)

# Draw a Bloch sphere
plot_bloch_multivector(out_vector)
Statevector([1.+0.j, 0.+0.j],
dims=(2,))

Output of the previous code cell

### (3) HZH|0> ###
##your code goes here##
qc = QuantumCircuit(1)
qc.h(0)
qc.z(0)
qc.h(0)
qc.draw("mpl")

Output of the previous code cell

# See the statevector
out_vector = Statevector(qc)
print(out_vector)

# Draw a Bloch sphere
plot_bloch_multivector(out_vector)
Statevector([0.+0.j, 1.+0.j],
dims=(2,))

Output of the previous code cell

3.3 Messung

Messung ist theoretisch ein sehr kompliziertes Thema. Aber in praktischer Hinsicht zwingt eine Messung entlang zz (wie es alle IBM®-Quantencomputer tun) den Zustand des Qubits α0+β1(s.t.α2+β2=1)\alpha|0\rangle+\beta|1\rangle \quad (s.t.|\alpha|^2+|\beta|^2=1) einfach in 0|0\rangle oder 1,|1\rangle, und wir beobachten das Ergebnis.

  • α2|\alpha|^2 ist die Wahrscheinlichkeit, dass wir 0|0\rangle erhalten, wenn wir messen.
  • β2|\beta|^2 ist die Wahrscheinlichkeit, dass wir 1|1\rangle erhalten, wenn wir messen.

Also werden α\alpha und β\beta als Wahrscheinlichkeitsamplituden bezeichnet. (siehe „Born-Regel")

Zum Beispiel hat 220+221\frac{\sqrt{2}}{2}|0\rangle+\frac{\sqrt{2}}{2}|1\rangle eine gleiche Wahrscheinlichkeit, bei der Messung zu 0|0\rangle oder 1|1\rangle zu werden. 32012i1\frac{\sqrt{3}}{2}|0\rangle-\frac{1}{2}i|1\rangle hat eine 75%ige Chance, zu 0|0\rangle zu werden.

Qiskit Aer Simulator

Als Nächstes messen wir einen Schaltkreis, der die obige Superposition mit gleicher Wahrscheinlichkeit vorbereitet. Wir sollten die Mess-Gates hinzufügen, da der Qiskit Aer Simulator standardmäßig eine ideale (rauschfreie) Quantenhardware simuliert. Hinweis: Der Aer Simulator kann auch ein Rauschmodell basierend auf einem echten Quantencomputer anwenden. Wir werden später auf Rauschmodelle zurückkommen.

# Create a new circuit with one qubits (first argument) and one classical bits (second argument)
qc = QuantumCircuit(1, 1)
qc.h(0)
qc.measure(0, 0) # Add the measurement gate

qc.draw(output="mpl")

Output of the previous code cell

Wir sind nun bereit, unseren Schaltkreis auf dem Aer Simulator auszuführen. In diesem Beispiel verwenden wir die Standardeinstellung shots=1024, was bedeutet, dass wir 1024 Mal messen. Dann stellen wir diese Zähler in einem Histogramm dar.

# Run the circuit on a simulator to get the results
# Define backend
backend = AerSimulator()

# Transpile to backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)

# Run the job
sampler = Sampler(mode=backend)
job = sampler.run([isa_qc])
result = job.result()

# Print the results
counts = result[0].data.c.get_counts()
print(counts)

# Plot the counts in a histogram
plot_histogram(counts)
{'0': 521, '1': 503}

Output of the previous code cell

Wir sehen, dass 0en und 1en jeweils mit einer Wahrscheinlichkeit von fast 50% gemessen wurden. Obwohl hier kein Rauschen simuliert wurde, sind die Zustände dennoch probabilistisch. Obwohl wir ungefähr eine 50-50-Verteilung erwarten, werden wir diese selten genau finden. Genauso wie 100 Münzwürfe selten genau 50 Instanzen jeder Seite ergeben würden.

4. Multi-Qubit-Gate und Verschränkung

4.1 Multi-Qubit-Quantenschaltkreis

Wir können einen Zwei-Qubit-Quantenschaltkreis mit folgendem Code erstellen. Wir werden ein H-Gate auf jedes Qubit anwenden.

# Create the two qubits quantum circuit
qc = QuantumCircuit(2)

# Apply an H gate to qubit 0
qc.h(0)

# Apply an H gate to qubit 1
qc.h(1)

# Draw the circuit
qc.draw(output="mpl")

Output of the previous code cell

# See the statevector
out_vector = Statevector(qc)
print(out_vector)
Statevector([0.5+0.j, 0.5+0.j, 0.5+0.j, 0.5+0.j],
dims=(2, 2))

Hinweis: Qiskit-Bit-Reihenfolge

Qiskit verwendet die Little-Endian-Notation bei der Anordnung von Qubits und Bits, was bedeutet, dass Qubit 0 das rechteste Bit in den Bitstrings ist. Beispiel: 01|01\rangle bedeutet q0 ist 1|1\rangle und q1 ist 0|0\rangle. Sei vorsichtig, denn einige Literatur im Quantencomputing verwendet die Big-Endian-Notation (Qubit 0 ist das linkeste Bit), und ein großer Teil der Quantenmechanik-Literatur ebenfalls.

Außerdem ist zu beachten, dass bei der Darstellung eines Quantenschaltkreises q0|q_0\rangle immer oben im Schaltkreis platziert wird. Mit diesem Wissen kann der Quantenzustand des obigen Schaltkreises als Tensorprodukt einzelner Qubit-Quantenzustände geschrieben werden.

q1q0=(a0+b1)(c0+d1)|q1\rangle \otimes|q0\rangle = (a|0\rangle+b|1\rangle) \otimes (c|0\rangle+d|1\rangle)

=ac00+ad01+bc10+bd11= ac|0\rangle|0\rangle+ad|0\rangle|1\rangle+bc|1\rangle|0\rangle+bd|1\rangle|1\rangle

=ac00+ad01+bc10+bd11= ac|00\rangle+ad|01\rangle+bc|10\rangle+bd|11\rangle

( ac2+ad2+bc2+bd2=1|ac|^2+ |ad|^2+ |bc|^2+ |bd|^2=1 )

Der Anfangszustand von Qiskit ist 00=00|0\rangle|0\rangle=|00\rangle, sodass er sich durch Anwendung von HH auf jedes Qubit in einen Zustand gleichmäßiger Superposition ändert.

H0H0=12(0+1)12(0+1)=12(00+01+10+11)H|0\rangle \otimes H|0\rangle=\frac{1}{\sqrt{2}}(|0\rangle+|1\rangle) \otimes \frac{1}{\sqrt{2}}(|0\rangle+|1\rangle) = \frac{1}{2}(|00\rangle+|01\rangle+|10\rangle+|11\rangle)

=12((11)(11))=12(1111)=12((1000)+(0100)+(0010)+(0001))=\frac{1}{2}\left( \begin{pmatrix} 1 \\ 1 \end{pmatrix} \otimes \begin{pmatrix} 1 \\ 1 \end{pmatrix}\right) = \frac{1}{2}\begin{pmatrix} 1 \\ 1 \\ 1 \\ 1 \end{pmatrix}=\frac{1}{2}\left(\begin{pmatrix} 1 \\ 0 \\ 0 \\ 0 \end{pmatrix}+\begin{pmatrix} 0 \\ 1 \\ 0 \\ 0 \end{pmatrix}+\begin{pmatrix} 0 \\ 0 \\ 1 \\ 0 \end{pmatrix}+\begin{pmatrix} 0 \\ 0 \\ 0 \\ 1 \end{pmatrix}\right)

Die Messregel ist dieselbe wie im Einzelqubit-Fall: Die Wahrscheinlichkeit, 00|00\rangle zu messen, beträgt ac2|ac|^2.

# Draw a Bloch sphere
plot_bloch_multivector(out_vector)

Output of the previous code cell

Als Nächstes messen wir diesen Schaltkreis.

# Create a new circuit with two qubits (first argument) and two classical bits (second argument)
qc = QuantumCircuit(2, 2)

# Apply the gates
qc.h(0)
qc.h(1)

# Add the measurement gates
qc.measure(0, 0) # Measure qubit 0 and save the result in bit 0
qc.measure(1, 1) # Measure qubit 1 and save the result in bit 1

# Draw the circuit
qc.draw(output="mpl")

Output of the previous code cell

Nun werden wir erneut den Aer Simulator verwenden, um experimentell zu überprüfen, dass die relativen Wahrscheinlichkeiten aller möglichen Ausgabezustände ungefähr gleich sind.

# Run the circuit on a simulator to get the results
# Define backend
backend = AerSimulator()

# Transpile to backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)

# Run the job
sampler = Sampler(mode=backend)
job = sampler.run([isa_qc])
result = job.result()

# Print the results
counts = result[0].data.c.get_counts()
print(counts)

# Plot the counts in a histogram
plot_histogram(counts)
{'10': 262, '01': 246, '00': 265, '11': 251}

Output of the previous code cell

Wie erwartet wurden die Zustände 00|00\rangle, 01|01\rangle, 10|10\rangle, 11|11\rangle jeweils mit fast 25% gemessen.

4.2 Multi-Qubit-Gates

CNOT-Gate

Ein CNOT-Gate („controlled NOT" oder CX) ist ein Zwei-Qubit-Gate, dessen Aktion zwei Qubits gleichzeitig einbezieht: das Steuerqubit und das Zielqubit. Ein CNOT kippt das Zielqubit nur dann, wenn das Steuerqubit 1|1\rangle ist.

Eingabe (Ziel,Steuer)Ausgabe (Ziel,Steuer)
0000
0111
1010
1101

Simulieren wir zunächst die Wirkung dieses Zwei-Qubit-Gates, wenn q0 und q1 beide 0|0\rangle sind, und erhalten den Ausgabe-Zustandsvektor. Die verwendete Qiskit-Syntax lautet qc.cx(control qubit, target qubit).

# Create a circuit with two quantum registers and two classical registers
qc = QuantumCircuit(2, 2)

# Apply the CNOT (cx) gate to a |00> state.
qc.cx(0, 1) # Here the control is set to q0 and the target is set to q1.

# Draw the circuit
qc.draw(output="mpl")

Output of the previous code cell

# See the statevector
out_vector = Statevector(qc)
print(out_vector)
Statevector([1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
dims=(2, 2))

Wie erwartet hat die Anwendung eines CNOT-Gates auf 00|00\rangle den Zustand nicht verändert, da das Steuerqubit im 0|0\rangle-Zustand war. Kehren wir zu unserer CNOT-Operation zurück. Diesmal wenden wir ein CNOT-Gate auf 01|01\rangle an und sehen, was passiert.

qc = QuantumCircuit(2, 2)

# q0=1, q1=0
qc.x(0) # Apply a X gate to initialize q0 to 1
qc.cx(0, 1) # Set the control bit to q0 and the target bit to q1.

# Draw the circuit
qc.draw(output="mpl")

Output of the previous code cell

# See the statevector
out_vector = Statevector(qc)
print(out_vector)
Statevector([0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],
dims=(2, 2))

Durch die Anwendung eines CNOT-Gates ist der 01|01\rangle-Zustand nun zu 11|11\rangle geworden.

Verifizieren wir diese Ergebnisse, indem wir den Schaltkreis auf einem Simulator ausführen.

# Add measurements
qc.measure(0, 0)
qc.measure(1, 1)

# Draw the circuit
qc.draw(output="mpl")

Output of the previous code cell

# Run the circuit on a simulator to get the results
# Define backend
backend = AerSimulator()

# Transpile to backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)

# Run the job
sampler = Sampler(backend)
job = sampler.run([isa_qc])
result = job.result()

# Print the results
counts = result[0].data.c.get_counts()
print(counts)

# Plot the counts in a histogram
plot_histogram(counts)
{'11': 1024}

Output of the previous code cell

Die Ergebnisse sollten zeigen, dass 11|11\rangle mit 100% Wahrscheinlichkeit gemessen wurde.

4.3 Quantenverschränkung und Ausführung auf einem echten Quantengerät

Beginnen wir mit der Einführung eines bestimmten verschränkten Zustands, der in der Quantenberechnung besonders wichtig ist, und definieren dann den Begriff „verschränkt":

1200+1211\frac{1}{\sqrt{2}}|00\rangle + \frac{1}{\sqrt{2}}|11\rangle

und dieser Zustand wird als Bell-Zustand bezeichnet.

Ein verschränkter Zustand ist ein Zustand ψAB|\psi_{AB}\rangle, bestehend aus den Quantenzuständen ψA|\psi_A\rangle und ψB|\psi_B\rangle, der nicht als Tensorprodukt einzelner Quantenzustände dargestellt werden kann.

Wenn ψAB|\psi_{AB}\rangle unten zwei Zustände ψA|\psi\rangle_A und ψB|\psi\rangle_B hat;

ψAB=12(00+11)=12(0A0B+1A1B)|\psi_{AB}\rangle = \frac{1}{\sqrt{2}}(|00\rangle +|11\rangle) = \frac{1}{\sqrt{2}}(|0\rangle_A|0\rangle_B +|1\rangle_A|1\rangle_B) ψA=a00+a11|\psi\rangle_A = a_0|0\rangle+a_1|1\rangle ψB=b00+b11|\psi\rangle_B = b_0|0\rangle+b_1|1\rangle

ist das Tensorprodukt dieser beiden Zustände das Folgende

ψAψB=a0b000+a0b101+a1b010+a1b111|\psi\rangle _A\otimes |\psi\rangle _B = a_0 b_0|00\rangle+a_0 b_1|01\rangle+a_1 b_0|10\rangle+a_1 b_1|11\rangle

aber es gibt keine Koeffizienten a0,a1,b0,a_0, a_1, b_0, und b1b_1, die diese beiden Gleichungen erfüllen. Daher wird ψAB|\psi_{AB}\rangle nicht als Tensorprodukt einzelner Quantenzustände ψA|\psi\rangle_A und ψB|\psi\rangle_B dargestellt, und das bedeutet, dass ψAB=12(00+11)|\psi_{AB}\rangle = \frac{1}{\sqrt{2}}(|00\rangle +|11\rangle) ein verschränkter Zustand ist.

Erstellen wir den Bell-Zustand und führen ihn auf einem echten Quantencomputer aus. Jetzt folgen wir den vier Schritten zum Schreiben eines Quantenprogramms, den sogenannten Qiskit Patterns:

  1. Problem auf Quantenschaltkreise und Operatoren abbilden
  2. Für die Zielhardware optimieren
  3. Auf der Zielhardware ausführen
  4. Ergebnisse nachbearbeiten

Schritt 1. Problem auf Quantenschaltkreise und Operatoren abbilden

In einem Quantenprogramm sind Quantenschaltkreise das native Format zur Darstellung von Quantenanweisungen. Beim Erstellen eines Schaltkreises erstellst du normalerweise ein neues QuantumCircuit-Objekt und fügst dann nacheinander Anweisungen hinzu.

Die folgende Code-Zelle erstellt einen Schaltkreis, der einen Bell-Zustand erzeugt, den oben beschriebenen spezifischen verschränkten Zwei-Qubit-Zustand.

qc = QuantumCircuit(2, 2)

qc.h(0)
qc.cx(0, 1)

qc.measure(0, 0)
qc.measure(1, 1)

qc.draw("mpl")

Output of the previous code cell

Schritt 2. Für die Zielhardware optimieren

Qiskit wandelt abstrakte Schaltkreise in QISA (Quantum Instruction Set Architecture)-Schaltkreise um, die die Einschränkungen der Zielhardware berücksichtigen, und optimiert die Schaltkreisleistung. Vor der Optimierung legen wir also die Zielhardware fest. Wenn du qiskit-ibm-runtime nicht hast, musst du dies zuerst installieren. Weitere Informationen über Qiskit Runtime findest du in der API-Referenz.

# Install
# !pip install qiskit-ibm-runtime

Wir legen die Zielhardware fest.

from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()
service.backends()
# You can specify the device
# backend = service.backend('ibm_kingston')
# You can also identify the least busy device
backend = service.least_busy(operational=True)
print("The least busy device is ", backend)

Das Transpilieren des Schaltkreises ist ein weiterer komplexer Prozess. Sehr kurz zusammengefasst: Es schreibt den Schaltkreis in einen logisch äquivalenten um, der „native Gates" verwendet (Gates, die ein bestimmter Quantencomputer implementieren kann), und bildet die Qubits in deinem Schaltkreis auf optimale reale Qubits auf dem Ziel-Quantencomputer ab. Weitere Informationen zur Transpilation findest du in dieser Dokumentation.

# Transpile the circuit into basis gates executable on the hardware
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
target_circuit = pm.run(qc)

target_circuit.draw("mpl", idle_wires=False)

Du kannst sehen, dass der Schaltkreis bei der Transpilation mit neuen Gates umgeschrieben wurde. Weitere Informationen findest du in der ECRGate-Dokumentation.

Schritt 3. Den Zielschaltkreis ausführen

Jetzt führen wir den Zielschaltkreis auf dem echten Gerät aus.

sampler = Sampler(backend)
job_real = sampler.run([target_circuit])

job_id = job_real.job_id()
print("job id:", job_id)

Die Ausführung auf dem echten Gerät kann eine Wartezeit in einer Warteschlange erfordern, da Quantencomputer wertvolle Ressourcen sind und sehr stark nachgefragt werden. Die job_id wird verwendet, um den Ausführungsstatus und die Ergebnisse des Jobs später zu überprüfen.

# Check the job status (replace the job id below with your own)
job_real.status(job_id)

Du kannst den Job-Status auch über dein IBM Quantum Dashboard überprüfen: https://quantum.cloud.ibm.com/workloads

# If the Notebook session got disconnected you can also check your job status by running the following code
from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()
job_real = service.job(job_id) # Input your job-id between the quotations
job_real.status()
# Execute after job has successfully run
result_real = job_real.result()
print(result_real[0].data.c.get_counts())

Schritt 4. Ergebnisse nachbearbeiten

Schließlich müssen wir unsere Ergebnisse nachbearbeiten, um Ausgaben im erwarteten Format zu erstellen, wie Werte oder Grafiken.

plot_histogram(result_real[0].data.c.get_counts())

Wie du sehen kannst, werden 00|00\rangle und 11|11\rangle am häufigsten beobachtet. Es gibt einige Ergebnisse, die von den erwarteten Daten abweichen, und diese sind auf Rauschen und Qubit-Dekohärenz zurückzuführen. Wir werden in späteren Lektionen dieses Kurses mehr über Fehler und Rauschen in Quantencomputern erfahren.

4.4 GHZ-Zustand

Das Konzept der Verschränkung kann auf Systeme mit mehr als zwei Qubits erweitert werden. Der GHZ-Zustand (Greenberger-Horne-Zeilinger-Zustand) ist ein maximal verschränkter Zustand von drei oder mehr Qubits. Der GHZ-Zustand für drei Qubits ist definiert als

12(000+111)\frac{1}{\sqrt 2}(|000\rangle + |111\rangle)

Er kann mit dem folgenden Quantenschaltkreis erstellt werden.

qc = QuantumCircuit(3, 3)

qc.h(0)
qc.cx(0, 1)
qc.cx(1, 2)

qc.measure(0, 0)
qc.measure(1, 1)
qc.measure(2, 2)

qc.draw("mpl")

Output of the previous code cell

Die „Tiefe" eines Quantenschaltkreises ist eine nützliche und gebräuchliche Metrik zur Beschreibung von Quantenschaltkreisen. Verfolge einen Pfad durch den Quantenschaltkreis von links nach rechts und wechsle nur dann die Qubits, wenn sie durch ein Multi-Qubit-Gate verbunden sind. Zähle die Anzahl der Gates entlang dieses Pfades. Die maximale Anzahl von Gates für jeden solchen Pfad durch einen Schaltkreis ist die Tiefe. In modernen verrauschten Quantencomputern haben Schaltkreise mit geringer Tiefe weniger Fehler und liefern wahrscheinlich gute Ergebnisse. Sehr tiefe Schaltkreise hingegen nicht.

Mit QuantumCircuit.depth() können wir die Tiefe unseres Quantenschaltkreises überprüfen. Die Tiefe des obigen Schaltkreises beträgt 4. Das oberste Qubit hat nur drei Gates einschließlich der Messung. Aber es gibt einen Pfad vom obersten Qubit hinunter zu Qubit 1 oder Qubit 2, der ein weiteres CNOT-Gate einschließt.

qc.depth()
4

Übung 2

Der GHZ-Zustand eines 8-Qubit-Systems ist

12(00000000+11111111)\frac{1}{\sqrt 2}(|00000000\rangle + |11111111\rangle)

Schreibe Code, um diesen Zustand mit dem flachstmöglichen Schaltkreis vorzubereiten. Die Tiefe des flachsten Quantenschaltkreises beträgt 5, einschließlich der Mess-Gates.

Lösung:

# Step 1
qc = QuantumCircuit(8, 8)

##your code goes here##
qc.h(0)
qc.cx(0, 4)
qc.cx(4, 6)
qc.cx(6, 7)

qc.cx(4, 5)

qc.cx(0, 2)
qc.cx(2, 3)

qc.cx(0, 1)
qc.barrier() # for visual separation

# measure
for i in range(8):
qc.measure(i, i)

qc.draw("mpl")
# print(qc.depth())

Output of the previous code cell

print(qc.depth())
5
from qiskit.visualization import plot_histogram
# Step 2
# For this exercise, the circuit and operators are simple, so no optimizations are needed.

# Step 3
# Run the circuit on a simulator to get the results
backend = AerSimulator()

pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)

sampler = Sampler(mode=backend)
job = sampler.run([isa_qc], shots=1024)
result = job.result()

counts = result[0].data.c.get_counts()
print(counts)

# Step 4
# Plot the counts in a histogram

plot_histogram(counts)
{'11111111': 535, '00000000': 489}

Output of the previous code cell

5. Zusammenfassung

Du hast Quantenberechnung mit dem Schaltkreismodell unter Verwendung von Quantenbits und Gates gelernt und Superposition, Messung und Verschränkung wiederholt. Du hast außerdem die Methode gelernt, den Quantenschaltkreis auf dem echten Quantengerät auszuführen.

In der letzten Übung zur Erstellung eines GHZ-Schaltkreises hast du versucht, die Schaltkreistiefe zu reduzieren, was ein wichtiger Faktor für die Erzielung einer Utility-Scale-Lösung auf einem verrauschten Quantencomputer ist. In späteren Lektionen dieses Kurses wirst du mehr über Rauschen und Methoden zur Fehlerminderung im Detail erfahren. In dieser Lektion haben wir als Einführung die Reduzierung der Schaltkreistiefe auf einem idealen Gerät betrachtet, aber in der Realität müssen wir die Einschränkungen des echten Geräts berücksichtigen, wie z.B. die Qubit-Konnektivität. Du wirst in den folgenden Lektionen dieses Kurses mehr darüber erfahren.

# See the version of Qiskit
import qiskit

qiskit.__version__
'2.0.2'