Badanie niepewności
W tym module Qiskit in Classrooms studenci muszą mieć działające środowisko Python z zainstalowanymi następującymi pakietami:
qiskitv2.1.0 lub nowszyqiskit-ibm-runtimev0.40.1 lub nowszyqiskit-aerv0.17.0 lub nowszyqiskit.visualizationnumpypylatexenc
Aby skonfigurować i zainstalować powyższe pakiety, zapoznaj się z przewodnikiem Instalacja Qiskit. Aby uruchamiać zadania na prawdziwych komputerach kwantowych, studenci muszą założyć konto w IBM Quantum®, postępując zgodnie z krokami opisanymi w przewodniku Konfiguracja konta IBM Cloud.
Ten moduł był testowany i zużył 8 minut czasu QPU. Jest to wyłącznie szacunek. Twoje rzeczywiste zużycie może się różnić. Dwa czasochłonne obliczenia są oznaczone jako takie w komentarzach nagłówkowych i można je przeprowadzić na symulatorach, jeśli studenci mają ograniczony czas QPU. Po ich usunięciu moduł wymaga jedynie ~30 sekund czasu QPU.
# 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'
Obejrzyj poniżej omówienie modułu autorstwa dr Katie McCormick lub kliknij tutaj, aby obejrzeć je na YouTube.
Wstęp
Zasadę nieoznaczoności słyszałeś(-aś) zapewne nieraz — nawet poza zajęciami z fizyki. Potoczna reinterpretacja niepewności brzmi: „Patrząc na coś, wpływasz na to". To z pewnością prawda. Jednak bardziej fizyczny opis niepewności mówi, że istnieją pary obserwowalnych fizycznych, które są ze sobą niezgodne w taki sposób, że obie nie mogą być jednocześnie znane z dowolną dokładnością. Wielu studentów po raz pierwszy spotyka się z parą niezgodnych zmiennych i — położeniem wzdłuż osi oraz pędem liniowym w tym kierunku. Dla tych zmiennych ograniczenie na niepewność zapisuje się jako Tutaj nazywamy „niepewnością w ", która ma taką samą definicję jak odchylenie standardowe w statystyce i może być zdefiniowana jako definiujemy analogicznie. W tym miejscu nie będziemy wyprowadzać tej relacji nieoznaczoności; wskażemy jedynie, że jest ona zgodna z naszym rozumieniem fal klasycznych. Mianowicie fala o dokładnie jednej częstotliwości i długości rozciągałaby się w nieskończoność jako idealna sinusoida. Kwantowo odpowiadałoby to doskonałej znajomości pędu zgodnie z hipotezą de Broglie'a: . Lecz aby wiedzieć, zlokalizowana jest cząstka o naturze falowej, opisująca ją fala musi stawać się coraz ostrzej skupiona w przestrzeni — na przykład jak bardzo wąska gaussiana. Wiemy, że każdą funkcję ciągłą, w tym tak ostro skupione funkcje falowe, możemy przedstawić jako szereg Fouriera funkcji sinusoidalnych o różnych długościach fal. Jednak im ostrzej skupiona staje się funkcja falowa (i im lepiej znane jest położenie), tym więcej wyrazów szeregu Fouriera potrzebujemy, co oznacza mieszaninę większej liczby długości fal (a zatem kwantowo — większej liczby wartości pędu).
Mówiąc prościej: stan o dobrze określonym pędzie (idealna sinusoida w przestrzeni) ma bardzo nieokreślone położenie. Stan o dobrze określonym położeniu (jak dystrybucja delta Diraca) ma bardzo nieokreślony pęd.
Istnieją inne zmienne wykazujące taką niezgodność. Na przykład rzut spinu cząstki może być dobrze określony wzdłuż jednej osi, ale wtedy nic nie wiemy o rzucie na oś prostopadłą. Przykładowo stan (dla Qubitu lub cząstki spin-1/2) ma określony rzut wzdłuż osi (wynoszący 1 w kontekście Qubitu i w kontekście cząstki spin-1/2). Ale ten stan można zapisać jako superpozycję dwóch stanów, z których każdy ma dobrze określony rzut na oś : lub równoważnie ma dobrze określony rzut na , podobnie jak . Jeśli więc określimy rzut stanu wzdłuż osi , nie znamy rzutu wzdłuż osi . I odwrotnie — jeśli określimy rzut na oś , nie znamy rzutu wzdłuż . Istnieją pewne subtelne różnice przy omawianiu tego w kontekście spinu i Qubitów. Jednak ogólnie rzecz biorąc, stany własne macierzy Pauliego mają ciekawą relację, którą możemy zbadać. Przez całą tę lekcję będziemy eksperymentalnie sprawdzać nasze intuicje dotyczące niepewności tych niezgodnych zmiennych i weryfikować, że relacje nieoznaczoności są spełnione na komputerach kwantowych IBM®.
Prosta weryfikacja intuicji
W pierwszym eksperymencie i przez cały moduł będziemy korzystać ze schematu programowania kwantowego zwanego „wzorcami Qiskit" (ang. Qiskit patterns), który dzieli przepływy pracy na następujące kroki:
- Krok 1: Odwzoruj dane klasyczne na problem kwantowy
- Krok 2: Zoptymalizuj problem pod kątem wykonania kwantowego
- Krok 3: Wykonaj z użyciem prymitywów Qiskit Runtime
- Krok 4: Przetwarzanie końcowe i analiza klasyczna
Będziemy na ogół postępować według tych kroków, choć nie zawsze będziemy je explicite oznaczać.
Zacznijmy od załadowania niezbędnych pakietów, w tym prymitywów Runtime. Wybierzemy również najmniej zajęty dostępny komputer kwantowy.
Poniżej znajdziesz kod służący do zapisania swoich poświadczeń przy pierwszym użyciu. Pamiętaj, aby usunąć te informacje z notatnika po ich zapisaniu w środowisku, żeby Twoje poświadczenia nie zostały przypadkowo udostępnione razem z notatnikiem. Więcej wskazówek znajdziesz w przewodnikach Konfiguracja konta IBM Cloud oraz Inicjalizacja usługi w środowisku niezaufanym.
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
Jeśli student wyczerpie dostępny czas obliczeń kwantowych podczas lekcji, poniższe linie można odkomentować i użyć do skonfigurowania symulatora, który częściowo naśladuje zachowanie szumowe wybranego powyżej komputera kwantowego.
# 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}})
Być może pamiętasz, że stan własny jednego operatora, Z, nie jest stanem własnym innego operatora X. Zaobserwujemy to teraz eksperymentalnie, wykonując pomiary wzdłuż osi i . Do pomiaru wzdłuż używamy po prostu qc.measure(), ponieważ komputery kwantowe IBM są skonstruowane tak, by mierzyć wzdłuż . Natomiast do pomiaru wzdłuż musimy obrócić układ, aby efektywnie przesunąć oś do orientacji, wzdłuż której mierzymy. Osiąga się to za pomocą bramki Hadamarda. Podobny krok jest wymagany do pomiarów wzdłuż . Niezbędne kroki zebrano tu dla wygody:
- Pomiar wzdłuż :
qc.measure() - Pomiar wzdłuż :
qc.h(), następnieqc.measure() - Pomiar wzdłuż :
qc.sdg(),qc.h(),qc.s, następnieqc.measure()
Krok 1: Odwzorowanie klasycznych danych wejściowych na problem kwantowy
W tym przypadku etap odwzorowania sprowadza się do wyrażenia opisanych powyżej pomiarów i rotacji w postaci Circuit kwantowego:
# 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")
Krok 2: Optymalizacja problemu pod kątem wykonania kwantowego
Ten krok przekształca operacje, które chcemy wykonać, i wyraża je w kategoriach funkcjonalności konkretnego komputera kwantowego. Odwzorowuje też nasz problem na układ topologiczny komputera kwantowego.
# 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)
Krok 3: Wykonanie z użyciem Qiskit Runtime Primitives
Do zbierania statystyk pomiarów możemy użyć Sampler. Skonstruujemy prymityw Sampler tak, aby działał na prawdziwym komputerze kwantowym, ustawiając mode = backend. Istnieją inne tryby przeznaczone do innych przepływów pracy — jeden z nich zastosujemy poniżej. Sampler wywołuje się metodą run() z listą „PUBów" (Primitive Unified Blocs). Każdy PUB zawiera do trzech wartości, które wspólnie definiują jednostkę pracy obliczeniowej do wykonania przez Estimator: Circuit, obserwable, parametry. Można też podać listę Circuit, listę obserwabli i listę parametrów. Więcej informacji znajdziesz w artykule Przegląd PUBów.
Chcemy uruchomić obliczenia na prawdziwym komputerze kwantowym, aby przeprowadzić rzeczywisty eksperyment z fizyki kwantowej. Jeśli wyczerpiesz przydzielony czas na prawdziwych komputerach kwantowych, możesz zakomentować poniższy kod dla komputera kwantowego i odkomentować kod uruchamiający symulator.
# 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()
Krok 4: Post-processing
Jest to wyjątkowo prosty przypadek przetwarzania końcowego, w którym po prostu wizualizujemy zliczenia.
Zwróć uwagę, że Qiskit porządkuje Qubity, pomiary i inne elementy, wymieniając element o najniższym numerze jako ostatni / po prawej stronie — ta konwencja nosi nazwę „little-endian". Oznacza to, że kolumna poniżej oznaczona „10" odnosi się do zliczeń, w których pierwszy pomiar dał wynik „0", a drugi pomiar dał wynik „1".
# Step 4: Post-process
from qiskit.visualization import plot_histogram
plot_histogram(counts)
Jeśli ta konwencja ci nie odpowiada, możesz użyć marginal_counts, aby zwizualizować wyniki każdego pomiaru osobno:
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"
)
Domyślnie stany w Qiskit są inicjalizowane do stanu . Nic zatem dziwnego, że niemal wszystkie pierwsze pomiary dały wynik . Warto jednak zwrócić uwagę, że w drugim pomiarze (dostarczającym informacji o rzutach stanu na ) wyniki rozłożyły się niemal równo. Wygląda na to, że stan dający bardzo przewidywalny wynik pomiarów wzdłuż dostarcza wysoce nieprzewidywalnych wyników pomiarów wzdłuż . Przyjrzyjmy się temu bliżej.
Co się stanie, jeśli wykonamy pomiary w odwrotnej kolejności? Moglibyśmy zacząć od użycia bramki Hadamarda, aby uzyskać statystyki prawdopodobieństwa zmierzenia w . Następnie dla drugiego pomiaru wrócimy do bazy przy użyciu drugiej bramki Hadamarda.
# 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)
Tym razem wyniki wydają się jeszcze mniej przewidywalne! Poprzednio przynajmniej wiedzieliśmy, jaki będzie wynik pierwszego pomiaru — teraz rozkład jest dość równomierny we wszystkich możliwych stanach. Nie trudno dostrzec, dlaczego tak się stało. Zaczęliśmy w stanie , który jest mieszanką 50-50 stanów i zgodnie z Wyraźnie więc powinno być równe prawdopodobieństwo uzyskania stanu + lub − (odwzorowanego odpowiednio na 0 i 1 na wykresie) dla pierwszego pomiaru. Pomiar wzdłuż rzutuje stan na jeden z eigenstanów: lub . Każdy z tych stanów jest mieszanką 50-50 stanów i zgodnie z Skoro układ znalazł się w eigenstate operatora , pomiary wzdłuż dadzą zarówno , jak i z mniej więcej równym prawdopodobieństwem. Pierwszy przykład pokazał nam zatem, że pewne stany będą dawać bardzo przewidywalne wyniki dla jednych pomiarów, lecz nieprzewidywalne dla innych. Bieżący przykład pokazuje, że może być jeszcze gorzej. Istnieją stany, które mogą dawać nieprzewidywalne wyniki obu pomiarów — nawet jeśli jedyne, co robimy, to zamiana kolejności tych pomiarów. Zbadajmy, jak pewna lub niepewna jest dana wielkość dla zadanego stanu.
Obliczanie niepewności
Możemy to skwantyfikować za pomocą niepewności lub wariancji. „Niepewność" jest często definiowana jako pierwiastek kwadratowy z „wariancji" rozkładu. Oznacza to, że niepewność pewnej obserwowalnej jest oznaczana i wyraża się wzorem
W przypadku macierzy Pauliego, dla których , wzór upraszcza się do
Zastosujmy to do konkretnego przykładu. Zacznijmy od stanu i wyznaczmy niepewność obserwowalnej w tym stanie.
Sprawdź swoje rozumienie
Przeczytaj poniższe pytanie, zastanów się nad odpowiedzią, a następnie kliknij trójkąt, aby ujawnić rozwiązanie.
Oblicz ręcznie niepewność w stanie .
Odpowiedź:
Dla podanego stanu daje to:
Dowolny stan początkowy można utworzyć za pomocą qc.initialize(). Zwróć uwagę, że jednostka urojona jest tu oznaczona jako .
# 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
Zgodnie z powyższym wzorem: Pozostańmy przy tym samym stanie i wyznaczmy teraz wartość oczekiwaną :
# 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
Moglibyśmy przeprowadzić te same obliczenia co wcześniej, ale zobaczylibyśmy, że wariancja jest znów bardzo bliska 1,0. Można by stwierdzić, że . Rzeczywiście jest to w przybliżeniu prawdziwe dla wybranego stanu. Ale czy możemy uzyskać wynik lepszy lub gorszy?
Przypomnij sobie, że istnieje relacja nieoznaczoności między położeniem wzdłuż jednego kierunku, a pędem wzdłuż tego samego kierunku, Dla tych zmiennych najpopularniejsza postać to prawdopodobnie Gdybyśmy pamiętali tylko to, moglibyśmy być skłonni sądzić, że i również mają podobne fundamentalne ograniczenie nieoznaczoności. Być może iloczyn nie może osiągnąć zera? Wypróbujmy inny stan i sprawdźmy, czy tak jest. Tym razem użyjemy Zobaczmy, co się stanie. Zwróć uwagę, że w poniższym kodzie Estimator może przyjąć dwa zestawy obwodów i obserwowalnych w ramach jednego zadania.
# Step 1: Map the problem into a quantum circuit
obs1 = SparsePauliOp("X")
obs2 = SparsePauliOp("Z")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Initialize the state
qc.initialize([1, 1] / np.sqrt(2))
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs1_isa = obs1.apply_layout(layout=qc_isa.layout)
obs2_isa = obs2.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
with Batch(backend=backend) as batch:
estimator = Estimator(mode=batch)
pubs = [(qc_isa, obs1_isa), (qc_isa, obs2_isa)]
job = estimator.run(pubs)
res = job.result()
batch.close()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([[qc,obs1],[qc,obs2]])
# res=job.result()
# Step 4: Return the result in classical form, and analyze.
print("The expectation value of the first observable is: ", res[0].data.evs)
print("The expectation value of the second observable is: ", res[1].data.evs)
The expectation value of the first observable is: 1.0011036174126302
The expectation value of the second observable is: 0.0029429797670141016
Wartość oczekiwana powinna być bliska 1,0, ale nie powinna jej przekraczać. Nie martw się, jeśli przekroczy ją o bardzo małą wartość. Można to przypisać takim czynnikom jak szum i/lub błąd odczytu. Choć jest to bardzo ważny temat, na razie możemy go pominąć.
Uzyskaliśmy wartość oczekiwaną bardzo bliską 1,0 (co odpowiada bardzo małej wariancji ). Sprawia to, że iloczyn obu wariancji jest całkiem mały:
Choć nie jest to dokładnie zero, wartość ta jest mała w porównaniu z wartościami własnymi operatorów Pauliego (). Być może pamiętasz, że relację nieoznaczoności między liniowym położeniem a pędem można zapisać inaczej, jawnie używając relacji komutacji między operatorami i :
gdzie
jest komutatorem i .
Jest to postać, którą najłatwiej rozszerzyć na operatory Pauliego. Ogólnie, dla dwóch operatorów i ,
W przypadku macierzy Pauliego i potrzebujemy , aby obliczyć
Pokażemy to poniżej, a podobne obliczenia pozostawiamy czytelnikowi jako ćwiczenie:
To jest poprawna odpowiedź, ale po jednym dodatkowym kroku widzimy
Relacja nieoznaczoności przyjmuje więc postać
Sprawdź swoje rozumienie
Przeczytaj poniższe pytanie, zastanów się nad odpowiedzią, a następnie kliknij trójkąt, aby ujawnić rozwiązanie.
Wyznacz i . Skorzystaj z tego, aby zapisać relacje nieoznaczoności między a oraz między a .
Odpowiedź:
Łącząc z ogólną relacją nieoznaczoności, otrzymujemy
Weryfikacja spójności
Zanim przejdziemy dalej, sprawdźmy, czy jest to zgodne z naszym wcześniejszym wynikiem. Użyliśmy stanu Znaleźliśmy, że Wiemy teraz, że ten iloczyn powinien być większy lub równy
Zatem rzeczywiście . Skorzystaj z poniższych pytań, aby wypracować intuicję odnośnie do tych wyników:
Sprawdź swoje rozumienie
Przeczytaj poniższe pytania, zastanów się nad odpowiedziami, a następnie kliknij trójkąty, aby zobaczyć rozwiązania.
Odpowiedz na poniższe punkty łącznie jako zestaw:
(a) Dla jakich stanów spodziewasz się zerowej niepewności w ?
(b) Dla jakich stanów spodziewasz się zerowej niepewności w ?
(c) W jakich stanach otrzymasz zerową wartość oczekiwaną ?
(d) Czy odpowiedzi na powyższe pytania są zgodne z przypadkiem ?
(e) Napisz kod, który jawnie to sprawdzi, korzystając z Estimatora.
Odpowiedzi:
(a) Możemy spodziewać się, że stany własne operatora dadzą zerową niepewność w . Rzeczywiście, dla mamy
(b) Możemy spodziewać się, że stany własne operatora dadzą zerową niepewność w . Rzeczywiście, dla mamy
(c) Oczekujemy dla dowolnych stanów, które przy pomiarze z równą częstością dają dodatnią i ujemną rzutnię na oś . Należą do nich stany własne operatorów i .
(d) Tak. Dla stanów własnych operatorów lub spodziewamy się bardzo małej wartości iloczynu niepewności : Może to zachodzić, ponieważ dla tych samych stanów oczekujemy również . Relacja nieoznaczoności może być zatem spełniona.
(e) Poniższy kod pozwoliłby to zweryfikować:
obs1 = SparsePauliOp.from_list(
[("X", 1.000)]
)
obs2 = SparsePauliOp.from_list(
[("Y", 1.000)]
)
obs3 = SparsePauliOp.from_list(
[("Z", 1.000)]
)
qc = QuantumCircuit(1,1)
qc.ry(pi/2,0)
job = estimator.run([(qc, [[obs1], [obs2], [obs3]])], precision=0.001)
res=job.result()
Wynik zwraca wszystkie wartości oczekiwane. Aby pobrać wszystkie wartości oczekiwane i obliczyć niepewności, można użyć:
xs=res[0].data.evs[0]
ys=abs(res[0].data.evs[1])
zs=res[0].data.evs[2]
import math
prodxz=((1-xs[i]*xs[i])**0.5)*(1-zs[i]*zs[i])**0.5
Odpowiedz na poniższe punkty łącznie jako zestaw:
(a) Czy możesz pomyśleć o stanie, w którym wartość oczekiwana byłaby duża?
(b) Czy spodziewasz się, że ten sam stan będzie miał dużą czy małą niepewność w ?
(c) Czy spodziewasz się, że ten sam stan będzie miał dużą czy małą niepewność w ?
(d) Czy odpowiedzi na powyższe pytania są zgodne z przypadkiem ?
(e) Napisz kod, który jawnie to sprawdzi, korzystając z Estimatora.
Odpowiedzi:
(a) Oczekujemy dla stanu własnego operatora : .
(b) Możemy spodziewać się dużej niepewności w stanie , ponieważ pomiar w tym stanie z równą częstością daje wynik dodatni i ujemny.
(c) Możemy spodziewać się dużej niepewności w stanie , ponieważ pomiar w tym stanie z równą częstością daje wynik dodatni i ujemny.
(d) Tak. Dla stanów własnych operatora , a w szczególności dla , spodziewamy się dużej wartości iloczynu niepewności . Dla tego samego stanu oczekujemy również . Zatem zarówno , jak i są duże w tym stanie, a relacja nieoznaczoności może być znowu spełniona.
(e) Poniższy kod pozwoliłby to zweryfikować:
obs1 = SparsePauliOp.from_list(
[("X", 1.000)]
)
obs2 = SparsePauliOp.from_list(
[("Y", 1.000)]
)
obs3 = SparsePauliOp.from_list(
[("Z", 1.000)]
)
qc = QuantumCircuit(1,1)
qc.rx(-pi/2,0)
job = estimator.run([(qc, [[obs1], [obs2], [obs3]])], precision=0.001)
res=job.result()
Wynik zwraca wszystkie wartości oczekiwane. Aby pobrać wszystkie wartości oczekiwane i obliczyć niepewności, można użyć:
xs=res[0].data.evs[0]
ys=abs(res[0].data.evs[1])
zs=res[0].data.evs[2]
import math
prodxz=((1-xs[i]*xs[i])**0.5)*(1-zs[i]*zs[i])**0.5
Testowanie relacji nieoznaczoności
Powyższy test demonstruje jedynie słuszność relacji nieoznaczoności dla pojedynczego wyboru wektora stanu . Aby przekonać się, że jest to zgodne z eksperymentem w ogólnym przypadku, powinniśmy przeprowadzić podobne obliczenia przy użyciu Estimatora dla wielu różnych wyborów wektora stanu. Zacznijmy od obracania naszego wektora stanu z dala od osi , stosując bramkę RY, aby wygenerować różne stany początkowe przy użyciu parametru .
# The calculation below uses approximately 3-4 minutes of QPU time.
# Step 1: Map the problem into a quantum circuit
from qiskit.circuit import Parameter
import numpy as np
# Specify observables
obs1 = SparsePauliOp("X")
obs2 = SparsePauliOp("Y")
obs3 = SparsePauliOp("Z")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Rotate away from |0>
theta = Parameter("θ")
qc.ry(theta, 0)
params = np.linspace(0, 2, num=21)
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs1_isa = obs1.apply_layout(layout=qc_isa.layout)
obs2_isa = obs2.apply_layout(layout=qc_isa.layout)
obs3_isa = obs3.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
with Batch(backend=backend) as batch:
estimator = Estimator(mode=batch)
pubs = [(qc_isa, [[obs1_isa], [obs2_isa], [obs3_isa]], [params])]
job = estimator.run(pubs, precision=0.01)
res = job.result()
batch.close()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([(qc, [[obs1], [obs2], [obs3]], [params])])
# res=job.result()
# Step 4: Post-processing and classical analysis.
xs = res[0].data.evs[0]
ys = abs(res[0].data.evs[1])
zs = res[0].data.evs[2]
# Calculate uncertainties
delx = []
delz = []
prodxz = []
for i in range(len(xs)):
delx.append(abs((1 - xs[i] * xs[i])) ** 0.5)
delz.append(abs((1 - zs[i] * zs[i])) ** 0.5)
prodxz.append(delx[i] * delz[i])
# Here we can plot the results from this simulation.
import matplotlib.pyplot as plt
plt.plot(params, delx, label=r"$\Delta$ X")
plt.plot(params, ys, label=r"$\langle$ Y $\rangle$")
plt.plot(params, delz, label=r"$\Delta$ Z")
plt.plot(params, prodxz, label=r"$\Delta$X $\Delta$Z")
plt.xlabel(r"$\theta$")
plt.ylabel("Expectation/Uncertainty Values")
plt.legend()
plt.show()
Zauważ, że czerwona krzywa jest zawsze większa niż pomarańczowa krzywa Czasami iloczyn nieoznaczoności spada i zbliża się do granicy, a innym razem rośnie i oddala się od niej, ale zawsze spełnia relację nieoznaczoności.
Oczywiście, może to nie być najlepszy test relacji nieoznaczoności, ponieważ nasza granica jest zawsze bardzo bliska zeru. Użyjmy stanu kwantowego, który ma większą rzutową na stany własne . Konkretnie — wciąż będziemy obracać w dół od osi o różne kąty, ale teraz obrócimy wynikający z tego stan wokół osi o pewien kąt, powiedzmy , i sprawdzimy, co się stanie.
# The calculation below uses approximately 3-4 minutes of QPU time.
from qiskit.circuit import Parameter
import numpy as np
# Step 1: Map the problem to a quantum circuit
# Specify observables
obs1 = SparsePauliOp("X")
obs2 = SparsePauliOp("Y")
obs3 = SparsePauliOp("Z")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Rotate away from |0> along one plane, and then along a transverse direction.
theta = Parameter("θ")
qc.ry(theta, 0)
qc.rz(pi / 4, 0)
params = np.linspace(0, 2, num=21)
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs1_isa = obs1.apply_layout(layout=qc_isa.layout)
obs2_isa = obs2.apply_layout(layout=qc_isa.layout)
obs3_isa = obs3.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
with Batch(backend=backend) as batch:
estimator = Estimator(mode=batch)
pubs = [(qc_isa, [[obs1_isa], [obs2_isa], [obs3_isa]], [params])]
job = estimator.run(pubs, precision=0.01)
res = job.result()
batch.close()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([(qc, [[obs1], [obs2], [obs3]], [params])])
# res=job.result()
# Step 4: Post-processing and classical analysis.
xs = res[0].data.evs[0]
ys = abs(res[0].data.evs[1])
zs = res[0].data.evs[2]
# Calculate uncertainties
delx = []
delz = []
prodxz = []
for i in range(len(xs)):
delx.append(abs((1 - xs[i] * xs[i])) ** 0.5)
delz.append(abs((1 - zs[i] * zs[i])) ** 0.5)
prodxz.append(delx[i] * delz[i])
# Here we can plot the results from this simulation.
import matplotlib.pyplot as plt
plt.plot(params, delx, label=r"$\Delta$ X")
plt.plot(params, ys, label=r"$\langle$ Y $\rangle$")
plt.plot(params, delz, label=r"$\Delta$ Z")
plt.plot(params, prodxz, label=r"$\Delta$X $\Delta$Z")
plt.xlabel(r"$\theta$")
plt.ylabel("Expectation/Uncertainty Values")
plt.legend()
plt.show()
Teraz widzimy, że granica nieoznaczoności jest naprawdę wystawiana na próbę! Czerwona krzywa zbliża się do pomarańczowej znacznie bardziej niż poprzednio. W rzeczywistości, przy braku szumów, relacja nieoznaczoności byłaby dokładnie nasycona () w jednym punkcie. Przy szumach i błędach odczytu nie powinno być zaskoczeniem, że przebieg może sporadycznie zwracać nieznacznie większe niż Nie jest to prawdziwe naruszenie nieoznaczoności — to jedynie artefakt niezerowego błędu.
Sprawdź swoją wiedzę
Przeczytaj poniższe pytania, zastanów się nad odpowiedzią, a następnie kliknij trójkąt, aby zobaczyć rozwiązanie.
Wyjaśnij, jak wypchnąć to do absolutnej granicy, czyniąc jak największym?
Odpowiedź:
Kod aktualnie zawiera linie, które obracają domyślny stan początkowy w dół od osi o pewien sparametryzowany kąt , a następnie wokół osi o kąt , co obraca wektor stanu częściowo w kierunku osi .
qc.ry(theta,0)
qc.rz(pi/4,0)
Możemy zmieni ć obrót wokół z na , obracając cały stan do stanu własnego :
qc.ry(theta,0)
qc.rz(pi/2,0)
Żadne inne zmiany nie są wymagane.
Zmień kod lub skopiuj go i zaimplementuj tę weryfikację relacji nieoznaczoności z maksymalną wartością oczekiwaną Y. Czy relacja nieoznaczoności jest spełniona?
Odpowiedź:
Użylibyśmy dokładnie kodu z powyższego przykładu, podstawiając
qc.rz(pi/2,0)
w miejsce
qc.rz(pi/4,0).
Wynikowy wykres powinien wyglądać jak poniżej, i tak — zasada nieoznaczoności powinna nadal być spełniona.

Zmodyfikuj powyższy kod, aby stworzyć podobny wykres, demonstrując na podstawie pomiarów z komputera kwantowego, że iloczyn zachowuje się zgodnie z oczekiwaniami. Wybierz dowolny zestaw stanów.
Odpowiedź:
Użylibyśmy dokładnie kodu z powyższego przykładu, a właściwie moglibyśmy skorzystać z tych samych wyników co wyżej, po prostu używając wartości oczekiwanych do obliczenia innych nieoznaczoności. Na przykład moglibyśmy użyć
xs=res[0].data.evs[0]
ys=res[0].data.evs[1]
zs=abs(res[0].data.evs[2])
import math
delx = []
dely = []
prodxy=[]
for i in range(len(xs)):
delx.append((1-xs[i]*xs[i])**0.5)
dely.append((1-ys[i]*ys[i])**0.5)
prodxy.append(((1-xs[i]*xs[i])**0.5)*(1-ys[i]*ys[i])**0.5)
a następnie możemy wykreślić
import matplotlib.pyplot as plt
plt.plot(params, delx, label=r'$\Delta$ X')
plt.plot(params, dely, label=r'$\langle$ Y $\rangle$')
plt.plot(params, zs, label=r'$\Delta$ Z')
plt.plot(params, prodxy, label=r'$\Delta$X $\Delta$Z')
plt.xlabel(r'$\theta$')
plt.ylabel('Expectation/Uncertainty Values')
plt.legend()
plt.show()
Wyzwanie: Napisz kod, który przeskanuje wiele wartości , tak jak skanowaliśmy wiele wartości , i stwórz trójwymiarowy wykres pokazujący, że relacja nieoznaczoności nigdy nie jest naruszona. Wybierz dowolne obserwowalne.
Pytania
Instruktorzy mogą poprosić o wersje tych notebooków z kluczem odpowiedzi oraz wskazówkami dotyczącymi umiejscowienia w popularnych programach nauczania, wypełniając tę krótką ankietę o sposobach korzystania z notebooków.
Kluczowe pojęcia:
- Relacje nieoznaczoności istnieją między wieloma parami fizycznych obserwowalnych, między innymi między położeniem a pędem liniowym oraz między składowymi spinu.
- Macierze Pauliego nie komutują. Jest to matematyczne odzwierciedlenie faktu, że nie wszystkie składowe spinu mogą być jednocześnie znane/wyznaczone.
- Obliczenia kwantowe w szerokim zakresie korzystają z operatorów/macierzy Pauliego, dlatego warto znać relacje nieoznaczoności dla operatorów Pauliego, a także ściśle z nimi powiązanych operatorów spinu.
- Ogólny wzór na nieoznaczoność dwóch operatorów i to
- Stan własny pewnego operatora daje zerową nieoznaczoność obserwowalnej fizycznej skojarzonej z tym operatorem. Nawet doświadczalnie
- Stan własny pewnego operatora daje większą nieoznaczoność dla operatora , który nie komutuje z .
- Wyniki eksperymentów przeprowadzonych na prawdziwym komputerze kwantowym potwierdzają intuicję, którą uzyskujemy z macierzowych reprezentacji operatorów fizycznych.
Pytania P/F:
- P/F Można jednocześnie zmierzyć i , ale nie .
- P/F Można jednocześnie zmierzyć i , ale nie .
- P/F Operatory położenia liniowego i pędu liniowego nie komutują.
- P/F Komputery kwantowe IBM domyślnie mierzą wzdłu ż , więc aby mierzyć wzdłuż dowolnego innego kierunku, konieczne jest wykonanie obrotu.
- P/F Poniższy Circuit efektywnie mierzy , a następnie .
Pytania wielokrotnego wyboru:
-
Poniższy diagram ilustruje którą z następujących relacji nieoznaczoności?
- a.
- b.
- c.
- d. Żadna z powyższych

-
Który z poniższych ciągów kroków jest standardową sekwencją pomiaru wzdłuż ?
- a. Wyłącznie
qc.measure() - b.
qc.h(), a następnieqc.measure() - c.
qc.h(),qc.h(), a następnieqc.measure() - d.
qc.h(),qc.s,qc.h(), a następnieqc.measure() - e.
qc.sdg(),qc.h(),qc.s, a następnieqc.measure() - f.
qc.sdg(),qc.h(),qc.s,qc.h(), a następnieqc.measure()
- a. Wyłącznie
-
Który z poniższych stanów daje największą wartość oczekiwaną ?
- a.
- b.
- c. zwany też
- d. zwany też
- e. zwany też
- f. zwany też
-
Który z poniższych stanów daje największą nieoznaczoność ?
- a.