Tutorial: Implementar um gerador de números aleatórios quânticos em Q#
Neste tutorial, você aprende a escrever um programa quântico básico que Q# aproveita a natureza da mecânica quântica para produzir um número aleatório.
Neste tutorial, vai:
- Crie um Q# programa.
- Analise os principais componentes de um Q# programa.
- Defina a lógica de um problema.
- Combine operações clássicas e quânticas para resolver um problema.
- Trabalhar com qubits e sobreposição para criar um gerador quântico de números aleatórios.
Gorjeta
Se você quiser acelerar sua jornada de computação quântica, confira Código com o Azure Quantum, um recurso exclusivo do site do Azure Quantum. Aqui, você pode executar amostras internas Q# ou seus próprios Q# programas, gerar novo Q# código a partir de seus prompts, abrir e executar seu código no VS Code for the Web com um clique e fazer perguntas ao Copilot sobre computação quântica.
Pré-requisitos
Para executar o exemplo de código no Copilot no Azure Quantum:
- Uma conta de email da Microsoft (MSA).
Para desenvolver e executar o exemplo de código no Visual Studio Code:
A versão mais recente do Visual Studio Code ou abra o VS Code na Web.
A versão mais recente da extensão do AzureQuantum Development Kit. Para obter detalhes da instalação, consulte Instalando o QDK no VS Code.
Se você quiser usar o Jupyter Notebooks, você também precisa instalar o Python e as extensões Jupyter e o pacote Python mais recente
qsharp
. Para fazer isso, abra um terminal e execute o seguinte comando:$ pip install --upgrade qsharp
Definir o problema
Os computadores clássicos não produzem números aleatórios, mas sim números pseudoaleatórios . Um gerador de números pseudoaleatórios gera uma sequência determinística de números com base em algum valor inicial, chamado de semente. Para melhor aproximar os valores aleatórios, este seed é muitas vezes a hora atual do relógio da CPU.
Os computadores quânticos, por outro lado, podem gerar números verdadeiramente aleatórios. Isso ocorre porque a medição de um qubit em superposição é um processo probabilístico. O resultado da medição é aleatório e não há como prever o resultado. Este é o princípio básico dos geradores quânticos de números aleatórios.
Um qubit é uma unidade de informação quântica que pode estar em sobreposição. Quando medido, um qubit só pode estar no estado 0 ou no estado 1 . No entanto, antes da medição, o estado do qubit representa a probabilidade de ler um 0 ou um 1 com uma medição.
Você começa tomando um qubit em um estado base, por exemplo, zero. O primeiro passo do gerador de números aleatórios é usar uma operação Hadamard para colocar o qubit em uma superposição igual. A medição deste estado resulta em um zero ou um com 50% de probabilidade de cada resultado, um bit verdadeiramente aleatório.
Não há como saber o que você obterá após a medição do qubit em superposição, e o resultado é um valor diferente cada vez que o código é invocado. Mas como você pode usar esse comportamento para gerar números aleatórios maiores?
Digamos que repete o processo quatro vezes e gera esta sequência de dígitos binários:
$${0, 1, 1, 0}$$
Se concatenar, ou combinar, estes bits numa cadeia de bits, pode 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. Usando este método, você pode criar um número para usar como uma senha segura, uma vez que você pode ter certeza de que nenhum hacker poderia determinar os resultados da sequência de medições.
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:
- Defina
max
como o número máximo que você deseja gerar. - Defina o número de bits aleatórios que você precisa gerar. Isso é feito calculando quantos bits,
nBits
, você precisa expressar inteiros atémax
. - Gere uma cadeia de bits aleatórios que tenha
nBits
de comprimento. - Se a cadeia de bits representar um número maior do que
max
, volte ao passo três. - De outro modo, o processo está concluído. Devolva o número gerado como um número inteiro.
Como exemplo, vamos definir max
para 12. Ou seja, 12 é o maior número que você deseja usar como senha.
Você precisa de ${\lfloor ln(12) / ln(2) + 1 \rfloor}$, ou 4 bits para representar um número entre 0 e 12. Podemos usar a função BitSizeI
built-in, que pega qualquer inteiro e retorna o número de bits necessários para representá-lo.
Digamos que gera a cadeia de bits ${1101_{\ binary}}$, que equivale a ${13_{\ decimal}}$. Uma vez que 13 é maior que 12, repete-se o processo.
Em seguida, gera a cadeia de bits ${0110_{\ binary}}$, que equivale a ${6_{\ decimal}}$. Uma vez que 6 é menor que 12, o processo está concluído.
O gerador de números aleatórios quânticos retornará o número 6 como sua senha. Na prática, defina um número maior como o máximo, porque números mais baixos são fáceis de decifrar apenas tentando todas as senhas possíveis. Na verdade, para aumentar a dificuldade de adivinhar ou quebrar sua senha, você pode usar o código ASCII para converter binário em texto e gerar uma senha usando números, símbolos e letras maiúsculas e minúsculas.
Escreva um gerador de bits aleatório
O primeiro passo é escrever uma Q# operação que gere um bit aleatório. Esta operação será um dos blocos de construção do gerador de números aleatórios.
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;
}
Agora dê uma olhada no novo código.
- Você define a
GenerateRandomBit
operação, que não recebe nenhuma entrada e produz um valor do tipoResult
. OResult
tipo representa o resultado de uma medição e pode ter dois valores possíveis:Zero
ouOne
. - Você aloca um único qubit com a
use
palavra-chave. Quando é alocado, um qubit está sempre no estado |0〉. - Você usa a
H
operação para colocar o qubit em uma superposição igual. - Você usa a
M
operação para medir o qubit, retornar o valor medido (Zero
ouOne
). - Use a
Reset
operação para redefinir o qubit para o estado |0〉.
Ao colocar o qubit em sobreposição com a H
operação e medi-lo com a M
operação, o resultado é um valor diferente cada vez que o código é invocado.
Visualize o Q# código com a esfera de Bloch
Na Esfera de Bloch, o polo norte representa o valor clássico 0 e o polo sul representa o valor clássico 1. Qualquer sobreposição pode ser representada por um ponto na esfera (representada por uma seta). Quanto mais próximo estiver o fim da seta de um polo, maior a probabilidade de o qubit ser incluído no valor clássico atribuído a esse polo quando medido. Por exemplo, o estado de qubit representado pela seta na figura a seguir tem uma probabilidade maior de dar o valor 0 se você medi-lo.
Você pode usar essa representação para visualizar o que o código está fazendo:
Primeiro, comece com um qubit inicializado no estado |0〉 e aplique uma
H
operação para criar uma superposição igual na qual as probabilidades para 0 e 1 são as mesmas.Em seguida, meça o qubit e salve a saída:
Como o resultado da medição é aleatório e as probabilidades de medir 0 e 1 são as mesmas, você obteve um bit completamente aleatório. Você pode chamar essa operação várias vezes para criar inteiros. Por exemplo, se você chamar a operação três vezes para obter três bits aleatórios, poderá criar números aleatórios de 3 bits (ou seja, um número aleatório entre 0 e 7).
Escreva um gerador de números aleatórios completo
Primeiro, você precisa importar os namespaces necessários da Q# biblioteca padrão para o programa. O Q# compilador carrega muitas funções e operações comuns automaticamente, no entanto, para o gerador de números aleatórios completo, você precisa de algumas funções e operações adicionais de dois Q# namespaces:
Microsoft.Quantum.Math
eMicrosoft.Quantum.Convert
.import Microsoft.Quantum.Convert.*; import Microsoft.Quantum.Math.*;
Em seguida, você define a
GenerateRandomNumberInRange
operação. Esta operação chama repetidamente a operaçãoGenerateRandomBit
para criar uma cadeia de bits./// 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 { 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 recapitular o novo código.
- Você precisa calcular o número de bits necessários para expressar inteiros até
max
. ABitSizeI
função do namespace converteMicrosoft.Quantum.Math
um inteiro para o número de bits necessários para representá-lo. - A operação
SampleRandomNumberInRange
utiliza um ciclo defor
para gerar números aleatórios até gerar um que seja igual ou inferior amax
. Ofor
loop funciona exatamente da mesma forma que umfor
loop em outras linguagens de programação. - A variável
bits
é uma variável mutável. Uma variável mutável é uma variável que pode mudar durante o cálculo. Utilize a diretivaset
para alterar o valor de uma variável mutável. - A
ResultArrayAsInt
função, do namespace padrãoMicrosoft.Quantum.Convert
, converte a cadeia de bits em um inteiro positivo.
- Você precisa calcular o número de bits necessários para expressar inteiros até
Finalmente, você adiciona um ponto de entrada ao programa. Por padrão, o compilador procura uma
Main
operação e começa a Q# processar lá. Ele chama aGenerateRandomNumberInRange
operação para gerar um número aleatório entre 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); }
A diretiva
let
declara variáveis que não mudam durante o cálculo. Aqui você define o valor máximo como 100.Para obter mais informações sobre a
Main
operação, consulte Pontos de entrada.O código completo para o gerador de números aleatórios é o seguinte:
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 {
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;
}
Execute o programa gerador de números aleatórios
Você pode executar o programa no Copilot no Azure Quantum e no Visual Studio Code como um aplicativo autônomo Q# ou usando um programa host Python.
Você pode testar seu Q# código com o Copilot no Azure Quantum gratuitamente - tudo o que você precisa é de uma conta de email da Microsoft (MSA). Para obter mais informações sobre o Copilot no Azure Quantum, consulte Explore Azure Quantum.
Abra o Copilot no Azure Quantum em seu navegador.
Copie e cole o código a seguir no editor de códigos.
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 { 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. }
Selecione o número de disparos a serem executados e selecione Executar.
Os resultados são exibidos no histograma e nos campos Resultados .
Selecione Explicar código para solicitar que o Copilot explique o código para você.
Gorjeta
No Copilot no Azure Quantum, você pode abrir seu programa no VS Code para a Web selecionando o botão do logotipo do VS Code no canto direito do editor de código.
Nota
Este trecho de código não é executado atualmente em nenhum hardware targetsdisponível do Azure Quantum, pois o chamável ResultArrayAsInt
requer uma QPU com perfil de computação completo.
Conteúdos relacionados
Explore outros Q# tutoriais:
- O entrelaçamento quântico mostra como escrever um Q# programa que manipula e mede qubits e demonstra os efeitos da sobreposição e do emaranhamento.
- O algoritmo de pesquisa de Grover mostra como escrever um Q# programa que usa o algoritmo de pesquisa de Grover.
- Quantum Fourier Transforms explora como escrever um Q# programa que aborda diretamente qubits específicos.
- Os Quantum Katas são tutoriais individualizados e exercícios de programação destinados a ensinar os elementos da computação quântica e Q# programação ao mesmo tempo.