Esercizio: Creare stati di sovrapposizione diversi con Q#

Completato

Nelle unità precedenti si è appresa la sovrapposizione e la notazione Dirac. Basta teoria per ora. È il momento di esaminare la sovrapposizione in Q# quando si scrive il codice.

In questa unità si creerà la sovrapposizione quantistica e approfondire le probabilità con Q# usando la funzione DumpMachine. La funzione DumpMachine esegue il dump delle informazioni sullo stato corrente del sistema quantistico nel punto in cui viene chiamato.

Creare un nuovo file Q#

  1. Aprire Visual Studio Code.
  2. In Visual Studio Code selezionare File> Nuovo file di testo e salvare il file come Main.qs.
  3. Selezionare Visualizza -> Riquadro comandi e digitare Q#: Impostare il profilo di destinazione di Azure Quantum QIR. Premere INVIO.
  4. Selezionare Q#: Senza restrizioni.

Introduzione alla sovrapposizione

Iniziamo con un semplice programma che genera un bit casuale usando un qubit in sovrapposizione. Verrà usata la funzione DumpMachine per visualizzare lo stato del qubit in punti diversi del programma.

  1. Aggiungere il codice seguente al file 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;
    }
    

    Qui DumpMachine viene chiamata quattro volte:

    • Dopo l'allocazione del qubit.
    • Dopo l'inserimento del qubit nella sovrapposizione.
    • Dopo la misurazione dello stato del qubit.
    • Dopo la reimpostazione del qubit.

    L'operazione MResetZ viene suddivisa in due operazioni: M e Reset. Questo avviene perché si vuole controllare lo stato dopo la misurazione.

  2. Per eseguire il programma nel simulatore predefinito, fare clic su Esegui sopra l'operazione Main o premere CTRL+F5. L'output verrà visualizzato nella console di debug.

  3. La funzione DumpMachine crea una tabella con informazioni che descrivono lo stato del registro di qubit. In particolare, indica l'ampiezza di probabilità, la probabilità e la fase in radianti per ogni stato di base.

  4. Al termine del programma, si ottiene il risultato Zero o One. Esaminare ogni passaggio.

    1. Qubit inizializzato: Ogni qubit allocato con l'istruzione use inizia nello stato $|0\rangle$. DumpMachine produce quindi le informazioni che corrispondono a un registro a singolo qubit nello stato $|0\rangle$.

      Initialized qubit:
      
      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
         |0⟩ |  1.0000+0.0000𝑖 |   100.0000% |   0.0000
      
    2. Qubit dopo l'applicazione di H: Dopo l'applicazione di H, viene preparato il qubit nello stato di sovrapposizione $|\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 dopo la misurazione: Dopo aver misurato e archiviato il risultato, che può essere un Zero o One. Ad esempio, se lo stato risultante è One, lo stato dei registri viene compresso in $|1\rangle$ e non è più in sovrapposizione.

      Qubit after the measurement:
      
      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
         |1⟩ |  1.0000+0.0000𝑖 |   100.0000% |   0.0000
      
    4. Qubit dopo la reimpostazione: L'operazione Reset ripristina lo stato $|0\rangle$ per il qubit. Tenere presente che per qualsiasi operazione Q# è sempre necessario lasciare i qubit usati nello stato $|0\rangle$, in modo che possano essere usati da altre operazioni.

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

    Nota

    Gli output potrebbero essere diversi perché il generatore di numeri casuali è probabilistico. Le probabilità dei risultati non sono deterministiche.

Esplorare altri tipi di stati di sovrapposizione

Ora che si è appreso come esaminare lo stato di un registro, è possibile osservare più operazioni che modificano lo stato dei qubit e li inseriscono in una sovrapposizione.

L'attuale generatore di numeri casuali produce Zero o One con una probabilità del 50%. Verrà ora esaminato un secondo esempio che genera numeri casuali con una probabilità diversa.

Generatore di bit casuali inclinato

Si supponga di voler creare un generatore di bit casuale asimmetrico, ovvero la probabilità di ottenere Zero è diversa dalla probabilità di ottenere One.

Si vuole, ad esempio, il risultato Zero con probabilità $P$ e il risultato One con probabilità $1-P$. Ecco uno stato qubit valido che produce un generatore di bit casuale di questo tipo:

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

In questo caso, $\alpha=\sqrt{P}$ e $\beta=\sqrt{1-P}$ sono, rispettivamente, le ampiezze degli stati di base $|0\rangle$ e $|1\rangle$.

Questo stato può essere ottenuto applicando in modo sequenziale l'operatore $R_y(2\arccos \sqrt{P})$ a un qubit nello stato $|0\rangle.$ Questo risultato si può ottenere in Q# usando l'operazione Ry della libreria Standard.

Suggerimento

Per altre informazioni sulla matematica dietro le operazioni a qubit singolo, vedere l'esercitazione Single-Qubit Gates in Quantum Katas.

  1. Modificare Main.qs come nell'esempio seguente e quindi salvare il file. In questo esempio si sceglie $\alpha$ in modo che sia circa $\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. Per eseguire il programma nel simulatore predefinito, fare clic su Esegui sopra l'operazione Main o premere CTRL+F5. L'output verrà visualizzato nella console di debug.

  3. È possibile vedere come DumpMachine visualizza lo stato previsto dopo aver applicato le operazioni e visualizza le probabilità associate. Si noti che la probabilità di ottenere Zero è circa il 33,33% e la probabilità di ottenere One è circa il 66,67%. Di conseguenza, il generatore di bit casuali è asimmetrico.

    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"
    

    Nota

    L'output potrebbe essere diverso perché il generatore di numeri casuali è probabilistico. Le probabilità dei risultati non sono deterministiche.

Sovrapposizione multi-qubit

Verranno ora esaminate le sovrapposizioni di un registro che include molti qubit. Se, ad esempio, il registro include tre qubit, si avranno otto diversi stati di base:

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

È quindi possibile esprimere uno stato arbitrario a tre qubit come:

$$|\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$$

In questo caso, $alpha_i$ rappresenta numeri complessi che soddisfano $\sum|alpha_i|^2=1$.

Ad esempio, è possibile inserire qubit in una sovrapposizione uniforme applicando H a ogni qubit. È possibile usare questa sovrapposizione uniforme per creare una versione diversa del generatore quantistico di numeri casuali che genera numeri a tre bit misurando tre qubit in sovrapposizione anziché un qubit tre volte.

Basis Numero
$\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. Modificare Main.qs come nell'esempio seguente e quindi salvare il file.

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

    Ecco tre concetti:

    • La variabile qubits rappresenta ora una matrice Qubit con lunghezza pari a tre.
    • Le operazioni ApplyToEach e ForEach sono utili per misurare più qubit e agire su di essi con meno codice. Le librerie Q# offrono molti tipi di operazioni e funzioni che rendono più efficiente la scrittura di programmi quantistici.
    • Le funzioni BoolArrayAsInt e ResultArrayAsBoolArray della libreria Microsoft.Quantum.Convert trasformano la matrice binaria Result restituita da ForEach(M, qubits) in un numero intero.
  2. Per eseguire il programma, fare clic su Esegui sopra l'operazione Main o premere CTRL+F5. L'output verrà visualizzato nella console di debug.

  3. Usando DumpMachine, è possibile vedere come l'azione di misurare i tre qubit comprima lo stato del registro in uno degli otto stati di base possibili. Ad esempio, se si ottiene il risultato 3, significa che lo stato del registro è compresso in $|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"
    

    Nota

    L'output potrebbe essere diverso perché il generatore di numeri casuali è probabilistico. Le probabilità dei risultati non sono deterministiche.

  4. L'operazione ForEach(M, qubit) misura ogni qubit a turno, comprimendo gradualmente lo stato. È anche possibile eseguire il dump degli stati intermedi dopo ogni misura. A tale scopo, modificare Main.qs come nell'esempio seguente e quindi salvare il file.

    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. In questo caso si usa un ciclo for per agire in sequenza su ogni qubit. Q# include funzionalità di controllo del flusso classiche, ad esempio cicli for e istruzioni if, che è possibile usare per controllare il flusso del programma.

  6. Per eseguire il programma, fare clic su Esegui dall'elenco dei comandi sopra l'operazione Main o premere CTRL+F5.

  7. È possibile vedere in che modo ogni misura consecutiva modifica lo stato quantistico e quindi le probabilità di ottenere ogni risultato. Ad esempio, se il risultato è il numero cinque, si otterrà l'output seguente. Di seguito verrà esaminato brevemente ogni passaggio:

    1. Preparazione dello stato: dopo aver applicato H a ogni qubit del registro, si ottiene una sovrapposizione 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. Prima misura: nella prima misura il risultato era One. Di conseguenza, tutte le ampiezze degli stati il cui qubit più a destra è Zero non sono più presenti. Le ampiezze sono $|0\rangle=|000\rangle, |2\rangle=|010\rangle, |4\rangle=|100\rangle$ e $|6\rangle= |110\rangle$. Tutte le altre ampiezze aumentano per soddisfare la condizione di normalizzazione.

      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. Seconda misura: nella seconda misura il risultato era Zero. Di conseguenza, tutte le ampiezze degli stati il cui secondo qubit più a destra (centrale) è One spariscono. Le ampiezze sono $|3\rangle=|011\rangle$ e $|7\rangle=|111\rangle$. Tutte le altre ampiezze aumentano per soddisfare la condizione di normalizzazione.

      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
       |001⟩ |  0.7071+0.0000𝑖 |    50.0000% |   0.0000
       |101⟩ |  0.7071+0.0000𝑖 |    50.0000% |   0.0000
      
    4. Terza misura: nella terza misura il risultato era One. Di conseguenza, tutte le ampiezze degli stati il cui qubit più a sinistra è Zero vengono eliminate. L'unico stato compatibile è $|5\rangle=|101\rangle$. Questo stato ottiene una probabilità di ampiezza di $1$.

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

    Nota

    L'output potrebbe essere diverso perché il generatore di numeri casuali è probabilistico. Le probabilità dei risultati non sono deterministiche.