Freigeben über


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;
}
  1. Legen Sie einen Haltepunkt in der Zeile H(qubit) fest, indem Sie links neben der Zeilennummer klicken.
  2. 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.
  3. 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.
  4. Gehen Sie in den Vorgang (F11) H und den Quellcode für den H Vorgang ein. Beachten Sie beim Durchlaufen des Vorgangs, dass sich der Quantenwert ändert, während der H Vorgang das Qubit in eine Superposition versetzt.
  5. 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 Variablen result wird angezeigt.
  6. 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_operationsie 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.