Parte 2 do Exercício: Criar um gerador quântico de números aleatórios
Nesta unidade, você implementa a segunda fase do gerador quântico de números aleatórios: combinando vários bits aleatórios para formar um número aleatório maior. Essa fase se baseia no gerador de bits aleatório que você já criou na unidade anterior.
Combine vários bits aleatórios para formar um número maior
Na unidade anterior, você criou um gerador de bits aleatórios que gera um bit aleatório colocando um qubit em superposição e medindo-o.
Ao medir o qubit, você obterá um bit aleatório, 0 ou 1, com igual probabilidade de 50%. O valor desse bit é verdadeiramente aleatório, não há como saber o que você obtém após a medição. Mas como você pode usar esse comportamento para gerar números aleatórios maiores?
Digamos que você repita o processo quatro vezes, gerando esta sequência de dígitos binários:
$${0, 1, 1, 0}$$
Se você concatenar ou combinar esses bits em uma cadeia de caracteres de bits, poderá formar um número maior. Neste exemplo, a sequência de bits ${0110}$ é equivalente a seis em decimal.
$${0110_{\ binary} \equiv 6_{\ decimal}}$$
Se você repetir esse processo muitas vezes, poderá combinar vários bits para formar qualquer número grande.
Definir a lógica do gerador de números aleatórios
Vamos descrever qual deve ser a lógica de um gerador de números aleatórios, desde que o gerador de bits aleatórios compilado na unidade anterior:
- Defina
max
como o número máximo que você deseja gerar. - Defina o número de bits aleatórios que você precisa gerar calculando quantos bits,
nBits
, você precisa para expressar números inteiros atémax
. - Gere uma cadeia de caracteres de bits aleatória com comprimento
nBits
. - Se a cadeia de caracteres de bits representar um número maior que
max
, volte para a etapa três. - Caso contrário, o processo está concluído. Retorna o número gerado como um inteiro.
Como exemplo, vamos definir max
como 12. Ou seja, 12 é o maior número que você deseja obter do gerador de números aleatórios.
Você precisa de ${\lfloor ln(12) / ln(2) + 1 \rfloor}$ ou quatro bits para representar um número entre 0 e 12. (Por questões de brevidade, vamos ignorar como derivar essa equação.)
Digamos que você gere a cadeia de caracteres de bits ${1101_{\ binary}}$, que é equivalente a ${13_{\ decimal}}$. Como 13 é maior que 12, você repete o processo.
Em seguida, você gera a cadeia de caracteres de bits ${0110_{\ binary}}$, que é equivalente a ${6_{\ decimal}}$. Já que 6 é menor que 12, o processo é concluído.
O gerador de números aleatórios quântico retorna o número 6.
Criar um gerador de número aleatório completo
Aqui, você expande o arquivo Main.qs
para compilar números aleatórios maiores.
Importar as bibliotecas necessárias
Primeiro, você precisa importar os namespaces necessários da biblioteca Q# Padrão para o programa. O compilador Q# carrega várias funções e operações comuns automaticamente. No entanto, para obter o gerador quântico de números aleatórios completo, você precisa de algumas funções e operações adicionais dos dois namespaces de Q#: Microsoft.Quantum.Math
e Microsoft.Quantum.Convert
.
Copie e cole as seguintes diretivas de import
na parte superior do seu arquivo Main.qs
:
import Microsoft.Quantum.Convert.*;
import Microsoft.Quantum.Math.*;
Renomeie a operação Main
como GenerateRandomBit
Para obter o gerador quântico de números aleatórios completo, você vai reutilizar a operação definida na unidade anterior. No entanto, o nome da operação Main
é o ponto de entrada do programa e deve ser exclusivo. Para evitar confusão, você precisa renomear a operação Main
como GenerateRandomBit
.
A operação GenerateRandomBit
agora deverá se parecer com o seguinte:
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;
}
Definir a operação de número aleatório quântico
Aqui, você define a operação GenerateRandomNumberInRange
. Essa operação chama repetidamente a operação GenerateRandomBit
para criar uma cadeia de caracteres de bits.
Copie o código a seguir e cole-o antes da operação GenerateRandomBit
no arquivo 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;
}
Vamos dedicar um momento para analisar o novo código.
- Você precisa calcular o número de bits necessários para expressar inteiros até
max
. A funçãoBitSizeI
da bibliotecaMicrosoft.Quantum.Math
converte um inteiro no número de bits necessários para representá-la. - A operação
GenerateRandomNumberInRange
usa um loopfor
para gerar números aleatórios até que ele gere um igual a ou menor quemax
. O loopfor
funciona exatamente como um loopfor
em outras linguagens de programação. - A variável
bits
é uma variável mutável. Uma variável mutável é aquela que pode ser alterada durante a computação. Você usa a diretivaset
para alterar o valor de uma variável mutável. - A função
ResultArrayAsInt
parte da bibliotecaMicrosoft.Quantum.Convert
. Essa função converte a cadeia de caracteres de bits em um inteiro positivo.
Adicione um ponto de entrada
Para terminar, você adiciona um ponto de entrada ao programa. Por padrão, o compilador Q# procura uma operação Main
e inicia o processamento a partir daí, independentemente de onde estiver localizada. A operação Main
chama a operação GenerateRandomNumberInRange
para gerar um número aleatório entre 0 e um número max
. Nesse exemplo, você define o valor máximo como 100.
Copie e cole o código a seguir no seu arquivo 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);
}
Programa final
O arquivo Main.qs
deve ter esta aparência:
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;
}
Execute o programa
Vamos experimentar nosso novo gerador de números aleatórios!
- Antes de executar o programa, você precisa definir o perfil de destino como Irrestrito. Selecione Visualizar>Paleta de Comandos, pesquise QIR, selecione Q#: Defina o perfil de destino QIR do Azure Quantum e selecione Q#: irrestrito.
- Para executar seu programa, selecione Executar na lista de comandos acima da operação
Main
ou pressione Ctrl+F5. A saída será exibida no console de depuração. - Execute o programa novamente para exibir um resultado diferente.
Observação
Se o perfil de destino não estiver definido como Irrestrito, um erro será recebido ao executar o programa.
Parabéns! Agora você sabe como combinar a lógica clássica com Q # para criar um gerador quântico de números aleatórios.
Exercício de bônus
Tente modificar o programa para também exigir que o número aleatório gerado seja maior que algum número mínimo, min
, em vez de zero.