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

如何调试和测试量子代码

与经典编程一样,能够检查量子程序是否按预期方式运行,并且能够诊断不正确的行为是至关重要的。 本文讨论 Azure Quantum Development Kit 提供用于测试和调试量子程序的工具。

Q#调试程序

Azure Quantum Development Kit (QDK) Visual Studio Code 扩展包括程序 Q# 调试器。 可以设置断点、单步执行代码并进入每个函数或操作,不仅跟踪局部变量,还可以跟踪量子比特的量子态。

注意

VS Code 调试器仅适用于 Q# (.qs) 文件,不适用于 Q# Jupyter Notebook 中的单元格。 若要测试 Jupyter Notebook 单元格,请参阅 测试代码

以下示例演示调试器的基本功能。 有关使用 VS Code 调试器的完整信息,请参阅 “调试”。

在 VS Code 中,使用以下代码创建并保存新的 .qs 文件:

import Microsoft.Quantum.Arrays.*;
import Microsoft.Quantum.Convert.*;

operation Main() : Result {
    use qubit = Qubit();
    H(qubit);
    let result = M(qubit);
    Reset(qubit);
    return result;
}
  1. 通过单击行号左侧的行设置断点 H(qubit)
  2. 选择调试器图标以打开调试器窗格,然后选择“运行”和“ 调试”。 调试器控件显示在屏幕顶部。
  3. 选择 F5 以开始调试并继续到断点。 在调试器 “变量 ”窗格中,展开 “量子状态 ”类别。 可以看到量子比特已初始化为 |0> 状态。
  4. 单步执行操作并显示操作的源代码H( F11H)。 在逐步执行操作时,请注意,当操作将量子位置于叠加状态时 H ,量子值会发生变化。
  5. 执行操作时(F10) M 将量子值解析为 |0> 或 |1> ,并显示经典变量 result 的值。
  6. 单步执行 Reset 操作时,量子位将重置为 |0>。

测试代码

尽管 VS Code Q# 调试器不适用于 Q# Jupyter Notebook 中的单元格,但 Azure QDK 提供了一些表达式和函数,可帮助对代码进行故障排除。

Fail 表达式

表达式 fail 完全结束计算,这与停止程序的致命错误相对应。

请考虑验证参数值的简单示例:

# import qsharp package to access the %%qsharp magic command
import qsharp 
// use the %%qsharp magic command to change the cell type from Python to Q#
%%qsharp 
function PositivityFact(value : Int) : Unit {
    if value <= 0 {
        fail $"{value} isn't a positive number.";
    }   
}
PositivityFact(0);
Error: program failed: 0 isn't a positive number.
Call stack:
    at PositivityFact in line_2
Qsc.Eval.UserFail

  × runtime error
  ╰─▶ program failed: 0 isn't a positive number.
   ╭─[line_2:5:1]
 5 │ 
 6 │             fail $"{value} isn't a positive number.";
   ·             ────────────────────┬───────────────────
   ·                                 ╰── explicit fail
 7 │     }   
   ╰────

在这里,表达式 fail 阻止程序继续运行无效数据。

Fact() 函数

可以使用命名空间中的Fact()Microsoft.Quantum.Diagnostics函数实现与上一示例相同的行为。 该 Fact() 函数计算给定的经典条件,如果为 false,则会引发异常。

import qsharp 
%%qsharp
function PositivityFact(value : Int) : Unit {
    Fact(value > 0, "Expected a positive number."); 
}
PositivityFact(4);
Error: program failed: Expected a positive number.
Call stack:
    at Microsoft.Quantum.Diagnostics.Fact in diagnostics.qs
    at PositivityFact in line_4
Qsc.Eval.UserFail

  × runtime error
  ╰─▶ program failed: Expected a positive number.
    ╭─[diagnostics.qs:29:1]
 29 │         if (not actual) {
 30 │             fail message;
    ·             ──────┬─────
    ·                   ╰── explicit fail
 31 │         }
    ╰────

DumpMachine() 函数

DumpMachine() 是一个 Q# 函数,可用于将有关计算机当前状态 target 的信息转储到控制台并继续运行程序。

注意

随着 Azure Quantum Development Kit的发布,该 DumpMachine() 函数现在对其输出使用 big-endian 排序。

import qsharp
%%qsharp
import Microsoft.Quantum.Diagnostics.*;
operation MultiQubitDumpMachineDemo() : Unit {
    use qubits = Qubit[2];
    X(qubits[1]);
    H(qubits[1]);
    DumpMachine();

    R1Frac(1, 2, qubits[0]);
    R1Frac(1, 3, qubits[1]);
    DumpMachine();
    
    ResetAll(qubits);
}
MultiQubitDumpMachineDemo();
Basis State
(|𝜓₁…𝜓ₙ⟩)	Amplitude	Measurement Probability	Phase
|00⟩	0.7071+0.0000𝑖	 50.0000%	↑	0.0000
|01⟩	−0.7071+0.0000𝑖	 50.0000%	↓	-3.1416

Basis State
(|𝜓₁…𝜓ₙ⟩)	Amplitude	Measurement Probability	Phase
|00⟩	0.7071+0.0000𝑖	 50.0000%	↑	0.0000
|01⟩	−0.6533−0.2706𝑖	 50.0000%	↙	-2.7489   

dump_machine() 函数

dump_machine 是一个 Python 函数,它返回当前分配的量子比特计数和可分析的稀疏状态振幅的 Python 字典。 使用 Jupyter Notebook 中的任一函数,可以像调试器一样逐步执行操作。 使用前面的示例程序:

import qsharp 
%%qsharp
use qubits = Qubit[2];
X(qubits[0]);
H(qubits[1]);
dump = qsharp.dump_machine()
dump

Basis State
(|𝜓₁…𝜓ₙ⟩)	Amplitude	Measurement Probability	Phase
|10⟩	0.7071+0.0000𝑖	 50.0000%	↑	0.0000
|11⟩	0.7071+0.0000𝑖	 50.0000%	↑	0.0000
%%qsharp
R1Frac(1, 2, qubits[0]);
R1Frac(1, 3, qubits[1]);
dump = qsharp.dump_machine()
dump
Basis State
(|𝜓₁…𝜓ₙ⟩)	Amplitude	Measurement Probability	Phase
|10⟩	0.5000+0.5000𝑖	 50.0000%	↗	0.7854
|11⟩	0.2706+0.6533𝑖	 50.0000%	↗	1.1781    
# you can print an abbreviated version of the values
print(dump)
STATE:
|10⟩: 0.5000+0.5000𝑖
|11⟩: 0.2706+0.6533𝑖
# you can access the current qubit count
dump.qubit_count
2
# you can access individual states by their index
dump[2]
(0.5+0.5000000000000001j)
dump[3]
(0.27059805007309845+0.6532814824381883j)

CheckZero() 和 CheckAllZero() 操作

CheckZero()以及CheckAllZero()Q#可以检查量子比特或量子比特数组的当前状态是 $\ket{0}$的操作。 CheckZero()true如果量子比特处于 $\ket{0}$ 状态,并且它处于任何其他状态,则false返回。 CheckAllZero() 如果 true 数组中的所有量子比特都处于 $\ket{0}$ 状态,并且 false 量子比特处于任何其他状态,则返回。

import Microsoft.Quantum.Diagnostics.*;

operation Main() : Unit {
    use qs = Qubit[2];
    X(qs[0]); 
    if CheckZero(qs[0]) {
        Message("X operation failed");
    }
    else {
        Message("X operation succeeded");
    }
    ResetAll(qs);
    if CheckAllZero(qs) {
        Message("Reset operation succeeded");
    }
    else {
        Message("Reset operation failed");
    }
}

dump_operation() 函数

dump_operation 是一个 Python 函数,它采用操作或操作定义,以及要使用的多个量子位,并返回表示操作输出的复数的平方矩阵。

qsharp.utils中导入 dump_operation

import qsharp
from qsharp.utils import dump_operation

此示例打印单量子比特标识门和 Hadamard 门的矩阵。

res = dump_operation("qs => ()", 1)
print(res)
res = dump_operation("qs => H(qs[0])", 1)
print(res)
[[(1+0j), 0j], [0j, (1+0j)]]
[[(0.707107+0j), (0.707107+0j)], [(0.707107+0j), (-0.707107-0j)]]

还可以使用 qsharp.eval() 定义函数或操作,然后从中 dump_operation引用它。 前面表示的单个量子比特也可以表示为

qsharp.eval("operation SingleQ(qs : Qubit[]) : Unit { }")

res = dump_operation("SingleQ", 1)
print(res)
[[(1+0j), 0j], [0j, (1+0j)]]

此示例使用 Controlled Ry 门将旋转应用到第二个量子位

qsharp.eval ("operation ControlRy(qs : Qubit[]) : Unit {qs[0]; Controlled Ry([qs[0]], (0.5, qs[1]));}")

res = dump_operation("ControlRy", 2)
print(res)
[[(1+0j), 0j, 0j, 0j], [0j, (1+0j), 0j, 0j], [0j, 0j, (0.968912+0j), (-0.247404+0j)], [0j, 0j, (0.247404+0j), (0.968912+0j)]]

以下代码定义 Q# 操作 ApplySWAP ,并输出其矩阵以及双量子比特标识操作的矩阵。

qsharp.eval("operation ApplySWAP(qs : Qubit[]) : Unit is Ctl + Adj { SWAP(qs[0], qs[1]); }")

res = dump_operation("qs => ()", 2)
print(res)
res = dump_operation("ApplySWAP", 2)
print(res)
[[(1+0j), 0j, 0j, 0j], [0j, (1+0j), 0j, 0j], [0j, 0j, (1+0j), 0j], [0j, 0j, 0j, (1+0j)]]
[[(1+0j), 0j, 0j, 0j], [0j, 0j, (1+0j), 0j], [0j, (1+0j), 0j, 0j], [0j, 0j, 0j, (1+0j)]]

可以在 QDK 中的“测试操作”示例页中找到更多使用dump_operation()测试操作的示例。