量子コードをデバッグしてテストする方法

従来のプログラミングと同様に、量子プログラムが意図したとおりに動作することの確認が可能で、正しくない動作の診断が可能であることが非常に重要です。 この記事では、量子プログラムのテストとデバッグのために Azure Quantum Development Kit によって提供されるツールについて説明します。

Q# プログラムをデバッグする

Azure Quantum Development Kit (QDK) Visual Studio Code 拡張機能には、 Q# プログラム用のデバッガーが含まれています。 ブレークポイントの設定、コードのステップ実行、各関数または操作のステップ実行、ローカル変数だけでなく、量子ビットの量子状態も追跡できます。

Note

VS Code デバッガーは、 Q# (.qs) ファイルでのみ機能し、Jupyter Notebook 内の Q# セルでは機能しません。 Jupyter Notebook のセルをテストするには、「 コードのテストを参照してください。

次の例は、デバッガーの基本的な機能を示しています。 VS Code デバッガーの使用の詳細については、「 Debugging」を参照してください。

VS Code で、次のコードを使用して新しい .qs ファイルを作成して保存します。

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. 行番号の左側をクリックして、 H(qubit) 行にブレークポイントを設定します。
  2. デバッガー アイコンを選択してデバッガー ウィンドウを開き、 実行とデバッグを選択します。 デバッガー コントロールが画面の上部に表示されます。
  3. F5 キーを押してデバッグを開始し、ブレークポイントに進みます。 デバッガーの Variables ペインで、 Quantum State カテゴリを展開します。 量子ビットが |0> 状態で初期化されていることがわかります。
  4. (F11) H 操作にステップ インし、 H 操作のソース コードが表示されます。 演算をステップ実行すると、 H 演算によって量子ビットが重ね合わせに設定されると、量子値が変化します。
  5. M演算をステップオーバー (F10) すると、測定の結果として量子値が |0> または |1> に解決され、従来の変数resultの値が表示されます。
  6. Reset操作をステップ オーバーすると、量子ビットは |0> にリセットされます。

コードのテスト

VS Code Q# デバッガーは Jupyter Notebook の Q# セルでは使用できませんが、Azure QDK には、コードのトラブルシューティングに役立ついくつかの式と関数が用意されています。

Fail 式

fail式は、プログラムを停止する致命的なエラーに対応して、計算を完全に終了します。

パラメーター値を検証する次の簡単な例を考えてみましょう。

# 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 式を使用すると、プログラムが無効なデータで実行され続けなくなります。

Fact() 関数

Microsoft.Quantum.Diagnostics名前空間のFact()関数を使用して、前の例と同じ動作を実装できます。 Fact()関数は、特定の古典的な条件を評価し、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() 関数

DumpMachine()は、target コンピューターの現在の状態に関する情報をコンソールにダンプし、プログラムの実行を続行できるQ#関数です。

Note

Azure Quantum Development Kitのリリースにより、 DumpMachine() 関数では出力にビッグ エンディアンの順序が使用されるようになりました。

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 は、現在割り当てられている量子ビット数と、解析できるスパース状態振幅の Python ディクショナリを返す Python 関数です。 Jupyter Notebook でこれらの関数のいずれかを使用すると、デバッガーと同様に操作をステップ実行できます。 前のプログラム例を使用します。

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() および CheckAllZero() 操作

CheckZero()およびCheckAllZero()は、量子ビット配列または量子ビット配列の現在の状態が $\ket{0}$ であるかどうかを確認できるQ#操作です。 CheckZero()は、量子ビットが $\ket{0}$ 状態の場合はtrueを返し、他の状態の場合はfalseします。 CheckAllZero()は、配列内のすべての量子ビットが $\ket{0}$ 状態の場合はtrueを返し、量子ビットが他の状態にある場合はfalseします。

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 は、操作または演算定義を受け取り、使用する量子ビットの数を受け取り、演算の出力を表す複素数の平方行列を返す Python 関数です。

qsharp.utilsからdump_operationをインポートします。

import qsharp
from qsharp.utils import dump_operation

次の使用例は、単一量子ビット ID ゲートと Hadmard ゲートの行列を出力します。

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

qsharp.eval()を使用して関数または操作を定義し、dump_operationから参照することもできます。 前に表した 1 つの量子ビットは、次のように表すこともできます。

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

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

この例では、 Controlled Ry ゲートを使用して、2 番目の量子ビットに回転を適用します。

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

次のコードでは、 Q# 操作 ApplySWAP を定義し、その行列を 2 量子ビット ID 演算のマトリックスと共に出力します。

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

dump_operation()を使用したテスト操作のその他の例については、QDK でのテスト操作サンプル ページを参照してください。