Tutoriel : Implémenter un générateur de nombres aléatoires quantique en Q#

Notes

Quantum Development Kit Microsoft (QDK classique) ne sera plus pris en charge après le 30 juin 2024. Si vous êtes un développeur QDK existant, nous vous recommandons de passer au nouvel Azure Quantum Development Kit (QDK moderne) pour continuer à développer des solutions quantiques. Pour plus d’informations, consultez Migrer votre Q# code vers le QDK moderne.

Découvrez comment écrire un programme quantique de base en Q# qui tire parti de la nature des mécanismes quantiques pour produire un nombre aléatoire.

Ce didacticiel présente les procédures suivantes :

  • Create un Q# programme.
  • Passez en revue les composants main d’un Q# programme.
  • Définissez la logique d’un problème.
  • Combinez les opérations classiques et quantiques pour résoudre un problème.
  • Utiliser des qubits et la superposition pour créer un générateur de nombres aléatoires quantiques

Conseil

Si vous souhaitez accélérer votre parcours d’informatique quantique, case activée du 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 seul clic, et poser des questions à Copilot sur l’informatique quantique.

Prérequis

Définir le problème

Les ordinateurs classiques ne produisent pas de nombres aléatoires, mais plutôt des nombres pseudo-aléatoires. Un générateur de nombres pseudo-aléatoires génère une suite déterministe de nombres en fonction d’une valeur initiale, appelée seed. Pour obtenir la meilleure approximation possible des valeurs aléatoires, cette valeur seed est souvent l’heure actuelle de l’horloge du processeur.

Les ordinateurs quantiques, d’autre part, peuvent générer des nombres vraiment aléatoires. En effet, la mesure d’un qubit en superposition est un processus probabiliste. Le résultat de la mesure est aléatoire et il n’existe aucun moyen de prédire le résultat. Il s’agit du principe de base des générateurs de nombres aléatoires quantiques.

Un qubit est une unité d’informations quantiques qui peut être en superposition. Quand il est mesuré, un qubit peut uniquement être dans l’état 0 ou dans l’état 1. Toutefois, avant la mesure, l’état du qubit représente la probabilité de lire un état 0 ou 1 avec une mesure.

Pour commencer, prenez un qubit dans un état basique, par exemple zéro. La première étape du générateur de nombres aléatoires consiste à utiliser une opération Hadamard pour placer le qubit dans une superposition égale. La mesure de cet état donne un zéro ou un avec une probabilité de 50 % de chaque résultat, un bit vraiment aléatoire.

Il n’existe aucun moyen de savoir ce que vous obtiendrez après la mesure du qubit en superposition, et le résultat est une valeur différente chaque fois que le code est appelé. Mais comment pouvez-vous utiliser ce comportement pour générer des nombres aléatoires plus grands ?

Supposons que vous répétiez le processus quatre fois, ce qui générerait cette suite de chiffres binaires :

$${0, 1, 1, 0}$$

Si vous concaténez (ou combinez) ces bits dans une chaîne binaire, vous pouvez obtenir un nombre plus grand. Dans cet exemple, la séquence de bits ${0110}$ est équivalente à 6 en décimal.

$${0110_{\ binary} \equiv 6_{\ decimal}}$$

Si vous répétez ce processus plusieurs fois, vous pouvez combiner plusieurs bits pour former un grand nombre. À présent, vous pouvez fournir à votre supérieur ce numéro comme mot de passe sécurisé, puisque vous pouvez être sûr qu’aucun pirate galactique ne pourra déterminer les résultats de la séquence de mesures.

Définir la logique du générateur de nombres aléatoires

Nous allons décrire la logique d’un générateur de nombres aléatoires, à condition que nous disposions d’un générateur de bits aléatoires :

  1. Définissez max comme le nombre maximal à générer.
  2. Définissez le nombre de bits aléatoires à générer. Pour ce faire, vous devez calculer le nombre de bits (nBits) dont vous avez besoin pour exprimer des entiers jusqu’à max.
  3. Générez une chaîne de bits aléatoires dont la longueur est nBits.
  4. Si la chaîne de bits représente un nombre supérieur à max, revenez à l’étape 3.
  5. Sinon, l’opération est terminée. Retournez le nombre généré sous la forme d’un entier.

À titre d’exemple, nous allons définir max sur 12. Autrement dit, 12 est le plus grand nombre que vous souhaitez utiliser comme mot de passe sécurisé.

Vous avez besoin de ${\lfloor ln(12) / ln(2) + 1 \rfloor}$, ou de 4 bits pour représenter un nombre compris entre 0 et 12. (Pour rester concis, nous n’expliquerons pas comment dériver cette équation.)

Mettons que vous générez la chaîne de bits ${1101_{\ binary}}$, qui est équivalente à $ ${13_{\ decimal}}$. Comme 13 est supérieur à 12, vous devez répéter le processus.

Ensuite, vous générez la chaîne de bits ${0110_{\ binary}}$, qui est équivalente à ${6_{\ decimal}}$. Étant donné que 6 est inférieur à 12, le processus est terminé.

Le générateur de nombres aléatoires quantiques retourne le numéro 6 comme mot de passe. Dans la pratique, définissez un nombre plus grand comme valeur maximale, car les nombres inférieurs sont faciles à craquer en essayant juste tous les mots de passe possibles. En fait, pour augmenter la difficulté de deviner ou de craquer votre mot de passe, vous pouvez utiliser le code ASCII pour convertir le binaire en texte et générer un mot de passe en utilisant des chiffres, des symboles et un mélange de lettres majuscules et minuscules.

Écrire un générateur de bits aléatoires

La première étape consiste à écrire une Q# opération qui génère un bit aléatoire. Cette opération sera l’un des blocs de construction du générateur de nombres aléatoires.

operation GenerateRandomBit() : Result {
    // Allocate a qubit.
    use q = Qubit();

    // Set the qubit into superposition of 0 and 1 using the Hadamard 
    H(q);

    // At this point the qubit `q` has 50% chance of being measured in the
    // |0〉 state and 50% chance of being measured in the |1〉 state.
    // Measure the qubit value using the `M` operation, and store the
    // measurement value in the `result` variable.
    let result = M(q);

    // Reset qubit to the |0〉 state.
    // Qubits must be in the |0〉 state by the time they are released.
    Reset(q);

    // Return the result of the measurement.
    return result;
}

Examinons à présent le nouveau code.

  • Vous définissez l’opération GenerateRandomBit, qui ne prend aucune entrée et produit une valeur de type Result. Le type Result représente le résultat d’une mesure et peut avoir deux valeurs : Zero ou One.
  • Vous allouez un qubit unique avec le use mot clé. Quand il est alloué, un qubit est toujours dans l’état Zero.
  • Vous utilisez l’opération H pour placer le qubit dans une superposition égale.
  • Vous utilisez l’opération M pour mesurer le qubit, renvoyer la valeur mesurée (Zero ou One).
  • Vous utilisez l’opération Reset pour réinitialiser le qubit à l’état |0〉.

En plaçant le qubit en superposition avec l’opération H et en le mesurant avec l’opération M, le résultat est une valeur différente chaque fois que le code est appelé.

Visualiser le Q# code avec la sphère Bloch

Dans la sphère de Bloch, le pôle nord représente la valeur classique 0 et le pôle sud représente la valeur classique 1. Toute superposition peut être représentée par un point sur la sphère (représentée par une flèche). Plus l’extrémité de la flèche est proche d’un pôle, plus la probabilité est élevée que le qubit soit réduit à la valeur classique attribuée à ce pôle lors de la mesure. Par exemple, l’état du qubit représenté par la flèche dans la figure ci-dessous a une probabilité plus élevée de donner la valeur 0 si vous le mesurez.

Diagramme montrant un état qubit avec une probabilité élevée de mesure de zéro.

Vous pouvez utiliser cette représentation pour visualiser ce que fait le code :

  1. Tout d’abord, commencez avec un qubit initialisé dans l’état 0 et appliquez une opération H pour créer une superposition égale dans laquelle les probabilités d’obtenir 0 et 1 sont les mêmes.

    Diagramme montrant la préparation d’un qubit en superposition en appliquant la porte hadamard.
  2. Ensuite, mesurez le qubit et enregistrez la sortie :

    Diagramme montrant la mesure d’un qubit et l’enregistrement de la sortie.

Comme le résultat de la mesure est aléatoire et que les probabilités de mesure de 0 et 1 sont identiques, vous avez obtenu un bit complètement aléatoire. Nous pouvons appeler cette opération plusieurs fois pour créer des entiers. Par exemple, si vous appelez l’opération trois fois pour obtenir trois bits aléatoires, vous pouvez générer des nombres de 3 bits aléatoires (c’est-à-dire, un nombre aléatoire compris entre 0 et 7).

Écrire un générateur de nombres aléatoires complet

  1. Tout d’abord, vous devez ajouter les espaces de noms requis Q# au programme. Pour le générateur de nombres aléatoires complet, vous devez inclure trois Q# espaces de noms : Microsoft.Quantum.Math, Microsoft.Quantum.Intrinsicet Microsoft.Quantum.Convert.

    open Microsoft.Quantum.Convert;
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Math;
    
  2. Ensuite, vous définissez l’opération GenerateRandomNumberInRange . Cette opération appelle à plusieurs reprises l’opération GenerateRandomBit pour générer une chaîne de bits.

        /// Generates a random number between 0 and `max`.
        operation GenerateRandomNumberInRange(max : Int) : Int {
            // Determine the number of bits needed to represent `max` and store it
            // in the `nBits` variable. Then generate `nBits` random bits which will
            // represent the generated random number.
            mutable bits = [];
            let nBits = BitSizeI(max);
            for idxBit in 1..nBits {
                set bits += [GenerateRandomBit()];
            }
            let sample = ResultArrayAsInt(bits);
    
            // Return random number if it is within the requested range.
            // Generate it again if it is outside the range.
            return sample > max ? GenerateRandomNumberInRange(max) | sample;
        }
    
    

    Prenons un moment pour examiner ce nouveau code.

    • Vous devez calculer le nombre de bits nécessaires pour exprimer des entiers jusqu’à max. La BitSizeI fonction de l’espace Microsoft.Quantum.Math de noms convertit un entier en nombre de bits nécessaires pour le représenter.
    • L’opération SampleRandomNumberInRange utilise une boucle for pour générer des nombres aléatoires jusqu’à générer une valeur inférieure ou égale à max. La for boucle fonctionne exactement comme une for boucle dans d’autres langages de programmation.
    • La variable bits est une variable mutable. Une variable mutable peut changer pendant le calcul. Vous devez utiliser la directive set pour modifier la valeur d’une variable mutable.
    • La ResultArrayAsInt fonction provient de l’espace Microsoft.Quantum.Convert de noms. Cette fonction convertit la chaîne de bits en un entier positif.
  3. Enfin, vous ajoutez un point d’entrée. Dans cet exemple, l’opération Main est le point d’entrée du programme. Il appelle l’opération GenerateRandomNumberInRange pour générer un nombre aléatoire compris entre 0 et 100.

        @EntryPoint()
        operation Main() : Int {
            let max = 100;
            Message($"Sampling a random number between 0 and {max}: ");
    
            // Generate random number in the 0..max range.
            return GenerateRandomNumberInRange(max);
        }
    

    La directive let déclare des variables qui ne changent pas pendant le calcul. Ici, nous définissons la valeur maximale comme 100.

  4. Le code complet du générateur de nombres aléatoires est le suivant :

namespace QuantumRandomNumberGenerator {
    open Microsoft.Quantum.Convert;
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Math;

    @EntryPoint()
    operation Main() : Int {
        let max = 100;
        Message($"Sampling a random number between 0 and {max}: ");

        // Generate random number in the 0..max range.
        return GenerateRandomNumberInRange(max);
    }

    /// Generates a random number between 0 and `max`.
    operation GenerateRandomNumberInRange(max : Int) : Int {
        // Determine the number of bits needed to represent `max` and store it
        // in the `nBits` variable. Then generate `nBits` random bits which will
        // represent the generated random number.
        mutable bits = [];
        let nBits = BitSizeI(max);
        for idxBit in 1..nBits {
            set bits += [GenerateRandomBit()];
        }
        let sample = ResultArrayAsInt(bits);

        // Return random number if it is within the requested range.
        // Generate it again if it is outside the range.
        return sample > max ? GenerateRandomNumberInRange(max) | sample;
    }

    operation GenerateRandomBit() : Result {
        // Allocate a qubit.
        use q = Qubit();

        // Set the qubit into superposition of 0 and 1 using the Hadamard 
        H(q);

        // At this point the qubit `q` has 50% chance of being measured in the
        // |0〉 state and 50% chance of being measured in the |1〉 state.
        // Measure the qubit value using the `M` operation, and store the
        // measurement value in the `result` variable.
        let result = M(q);

        // Reset qubit to the |0〉 state.
        // Qubits must be in the |0〉 state by the time they are released.
        Reset(q);

        // Return the result of the measurement.
        return result;
    }
}

Exécuter le programme de génération de nombres aléatoires

Vous pouvez exécuter le programme dans Copilot dans Azure Quantum et dans Visual Studio Code en tant qu’application autonome Q# ou à l’aide d’un programme hôte Python.

Vous pouvez tester gratuitement votre Q# code avec Copilot dans Azure Quantum. Il vous suffit d’un compte de messagerie Microsoft (MSA). Pour plus d’informations sur copilote dans Azure Quantum, consultez Explorer Azure Quantum.

  1. Ouvrez Copilot dans Azure Quantum dans votre navigateur.

  2. Copiez et collez le code suivant dans l’éditeur de code.

    namespace Tutorial {
        open Microsoft.Quantum.Convert;
        open Microsoft.Quantum.Intrinsic;
        open Microsoft.Quantum.Math;
    
        @EntryPoint()
        operation Main() : Int {
            let max = 100;
            Message($"Sampling a random number between 0 and {max}: ");
    
            // Generate random number in the 0..max range.
            return GenerateRandomNumberInRange(max);
        }
    
        /// # Summary
        /// Generates a random number between 0 and `max`.
        operation GenerateRandomNumberInRange(max : Int) : Int {
            // Determine the number of bits needed to represent `max` and store it
            // in the `nBits` variable. Then generate `nBits` random bits which will
            // represent the generated random number.
            mutable bits = [];
            let nBits = BitSizeI(max);
            for idxBit in 1..nBits {
                set bits += [GenerateRandomBit()];
            }
            let sample = ResultArrayAsInt(bits);
    
            // Return random number if it is within the requested range.
            // Generate it again if it is outside the range.
            return sample > max ? GenerateRandomNumberInRange(max) | sample;
        }
    
        /// # Summary
        /// Generates a random bit.
        operation GenerateRandomBit() : Result {
            // Allocate a qubit.
            use q = Qubit();
    
            // Set the qubit into superposition of 0 and 1 using the Hadamard 
            // operation `H`.
            H(q);
    
            // At this point the qubit `q` has 50% chance of being measured in the
            // |0〉 state and 50% chance of being measured in the |1〉 state.
            // Measure the qubit value using the `M` operation, and store the
            // measurement value in the `result` variable.
            let result = M(q);
    
            // Reset qubit to the |0〉 state.
            // Qubits must be in the |0〉 state by the time they are released.
            Reset(q);
    
            // Return the result of the measurement.
            return result;
    
            // Note that Qubit `q` is automatically released at the end of the block.
        }
    }
    
  3. Sélectionnez le nombre de captures à exécuter, puis cliquez sur Exécuter.

  4. Les résultats sont affichés dans l’histogramme et dans les champs Résultats .

  5. Cliquez sur Expliquer le code pour inviter Copilot à vous expliquer le code.

Conseil

À partir de Copilot dans Azure Quantum, vous pouvez ouvrir votre programme dans VS Code pour le web en cliquant sur le bouton de logo VS Code dans le coin droit de l’éditeur de code.

Notes

Cet extrait de code ne s’exécute actuellement sur aucun matériel targetsAzure Quantum disponible, car l’appelant ResultArrayAsInt nécessite un QPU avec un profil de calcul complet.

Étapes suivantes

Explorez les autres tutoriels Q# :

  • L’intrication quantique montre comment écrire un Q# programme qui manipule et mesure les qubits et illustre les effets de la superposition et de l’intrication.
  • L’algorithme de recherche de Grover montre comment écrire un Q# programme qui utilise l’algorithme de recherche de Grover.
  • Quantum Fourier Transforms explore comment écrire un Q# programme qui traite directement des qubits spécifiques.
  • Les katas quantiques sont des tutoriels auto-rythmés et des exercices de programmation visant à enseigner les éléments de l’informatique quantique et Q# de la programmation en même temps.