Partager via


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 : Diagramme d’un circuit de transformation de Fourier quantique.

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

Créer un Q# fichier

  1. Dans VS Code, sélectionnez Fichier > nouveau fichier texte
  2. Enregistrez le fichier en tant que QFTcircuit.qs. Ce fichier contient le Q# code de votre programme.
  3. 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 :

Diagramme montrant un circuit pour trois QFT qubits à la première Hadamard.

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

Diagramme montrant un circuit pour trois qubits Quantum Fourier Transform through first qubit.

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

Diagramme montrant un circuit pour la transformation fourier quantique de trois qubits.

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

  1. 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.
  2. 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.
  3. Les Message sorties et DumpMachine 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.

  1. 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.
  2. 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.
  3. Les Message sorties et DumpMachine 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 :

  1. 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.
  2. 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.

  1. Remplacez tout, de la première H opération à l’opération SWAP , inclusive, par :

    ApplyQFT(qs);
    
  2. 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;
    
    }
    
  3. Réexécutez le Q# programme et notez que la sortie est la même que précédemment.

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

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.