Exercice : créer différents états de superposition avec Q#

Effectué

Dans les unités précédentes, vous avez découvert la superposition et la notation Dirac. Assez de théorie pour l’instant ! Explorons la superposition en Q# en écrivant du code.

Dans cette unité, vous allez à créer une superposition quantique et vous plonger dans les probabilités avec Q# en utilisant la fonction DumpMachine. La fonction DumpMachine vide les informations sur l’état actuel du système quantique au point où il est appelé.

Créer un fichier Q#

  1. Ouvrez Visual Studio Code.
  2. Dans Visual Studio Code, sélectionnez Fichier> Nouveau fichier texte et enregistrez le fichier sous Main.qs.
  3. Sélectionnez Afficher -> Palette de commandes et tapez Q# : Définissez le profil cible QIR Azure Quantum. Appuyez sur Entrée.
  4. Sélectionnez Q# : Sans restriction.

Prise en main de la superposition

Commençons par un programme simple qui génère un bit aléatoire à l’aide d’un qubit dans la superposition. Vous allez utiliser la fonction DumpMachine pour voir l’état du qubit à différents points du programme.

  1. Ajoutez le code suivant au fichier Main.qs :

    import Microsoft.Quantum.Diagnostics.*;
    
    operation Main() : Result {
        use q = Qubit();
        Message("Initialized qubit:");
        DumpMachine(); // First dump
        Message(" ");
        H(q);
        Message("Qubit after applying H:");
        DumpMachine(); // Second dump
        Message(" ");
        let randomBit = M(q);
        Message("Qubit after the measurement:");
        DumpMachine(); // Third dump
        Message(" ");
        Reset(q);
        Message("Qubit after resetting:");
        DumpMachine(); // Fourth dump
        Message(" ");
        return randomBit;
    }
    

    Ici, vous appelez DumpMachine quatre fois :

    • Une fois le qubit alloué.
    • Après avoir placé le qubit en superposition.
    • Après avoir mesuré l’état du qubit.
    • Après avoir réinitialisé le qubit.

    Vous fractionnez l'opération MResetZ en deux opérations : M et Reset. Pour ce faire, vous devez inspecter l’état après la mesure.

  2. Pour exécuter votre programme sur le simulateur intégré, cliquez sur Exécuter au-dessus de l’opération Main ou appuyez sur Ctrl+F5. Votre sortie s’affiche dans la console de débogage.

  3. La fonction DumpMachine crée une table contenant les informations qui décrivent l'état du registre qubit. Plus précisément, elle indique l’amplitude de probabilité, la probabilité ainsi que la phase en radians pour chaque état de base.

  4. À la fin du programme, vous obtenez un résultat de Zero ou One. Examinons chaque étape.

    1. Qubit initialisé : Chaque qubit alloué avec l'instruction use commence dans l'état $|0\rangle$. DumpMachine produit donc l'information qui correspond à un registre à qubit unique dont l'état est $|0\rangle$.

      Initialized qubit:
      
      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
         |0⟩ |  1.0000+0.0000𝑖 |   100.0000% |   0.0000
      
    2. Qubit après l’application de H : Après avoir appliqué H, nous préparons le qubit dans l'état de superposition $|\psi\rangle=\frac1{\sqrt2} |0\rangle + \frac1{\sqrt2} |1\rangle$.

      Qubit after applying H:
      
      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
         |0⟩ |  0.7071+0.0000𝑖 |    50.0000% |   0.0000
         |1⟩ |  0.7071+0.0000𝑖 |    50.0000% |   0.0000
      
    3. Qubit après la mesure : Après avoir mesuré et stocké le résultat, qui peut être une valeur de Zero ou One. Par exemple, si l’état résultant est One, l’état des registres est réduit à $|1\rangle$ et n’est plus en superposition.

      Qubit after the measurement:
      
      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
         |1⟩ |  1.0000+0.0000𝑖 |   100.0000% |   0.0000
      
    4. Qubit après la réinitialisation : L’opération Reset réinitialise le qubit à l’état $|0\rangle$. N'oubliez pas que pour toute opération Q#, vous devez toujours maintenir les qubits que vous utilisez dans l'état $|0\rangle$ afin que d'autres opérations puissent s'en servir.

      Qubit after resetting:
      
      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
         |0⟩ |  1.0000+0.0000𝑖 |   100.0000% |   0.0000
      

    Remarque

    Vos sorties peuvent différer, car le générateur de nombres aléatoires est probabiliste. Les probabilités des résultats ne sont pas déterministes.

Explorer d’autres types d’états de superposition

Maintenant que vous savez inspecter l’état d'un registre, vous pouvez voir d’autres opérations qui modifient l’état de vos qubits et les placer dans une superposition.

Le générateur de nombres aléatoires actuel produit Zero ou One avec une probabilité de 50 %. Examinons un deuxième exemple qui génère des nombres aléatoires avec une probabilité différente.

Générateur de bits aléatoires asymétriques

Supposons que vous souhaitez créer un générateur de bits aléatoire qui est asymétrique, autrement dit, la probabilité d’obtenir Zero est différente de la probabilité d’obtenir One.

Par exemple, vous souhaitez obtenir le résultat Zero avec la probabilité $P$, et le résultat One avec la probabilité $1-P$. Voici un état de qubit valide qui produit un générateur de bits aléatoires :

$$|\psi\rangle=\sqrt{P}|0\rangle+\sqrt{1-P}|1\rangle$$

Ici, $\alpha=\sqrt{P}$ et $\beta=\sqrt{1-P}$ sont respectivement les amplitudes des états de base $|0\rangle$ et $|1\rangle$.

Cet état peut être obtenu en appliquant séquentiellement l’opérateur $R_y(2\arccos\sqrt{P})$ à un qubit dont l’état est $|0\rangle.$. Vous pouvez obtenir ce résultat dans Q# en utilisant l’opération Ry de la bibliothèque Standard.

Conseil

Pour en savoir plus sur la logique mathématique sous-jacente aux opérations à qubit unique, consultez le tutoriel sur les portes à qubit unique dans Quantum Kata.

  1. Modifiez Main.qs comme dans l’exemple suivant, puis enregistrez le fichier. Cet exemple choisit $\alpha$ avec une valeur approximative $\frac13$.

    import Microsoft.Quantum.Diagnostics.*;
    import Microsoft.Quantum.Math.*;
    
    operation Main() : Result {
        use q = Qubit();
        let P = 0.333333; // P is 1/3
        Ry(2.0 * ArcCos(Sqrt(P)), q);
        Message("The qubit is in the desired state.");
        Message("");
        DumpMachine(); // Dump the state of the qubit 
        Message("");
        Message("Your skewed random bit is:");
        let skewedrandomBit = M(q);
        Reset(q);
        return skewedrandomBit;
    }
    
  2. Pour exécuter votre programme sur le simulateur intégré, cliquez sur Exécuter au-dessus de l’opération Main ou appuyez sur Ctrl+F5. Votre sortie s’affiche dans la console de débogage.

  3. Vous pouvez constater que DumpMachine affiche l'état attendu après avoir appliqué les opérations, puis affiche les probabilités associées. Notez que la probabilité d’obtenir Zero est d’environ 33,33 % et que la probabilité d’obtenir One est d’environ 66,67 %. Par conséquent, le générateur de bits aléatoires est asymétrique.

    The qubit is in the desired state.
    
    DumpMachine:
    
     Basis | Amplitude      | Probability | Phase
     -----------------------------------------------
       |0⟩ |  0.5773+0.0000𝑖 |    33.3333% |   0.0000
       |1⟩ |  0.8165+0.0000𝑖 |    66.6667% |   0.0000
    
    
    Your skewed random bit is:
    Result: "One"
    

    Remarque

    Votre sortie peut différer, car le générateur de nombres aléatoires est probabiliste. Les probabilités des résultats ne sont pas déterministes.

Superposition de plusieurs qubits

Examinons maintenant les superpositions d'un registre contenant de nombreux qubits. Par exemple, si votre registre contient trois qubits, vous disposez de huit états de base :

$$|000\rangle,|001\rangle,|010\rangle,|011\rangle,|100\rangle,|101\rangle, |110\rangle,|111\rangle $$

Vous pouvez donc exprimer un état arbitraire de trois qubits :

$$|\psi\rangle=\alpha_0|000\rangle+\alpha_1|001\rangle+\alpha_2|010\rangle+\alpha_3|011\rangle+\alpha_4|100\rangle+\alpha_5|101\rangle+\alpha_6 |110\rangle+\alpha_7|111\rangle$$

Où $\alpha_i$ représente des nombres complexes qui remplissent la condition $\sum|\alpha_i|^2=1$.

Par exemple, vous pouvez placer des qubits dans une superposition uniforme en appliquant H à chaque qubit. Vous pouvez utiliser cette superposition uniforme pour créer une version différente du générateur de nombres aléatoires quantiques, afin de produire des nombres à trois bits en mesurant trois qubits en superposition plutôt que de mesurer trois fois un qubit.

Base Nombre
$\ket{000}$ 0
$\ket{001}$ 1
$\ket{010}$ 2
$\ket{011}$ 3
$\ket{100}$ 4
$\ket{101}$ 5
$\ket{110}$ 6
$\ket{111}$ 7
  1. Modifiez Main.qs comme dans l’exemple suivant, puis enregistrez le fichier.

    import Microsoft.Quantum.Diagnostics.*;
    import Microsoft.Quantum.Math.*;
    import Microsoft.Quantum.Convert.*;
    import Microsoft.Quantum.Arrays.*;
    
    operation Main() : Int {
        use qubits = Qubit[3];
        ApplyToEach(H, qubits);
        Message("The qubit register in a uniform superposition: ");
        DumpMachine();
        let result = ForEach(M, qubits);
        Message("Measuring the qubits collapses the superposition to a basis state.");
        DumpMachine();
        ResetAll(qubits);
        return BoolArrayAsInt(ResultArrayAsBoolArray(result));
    }
    

    Ici, vous voyez trois concepts :

    • La variable qubits représente maintenant un tableau Qubit avec une longueur de trois.
    • Les opérations ApplyToEach et ForEach permettent de mesurer plusieurs qubits et d’agir sur ceux-ci, et elles utilisent moins de code. Les bibliothèques Q# offrent de nombreuses types d'opérations et de fonctions qui facilitent l'écriture de programmes quantiques.
    • Les fonctions BoolArrayAsInt et ResultArrayAsBoolArray de la bibliothèque Microsoft.Quantum.Convert transforment le tableau Result binaire renvoyé par ForEach(M, qubits) en un entier.
  2. Pour exécuter le programme, cliquez sur Exécuter au-dessus de l’opération Main ou appuyez sur Ctrl+F5. Votre sortie s’affiche dans la console de débogage.

  3. En utilisant DumpMachine, vous voyez comment le fait de mesurer les trois qubits réduit l'état du registre à l'un des huit états de base possibles. Par exemple, si vous obtenez le résultat 3, cela signifie que l’état du registre est réduit à $|110\rangle$.

    The qubit register in a uniform superposition:
    
    DumpMachine:
    
     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
    
    Measuring the qubits collapses the superposition to a basis state.
    
    DumpMachine:
    
     Basis | Amplitude      | Probability | Phase
     -----------------------------------------------
     |110⟩ |  1.0000+0.0000𝑖 |   100.0000% |   0.0000
    
    Result: "3"
    

    Remarque

    Votre sortie peut différer, car le générateur de nombres aléatoires est probabiliste. Les probabilités des résultats ne sont pas déterministes.

  4. L'opération ForEach(M, qubit) mesure chaque qubit un par un, en réduisant progressivement l'état. Vous pouvez également vider les états intermédiaires après chaque mesure. Pour ce faire, modifiez Main.qs comme dans l’exemple suivant, puis enregistrez le fichier.

    import Microsoft.Quantum.Diagnostics.*;
    import Microsoft.Quantum.Measurement.*;
    import Microsoft.Quantum.Math.*;
    import Microsoft.Quantum.Convert.*;
    
    operation Main() : Int {
        use qubits = Qubit[3];
        ApplyToEach(H, qubits);
        Message("The qubit register in a uniform superposition: ");
        DumpMachine();
        mutable results = [];
        for q in qubits {
            Message(" ");
            set results += [M(q)];
            DumpMachine();
        }
        Message(" ");
        Message("Your random number is: ");
        ResetAll(qubits);
        return BoolArrayAsInt(ResultArrayAsBoolArray(results));
    }
    
  5. Ici, vous utilisez une boucle for pour agir sur chaque qubit de manière séquentielle. Q# offre des capacités de contrôle de flux classiques, telles que des boucles for et des instructions if, que vous pouvez utiliser pour contrôler le flux de votre programme.

  6. Pour exécuter le programme, cliquez sur Exécuter dans la liste des commandes au-dessus de l’opération Main, ou appuyez sur Ctrl+F5.

  7. Vous pouvez constater que chacune des mesures consécutives modifie l'état quantique et, par conséquent, les probabilités d'obtention de chaque résultat. Par exemple, si votre résultat est numéro cinq, vous obtenez la sortie suivante. Examinons brièvement chaque étape :

    1. Préparation de l'état : après avoir appliqué H à chaque qubit du registre, nous obtenons une superposition uniforme.

      The qubit register in a uniform superposition: 
      
      DumpMachine:
      
       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
      
    2. Première mesure : dans la première mesure, le résultat était One. Par conséquent, les amplitudes des états dont le qubit le plus à droite est Zero ont disparu. Les amplitudes sont $|0\rangle=|000\rangle, |2\rangle=|010\rangle, |4\rangle=|100\rangle$ et $|6\rangle= |110\rangle$. Les autres amplitudes augmentent pour remplir la condition de normalisation.

      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
       |001⟩ |  0.5000+0.0000𝑖 |    25.0000% |   0.0000
       |011⟩ |  0.5000+0.0000𝑖 |    25.0000% |   0.0000
       |101⟩ |  0.5000+0.0000𝑖 |    25.0000% |   0.0000
       |111⟩ |  0.5000+0.0000𝑖 |    25.0000% |   0.0000
      
    3. Deuxième mesure : dans la deuxième mesure, le résultat était Zero. Par conséquent, les amplitudes des états dont le deuxième qubit le plus à droite (au milieu) est One ont disparu. Les amplitudes sont $|3\rangle=|011\rangle$ et $|7\rangle=|111\rangle$. Les autres amplitudes augmentent pour remplir la condition de normalisation.

      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
       |001⟩ |  0.7071+0.0000𝑖 |    50.0000% |   0.0000
       |101⟩ |  0.7071+0.0000𝑖 |    50.0000% |   0.0000
      
    4. Troisième mesure : dans la troisième mesure, le résultat était One. Par conséquent, les amplitudes des états dont le qubit le plus à gauche est Zero ont disparu. Le seul état compatible est $|5\rangle=|101\rangle$. La probabilité d'amplitude de cet état est $1$.

      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
       |101⟩ |  1.0000+0.0000𝑖 |   100.0000% |   0.0000
      
      
      Your random number is: 
      Result: "5"
      

    Remarque

    Votre sortie peut différer, car le générateur de nombres aléatoires est probabiliste. Les probabilités des résultats ne sont pas déterministes.