Exercício – 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 já criou. Você precisará escrever algum código clássico para esta fase.

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 RandomNumberGenerator.qs arquivo para criar números aleatórios maiores.

Adicionar as bibliotecas necessárias

Para o gerador de números aleatórios completo, você precisa incluir três bibliotecas Q#: Microsoft.Quantum.Math, Microsoft.Quantum.Intrinsic, e Microsoft.Quantum.Convert. Adicione as seguintes open diretivas para RandomNumberGenerator.qs assim:

namespace QuantumRandomNumberGenerator {
open Microsoft.Quantum.Convert;
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Math;

// The rest of the code goes here.

}

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.

Modifique RandomNumberGenerator.qs assim:

namespace QuantumRandomNumberGenerator {
    open Microsoft.Quantum.Convert;
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Math;

    /// 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.

Definir o ponto de entrada

Agora o seu programa pode gerar números aleatórios. Aqui, define o ponto de entrada para o programa.

Modifique RandomNumberGenerator.qs o arquivo assim:

namespace QuantumRandomNumberGenerator {
    open Microsoft.Quantum.Convert;
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Math;

    @EntryPoint()
    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);

        // 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;
    }
}

A diretiva let declara variáveis que não mudam durante o cálculo. Para fins de aprendizagem, aqui definimos o valor máximo como 100.

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 abaixo @EntryPoint()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.