Transformée de Fourier quantique
Pour ce module Qiskit en classe, les étudiants doivent disposer d'un environnement Python fonctionnel avec les packages suivants installés :
qiskitv2.1.0 ou plus récentqiskit-ibm-runtimev0.40.1 ou plus récentqiskit-aerv0.17.0 ou plus récentqiskit.visualizationnumpypylatexenc
Pour configurer et installer les packages ci-dessus, consulte le guide Installer Qiskit. Pour exécuter des jobs sur de vrais ordinateurs quantiques, les étudiants devront créer un compte IBM Quantum® en suivant les étapes du guide Configurer ton compte IBM Cloud.
Ce module a été testé et a utilisé 13 secondes de temps QPU. Il s'agit d'une estimation de bonne foi ; ton utilisation réelle peut varier.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer qiskit-ibm-runtime
# Uncomment and modify this line as needed to install dependencies
#!pip install 'qiskit>=2.1.0' 'qiskit-ibm-runtime>=0.40.1' 'qiskit-aer>=0.17.0' 'numpy' 'pylatexenc'
Introduction
Une transformée de Fourier est un outil omniprésent avec des applications en mathématiques, physique, traitement du signal, compression de données et d'innombrables autres domaines. Une version quantique de la transformée de Fourier, appelée à juste titre la transformée de Fourier quantique, constitue la base de certains des algorithmes quantiques les plus importants.
Aujourd'hui, après un rappel de la transformée de Fourier classique, on va parler de la façon dont on implémente la transformée de Fourier quantique sur un ordinateur quantique. Ensuite, on va aborder l'une des applications de la transformée de Fourier quantique à un algorithme appelé l'algorithme d'estimation de phase. L'estimation de phase quantique est une sous-routine dans le célèbre algorithme de factorisation de Shor, parfois désigné comme le « joyau de la couronne » de l'informatique quantique. Ce module prépare le terrain pour un autre module entièrement consacré à l'algorithme de Shor, mais il est aussi conçu pour être autonome. La transformée de Fourier quantique est un algorithme fascinant et utile en soi !
La transformée de Fourier classique
Avant de plonger dans la transformée de Fourier quantique, rappelons-nous d'abord la version classique. La transformée de Fourier est une méthode de passage d'une « base » à une autre. On peut penser à deux bases comme deux perspectives différentes sur un même problème — toutes deux sont des façons valides d'exprimer une fonction, mais l'une ou l'autre peut être plus éclairante selon le problème à résoudre. Quelques exemples de paires de bases reliées par la transformée de Fourier : position et impulsion, temps et fréquence.
Voyons un exemple de la façon dont la transformée de Fourier peut nous aider à déterminer quelle note joue un instrument à partir de sa forme d'onde audio. Généralement, on voit les formes d'onde représentées dans la base temporelle — c'est-à-dire que l'amplitude de l'onde est exprimée en fonction du temps.

On peut appliquer la transformée de Fourier à cette forme d'onde pour passer de la base temporelle à la base fréquentielle :

Dans la base fréquentielle, on voit clairement un pic à environ 260 Hz. C'est un do central !
Tu aurais peut-être pu déterminer qu'un do central était joué sans utiliser de transformée de Fourier, mais que se passe-t-il si plusieurs notes sont jouées en même temps ? La forme d'onde devient alors plus complexe lorsqu'on la trace dans la base temporelle :

Mais le spectre fréquentiel identifie clairement trois pics :

C'était un accord de do majeur, jouant les notes do, mi et sol.
Ce type d'analyse de Fourier peut nous aider à extraire les composantes fréquentielles de tout signal complexe.
Transformée de Fourier discrète
La transformée de Fourier est utile pour de nombreuses applications de traitement du signal. Mais dans la plupart de ces applications réelles (y compris l'exemple musical que l'on vient d'utiliser), on veut transformer un ensemble discret de points de données — pas une fonction continue. Dans ce cas, on utilise la transformée de Fourier discrète. La transformée de Fourier discrète (DFT) agit sur un vecteur et le fait correspondre au vecteur selon la formule :
où l'on prend . (Note qu'il existe d'autres conventions avec un signe moins dans l'exponentielle, fais attention quand tu rencontres la DFT.) Rappelle-toi que est une fonction périodique, de période . Ainsi, en multipliant par cette fonction, la transformée de Fourier est essentiellement une façon de décomposer la fonction (discrète) en une combinaison linéaire de ses fonctions périodiques constitutives, chacune de période .
La transformée de Fourier quantique
Maintenant qu'on a vu comment la transformée de Fourier permet de représenter une fonction comme une combinaison linéaire d'un nouvel ensemble de « fonctions de base », on peut aborder les transformations de base sur les états de qubits. Par exemple, l'état d'un seul qubit peut être exprimé dans la base computationnelle , avec les états de base et , ou dans la base : avec les états de base et . Les deux sont également valides, mais l'une peut être plus naturelle que l'autre selon le type de problème à résoudre.
Les états de qubits peuvent aussi être exprimés dans la base de Fourier, où un état est exprimé en termes de combinaison linéaire des états de base de Fourier , plutôt que des états de base computationnels habituels . Pour ce faire, il faut appliquer une transformée de Fourier quantique (QFT) :
avec comme précédemment, et est le nombre d'états de base dans ton système quantique. Comme on travaille maintenant avec des qubits, qubits donnent états de base, donc . Ici, les états de base sont écrits comme un seul nombre où va de à , mais tu verras plus souvent les états de base exprimés comme , , , ..., , où chaque chiffre binaire représente l'état du qubit 0 au qubit , de droite à gauche. Il y a une façon simple de convertir ces états binaires en un seul nombre : traite-les simplement comme des nombres binaires ! Ainsi, , , , , et ainsi de suite, jusqu'à .
Développe ton intuition pour les états de base de Fourier
On vient de passer en revue ce que sont les états de base computationnels et comment ils sont ordonnés : ce sont les états où chaque qubit est soit en soit en , ordonnés de l'état où tous les qubits sont à , , à l'état où ils sont tous à , .
Mais comment comprendre les états de base de Fourier ? Tous les états de base de Fourier sont des superpositions égales de tous les états de base computationnels, mais chaque état diffère des autres par la périodicité de la phase de ses composantes. Pour comprendre cela de manière concrète, examinons les quatre états de base de Fourier d'un système à deux qubits. L'état de Fourier le plus bas est celui dont la phase ne varie pas du tout :
On peut visualiser cet état en traçant l'amplitude complexe de chacun des termes. La ligne rouge guide l'œil pour montrer comment la phase de cette amplitude s'enroule dans le plan complexe en fonction de l'état de base computationnel. Pour , la phase reste constante :

L'état de base de Fourier suivant est celui dont les phases des composantes s'enroulent de à exactement une fois :
Et on peut voir cet enroulement dans le graphique de l'amplitude complexe en fonction de l'état de base computationnel :

Ainsi, chaque état a une phase supérieure de radians à l'état précédent lorsqu'ils sont ordonnés de la façon habituelle, car dans cet exemple on a quatre états de base (). L'état de base suivant s'enroule de 0 à deux fois :

Enfin, la composante de Fourier la plus élevée est celle dont la phase varie le plus rapidement. Pour notre exemple avec deux qubits, c'est celle dont les phases s'enroulent de 0 à trois fois :

En général, pour un état à qubits, il y aura états de base de Fourier, dont la fréquence de variation de phase va de constante pour à rapidement variable pour , complétant tours autour de sur la superposition d'états. Donc, quand on applique une QFT à un état quantique, on fait essentiellement la même analyse de base qu'on a faite pour la forme d'onde musicale dans l'introduction. On détermine les composantes fréquentielles de Fourier qui contribuent à créer l'état quantique d'intérêt.
Essaie quelques exemples de QFT
Continuons à développer notre intuition pour la transformée de Fourier quantique en préparant un état dans la base computationnelle, puis en observant ce qui se passe lorsqu'on applique la QFT. Pour l'instant, on va traiter la QFT comme une boîte noire qu'on applique avec le QFTGate de la bibliothèque de circuits Qiskit. Plus tard, on regardera sous le capot pour voir comment elle est implémentée.
On commence par charger les packages nécessaires et sélectionner un dispositif pour exécuter notre Circuit :
import numpy as np
from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram
from qiskit.circuit.library import QFTGate
# Load the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService
# Load the Runtime primitive and session
from qiskit_ibm_runtime import SamplerV2 as Sampler
service = QiskitRuntimeService()
# Use the least busy backend
# backend = service.least_busy(operational=True, simulator=False, min_num_qubits = 127)
backend = service.backend("ibm_pinguino2")
print(backend.name)
ibm_pinguino2
Si tu n'as pas de temps disponible sur ton compte ou si tu veux utiliser un simulateur pour une raison quelconque, tu peux exécuter la cellule ci-dessous pour configurer un simulateur qui imitera le dispositif quantique qu'on a sélectionné ci-dessus :
# Load the backend sampler
from qiskit.primitives import BackendSamplerV2
# Load the Aer simulator and generate a noise model based on the currently-selected backend.
from qiskit_aer import AerSimulator
from qiskit_aer.noise import NoiseModel
noise_model = NoiseModel.from_backend(backend)
# Define a simulator using Aer, and use it in Sampler.
backend_sim = AerSimulator(noise_model=noise_model)
sampler_sim = BackendSamplerV2(backend=backend_sim)
# Alternatively, load a fake backend with generic properties and define a simulator.
from qiskit.providers.fake_provider import GenericBackendV2
backend_gen = GenericBackendV2(num_qubits=18)
sampler_gen = BackendSamplerV2(backend=backend_gen)
Un seul état de base computationnel
D'abord, essayons de transformer un seul état de base computationnel. On commence par créer un état computationnel aléatoire :
# Step 1: Map
qubits = 4
N = 2**qubits
qc = QuantumCircuit(qubits)
# flip state of random qubits to put in a random single computational basis state
for i in range(1, qubits):
if np.random.randint(0, 2):
qc.x(i)
# make a copy of the above circuit. (to be used when we apply the QFT in next part)
qc_qft = qc.copy()
qc.measure_all()
qc.draw("mpl")
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
# Step 3: Run the job on a real quantum computer OR try fake backend
sampler = Sampler(mode=backend)
pubs = [qc_isa]
# Run the job on real quantum device
job = sampler.run(pubs, shots=1000)
res = job.result()
counts = res[0].data.meas.get_counts()
# OR Run the job on the Aer simulator with noise model from real backend
# job = sampler_sim.run([qc_isa])
# res = job.result()
# counts = res[0].data.meas.get_counts()
# Step 4: Post-Process
plot_histogram(counts)
Maintenant, appliquons la transformée de Fourier à cet état avec QFTGate :
# Step 1: Map
qc_qft.compose(QFTGate(qubits), inplace=True)
qc_qft.measure_all()
qc_qft.draw("mpl")
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc_qft)
# Step 3: Run the job on a real quantum computer - try fake backend
sampler = Sampler(mode=backend)
pubs = [qc_isa]
# Run the job on real quantum device
job = sampler.run(pubs, shots=1000)
res = job.result()
counts = res[0].data.meas.get_counts()
# OR Run the job on the Aer simulator with noise model from real backend
# job = sampler_sim.run([qc_isa])
# res = job.result()
# counts = res[0].data.meas.get_counts()
# Step 4: Post-Process
plot_histogram(counts)
Comme tu peux le voir, on mesure les populations de chaque état comme étant plus ou moins égales, à quelques bruits expérimentaux et statistiques près. Donc, si on applique la QFT à un seul état de base computationnel, le résultat est une superposition égale de tous les états. Si tu es familier avec les transformées de Fourier, cela ne te surprend probablement pas. Un principe de base qui peut nous aider à construire une connexion intuitive entre une fonction et sa transformée de Fourier est que la largeur d'une fonction est inversement proportionnelle à la largeur de sa transformée de Fourier. Donc, quelque chose de très localisé dans le temps, par exemple une très courte impulsion, nécessitera une large gamme de fréquences pour générer cette impulsion. Ce signal sera très étendu dans l'espace de Fourier.
Ce fait est en réalité lié à l'incertitude quantique ! Le principe d'incertitude de Heisenberg est généralement énoncé comme . Donc si l'incertitude sur () est petite, l'incertitude sur la quantité de mouvement () doit être grande, et vice versa. Il s'avère que passer de la base de position à la base d'impulsion s'accomplit via une transformée de Fourier.
Note : Garde à l'esprit qu'on mesure les populations dans chacun des états de base, donc on perd des informations sur les phases relatives entre les différentes parties de la superposition. Ainsi, bien que la QFT de n'importe quel état de base computationnel unique donne la même répartition égale en population sur tous les états de base, les phases ne seront pas nécessairement les mêmes.
Deux états de base computationnels
Voyons maintenant ce qui se passe quand on prépare une superposition d'états de base computationnels. À ton avis, à quoi ressemblera la transformée de Fourier dans ce cas ?
Choisissons la superposition :
# Step 1: Map
qubits = 4
N = 2**qubits
qc = QuantumCircuit(qubits)
# To make this state, we just need to apply a Hadamard to the last qubit
qc.h(qubits - 1)
qc_qft = qc.copy()
qc.measure_all()
qc.draw("mpl")
# First, let's go through steps 2-4 for the first circuit, qc
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
# Step 3: Run the job on a real quantum computer - try fake backend
sampler = Sampler(mode=backend)
pubs = [qc_isa]
# Run the job on real quantum device
job = sampler.run(pubs, shots=1000)
res = job.result()
counts = res[0].data.meas.get_counts()
# OR run the job on the Aer simulator with noise model from real backend
# job = sampler_sim.run([qc_isa])
# res = job.result()
# counts = res[0].data.meas.get_counts()
# Step 4: Post-process
plot_histogram(counts)
Maintenant, appliquons la transformée de Fourier à cet état avec QFTGate :
# Step 1: Map
qc_qft.compose(QFTGate(qubits), inplace=True)
qc_qft.measure_all()
qc_qft.draw("mpl")
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc_qft)
# Step 3: Run the job on a real quantum computer OR try fake backend
sampler = Sampler(mode=backend)
pubs = [qc_isa]
# Run the job on real quantum device
job = sampler.run(pubs, shots=1000)
res = job.result()
counts = res[0].data.meas.get_counts()
# OR run the job on the Aer simulator with noise model from real backend
# job = sampler_sim.run([qc_isa])
# res = job.result()
# counts = res[0].data.meas.get_counts()
# Step 4: Post-process
plot_histogram(counts)
Ce résultat pourrait être un peu surprenant. On dirait que la QFT de l'état est une superposition de tous les états de base pairs. Mais si on repense à notre visualisation de chaque état de base , et à la façon dont la phase de chaque composante s'enroule fois autour de , la raison pour laquelle on obtient ce résultat devrait devenir claire.
Vérifie ta compréhension
Lis la ou les questions ci-dessous, réfléchis à ta réponse, puis clique sur le triangle pour révéler la solution.
En utilisant l'indice ci-dessus, explique pourquoi le résultat qu'on a obtenu pour la QFT de est attendu.
Réponse :
L'état original a une phase relative de 0 (ou un multiple entier de ) entre les deux parties de la superposition. On sait donc que cet état a des composantes de Fourier dont les phases s'accordent de cette façon : celles qui ont un déphasage nul entre le terme |0000> et le terme |1000>. Chaque état de base de Fourier est composé de termes dont la phase s'accumule à un taux de , ce qui signifie que, ordonnés de la façon habituelle, chaque terme de la superposition a une phase de supérieure au terme précédent. Donc, au point médian , on veut que la phase soit un multiple entier de . Cela se produit quand est pair.
Quelle superposition d'états computationnels correspondrait à une QFT avec des pics sur chaque nombre binaire impair ?
Réponse :
Si tu appliquais la QFT à l'état , tu verrais des pics sur chaque état numéroté binaire impair.
Décompose l'algorithme QFT
Maintenant qu'on a acquis plus d'intuition sur la relation entre les états de qubits dans la base computationnelle et la base de Fourier, creusons dans l'algorithme QFT lui-même. En d'autres termes, quelles portes applique-t-on réellement sur l'ordinateur quantique pour réaliser cette transformée ?
Commençons petit, avec un seul Qubit. Ça signifie qu'on aura deux états de base. QFT transforme les états de base computationnels et en états de base de Fourier et :