Dela via


Så här felsöker och testar du kvantkoden

Precis som med klassisk programmering är det viktigt att kunna kontrollera att kvantprogram fungerar som avsett och att kunna diagnostisera felaktigt beteende. I den här artikeln beskrivs de verktyg som erbjuds av Azure Quantum Development Kit för testning och felsökning av kvantprogram.

Felsöka ditt Q# program

Tillägget Azure Quantum Development Kit (QDK) Visual Studio Code innehåller ett felsökningsprogram för Q# program. Du kan ange brytpunkter, stega igenom koden och in i varje funktion eller åtgärd och spåra inte bara de lokala variablerna, utan även kvanttillståndet för kvantbitarna.

Kommentar

VS Code-felsökningsprogrammet fungerar bara med Q# (.qs) filer och fungerar inte med Q# celler i en Jupyter Notebook. Information om hur du testar Jupyter Notebook-celler finns i Testa din kod.

I följande exempel visas de grundläggande funktionerna i felsökningsprogrammet. Fullständig information om hur du använder VS Code-felsökningsprogram finns i Felsökning.

I VS Code skapar och sparar du en ny .qs-fil med följande kod:

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. Ange en brytpunkt på raden H(qubit) genom att klicka till vänster om radnumret.
  2. Välj felsökningsikonen för att öppna felsökningsfönstret och välj Kör och Felsök. Felsökningskontrollerna visas överst på skärmen.
  3. Välj F5 för att börja felsöka och fortsätta till brytpunkten. I fönstret Variabler för felsökning expanderar du kategorin Kvanttillstånd. Du kan se att kvantbiten har initierats i tillståndet |0> .
  4. Stega in i (F11) åtgärden H och källkoden för H åtgärden visas. När du går igenom åtgärden bör du notera att kvantvärdet ändras när H åtgärden placerar kvantbiten i superposition.
  5. När du kliver över (F10) M matchas kvantvärdet till antingen |0> eller |1> som ett resultat av mätningen, och värdet för den klassiska variabeln result visas.
  6. När du kliver över åtgärden Reset återställs kvantbiten till |0>.

Testa koden

Även om VS Code-felsökaren Q# inte är tillgänglig för Q# celler i en Jupyter Notebook innehåller Azure QDK vissa uttryck och funktioner som kan hjälpa dig att felsöka koden.

Feluttryck

Uttrycket fail avslutar beräkningen helt och hållet, vilket motsvarar ett allvarligt fel som stoppar programmet.

Tänk dig det här enkla exemplet som validerar ett parametervärde:

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

fail Här förhindrar uttrycket att programmet fortsätter att köras med ogiltiga data.

Funktionen Fact()

Du kan implementera samma beteende som i föregående exempel med hjälp av Fact() funktionen från Microsoft.Quantum.Diagnostics namnområdet. Funktionen Fact() utvärderar ett angivet klassiskt villkor och utlöser ett undantag om det är falskt.

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

Funktionen DumpMachine()

DumpMachine() är en Q# funktion som gör att du kan dumpa information om datorns target aktuella tillstånd till konsolen och fortsätta att köra programmet.

Kommentar

Med lanseringen av Azure Quantum Development KitDumpMachine() använder funktionen nu storslutsordning för sina utdata.

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   

funktionen dump_machine()

dump_machine är en Python-funktion som returnerar det aktuella allokerade kvantbitsantalet och en Python-ordlista med glesa tillståndssamplituder som du kan parsa. Med någon av dessa funktioner i en Jupyter Notebook kan du gå igenom dina åtgärder ungefär som ett felsökningsprogram. Använd föregående exempelprogram:

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() och CheckAllZero() åtgärder

CheckZero() och CheckAllZero() är Q# åtgärder som kan kontrollera om det aktuella tillståndet för en qubit- eller qubit-matris är $\ket{0}$. CheckZero() returnerar true om kvantbiten är i tillståndet $\ket{0}$ och false om den är i något annat tillstånd. CheckAllZero() returnerar true om alla kvantbitar i matrisen är i tillståndet $\ket{0}$ och false om kvantbitarna är i något annat tillstånd.

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

funktionen dump_operation()

dump_operation är en Python-funktion som tar en åtgärd eller åtgärdsdefinition och ett antal kvantbitar att använda och returnerar en kvadratmatris med komplexa tal som representerar utdata från åtgärden.

Du importerar dump_operation från qsharp.utils.

import qsharp
from qsharp.utils import dump_operation

Det här exemplet skriver ut matrisen för en identitetsport med en enda qubit och Hadamard-porten.

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

Du kan också definiera en funktion eller åtgärd med och qsharp.eval() sedan referera till den från dump_operation. Den enda qubit som representeras tidigare kan också representeras som

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

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

I det här exemplet används en Controlled Ry grind för att tillämpa en rotation på den andra kvantbiten

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

Följande kod definierar Q# åtgärden ApplySWAP och skriver ut dess matris tillsammans med den två qubitsidentitetsåtgärden.

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

Fler exempel på teståtgärder som använder dump_operation() finns på exempelsidan Testningsåtgärder i QDK.