Comment déboguer et tester votre code quantique
Comme pour la programmation classique, il est essentiel de pouvoir vérifier que les programmes quantiques fonctionnent comme prévu et de pouvoir diagnostiquer un comportement incorrect. Cet article décrit les outils proposés par Azure Quantum Development Kit pour tester et déboguer des programmes quantiques.
Déboguer votre Q# programme
L’extension Visual Studio Code (QDK) Azure Quantum Development Kit inclut un débogueur pour Q# les programmes. Vous pouvez définir des points d’arrêt, parcourir votre code et entrer dans chaque fonction ou opération, et suivre non seulement les variables locales, mais également l’état quantique des qubits.
Remarque
Le débogueur VS Code fonctionne uniquement avec Q# les fichiers (.qs) et ne fonctionne pas avec Q# les cellules d’un bloc-notes Jupyter. Pour tester les cellules Jupyter Notebook, consultez Tester votre code.
L’exemple suivant illustre les fonctionnalités de base du débogueur. Pour plus d’informations sur l’utilisation des débogueurs VS Code, consultez Débogage.
Dans VS Code, créez et enregistrez un nouveau fichier .qs avec le code suivant :
import Microsoft.Quantum.Arrays.*;
import Microsoft.Quantum.Convert.*;
operation Main() : Result {
use qubit = Qubit();
H(qubit);
let result = M(qubit);
Reset(qubit);
return result;
}
- Définissez un point d’arrêt sur la ligne
H(qubit)
en cliquant sur la gauche du numéro de ligne. - Sélectionnez l’icône du débogueur pour ouvrir le volet débogueur, puis sélectionnez Exécuter et Déboguer. Les contrôles du débogueur s’affichent en haut de l’écran.
- Sélectionnez F5 pour démarrer le débogage et passer au point d’arrêt. Dans le volet Variables du débogueur, développez la catégorie État quantique. Vous pouvez voir que le qubit a été initialisé dans l’état |0> .
- Pas à pas dans (F11) l’opération
H
et le code source de l’opération s’afficheH
. Lorsque vous parcourez l’opération, notez que la valeur quantique change à mesure que l’opérationH
place le qubit en superposition. - Lorsque vous effectuez un pas à pas (F10) l’opération
M
, la valeur quantique est résolue en |0> ou |1> à la suite de la mesure, et la valeur de la variableresult
classique est affichée. - Lorsque vous effectuez un pas à pas sur l’opération
Reset
, le qubit est réinitialisé à |0>.
Test de votre code
Bien que le débogueur VS Code Q# ne soit pas disponible pour Q# les cellules d’un jupyter Notebook, le QDK Azure fournit certaines expressions et fonctions qui peuvent vous aider à résoudre les problèmes de votre code.
Expression d’échec
L’expression fail
termine entièrement le calcul, correspondant à une erreur irrécupérable qui arrête le programme.
Considérez cet exemple simple qui valide une valeur de paramètre :
# 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 │ }
╰────
Ici, l’expression fail
empêche le programme de continuer à s’exécuter avec des données non valides.
Fact(), fonction
Vous pouvez implémenter le même comportement que l’exemple précédent à l’aide de la Fact()
fonction à partir de l’espace Microsoft.Quantum.Diagnostics
de noms. La Fact()
fonction évalue une condition classique donnée et lève une exception si elle est 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(), fonction
DumpMachine()
est une Q# fonction qui vous permet de vider des informations sur l’état actuel de l’ordinateur sur la target console et de continuer à exécuter votre programme.
Remarque
Avec la version d’Azure Quantum Development Kit, la DumpMachine()
fonction utilise désormais le classement big-endian pour sa sortie.
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
fonction dump_machine()
dump_machine
est une fonction Python qui retourne le nombre de qubits alloués actuel et un dictionnaire Python d’amplitudes d’état éparses que vous pouvez analyser. L’utilisation de l’une de ces fonctions dans un notebook Jupyter vous permet de parcourir vos opérations comme un débogueur. Utilisation de l’exemple de programme précédent :
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)
Opérations CheckZero() et CheckAllZero()
CheckZero()
et CheckAllZero()
sont Q# des opérations qui peuvent vérifier si l’état actuel d’un tableau qubit ou qubit est $\ket{0}$. CheckZero()
retourne true
si le qubit est dans l’état $\ket{0}$ et false
s’il se trouve dans un autre état. CheckAllZero()
retourne true
si tous les qubits du tableau sont dans l’état $\ket{0}$ et false
si les qubits sont dans un autre état.
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");
}
}
fonction dump_operation()
dump_operation
est une fonction Python qui prend une opération, ou une définition d’opération, et un certain nombre de qubits à utiliser, et retourne une matrice carrée de nombres complexes représentant la sortie de l’opération.
Vous importez dump_operation
à partir de qsharp.utils
.
import qsharp
from qsharp.utils import dump_operation
Cet exemple montre comment imprimer la matrice d’une porte d’identité à qubit unique et de la porte 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)]]
Vous pouvez également définir une fonction ou une opération à l’aide qsharp.eval()
de celle-ci, puis la référencer à partir de dump_operation
. Le qubit unique représenté précédemment peut également être représenté en tant que
qsharp.eval("operation SingleQ(qs : Qubit[]) : Unit { }")
res = dump_operation("SingleQ", 1)
print(res)
[[(1+0j), 0j], [0j, (1+0j)]]
Cet exemple utilise une porte pour appliquer une Controlled Ry
rotation au deuxième qubit
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)]]
Le code suivant définit Q# l’opération ApplySWAP
et imprime sa matrice en même temps que celle de l’opération d’identité à deux qubits.
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)]]
Vous trouverez d’autres exemples d’opérations de test à l’aide dump_operation()
de la page Exemples d’opérations de test dans le QDK.