练习第 2 部分 - 创建量子随机数生成器

已完成

在此单元中,你将实现量子随机数生成器的第二个阶段:组合多个随机位以形成更大的随机数。 此阶段基于在上一单元中创建的随机位生成器而构建。

将多个随机位组合成一个较大的数

在上一个单元中,你创建了一个随机位生成器,该生成器将一个量子比特置于叠加态并对其进行测量,从而生成随机位。

当你测量量子比特时,你将得到一个随机位,值为 0 或 1,概率均为 50%。 此位的值是真正随机的,没有办法知道在测量之后你会得到什么。 但如何才能通过这种行为生成更大的随机数?

假设重复这个过程四次,生成以下二进制数字序列:

$${0, 1, 1, 0}$$

如果将这些位连接或合并成一个位字符串,就可以形成更大的数字。 在此示例中,位序列 ${0110}$ 等同于十进制的 6。

$${0110_{\ binary} \equiv 6_{\ decimal}}$$

如果多次重复执行此过程,则可以将多个比特组合成任何一个大数字。

定义随机数生成器逻辑

让我们概述一下随机数生成器的逻辑应该是什么(假设前面的单元中内置了随机比特生成器):

  1. max 定义为要生成的最大数字。
  2. 通过计算表示最高到 max 的整数所需的位数 nBits,定义需要生成的随机位数。
  3. 生成长度为 nBits 的随机位字符串。
  4. 如果位字符串表示一个大于 max 的数,则返回到步骤 3。
  5. 否则,此过程完成。 返回生成的数字(整数形式)。

例如,我们将 max 设置为 12。 也就是说,12 是你想要从随机数生成器获得的最大数字。

需要 ${\lfloor ln(12) / ln(2) + 1 \rfloor}$ 或 4 比特来表示一个介于 0 和 12 之间的数字。 (为简便起见,我们跳过推导此公式的过程。)

假设生成了位字符串 ${1101_{\ binary}}$,它等同于 ${13_{\ decimal}}$。 由于 13 大于 12,因此将复该过程。

接下来,生成位字符串 ${0110_{\ binary}}$,它等同于 ${6_{\ decimal}}$。 由于 6 小于 12,因此该过程完成。

量子随机数生成器返回数字 6。

创建完整的随机数生成器

在这里,你将展开 Main.qs 文件以生成更大的随机数。

导入所需的库

首先,需要将所需的命名空间从 Q# 标准库导入到程序。 Q# 编译器会自动加载许多常见函数和操作,但对于完整的量子随机数生成器,需要使用两个 Q# 命名空间中的一些其他函数和操作:Microsoft.Quantum.MathMicrosoft.Quantum.Convert

将以下 import 指令复制并粘贴到 Main.qs 文件顶部:

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

Main 操作重命名为 GenerateRandomBit

对于完整的随机数生成器,你将重用在上一单元中定义的操作。 但操作名称 Main 是程序的入口点,并且应该是唯一的。 要避免混淆,需要将 Main 操作重命名为 GenerateRandomBit

GenerateRandomBit 操作现在应如下所示:

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

定义量子随机数运算

在此处,你将定义 GenerateRandomNumberInRange 操作。 此操作重复调用 GenerateRandomBit 操作以生成位字符串。

复制以下代码并将其粘贴到 Main.qs 文件中 GenerateRandomBit 操作的前面:

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

让我们花点时间回顾一下新代码。

  • 你需要计算表示最大为 max 的整数所需的位数。 Microsoft.Quantum.Math 库中的 BitSizeI 函数将整数转换为表示该整数所需的位数。
  • GenerateRandomNumberInRange 操作使用 for 循环来生成随机数,直到生成的数字等于或小于 max 为止。 for 循环的工作方式与其他编程语言中的 for 循环完全相同。
  • 变量 bits 是可变变量。 可变变量是计算过程中可以更改的变量。 使用 set 指令可以更改可变变量的值。
  • ResultArrayAsInt 函数来自 Microsoft.Quantum.Convert 库。 此函数将位字符串转换为正整数。

添加入口点

最后,向程序添加入口点。 默认情况下,无论 Main 操作位于何处,Q# 编译器都会查找它并在该处开始处理。 该 Main 操作会调用 GenerateRandomNumberInRange 操作以生成介于 0 和数字 max 之间的随机数。 在此示例中,你将最大值定义为 100。

将以下代码复制并粘贴到 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);
}

最终程序

Main.qs 文件应如下所示:

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

运行程序

让我们尝试使用新的随机数生成器!

  1. 在运行程序之前,需要将目标配置文件设置为“不受限制”。 选择“视图”>“命令面板”,搜索 QIR,然后选择“Q#:设置 Azure Quantum QIR 目标配置文件”,然后选择“Q#: 不受限制”
  2. 要运行程序,请从 Main 操作上方的命令列表中选择“运行”,或按 Ctrl+F5。 输出会显示在调试控制台中。
  3. 再次运行程序以查看不同的结果。

注意

如果未将目标配置文件设置为“不受限制”,则运行程序时会出现错误。

祝贺你! 现在,你已了解如何结合使用传统逻辑和 Q# 来创建量子随机数生成器。

额外练习

尝试修改程序,同时要求生成的随机数还需要大于某个最小数 min 而不是 0。