Exercice - Créer un générateur de nombres aléatoires quantiques

Effectué

Dans cette unité, vous implémentez la deuxième phase de votre générateur de nombres aléatoires quantiques : la combinaison de plusieurs bits aléatoires pour former un plus grand nombre aléatoire. Cette phase s’appuie sur le générateur de bits aléatoires que vous avez déjà créé dans l’unité précédente.

Combiner plusieurs bits aléatoires pour former un plus grand nombre

Dans l’unité précédente, vous avez créé un générateur de bit aléatoire qui génère un bit aléatoire en plaçant un qubit en superposition et en le mesurant.

Lorsque vous mesurez le qubit, vous obtenez un bit aléatoire, 0 ou 1, avec une probabilité égale de 50 %. La valeur de ce bit est vraiment aléatoire, il n’existe aucun moyen de savoir ce que vous obtenez après la mesure. 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.

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

Nous allons expliquer à quoi doit ressembler la logique d’un générateur de nombres aléatoires, en utilisant le générateur de bits aléatoires de l’unité précédente :

  1. Définissez max comme le nombre maximal à générer.
  2. Définissez le nombre de bits aléatoires que vous devez générer, en calculant 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 voulez obtenir à partir du générateur de nombres aléatoires.

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’expliquons 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é.

Votre générateur de nombres aléatoires quantiques renvoie le nombre 6.

Créer un générateur de nombres aléatoires complet

Ici, vous développez le fichier Main.qs pour générer des nombres aléatoires plus grands.

Importer les bibliothèques nécessaires

Vous devez d’abord importer les espaces de noms nécessaires de la bibliothèque standard Q# vers le programme. Le compilateur Q# charge automatiquement de nombreuses fonctions et opérations courantes. Toutefois, pour obtenir le générateur de nombres aléatoires quantiques complet, vous avez besoin de fonctions et d’opérations supplémentaires provenant de deux espaces de noms Q# : Microsoft.Quantum.Math et Microsoft.Quantum.Convert.

Copiez et collez les directives import suivantes en haut de votre fichier Main.qs :

import Microsoft.Quantum.Convert.*;
import Microsoft.Quantum.Math.*;

Renommer l’opération Main en GenerateRandomBit

Pour obtenir le générateur de nombres aléatoires complet, vous allez réutiliser l’opération définie dans l’unité précédente. Toutefois, le nom d’opération Main est le point d’entrée du programme, et doit être unique. Pour éviter toute confusion, vous devez renommer l’opération Main en GenerateRandomBit.

L’opération GenerateRandomBit doit ressembler à ceci :

    operation GenerateRandomBit() : Result {
        // Allocate a qubit.
        use q = Qubit();
    
        // Set the qubit into superposition of 0 and 1 using the Hadamard 
        H(q);
    
        // Measure the qubit and store the result.
    
        let result = M(q);
    
        // Reset qubit to the |0〉 state.
        Reset(q);
    
        // Return the result of the measurement.
        return result;
    }

Définir l’opération de nombre aléatoire quantique

Ici, 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.

Copiez le code suivant, puis collez-le avant l’opération GenerateRandomBit dans votre fichier Main.qs :

    /// 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 fonction BitSizeI de la bibliothèque Microsoft.Quantum.Math convertit un entier en nombre de bits nécessaires pour le représenter.
  • L’opération GenerateRandomNumberInRange utilise une boucle for pour générer des nombres aléatoires jusqu’à générer une valeur inférieure ou égale à max. La boucle for fonctionne exactement de la même façon qu’une boucle for 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 fonction ResultArrayAsInt vient de la bibliothèque Microsoft.Quantum.Convert. Cette fonction convertit la chaîne de bits en un entier positif.

Ajouter un point d’entrée

Enfin, vous ajoutez un point d’entrée au programme. Par défaut, le compilateur Q# recherche une opération Main, et commence le traitement à partir de ce point, peu importe où il se trouve. L’opération Main appelle l’opération GenerateRandomNumberInRange pour générer un nombre aléatoire compris entre 0 et max. Dans cet exemple, vous définissez la valeur maximale à 100.

Copiez et collez le code suivant dans votre fichier Main.qs :

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);
}

Programme final

Votre fichier Main.qs doit se présenter ainsi :

import Microsoft.Quantum.Convert.*;
import Microsoft.Quantum.Math.*;

    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 operation
        H(q);
    
        // 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.
        Reset(q);
    
        // Return the result of the measurement.
        return result;
    }

Exécuter le programme

Essayons notre nouveau générateur de nombres aléatoires.

  1. Avant d’exécuter le programme, vous devez définir le profil cible sur Non restreint. Sélectionnez Afficher>Palette de commandes, recherchez QIR, sélectionnez Q# : Définir le profil cible QIR Azure Quantum, puis sélectionnez Q# : Non restreint.
  2. Pour exécuter votre programme, sélectionnez Exécuter dans la liste des commandes au-dessus de l’opération Main, ou appuyez sur Ctrl+F5. Votre sortie s’affiche dans la console de débogage.
  3. Réexécutez le programme pour voir un résultat différent.

Remarque

Si le profil cible n’est pas défini sur Non restreint, vous obtenez une erreur quand vous exécutez le programme.

Félicitations ! Vous savez maintenant comment combiner la logique classique au langage Q# pour créer un générateur de nombres aléatoires quantiques.

Exercice bonus

Tentez de modifier le programme pour exiger également que le nombre aléatoire généré soit supérieur à un nombre minimal (min), plutôt qu’à zéro.