Implémentation Qiskit
Dans cette section, nous allons examiner quelques implémentations Qiskit des concepts introduits dans cette leçon. Si tu souhaites exécuter ces implémentations toi-même — ce qui est fortement encouragé —, consulte la page Installer Qiskit dans la documentation IBM Quantum pour savoir comment configurer Qiskit.
Il faut savoir que Qiskit est en développement continu et se concentre principalement sur l'optimisation des performances des ordinateurs quantiques qu'il sert à piloter, lesquels continuent eux-mêmes d'évoluer. En conséquence, Qiskit est sujet à des changements qui peuvent occasionnellement entraîner la dépréciation de certains codes. Dans cet esprit, nous exécuterons toujours les commandes suivantes avant de présenter des exemples de code Qiskit dans ce cours, afin de préciser clairement quelle version de Qiskit a été utilisée. À partir de Qiskit v1.0, c'est une façon simple de voir quelle version de Qiskit est actuellement installée.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit
from qiskit import __version__
print(__version__)
2.1.1
Si tu exécutes ce code dans un environnement Python hébergé dans le cloud, tu devras peut-être installer certains des packages suivants :
#!pip install qiskit
#!pip install jupyter
#!pip install sympy
#!pip install matplotlib
#!pip install pylatexenc
Vecteurs et matrices en Python
Qiskit utilise le langage de programmation Python, donc avant d'aborder Qiskit spécifiquement, il peut être utile d'évoquer très brièvement les calculs matriciels et vectoriels en Python.
En Python, les calculs matriciels et vectoriels peuvent être effectués à l'aide de la classe array de la bibliothèque NumPy, qui fournit des fonctionnalités pour de nombreux calculs numériques et scientifiques.
Le code suivant charge cette bibliothèque, définit deux vecteurs colonnes, ket0 et ket1, correspondant aux vecteurs d'état qubit et puis affiche leur moyenne.
import numpy as np
ket0 = np.array([[1], [0]])
ket1 = np.array([[0], [1]])
print(ket0 / 2 + ket1 / 2)
[[0.5]
[0.5]]
On peut aussi utiliser array pour créer des matrices représentant des opérations.
M1 = np.array([[1, 1], [0, 0]])
M2 = np.array([[1, 0], [0, 1]])
M = M1 / 2 + M2 / 2
print(M)
[[1. 0.5]
[0. 0.5]]
Note que tout le code d'une même leçon de ce cours est censé être exécuté séquentiellement.
Il n'est donc pas nécessaire d'importer NumPy de nouveau ici, car il a déjà été importé.
La multiplication matricielle, y compris le produit matrice-vecteur comme cas particulier, peut être effectuée à l'aide de la fonction matmul de NumPy.
print(np.matmul(M1, ket1))
print(np.matmul(M1, M2))
print(np.matmul(M, M))
[[1]
[0]]
[[1 1]
[0 0]]
[[1. 0.75]
[0. 0.25]]
Ce formatage de sortie laisse à désirer visuellement.
Pour les situations où l'on veut quelque chose de plus élégant, une solution consiste à utiliser la fonction array_to_latex de Qiskit, disponible dans le module qiskit.visualization.
Remarque que, dans le code qui suit, on utilise la fonction générique display de Python.
En revanche, le comportement spécifique de print peut varier selon ce qui est affiché, comme c'est le cas pour les tableaux définis par NumPy.
from qiskit.visualization import array_to_latex
display(array_to_latex(np.matmul(M1, ket1)))
display(array_to_latex(np.matmul(M1, M2)))
display(array_to_latex(np.matmul(M, M)))
États, mesures et opérations
Qiskit comprend plusieurs classes permettant de créer et de manipuler des états, des mesures et des opérations — il n'est donc pas nécessaire de tout programmer soi-même pour simuler des états quantiques, des mesures et des opérations en Python. Quelques exemples pour te permettre de démarrer sont inclus ci-dessous.
Définir et afficher des vecteurs d'état
La classe Statevector de Qiskit fournit des fonctionnalités pour définir et manipuler des vecteurs d'état quantiques.
Dans le code qui suit, la classe Statevector est importée et quelques vecteurs sont définis.
(On importe aussi la fonction sqrt de la bibliothèque NumPy pour calculer une racine carrée.
Cette fonction pourrait alternativement être appelée np.sqrt à condition que NumPy ait déjà été importé, comme c'est le cas ci-dessus ; c'est simplement une autre façon d'importer et d'utiliser cette fonction spécifique seule.)
from qiskit.quantum_info import Statevector
from numpy import sqrt
u = Statevector([1 / sqrt(2), 1 / sqrt(2)])
v = Statevector([(1 + 2.0j) / 3, -2 / 3])
w = Statevector([1 / 3, 2 / 3])
La classe Statevector inclut une méthode draw pour afficher les vecteurs d'état de différentes manières, notamment
text pour le texte brut, latex pour du LaTeX rendu, et latex_source pour le code LaTeX brut, ce qui peut être pratique pour copier-coller dans des documents.
(Utilise print plutôt que display pour afficher le code LaTeX avec les meilleurs résultats.)
display(u.draw("text"))
display(u.draw("latex"))
print(u.draw("latex_source"))
[0.70710678+0.j,0.70710678+0.j]
\frac{\sqrt{2}}{2} |0\rangle+\frac{\sqrt{2}}{2} |1\rangle
La classe Statevector inclut aussi la méthode is_valid, qui vérifie si un vecteur donné est un vecteur d'état quantique valide (autrement dit, s'il a une norme euclidienne égale à 1) :
display(u.is_valid())
display(w.is_valid())
True
False
Simuler des mesures avec Statevector
Nous allons maintenant voir une façon de simuler des mesures d'états quantiques dans Qiskit, en utilisant la méthode measure de la classe Statevector.
Utilisons le même vecteur d'état qubit v défini précédemment.
display(v.draw("latex"))
L'exécution de la méthode measure simule une mesure dans la base standard.
Elle retourne le résultat de cette mesure, ainsi que le nouveau vecteur d'état quantique du système après la mesure.
(Ici on utilise la fonction print de Python avec le préfixe f pour un affichage formaté avec des expressions embarquées.)
outcome, state = v.measure()
print(f"Measured: {outcome}\nPost-measurement state:")
display(state.draw("latex"))
Measured: 1
Post-measurement state:
Les résultats de mesure sont probabilistes, donc cette méthode peut retourner des résultats différents lorsqu'elle est exécutée plusieurs fois.
Pour l'exemple particulier du vecteur v défini ci-dessus, la méthode measure définit le vecteur d'état quantique après la mesure comme étant
(plutôt que ) ou
(plutôt que ), selon le résultat de la mesure. Dans les deux cas, les alternatives à et sont en fait équivalentes à ces vecteurs d'état ; on dit qu'elles sont équivalentes à une phase globale près, car l'une est égale à l'autre multipliée par un nombre complexe de module 1. Cette question est traitée plus en détail dans la leçon Circuits quantiques et peut être ignorée pour l'instant.
Statevector lèvera une erreur si la méthode measure est appliquée à un vecteur d'état quantique invalide.
Statevector est également doté d'une méthode sample_counts qui permet de simuler un nombre quelconque de mesures sur le système, en repartant à chaque fois d'une copie fraîche de l'état. Par exemple, le code suivant montre le résultat de la mesure du vecteur v fois, ce qui (avec une forte probabilité) donne le résultat environ fois sur (soit environ des essais) et le résultat environ fois sur (soit environ des essais).
Le code qui suit illustre également la fonction plot_histogram du module qiskit.visualization pour visualiser les résultats.
from qiskit.visualization import plot_histogram
statistics = v.sample_counts(1000)
plot_histogram(statistics)
Exécuter ce code plusieurs fois toi-même, avec différents nombres d'échantillons à la place de peut aider à développer une certaine intuition sur la façon dont le nombre d'essais influence le nombre de fois où chaque résultat apparaît. Avec de plus en plus d'échantillons, la fraction d'échantillons pour chaque possibilité a tendance à se rapprocher de plus en plus de la probabilité correspondante. Ce phénomène, de façon plus générale, est connu sous le nom de loi des grands nombres en théorie des probabilités.
Effectuer des opérations avec Operator et Statevector
Les opérations unitaires peuvent être définies dans Qiskit à l'aide de la classe Operator, comme dans l'exemple qui suit.
Cette classe inclut une méthode draw avec des arguments similaires à ceux de Statevector.
Remarque que l'option latex produit des résultats équivalents à array_from_latex.
from qiskit.quantum_info import Operator
Y = Operator([[0, -1.0j], [1.0j, 0]])
H = Operator([[1 / sqrt(2), 1 / sqrt(2)], [1 / sqrt(2), -1 / sqrt(2)]])
S = Operator([[1, 0], [0, 1.0j]])
T = Operator([[1, 0], [0, (1 + 1.0j) / sqrt(2)]])
display(T.draw("latex"))
On peut appliquer une opération unitaire à un vecteur d'état en utilisant la méthode evolve.
v = Statevector([1, 0])
v = v.evolve(H)
v = v.evolve(T)
v = v.evolve(H)
v = v.evolve(S)
v = v.evolve(Y)
display(v.draw("latex"))
Un aperçu des circuits quantiques
Les circuits quantiques ne seront formellement introduits que dans la leçon Circuits quantiques, qui est la troisième leçon de ce cours, mais on peut néanmoins expérimenter la composition d'opérations unitaires sur un qubit à l'aide de la classe QuantumCircuit de Qiskit.
En particulier, on peut définir un circuit quantique (qui, dans ce cas, sera simplement une séquence d'opérations unitaires effectuées sur un seul qubit) comme suit.
from qiskit import QuantumCircuit
circuit = QuantumCircuit(1)
circuit.h(0)
circuit.t(0)
circuit.h(0)
circuit.s(0)
circuit.y(0)
display(circuit.draw(output="mpl"))
Ici on utilise la méthode draw de la classe QuantumCircuit avec le moteur de rendu mpl (abréviation de Matplotlib, une bibliothèque de visualisation Python).
C'est le seul moteur de rendu que nous utiliserons pour les circuits quantiques dans ce cours, mais il en existe d'autres, notamment un moteur textuel et un moteur basé sur LaTeX.
Les opérations sont appliquées séquentiellement, de gauche à droite dans le diagramme.
Une façon pratique d'obtenir la matrice unitaire correspondant à ce circuit est d'utiliser la méthode from_circuit de la classe Operator.
display(Operator.from_circuit(circuit).draw("latex"))
On peut aussi initialiser un vecteur d'état quantique de départ, puis faire évoluer cet état selon la séquence d'opérations décrite par le circuit.
ket0 = Statevector([1, 0])
v = ket0.evolve(circuit)
display(v.draw("latex"))
Le code suivant simule une expérience où l'état obtenu à partir du circuit ci-dessus est mesuré dans la base standard 4000 fois (en repartant à chaque fois d'une copie fraîche de l'état).
statistics = v.sample_counts(4000)
display(plot_histogram(statistics))