Debuggen und Testen des Quantencodes
Wie bei der herkömmlichen Programmierung muss unbedingt überprüft werden können, ob sich Quantenprogramme wie vorgesehen verhalten, und es muss möglich sein, fehlerhaftes Verhalten zu diagnostizieren. In diesem Artikel werden die Tools erläutert, die von Azure Quantum Development Kit zum Testen und Debuggen von Quantenprogrammen angeboten werden.
Debuggen des Q# Programms
Die Visual Studio Code-Erweiterung (Azure Quantum Development Kit , QDK) enthält einen Debugger für Q# Programme. Sie können Haltepunkte festlegen, Den Code durchlaufen und in jede Funktion oder jeden Vorgang durchlaufen und nicht nur die lokalen Variablen, sondern auch den Quantenzustand der Qubits nachverfolgen.
Hinweis
Der VS Code-Debugger funktioniert nur mit Q# Dateien (QS) und funktioniert nicht mit Q# Zellen in einem Jupyter-Notizbuch. Informationen zum Testen von Jupyter-Notizbuchzellen finden Sie unter Testen des Codes.
Im folgenden Beispiel werden die grundlegenden Features des Debuggers veranschaulicht. Vollständige Informationen zur Verwendung von VS-Codedebuggern finden Sie unter Debuggen.
Erstellen und speichern Sie in VS Code eine neue QS-Datei mit dem folgenden Code:
import Microsoft.Quantum.Arrays.*;
import Microsoft.Quantum.Convert.*;
operation Main() : Result {
use qubit = Qubit();
H(qubit);
let result = M(qubit);
Reset(qubit);
return result;
}
- Legen Sie einen Haltepunkt in der Zeile
H(qubit)
fest, indem Sie links neben der Zeilennummer klicken. - Wählen Sie das Debuggersymbol aus, um den Debuggerbereich zu öffnen, und wählen Sie "Ausführen" und "Debuggen" aus. Die Debuggersteuerelemente werden oben auf dem Bildschirm angezeigt.
- Wählen Sie F5 aus, um mit dem Debuggen zu beginnen und mit dem Haltepunkt fortzufahren. Erweitern Sie im Bereich "Debuggervariablen" die Kategorie "Quantum State". Sie können sehen, dass der Qubit im Zustand '|0'> initialisiert wurde.
- Gehen Sie in den Vorgang (F11)
H
und den Quellcode für denH
Vorgang ein. Beachten Sie beim Durchlaufen des Vorgangs, dass sich der Quantenwert ändert, während derH
Vorgang das Qubit in eine Superposition versetzt. - Während Sie den
M
Vorgang (F10) durchlaufen, wird der Quantenwert als Ergebnis der Messung in |0> oder |1> aufgelöst, und der Wert der klassischen Variablenresult
wird angezeigt. - Während Sie den
Reset
Vorgang durchlaufen, wird der Qubit auf |0> zurückgesetzt.
Testen Ihres Codes
Obwohl der VS-Codedebugger Q# für Q# Zellen in einem Jupyter-Notizbuch nicht verfügbar ist, stellt azure QDK einige Ausdrücke und Funktionen bereit, mit denen Sie Probleme mit Ihrem Code beheben können.
Fehlerausdruck
Der fail
Ausdruck beendet die Berechnung vollständig, was einem schwerwiegenden Fehler entspricht, der das Programm beendet.
Betrachten Sie dieses einfache Beispiel, das einen Parameterwert überprüft:
# 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 │ }
╰────
Hier verhindert der fail
Ausdruck, dass das Programm weiterhin mit ungültigen Daten ausgeführt wird.
Fact()-Funktion
Sie können dasselbe Verhalten wie im vorherigen Beispiel mithilfe der Fact()
Funktion aus dem Microsoft.Quantum.Diagnostics
Namespace implementieren. Die Fact()
Funktion wertet eine bestimmte klassische Bedingung aus und löst eine Ausnahme aus, wenn sie falsch ist.
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()-Funktion
DumpMachine()
ist eine Q# Funktion, mit der Sie Informationen zum aktuellen Zustand des target Computers auf der Konsole abbilden und das Programm weiterhin ausführen können.
Hinweis
Mit der Veröffentlichung von Azure Quantum Development Kitverwendet die DumpMachine()
Funktion jetzt die Big-End-Sortierung für ihre Ausgabe.
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()-Funktion
dump_machine
ist eine Python-Funktion, die die aktuelle zugewiesene Qubitanzahl und ein Python-Wörterbuch mit geringen Zustandsamplituden zurückgibt, die Sie analysieren können. Wenn Sie eine dieser Funktionen in einem Jupyter-Notizbuch verwenden, können Sie Ihre Vorgänge ähnlich wie einen Debugger durchlaufen. Verwenden des vorherigen Beispielprogramms:
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() und CheckAllZero()-Vorgänge
CheckZero()
und CheckAllZero()
sind Q# Vorgänge, die überprüfen können, ob der aktuelle Zustand eines Qubit- oder Qubit-Arrays $\ket{0}$ist. CheckZero()
gibt zurück true
, wenn sich der Qubit im Zustand $\ket{0}$ befindet und false
sich in einem anderen Zustand befindet. CheckAllZero()
gibt zurück true
, wenn sich alle Qubits im Array im Zustand $\ket{0}$ befinden und false
sich die Qubits in einem anderen Zustand befinden.
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()-Funktion
dump_operation
ist eine Python-Funktion, die eine Vorgangs- oder Vorgangsdefinition und eine Reihe von zu verwendenden Qubits verwendet, und gibt eine quadratische Matrix komplexer Zahlen zurück, die die Ausgabe des Vorgangs darstellt.
Sie importieren dump_operation
aus qsharp.utils
.
import qsharp
from qsharp.utils import dump_operation
In diesem Beispiel wird die Matrix eines Single-Qubit-Identitätsgaters und des Hadamard-Gates gedruckt.
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)]]
Sie können eine Funktion oder einen Vorgang auch mithilfe qsharp.eval()
definieren und dann auf dump_operation
sie verweisen. Der zuvor dargestellte einzelne Qubit kann auch als
qsharp.eval("operation SingleQ(qs : Qubit[]) : Unit { }")
res = dump_operation("SingleQ", 1)
print(res)
[[(1+0j), 0j], [0j, (1+0j)]]
In diesem Beispiel wird ein Controlled Ry
Gate verwendet, um eine Drehung auf das zweite Qubit anzuwenden.
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)]]
Der folgende Code definiert den Vorgang ApplySWAP
und druckt Q# seine Matrix zusammen mit der des Zwei-Qubit-Identitätsvorgangs.
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)]]
Weitere Beispiele für Die Verwendung dump_operation()
von Testvorgängen finden Sie auf der Beispielseite "Testvorgänge" im QDK.