Esercizio Parte 2: Creare un generatore quantistico di numeri casuali

Completato

In questa lezione viene implementata la seconda fase del generatore quantistico di numeri casuali, ovvero la combinazione di più bit casuali per formare un numero più grande. Questa fase si basa sul generatore di bit casuale già creato nell'unità precedente.

Combinare più bit casuali per formare un numero maggiore

Nell'unità precedente è stato creato un generatore di bit casuali in grado di generarne uno inserendo un qubit in sovrapposizione e misurandolo.

Quando si misura il qubit, si otterrà un bit casuale, sia 0 che 1, con una probabilità pari al 50%. Il valore di questo bit è effettivamente casuale, in quanto non è possibile sapere cosa si otterrà dopo la misurazione. Ma come è possibile usare questo comportamento per generare numeri casuali più grandi?

Si supponga di ripetere il processo quattro volte, generando questa sequenza di cifre binarie:

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

Se si concatenano, o si combinano, questi bit in una stringa di bit, è possibile formare un numero più grande. In questo esempio, la sequenza di bit ${0110}$ è equivalente a sei in notazione decimale.

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

Se si ripete questo processo molte volte, è possibile combinare più bit per formare qualsiasi numero elevato.

Definire la logica del generatore di numeri casuali

Verrà ora descritta la logica di un generatore di numeri casuali, a condizione che sia disponibile il generatore di bit casuale compilato nell'unità precedente:

  1. Definire max come il numero massimo da generare.
  2. Definire il numero di bit casuali che è necessario generare, calcolando il numero di bit, nBits, necessario per esprimere numeri interi fino a max.
  3. Generare una stringa di bit casuale con lunghezza pari a nBits.
  4. Se la stringa di bit rappresenta un numero maggiore di max, tornare al passaggio tre.
  5. In caso contrario, il processo è completato. Restituire il numero generato come valore intero.

Impostare ad esempio max su 12. Ovvero, 12 è il numero più grande che si vuole ottenere dal generatore di numeri casuali.

Per rappresentare un numero compreso tra 0 e 12, sono necessari 4 bit, ovvero ${\lfloor ln(12) / ln(2) + 1 \rfloor}$. (Per brevità, non viene descritto come derivare questa equazione.)

Si supponga di generare la stringa di bit ${1101_{\ binary}}$, equivalente a ${13_{\ decimal}}$. Poiché 13 è maggiore di 12, si ripete il processo.

Si genera quindi la stringa di bit ${0110_{\ binary}}$, equivalente a ${6_{\ decimal}}$. Poiché 6 è minore di 12, il processo è completato.

Il generatore di numeri casuali quantistici restituisce il numero 6.

Creare un generatore di numeri casuali completo

Si partirà dal file Main.qs per creare numeri casuali più grandi.

Importare le librerie necessarie

Prima di tutto, è necessario importare gli spazi dei nomi necessari dalla libreria Q# Standard al programma. Il compilatore Q# carica automaticamente molte funzioni e operazioni comuni, ma per il generatore di numeri casuali quantistici completi sono necessarie alcune funzioni e operazioni aggiuntive da due spazi dei nomi Q#: Microsoft.Quantum.Mathe Microsoft.Quantum.Convert.

Copiare e incollare le direttive import seguenti all'inizio del file Main.qs:

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

Rinominare l'operazione Main in GenerateRandomBit

Per il generatore di numeri casuali completo, si riuserà l'operazione definita nell'unità precedente. Tuttavia, il nome dell'operazione Main è il punto di ingresso del programma e deve essere univoco. Per evitare confusione, è necessario rinominare l'operazione Main in GenerateRandomBit.

L'aspetto dell'operazione GenerateRandomBit dovrebbe essere simile al seguente:

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

Definire l'operazione di numero casuale quantistico

Si definirà ora l'operazione GenerateRandomNumberInRange. Questa operazione chiama ripetutamente l'operazione GenerateRandomBit per creare una stringa di bit.

Copiare il codice seguente e incollarlo prima dell'operazione GenerateRandomBit nel file 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;
    }

Esaminare per un attimo il nuovo codice.

  • È necessario calcolare il numero di bit necessari per esprimere numeri interi fino a max. La funzione BitSizeI dalla libreria Microsoft.Quantum.Math converte un numero intero nel numero di bit necessari per rappresentarlo.
  • L'operazione GenerateRandomNumberInRange usa un ciclo for per generare numeri casuali fino a quando non viene generato un valore uguale o minore di max. Il ciclo for funziona esattamente come un ciclo for in altri linguaggi di programmazione.
  • La variabile è una variabile bits modificabile. Una variabile modificabile può cambiare durante il calcolo. Usare la direttiva set per cambiare il valore di una variabile modificabile.
  • La funzione ResultArrayAsInt proviene dalla libreria Microsoft.Quantum.Convert. Questa funzione converte la stringa di bit in un numero intero positivo.

Aggiungere un punto di ingresso

Infine, si aggiunge un punto di ingresso al programma. Per impostazione predefinita, il compilatore Q# cerca un'operazione Main e avvia l'elaborazione, indipendentemente dalla posizione in cui si trova. L'operazione Main chiama l'operazione GenerateRandomNumberInRange per generare un numero casuale compreso tra 0 e un numero max. In questo esempio si definisce il valore massimo come 100.

Copiare e incollare il codice seguente nel file 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);
}

Programma finale

Il file Main.qs avrà un aspetto simile al seguente:

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

Eseguire il programma

Provare ora a usare il nuovo generatore di numeri casuali.

  1. Prima di eseguire il programma, è necessario impostare il profilo di destinazione su Senza restrizioni. Selezionare Visualizza>Riquadro comandi, cercare QIR, selezionare Q#: Impostare il profilo di destinazione di Azure Quantum QIR e quindi selezionare Q#: senza restrizioni.
  2. Per eseguire il programma, selezionare Esegui dall'elenco dei comandi sopra l'operazione Main o premere CTRL+F5. L'output verrà visualizzato nella console di debug.
  3. Eseguire di nuovo il programma per visualizzare un risultato diverso.

Nota

Se il profilo di destinazione non è impostato su Senza restrizioni, verrà visualizzato un errore quando si esegue il programma.

Complimenti. A questo punto è possibile combinare la logica classica con Q# per creare un generatore quantistico di numeri casuali.

Esercizio bonus

Provare a modificare il programma in modo da richiedere anche che il numero casuale generato sia maggiore di un numero minimo, min, anziché zero.