练习第 2 部分 - 创建量子随机数生成器
在本单元中,你将实现量子随机数生成器的第二部分。 将多个随机位组合在一起,形成更大的随机数。 此部分基于在上一单元中创建的随机位生成器。
将多个随机位组合成一个较大的数
在上一单元中,你创建了一个随机位生成器,该生成器将量子比特置于叠加状态,然后测量该量子比特以生成 0 或 1 的随机位值,每个随机位值具有 50% 概率。 此位的值确实是随机的,无法提前知道测量结果是什么。 但如何才能通过这种行为生成更大的随机数?
如果重复此过程四次,则可能会生成以下二进制数字序列:
$${0、1、1、0}$$
如果将这些位拼接成一个位字符串,则可以形成一个更大的数字。 在此示例中,二进制中的位序列 ${0110}$ 等效于十进制数字 6。
$${0110_{\ binary} \equiv 6_{\ decimal}}$$
若要生成任意较大的随机数,只需多次重复此过程。 然后,将所有位合并为二进制数,并将该二进制数转换为十进制数。
定义随机数生成器逻辑
在编写 Q# 代码之前,让我们概述生成随机数的逻辑:
- 将
max定义为您想要生成的最大十进制数。 - 确定生成
max所需的随机位数nBits。 - 生成长度为
nBits的随机位字符串。 - 如果位字符串表示大于
max的数字,则返回上一步。 - 否则,此过程完成。 将生成的数字作为小数整数返回。
例如,定义 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。