Esercitazione: Implementare un generatore quantistico di numeri casuali in Q#
In questa esercitazione si apprenderà come scrivere un programma quantistico di base in Q# che sfrutta la natura della meccanica quantistica per produrre un numero casuale.
Questa esercitazione illustra come:
- Creare un Q# programma.
- Esaminare i componenti principali di un Q# programma.
- Definire la logica di un problema.
- Combinare operazioni classiche e quantistice per risolvere un problema.
- Usare qubit e sovrapposizioni per creare un generatore quantistico di numeri casuali.
Suggerimento
Per accelerare il percorso di calcolo quantistico, vedere Codice con Azure Quantum, una funzionalità univoca del sito Web di Azure Quantum. Qui è possibile eseguire esempi predefiniti Q# o programmi personalizzati Q# , generare nuovo Q# codice dalle richieste, aprire ed eseguire il codice in VS Code per il Web con un solo clic e porre a Copilot eventuali domande sul calcolo quantistico.
Prerequisiti
Per eseguire l'esempio di codice in Copilot in Azure Quantum:
- Un account di posta elettronica Microsoft (MSA).
Per sviluppare ed eseguire l'esempio di codice in Visual Studio Code:
La versione più recente di Visual Studio Code o aprire VS Code sul Web.
Versione più recente dell'estensione di AzureQuantum Development Kit. Per informazioni dettagliate sull'installazione, vedere Installazione di QDK in VS Code.
Se si vogliono usare Jupyter Notebook, è anche necessario installare Python e le estensioni Jupyter e il pacchetto Python più recente
qsharp
. A tale scopo, aprire un terminale ed eseguire il comando seguente:$ pip install --upgrade qsharp
Definire il problema
I computer classici non producono numeri casuali, ma piuttosto numeri pseudocasuali. Un generatore di numeri pseudocasuali genera una sequenza deterministica di numeri in base a un valore iniziale, detto seme. Per una migliore approssimazione dei valori casuali, questo seme corrisponde spesso all'ora corrente del clock della CPU.
I computer quantistici, d'altra parte, possono generare numeri realmente casuali. Ciò è dovuto al fatto che la misurazione di un qubit in sovrapposizione è un processo probabilistico. Il risultato della misurazione è casuale e non è possibile stimarne il risultato. Questo è il principio di base dei generatori di numeri casuali quantistici.
Un qubit è un'unità di informazioni quantistica 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.
Si inizia con un qubit in uno stato di base, ad esempio zero. Il primo passaggio del generatore di numeri casuali consiste nell'usare un'operazione Hadamard per inserire il qubit in una sovrapposizione uguale. La misurazione di questo stato produce uno zero o uno con probabilità del 50% di ogni risultato, un bit veramente casuale.
Non è possibile sapere cosa si otterrà dopo la misurazione del qubit in sovrapposizione e il risultato è un valore diverso ogni volta che viene richiamato il codice. 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. Usando questo metodo, è possibile creare un numero da usare come password sicura, poiché è possibile assicurarsi che nessun hacker possa determinare i risultati della sequenza di misurazioni.
Definire la logica del generatore di numeri casuali
Si esaminerà ora la logica di un generatore di numeri casuali:
- Definire
max
come il numero massimo da generare. - Definire il numero di bit casuali che è necessario generare. Questa operazione viene eseguita calcolando il numero di bit,
nBits
, è necessario esprimere numeri interi fino amax
. - Generare una stringa di bit casuale con lunghezza pari a
nBits
. - Se la stringa di bit rappresenta un numero maggiore di
max
, tornare al passaggio tre. - 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 usare come password.
Per rappresentare un numero compreso tra 0 e 12, sono necessari 4 bit, ovvero ${\lfloor ln(12) / ln(2) + 1 \rfloor}$. È possibile usare la funzione BitSizeI
predefinita , che accetta qualsiasi numero intero e restituisce il numero di bit necessari per rappresentarlo.
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 restituirà il numero 6 come password. Nella pratica impostare un numero più grande come massimo perché è possibile violare facilmente i numeri più piccoli semplicemente provando tutte le password possibili. Infatti, perché risulti più difficile indovinare o violare la password, è possibile usare il codice ASCII per convertire i dati binari in testo e generare una password usando numeri, simboli e lettere maiuscole/minuscole.
Scrivere un generatore di bit casuali
Il primo passaggio consiste nel scrivere un'operazione Q# che genera un bit casuale. Questa operazione sarà uno dei blocchi predefiniti del generatore di numeri casuali.
operation GenerateRandomBit() : Result {
// Allocate a qubit.
use q = Qubit();
// Set the qubit into superposition of 0 and 1 using the Hadamard
H(q);
// At this point the qubit `q` has 50% chance of being measured in the
// |0〉 state and 50% chance of being measured in the |1〉 state.
// 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.
// Qubits must be in the |0〉 state by the time they are released.
Reset(q);
// Return the result of the measurement.
return result;
}
Osservare il nuovo codice.
- Viene definita l'operazione
GenerateRandomBit
, che non accetta input e produce un valore di tipoResult
. Il tipoResult
rappresenta il risultato di una misurazione e può avere due valori:Zero
oOne
. - Allocare un singolo qubit con la
use
parola chiave . Quando viene allocata, un qubit è sempre nello stato |0〉. - Usare l'operazione
H
per posizionare il qubit in una sovrapposizione uguale. - Usare l'operazione
M
per misurare il qubit, restituire il valore misurato (Zero
oOne
). - Usare l'operazione
Reset
per reimpostare il qubit sullo stato |0〉.
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.
Visualizzare il Q# codice con la sfera Bloch
Nella sfera di Bloch il polo nord rappresenta il valore classico 0 e 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.
È possibile usare questa rappresentazione per visualizzare le operazioni eseguite dal codice:
Prima di tutto, iniziare con un qubit inizializzato nello stato |0〉 e applicare un'operazione
H
per creare una sovrapposizione uguale in cui le probabilità per 0 e 1 sono uguali.Quindi misurare il qubit e salvare l'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.
Scrivere un generatore di numeri casuali completo
Prima di tutto, è necessario importare gli spazi dei nomi necessari dalla Q# libreria standard al programma. Il Q# compilatore carica automaticamente molte funzioni e operazioni comuni, ma per il generatore di numeri casuali completo sono necessarie alcune funzioni e operazioni aggiuntive da due Q# spazi dei nomi:
Microsoft.Quantum.Math
eMicrosoft.Quantum.Convert
.import Microsoft.Quantum.Convert.*; import Microsoft.Quantum.Math.*;
Successivamente, si definisce l'operazione
GenerateRandomNumberInRange
. Questa operazione chiama ripetutamente l'operazioneGenerateRandomBit
per creare una stringa di bit./// 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
. LaBitSizeI
funzione delloMicrosoft.Quantum.Math
spazio dei nomi converte un numero intero nel numero di bit necessari per rappresentarlo. - L'operazione
SampleRandomNumberInRange
usa un ciclofor
per generare numeri casuali fino a quando non viene generato un valore uguale o minore dimax
. Il ciclofor
funziona esattamente come un ciclofor
in altri linguaggi di programmazione. - La variabile è una variabile
bits
modificabile. Una variabile modificabile può cambiare durante il calcolo. Usare la direttivaset
per cambiare il valore di una variabile modificabile. - La
ResultArrayAsInt
funzione, dallo spazio dei nomi predefinitoMicrosoft.Quantum.Convert
, converte la stringa di bit in un numero intero positivo.
- È necessario calcolare il numero di bit necessari per esprimere numeri interi fino a
Infine, si aggiunge un punto di ingresso al programma. Per impostazione predefinita, il Q# compilatore cerca un'operazione
Main
e avvia l'elaborazione. Chiama l'operazioneGenerateRandomNumberInRange
per generare un numero casuale compreso tra 0 e 100.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); }
La direttiva
let
dichiara variabili che non cambiano durante il calcolo. Qui si definisce il valore massimo come 100.Per altre informazioni sull'operazione
Main
, vedere Punti di ingresso.Il codice completo per il generatore di numeri casuali è il 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 a Hadamard operation
H(q);
// At this point the qubit `q` has 50% chance of being measured in the
// |0〉 state and 50% chance of being measured in the |1〉 state.
// 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.
// Qubits must be in the |0〉 state by the time they are released.
Reset(q);
// Return the result of the measurement.
return result;
}
Eseguire il programma di generazione di numeri casuali
È possibile eseguire il programma in Copilot in Azure Quantum e in Visual Studio Code come applicazione autonoma Q# o usando un programma host Python.
È possibile testare il Q# codice con Copilot in Azure Quantum gratuitamente. Tutto ciò che serve è un account di posta elettronica Microsoft (MSA). Per altre informazioni su Copilot in Azure Quantum, vedere Esplorare Azure Quantum.
Aprire Copilot in Azure Quantum nel browser.
Copiare e incollare il codice seguente nell'editor di codice.
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); } /// # Summary /// 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; } /// # Summary /// Generates a random bit. operation GenerateRandomBit() : Result { // Allocate a qubit. use q = Qubit(); // Set the qubit into superposition of 0 and 1 using the Hadamard // operation `H`. H(q); // At this point the qubit `q` has 50% chance of being measured in the // |0〉 state and 50% chance of being measured in the |1〉 state. // 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. // Qubits must be in the |0〉 state by the time they are released. Reset(q); // Return the result of the measurement. return result; // Note that Qubit `q` is automatically released at the end of the block. }
Selezionare il numero di scatti da eseguire e selezionare Esegui.
I risultati vengono visualizzati nell'istogramma e nei campi Risultati .
Selezionare Spiega codice per richiedere a Copilot di spiegare il codice.
Suggerimento
Da Copilot in Azure Quantum è possibile aprire il programma in VS Code per il Web selezionando il pulsante logo di VS Code nell'angolo destro dell'editor di codice.
Nota
Questo frammento di codice non viene attualmente eseguito in alcun hardware targetsdi Azure Quantum disponibile, perché il chiamabile ResultArrayAsInt
richiede una QPU con profilo di calcolo completo.
Contenuto correlato
Esplorare altre esercitazioni su Q#:
- L'entanglement quantistico mostra come scrivere un Q# programma che manipola e misura i qubit e illustra gli effetti della sovrapposizione e dell'entanglement.
- L'algoritmo di ricerca di Grover mostra come scrivere un Q# programma che usa l'algoritmo di ricerca di Grover.
- Le trasformazioni Quantum Fourier esplorano come scrivere un Q# programma che punta direttamente a qubit specifici.
- I kata quantistici sono esercitazioni e esercizi di programmazione auto-ritmo volti a insegnare contemporaneamente gli elementi del calcolo quantistico e Q# della programmazione.