Exercício Parte 2 - Criar um gerador quântico de números aleatórios

Concluído

Nesta unidade, você implementa a segunda fase do seu gerador quântico de números aleatórios: combinando vários bits aleatórios para formar um número aleatório maior. Esta fase baseia-se no gerador de bits aleatórios 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ório que gera um bit aleatório colocando um qubit em superposição e medindo-o.

Quando você mede o qubit, você obterá um bit aleatório, 0 ou 1, com igual probabilidade de 50%. O valor desse bit é realmente 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 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.

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 construído na unidade anterior:

  1. Defina max como o número máximo que você deseja gerar.
  2. Defina o número de bits aleatórios que você precisa gerar calculando quantos bits, nBits, você precisa expressar inteiros até max.
  3. Gere uma cadeia de bits aleatórios que tenha nBits de comprimento.
  4. Se a cadeia de bits representar um número maior do que max, volte ao passo três.
  5. 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 obter do gerador de números aleatórios.

Você precisa de ${\lfloor ln(12) / ln(2) + 1 \rfloor}$, ou 4 bits para representar um número entre 0 e 12. (Por uma questão de brevidade, ignoramos como derivar esta equação.)

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 retorna o número 6.

Crie um gerador de números aleatórios completo

Aqui, você expande o Main.qs arquivo para criar números aleatórios maiores.

Importar as bibliotecas necessárias

Primeiro, você precisa importar os namespaces necessários da biblioteca Q# Standard para o programa. O compilador Q# carrega muitas funções e operações comuns automaticamente, no entanto, para o gerador de números aleatórios quânticos completo, você precisa de algumas funções e operações adicionais de dois namespaces Q#: Microsoft.Quantum.Mathe Microsoft.Quantum.Convert.

Copie e cole as seguintes import diretivas na parte superior do arquivo Main.qs :

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

Renomeie a Main operação para GenerateRandomBit

Para o gerador de números aleatórios completo, você vai reutilizar a operação definida na unidade anterior. No entanto, o nome Main da operação é o ponto de entrada do programa e deve ser exclusivo. Para evitar confusão, você precisa renomear a Main operação para GenerateRandomBit.

A GenerateRandomBit operação deve ter esta aparência:

    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, define a operação GenerateRandomNumberInRange. Esta operação chama repetidamente a operação GenerateRandomBit para criar uma cadeia de bits.

Copie o código a seguir e cole-o antes da GenerateRandomBit operação em seu Main.qs arquivo:

    /// 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 recapitular o novo código.

  • Você precisa calcular o número de bits necessários para expressar inteiros até max. A BitSizeI função da biblioteca converte Microsoft.Quantum.Math um inteiro para o número de bits necessários para representá-lo.
  • A operação GenerateRandomNumberInRange utiliza um ciclo de for para gerar números aleatórios até gerar um que seja igual ou inferior a max. O for loop funciona exatamente da mesma forma que um for 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 diretiva set para alterar o valor de uma variável mutável.
  • A ResultArrayAsInt função vem da Microsoft.Quantum.Convert biblioteca. Esta função converte a cadeia de bits para um número inteiro positivo.

Adicionar um ponto de entrada

Finalmente, você adiciona um ponto de entrada ao programa. Por padrão, o compilador Q# procura uma Main operação e começa a processar lá, não importa onde ela esteja localizada. A Main operação chama a GenerateRandomNumberInRange operação para gerar um número aleatório entre 0 e um max número. Neste exemplo, você define o valor máximo como 100.

Copie e cole o seguinte código no seu Main.qs ficheiro:

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 seu Main.qs ficheiro deve ter o seguinte aspeto:

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 o novo gerador de números aleatórios!

  1. Antes de executar o programa, você precisa definir o perfil de destino como Irrestrito. Selecione Exibir>Paleta de Comandos, procure QIR, selecione Q#: Definir o perfil de destino do Azure Quantum QIR e selecione Q#: irrestrito.
  2. Para executar o programa, selecione Executar na lista de comandos acima da Main operação ou pressione Ctrl+F5. Sua saída aparecerá no console de depuração.
  3. Execute o programa novamente para ver um resultado diferente.

Nota

Se o perfil de destino não estiver definido como Sem restrições, você receberá um erro ao executar o programa.

Parabéns! Agora já sabe como combinar lógica clássica com o 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 do que algum número mínimo, minem vez de zero.