Vai al contenuto principale

Teletrasporto quantistico e codifica superdensa

nota

Kifumi Numata (26 Apr 2024)

Scarica il PDF della lezione originale. Alcuni frammenti di codice potrebbero essere obsoleti poiché sono immagini statiche.

Il tempo QPU approssimativo per eseguire questo esperimento è di 10 secondi.

1. Introduzione

Per risolvere qualsiasi problema quantistico su scala utility, dobbiamo spostare le informazioni all'interno di un computer quantistico da un qubit a un altro. Esistono protocolli ben noti per farlo, ma alcuni dei più fondamentali sono stati concepiti nel contesto dell'invio di informazioni tra parti distanti. Nel corso di questa lezione, useremo a volte un linguaggio coerente con questo contesto, come "amici lontani che si scambiano informazioni". Tuttavia, tieni presente che questi protocolli hanno un significato più ampio nel calcolo quantistico. In questa lezione prendiamo in considerazione i seguenti protocolli di comunicazione quantistica:

  • Teletrasporto quantistico Uso di uno stato entangled condiviso (a volte chiamato e-bit) per inviare uno stato quantistico sconosciuto a un amico lontano, richiedendo una comunicazione classica supplementare.
  • Codifica superdensa quantistica Come inviare due bit di informazione trasmettendo un singolo qubit a un amico lontano (anche in questo caso utilizzando qubit entangled condivisi in precedenza).

Per ulteriori approfondimenti su questi argomenti, consigliamo la lezione 4 di Nozioni di base sull'informazione quantistica su Entanglement in azione.

Nella descrizione precedente, uno "stato quantistico sconosciuto" si riferisce semplicemente a uno stato della forma descritta nella lezione precedente:

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

dove α\alpha e β\beta sono numeri complessi tali che α2+β2=1|\alpha|^2+|\beta|^2 = 1. Questo ci permette di scrivere lo stato quantistico come

ψ=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{matrix} \cos\frac{\theta}{2}\\ e^{i\varphi}\sin\frac{\theta}{2} \end{matrix} \right)

Poiché vogliamo poter trasferire le informazioni contenute in qualsiasi stato quantistico casuale, questa lezione inizierà proprio dalla generazione di tale stato.

2. Matrici densità

Possiamo anche scrivere lo stato quantistico ψ|\psi \rangle come sua matrice densità. Questa forma è utile per indicare la miscela probabilistica di stati quantistici puri. Nel caso di un singolo qubit, possiamo scrivere

ψψρ=((cosθ2eiφsinθ2))((cosθ2eiφsinθ2))=12((1+cosθeiφsinθeiφsinθ1cosθ))|\psi \rangle \langle \psi| \equiv \rho = \left( \begin{pmatrix} \cos\frac{\theta}{2}\\ e^{i\varphi}\sin\frac{\theta}{2} \end{pmatrix} \right) \left( \begin{pmatrix} \cos\frac{\theta}{2} & e^{-i\varphi}\sin\frac{\theta}{2} \end{pmatrix} \right) =\frac{1}{2}\left(\begin{pmatrix} 1+\cos\theta & e^{-i\varphi}\sin\theta\\ e^{-i\varphi}\sin\theta & 1-\cos\theta \end{pmatrix}\right)

Nota che la matrice densità ρ\rho è una somma lineare delle matrici di Pauli, come mostrato di seguito:

ρ=12(I+(sinθcosφ)X+(sinθsinφ)Y+(cosθ)Z)\rho = \frac{1}{2}\bigl( \textbf{I} + (\sin{\theta}\cos{\varphi})\textbf{X}+ (\sin{\theta}\sin{\varphi})\textbf{Y} + (\cos{\theta})\textbf{Z} \bigr)

O, in generale,

ρ=12(I+rxX+ryY+rzZ)\rho = \frac{1}{2}(\textbf{I} + r_{x}\textbf{X}+ r_{y}\textbf{Y} + r_{z}\textbf{Z})

dove rx2+ry2+rz2=1r_{x}^2+r_{y}^2+r_{z}^2=1.

Il vettore di Bloch è r=(rx,ry,rz)\textbf{r} = (r_{x}, r_{y}, r_{z}).

Ora creiamo un stato quantistico arbitrario usando numeri casuali.

# 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)

Possiamo visualizzare questo vettore di Bloch sulla sfera di Bloch.

from qiskit.visualization import plot_bloch_vector

r = [rx, ry, rz]
plot_bloch_vector(r)

Output of the previous code cell

3. Tomografia dello stato quantistico

Se misuri lo stato quantistico solo nella base computazionale (0|0 \rangle e 1|1 \rangle), le informazioni di fase (le informazioni sui numeri complessi) andranno perse. Ma se abbiamo molte copie di ψ|\psi \rangle ripetendo il processo di preparazione (non possiamo clonare gli stati, ma possiamo ripetere i processi di preparazione), possiamo stimare il valore di rx,ry,rzr_{x}, r_{y}, r_{z} eseguendo la tomografia dello stato quantistico per la matrice densità ρ\rho. Data la forma:

ρ=12(I+rxX+ryY+rzZ)\rho = \frac{1}{2}(\textbf{I} + r_{x}\textbf{X}+ r_{y}\textbf{Y} + r_{z}\textbf{Z})

vale che

Tr(Xρ)=rx,Tr(Yρ)=ry,Tr(Zρ)=rzTr(\textbf{X} \rho) = r_{x}, \quad Tr(\textbf{Y} \rho) = r_{y}, \quad Tr(\textbf{Z} \rho) = r_{z}

Nel caso di rzr_{z},

Tr(Zρ)=0Zρ0+1Zρ1Tr(\textbf{Z} \rho) = \langle 0|\textbf{Z} \rho|0 \rangle + \langle 1|\textbf{Z} \rho|1 \rangle =0(0011)ρ0+1(0011)ρ1= \langle 0|(|0 \rangle\langle 0|-|1 \rangle\langle 1|) \rho|0 \rangle +\langle 1|(|0 \rangle\langle 0|-|1 \rangle\langle 1|) \rho|1 \rangle =0ρ01ρ1=\langle 0|\rho|0 \rangle- \langle 1| \rho|1 \rangle =0ψψ01ψψ1=\langle 0|\psi\rangle\langle \psi|0 \rangle - \langle 1| \psi\rangle\langle \psi|1 \rangle =α2β2=|\alpha|^2-|\beta|^2

L'ultima trasformazione dell'equazione vale per ψ=α0+β1|\psi \rangle =\alpha|0\rangle+\beta|1\rangle. Pertanto, possiamo ottenere rzr_{z} come probabilità di 0|0 \rangle - Probabilità di 1|1 \rangle.

Stima del valore rzr_z

Per stimare rzr_z, creiamo uno stato quantistico e lo misuriamo. Poi ripetiamo la preparazione e la misurazione molte volte. Infine usiamo le statistiche delle misurazioni per stimare le probabilità precedenti e quindi stimare rzr_z.

Per creare lo stato quantistico casuale, utilizzeremo il gate unitario generale UU con i parametri θ,φ\theta, \varphi. (Consulta U-gate per ulteriori informazioni.)

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")

Output of the previous code cell

Usando AerSimulator, misuriamo nella base computazionale per stimare rzr_z.

# 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}

Output of the previous code cell

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

Usando il metodo della tomografia dello stato quantistico, abbiamo stimato il valore di rzr_z. In questo caso, poiché abbiamo scelto un parametro per lo stato "casuale", conosciamo il valore di rzr_z e possiamo verificare il nostro lavoro. Ma per sua stessa natura, il lavoro su scala utility non è sempre così banale da verificare. Parleremo più avanti in questo corso di come controllare i risultati quantistici. Per ora, nota semplicemente che la nostra stima era ragionevolmente accurata.

Esercizio 1: Stima del valore rxr_x

Ricorda che i computer quantistici IBM® misurano lungo l'asse zz (a volte indicato come "nella base zz" o "nella base computazionale"). Tuttavia, usando delle rotazioni prima della misurazione, possiamo misurare anche la proiezione dello stato quantistico sull'asse x. Per essere più precisi, se ruotiamo il sistema in modo che ciò che puntava lungo xx ora punti lungo zz, possiamo mantenere lo stesso hardware di misurazione lungo zz, ma apprendere lo stato che poco fa era lungo xx. Così la maggior parte dei computer quantistici (e tutti i computer quantistici IBM) esegue misurazioni lungo più assi.

Con questa comprensione, prova a scrivere del codice per stimare il valore di rxr_x usando la tomografia dello stato quantistico.

Soluzione:

# 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")

Output of the previous code cell

# 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}

Output of the previous code cell

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

Esercizio 2: Stima del valore ryr_y

Usando gli stessi argomenti logici di prima, possiamo ruotare il sistema prima della misurazione per apprendere il valore di ryr_y. Prova a scrivere il codice per stimare il valore di ryr_y usando la tomografia dello stato quantistico. Puoi partire dall'esempio precedente, ma applicare rotazioni diverse. (Per ulteriori informazioni sui vari gate usati, incluso sdg, consulta il riferimento API.)

Soluzione:

# 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")

Output of the previous code cell

# 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}

Output of the previous code cell

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

Abbiamo ora stimato tutte le componenti di r\vec{r} e possiamo scrivere il vettore completo.

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).

Hai ottenuto una stima del vettore casuale originale con buona precisione usando questo metodo di tomografia dello stato quantistico.

4. Teletrasporto quantistico

Consideriamo la situazione in cui Alice vuole inviare uno stato quantistico sconosciuto ψ|\psi \rangle al suo amico Bob, che si trova lontano. Supponiamo che possano comunicare solo tramite comunicazione classica (ad esempio via email o telefono). Alice non può copiare lo stato quantistico (a causa del teorema di non clonazione). Se ripetesse lo stesso processo di preparazione molte volte, potrebbe raccogliere statistiche come abbiamo appena fatto. Ma cosa succederebbe se ci fosse un solo stato sconosciuto? Questo stato potrebbe essere emerso da un processo fisico che vuoi studiare. Oppure potrebbe far parte di un calcolo quantistico più ampio. In quel caso, come potrebbe Alice inviare lo stato a Bob? Può farlo, se lei e Bob condividono una preziosa risorsa quantistica: uno stato entangled condiviso, come lo stato di Bell introdotto nella lezione precedente: 00+112.\frac {|00\rangle + |11\rangle}{\sqrt 2}. A volte questo viene chiamato anche "coppia EPR" o "e-bit" (un'unità fondamentale di entanglement). Se Alice condivide un tale stato entangled con Bob, può teletrasportare lo stato quantistico sconosciuto a Bob eseguendo una serie di operazioni quantistiche e inviandogli due bit di informazione classica.

4.1 Il protocollo del teletrasporto quantistico

Ipotesi: Alice ha uno stato quantistico sconosciuto ψ|\psi \rangle da inviare a Bob. Alice e Bob condividono uno stato entangled a 2 qubit, o e-bit, ciascuno con uno dei qubit fisicamente nella propria posizione.

Qui descriviamo la procedura senza spiegazione. Questi passaggi saranno implementati in dettaglio di seguito.

  1. Alice entangla ψ|\psi \rangle con la sua parte dell'e-bit utilizzando il gate CNOT.
  2. Alice applica un gate Hadamard a ψ|\psi \rangle e misura entrambi i suoi qubit nella base computazionale.
  3. Alice invia a Bob i risultati della sua misurazione (either "00", "01", "10", o "11")
  4. Bob esegue un operatore di correzione basato sui due bit di informazione di Alice sulla sua parte della coppia e-bit.
    • Se "00", Bob non fa nulla
    • Se "01", Bob applica il gate X
    • Se "10", Bob applica il gate Z
    • Se "11", Bob applica iY = ZX gate
  5. La parte di Bob dell'e-bit diventa ψ|\psi \rangle.

Questo è trattato in modo più dettagliato anche in Basics of Quantum Information. Ma la situazione sarà più chiara quando lo istanzieremo in Qiskit.

4.2 Circuito quantistico che simula il teletrasporto quantistico

Come sempre, applicheremo il framework dei pattern Qiskit. Questa sottosezione si concentrerà solo sulla mappatura.

Step 1: Mappa il problema su circuiti quantistici e operatori

Per descrivere lo scenario precedente, abbiamo bisogno di un circuito con tre qubit: due per la coppia entangled condivisa tra Alice e Bob, e uno per lo stato quantistico sconosciuto ψ|\psi\rangle.

from qiskit import QuantumCircuit
import numpy as np
# create 3-qubits circuit
qc = QuantumCircuit(3, 3)

qc.draw(output="mpl")

Output of the previous code cell

All'inizio, Alice ha uno stato quantistico sconosciuto ψ.|\psi \rangle. Lo creeremo usando il gate UU.

# 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")

Output of the previous code cell

Possiamo visualizzare lo stato che abbiamo creato, ma solo perché sappiamo quali parametri sono stati usati nel gate UU. Se questo stato fosse emerso da un processo quantistico complicato, lo stato non sarebbe conoscibile senza eseguire il processo molte volte per creare lo stato e raccogliere statistiche come nella tomografia.

# 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)

Output of the previous code cell

Prima ancora che questo protocollo abbia inizio, assumiamo che Alice e Bob abbiano una coppia entangled condivisa. Se Alice e Bob si trovano davvero in luoghi diversi, potrebbero aver configurato lo stato condiviso prima che lo stato sconosciuto ψ|\psi\rangle venisse mai creato. Poiché queste operazioni avvengono su qubit diversi, il loro ordine non è importante, e questo ordine è conveniente per la visualizzazione.

# 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")

Output of the previous code cell

Successivamente, Alice entangla ψ|\psi \rangle con la sua parte dell'e-bit condiviso, utilizzando il gate CXCX e il gate HH, e li misura nella base computazionale.

# 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")

Output of the previous code cell

Alice invia a Bob i risultati della sua misurazione (either "00", "01", "10", o "11"), e Bob esegue un operatore di correzione basato sui due bit di informazione di Alice sulla sua parte dell'e-bit condiviso. Poi, la parte di Bob diventa ψ|\psi \rangle.

# 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")

Output of the previous code cell

Hai completato un circuito di teletrasporto quantistico! Vediamo lo stato di output di questo circuito usando il simulatore di statevector.

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)

Output of the previous code cell

Puoi vedere che lo stato quantistico creato dal gate UU del qubit 0 (il qubit che originariamente conteneva lo stato segreto) è stato trasferito al qubit 2 (il qubit di Bob).

Puoi eseguire la cella precedente alcune volte per assicurarti. Potresti notare che i qubit 0 e 1 cambiano stato, ma il qubit 2 è sempre nello stato ψ|\psi\rangle.

4.3 Esecuzione e verifica del risultato applicando U inverso

In precedenza, abbiamo verificato visivamente che lo stato teletrasportato sembrava corretto. Un altro modo per verificare se lo stato quantistico è stato teletrasportato correttamente è applicare l'inverso del gate UU sul qubit di Bob, in modo da poter misurare '0'. Cioè, poiché U1UU^{-1}U è l'identità, se il qubit di Bob si trova nello stato creato da U0,U|0\rangle, allora applicare l'inverso dovrebbe dare U1U0=0.U^{-1}U|0\rangle=|0\rangle.

# 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")

Output of the previous code cell

Eseguiremo il circuito prima usando l'AerSimulator, prima di passare a un vero computer quantistico.

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}

Output of the previous code cell

Ricorda che nella notazione little endian, il qubit 2 è il qubit più a sinistra (o più in basso, nelle etichette delle colonne). Nota che il qubit più a sinistra e più in basso nelle etichette delle colonne è 0 per tutti i possibili risultati. Ciò dimostra che abbiamo una probabilità del 100% di misurare q2q_2 nello stato 0|0\rangle. Questo è il risultato atteso e indica che il protocollo di teletrasporto ha funzionato correttamente.

4.4 Teletrasporto su un vero computer quantistico

Successivamente, eseguiremo il teletrasporto su un vero computer quantistico. Utilizzando la funzione dei circuiti dinamici, possiamo operare a metà circuito usando i risultati delle misurazioni, implementando in tempo reale le operazioni condizionali nel circuito di teletrasporto. Per risolvere problemi con veri computer quantistici, seguiremo i quattro passaggi dei pattern Qiskit.

  1. Mappa il problema su circuiti quantistici e operatori
  2. Ottimizza per l'hardware di destinazione
  3. Esegui sull'hardware di destinazione
  4. Post-elabora i risultati

Esercizio 3: Costruisci il circuito di teletrasporto

Prova a costruire l'intero circuito di teletrasporto da zero per testare la tua comprensione. Scorri su se hai bisogno di un promemoria.

Soluzione:

# 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")

Output of the previous code cell

Come promemoria, applicare l'inverso del gate UU serve solo per verificare il comportamento atteso. Non fa parte dell'invio dello stato a Bob, e non useremmo quel gate UU inverso se l'unico obiettivo fosse trasferire informazioni quantistiche.

Step 2: Ottimizza per l'hardware di destinazione

Per eseguire sull'hardware, importa QiskitRuntimeService e carica le tue credenziali salvate. Seleziona il backend con il minor numero di job in coda.

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')

Vediamo la mappa di accoppiamento del dispositivo che hai selezionato.

from qiskit.visualization import plot_gate_map

plot_gate_map(backend)

Output of the previous code cell

Dispositivi diversi possono avere mappe di accoppiamento diverse, e ogni dispositivo ha alcuni qubit e connettori più performanti di altri. Infine, diversi computer quantistici potrebbero avere gate nativi diversi (gate che l'hardware è in grado di eseguire). La transpilazione del circuito riscrive il circuito quantistico astratto usando gate che il computer quantistico di destinazione può eseguire, e seleziona la mappatura ottimale sui qubit fisici (tra le altre cose). La transpilazione è un argomento ricco e complesso. Per ulteriori informazioni sulla transpilazione, consulta il riferimento 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)

Output of the previous code cell

Step 3: Esegui il circuito.

Usando la primitiva Runtime Sampler, eseguiremo il circuito di destinazione.

# 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'

Puoi anche controllare lo stato del job dalla tua dashboard 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'

Se vedi 'DONE', puoi ottenere il risultato eseguendo la cella seguente.

# 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}

Step 4: Post-elabora i risultati

# Step 4: Post-process the results
from qiskit.visualization import plot_histogram

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

Output of the previous code cell

Puoi interpretare i risultati precedenti direttamente. Oppure, usando marginal_count, puoi tracciare i risultati di Bob sul qubit 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)

Output of the previous code cell

Come vediamo qui, ci sono alcuni risultati in cui abbiamo misurato 1|1 \rangle. Questi sono dovuti al rumore e agli errori. In particolare, i circuiti dinamici tendono ad avere un tasso di errore più elevato a causa della misurazione che richiede tempo a metà del circuito.

4.5 Punti chiave sul teletrasporto quantistico

Possiamo trasportare uno stato quantistico a un amico lontano condividendo una coppia di qubit entangled (un e-bit).

  1. Il teletrasporto quantistico può inviare lo stato quantistico più veloce della luce? No, perché Alice deve comunicare a Bob i risultati della misurazione in modo classico.

  2. Il teletrasporto quantistico violerebbe il "teorema di non clonazione", che vieta la copia di uno stato quantistico? No, perché lo stato quantistico originale dato ad Alice su uno dei suoi qubit è andato perso nella misurazione. È collassato a 0|0\rangle o 1|1\rangle.

5. Codifica superdensa

La stessa configurazione può essere usata per uno scopo diverso. Supponiamo che Alice voglia inviare a Bob due bit di informazione classica, ma non disponga di mezzi di comunicazione classica con Bob. Ha però una coppia entangled condivisa con Bob ed è autorizzata a inviare il suo qubit alla posizione di Bob. Nota il contrasto con il protocollo di teletrasporto quantistico. Nel teletrasporto, la comunicazione classica era disponibile per i due amici, e l'obiettivo era inviare uno stato quantistico. Qui, la comunicazione classica non è accessibile e si usa il trasferimento di un qubit per condividere due bit di informazione classica.

5.1 Il protocollo della codifica superdensa

Ipotesi: Alice ha due bit di informazione, diciamo, a1a2{00,01,10,11}a_1a_2 \in \{00, 01, 10, 11\}. Alice e Bob condividono una coppia entangled (e-bit), ma non possono comunicare classicamente.

  1. Alice esegue una delle seguenti operazioni sulla sua parte dell'e-bit.
    • Se a1a2=00a_1a_2 = 00, non fa nulla
    • Se a1a2=01a_1a_2 = 01, applica il gate Z
    • Se a1a2=10a_1a_2 = 10, applica il gate X
    • Se a1a2=11a_1a_2 = 11, applica il gate Z e il gate X.
  2. Alice invia la sua parte dell'e-bit alla posizione di Bob.
  3. Bob applica un gate CNOT con il qubit di Alice come controllo e il suo qubit come target, poi applica il gate H al qubit di Alice, e misura i due qubit. I possibili stati iniziali e i risultati delle operazioni di Bob sono:
00+112CX01H000\frac {|00\rangle + |11\rangle}{\sqrt 2} \rightarrow CX_{01}\otimes H_0 \rightarrow |00\rangle 00112CX01H001\frac {|00\rangle - |11\rangle}{\sqrt 2} \rightarrow CX_{01}\otimes H_0 \rightarrow |01\rangle 10+012CX01H010\frac {|10\rangle + |01\rangle}{\sqrt 2} \rightarrow CX_{01}\otimes H_0 \rightarrow |10\rangle 10012CX01H011\frac {|10\rangle - |01\rangle}{\sqrt 2} \rightarrow CX_{01}\otimes H_0 \rightarrow -|11\rangle

Nota che il segno negativo di 11-|11\rangle è una fase globale, quindi non è misurabile.

5.2 Circuito quantistico che simula la codifica superdensa

Basandoti sul protocollo della codifica superdensa, puoi costruire il circuito di codifica superdensa come mostrato di seguito. Prova a cambiare il messaggio, msg, che Alice vuole trasmettere a Bob.

from qiskit import QuantumCircuit

I passaggi dei pattern Qiskit sono identificati nei commenti del codice.

# 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")

Output of the previous code cell

# 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)

Output of the previous code cell

Puoi vedere che Bob ha ricevuto il messaggio che Alice voleva inviargli.

Ora proviamo con un vero computer quantistico.

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)

Output of the previous code cell

# 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())

Output of the previous code cell

Il risultato è quello che ci aspettavamo. Nota che la codifica superdensa su un vero computer quantistico ha mostrato meno errori rispetto al caso del teletrasporto quantistico su un vero computer quantistico. Una ragione potrebbe essere che il teletrasporto quantistico utilizza circuiti dinamici, mentre la codifica superdensa no. Impareremo di più sugli errori nei circuiti quantistici nelle lezioni successive.

6. Riepilogo

In questa sessione, abbiamo implementato due protocolli quantistici. Sebbene gli scenari per entrambi, che coinvolgono amici lontani, siano in qualche modo distanti dal calcolo quantistico su un singolo QPU, hanno applicazioni nel calcolo quantistico e ci aiutano a comprendere meglio il trasferimento di informazioni quantistiche.

  • Teletrasporto quantistico: Sebbene non possiamo copiare stati quantistici, possiamo teletrasportare stati quantistici sconosciuti avendo un entanglement condiviso.
  • Codifica superdensa quantistica: Una coppia entangled condivisa e il trasferimento di un qubit consentono la comunicazione di due bit di informazione classica.
# See the version of Qiskit
import qiskit

qiskit.__version__
'2.0.2'