Поделиться через


Отладка и проверка квантового кода

Возможность проверить, что квантовая программа работает должным образом, и диагностировать ее в случае некорректного поведения очень важна, как и в классическом программировании. В этой статье рассматриваются средства, предлагаемые 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;
}
  1. Задайте точку останова в строке H(qubit) , щелкнув слева от номера строки.
  2. Щелкните значок отладчика, чтобы открыть панель отладчика и выбрать команду "Запуск и отладка". Элементы управления отладчиком отображаются в верхней части экрана.
  3. Выберите F5, чтобы начать отладку и перейти к точке останова. В области переменных отладчика разверните категорию "Квантовое состояние". Вы можете увидеть, что кубит инициализирован в состоянии |0> .
  4. Шаг в (F11) 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()

Вы можете реализовать то же поведение, что и предыдущий пример, используя 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.