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


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

Тестирование и отладка являются столь же важными в квантовом программировании, как и в классическом программировании. В этой статье описывается отладка и тестирование квантовых программ с помощью Microsoft Quantum Development Kit QDK в Visual Studio Code (VS Code) и Jupyter Notebook.

Отладка квантового кода

QDK предоставляет несколько средств для отладки кода. При написании Q# или использовании программ OpenQASM в VS Code можно использовать отладчик VS Code для задания точек останова в программах и анализа кода. QDK также предоставляет набор функций дампа, которые можно использовать для получения информации в различных точках в программе.

Использование отладчика VS Code

С расширением QDK в VS Code можно использовать отладчик для пошагового выполнения кода и каждой функции или операции, отслеживания значений локальных переменных и выполнения квантовых состояний кубитов.

В следующем примере показано, как использовать отладчик с Q# программой. Полные сведения об отладчиках VS Code см. на веб-сайте VS Code в разделе Отладка.

  1. В VS Code создайте и сохраните новый .qs файл со следующим кодом:

    import Std.Arrays.*;
    import Std.Convert.*;
    
    operation Main() : Result {
        use qubit = Qubit();
        H(qubit);
        let result = M(qubit);
        Reset(qubit);
        return result;
    }
    
  2. В строке 6 щелкните слева от номера строки, H(qubit)чтобы задать точку останова. Отображается красный круг.

  3. На боковой панели основной панели выберите значок отладчика, чтобы открыть панель отладчика, а затем нажмите кнопку "Выполнить и отладить". Откроется панель управления отладчика.

  4. Нажмите клавишу F5 , чтобы запустить отладчик и перейти к точке останова. В меню "Переменные " области отладчика разверните раскрывающийся список "Квантовое состояние ", чтобы увидеть, что кубит инициализирован в состоянии $\ket{0}$.

  5. Нажмите клавишу F11, чтобы выполнить H операцию. Появится исходный H код для операции. Обратите внимание, что квантовое состояние изменяется на суперпозицию при выполнении H операции.

  6. Нажмите F10, чтобы пропустить M операцию. Обратите внимание, что квантовое состояние разрешается в $\ket{c1}$ или $\ket{c2}$ после измерения. Переменная result указана в разделе "Локальные".

  7. Нажмите F10 клавишу еще раз, чтобы пропустить Reset операцию. Обратите внимание, что квантовое состояние преобразуется обратно в $\ket{0}$.

Завершив изучение отладчика, нажмите клавиши SHIFT+F5 , чтобы выйти из отладчика.

Примечание.

Отладчик VS Code работает только с файлами Q# (.qs) и OpenQASM (.qasm). Не удается использовать отладчик VS Code в Q# ячейках в Jupyter Notebook.

Отладка с помощью функций дампа QDK

QDK предоставляет несколько Q# функций и функций Python, которые сбрасывают сведения о текущем состоянии программы при вызове этих функций. Используйте информацию из этих функций дампа, чтобы проверить, ведет ли себя программа так, как вы ожидаете.

Функция Q#DumpMachine

DumpMachine Q#— это функция, которая позволяет выводить информацию о текущем состоянии системы кубитов в консоль во время выполнения программы. DumpMachine не останавливает или не прерывает программу во время выполнения.

Следующий пример вызывает DumpMachine в двух точках в программе Q# и анализирует полученные результаты.

  1. В VS Code создайте и сохраните новый .qs файл со следующим кодом:

    import Std.Diagnostics.*;
    
    operation Main() : 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);
    }
    
  2. Нажмите клавиши CTRL+SHIFT+Y , чтобы открыть консоль отладки.

  3. Нажмите клавиши CTRL+F5 , чтобы запустить программу. В DumpMachine отображаются следующие выходные данные:

    Basis | Amplitude      | Probability | Phase
    -----------------------------------------------
     |00⟩ |  0.7071+0.0000𝑖 |    50.0000% |   0.0000
     |01⟩ | −0.7071+0.0000𝑖 |    50.0000% |  -3.1416
    
    Basis | Amplitude      | Probability | Phase
    -----------------------------------------------
     |00⟩ |  0.7071+0.0000𝑖 |    50.0000% |   0.0000
     |01⟩ | −0.6533−0.2706𝑖 |    50.0000% |  -2.7489
    

В выходных данных DumpMachine показано, как состояние кубитных систем изменяется после каждого набора ворот.

Примечание.

Выходные данные в формате DumpMachine используют порядок байтов от старшего к младшему.

Функция Python dump_machine

Функция dump_machine — это функция из qsharp пакета Python. Эта функция возвращает текущее выделенное число кубитов и словарь, содержащий разреженные амплитуды состояния системы кубитов.

В следующем примере выполняется та же программа, что и предыдущий DumpMachine пример, но в записной книжке Jupyter вместо .qs файла.

  1. В VS Code нажмите клавиши CTRL+SHIFT+P , чтобы открыть палитру команд.

  2. Введите команду Create: New Jupyter Notebook и нажмите клавишу ВВОД. Откроется новая вкладка Jupyter Notebook.

  3. В первой ячейке скопируйте и запустите следующий код:

    from qdk import qsharp 
    
  4. Создайте новую ячейку кода, а затем скопируйте и запустите следующий Q# код:

    %%qsharp
    
    use qubits = Qubit[2];
    X(qubits[0]);
    H(qubits[1]);
    
  5. Создайте новую ячейку кода. Скопируйте и запустите следующий код Python, чтобы просмотреть состояние кубита в этой точке программы:

    dump = qsharp.dump_machine()
    dump
    

    Функция dump_machine отображает следующие выходные данные:

    Basis State
    (|𝜓₁…𝜓ₙ⟩)  Amplitude       Measurement Probability  Phase
    |10⟩       0.7071+0.0000𝑖   50.0000%                 ↑  0.0000
    |11⟩       0.7071+0.0000𝑖   50.0000%                 ↑  0.0000
    
  6. Создайте новую ячейку кода, а затем скопируйте и запустите следующий Q# код:

    %%qsharp
    
    R1Frac(1, 2, qubits[0]);
    R1Frac(1, 3, qubits[1]);
    
  7. Создайте новую ячейку кода. Скопируйте и запустите следующий код Python, чтобы просмотреть состояние кубита в этой точке программы:

    dump = qsharp.dump_machine()
    dump
    

    Функция dump_machine отображает следующие выходные данные:

    Basis State
    (|𝜓₁…𝜓ₙ⟩)  Amplitude      Measurement Probability  Phase
    |10⟩       0.5000+0.5000𝑖  50.0000%                 ↗  0.7854
    |11⟩       0.2706+0.6533𝑖  50.0000%                 ↗  1.1781
    
  8. Чтобы распечатать сокращенную версию dump_machine выходных данных, создайте новую ячейку и запустите следующий код Python:

    print(dump)
    
  9. Чтобы получить общее количество кубитов в системе, создайте новую ячейку кода и выполните следующий код Python:

    dump.qubit_count
    
  10. Вы можете получить доступ к амплитудам состояний отдельных кубитов, которые имеют ненулевое значение. Например, создайте новую ячейку кода и выполните следующий код Python, чтобы получить отдельные амплитуды для состояний $\ket{10}$ и $\ket{11}$:

    print(dump[2])
    print(dump[3])
    

Функция dump_operation.

Функция dump_operation — это функция из qsharp.utils пакета Python. Эта функция принимает два входных параметра: Q# строковое представление определения операции или самой операции, а также количество кубитов, используемых в операции. Выходные данные dump_operation — это вложенный список, представляющий квадратную матрицу сложных чисел, соответствующую заданной квантовой операции. Значения матрицы находятся в вычислительной основе, и каждый подлист представляет строку матрицы.

В следующем примере используется dump_operation для отображения сведений для систем с 1 и 2 кубитами.

  1. В VS Code нажмите клавиши CTRL+SHIFT+P , чтобы открыть палитру команд.

  2. Введите команду Create: New Jupyter Notebook и нажмите клавишу ВВОД. Откроется новая вкладка Jupyter Notebook.

  3. В первой ячейке скопируйте и запустите следующий код:

    from qdk import qsharp
    from qsharp.utils import dump_operation
    
  4. Чтобы отобразить матричные элементы однокубитного шлюза, вызовите dump_operation и передайте 1 для числа кубитов. Например, скопируйте и запустите следующий код Python в новой ячейке кода, чтобы получить элементы матрицы для шлюза удостоверений и шлюза Hadamard:

    res = dump_operation("qs => ()", 1)
    print("Single-qubit identity gate:\n", res)
    print()
    
    res = dump_operation("qs => H(qs[0])", 1)
    print("Single-qubit Hadamard gate:\n", res)
    
  5. Вы также можете вызвать функцию qsharp.eval, а затем ссылаться на операцию Q# в dump_operation, чтобы получить тот же результат. Например, создайте новую ячейку кода, а затем скопируйте и запустите следующий код Python, чтобы распечатать элементы матрицы для однокубитных шлюзов Hadamard:

    qsharp.eval("operation SingleH(qs : Qubit[]) : Unit { H(qs[0]) }")
    
    res = dump_operation("SingleH", 1)
    print("Single-qubit Hadamard gate:\n", res)
    
  6. Чтобы отобразить матричные элементы двух кубитового шлюза, вызовите dump_operation и передайте 2 для количества кубитов. Например, скопируйте и запустите следующий код Python в новой ячейке кода, чтобы получить элементы матрицы для операции Управляемого Ry, где второй кубит является target кубитом:

    qsharp.eval ("operation ControlRy(qs : Qubit[]) : Unit { Controlled Ry([qs[0]], (0.5, qs[1])); }")
    
    res = dump_operation("ControlRy", 2)
    print("Controlled Ry rotation gate:\n", res)
    

Для получения дополнительных примеров тестирования и отладки вашего кода с помощью dump_operation, смотрите "Тестирование операций" из примеров QDK.

Тестирование квантового кода

QDK предоставляет несколько Q# функций и операций, которые можно использовать для тестирования кода при выполнении. Вы также можете написать модульные тесты для Q# программ.

Выражение fail

Выражение fail немедленно завершает программу. Чтобы включить тесты в код, используйте fail выражения внутри условных операторов.

В следующем примере используется оператор fail для проверки того, что массив кубитов содержит ровно 3 кубита. Программа заканчивается сообщением об ошибке, когда тест не проходит.

  1. В VS Code создайте и сохраните новый .qs файл со следующим кодом:

    operation Main() : Unit {
        use qs = Qubit[6];
        let n_qubits = Length(qs);
    
        if n_qubits != 3 {
            fail $"The system should have 3 qubits, not {n_qubits}.";
        }  
    }
    
  2. Нажмите клавиши CTRL+F5 , чтобы запустить программу. Программа завершается ошибкой, и в консоли отладки отображаются следующие выходные данные:

    Error: program failed: The system should have 3 qubits, not 6.
    
  3. Измените код с Qubit[6] на Qubit[3], сохраните файл и нажмите Ctrl + F5, чтобы снова запустить программу. Программа выполняется без ошибки, так как тест проходит.

Функция Fact.

Вы также можете использовать функцию Q#Fact из Std.Diagnostics пространства имен для тестирования кода. Функция Fact принимает логическое выражение и строку сообщения об ошибке. Если логическое выражение имеет значение true, тест проходит и программа продолжает выполняться. Если логическое выражение равно false, Fact завершит программу и отобразит сообщение об ошибке.

Чтобы выполнить тот же тест длины массива в предыдущем коде с функцией Fact, выполните следующие действия:

  1. В VS Code создайте и сохраните новый .qs файл со следующим кодом:

    import Std.Diagnostics.Fact;
    
    operation Main() : Unit {
        use qs = Qubit[6];
        let n_qubits = Length(qs);
    
        Fact(n_qubits == 3,  $"The system should have 3 qubits, not {n_qubits}.")
    }
    
  2. Нажмите клавиши CTRL+F5 , чтобы запустить программу. Условие теста Fact не выполняется, и сообщение об ошибке отображается в консоли отладки.

  3. Измените код с Qubit[6] на Qubit[3], сохраните файл и нажмите Ctrl + F5, чтобы снова запустить программу. Условие теста Fact проходит и программа выполняется без ошибки.

Напишите Q# модульные тесты с аннотацией @Test()

В Q# программах можно применить заметку @Test() к вызываемому (функции или операции), чтобы преобразовать вызываемый объект в модульный тест. Эти модульные тесты отображаются в меню тестирования в VS Code, чтобы воспользоваться этой функцией VS Code. Вызывающий объект можно превратить в модульный тест только в том случае, если вызывающий объект не принимает входные параметры.

В следующем примере тестовый код длины массива оборачивается в операцию, которая затем используется для модульного тестирования.

  1. В VS Code создайте и сохраните новый .qs файл со следующим кодом:

    import Std.Diagnostics.Fact;
    
    @Test()
    operation TestCase() : Unit {
        use qs = Qubit[3];
        let n_qubits = Length(qs);
    
        Fact(n_qubits == 3, $"The system should have 3 qubits, not {n_qubits}.");
    }
    

    Заметка @Test() в строке перед TestCase определением операции преобразует операцию в модульный тест VS Code. Зеленая стрелка отображается в строке определения операции.

  2. Выберите зеленую стрелку, чтобы запустить TestCase и сообщить о результатах теста.

  3. Чтобы взаимодействовать с модульными тестами в Test Explorer в VS Code, найдите значок Тестирования Flask на основной боковой панели.

  4. Измените код в диапазоне от Qubit[3] до Qubit[6], затем снова запустите модульный тест, чтобы узнать, как изменяются сведения о тесте.

Модульные тесты можно записывать и запускать Q# в VS Code без операции точки входа в программе.

Примечание.

Объекты, которые могут быть вызваны из Std.Diagnostics пространства имен, несовместимы с генерацией QIR, так что включайте только модульные тесты в код, который выполняете на симуляторах Q#. Если вы хотите создать QIR из Q# кода, не включайте модульные тесты в код.

Операции CheckZero и CheckAllZero

Операции CheckZero и CheckAllZeroQ# проверяют, является ли текущее состояние кубита или массива кубитов $\ket{{0}}$. Операция CheckZero принимает один кубит и возвращается true только в том случае, если кубит находится в состоянии $\ket{0}$. Операции CheckAllZero принимают массив кубитов и возвращаются true только в том случае, если все кубиты в массиве находятся в состоянии $\ket{0}$. Для использования CheckZero и CheckAllZero, импортируйте их из пространства имен Std.Diagnostics.

В следующем примере используются обе операции. Операция CheckZero переворачивает первый кубит из состояния $\ketX$ в состояние $\ket{0}$. Операция {1} тестирует, что оба кубита сбрасываются в состояние $\ketCheckAllZero$.

В VS Code создайте и сохраните новый .qs файл со следующим кодом, а затем запустите программу и просмотрите выходные данные в консоли отладки.

import Std.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");
    }
}