Esercitazione: Implementare un generatore quantistico di numeri casuali in Q#

Informazioni su come scrivere un programma quantistico di base in Q# che sfrutta la natura della meccanica quantistica per produrre un numero casuale.

In questa esercitazione si apprenderà come

  • Creare un progetto Q#.
  • Preparare l'ambiente di sviluppo per la scrittura di programmi quantistici in Q#.
  • Comprendere come sono strutturati i programmi Q#.
  • Usare qubit e sovrapposizioni per creare un generatore quantistico di numeri casuali.

Prerequisiti

Creazione di un progetto Q#

La prima cosa da fare è creare un nuovo progetto Q#. Questa esercitazione usa l'ambiente basato su applicazioni Q# con VS Code, ma è possibile usare l'IDE preferito.

Per creare un nuovo progetto in Visual Studio Code:

  1. Selezionare Visualizza ->Riquadro comandi, quindi Q#: Crea nuovo progetto.
  2. Selezionare Standalone console application (Applicazione console autonoma).
  3. Selezionare un percorso in cui salvare il progetto, assegnare al progetto il nome Qrng e selezionare Crea progetto.
  4. Al termine dell'operazione, selezionare Open new project... (Apri nuovo progetto...) in basso a destra.

Vengono generati due file: il file di progetto, Qrng.csproj, e un modello di applicazione Q#, Program.qs, che verrà usato per scrivere l'applicazione.

Scrivere un'operazione Q#

A questo punto, è necessario sostituire il contenuto del file Program.qs con il codice seguente:

namespace Qrng {
    open Microsoft.Quantum.Convert;
    open Microsoft.Quantum.Math;
    open Microsoft.Quantum.Measurement;
    open Microsoft.Quantum.Canon;
    open Microsoft.Quantum.Intrinsic;
    
    operation SampleQuantumRandomNumberGenerator() : Result {
        // Allocate a qubit        
        use q = Qubit();  
        // Put the qubit to superposition
        // It now has a 50% chance of being measured 0 or 1  
        H(q);      
        // Measure the qubit value            
        return M(q); 
    }
}

Osservare il nuovo codice.

  • Prima open gli spazi dei nomi necessari dalle librerie Q# per le funzioni e le operazioni richieste.
  • Viene definita l'operazione SampleQuantumRandomNumberGenerator, che non accetta input e produce un valore di tipo Result. Il tipo Result rappresenta il risultato di una misurazione e può avere due valori: Zero o One.
  • Allocare un singolo qubit con la parola chiave use.
  • Usare l'operazione H (Hadamard) per posizionare il qubit in una sovrapposizione uguale.
  • Usare l'operazione M per misurare il qubit e restituire il valore misurato (Zero o One).

Come illustrato nell'articolo Informazioni sul calcolo quantistico, un qubit è un'unità di informazioni quantistiche che possono essere in sovrapposizione. Quando viene misurato, un qubit può trovarsi solo nello stato 0 o 1. Tuttavia, prima della misurazione, lo stato del qubit rappresenta la probabilità di leggere un valore 0 o 1 con una misurazione. In questo esempio, prima della misurazione il qubit si trova in una sovrapposizione uguale, il che significa che c'è una probabilità del 50% di leggere 0 e del 50% di leggere 1. È possibile usare questa probabilità per generare numeri casuali.

L'operazione SampleQuantumRandomNumberGenerator definita dall'utente introduce il tipo di dati Qubit, nativo di Q#. È possibile allocare Qubit solo con un'istruzione use. Quando viene allocato, un qubit si trova sempre nello stato Zero.

Inserendo il qubit in sovrapposizione con l'operazione H e misurandolo con l'operazione M, il risultato è un valore diverso ogni volta che viene richiamato il codice.

Visualizzazione del codice con la sfera di Bloch

Nella sfera di Bloch il polo nord rappresenta il valore classico 0, mentre il polo sud rappresenta il valore classico 1. Qualsiasi sovrapposizione può essere rappresentata da un punto sulla sfera (rappresentato da una freccia). Più vicina è la fine della freccia a un polo, più alta è la probabilità che il qubit collassi nel valore classico assegnato a tale polo quando viene misurato. Ad esempio, lo stato del qubit rappresentato dalla freccia rossa nella figura seguente ha una probabilità più elevata di restituire il valore 0 se lo si misura.

Diagramma che mostra uno stato qubit con una probabilità elevata di misurazione zero.

È possibile usare questa rappresentazione per visualizzare le operazioni eseguite dal codice:

  • Iniziare con un qubit inizializzato nello stato 0 e applicare un'operazione H per creare una sovrapposizione uguale in cui le probabilità di 0 e 1 siano le stesse.
Diagramma che mostra la preparazione di un qubit in sovrapposizione applicando il gate hadamard.
  • Quindi misurare il qubit e salvare l'output:
Diagramma che mostra la misurazione di un qubit e il salvataggio dell'output.

Poiché il risultato della misurazione è casuale e le probabilità di misurare 0 e 1 sono identiche, si è ottenuto un bit completamente casuale. È possibile chiamare questa operazione più volte per creare numeri interi. Ad esempio, se si chiama l'operazione tre volte per ottenere tre bit casuali, è possibile creare numeri casuali a 3 bit, ovvero un numero casuale compreso tra 0 e 7.

Creare un generatore di numeri casuali completo

Ora che è disponibile un'operazione Q# che genera bit casuali, è possibile combinare più bit casuali per compilare un generatore quantistico di numeri casuali completo. È possibile eseguire il programma come applicazione Q# autonoma o usare un programma host in Python o .NET per chiamare il codice Q#.

Definire la logica del generatore di numeri casuali

Prima esaminare come deve essere la logica di un generatore di numeri casuali, a condizione che sia disponibile un generatore di bit casuali:

  1. Definire max come numero massimo da generare.
  2. Definire il numero di bit casuali che è necessario generare. Questa operazione viene eseguita calcolando il numero di bit, numBits, necessari per esprimere numeri interi fino a max.
  3. Generare una stringa di bit casuale di lunghezza numBits.
  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.

Definire l'operazione

Definire quindi l'operazione SampleRandomNumberInRange, che usa un ciclo for per chiamare ripetutamente l'operazione SampleQuantumRandomNumberGenerator e compilare una stringa di bit.

Modificare Program.qs in modo da aggiungere la nuova operazione:

namespace Qrng {

    open Microsoft.Quantum.Canon;
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Measurement;
    open Microsoft.Quantum.Math;
    open Microsoft.Quantum.Convert;

    operation SampleQuantumRandomNumberGenerator() : Result {
        // Allocate a qubit        
        use q = Qubit();  
        // Put the qubit to superposition
        // It now has a 50% chance of being measured 0 or 1  
        H(q);      
        // Measure the qubit value            
        return M(q);           
    }

    operation SampleRandomNumberInRange(max : Int) : Int {
        mutable output = 0; 
        repeat {
            mutable bits = []; 
            for idxBit in 1..BitSizeI(max) {
                set bits += [SampleQuantumRandomNumberGenerator()]; 
            }
            set output = ResultArrayAsInt(bits);
        } until (output <= max);
        return output;
    }
}

A questo punto esaminare per un attimo la nuova operazione.

  • Per calcolare il numero di bit necessari per esprimere numeri interi fino a max, usare la funzione BitSizeI.
  • L'operazione SampleRandomNumberInRange usa un ciclo repeat per generare numeri casuali fino a quando non viene generato un valore uguale o minore di max.
  • Il ciclo for all'interno di repeat funziona esattamente come un ciclo negli altri linguaggi di programmazione.
  • In questo esempio output e bits sono variabili modificabili. Una variabile modificabile può cambiare durante il calcolo. Per cambiare il valore di un valore mutabile, si usa la direttiva set.
  • La funzione ResultArrayAsInt converte la stringa di bit in un numero intero positivo.

Il programma Qrng può ora generare numeri interi casuali.

Eseguire il programma di generazione di numeri casuali

Usando la versione finale del codice Q#,

namespace Qrng {

    open Microsoft.Quantum.Canon;
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Measurement;
    open Microsoft.Quantum.Math;
    open Microsoft.Quantum.Convert;

    operation SampleQuantumRandomNumberGenerator() : Result {
        // Allocate a qubit        
        use q = Qubit();  
        // Put the qubit to superposition
        // It now has a 50% chance of being measured 0 or 1  
        H(q);      
        // Measure the qubit value            
        return M(q);           
    }

    operation SampleRandomNumberInRange(max : Int) : Int {
        mutable output = 0; 
        repeat {
            mutable bits = []; 
            for idxBit in 1..BitSizeI(max) {
                set bits += [SampleQuantumRandomNumberGenerator()]; 
            }
            set output = ResultArrayAsInt(bits);
        } until (output <= max);
        return output;
    }
}

selezionare la scheda per il linguaggio e l'ambiente preferiti e seguire le istruzioni per eseguire o chiamare il programma Q#.

Un'applicazione Q# autonoma richiede EntryPoint in modo che il compilatore Q# sappia dove avviare il programma. Per creare l'applicazione Q# completa, aggiungere il punto di ingresso seguente al programma Q#, Program.qs:

namespace Qrng {

    open Microsoft.Quantum.Canon;
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Measurement;
    open Microsoft.Quantum.Math;
    open Microsoft.Quantum.Convert;

    operation SampleQuantumRandomNumberGenerator() : Result {
        // Allocate a qubit.
        use q = Qubit();
        // Put the qubit to superposition.
        H(q);
        // It now has a 50% chance of being measured 0 or 1.
        // Measure the qubit value.
        return M(q);
    }

    operation SampleRandomNumberInRange(max : Int) : Int {
        mutable output = 0; 
        repeat {
            mutable bits = []; 
            for idxBit in 1..BitSizeI(max) {
                set bits += [SampleQuantumRandomNumberGenerator()]; 
            }
            set output = ResultArrayAsInt(bits);
        } until (output <= max);
        return output;
    }

    @EntryPoint()
    operation SampleRandomNumber() : Int {
        let max = 50;
        Message($"Sampling a random number between 0 and {max}: ");
        return SampleRandomNumberInRange(max);
    }
}

Il programma esegue l'operazione o la funzione contrassegnata con l'attributo @EntryPoint() in un simulatore o in uno strumento di stima delle risorse, a seconda della configurazione del progetto e delle opzioni della riga di comando.

In Visual Studio è sufficiente premere Ctrl + F5 per eseguire lo script.

In VS Code compilare Program.qs la prima volta digitando nel terminale quanto segue:

dotnet build

Per le esecuzioni successive non è necessario ripetere la compilazione. Per eseguirlo, digitare il comando seguente e premere INVIO:

dotnet run --no-build

Nota

Questo frammento di codice non viene attualmente eseguito in alcun hardware targetsAzure Quantum disponibile, perché il chiamabile ResultArrayAsInt richiede una QPU con profilo di calcolo completo.

Passaggi successivi

Esplorare altre esercitazioni su Q#: