Exercice Partie 2 : créer un générateur de nombres aléatoires quantiques

Effectué

Dans cette unité, vous implémentez la deuxième partie de votre générateur de nombres aléatoires quantiques. Vous combinez plusieurs bits aléatoires pour former un plus grand nombre aléatoire. Cette partie s’appuie sur le générateur de bits aléatoire 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 bits aléatoire qui place un qubit dans un état de superposition, puis mesure ce qubit pour générer une valeur de bit aléatoire de 0 ou 1, chacune avec 50% probabilité. La valeur de ce bit est vraiment aléatoire, il n’existe aucun moyen de savoir à l’avance quel sera le résultat de la mesure. Mais comment pouvez-vous utiliser ce comportement pour générer des nombres aléatoires plus grands ?

Si vous répétez le processus quatre fois, vous pouvez générer cette séquence de chiffres binaires :

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

Si vous combinez ces bits en chaîne de bits, vous pouvez former un nombre plus grand. Dans cet exemple, la séquence de bits ${0110}$ en binaire équivaut au nombre 6 en décimal.

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

Pour générer un nombre aléatoire arbitrairement important, répétez simplement ce processus plusieurs fois. Ensuite, combinez tous les bits en nombre binaire et convertissez ce nombre binaire en nombre décimal.

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

Avant d’écrire votre code Q#, nous allons décrire la logique pour générer un nombre aléatoire :

  1. Définissez max comme nombre décimal maximal que vous souhaitez générer.
  2. Déterminez le nombre de bits aléatoires, nBitsqui sont requis pour générer 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 précédente.
  5. Sinon, l’opération est terminée. Retourne le nombre généré sous forme d’entier décimal.

Par exemple, définissons max la valeur 12. Autrement dit, 12 est le plus grand nombre que votre générateur de nombres aléatoires doit générer.

Utilisez l’équation suivante pour déterminer le nombre de bits requis pour représenter le nombre 12 en binaire :

$${\lfloor ln(12) / ln(2) + 1 \rfloor}$$

Selon cette équation, vous avez besoin de 4 bits pour représenter un nombre compris entre 0 et 12.

Par exemple, supposons que vous générez un bit aléatoire quatre fois et obtenez la chaîne de bits ${1101_{\ binary}}$. Cette valeur en binaire est égale à 13 en décimale. 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 égale à ${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 dans Q#

Ici, vous développez le Main.qs fichier de la leçon précédente pour générer votre générateur de nombres aléatoires.

Importer les bibliothèques nécessaires

Tout d’abord, importez les espaces de noms de la bibliothèque standard Q# qui contiennent les fonctions et les opérations dont vous avez besoin pour écrire votre programme. Le compilateur Q# charge automatiquement de nombreuses fonctions et opérations courantes. Mais pour le générateur de nombres aléatoires quantiques, vous avez besoin de certaines fonctions et opérations supplémentaires à partir de deux espaces de noms Q# : Microsoft.Quantum.Math et Microsoft.Quantum.Convert.

Copiez et collez les directives suivantes import au début de votre Main.qs fichier :

import Std.Convert.*;
import Std.Math.*;

Remarque

Vous pouvez utiliser Std au lieu de Microsoft.Quantum pour importer des fonctions et des opérations à partir de la bibliothèque standard.

Renommer l’opération Main en GenerateRandomBit

Le programme générateur de nombres aléatoires utilise l’opération Main que vous avez écrite dans l’unité précédente pour générer un bit aléatoire. Renommez l’opération Main pour GenerateRandomBit que cette opération ait un nom plus descriptif et n’est pas le point d’entrée du programme.

Copiez et collez le code suivant dans Main.qs:

import Std.Convert.*;
import Std.Math.*;

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 générateur de nombres aléatoires

Créez une opération appelée GenerateRandomNumberInRange. Cette opération appelle à plusieurs reprises l’opération GenerateRandomBit pour générer une chaîne de bits.

Copiez le code suivant et placez-le directement avant l’opération GenerateRandomBit dans votre Main.qs fichier :

/// 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's within the requested range.
    // Generate it again if it's outside the range.
    return sample > max ? GenerateRandomNumberInRange(max) | sample;
}

Voici une vue d’ensemble du code dans GenerateRandomNumberInRange:

  • Appelez la BitSizeI fonction de la Std.Math bibliothèque pour calculer le nombre de bits nécessaires pour représenter l’entier stocké dans max.
  • Utilisez une for boucle pour générer un nombre de bits aléatoires égaux à nBits. Appelez votre GenerateRandomBit opération pour générer les bits aléatoires.
  • Dans la for boucle, utilisez l’instruction set pour mettre à jour la bits variable avec chaque nouveau bit aléatoire. La variable bits est une variable mutable, ce qui signifie que la valeur de bits peut changer pendant le calcul.
  • Appelez la fonction ResultArrayAsInt de la bibliothèque Std.Convert pour convertir le tableau de bits dans bits en entier positif stocké dans sample.
  • Dans l’instruction return, vérifiez si sample est supérieur à max. Si sample est supérieur à max, appelez GenerateRandomNumberInRange à nouveau et recommencez. Sinon, retournez le nombre aléatoire stocké dans sample.

Ajouter un point d’entrée

Enfin, ajoutez une opération de point d’entrée à votre code afin que le compilateur puisse exécuter votre programme. Par défaut, le compilateur Q# recherche une Main opération et utilise Main comme point d’entrée, quel que soit l’emplacement Main de votre fichier. Ici, l’opération Main définit une valeur pour max et appelle l’opération GenerateRandomNumberInRange pour générer un nombre aléatoire compris entre 0 et max.

Par exemple, pour générer un nombre aléatoire compris entre 0 et 100, copiez le code suivant dans votre Main.qs fichier :

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

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

Programme final

Voici le code Q# complet de votre programme dans Main.qs:

import Std.Convert.*;
import Std.Math.*;

operation Main() : Int {
    let max = 100;
    Message($"Generating 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's within the requested range.
    // Generate it again if it's 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

Essayez votre nouveau générateur de nombres aléatoires quantiques !

Pour exécuter votre programme, choisissez le code lens Exécuter dans la liste des commandes au-dessus de l'opération Main. Ou appuyez sur Ctrl + F5. La sortie s’affiche dans la console de débogage. Exécutez le programme plusieurs fois et notez comment le résultat change.

Félicitations ! Vous avez créé un générateur de nombres quantiques vraiment aléatoires en Q#.

Exercice bonus

Essayez de modifier le programme afin qu’il exige également que le nombre aléatoire généré soit supérieur à un nombre positif minimal, minau lieu de zéro.