Aller au contenu principal

Téléportation quantique et codage superdense

remarque

Kifumi Numata (26 avr. 2024)

Télécharger le PDF du cours original. Attention, certains extraits de code pourraient être obsolètes car il s'agit d'images statiques.

Le temps QPU approximatif pour exécuter cette expérience est de 10 secondes.

1. Introduction

Pour résoudre tout problème quantique à l'échelle utilitaire, nous aurons besoin de déplacer de l'information sur un ordinateur quantique d'un qubit à un autre. Il existe des protocoles bien connus pour ce faire, mais certains des plus fondamentaux ont été formulés dans le contexte de l'envoi d'information entre des parties distantes. Tout au long de cette leçon, nous utiliserons parfois un langage cohérent avec ce contexte, comme « des amis distants qui s'envoient de l'information ». Mais garde à l'esprit que ces protocoles ont une portée plus large en informatique quantique. Dans cette leçon, nous examinons les protocoles de communication quantique suivants :

  • Téléportation quantique Utiliser un état intriqué partagé (parfois appelé e-bit) pour envoyer un état quantique inconnu à un ami distant, en nécessitant une communication classique supplémentaire.
  • Codage superdense quantique Comment envoyer deux bits d'information en transmettant un seul qubit à un ami distant (là encore en utilisant des qubits intriqués partagés au préalable).

Pour plus de contexte sur ces sujets, nous recommandons la leçon 4 des Bases de l'information quantique sur L'intrication en action.

Dans la description ci-dessus, un « état quantique inconnu » désigne simplement un état de la forme décrite dans la leçon précédente :

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

α\alpha et β\beta sont des nombres complexes tels que α2+β2=1|\alpha|^2+|\beta|^2 = 1. Cela nous permet d'écrire l'état quantique sous la forme

ψ=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)

Puisque nous voulons pouvoir transférer l'information contenue dans n'importe quel état quantique aléatoire, la génération d'un tel état sera notre point de départ dans cette leçon.

2. Matrices densité

On peut aussi écrire l'état quantique ψ|\psi \rangle sous forme de matrice densité. Cette représentation est utile pour décrire un mélange probabiliste d'états quantiques purs. Dans le cas d'un seul qubit, on peut écrire

ψψρ=((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)

Note que la matrice densité ρ\rho est une combinaison linéaire des matrices de Pauli, comme ci-dessous,

ρ=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)

Ou, de manière générale,

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

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

Et le vecteur de Bloch est r=(rx,ry,rz)\textbf{r} = (r_{x}, r_{y}, r_{z}).

Maintenant, créons un état quantique arbitraire à l'aide de nombres aléatoires.

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

On peut représenter ce vecteur de Bloch sur la sphère de Bloch.

from qiskit.visualization import plot_bloch_vector

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

Sortie de la cellule de code précédente

3. Tomographie d'état quantique

Si tu mesures l'état quantique uniquement dans la base computationnelle (0|0 \rangle et 1|1 \rangle), l'information de phase (l'information sur les nombres complexes) sera perdue. Mais si on dispose de nombreuses copies de ψ|\psi \rangle en répétant le processus de préparation (on ne peut pas cloner des états, mais on peut répéter les processus de préparation), on peut estimer les valeurs de rx,ry,rzr_{x}, r_{y}, r_{z} en réalisant une tomographie d'état quantique pour la matrice densité ρ\rho. Étant donné la forme :

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

il s'ensuit que

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}

Dans le cas de 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

La dernière transformation de l'équation est valable pour ψ=α0+β1|\psi \rangle =\alpha|0\rangle+\beta|1\rangle. On peut donc obtenir rzr_{z} en calculant la probabilité de 0|0 \rangle moins la probabilité de 1|1 \rangle.

Estimer la valeur de rzr_z

Pour estimer rzr_z, nous créons un état quantique et le mesurons. Nous répétons ensuite la préparation et la mesure de nombreuses fois. Enfin, nous utilisons les statistiques des mesures pour estimer les probabilités ci-dessus et ainsi estimer rzr_z.

Pour créer l'état quantique aléatoire, nous utiliserons la porte unitaire générale UU avec les paramètres θ,φ\theta, \varphi. (Consulter la porte U pour plus d'informations.)

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

Sortie de la cellule de code précédente

En utilisant l'AerSimulator, nous allons mesurer dans la base computationnelle pour estimer 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}

Sortie de la cellule de code précédente

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

En utilisant la méthode de tomographie d'état quantique, nous avons estimé la valeur de rzr_z. Dans ce cas, comme nous avons choisi un paramètre pour l'état « aléatoire », nous connaissons la valeur de rzr_z et pouvons vérifier notre résultat. Mais par nature, les travaux à l'échelle utilitaire ne sont pas toujours aussi simples à vérifier. Nous aborderons plus en détail la vérification des résultats quantiques plus loin dans ce cours. Pour l'instant, note simplement que notre estimation était raisonnablement précise.

Exercice 1 : Estimer la valeur de rxr_x

Rappelle-toi que les ordinateurs quantiques IBM® mesurent le long de l'axe zz (parfois formulé « dans la base zz » ou « dans la base computationnelle »). Cependant, en appliquant des rotations avant la mesure, nous pouvons aussi mesurer la projection de l'état quantique sur l'axe x. Pour être plus précis, si nous faisons pivoter notre système de sorte que ce qui pointait le long de xx pointe maintenant le long de zz, alors nous pouvons conserver le même matériel de mesure le long de zz, tout en apprenant des informations sur l'état qui pointait le long de xx un instant auparavant. C'est ainsi que la plupart des ordinateurs quantiques (et tous les ordinateurs quantiques IBM) effectuent des mesures selon plusieurs axes.

Avec cette compréhension, essaie d'écrire du code pour estimer la valeur de rxr_x en utilisant la tomographie d'état quantique.

Solution :

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

Sortie de la cellule de code précédente

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

Sortie de la cellule de code précédente

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

Exercice 2 : Estimer la valeur de ryr_y

En utilisant les mêmes arguments logiques que précédemment, nous pouvons faire pivoter le système avant la mesure pour obtenir des informations sur ryr_y. Essaie d'écrire toi-même du code pour estimer la valeur de ryr_y en utilisant la tomographie d'état quantique. Tu peux partir de l'exemple précédent, mais effectuer des rotations différentes. (Pour plus d'informations sur les diverses portes utilisées, notamment sdg, consulte la référence API.)

Solution :

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

Sortie de la cellule de code précédente

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

Sortie de la cellule de code précédente

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

Nous avons maintenant estimé toutes les composantes de r\vec{r} et pouvons écrire le vecteur complet.

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

Tu as obtenu une estimation assez précise du vecteur aléatoire original grâce à cette méthode de tomographie d'état quantique.

4. Téléportation quantique

Considérons la situation où un personnage, Alice, souhaite envoyer un état quantique inconnu ψ|\psi \rangle à son ami Bob, qui est loin. Supposons qu'ils ne peuvent communiquer que par communication classique (par e-mail ou par téléphone). Alice ne peut pas copier l'état quantique (en raison du théorème de non-clonage). Si elle répétait le même processus de préparation de nombreuses fois, elle pourrait accumuler des statistiques comme nous venons de le faire. Mais que se passe-t-il s'il n'y a qu'un seul état inconnu ? Cet état a peut-être émergé d'un processus physique que tu veux étudier. Ou il pourrait faire partie d'un calcul quantique plus grand. Dans ce cas, comment Alice pourrait-elle envoyer l'état à Bob ? Elle le peut, si elle et Bob partagent une précieuse ressource quantique : un état intriqué partagé, comme l'état de Bell introduit dans la leçon précédente : 00+112.\frac {|00\rangle + |11\rangle}{\sqrt 2}. Tu verras parfois aussi cela appelé « paire EPR » ou « e-bit » (unité fondamentale d'intrication). Si Alice partage un tel état intriqué avec Bob, elle peut téléporter l'état quantique inconnu à Bob en effectuant une série d'opérations quantiques et en lui envoyant deux bits d'information classique.

4.1 Le protocole de téléportation quantique

Hypothèse : Alice possède un état quantique inconnu ψ|\psi \rangle à envoyer à Bob. Alice et Bob partagent un état intriqué à 2 qubits, ou e-bit, chacun ayant physiquement l'un des qubits à son emplacement.

Voici un aperçu de la procédure sans explication. Les détails seront implémentés ci-dessous.

  1. Alice intrique ψ|\psi \rangle avec sa partie de l'e-bit en utilisant la porte CNOT.
  2. Alice applique une porte Hadamard à ψ|\psi \rangle et mesure ses deux qubits dans la base computationnelle.
  3. Alice envoie à Bob ses résultats de mesure (soit « 00 », « 01 », « 10 » ou « 11 »)
  4. Bob effectue un opérateur de correction basé sur les deux bits d'information d'Alice sur sa partie de la paire e-bit.
    • Si « 00 », Bob ne fait rien
    • Si « 01 », Bob applique la porte X
    • Si « 10 », Bob applique la porte Z
    • Si « 11 », Bob applique iY = ZX
  5. La partie de l'e-bit de Bob devient ψ|\psi \rangle.

Ceci est également développé plus en détail dans Bases de l'information quantique. Mais la situation deviendra plus claire au fur et à mesure que nous l'instancierons dans Qiskit.

4.2 Circuit quantique simulant la téléportation quantique

Comme toujours, nous appliquerons le cadre des Qiskit patterns. Cette sous-section se concentrera uniquement sur la cartographie.

Étape 1 : Mapper le problème sur des circuits et des opérateurs quantiques

Pour décrire le scénario ci-dessus, nous avons besoin d'un circuit à trois qubits : deux pour la paire intriquée partagée par Alice et Bob, et un pour l'état quantique inconnu ψ|\psi\rangle.

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

qc.draw(output="mpl")

Sortie de la cellule de code précédente

Au départ, Alice possède un état quantique inconnu ψ.|\psi \rangle. Nous allons le créer en utilisant la porte 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")

Sortie de la cellule de code précédente

Nous pouvons visualiser l'état que nous avons créé, mais uniquement parce que nous connaissons les paramètres utilisés dans la porte UU. Si cet état avait émergé d'un processus quantique complexe, l'état ne serait pas connaissable sans exécuter le processus pour créer l'état de nombreuses fois et collecter des statistiques comme dans la tomographie.

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

Sortie de la cellule de code préc�édente

Avant même que ce protocole commence, nous supposons qu'Alice et Bob ont une paire intriquée partagée. Si Alice et Bob se trouvent vraiment à des emplacements différents, ils pourraient avoir établi l'état partagé avant que l'état inconnu ψ|\psi\rangle ait jamais été créé. Étant donné que ces opérations se déroulent sur des qubits différents, leur ordre n'a pas d'importance ici, et cet ordre est pratique pour la visualisation.

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

Sortie de la cellule de code précédente

Ensuite, Alice intrique ψ|\psi \rangle avec sa partie de l'e-bit partagé, en utilisant la porte CXCX et la porte HH, et les mesure dans la base computationnelle.

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

Sortie de la cellule de code précédente

Alice envoie à Bob ses résultats de mesure (soit « 00 », « 01 », « 10 » ou « 11 »), et Bob effectue un opérateur de correction basé sur les deux bits d'information d'Alice sur sa partie de l'e-bit partagé. Ensuite, la partie de Bob devient ψ|\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")

Sortie de la cellule de code précédente

Tu as complété un circuit de téléportation quantique ! Voyons l'état de sortie de ce circuit en utilisant le simulateur de vecteur d'état.

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)

Sortie de la cellule de code précédente

Tu peux constater que l'état quantique créé par la porte UU du qubit 0 (le qubit contenant initialement l'état secret) a été transféré vers le qubit 2 (le qubit de Bob).

Tu peux exécuter la cellule ci-dessus plusieurs fois pour t'en assurer. Tu remarqueras peut-être que les qubits 0 et 1 changent d'état, mais le qubit 2 est toujours dans l'état ψ|\psi\rangle.

4.3 Exécuter et confirmer le résultat en appliquant l'inverse de U

Ci-dessus, nous avons vérifié visuellement que l'état téléporté semblait correct. Une autre façon de vérifier si l'état quantique a été téléporté correctement est d'appliquer l'inverse de la porte UU sur le qubit de Bob afin que nous puissions mesurer « 0 ». Autrement dit, puisque U1UU^{-1}U est l'identité, si le qubit de Bob est dans l'état créé à partir de U0U|0\rangle, alors l'application de l'inverse devrait donner 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")

Sortie de la cellule de code précédente

Nous allons d'abord exécuter le circuit avec l'AerSimulator avant de passer à un vrai ordinateur quantique.

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}

Sortie de la cellule de code précédente

Rappelle-toi qu'en notation little endian, le qubit 2 est le qubit le plus à gauche (ou le plus en bas, dans les étiquettes de colonnes). Note que le qubit le plus à gauche et le plus en bas dans les étiquettes de colonnes est un 0 pour tous les résultats possibles. Cela montre que nous avons 100 % de chance de mesurer q2q_2 dans l'état 0|0\rangle. C'est le résultat attendu et indique que le protocole de téléportation a fonctionné correctement.

4.4 Téléportation sur un vrai ordinateur quantique

Ensuite, nous allons effectuer la téléportation sur un vrai ordinateur quantique. En utilisant la fonction de circuit dynamique, nous pouvons opérer au milieu du circuit en utilisant les résultats de mesure, implémentant en temps réel les opérations conditionnelles dans le circuit de téléportation. Pour résoudre des problèmes avec de vrais ordinateurs quantiques, nous suivrons les quatre étapes des Qiskit patterns.

  1. Mapper le problème sur des circuits et des opérateurs quantiques
  2. Optimiser pour le matériel cible
  3. Exécuter sur le matériel cible
  4. Post-traiter les résultats

Exercice 3 : Construire le circuit de téléportation

Essaie de construire l'intégralité du circuit de téléportation de zéro pour tester ta compréhension. Remonte si tu as besoin d'un rappel.

Solution :

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

Sortie de la cellule de code précédente

Pour rappel, l'application de l'inverse de la porte UU sert uniquement à vérifier le comportement attendu. Cela ne fait pas partie de l'envoi de l'état à Bob, et nous n'utiliserions pas cette porte UU inverse si le seul objectif était de transférer de l'information quantique.

Étape 2 : Optimiser pour le matériel cible

Pour s'exécuter sur du matériel, importe QiskitRuntimeService et charge tes identifiants sauvegardés. Sélectionne le backend avec le moins de tâches dans la file d'attente.

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

Voyons la carte de couplage du dispositif que tu as sélectionné.

from qiskit.visualization import plot_gate_map

plot_gate_map(backend)

Sortie de la cellule de code précédente

Différents dispositifs peuvent avoir des cartes de couplage différentes, et chaque dispositif possède certains qubits et coupleurs plus performants que d'autres. Enfin, différents ordinateurs quantiques peuvent avoir des portes natives différentes (des portes que le matériel peut exécuter). La transpilation du circuit réécrit le circuit quantique abstrait en utilisant des portes que l'ordinateur quantique cible peut exécuter et sélectionne la correspondance optimale avec les qubits physiques (entre autres). La transpilation est un sujet riche et complexe. Pour en savoir plus sur la transpilation, consulte la référence 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)

Sortie de la cellule de code précédente

Étape 3 : Exécuter le circuit.

En utilisant la primitive Runtime Sampler, nous allons exécuter le circuit cible.

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

Tu peux aussi vérifier le statut de la tâche depuis ton tableau de bord 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'

Si tu vois 'DONE' s'afficher, tu peux obtenir le résultat en exécutant la cellule ci-dessous.

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

Étape 4 : Post-traiter les résultats

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

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

Sortie de la cellule de code précédente

Tu peux interpréter les résultats ci-dessus directement. Ou, en utilisant marginal_count, tu peux tracer les résultats de Bob sur le 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)

Sortie de la cellule de code précédente

Comme on le voit ici, il y a quelques résultats dans lesquels nous avons mesuré 1|1 \rangle. Ceux-ci sont dus au bruit et aux erreurs. En particulier, les circuits dynamiques ont tendance à avoir un taux d'erreur plus élevé en raison de la mesure chronophage au milieu du circuit.

4.5 Points clés sur la téléportation quantique

Nous pouvons transporter un état quantique vers un ami distant en partageant une paire de qubits intriqués (un e-bit).

  1. La téléportation quantique peut-elle envoyer l'état quantique plus vite que la lumière ? Non, parce qu'Alice doit communiquer à Bob les résultats de mesure de manière classique.

  2. La téléportation quantique contournerait-elle le « théorème de non-clonage », qui interdit la copie d'un état quantique ? Non, parce que l'état quantique original donné à Alice sur l'un de ses qubits a été perdu lors de la mesure. Il s'est effondré en 0|0\rangle ou 1|1\rangle.

5. Codage superdense

Pratiquement le même dispositif peut être utilisé à une fin différente. Supposons qu'Alice veuille envoyer à Bob deux bits d'information classique, mais qu'elle n'ait aucun moyen de communication classique avec Bob. Elle partage cependant une paire intriquée avec Bob et est autorisée à envoyer son qubit à l'emplacement de Bob. Remarque le contraste avec le protocole de téléportation quantique. Dans la téléportation, la communication classique était disponible pour les amis, et l'objectif était d'envoyer un état quantique. Ici, la communication classique n'est pas accessible et ils utilisent le transfert d'un qubit pour partager deux bits d'information classique.

5.1 Le protocole du codage superdense

Hypothèse : Alice dispose de deux bits d'information, disons a1a2{00,01,10,11}a_1a_2 \in \{00, 01, 10, 11\}. Alice et Bob partagent une paire intriquée (e-bit), mais ils ne peuvent pas communiquer classiquement.

  1. Alice effectue l'une des opérations suivantes sur sa partie de l'e-bit.
    • Si a1a2=00a_1a_2 = 00, elle ne fait rien
    • Si a1a2=01a_1a_2 = 01, elle applique la porte Z
    • Si a1a2=10a_1a_2 = 10, elle applique la porte X
    • Si a1a2=11a_1a_2 = 11, elle applique la porte Z puis la porte X.
  2. Alice envoie sa partie de l'e-bit à l'emplacement de Bob.
  3. Bob applique une porte CNOT avec le qubit d'Alice comme contrôle et son qubit comme cible, puis applique la porte H au qubit d'Alice, et mesure les deux qubits. Les états de départ possibles et les résultats des opérations de Bob sont :
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

Note que le signe négatif de 11-|11\rangle est une phase globale, donc elle n'est pas mesurable.

5.2 Circuit quantique simulant le codage superdense

Sur la base du protocole du codage superdense, tu peux construire le circuit de codage superdense comme ci-dessous. Essaie de changer le message, msg, qu'Alice veut transmettre à Bob.

from qiskit import QuantumCircuit

Les étapes des Qiskit patterns sont identifiées dans les commentaires du code.

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

Sortie de la cellule de code précédente

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

Sortie de la cellule de code précédente

Tu peux constater que Bob a bien reçu le message qu'Alice voulait lui envoyer.

Ensuite, essayons avec un vrai ordinateur quantique.

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)

Sortie de la cellule de code précédente

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

Sortie de la cellule de code précédente

Le résultat est celui que nous attendions. Note que le codage superdense sur un vrai ordinateur quantique a montré moins d'erreurs que dans le cas de la téléportation quantique sur un vrai ordinateur quantique. L'une des raisons pourrait être que la téléportation quantique utilise des circuits dynamiques, et pas le codage superdense. Nous en apprendrons davantage sur les erreurs dans les circuits quantiques dans les leçons suivantes.

6. Résumé

Dans cette session, nous avons implémenté deux protocoles quantiques. Bien que les scénarios impliquant des amis distants pour les deux soient quelque peu éloignés de l'informatique quantique sur un seul QPU, ils ont des applications en informatique quantique et nous aident à mieux comprendre le transfert d'information quantique.

  • Téléportation quantique : bien que nous ne puissions pas copier des états quantiques, nous pouvons téléporter des états quantiques inconnus en ayant une intrication partagée.
  • Codage superdense quantique : une paire intriquée partagée, et le transfert d'un qubit, permettent la communication de deux bits d'information classique.
# See the version of Qiskit
import qiskit

qiskit.__version__
'2.0.2'