Unbestimmtheit erkunden
Für dieses Qiskit-in-Classrooms-Modul benötigen Studierende eine funktionierende Python-Umgebung mit den folgenden installierten Paketen:
qiskitv2.1.0 oder neuerqiskit-ibm-runtimev0.40.1 oder neuerqiskit-aerv0.17.0 oder neuerqiskit.visualizationnumpypylatexenc
Zur Einrichtung und Installation der oben genannten Pakete siehe die Anleitung Qiskit installieren. Um Jobs auf echten Quantencomputern auszuführen, müssen Studierende ein Konto bei IBM Quantum® einrichten, indem sie den Schritten in der Anleitung IBM Cloud-Konto einrichten folgen.
Dieses Modul wurde getestet und verbrauchte 8 Minuten QPU-Zeit. Dies ist nur eine Schätzung. Dein tatsächlicher Verbrauch kann abweichen. Zwei zeitaufwendige Berechnungen sind als solche in den Header-Kommentaren gekennzeichnet und können auf Simulatoren ausgeführt werden, wenn den Studierenden die QPU-Zeit knapp wird. Ohne diese benötigt das Modul nur ~30 Sekunden QPU-Zeit.
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-aer qiskit-ibm-runtime
# Uncomment and modify this line as needed to install dependencies
#!pip install 'qiskit>=2.1.0' 'qiskit-ibm-runtime>=0.40.1' 'qiskit-aer>=0.17.0' 'numpy' 'pylatexenc'
Sieh dir unten die Modulvorstellung von Dr. Katie McCormick an, oder klicke hier, um sie auf YouTube anzusehen.
Einführung
Du hast wahrscheinlich schon von der Unbestimmtheitsrelation gehört, auch außerhalb deiner Physikkurse. Eine gängige umgangssprachliche Umschreibung der Unbestimmtheit lautet: „Indem man etwas betrachtet, beeinflusst man es." Das ist sicherlich wahr. Aber eine physikalisch treffendere Beschreibung der Unbestimmtheit besagt, dass es bestimmte physikalische Observable gibt, die eine Inkompatibilität aufweisen, die verhindert, dass beide gleichzeitig mit beliebiger Genauigkeit bekannt sind. Viele Studierende begegnen erstmals dem Paar inkompatibler Variablen und , also der Position entlang einer Achse, die als -Achse bezeichnet wird, und dem linearen Impuls in diese Richtung. Für diese Variablen wird die Unbestimmtheitsrelation geschrieben als Hier wird als „Unbestimmtheit in " bezeichnet, was dieselbe Definition wie die Standardabweichung in der Statistik hat und definiert werden kann als ist auf die gleiche Weise definiert. Hier werden wir diese Unbestimmtheitsrelation nicht herleiten; wir werden darauf hinweisen, dass sie mit unserem Verständnis klassischer Wellen konsistent ist. Das heißt, eine Welle mit wirklich einer perfekten Frequenz und Wellenlänge würde ewig als perfekte Sinuswelle weiterlaufen. Quantenmechanisch würde dies einem perfekt bekannten Impuls nach der de-Broglie-Hypothese entsprechen: . Aber um zu wissen, sich ein wellenartiges Teilchen befindet, muss die Welle, die es beschreibt, im Raum schärfer lokalisiert werden, wie zum Beispiel eine sehr schmale Gauß-Funktion. Wir wissen, dass wir jede stetige Funktion, einschließlich solcher scharf lokalisierter Wellenfunktionen, als Fourier-Reihe von Sinusfunktionen mit verschiedenen Wellenlängen ausdrücken können. Aber je schärfer die Wellenfunktion lokalisiert wird (und die Position besser bekannt ist), desto mehr Terme benötigen wir in der Fourier-Reihe, was eine Mischung aus mehr Wellenlängen (und damit quantenmechanisch mehr Impulswerten) bedeutet.
Einfacher ausgedrückt: Ein Zustand mit einem wohldefinierten Impuls (eine perfekte Sinuswelle im Raum) hat eine sehr unbestimmte Position. Ein Zustand mit einer wohldefinierten Position (wie eine Dirac-Delta-Distribution) hat einen sehr unbestimmten Impuls.
Es gibt weitere Variablen, die eine solche Inkompatibilität aufweisen. Zum Beispiel kann der Spin eines Teilchens eine wohldefinierte Projektion entlang einer Achse haben, aber dann wissen wir nichts über die Projektion auf eine orthogonale Achse. Beispielsweise hat der Zustand (für ein Qubit oder Spin-1/2-Teilchen) eine bestimmte Projektion entlang der -Achse (von 1 im Kontext eines Qubits und von im Kontext eines Spin-1/2-Teilchens). Aber dieser Zustand kann als Überlagerung zweier Zustände geschrieben werden, die jeweils eine wohldefinierte Projektion auf die -Achse haben: oder äquivalent hat eine wohldefinierte Projektion auf , ebenso . Wenn wir also die Projektion eines Zustands entlang der -Achse festlegen, kennen wir die Projektion entlang der -Achse nicht. Und wenn wir die Projektion auf die -Achse festlegen, kennen wir die Projektion entlang nicht. Es gibt geringfügige Unterschiede, wenn man dies im Kontext von Spin und Qubits diskutiert. Aber allgemein gesprochen haben Eigenzustände der Pauli-Matrizen eine interessante Beziehung, die wir erkunden können. In dieser Lektion werden wir experimentell unsere Intuition für die Unbestimmtheit dieser inkompatiblen Variablen überprüfen und verifizieren, dass Unbestimmtheitsrelationen auf IBM®-Quantencomputern gelten.
Einfache Intuitionsüberprüfung
In diesem ersten Experiment und im gesamten Modul werden wir ein Framework für Quantencomputing namens „Qiskit Patterns" verwenden, das Arbeitsabläufe in die folgenden Schritte unterteilt:
- Schritt 1: Klassische Eingaben auf ein Quantenproblem abbilden
- Schritt 2: Problem für die Quantenausführung optimieren
- Schritt 3: Mit Qiskit Runtime Primitives ausführen
- Schritt 4: Nachbearbeitung und klassische Analyse
Wir werden diesen Schritten im Allgemeinen folgen, sie aber nicht immer explizit kennzeichnen.
Beginnen wir mit dem Laden einiger notwendiger Pakete, einschließlich der Runtime-Primitives. Wir werden auch den am wenigsten ausgelasteten verfügbaren Quantencomputer auswählen.
Unten findest du Code zum Speichern deiner Zugangsdaten bei der ersten Verwendung. Achte darauf, diese Informationen nach dem Speichern in deiner Umgebung aus dem Notebook zu löschen, damit deine Zugangsdaten nicht versehentlich weitergegeben werden, wenn du das Notebook teilst. Weitere Hinweise findest du unter IBM Cloud-Konto einrichten und Service in einer nicht vertrauenswürdigen Umgebung initialisieren.
from numpy import pi
# Load the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService
# Syntax for first saving your token. Delete these lines after saving your credentials.
# QiskitRuntimeService.save_account(channel='ibm_quantum_platform', instance = '<YOUR_IBM_INSTANCE_CRN>', token='<YOUR-API_KEY>', overwrite=True, set_as_default=True)
# service = QiskitRuntimeService(channel='ibm_quantum_platform')
# Load saved credentials
service = QiskitRuntimeService()
# Load the Runtime primitive and session
from qiskit_ibm_runtime import (
Batch,
SamplerV2 as Sampler,
EstimatorV2 as Estimator,
)
# Use the least busy backend
backend = service.least_busy(min_num_qubits=127)
print(backend.name)
ibm_sherbrooke
Falls ein Studierender die verfügbare Quantencomputing-Zeit während der Lektion aufbraucht, können die folgenden Zeilen auskommentiert und verwendet werden, um einen Simulator einzurichten, der das Rauschverhalten des oben ausgewählten Quantencomputers teilweise nachahmt.
# Import an estimator, this time from qiskit (we will import from Runtime for real hardware)
from qiskit_aer.primitives import SamplerV2, EstimatorV2
from qiskit_aer.noise import NoiseModel
# Generate the noise model from the backend properties
noise_model = NoiseModel.from_backend(backend)
noisy_sampler = SamplerV2(options={"backend_options": {"noise_model": noise_model}})
noisy_estimator = EstimatorV2(options={"backend_options": {"noise_model": noise_model}})
Du erinnerst dich vielleicht, dass ein Eigenzustand eines Operators Z kein Eigenzustand eines anderen Operators X ist. Wir werden das jetzt experimentell beobachten, indem wir Messungen entlang der - und -Achsen durchführen. Für die Messung entlang verwenden wir einfach qc.measure(), da IBM-Quantencomputer so konstruiert sind, dass sie entlang messen. Aber um entlang zu messen, müssen wir das System rotieren, um die -Achse effektiv in die Orientierung zu bringen, entlang der wir messen. Dies wird mit einem Hadamard-Gate erreicht. Es gibt einen ähnlichen Schritt für Messungen entlang . Die notwendigen Schritte sind hier zur Übersicht zusammengefasst:
- Um entlang zu messen:
qc.measure() - Um entlang zu messen:
qc.h()dannqc.measure() - Um entlang zu messen:
qc.sdg(),qc.h(),qc.sdannqc.measure()
Schritt 1: Klassische Eingaben auf ein Quantenproblem abbilden
In diesem Fall besteht der Abbildungsschritt einfach darin, die oben beschriebenen Messungen und Rotationen in einem Quanten-Circuit auszudrücken:
# Step 1: Map
# Import some general packages
from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
# Add a first measurement
qc.measure(qr, cr[0])
qc.barrier()
# Change basis so that measurements made on quantum computer which normally tell us about z, now tell us about x.
qc.h(qr)
# Add a second measurement
qc.measure(qr, cr[1])
qc.draw("mpl")
Schritt 2: Problem für die Quantenausführung optimieren
Dieser Schritt nimmt die Operationen, die wir ausführen möchten, und drückt sie in der Funktionalität eines bestimmten Quantencomputers aus. Er bildet unser Problem auch auf das Layout des Quantencomputers ab.
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
Schritt 3: Mit Qiskit Runtime Primitives ausführen
Wir können den Sampler verwenden, um Statistiken über die Messungen zu sammeln. Wir werden das Sampler-Primitive so konstruieren, dass es auf einem echten Quantencomputer läuft, indem wir mode = backend verwenden. Es gibt andere Modi für andere Arbeitsabläufe, und wir werden unten einen verwenden. Der Sampler wird durch Aufruf seiner run()-Methode mit einer Liste von „PUBs" (Primitive Unified Blocs) verwendet. Jedes PUB enthält bis zu drei Werte, die zusammen eine Berechnungseinheit für den Estimator definieren: Circuits, Observablen, Parameter. Du kannst auch eine Liste von Circuits, eine Liste von Observablen und eine Liste von Parametern angeben. Weitere Informationen findest du in der Übersicht der PUBs.
Wir möchten auf einem echten Quantencomputer rechnen, damit wir ein echtes quantenphysikalisches Experiment durchführen. Wenn du dein Zeitkontingent auf echten Quantencomputern aufbrauchst, kannst du den Code unten für den Quantencomputer auskommentieren und den Code für die Ausführung auf einem Simulator einkommentieren.
# Step 3: Run the job on a real quantum computer
sampler = Sampler(mode=backend)
pubs = [qc_isa]
job = sampler.run(pubs)
res = job.result()
counts = res[0].data.c.get_counts()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_sampler.run([qc_isa])
# res=job.result()
# counts=res[0].data.c.get_counts()
Schritt 4: Nachbearbeitung
Dies ist ein besonders einfacher Fall der Nachbearbeitung, bei dem wir die Zählungen einfach visualisieren.
Beachte, dass Qiskit Qubits, Messungen und andere Dinge ordnet, indem das niedrigst-nummerierte Element zuletzt/rechts aufgelistet wird, eine Konvention, die als „Little-Endian" bezeichnet wird. Das bedeutet, dass die Spalte unten mit der Bezeichnung „10" sich auf Zählungen bezieht, bei denen die erste Messung eine „0" ergab und die zweite Messung eine „1".
# Step 4: Post-process
from qiskit.visualization import plot_histogram
plot_histogram(counts)
Wenn dir diese Konvention nicht zusagt, kannst du marginal_counts verwenden, um die Ergebnisse jeder Messung separat zu visualisieren:
from qiskit.result import marginal_counts
plot_histogram(
marginal_counts(counts, indices=[0]), title="Counts after first measurement"
)
plot_histogram(
marginal_counts(counts, indices=[1]), title="Counts after second measurement"
)
Standardmäßig werden Zustände in Qiskit im -Zustand initialisiert. Es ist daher keine Überraschung, dass fast alle ersten Messungen ergaben. Beachte jedoch, dass es bei der zweiten Messung (die Informationen über Projektionen des Zustands auf liefert) eine fast gleichmäßige Aufteilung gab. Es scheint, als würde dieser Zustand, der uns ein sehr vorhersagbares Ergebnis bei Messungen entlang liefert, eine sehr unvorhersagbare Menge an Ergebnissen für Messungen entlang ergeben. Untersuchen wir das genauer.
Was passiert, wenn wir die Messungen in umgekehrter Reihenfolge durchführen? Wir könnten damit beginnen, das Hadamard-Gate zu verwenden, um Statistiken über die Wahrscheinlichkeit zu erhalten, dass in gemessen wird. Dann werden wir für die zweite Messung mit einem zweiten Hadamard-Gate zur -Basis zurückkehren.
# Step 1:
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
# Change basis to measure along x.
qc.h(qr)
qc.measure(qr, cr[0])
qc.barrier()
# Change our basis back to z and make a second measurement
qc.h(qr)
qc.measure(qr, cr[1])
qc.draw("mpl")
# Step 2: Transpile the circuit for running on a quantum computer
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
# Step 3: Run the job on a real quantum computer
sampler = Sampler(mode=backend)
pubs = [qc_isa]
job = sampler.run(pubs)
res = job.result()
counts = res[0].data.c.get_counts()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_sampler.run([qc_isa])
# res=job.result()
# counts=res[0].data.c.get_counts()
# Step 4: Post-process
from qiskit.visualization import plot_histogram
plot_histogram(counts)
Hier scheinen wir noch weniger Vorhersagbarkeit zu haben! Zuvor wussten wir zumindest, was das Ergebnis der ersten Messung sein würde, jetzt haben wir eine ziemlich gleichmäßige Verteilung über alle möglichen Zustände. Es ist nicht schwer zu sehen, warum das passiert ist. Wir begannen in , was eine 50-50-Mischung aus und ist, gemäß Es sollte also klar sein, dass es eine gleiche Wahrscheinlichkeit gibt, den + oder - Zustand (auf 0 und 1 im Diagramm abgebildet) bei der ersten Messung zu erhalten. Die Messung entlang kollabiert den Zustand in entweder den Eigenzustand oder den Eigenzustand . Jeder dieser Zustände ist eine 50-50-Mischung aus und , gemäß Sobald sich das System also in einem Eigenzustand von befindet, werden Messungen entlang eindeutig sowohl als auch ergeben, und zwar mit ungefähr gleicher Wahrscheinlichkeit. Unser erstes Beispiel zeigte uns also, dass einige Zustände sehr vorhersagbare Ergebnisse für einige Messungen haben, aber unvorhersagbare Ergebnisse für andere Messungen. Das aktuelle Beispiel zeigt uns, dass es noch schlechter geht. Es gibt Zustände, die uns unvorhersagbare Ergebnisse für beide Messungen liefern können, selbst wenn wir nur die Reihenfolge der Messungen vertauschen. Untersuchen wir, wie bestimmt oder unbestimmt eine Größe für einen gegebenen Zustand ist.
Berechnung der Unbestimmtheit
Wir können dies mit der Unbestimmtheit oder Varianz quantifizieren. Die „Unbestimmtheit" wird oft als Quadratwurzel der „Varianz" einer Verteilung definiert. Das heißt, die Unbestimmtheit für eine Observable wird mit bezeichnet und ist gegeben durch
Für den Fall der Pauli-Matrizen, bei denen gilt, wird dies zu
Wenden wir dies auf ein konkretes Beispiel an. Beginnen wir mit dem Zustand und bestimmen wir die Unbestimmtheit der Observablen in diesem Zustand.
Überprüfe dein Verständnis
Lies die Frage unten, denke über deine Antwort nach und klicke dann auf das Dreieck, um die Lösung anzuzeigen.
Berechne die Unbestimmtheit von im Zustand von Hand.
Antwort:
Im gegebenen Zustand ergibt dies:
Wir können einen beliebigen Anfangszustand mit qc.initialize() erstellen. Beachte, dass die Syntax für die imaginäre Einheit hier ist.
# Step 1: Map the problem into a quantum circuit
from qiskit.quantum_info import SparsePauliOp
import numpy as np
obs = SparsePauliOp("X")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Initialize the state
qc.initialize([1, 1j] / np.sqrt(2))
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs_isa = obs.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
estimator = Estimator(mode=backend)
pubs = [(qc_isa, obs_isa)]
job = estimator.run([[qc_isa, obs_isa]])
res = job.result()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([[qc_isa,obs_isa]])
# res=job.result()
# Step 4: Return the result in classical form, and analyze.
print(res[0].data.evs)
-0.02408454165642664
Gemäß unserer obigen Gleichung gilt: Bleiben wir bei demselben Zustand, finden aber jetzt den Erwartungswert von :
# Step 1: Map the problem into a quantum circuit
obs = SparsePauliOp("Z")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Initialize the state to |+>_y
qc.initialize([1, 1j] / np.sqrt(2))
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs_isa = obs.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
estimator = Estimator(mode=backend)
pubs = [(qc_isa, obs_isa)]
job = estimator.run(pubs)
res = job.result()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([[qc_isa,obs_isa]])
# res=job.result()
# Step 4: Return the result in classical form, and analyze.
print(res[0].data.evs)
0.04958271968581247
Wir könnten die gleiche Rechnung wie zuvor durchführen, würden aber sehen, dass die Varianz wieder sehr nahe bei 1,0 liegt. Wir könnten schlussfolgern, dass . Das ist in der Tat für den gewählten Zustand ungefähr korrekt. Aber können wir es besser machen? Oder schlechter?
Erinnere dich, dass es eine Unbestimmtheitsrelation zwischen der Position in einer Richtung, und dem Impuls in derselben Richtung, gibt. Für diese Variablen ist die bekannteste Form wahrscheinlich