Tutoriel : Implémenter la transformation Quantum Fourier dans Q#
Ce tutoriel vous montre comment écrire et simuler un programme quantique de base qui fonctionne sur des qubits individuels.
Même si Q# a principalement été créé comme un langage de programmation élémentaire destiné à des programmes quantiques à grande échelle, il peut aussi s’utiliser pour explorer la programmation quantique de manière plus approfondie, à savoir en traitant directement des qubits spécifiques. Plus précisément, ce tutoriel étudie plus en détail la transformation de Fourier quantique (QFT), une sous-routine qui fait partie intégrante de nombreux algorithmes quantiques plus importants.
Ce didacticiel vous montre comment effectuer les opérations suivantes :
- Définir des opérations quantiques dans Q#.
- Écrire le circuit de transformation de Fourier quantique
- Simuler une opération quantique de l’allocation qubit à la sortie de mesure.
- Observez comment la fonction d’onde simulée du système quantique évolue tout au long de l’opération.
Remarque
Cette vue plus approfondie du traitement des informations quantiques est souvent décrite par le terme de circuits quantiques, qui représentent l’application séquentielle de portes, ou opérations, à des qubits spécifiques d’un système. Ainsi, les opérations mono- et multi-qubit que vous appliquez séquentiellement peuvent être facilement représentées dans des schémas de circuit. Par exemple, la transformation fourier quantique à trois qubits complète utilisée dans ce didacticiel présente la représentation suivante en tant que circuit :
Conseil
Si vous souhaitez accélérer votre parcours d’informatique quantique, consultez Code avec Azure Quantum, une fonctionnalité unique du site web Azure Quantum. Ici, vous pouvez exécuter des exemples intégrés Q# ou vos propres Q# programmes, générer du nouveau Q# code à partir de vos invites, ouvrir et exécuter votre code dans VS Code pour le web en un clic et poser des questions à Copilot sur l’informatique quantique.
Prérequis
La dernière version de Visual Studio Code ou ouvrir VS Code sur le web.
Dernière version de l’extension AzureQuantum Development Kit. Pour plus d’informations sur l’installation, consultez Installation du QDK sur VS Code.
Si vous souhaitez utiliser jupyter Notebooks, vous devez également installer Python et les extensions Jupyter, ainsi que le dernier
qsharp
package Python. Pour ce faire, ouvrez un terminal et exécutez la commande suivante :$ pip install --upgrade qsharp
Créer un Q# fichier
- Dans VS Code, sélectionnez Fichier > nouveau fichier texte
- Enregistrez le fichier en tant que QFTcircuit.qs. Ce fichier contient le Q# code de votre programme.
- Ouvrez QFTcircuit.qs.
Écrire un circuit QFT dans Q#
La première partie de ce tutoriel consiste à définir l’opération Q# Main
, qui exécute la transformation de Fourier quantique sur trois qubits. La fonction DumpMachine
est utilisée pour observer la façon dont la fonction d’onde simulée du système à trois qubits évolue au fil de l’opération. Dans la deuxième partie du tutoriel, vous ajouterez des fonctionnalités de mesure et vous comparerez les états des qubits avant et après les mesures.
Vous construirez l’opération étape par étape. Copiez et collez le code dans les sections suivantes dans le fichier QFTcircuit.qs .
Vous pouvez afficher le code complet Q# de cette section en tant que référence.
Importer des bibliothèques requises Q#
Dans votre Q# fichier, importez les espaces de noms appropriés Microsoft.Quantum.*
.
import Microsoft.Quantum.Diagnostics.*;
import Microsoft.Quantum.Math.*;
import Microsoft.Quantum.Arrays.*;
// operations go here
Définir des opérations avec des arguments et des retours
Ensuite, définissez l’opération Main
:
operation Main() : Unit {
// do stuff
}
L’opération Main()
ne prend jamais d’arguments, et pour le moment retourne un Unit
objet, qui est analogue au retour void
en C# ou à un tuple vide, Tuple[()]
en Python.
Plus tard, vous modifierez l’opération afin qu’elle retourne un tableau des résultats de mesure.
Allouer des qubits
Dans l’opération Q# , allouez un registre de trois qubits avec le use
mot clé. Avec use
, les qubits sont automatiquement alloués dans l’état $\ket{0}$.
use qs = Qubit[3]; // allocate three qubits
Message("Initial state |000>:");
DumpMachine();
De la même façon que dans les calculs quantiques réels, Q# ne vous permet pas d’accéder directement aux états des qubits. Toutefois, l’opération imprime l’état DumpMachine
actuel de la target machine, de sorte qu’elle peut fournir des informations précieuses pour le débogage et l’apprentissage lorsqu’elle est utilisée conjointement avec le simulateur d’état complet.
Appliquer des opérations à qubit unique et contrôlées
Ensuite, vous appliquez les opérations qui composent l’opération Main
elle-même. Q# contient déjà un grand nombre de ces opérations quantiques, ainsi que d’autres opérations quantiques de base, dans l’espace Microsoft.Quantum.Intrinsic
de noms.
Remarque
Notez qu’il Microsoft.Quantum.Intrinsic
n’a pas été importé dans l’extrait de code précédent avec les autres espaces de noms, car il est chargé automatiquement par le compilateur pour tous les Q# programmes.
L’opération H
(de Hadamard) est la première opération appliquée au premier qubit :
Pour appliquer une opération à un qubit spécifique à partir d’un registre (par exemple, un seul Qubit
issu d’un tableau Qubit[]
), utilisez la notation d’index standard.
Donc, l’application de l’opération H
au premier qubit du registre qs
s’écrit ainsi :
H(qs[0]);
En plus d’appliquer l’opération H
à des qubits individuels, le circuit QFT consiste principalement en des rotations R1
contrôlées. Une R1(θ, <qubit>)
opération en général laisse le composant $\ket{0}$ du qubit inchangé lors de l’application d’une rotation de $e^{i\theta}$ au composant $\ket{1}$.
Q# permet de conditionner facilement l’exécution d’une opération sur un ou plusieurs qubits de contrôle. En général, il suffit de faire précéder l’appel par Controlled
pour que les arguments d’opération changent comme suit :
Op(<normal args>)
$\to$ Controlled Op([<control qubits>], (<normal args>))
Notez que l’argument de qubit de contrôle doit être un tableau, même s’il référence un seul qubit.
Les opérations contrôlées dans le QFT sont les R1
opérations qui agissent sur le premier qubit (et contrôlées par les deuxième et troisième qubits) :
Dans votre fichier Q#, appelez ces opérations avec ces instructions :
Controlled R1([qs[1]], (PI()/2.0, qs[0]));
Controlled R1([qs[2]], (PI()/4.0, qs[0]));
La fonction PI()
est utilisée pour définir les rotations en termes de pi radians.
Appliquer l’opération SWAP
Après avoir appliqué les opérations pertinentes H
et les rotations contrôlées aux deuxième et troisième qubits, le circuit ressemble à ceci :
//second qubit:
H(qs[1]);
Controlled R1([qs[2]], (PI()/2.0, qs[1]));
//third qubit:
H(qs[2]);
Enfin, vous appliquez une SWAP
opération aux premier et troisième qubits pour terminer le circuit. Celle-ci est nécessaire, car la nature de la transformation de Fourier quantique retourne les qubits dans l’ordre inverse, de sorte que les échanges permettent une intégration continue de la sous-routine dans des algorithmes plus importants.
SWAP(qs[2], qs[0]);
Vous avez maintenant terminé d’écrire les opérations au niveau qubit de la transformation de Fourier quantique dans l’opération Q# :
Libérer des qubits
La dernière étape consiste à appeler DumpMachine()
une nouvelle fois pour voir l’état après l’opération, puis à libérer les qubits. Les qubits étaient dans l’état $\ket{0}$ lorsque vous les avez alloués. Vous devez maintenant les rétablir à leur état initial en utilisant l’opération ResetAll
.
Exiger que tous les qubits soient explicitement réinitialisés à $\ket{0}$ est une fonctionnalité de base de Q#, car il permet à d’autres opérations de connaître leur état précisément quand ils commencent à utiliser ces mêmes qubits (une ressource rare). En outre, cela garantit qu’ils ne sont pas intriqués dans d’autres qubits dans le système. Si la réinitialisation n’est pas effectuée à la fin d’un bloc d’allocation use
, une erreur d’exécution peut être générée.
Ajoutez les lignes suivantes à votre fichier Q# :
Message("After:");
DumpMachine();
ResetAll(qs); // deallocate qubits
Opération QFT complète
Le Q# programme est terminé. Votre fichier QFTcircuit.qs doit maintenant ressembler à ceci :
import Microsoft.Quantum.Diagnostics.*;
import Microsoft.Quantum.Math.*;
import Microsoft.Quantum.Arrays.*;
operation Main() : Unit {
use qs = Qubit[3]; // allocate three qubits
Message("Initial state |000>:");
DumpMachine();
//QFT:
//first qubit:
H(qs[0]);
Controlled R1([qs[1]], (PI()/2.0, qs[0]));
Controlled R1([qs[2]], (PI()/4.0, qs[0]));
//second qubit:
H(qs[1]);
Controlled R1([qs[2]], (PI()/2.0, qs[1]));
//third qubit:
H(qs[2]);
SWAP(qs[2], qs[0]);
Message("After:");
DumpMachine();
ResetAll(qs); // deallocate qubits
}
Exécuter le circuit QFT
Pour l’instant, l’opération Main
ne retourne aucune valeur : l’opération retourne Unit
la valeur. Plus tard, vous allez modifier l’opération pour retourner un tableau de résultats de mesure (Result[]
).
- Avant d’exécuter le programme, vérifiez dans la barre d’état en bas de VS Code que le target profil est défini sur Q#: Sans restriction. Pour modifier le target profil, sélectionnez le target profil dans la barre d’état, puis sélectionnez Illimité dans le menu déroulant. Si le target profil n’est pas défini sur Non restreint, vous obtenez une erreur lorsque vous exécutez le programme.
- Pour exécuter votre programme, sélectionnez Exécuter Q# le fichier dans la liste déroulante de l’icône de lecture en haut à droite, ou appuyez sur Ctrl+F5. Le programme exécute l’opération
Main()
sur le simulateur par défaut. - Les
Message
sorties etDumpMachine
les sorties s’affichent dans la console de débogage.
Si vous êtes curieux de savoir comment les autres états d’entrée sont impactés, vous pouvez essayer d’appliquer d’autres opérations qubit avant la transformation.
Ajouter des mesures au circuit QFT
L’affichage de la fonction DumpMachine
a montré les résultats de l’opération, mais malheureusement, un principe fondamental de la mécanique quantique veut qu’un système quantique réel ne peut pas avoir une telle fonction DumpMachine
.
Au lieu de cela, les informations sont extraites par le biais de mesures, ce qui, en général, ne permet pas de fournir des informations sur l’état quantique complet, mais peut également altérer radicalement le système en lui-même.
Il existe de nombreux types de mesures quantiques, mais l’exemple étudié ici se concentre sur les plus basiques, à savoir les mesures projectives sur des qubits uniques. En cas de mesure dans une base donnée (par exemple, la base de calcul $ { \ket{0}, \ket{1} } $), l’état du qubit est projeté sur tout état de base qui a été mesuré, détruisant ainsi toute superposition entre les deux.
Modifier l’opération QFT
Pour implémenter des mesures dans un programme Q#, utilisez l’opération M
, qui retourne un type Result
.
Tout d’abord, modifiez l’opération Main
pour retourner un tableau de résultats de mesure, Result[]
, au lieu de Unit
.
operation Main() : Result[] {
Définir et initialiser un tableau Result[]
Avant d’allouer des qubits, déclarez et liez un tableau à trois éléments (un Result
pour chaque qubit) :
mutable resultArray = [Zero, size = 3];
Le mot clé mutable
qui précède resultArray
permet à la variable d’être modifiée dans le code plus tard, par exemple, lors de l’ajout des résultats de vos mesures.
Effectuer des mesures dans une boucle for
et ajouter des résultats au tableau
Après les opérations de transformation QFT, insérez le code suivant :
for i in IndexRange(qs) {
set resultArray w/= i <- M(qs[i]);
}
La fonction IndexRange
appelée sur un tableau (par exemple, le tableau de qubits, qs
) retourne une plage sur les index du tableau.
Ici, il est utilisé dans la boucle for
pour mesurer séquentiellement chaque qubit avec l’instruction M(qs[i])
.
Chaque type Result
mesuré (soit Zero
, soit One
) est ensuite ajouté à la position d’index correspondante dans resultArray
avec une instruction de mise à jour et réaffectation.
Remarque
La syntaxe de cette instruction est propre à Q#, mais elle correspond à la réaffectation de variables similaires resultArray[i] <- M(qs[i])
, vue dans d’autres langages comme F# et R.
Le mot clé set
est toujours utilisé pour réaffecter des variables liées à l’aide de mutable
.
Retourner resultArray
Avec les trois qubits mesurés et les résultats ajoutés à resultArray
, vous pouvez sereinement réinitialiser et libérer les qubits comme auparavant. Pour retourner les mesures, insérez :
return resultArray;
Exécuter le circuit QFT avec les mesures
Changez maintenant le placement des DumpMachine
pour sortir l’état avant et après les mesures.
Votre code Q# final doit ressembler à ceci :
import Microsoft.Quantum.Diagnostics.*;
import Microsoft.Quantum.Math.*;
import Microsoft.Quantum.Arrays.*;
operation Main() : Result[] {
mutable resultArray = [Zero, size = 3];
use qs = Qubit[3];
//QFT:
//first qubit:
H(qs[0]);
Controlled R1([qs[1]], (PI()/2.0, qs[0]));
Controlled R1([qs[2]], (PI()/4.0, qs[0]));
//second qubit:
H(qs[1]);
Controlled R1([qs[2]], (PI()/2.0, qs[1]));
//third qubit:
H(qs[2]);
SWAP(qs[2], qs[0]);
Message("Before measurement: ");
DumpMachine();
for i in IndexRange(qs) {
set resultArray w/= i <- M(qs[i]);
}
Message("After measurement: ");
DumpMachine();
ResetAll(qs);
Message("Post-QFT measurement results [qubit0, qubit1, qubit2]: ");
return resultArray;
}
Conseil
N’oubliez pas d’enregistrer votre fichier chaque fois que vous introduisez une modification du code avant de l’exécuter à nouveau.
- Avant d’exécuter le programme, vérifiez dans la barre d’état en bas de VS Code que le target profil est défini sur Q#: Sans restriction. Pour modifier le target profil, sélectionnez le target profil dans la barre d’état, puis sélectionnez Illimité dans le menu déroulant. Si le target profil n’est pas défini sur Non restreint, vous obtenez une erreur lorsque vous exécutez le programme.
- Pour exécuter votre programme, sélectionnez Exécuter Q# le fichier dans la liste déroulante de l’icône de lecture en haut à droite, ou appuyez sur Ctrl+5. Le programme exécute l’opération
Main()
sur le simulateur par défaut. - Les
Message
sorties etDumpMachine
les sorties s’affichent dans la console de débogage.
La sortie doit ressembler à ceci :
Before measurement:
Basis | Amplitude | Probability | Phase
-----------------------------------------------
|000⟩ | 0.3536+0.0000𝑖 | 12.5000% | 0.0000
|001⟩ | 0.3536+0.0000𝑖 | 12.5000% | 0.0000
|010⟩ | 0.3536+0.0000𝑖 | 12.5000% | 0.0000
|011⟩ | 0.3536+0.0000𝑖 | 12.5000% | 0.0000
|100⟩ | 0.3536+0.0000𝑖 | 12.5000% | 0.0000
|101⟩ | 0.3536+0.0000𝑖 | 12.5000% | 0.0000
|110⟩ | 0.3536+0.0000𝑖 | 12.5000% | 0.0000
|111⟩ | 0.3536+0.0000𝑖 | 12.5000% | 0.0000
After measurement:
Basis | Amplitude | Probability | Phase
-----------------------------------------------
|010⟩ | 1.0000+0.0000𝑖 | 100.0000% | 0.0000
Post-QFT measurement results [qubit0, qubit1, qubit2]:
[Zero, One, Zero]
Cette sortie illustre plusieurs choses différentes :
- En comparant le résultat retourné à la pré-mesure
DumpMachine
, cela n’illustre clairement pas la superposition post-QFT sur les états de base. Une mesure ne retourne qu’un seul état de base, avec une probabilité déterminée par l’amplitude de cet état dans la fonction d’onde du système. - D’après la post-mesure
DumpMachine
, vous voyez que la mesure change l’état lui-même, en le projetant de la superposition initiale sur les états de base vers l’état de base unique qui correspond à la valeur mesurée.
Si vous répétez cette opération de nombreuses fois, vous pouvez voir que les statistiques des résultats commencent à illustrer la superposition pondérée de l’état post-QFT qui donne lieu à un résultat aléatoire à chaque fois. Toutefois, en plus d’être inefficace et toujours imparfait, cela ne ferait que reproduire les amplitudes relatives des états de base, et non les phases relatives entre elles. Ce dernier point ne constitue pas un problème dans cet exemple, mais vous verriez des phases relatives apparaître si une entrée plus complexe que $\ket{000}$ était donnée à QFT.
Utiliser les Q# opérations pour simplifier le circuit QFT
Comme mentionné en introduction, la puissance de Q# repose en grande partie sur sa capacité à vous libérer des soucis liés à la gestion des qubits individuels.
En effet, si vous voulez développer des programmes quantiques applicables à grande échelle, déterminer si une opération H
doit être effectuée avant ou après une rotation particulière ne fait que vous ralentir. Azure Quantum fournit l’opération ApplyQFT
, que vous pouvez utiliser et appliquer pour n’importe quel nombre de qubits.
Remplacez tout, de la première
H
opération à l’opérationSWAP
, inclusive, par :ApplyQFT(qs);
Votre code doit maintenant ressembler à ceci
import Microsoft.Quantum.Diagnostics.*; import Microsoft.Quantum.Math.*; import Microsoft.Quantum.Arrays.*; operation Main() : Result[] { mutable resultArray = [Zero, size = 3]; use qs = Qubit[3]; //QFT: //first qubit: ApplyQFT(qs); Message("Before measurement: "); DumpMachine(); for i in IndexRange(qs) { set resultArray w/= i <- M(qs[i]); } Message("After measurement: "); DumpMachine(); ResetAll(qs); Message("Post-QFT measurement results [qubit0, qubit1, qubit2]: "); return resultArray; }
Réexécutez le Q# programme et notez que la sortie est la même que précédemment.
Pour voir l’avantage réel de l’utilisation Q# des opérations, remplacez le nombre de qubits par quelque chose d’autre que
3
:
mutable resultArray = [Zero, size = 4];
use qs = Qubit[4];
//...
Vous pouvez donc appliquer le QFT approprié pour un nombre donné de qubits, sans avoir à vous soucier de l’ajout de nouvelles H
opérations et rotations sur chaque qubit.
Contenu connexe
Explorez les autres tutoriels Q# :
- Le générateur de nombres aléatoires quantiques montre comment écrire un Q# programme qui génère des nombres aléatoires hors qubits dans la superposition.
- L’algorithme de recherche de Grover montre comment écrire un Q# programme qui utilise l’algorithme de recherche de Grover.
- L’inanglement quantique montre comment écrire un Q# programme qui manipule et mesure des qubits et illustre les effets de la superposition et de l’inanglement.
- Les katas quantiques sont des tutoriels auto-rythmes et des exercices de programmation visant à enseigner les éléments de l’informatique quantique et Q# de la programmation en même temps.