如何偵錯及測試量子程序代碼

如同傳統程序設計,請務必能夠檢查量子程式是否如預期般運作,以及能夠診斷不正確的行為。 本文討論 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 與作業的 H 原始碼會顯示 。 當您逐步執行作業時,請注意量子值隨著作業將量子位放入迭加而 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() 函式

您可以使用 命名空間中的 Microsoft.Quantum.Diagnostics 函式,實作與上一個範例Fact()相同的行為。 函 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 函式,以及要使用的數個量子位,並傳回代表作業輸出之複數的平方矩陣。

您從 匯入 dump_operation qsharp.utils

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() 的測試作業範例。