Q# 的量子基础知识Quantum basics with Q#

在本快速入门中,我们演示如何编写一个 Q# 程序,用于操作和度量量子位并演示叠加和纠缠效果。In this Quickstart, we show you how to write a Q# program that manipulates and measures qubits and demonstrates the effects of superposition and entanglement. 我们可以据此安装 QDK、生成程序并在量子模拟器上执行该程序。This guides you on installing the QDK, building the program and executing that program on a quantum simulator.

我们将编写一个用于演示量子纠缠的名为 Bell 的应用程序。You will write an application called Bell to demonstrate quantum entanglement. Bell 这一名称是指 Bell 状态,即两个量子位的特定量子状态,用于表示叠加和量子纠缠的最简单示例。The name Bell is in reference to Bell states, which are specific quantum states of two qubits that are used to represent the simplest examples of superposition and quantum entanglement.

先决条件Pre-requisites

如果准备开始编码,请在继续之前按照以下步骤操作:If you are ready to start coding, follow these steps before proceeding:

  • 使用首选语言和开发环境安装 Quantum 开发工具包Install the Quantum Development Kit using your preferred language and development environment
  • 如果已安装 QDK,请确保将其更新至最新版本If you already have the QDK installed, make sure you have updated to the latest version

也可以阅读说明而不安装 QDK,查看 Q# 编程语言的概述和基本的量子计算概念。You can also follow along with the narrative without installing the QDK, reviewing the overviews of the Q# programming language and the first concepts of quantum computing.

使用 Q# 演示量子位行为Demonstrating qubit behavior with Q#

回想一下简单的量子位定义Recall our simple definition of a qubit. 经典位保存单个二进制值(如 0 或 1),而量子位的状态则可以是 0 和 1 的同时叠加Where classical bits hold a single binary value such as a 0 or 1, the state of a qubit can be in a superposition of 0 and 1 simultaneously. 从概念上讲,可以将量子位视为空间中的方向(也称为矢量)。Conceptually, a qubit can be thought of as a direction in space (also known as a vector). 量子位可以是任何可能的方向。A qubit can be in any of the possible directions. 两个经典状态是两个方向,一个方向表示度量结果为 0 的可能性为 100%,另一个方向表示度量结果为 1 的可能性为 100%。The two classical states are the two directions; representing 100% chance of measuring 0 and 100% chance of measuring 1. 这种表示方式也可通过 Bloch 球更正式地可视化。This representation is also more formally visualized by the bloch sphere.

度量行为会生成二进制结果并改变量子位状态。The act of measurement produces a binary result and changes a qubit state. 度量会生成一个二进制值(0 或 1)。Measurement produces a binary value, either 0 or 1. 量子位从叠加态(任何方向)变为经典状态之一。The qubit goes from being in superposition (any direction) to one of the classical states. 随后,在没有任何干预操作的情况下重复进行相同的度量会生成相同的二进制结果。Thereafter, repeating the same measurement without any intervening operations produces the same binary result.

多个量子位可以“纠缠”在一起。 Multiple qubits can be entangled. 度量一个纠缠的量子位时,就会知道另一个量子位的状态。When we make a measurement of one entangled qubit, our knowledge of the state of the other(s) is updated as well.

现在,我们可以演示如何通过 Q# 来表达这种行为了。Now, we're ready to demonstrate how Q# expresses this behavior. 一开始可以编写并生成一个最简单的程序,用于演示量子叠加和量子纠缠。You start with the simplest program possible and build it up to demonstrate quantum superposition and quantum entanglement.

设置Setup

使用 Microsoft Quantum 开发工具包开发的应用程序由两个部分组成:Applications developed with Microsoft's Quantum Development Kit consist of two parts:

  1. 使用 Q# 量子编程语言实现的一个或多个量子算法。One or more quantum algorithms, implemented using the Q# quantum programming language.
  2. 使用 C# 或 Python 等编程语言实现且充当主入口点并调用 Q# 运算来执行量子算法的主机程序。A host program, implemented in a programming language like Python or C# that serves as the main entry point and invokes Q# operations to execute a quantum algorithm.
  1. 为应用程序选择一个位置Choose a location for your application

  2. 创建名为 Bell.qs 的文件。Create a file called Bell.qs. 此文件将包含你的 Q# 代码。This file will contain your Q# code.

  3. 创建名为 host.py 的文件。Create a file called host.py. 此文件将包含你的 Python 主机代码。This file will contain your Python host code.

编写 Q# 运算Write a Q# operation

我们的目标是准备两个处于特定量子状态的量子位,演示如何通过 Q# 操作量子位,以便更改其状态并演示叠加和纠缠效果。Our goal is to prepare two qubits in a specific quantum state, demonstrating how to operate on qubits with Q# to change their state and demonstrate the effects of superposition and entanglement. 我们将逐步完成这一切,以演示量子位状态、操作和度量。We will build this up piece by piece to demonstrate qubit states, operations, and measurement.

概述: 在下面的第一个代码中,我们演示如何在 Q# 中操作量子位。Overview: In the first code below, we show you how to work with qubits in Q#. 我们将引入两个操作(MX)来转换量子位的状态。We’ll introduce two operations, M and X that transform the state of a qubit.

在此代码片段中,我们定义了操作 Set。该操作使用一个量子位作为参数,使用另一个参数 (desired) 来表示我们希望该量子位呈现的状态。In this code snippet, an operation Set is defined that takes as a parameter a qubit and another parameter, desired, representing the state that we would like the qubit to be in. 操作 Set 使用操作 M 对量子位进行度量。The operation Set performs a measurement on the qubit using the operation M. 在 Q# 中,量子位的度量始终返回 ZeroOneIn Q#, a qubit measurement always returns either Zero or One. 如果度量返回的值不等于所需的值,Set 会“翻转”该量子位;也就是说,它会执行 X 操作,将量子位状态变为新状态,使度量时返回 ZeroOne 的概率反转。If the measurement returns a value not equal to a desired value, Set “flips” the qubit; that is, it executes an X operation, which changes the qubit state to a new state in which the probabilities of a measurement returning Zero and One are reversed. 为了演示 Set 操作的效果,我们接着添加了 TestBellState 操作。To demonstrate the effect of the Set operation, a TestBellState operation is then added. 此操作以 ZeroOne 作为输入,使用该输入调用 Set 操作特定的次数,然后计算对量子位进行度量时返回 Zero 的次数和返回 One 的次数。This operation takes as input a Zero or One, and calls the Set operation some number of times with that input, and counts the number of times that Zero was returned from the measurement of the qubit and the number of times that One was returned. 当然,在第一次对 TestBellState 操作进行这样的模拟时,我们预期输出会表明:在将 Zero 作为参数输入的情况下,对量子位集进行的所有度量都会返回 Zero;在将 One 作为参数输入的情况下,对量子位集进行的所有度量都会返回 OneOf course, in this first simulation of the TestBellState operation, we expect that the output will show that all measurements of the qubit set with Zero as the parameter input will return Zero, and all measurements of a qubit set with One as the parameter input will return One. 接下来,我们会向 TestBellState 添加代码,演示叠加和纠缠。Further on, we’ll add code to TestBellState to demonstrating superposition and entanglement.

Q# 运算代码Q# operation code

  1. 将 Bell.qs 文件的内容替换为以下代码:Replace the contents of the Bell.qs file with the following code:

    namespace Quantum.Bell {
        open Microsoft.Quantum.Intrinsic;
        open Microsoft.Quantum.Canon;
    
        operation Set(desired : Result, q1 : Qubit) : Unit {
            if (desired != M(q1)) {
                X(q1);
            }
        }
    }
    

    现在可以调用此操作,将量子位设置为经典状态:100% 的情况下返回 Zero,或者 100% 的情况下返回 OneThis operation may now be called to set a qubit to a classical state, either returning Zero 100% of the time or returning One 100% of the time. ZeroOne 为常量,表示对量子位进行度量时仅有的两个可能结果。Zero and One are constants that represent the only two possible results of a measurement of a qubit.

    操作 Set 用于度量量子位。The operation Set measures the qubit. 如果量子位处于所需状态,Set 会将其保留,否则会执行 X 操作,将量子位状态更改为所需状态。If the qubit is in the state we want, Set leaves it alone; otherwise, by executing the X operation, we change the qubit state to the desired state.

关于 Q# 运算About Q# operations

Q# 操作是量子子例程。A Q# operation is a quantum subroutine. 也就是说,它是一个包含量子操作的可调用例程。That is, it is a callable routine that contains quantum operations.

运算的参数在括号内指定为元组。The arguments to an operation are specified as a tuple, within parentheses.

运算的返回类型在冒号之后指定。The return type of the operation is specified after a colon. 根据这个规则,Set 运算表示没有返回类型,因此将标记为返回 UnitIn this case, the Set operation has no return, so it is marked as returning Unit. 此 Q# 运算等效于 F# 中的 unit,大致类似于 C# 中的 void 和 Python 中的空元组 (Tuple[()])。This is the Q# equivalent of unit in F#, which is roughly analogous to void in C#, and an empty tuple (Tuple[()]) in Python.

在第一个 Q# 操作中,我们已经使用了两个量子操作:You have used two quantum operations in your first Q# operation:

  • M 操作,用于度量量子位的状态The M operation, which measures the state of the qubit
  • X 操作,用于翻转量子位的状态The X operation, which flips the state of a qubit

量子操作可转换量子位的状态。A quantum operation transforms the state of a qubit. 有时候,人们在讨论时会使用与经典“逻辑门”类似的“量子门”(而不是“量子操作”)这一术语。Sometime people talk about quantum gates instead of operations, in analogy to classical logic gates. 这种习惯根源于早期的量子计算时代。那时候,算法只是一种理论构造,以图形(类似于经典计算中的线路图)方式表示。This is rooted in the early days of quantum computing when algorithms were merely a theoretical construct and visualized as diagrams similarly to circuit diagrams in classical computing.

添加 Q# 测试代码Add Q# test code

  1. Set 运算结束后,在命名空间内将以下运算添加到 Bell.qs 文件:Add the following operation to the Bell.qs file, inside the namespace, after the end of the Set operation:

    operation TestBellState(count : Int, initial : Result) : (Int, Int) {
    
        mutable numOnes = 0;
        using (qubit = Qubit()) {
    
            for (test in 1..count) {
                Set(initial, qubit);
                let res = M(qubit);
    
                // Count the number of ones we saw:
                if (res == One) {
                    set numOnes += 1;
                }
            }
            Set(Zero, qubit);
        }
    
        // Return number of times we saw a |0> and number of times we saw a |1>
        return (count-numOnes, numOnes);
    }
    

    此运算 (TestBellState) 将循环执行 count 迭代,在量子位上设置指定的 initial 值,然后对结果进行度量 (M)。This operation (TestBellState) will loop for count iterations, set a specified initial value on a qubit and then measure (M) the result. 它将收集我们所度量的 0 和 1 的个数统计信息,并将其返回给调用方。It will gather statistics on how many zeros and ones we've measured and return them to the caller. 它执行另一个必需的运算。It performs one other necessary operation. 它将量子位重置为已知状态 (Zero),然后将其返回,使其他人可以在已知状态下分配此量子位。It resets the qubit to a known state (Zero) before returning it allowing others to allocate this qubit in a known state. 这是 using 语句所必需的。This is required by the using statement.

关于 Q# 中的变量About variables in Q#

默认情况下,Q# 中的变量是不可变的;它们的值在绑定后将不能更改。By default, variables in Q# are immutable; their value may not be changed after they are bound. let 关键字用于指示不可变变量的绑定。The let keyword is used to indicate the binding of an immutable variable. 运算参数始终是不可变的。Operation arguments are always immutable.

如果需要可以更改值的变量(如示例中的 numOnes),可以使用 mutable 关键字声明该变量。If you need a variable whose value can change, such as numOnes in the example, you can declare the variable with the mutable keyword. 使用 set 语句可以更改可变变量的值。A mutable variable's value may be changed using a set statement.

在这两种情况下,编译器都会推断变量的类型。In both cases, the type of a variable is inferred by the compiler. Q# 不需要为变量提供任何类型批注。Q# doesn't require any type annotations for variables.

关于 Q# 中的 using 语句About using statements in Q#

Q# 中的 using 语句也很特殊。The using statement is also special to Q#. 它用于分配要在代码块中使用的量子位。It is used to allocate qubits for use in a block of code. 在 Q# 中,所有量子位都是动态分配和释放的,而不是在复杂算法的整个生命周期内都存在的固定资源。In Q#, all qubits are dynamically allocated and released, rather than being fixed resources that are there for the entire lifetime of a complex algorithm. using 语句在代码块的开头分配一组量子位,并在代码块的末尾释放这些量子位。A using statement allocates a set of qubits at the start, and releases those qubits at the end of the block.

创建主机应用程序代码Create the host application code

  1. 打开 host.py 文件,并添加以下代码:Open the host.py file and add the following code:

    import qsharp
    
    from qsharp import Result
    from Quantum.Bell import TestBellState
    
    initials = (Result.Zero, Result.One)
    
    for i in initials:
      res = TestBellState.simulate(count=1000, initial=i)
      (num_zeros, num_ones) = res
      print(f'Init:{i: <4} 0s={num_zeros: <4} 1s={num_ones: <4}')
    

关于主机应用程序代码About the host application code

Python 主机应用程序包含三个部分:The Python host application has three parts:

  • 计算量子算法所需的任何参数。Compute any arguments required for the quantum algorithm. 在示例中,count 固定为 1000,initial 是量子位的初始值。In the example, count is fixed at a 1000 and initial is the initial value of the qubit.
  • 通过调用所导入 Q# 运算的 simulate() 方法来运行量子算法。Run the quantum algorithm by calling the simulate() method of the imported Q# operation.
  • 处理运算结果。Process the result of the operation. 在示例中,res 接收运算的结果。In the example, res receives the result of the operation. 此结果是模拟器所度量 0 的个数 (num_zeros) 和 1 的个数 (num_ones) 的元组。Here the result is a tuple of the number of zeros (num_zeros) and number of ones (num_ones) measured by the simulator. 我们通过析构元组来获取两个字段,然后打印结果。We deconstruct the tuple to get the two fields, and print the results.

生成并运行Build and run

  1. 在终端运行以下命令:Run the following command at your terminal:

    python host.py
    

    此命令将运行模拟 Q# 运算的主机应用程序。This command runs the host application, which simulates the Q# operation.

结果应为:The results should be:

Init:0    0s=1000 1s=0   
Init:1    0s=0    1s=1000

准备叠加Prepare superposition

概述 现在,让我们看看 Q# 如何表达将量子位置于叠加态的方式。Overview Now let’s look at how Q# expresses ways to put qubits in superposition. 回想一下,量子位的状态可以是 0 和 1 的叠加。Recall that the state of a qubit can be in a superposition of 0 and 1. 为了实现这种叠加,我们将使用 Hadamard 操作。We’ll use the Hadamard operation to accomplish this. 如果量子位处于任一经典状态(度量始终返回 Zero 或始终返回 One),则 Hadamard(简称 H)操作会将量子位置于这样一种状态:对量子位进行度量时,50% 的情况下会返回 Zero,50% 的情况下会返回 OneIf the qubit is in either of the classical states (where a measurement returns Zero always or One always), then the Hadamard or H operation will put the qubit in a state where a measurement of the qubit will return Zero 50% of the time and return One 50% of the time. 从概念上讲,可以将此量子位视为介于 ZeroOne 之间的一种中间状态。Conceputually, the qubit can be thought of as halfway between the Zero and One. 现在,我们在模拟 TestBellState 操作时会看到度量后的结果会大致返回相等数量的 ZeroOneNow, when we simulate the TestBellState operation, we will see the results will return roughly an equal number of Zero and One after measurement.

首先,我们来尝试翻转量子位(如果量子位为 Zero 状态,则会翻转为 One,反之亦然)。First we'll just try to flip the qubit (if the qubit is in Zero state will flip to One and vice versa). 操作步骤:先执行 X 操作,然后在 TestBellState 操作中度量它:This is accomplished by performing an X operation before we measure it in TestBellState:

X(qubit);
let res = M(qubit);

现在结果将翻转(按下 F5 后):Now the results (after pressing F5) are reversed:

Init:Zero 0s=0    1s=1000
Init:One  0s=1000 1s=0

但到目前为止,我们所看到的都是经典运算。However, everything we've seen so far is classical. 接下来,我们来获取量子结果。Let's get a quantum result. 我们需要做的就是将上一个运行中的 X 操作替换为 H(全称为 Hadamard)操作。All we need to do is replace the X operation in the previous run with an H or Hadamard operation. 我们不会将所有量子位都从 0 翻转到 1,而是只翻转一半。Instead of flipping the qubit all the way from 0 to 1, we will only flip it halfway. TestBellState 中的替换行现在如下所示:The replaced lines in TestBellState now look like:

H(qubit);
let res = M(qubit);

现在,结果变得更加有趣:Now the results get more interesting:

Init:Zero 0s=484  1s=516
Init:One  0s=522  1s=478

每次度量状态时,我们都会请求一个经典值,但量子位的 0 和 1 值各占一半,因此从统计学角度而言,我们得到的 0 和 1 各占一半。Every time we measure, we ask for a classical value, but the qubit is halfway between 0 and 1, so we get (statistically) 0 half the time and 1 half the time. 这称为“叠加”,它让我们对量子状态有了一个初步的认识 。This is known as superposition and gives us our first real view into a quantum state.

准备展示纠缠Prepare entanglement

概述: 现在,让我们看看 Q# 如何表达纠缠量子位的方式。Overview: Now let’s look at how Q# expresses ways to entangle qubits. 首先,我们将第一个量子位设置为初始状态,然后使用 H 操作将其置于叠加状态。First, we set the first qubit to the initial state and then use the H operation to put it into superposition. 接着,在度量第一个量子位之前,我们使用一个新的操作(CNOT,代表“可控非”)。Then, before we measure the first qubit, we use a new operation (CNOT), which stands for Controlled-Not. 对两个量子位执行此操作的结果是,在第一个量子位是 One 的情况下翻转第二个量子位。The result of executing this operation on two qubits is to flip the second qubit if the first qubit is One. 现在,这两个量子位纠缠在一起。Now, the two qubits are entangled. 第一个量子位的统计信息没有变化(在度量后,ZeroOne 各一半),但现在当我们度量第二个量子位时,它__始终__与我们第一个量子位的度量值相同。Our statistics for the first qubit haven't changed (50-50 chance of a Zero or a One after measurement), but now when we measure the second qubit, it is always the same as what we measured for the first qubit. CNOT 把这两个量子位纠缠在了一起,因此,不论其中一个发生什么,另一个也会同样发生。Our CNOT has entangled the two qubits, so that whatever happens to one of them, happens to the other. 如果翻转度量值(先翻转第二个量子位,再翻转第一个),会发生相同的情况。If you reversed the measurements (did the second qubit before the first), the same thing would happen. 第一个度量值是随机的,第二个将与第一个同步。The first measurement would be random and the second would be in lock step with whatever was discovered for the first.

我们需要做的第一件事是分配 2 个量子位,而不是在 TestBellState 中分配 1 个量子位:The first thing we'll need to do is allocate 2 qubits instead of one in TestBellState:

using ((q0, q1) = (Qubit(), Qubit())) {

在这种情况下,我们可以先添加一个新操作 (CNOT),再在 TestBellState 中度量 (M):This will allow us to add a new operation (CNOT) before we measure (M) in TestBellState:

Set(initial, q0);
Set(Zero, q1);

H(q0);
CNOT(q0, q1);
let res = M(q0);

我们还添加了另一个 Set 运算,用于初始化第一个量子位,以确保启动时它始终处于 Zero 状态。We've added another Set operation to initialize the first qubit to make sure that it's always in the Zero state when we start.

我们还需要重置第二个量子位,然后再将其释放。We also need to reset the second qubit before releasing it.

Set(Zero, q0);
Set(Zero, q1);

完整的例程现在如下所示:The full routine now looks like this:

    operation TestBellState(count : Int, initial : Result) : (Int, Int) {

        mutable numOnes = 0;
        using ((q0, q1) = (Qubit(), Qubit())) {
            for (test in 1..count) {
                Set (initial, q0);
                Set (Zero, q1);

                H(q0);
                CNOT(q0,q1);
                let res = M(q0);

                // Count the number of ones we saw:
                if (res == One) {
                    set numOnes += 1;
                }
            }
            
            Set(Zero, q0);
            Set(Zero, q1);
        }

        // Return number of times we saw a |0> and number of times we saw a |1>
        return (count-numOnes, numOnes);
    }

如果我们运行这段代码,我们将获得与之前相同的 0 和 1 各占一半的结果。If we run this, we'll get exactly the same 50-50 result we got before. 但是,我们想要知道第二个量子位如何响应所度量的第一个量子位。However, what we're interested in is how the second qubit reacts to the first being measured. 我们将使用 TestBellState 运算的新版本来添加此统计信息:We'll add this statistic with a new version of the TestBellState operation:

    operation TestBellState(count : Int, initial : Result) : (Int, Int, Int) {
        mutable numOnes = 0;
        mutable agree = 0;
        using ((q0, q1) = (Qubit(), Qubit())) {
            for (test in 1..count) {
                Set(initial, q0);
                Set(Zero, q1);

                H(q0);
                CNOT(q0, q1);
                let res = M(q0);

                if (M(q1) == res) {
                    set agree += 1;
                }

                // Count the number of ones we saw:
                if (res == One) {
                    set numOnes += 1;
                }
            }
            
            Set(Zero, q0);
            Set(Zero, q1);
        }

        // Return number of times we saw a |0> and number of times we saw a |1>
        return (count-numOnes, numOnes, agree);
    }

新的返回值 (agree) 会跟踪第一个量子位的度量值与第二个量子位的度量值相同的次数。The new return value (agree) keeps track of every time the measurement from the first qubit matches the measurement of the second qubit. 我们还需要相应地更新主机应用程序:We also have to update the host application accordingly:

import qsharp

from qsharp import Result
from Quantum.Bell import TestBellState

initials = {Result.Zero, Result.One} 

for i in initials:
    res = TestBellState.simulate(count=1000, initial=i)
    (num_zeros, num_ones, agree) = res
    print(f'Init:{i: <4} 0s={num_zeros: <4} 1s={num_ones: <4} agree={agree: <4}')

现在,运行代码,我们将会得到非常惊人的结果:Now when we run, we get something pretty amazing:

Init:Zero 0s=499  1s=501  agree=1000
Init:One  0s=490  1s=510  agree=1000

如概述中所述,第一个量子位的统计信息没有变化(0 和 1 各一半),但现在当我们度量第二个量子位时,它__始终__与我们第一个量子位的度量值相同,因为这两个量子位已纠缠在一起!As stated in the overview, our statistics for the first qubit haven't changed (50-50 chance of a 0 or a 1), but now when we measure the second qubit, it is always the same as what we measured for the first qubit, because they are entangled!

恭喜,你已经编写了第一个量子程序!Congratulations, you've written your first quantum program!

下一步是什么?What's next?

Grover 搜索快速入门介绍了如何生成并运行 Grover 搜索(最常用的量子计算算法之一),并通过一个很好的 Q# 程序示例演示了如何使用量子计算来解决实际问题。The QuickStart Grover’s search shows you how to build and run Grover search, one of the most popular quantum computing algorithms and offers a nice example of a Q# program that can be used to solve real problems with quantum computing.

量子开发工具包入门建议了更多的学习 Q# 和量子编程的方法。Get Started with the Quantum Development Kit recommends more ways to learn Q# and quantum programming.