Отладка и проверка квантового кода
Возможность проверить, что квантовая программа работает должным образом, и диагностировать ее в случае некорректного поведения очень важна, как и в классическом программировании. В этой статье рассматриваются средства, предлагаемые Azure Quantum Development Kit для тестирования и отладки квантовых программ.
Q# Отладка программы
Расширение Visual Studio Code Azure Quantum Development Kit (QDK) включает отладчик для Q# программ. Вы можете задать точки останова, выполнить шаги по коду и в каждую функцию или операцию, а также отслеживать не только локальные переменные, но и квантовое состояние кубитов.
Примечание.
Отладчик VS Code работает только с файлами (QS) и не работает с Q# 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;
}
- Задайте точку останова в строке
H(qubit)
, щелкнув слева от номера строки. - Щелкните значок отладчика, чтобы открыть панель отладчика и выбрать команду "Запуск и отладка". Элементы управления отладчиком отображаются в верхней части экрана.
- Выберите F5, чтобы начать отладку и перейти к точке останова. В области переменных отладчика разверните категорию "Квантовое состояние". Вы можете увидеть, что кубит инициализирован в состоянии |0> .
- Шаг в (F11)
H
операции и исходный код дляH
операции. По мере выполнения операции обратите внимание, что квантовое значение изменяется, так какH
операция помещает кубита в суперпозицию. - По мере шага операции (F10)
M
квантовое значение разрешается в |0> или |1> в результате измерения, а значение классической переменнойresult
отображается. - По мере выполнения
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 KitDumpMachine()
функция теперь использует упорядочение больших элементов для выходных данных.
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)]]
Дополнительные примеры операций тестирования, которые используются dump_operation()
, можно найти на странице "Операции тестирования примеров" в QDK.