你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

教程:使用 Q# 实现量子随机数生成器

注意

2024 年 6 月 30 日之后将不再支持 Microsoft Quantum Development Kit (经典 QDK) 。 如果你是现有的 QDK 开发人员,我们建议你过渡到新的 Azure Quantum Development Kit (新式 QDK) ,以继续开发量子解决方案。 有关详细信息,请参阅 将 Q# 代码迁移到新式 QDK

了解如何使用 Q# 编写基本的量子程序,该程序利用量子力学的特性来生成随机数。

在本教程中,将:

  • Create程序Q#。
  • 查看程序main组件Q#。
  • 定义问题的逻辑。
  • 结合经典运算和量子运算来解决问题。
  • 使用量子位和叠加来生成量子随机数生成器。

提示

若要加速量子计算之旅,检查 Azure Quantum 代码,这是 Azure Quantum网站的独特功能。 在这里,可以运行内置 Q# 示例或自己的 Q# 程序,从提示生成新 Q# 代码,单击一下即可在 VS Code for the Web 中打开并运行代码,并询问 Copilot 有关量子计算的任何问题。

先决条件

定义问题

经典计算机生成的不是随机数,而是伪随机数。 伪随机数生成器根据某初始值(称为“种子”)生成一个确定的数字序列。 为了更好地估计随机值,此种子通常是 CPU 时钟的当前时间。

另一方面,量子计算机可以生成真正的随机数。 这是因为叠加中量子比特的测量是一个概率过程。 度量的结果是随机的,无法预测结果。 这是量子随机数生成器的基本原理。

量子比特是可以叠加的量子信息单位。 测量时,量子比特的状态只能为 0 或 1。 但在测量前,量子比特的状态表示进行测量时读取值为 0 或 1 的概率。

从处于基态(例如 0)的量子比特入手。 随机数生成器的第一步是使用 Hadamard 运算将量子位置于相等叠加中。 此状态的度量结果为 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 作为密码。 在实际操作中,将较大的数字设置为最大数字,因为较小的数字很容易通过尝试所有可能的密码而被破解。 实际上,为了增加猜测或破解密码的难度,可以使用 ASCII 代码将二进制数转换为文本,并使用数字、符号和混合大小写的字母生成密码。

写入随机位生成器

第一步是编写生成 Q# 随机位的操作。 此操作将是随机数生成器的构建基块之一。

operation GenerateRandomBit() : Result {
    // Allocate a qubit.
    use q = Qubit();

    // Set the qubit into superposition of 0 and 1 using the Hadamard 
    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;
}

现在来看看新代码。

  • 定义 GenerateRandomBit 运算,它不接受输入,并生成 Result 类型的值。 Result 类型表示测量的结果,可能为以下任一值:ZeroOne
  • 使用 关键字 (keyword) 分配单个量子比特use。 分配后,量子比特始终处于 Zero 状态。
  • 使用 H 运算将量子比特置于相等叠加中。
  • 使用 M 运算来测量量子比特, (或 One) Zero 返回测量值。
  • 使用 Reset 运算将量子比特重置为 |0→ 状态。

通过 H 操作将量子比特置于叠加态并通过 M 操作对其进行测量以后,每次调用代码时,结果都会是一个不同值。

Q#使用 Bloch 球体可视化代码

在 Bloch 球中,北极表示经典值 0,南极表示经典值 1。 任何叠加态都可以用球上的某个点来表示(用箭头表示)。 箭头末端越靠近极点,量子位塌缩成经典值(在度量时分配给该极点)的概率越高。 例如,下图中箭头所表示的量子比特状态在你测量它时有较高的概率给出值 0。

显示测量零的概率较高的量子比特状态的关系图。

你可以使用此表示法将代码的功能可视化:

  1. 首先,从初始化为状态 0 的某个量子比特着手,并应用 H 操作来创建一个相等的叠加,其中获得 0 和 1 的概率相同。

    显示通过应用 hadamard 门准备叠加量子比特的关系图。
  2. 然后,测量该量子比特并保存输出:

    显示量子比特测量并保存输出的关系图。

由于测量的结果是随机的,并且测量结果为 0 和 1 的概率相同,因此获得了一个完全随机的位。 可以多次调用此操作来创建整数。 例如,如果调用此操作三次来获取三个随机位,就可以生成随机的 3 位数(即 0 到 7 之间的随机数)。

编写完整的随机数生成器

  1. 首先,需要将所需的 Q# 命名空间添加到程序。 对于完整的随机数生成器,需要包含三 Q# 个命名空间: Microsoft.Quantum.MathMicrosoft.Quantum.IntrinsicMicrosoft.Quantum.Convert

    open Microsoft.Quantum.Convert;
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Math;
    
  2. 接下来,定义 GenerateRandomNumberInRange 操作。 此操作重复调用 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至 的位数。 BitSizeI命名空间中的 Microsoft.Quantum.Math 函数将整数转换为表示整数所需的位数。
    • SampleRandomNumberInRange 操作使用 for 循环来生成随机数,直到生成的数字等于或小于 max 为止。 循环 for 的工作方式与其他编程语言中的循环完全相同 for
    • 变量 bits 是可变变量。 可变变量是计算过程中可以更改的变量。 使用 set 指令可以更改可变变量的值。
    • 函数 ResultArrayAsInt 来自 Microsoft.Quantum.Convert 命名空间。 此函数将位字符串转换为正整数。
  3. 最后,添加入口点。 在此示例中, Main 操作是程序的入口点。 它调用 GenerateRandomNumberInRange 操作以生成介于 0 和 100 之间的随机数。

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

    let 指令声明在计算过程中不更改的变量。 此处,我们将最大值定义为 100。

  4. 随机数生成器的完整代码如下所示:

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

运行随机数生成器程序

可以在 Azure Quantum 的 Copilot 中运行程序,并在 Visual Studio Code 中作为独立Q#应用程序或使用 Python 主机程序运行程序。

可以使用 Azure Quantum 中的 Copilot 免费测试 Q# 代码 - 只需一个 Microsoft (MSA) 电子邮件帐户即可。 有关 Azure Quantum 中的 Copilot 的详细信息,请参阅 探索 Azure Quantum

  1. 在浏览器中 打开 Azure Quantum 中的 Copilot

  2. 将以下代码复制并粘贴到代码编辑器中。

    namespace Tutorial {
        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);
        }
    
        /// # Summary
        /// 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;
        }
    
        /// # Summary
        /// Generates a random bit.
        operation GenerateRandomBit() : Result {
            // Allocate a qubit.
            use q = Qubit();
    
            // Set the qubit into superposition of 0 and 1 using the Hadamard 
            // operation `H`.
            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;
    
            // Note that Qubit `q` is automatically released at the end of the block.
        }
    }
    
  3. 选择要运行的镜头数,然后单击“ 运行”。

  4. 结果显示在直方图和 “结果 ”字段中。

  5. 单击“ 说明代码 ”,提示 Copilot 向你解释代码。

提示

在 Azure Quantum 中的 Copilot 中,可以通过单击代码编辑器右侧的 VS Code 徽标按钮,在 VS Code for the Web 中打开程序。

注意

此代码片段当前未在任何可用的 Azure Quantum 硬件 targets上运行,因为可调用对象 ResultArrayAsInt 需要具有 完整计算配置文件的 QPU。

后续步骤

浏览其他 Q# 教程:

  • 量子纠缠 演示了如何编写一个 Q# 程序来操作和测量量子比特,并演示叠加和纠缠的影响。
  • Grover 的搜索算法 演示如何编写 Q# 使用 Grover 搜索算法的程序。
  • 量子傅立叶变换 探索了如何编写 Q# 直接处理特定量子比特的程序。
  • Quantum Katas 是自定进度教程和编程练习,旨在同时教授量子计算和Q#编程的元素。