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

已完成

在本单元中,你将实现量子随机数生成器的第二部分。 将多个随机位组合在一起,形成更大的随机数。 此部分基于在上一单元中创建的随机位生成器。

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

在上一单元中,你创建了一个随机位生成器,该生成器将量子比特置于叠加状态,然后测量该量子比特以生成 0 或 1 的随机位值,每个随机位值具有 50% 概率。 此位的值确实是随机的,无法提前知道测量结果是什么。 但如何才能通过这种行为生成更大的随机数?

如果重复此过程四次,则可能会生成以下二进制数字序列:

$${0、1、1、0}$$

如果将这些位拼接成一个位字符串,则可以形成一个更大的数字。 在此示例中,二进制中的位序列 ${0110}$ 等效于十进制数字 6。

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

若要生成任意较大的随机数,只需多次重复此过程。 然后,将所有位合并为二进制数,并将该二进制数转换为十进制数。

定义随机数生成器逻辑

在编写 Q# 代码之前,让我们概述生成随机数的逻辑:

  1. max 定义为您想要生成的最大十进制数。
  2. 确定生成max所需的随机位数nBits
  3. 生成长度为 nBits 的随机位字符串。
  4. 如果位字符串表示大于 max的数字,则返回上一步。
  5. 否则,此过程完成。 将生成的数字作为小数整数返回。

例如,定义 max 为 12。 也就是说,12 是随机数生成器应输出的最大数。

使用以下公式确定表示二进制数字 12 所需的位数:

$${\lfloor ln(12) / ln(2) + 1 \rfloor}$$

根据此公式,需要 4 位来表示介于 0 和 12 之间的数字。

例如,假设你生成一个随机比特四次,并得到比特字符串 ${1101_{\ binary}}$。 二进制中的此值等于十进制中的 13。 由于 13 大于 12,因此将复该过程。

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

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

在 Q 中创建完整的随机数生成器#

在这里,展开上一课中的 Main.qs 文件以生成随机数生成器。

导入所需的库

首先,从 Q# 标准库导入命名空间,其中包含编写程序所需的函数和作。 Q# 编译器会自动加载许多常见函数和作。 但对于量子随机数生成器,需要两个 Q# 命名空间中的一些附加函数和作: Microsoft.Quantum.Math 以及 Microsoft.Quantum.Convert

将以下import指令复制并粘贴到Main.qs文件的开头:

import Std.Convert.*;
import Std.Math.*;

注意

可以使用 Std 替代 Microsoft.Quantum 从标准库导入函数和作。

Main 操作重命名为 GenerateRandomBit

随机数生成器程序使用你在上一单元中编写的Main操作来生成一个随机位。 将Main重命名为GenerateRandomBit,以便此操作具有更描述性的名称,且不是程序的入口。

将以下代码复制并粘贴到 Main.qs

import Std.Convert.*;
import Std.Math.*;

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's within the requested range.
    // Generate it again if it's outside the range.
    return sample > max ? GenerateRandomNumberInRange(max) | sample;
}

这是 GenerateRandomNumberInRange 代码的概述:

  • 调用Std.Math库中的BitSizeI函数来计算表示存储在max中的整数所需的位数。
  • 使用 for 循环生成一定数量的随机位,这相当于 nBits。 调用 GenerateRandomBit 操作以生成随机位。
  • for 循环内,使用 set 语句,通过每个新的随机位来更新 bits 变量。 该变量 bits 是可变变量,这意味着计算过程中可以更改的值 bits
  • 调用ResultArrayAsInt函数从Std.Convert库中将bits的位数组转换为存储在sample中的正整数。
  • 在语句中 return ,检查是否 sample 大于 max。 如果 sample 大于 max,则再次调用 GenerateRandomNumberInRange 并重新开始。 否则,返回存储在sample中的随机数。

添加入口点

最后,向代码添加一个入口点操作,以便编译器可以运行您的程序。 默认情况下,Q# 编译器会查找 Main 操作,并将 Main 用作入口点,无论 Main 在文件中的位置。 在这里,Main 操作为 max 设置一个值,并调用 GenerateRandomNumberInRange 操作以生成介于 0 和 max 之间的随机数。

例如,若要生成介于 0 到 100 之间的随机数,请将以下代码复制到 Main.qs 文件中:

operation Main() : Int {
    let max = 100;
    Message($"Generating a random number between 0 and {max}: ");

    // Generate random number in the 0..max range.
    return GenerateRandomNumberInRange(max);
}

最终程序

以下是程序的完整 Q# 代码:Main.qs

import Std.Convert.*;
import Std.Math.*;

operation Main() : Int {
    let max = 100;
    Message($"Generating 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's within the requested range.
    // Generate it again if it's 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;
}

运行程序

试用新的量子随机数生成器!

若要运行程序,请从 Main 操作上方的命令列表中选择“运行”代码可重用功能区。 或者,按 Ctrl + F5。 输出显示在调试控制台中。 多次运行程序,并注意结果的更改方式。

恭喜! 你在 Q# 中创建了一个真正的随机量子数生成器。

额外练习

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