Compartir a través de


Depuración y prueba del código cuántico

Al igual que con la programación clásica, es esencial poder comprobar que los programas cuánticos actúan según lo previsto y poder diagnosticar comportamientos incorrectos. En este artículo se describen las herramientas que ofrece Azure Quantum Development Kit para probar y depurar programas cuánticos.

Depuración del Q# programa

La extensión de Visual Studio Code de Azure Quantum Development Kit (QDK) incluye un depurador para Q# programas. Puede establecer puntos de interrupción, recorrer el código y en cada función o operación, y realizar un seguimiento no solo de las variables locales, sino también del estado cuántico de los cúbits.

Nota:

El depurador de VS Code solo funciona con Q# archivos (.qs) y no funciona con Q# celdas en un cuaderno de Jupyter Notebook. Para probar las celdas de Jupyter Notebook, consulte Prueba del código.

En el ejemplo siguiente se muestran las características básicas del depurador. Para obtener información completa sobre el uso de depuradores de VS Code, consulte Depuración.

En VS Code, cree y guarde un nuevo archivo .qs con el código siguiente:

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. Establezca un punto de interrupción en la línea H(qubit) haciendo clic a la izquierda del número de línea.
  2. Seleccione el icono del depurador para abrir el panel del depurador y seleccione Ejecutar y depurar. Los controles del depurador se muestran en la parte superior de la pantalla.
  3. Seleccione F5 para iniciar la depuración y continuar con el punto de interrupción. En el panel Variables del depurador, expanda la categoría Estado cuántico. Puede ver que el cúbit se ha inicializado en el estado |0> .
  4. Entra en paso a paso (F11) la H operación y el código fuente de la H operación se muestra. A medida que avanza por la operación, tenga en cuenta que el valor cuántico cambia a medida que la H operación coloca el cúbit en superposición.
  5. A medida que se supera (F10) la M operación, el valor cuántico se resuelve en |0> o |1> como resultado de la medida y se muestra el valor de la variable result clásica.
  6. A medida que avanza por la Reset operación, el cúbit se restablece a |0>.

Prueba del código

Aunque el depurador de VS Code Q# no está disponible para Q# las celdas de un cuaderno de Jupyter Notebook, el QDK de Azure proporciona algunas expresiones y funciones que pueden ayudar a solucionar problemas del código.

Expresión fail

La fail expresión finaliza el cálculo por completo, correspondiente a un error irrecuperable que detiene el programa.

Considere este ejemplo sencillo que valida un valor de parámetro:

# 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 │     }   
   ╰────

Aquí, la fail expresión impide que el programa continúe ejecutándose con datos no válidos.

Función Fact()

Puede implementar el mismo comportamiento que el ejemplo anterior mediante la Fact() función del espacio de Microsoft.Quantum.Diagnostics nombres . La Fact() función evalúa una condición clásica determinada y produce una excepción si es 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 │         }
    ╰────

Función DumpMachine()

DumpMachine() es una Q# función que permite volcar información sobre el estado actual de la target máquina en la consola y continuar ejecutando el programa.

Nota:

Con la versión de Azure Quantum Development Kit, la DumpMachine() función ahora usa el orden big-endian para su salida.

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   

función dump_machine()

dump_machine es una función de Python que devuelve el recuento de cúbits asignado actual y un diccionario de Python de amplitudes de estado dispersas que puede analizar. El uso de cualquiera de estas funciones en un cuaderno de Jupyter Notebook le permite recorrer paso a paso las operaciones de forma muy similar a un depurador. Con el programa de ejemplo anterior:

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)

Operaciones CheckZero() y CheckAllZero()

CheckZero() y CheckAllZero() son Q# operaciones que pueden comprobar si el estado actual de una matriz de cúbits o cúbits es $\ket{0}$. CheckZero() devuelve true si el cúbit está en el estado $\ket{0}$ y false si está en cualquier otro estado. CheckAllZero() devuelve true si todos los cúbits de la matriz están en estado $\ket{0}$ y false si los cúbits están en cualquier otro estado.

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

función dump_operation()

dump_operation es una función de Python que toma una operación o definición de operación, y un número de cúbits que se van a usar y devuelve una matriz cuadrada de números complejos que representa la salida de la operación.

dump_operation Importe desde qsharp.utils.

import qsharp
from qsharp.utils import dump_operation

En este ejemplo se imprime la matriz de una puerta de identidad de un solo cúbit y la puerta 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)]]

También puede definir una función o una operación mediante qsharp.eval() y, a continuación, hacer referencia a ella desde dump_operation. El único cúbit representado anteriormente también se puede representar como

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

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

En este ejemplo se usa una Controlled Ry puerta para aplicar una rotación al segundo cúbit.

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)]]

El código siguiente define Q# la operación ApplySWAP e imprime su matriz junto con la de la operación de identidad de dos cúbits.

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)]]

Puede encontrar más ejemplos de operaciones de prueba mediante dump_operation() en la página de ejemplos Operaciones de prueba en QDK.