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;
}
- Establezca un punto de interrupción en la línea
H(qubit)
haciendo clic a la izquierda del número de línea. - 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.
- 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> .
- Entra en paso a paso (F11) la
H
operación y el código fuente de laH
operación se muestra. A medida que avanza por la operación, tenga en cuenta que el valor cuántico cambia a medida que laH
operación coloca el cúbit en superposición. - 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 variableresult
clásica. - 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.