Teleportacja kwantowa i kodowanie supergęste
Kifumi Numata (26 kwietnia 2024)
Pobierz plik pdf oryginalnego wykładu. Zwróć uwagę, że niektóre fragmenty kodu mogą stać się przestarzałe, ponieważ są to obrazy statyczne.
Przybliżony czas QPU potrzebny do uruchomienia tego eksperymentu wynosi 10 sekund.
1. Wprowadzenie
Aby rozwiązać dowolny problem kwantowy na skalę użytkową, będziemy musieli przenosić informacje na komputerze kwantowym z jednego kubitu do drugiego. Istnieją dobrze znane protokoły, które to umożliwiają, lecz niektóre z najbardziej fundamentalnych zostały sformułowane w kontekście przesyłania informacji pomiędzy odległymi stronami. W trakcie tej lekcji będziemy niekiedy używać języka zgodnego z tym kontekstem, np. „odlegli przyjaciele przesyłający informację”. Pamiętaj jednak, że protokoły te mają szersze znaczenie w obliczeniach kwantowych. W tej lekcji rozważamy następujące kwantowe protokoły komunikacyjne:
- Teleportacja kwantowa Wykorzystanie współdzielonego stanu splątanego (czasami nazywanego e-bitem) do wysłania nieznanego stanu kwantowego odległemu przyjacielowi, co wymaga uzupełniającej komunikacji klasycznej.
- Kwantowe kodowanie supergęste Jak przesłać dwa bity informacji, wysyłając pojedynczy kubit odległemu przyjacielowi (ponownie z użyciem wcześniej współdzielonych splątanych kubitów).
Aby uzyskać więcej informacji istotnych dla tych tematów, polecamy lekcję 4 w Podstawach informacji kwantowej na temat Splątanie w działaniu.
W powyższym opisie „nieznany stan kwantowy” odnosi się po prostu do stanu postaci opisanej w poprzedniej lekcji:
gdzie i są liczbami zespolonymi takimi, że . Pozwala nam to zapisać stan kwantowy jako
Ponieważ chcemy móc przesłać informację w dowolnym losowym stanie kwantowym, wygenerowanie takiego stanu jest punktem, od którego rozpoczniemy tę lekcję.
2. Macierze gęstości
Stan kwantowy możemy również zapisać jako jego macierz gęstości. Taka forma jest użyteczna do oznaczania probabilistycznej mieszaniny czystych stanów kwantowych. W przypadku pojedynczego kubitu możemy zapisać
Zauważ, że macierz gęstości jest liniową sumą macierzy Pauliego, tak jak poniżej,
Albo, ogólnie,
gdzie .
Zaś wektor Blocha to .
Teraz utwórzmy dowolny stan kwantowy za pomocą liczb losowych.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer qiskit-ibm-runtime
import numpy as np
# create a random 1-qubit state from a random (theta, varphi) to define r vector
np.random.seed(1) # fixing seed for repeatibility
theta = np.random.uniform(0.0, 1.0) * np.pi # from 0 to pi
varphi = np.random.uniform(0.0, 2.0) * np.pi # from 0 to 2*pi
def get_r_vec(theta, varphi):
rx = np.sin(theta) * np.cos(varphi)
ry = np.sin(theta) * np.sin(varphi)
rz = np.cos(theta)
return (rx, ry, rz)
# get r vector
rx, ry, rz = get_r_vec(theta, varphi)
print("theta=" + str(theta), ",varphi=" + str(varphi))
print("(rx, ry, rz) = (" + str(rx) + ", " + str(ry) + ", " + str(rz) + ")")
theta=1.3101132663588946 ,varphi=4.525932273597346
(rx, ry, rz) = (-0.1791150283307452, -0.9494670044331133, 0.2577405946274022)
Możemy przedstawić ten wektor Blocha na sferze Blocha.
from qiskit.visualization import plot_bloch_vector
r = [rx, ry, rz]
plot_bloch_vector(r)
3. Tomografia stanu kwantowego
Jeśli mierzysz stan kwantowy tylko w bazie obliczeniowej ( i ), informacja o fazie (informacja o liczbach zespolonych) zostanie utracona. Ale jeśli mamy wiele kopii dzięki powtarzaniu procesu przygotowania (nie możemy klonować stanów, ale możemy powtarzać procesy przygotowania), możemy oszacować wartości wykonując tomografię stanu kwantowego dla macierzy gęstości . Biorąc pod uwagę postać:
zachodzi
W przypadku ,
Ostatnie przekształcenie równania dotyczy . Zatem możemy otrzymać jako prawdopodobieństwo - Prawdopodobieństwo .
Oszacuj wartość
Aby oszacować , tworzymy stan kwantowy i mierzymy go. Następnie powtarzamy przygotowanie i pomiar wiele razy. Na koniec używamy statystyk pomiarów, aby oszacować powyższe prawdopodobieństwa, a tym samym oszacować .
Do utworzenia losowego stanu kwantowego wykorzystamy ogólną bramkę unitarną z parametrami . (Więcej informacji można znaleźć w U-gate.)
from qiskit import QuantumCircuit
# create a 1-qubit quantum state psi from theta, varphi parameters
qc = QuantumCircuit(1, 1)
qc.u(theta, varphi, 0.0, 0)
# measure in computational basis
qc.measure(0, 0)
qc.draw(output="mpl")
Korzystając z AerSimulator, zmierzymy go w bazie obliczeniowej, aby oszacować .
# see if the expected value of measuring in the computational basis
# approaches the limit of rz
from qiskit_aer import AerSimulator
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import Sampler
from qiskit.visualization import plot_histogram
# Define backend
backend = AerSimulator()
nshots = 1000 # or 10000
# nshots = 10000
# 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], shots=nshots)
result = job.result()
# Extract counts data
counts = result[0].data.c.get_counts()
print(counts)
# Plot the counts in a histogram
plot_histogram(counts)
{'1': 375, '0': 625}
rz_approx = (counts["0"] - counts["1"]) / nshots
print("rz = ", rz, " and approx of rz = ", rz_approx)
rz = 0.2577405946274022 and approx of rz = 0.25
Korzystając z metody kwantowej tomografii stanu, oszacowaliśmy wartość . W tym przypadku, ponieważ wybraliśmy parametr dla "losowego" stanu, znamy wartość i możemy sprawdzić naszą pracę. Ale z samej swojej natury praca w skali użyteczności nie zawsze jest tak trywialna do sprawdzenia. Więcej o sprawdzaniu wyników kwantowych omówimy później w tym kursie. Na razie po prostu zauważmy, że nasze oszacowanie było rozsądnie dokładne.
Ćwiczenie 1: Oszacuj wartość
Przypomnijmy, że komputery kwantowe IBM® mierzą wzdłuż osi (czasem mówi się "w bazie " lub "w bazie obliczeniowej"). Jednak używając rotacji przed pomiarem, możemy zmierzyć rzut stanu kwantowego również na oś x. Mówiąc dokładniej, jeśli obrócimy nasz układ tak, że rzeczy, które wskazywały wzdłuż , teraz wskazują wzdłuż , wówczas możemy zachować ten sam sprzęt pomiarowy wzdłuż , ale dowiedzieć się o stanie, który chwilę temu był wzdłuż . W ten sposób większość komputerów kwantowych (oraz wszystkie komputery kwantowe IBM) wykonują pomiary wzdłuż wielu osi.
Z tym zrozumieniem spróbuj napisać kod, aby oszacować wartość używając kwantowej tomografii stanu.
Rozwiązanie:
# create a 1-qubit quantum state psi from theta, varphi parameters
qc = QuantumCircuit(1, 1)
qc.u(theta, varphi, 0.0, 0)
qc.h(0)
qc.measure(0, 0)
qc.draw(output="mpl")
# Define backend
backend = AerSimulator()
nshots = 10000
# 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], shots=nshots)
result = job.result()
# Extract counts data
counts = result[0].data.c.get_counts()
print(counts)
# Plot the counts in a histogram
plot_histogram(counts)
{'1': 5925, '0': 4075}
rx_approx = (counts["0"] - counts["1"]) / nshots
print("rx = ", rx, " and approx of rx = ", rx_approx)
rx = -0.1791150283307452 and approx of rx = -0.185
Ćwiczenie 2: Oszacuj wartość
Korzystając z tych samych argumentów logicznych co wcześniej, możemy obrócić układ przed pomiarem, aby dowiedzieć się o .
Spróbuj samodzielnie napisać kod, aby oszacować wartość przy użyciu kwantowej tomografii stanu. Możesz zacząć od poprzedniego przykładu, ale wykonać inne rotacje. (Aby uzyskać więcej informacji o różnych bramkach, w tym sdg, zapoznaj się z dokumentacją API.)
Rozwiązanie:
# create a 1-qubit quantum state psi from theta, varphi parameters
qc = QuantumCircuit(1, 1)
qc.u(theta, varphi, 0.0, 0)
qc.sdg(0)
qc.h(0)
qc.measure(0, 0)
qc.draw(output="mpl")
# Define backend
backend = AerSimulator()
nshots = 10000
# 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], shots=nshots)
result = job.result()
# Extract counts data
counts = result[0].data.c.get_counts()
print(counts)
# Plot the counts in a histogram
plot_histogram(counts)
{'1': 9759, '0': 241}
ry_approx = (counts["0"] - counts["1"]) / nshots
print("ry = ", ry, " and approx of ry = ", ry_approx)
ry = -0.9494670044331133 and approx of ry = -0.9518
Oszacowaliśmy teraz wszystkie składowe i możemy zapisać pełny wektor.
print("Estimated vector is (", rx_approx, ",", ry_approx, ",", rz_approx, ").")
print("Original random vector was (" + str(rx) + ", " + str(ry) + ", " + str(rz) + ").")
Estimated vector is ( -0.185 , -0.9518 , 0.25 ).
Original random vector was (-0.1791150283307452, -0.9494670044331133, 0.2577405946274022).
Przy użyciu tej metody tomografii stanu kwantowego uzyskano dość dokładne oszacowanie pierwotnego losowego wektora.
4. Teleportacja kwantowa
Rozważmy sytuację, w której postać o imieniu Alice chce wysłać nieznany stan kwantowy swojemu przyjacielowi Bobowi, który znajduje się daleko. Załóżmy, że mogą komunikować się wyłącznie za pomocą komunikacji klasycznej (np. e-mailem lub telefonem). Alice nie może skopiować stanu kwantowego (z powodu twierdzenia o nieklonowaniu). Gdyby wielokrotnie powtarzała ten sam proces przygotowania, mogłaby zebrać statystyki, tak jak przed chwilą to zrobiliśmy. Ale co, jeśli istnieje tylko jeden, pojedynczy nieznany stan? Ten stan mógł powstać w procesie fizycznym, który chcesz badać. Albo może być częścią większych obliczeń kwantowych. Jak wtedy Alice mogłaby przesłać ten stan Bobowi? Może to zrobić, jeśli ona i Bob dzielą cenny zasób kwantowy: wspólny stan splątany, taki jak stan Bella wprowadzony w poprzedniej lekcji: Czasami spotyka się także określenie „para EPR” lub „e-bit” (podstawowa jednostka splątania). Jeśli Alice dzieli z Bobem taki stan splątany, może teleportować nieznany stan kwantowy do Boba, wykonując serię operacji kwantowych i przesyłając mu dwa bity informacji klasycznej.
4.1 Protokół teleportacji kwantowej
Założenie: Alice ma nieznany stan kwantowy do wysłania do Boba. Alice i Bob dzielą 2-kubitowy stan splątany, czyli e-bit, a każde z nich fizycznie posiada jeden z kubitów w swoim miejscu.
Poniżej nakreślamy procedurę bez wyjaśnień. Zostaną one szczegółowo zaimplementowane poniżej.
- Alice splątuje ze swoją częścią e-bitu za pomocą bramki CNOT.
- Alice aplikuje bramkę Hadamard do i dokonuje pomiaru obu swoich kubitów w bazie obliczeniowej.
- Alice przesyła Bobowi wyniki swoich pomiarów (jeden z: „00”, „01”, „10” lub „11”)
- Bob wykonuje operator korekty na swojej części pary e-bitu na podstawie dwubitowej informacji od Alice.
- Jeśli „00”, Bob nic nie robi
- Jeśli „01”, Bob aplikuje bramkę X
- Jeśli „10”, Bob aplikuje bramkę Z
- Jeśli „11”, Bob aplikuje bramkę iY = ZX
- Część e-bitu Boba staje się .
Zostało to również bardziej szczegółowo omówione w Podstawach informacji kwantowej. Sytuacja stanie się jednak jaśniejsza, gdy zaimplementujemy to w Qiskicie.
4.2 Obwód kwantowy symulujący teleportację kwantową
Jak zawsze, zastosujemy szkielet wzorców Qiskit. W tym podrozdziale skupimy się wyłącznie na odwzorowaniu (mapping).
Krok 1: Odwzoruj problem na obwody kwantowe i operatory
Aby opisać powyższy scenariusz, potrzebujemy obwodu z trzema kubitami: dwa dla splątanej pary współdzielonej przez Alice i Boba oraz jeden dla nieznanego stanu kwantowego .
from qiskit import QuantumCircuit
import numpy as np
# create 3-qubits circuit
qc = QuantumCircuit(3, 3)
qc.draw(output="mpl")
Na początku Alice ma nieznany stan kwantowy Utworzymy go za pomocą bramki .
# Create the unknown quantum state using the u-gate. Alice has this.
qc.u(theta, varphi, 0.0, 0)
qc.barrier() # for visual separation
qc.draw(output="mpl")
Możemy zwizualizować utworzony stan, ale tylko dlatego, że znamy parametry użyte w bramce . Gdyby stan ten powstał w skomplikowanym procesie kwantowym, nie byłby znany bez wielokrotnego uruchomienia procesu tworzenia stanu i zebrania statystyk, tak jak w tomografii.
# show the quantum state on bloch sphere
from qiskit.quantum_info import Statevector
from qiskit.visualization import plot_bloch_multivector
out_vector = Statevector(qc)
plot_bloch_multivector(out_vector)

Zanim ten protokół w ogóle się rozpocznie, zakładamy, że Alice i Bob dzielą splątaną parę. Jeśli Alice i Bob naprawdę znajdują się w różnych miejscach, mogli ustawić współdzielony stan zanim nieznany stan w ogóle został utworzony. Ponieważ te rzeczy dzieją się na różnych kubitach, ich kolejność nie będzie tu miała znaczenia, a ta kolejność jest wygodna do wizualizacji.
# Alice and Bob are together in the same place and set up an entangled pair.
qc.h(1)
qc.cx(1, 2)
qc.barrier() # for visual separation.
# We can consider that Alice and Bob might move their qubits to different physical locations, now.
qc.draw(output="mpl")
Następnie Alice splątuje ze swoją częścią współdzielonego e-bitu, używając bramki i bramki , a następnie dokonuje ich pomiaru w bazie obliczeniowej.
# Alice entangles the unknown state with her part of the e-bit, using the CNOT gate and H gate.
qc.cx(0, 1)
qc.h(0)
qc.barrier()
# Alice measures the two qubits.
qc.measure(0, 0)
qc.measure(1, 1)
qc.draw(output="mpl")
Alice przesyła Bobowi wyniki swoich pomiarów (jeden z: „00”, „01”, „10” lub „11”), a Bob wykonuje operator korekty na swojej części współdzielonego e-bitu na podstawie dwóch bitów informacji od Alice. Wtedy kubit Boba staje się .
# Alice sent the results to Bob. Bob applies correction
with qc.if_test((0, 1)):
qc.z(2)
with qc.if_test((1, 1)):
qc.x(2)
qc.barrier()
qc.draw(output="mpl")
Ukończyłeś obwód teleportacji kwantowej! Zobaczmy stan wyjściowy tego obwodu za pomocą symulatora wektora stanu.
from qiskit_aer import StatevectorSimulator
backend = StatevectorSimulator()
out_vector = backend.run(qc, shots=1).result().get_statevector() # set shots = 1
plot_bloch_multivector(out_vector)

Możesz zobaczyć, że stan kwantowy utworzony przez bramkę na kubicie 0 (kubicie pierwotnie zawierającym tajny stan) został przeniesiony na kubit 2 (kubit Boba).
Możesz uruchomić powyższą komórkę kilka razy, aby się upewnić. Możesz zauważyć, że kubity 0 i 1 zmieniają stany, ale kubit 2 zawsze jest w stanie .
4.3 Wykonaj obwód i potwierdź wynik, aplikując odwrotność U
Powyżej sprawdziliśmy wizualnie, że teleportowany stan wygląda poprawnie. Innym sposobem sprawdzenia, czy stan kwantowy został poprawnie teleportowany, jest zastosowanie odwrotności bramki na kubicie Boba, tak abyśmy mogli zmierzyć '0'. To znaczy, ponieważ jest identycznością, jeśli kubit Boba jest w stanie utworzonym z to zastosowanie odwrotności powinno dać
# Apply the inverse of u-gate to measure |0>
qc.u(theta, varphi, 0.0, 2).inverse() # inverse of u(theta,varphi,0.0)
qc.measure(2, 2) # add measurement gate
qc.draw(output="mpl")
Wykonamy obwód najpierw za pomocą AerSimulator, zanim przejdziemy do prawdziwego komputera kwantowego.
from qiskit_aer import AerSimulator
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import Sampler
from qiskit.visualization import plot_histogram
# 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], shots=nshots)
result = job.result()
# Extract counts data
counts = result[0].data.c.get_counts()
print(counts)
# Plot the counts in a histogram
plot_histogram(counts)
{'011': 2510, '010': 2417, '000': 2635, '001': 2438}
Przypomnijmy, że w notacji little endian kubit 2 jest skrajnie lewym (lub skrajnie dolnym, w etykietach kolumn) kubitem. Zauważ, że skrajnie lewy i skrajnie dolny kubit w etykietach kolumn wynosi 0 dla wszystkich możliwych wyników. Pokazuje to, że mamy 100% szans na zmierzenie w stanie . Jest to oczekiwany wynik i wskazuje, że protokół teleportacji zadziałał poprawnie.
4.4 Teleportacja na prawdziwym komputerze kwantowym
Następnie wykonamy teleportację na prawdziwym komputerze kwantowym. Używając funkcji obwodu dynamicznego, możemy działać w trakcie obwodu, korzystając z wyników pomiarów, implementując w czasie rzeczywistym operacje warunkowe w obwodzie teleportacji. Do rozwiązywania problemów przy użyciu prawdziwych komputerów kwantowych zastosujemy cztery kroki wzorców Qiskit.
- Odwzoruj problem na obwody kwantowe i operatory
- Zoptymalizuj pod kątem docelowego sprzętu
- Wykonaj na docelowym sprzęcie
- Przetwórz wyniki
Ćwiczenie 3: Zbuduj obwód teleportacji
Spróbuj zbudować cały obwód teleportacji od podstaw, aby sprawdzić swoje zrozumienie. Przewiń do góry, jeśli potrzebujesz przypomnienia.
Rozwiązanie:
# Step 1: Map problem to quantum circuits and operators
# Create the circuit with 3-qubits and 1-bit
qc = QuantumCircuit(3, 3)
# Alice creates an unknown quantum state using the u-gate.
qc.u(theta, varphi, 0.0, 0)
qc.barrier() # for visual separation
# Eve creates EPR pair and sends q1 to Alice and q2 to Bob
##your code goes here##
qc.h(1)
qc.cx(1, 2)
qc.barrier()
# Alice entangles the unknown state with her EPR part, using the CNOT gate and H gate.
##your code goes here##
qc.cx(0, 1)
qc.h(0)
qc.barrier()
# Alice measures the two qubits.
##your code goes here##
qc.measure(0, 0)
qc.measure(1, 1)
# Alice sent the results to Bob. Now, Bob applies correction
##your code goes here##
with qc.if_test((0, 1)):
qc.z(2)
with qc.if_test((1, 1)):
qc.x(2)
qc.barrier()
# Apply the inverse of u-gate to measure |0>
qc.u(theta, varphi, 0.0, 2).inverse()
qc.measure(2, 2)
qc.draw(output="mpl")
Przypominamy, że zastosowanie odwrotności bramki służy jedynie temu, abyśmy mogli zweryfikować oczekiwane zachowanie. Nie jest to część wysyłania stanu do Boba i nie użylibyśmy tej odwrotnej bramki , gdyby jedynym celem było przesłanie informacji kwantowej.
Krok 2: Optymalizacja pod kątem docelowego sprzętu
Aby uruchomić na sprzęcie, zaimportuj QiskitRuntimeService i wczytaj zapisane dane uwierzytelniające. Wybierz backend z najmniejszą liczbą zadań w kolejce.
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
service.backends()
[<IBMBackend('ibm_brisbane')>,
<IBMBackend('ibm_torino')>]
# You can also identify the least busy device
backend = service.least_busy(operational=True)
print("The least busy device is ", backend)
The least busy device is <IBMBackend('ibm_brisbane')>
# You can specify the device
# backend = service.backend('ibm_brisbane')
Zobaczmy mapę sprzężeń wybranego urządzenia.
from qiskit.visualization import plot_gate_map
plot_gate_map(backend)

Różne urządzenia mogą mieć różne mapy sprzężeń, a każde urządzenie posiada pewne kubity i sprzęgacze, które działają wydajniej niż inne. Ponadto różne komputery kwantowe mogą mieć różne bramki natywne (bramki, które sprzęt potrafi wykonać). Transpilacja obwodu przepisuje abstrakcyjny obwód kwantowy przy użyciu bramek, które docelowy komputer kwantowy potrafi wykonać, i wybiera optymalne odwzorowanie na fizyczne kubity (między innymi). Transpilacja jest bogatym i skomplikowanym zagadnieniem. Więcej informacji o transpilacji znajdziesz w dokumentacji API.
# Step 2: Optimize for target hardware
# Transpile the circuit into basis gates executable on the hardware
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
pm = generate_preset_pass_manager(backend=backend, optimization_level=2)
qc_compiled = pm.run(qc)
qc_compiled.draw("mpl", idle_wires=False, fold=-1)
Krok 3: Wykonaj obwód.
Używając prymitywu Runtime Sampler, wykonamy docelowy obwód.
# Step 3: Execute the target circuit
sampler = Sampler(backend)
job = sampler.run([qc_compiled])
job_id = job.job_id()
print("job id:", job_id)
job id: d13nkhpn2txg008jt0d0
# Check the job status
job.status()
'DONE'
Status zadania możesz również sprawdzić na swoim panelu IBM Quantum®.
# 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.job_id()) # Input your job-id between the quotations
job_real.status()
'DONE'
Jeśli widzisz wyświetlony komunikat 'DONE', możesz uzyskać wynik, wykonując poniższą komórkę.
# Execute after 'DONE' is displayed
result_real = job_real.result()
print(result_real[0].data.c.get_counts())
{'001': 992, '110': 430, '011': 579, '010': 605, '111': 402, '000': 925, '100': 57, '101': 106}
Krok 4: Przetwarzanie końcowe wyników
# Step 4: Post-process the results
from qiskit.visualization import plot_histogram
plot_histogram(result_real[0].data.c.get_counts())
Powyższe wyniki można interpretować bezpośrednio. Alternatywnie, używając marginal_count, można wyodrębnić wyniki Boba na kubicie 2.
# trace out Bob's results on qubit 2
from qiskit.result import marginal_counts
bobs_qubit = 2
real_counts = result_real[0].data.c.get_counts()
bobs_counts = marginal_counts(real_counts, [bobs_qubit])
plot_histogram(bobs_counts)
Jak widać, jest kilka wyników, w których zmierzyliśmy . Wynikają one z szumu i błędów. W szczególności obwody dynamiczne zwykle mają wyższy wskaźnik błędów ze względu na czasochłonny pomiar w środku obwodu.
4.5 Kluczowe wnioski dotyczące teleportacji kwantowej
Możemy przesłać stan kwantowy odległemu znajomemu, dzieląc parę splątanych kubitów (e-bit).
-
Czy teleportacja kwantowa może przesłać stan kwantowy szybciej niż światło? Nie, ponieważ Alice musi przekazać Bobowi wyniki pomiaru w sposób klasyczny.
-
Czy teleportacja kwantowa złamałaby „twierdzenie o nieklonowaniu”, które zabrania kopiowania stanu kwantowego? Nie, ponieważ pierwotny stan kwantowy przekazany Alice na jednym z jej kubitów został utracony podczas pomiaru. Został on skolapsowany do lub .
5. Kodowanie supergęste
Niemal taki sam układ można wykorzystać w innym celu. Załóżmy, że Alice chce wysłać Bobowi dwa bity informacji klasycznej, ale nie dysponuje żadnymi środkami komunikacji klasycznej z Bobem. Dzieli jednak z Bobem parę splątaną i może wysłać swój kubit do lokalizacji Boba. Zwróć uwagę na kontrast z protokołem teleportacji kwantowej. W teleportacji komunikacja klasyczna była dostępna między znajomymi, a celem było przesłanie stanu kwantowego. Tutaj komunikacja klasyczna jest niedostępna i używają oni transferu kubitu, aby współdzielić dwa bity informacji klasycznej.
5.1 Protokół kodowania supergęstego
Założenie: Alice ma dwa bity informacji, powiedzmy . Alice i Bob współdzielą splątaną parę (e-bit), ale nie mogą komunikować się klasycznie.
- Alice wykonuje jedną z następujących operacji na swojej części e-bitu.
- Jeśli , nie robi nic
- Jeśli , stosuje bramkę Z
- Jeśli , stosuje bramkę X
- Jeśli , stosuje bramkę Z oraz bramkę X.
- Alice wysyła swoją część e-bitu do lokalizacji Boba.
- Bob stosuje bramkę CNOT z kubitem od Alice jako sterującym i swoim kubitem jako celem, a następnie stosuje bramkę H na kubicie od Alice i mierzy oba kubity. Możliwe stany początkowe oraz wyniki operacji Boba to:
Zauważ, że ujemny znak w jest fazą globalną, więc nie jest mierzalny.
5.2 Obwód kwantowy symulujący kodowanie supergęste
Na podstawie protokołu kodowania supergęstego można zbudować obwód kodowania supergęstego jak poniżej. Spróbuj zmienić wiadomość msg, którą Alice chce przekazać Bobowi.
from qiskit import QuantumCircuit
Kroki wzorca Qiskit są oznaczone w komentarzach w kodzie.
# Step 1: Map problem to quantum circuits and operators
# Create 2-qubits circuit
qc = QuantumCircuit(2, 2)
# Eve creates EPR pair and send q0 to Alice and q1 to Bob
qc.h(0)
qc.cx(0, 1)
qc.barrier()
# set message which Alice wants to transform to Bob
msg = "11" # You can change the message
if msg == "00":
pass
elif msg == "10":
qc.x(0)
elif msg == "01":
qc.z(0)
elif msg == "11":
qc.z(0)
qc.x(0)
qc.barrier()
# Bob receives EPR qubit from Alice and performs unitary operations
qc.cx(0, 1)
qc.h(0)
qc.barrier()
# Bob measures q0 and q1
qc.measure(0, 0)
qc.measure(1, 1)
qc.draw(output="mpl")
# We will execute on a simulator first
from qiskit_aer import AerSimulator
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import Sampler
# Define backend
backend = AerSimulator()
shots = 1000
# 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_sim = sampler.run([isa_qc], shots=shots)
result_sim = job_sim.result()
# Extract counts data
counts = result_sim[0].data.c.get_counts()
print(counts)
{'11': 1000}
# Visualize the results
from qiskit.visualization import plot_histogram
plot_histogram(counts)
Jak widać, Bob otrzymał wiadomość, którą chciała mu wysłać Alice.
Następnie wypróbujmy to na prawdziwym komputerze kwantowym.
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
backend = service.least_busy(operational=True)
print("The least busy device is ", backend)
The least busy device is <IBMBackend('ibm_brisbane')>
# Step 1 was already completed before the simulator job above.
# Step 2: Optimize for target hardware
# Transpile the circuit into basis gates executable on the hardware
pm = generate_preset_pass_manager(backend=backend, optimization_level=2)
qc_compiled = pm.run(qc)
qc_compiled.draw("mpl", idle_wires=False)
# Step 3:Execute the target circuit
sampler = Sampler(backend)
job = sampler.run([qc_compiled])
job_id = job.job_id()
print("job id:", job_id)
job id: d13nnyq3grvg008j0zag
# Check the job status
job.status()
'DONE'
# 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 = service.job(job_id) # Input your job-id between the quotations
job.status()
'DONE'
# Execute after job has successfully run
real_result = job.result()
print(real_result[0].data.c.get_counts())
{'11': 3942, '01': 107, '10': 41, '00': 6}
# Step 4: post-process the results
from qiskit.visualization import plot_histogram
plot_histogram(real_result[0].data.c.get_counts())
Wynik jest zgodny z oczekiwaniami. Zauważ, że kodowanie superskomasowane na prawdziwym komputerze kwantowym wykazało mniej błędów niż teleportacja kwantowa na prawdziwym komputerze kwantowym. Jednym z powodów może być to, że teleportacja kwantowa korzysta z obwodów dynamicznych, a kodowanie superskomasowane nie. Więcej o błędach w obwodach kwantowych dowiemy się w kolejnych lekcjach.
6. Podsumowanie
W tej sesji zaimplementowaliśmy dwa protokoły kwantowe. Chociaż scenariusze obu z nich, obejmujące oddalonych od siebie przyjaciół, są nieco oderwane od obliczeń kwantowych na pojedynczym QPU, mają one zastosowania w obliczeniach kwantowych i pomagają lepiej zrozumieć przekazywanie informacji kwantowej.
- Teleportacja kwantowa: Chociaż nie możemy kopiować stanów kwantowych, możemy teleportować nieznane stany kwantowe, dysponując współdzielonym splątaniem.
- Kwantowe kodowanie superskomasowane: Współdzielona para splątanych kubitów oraz przesłanie jednego kubita umożliwiają przekazanie dwóch bitów informacji klasycznej.
# See the version of Qiskit
import qiskit
qiskit.__version__
'2.0.2'