Como depurar e testar seu código quântico
Assim como acontece com a programação clássica, é essencial poder verificar se os programas quantum atuam como o pretendido e podem diagnosticar o comportamento incorreto. Este artigo discute as ferramentas oferecidas pelo Azure Quantum Development Kit para testar e depurar programas quânticos.
Depurar seu Q# programa
A extensão do Visual Studio Code do Azure Quantum Development Kit (QDK) inclui um depurador para Q# programas. Você pode definir pontos de interrupção, percorrer seu código e entrar em cada função ou operação e rastrear não apenas as variáveis locais, mas também o estado quântico dos qubits.
Observação
O depurador do VS Code só funciona com Q# arquivos (.qs) e não funciona com Q# células em um Jupyter Notebook. Para testar células do Jupyter Notebook, consulte Testar seu código.
O exemplo a seguir demonstra os recursos básicos do depurador. Para obter informações completas sobre como usar depuradores do VS Code, consulte Depuração.
No VS Code, crie e salve um novo arquivo .qs com o seguinte código:
import Microsoft.Quantum.Arrays.*;
import Microsoft.Quantum.Convert.*;
operation Main() : Result {
use qubit = Qubit();
H(qubit);
let result = M(qubit);
Reset(qubit);
return result;
}
- Defina um ponto de interrupção na linha
H(qubit)
clicando à esquerda do número da linha. - Selecione o ícone do depurador para abrir o painel do depurador e selecione Executar e Depurar. Os controles do depurador são exibidos na parte superior da tela.
- Selecione F5 para iniciar a depuração e continuar até o ponto de interrupção. No painel Variáveis do depurador, expanda a categoria Estado Quântico. Você pode ver que o qubit foi inicializado no estado |0> .
- Entrar em (F11) a
H
operação e o código-fonte daH
operação será exibido. À medida que você percorre a operação, observe que o valor quântico muda à medida que aH
operação coloca o qubit em superposição. - À medida que você passa por cima (F10) da
M
operação, o valor quântico é resolvido para |0> ou |1> como resultado da medição e o valor da variávelresult
clássica é exibido. - À medida que
Reset
você passa pela operação, o qubit é redefinido para |0>.
Testar seu código
Embora o depurador do VS Code Q# não esteja disponível para Q# células em um Jupyter Notebook, o Azure QDK fornece algumas expressões e funções que podem ajudar a solucionar problemas de código.
Expressão de falha
A fail
expressão encerra totalmente o cálculo, correspondendo a um erro fatal que interrompe o programa.
Considere este exemplo simples que valida um 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 │ }
╰────
Aqui, a fail
expressão impede que o programa continue a ser executado com dados inválidos.
Função Fact()
Você pode implementar o mesmo comportamento do exemplo anterior usando a Fact()
função do Microsoft.Quantum.Diagnostics
namespace. A Fact()
função avalia uma determinada condição clássica e lança uma exceção se ela for falsa.
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 │ }
╰────
Função DumpMachine()
DumpMachine()
é uma Q# função que permite despejar informações sobre o estado atual da target máquina no console e continuar a executar o programa.
Observação
Com o lançamento do Azure Quantum Development Kit, a DumpMachine()
função agora usa a ordenação big-endian para sua saída.
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()
dump_machine
é uma função Python que retorna a contagem de qubits alocada atual e um dicionário Python de amplitudes de estado esparsas que você pode analisar. O uso de qualquer uma dessas funções em um Jupyter Notebook permite que você percorra suas operações como um depurador. Usando o programa de exemplo 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)
Operações CheckZero() e CheckAllZero()
CheckZero()
e CheckAllZero()
são Q# operações que podem verificar se o estado atual de uma matriz de qubit ou qubit é $\ket{0}$. CheckZero()
Retorna true
se o qubit estiver no estado $\ket{0}$ e false
se estiver em qualquer outro estado. CheckAllZero()
retorna true
se todos os qubits na matriz estiverem no estado $\ket{0}$ e false
se os qubits estiverem em qualquer outro 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");
}
}
dump_operation()
dump_operation
é uma função Python que usa uma operação, ou definição de operação, e um número de qubits a serem usados e retorna uma matriz quadrada de números complexos que representam a saída da operação.
Você importa dump_operation
de qsharp.utils
.
import qsharp
from qsharp.utils import dump_operation
Este exemplo imprime a matriz de uma porta de identidade de qubit único e a porta 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)]]
Você também pode definir uma função ou operação usando qsharp.eval()
e referenciá-la a partir do dump_operation
. O único qubit representado anteriormente também pode ser representado como
qsharp.eval("operation SingleQ(qs : Qubit[]) : Unit { }")
res = dump_operation("SingleQ", 1)
print(res)
[[(1+0j), 0j], [0j, (1+0j)]]
Este exemplo usa uma Controlled Ry
porta para aplicar uma rotação ao segundo 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)]]
O código a seguir define Q# a operação ApplySWAP
e imprime sua matriz junto com a da operação de identidade de dois 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)]]
Mais exemplos de operações de teste usando dump_operation()
podem ser encontrados na página de exemplos Operações de teste no QDK.