量子メモリの管理
プログラムは常に量子ビットなしで開始します。つまり、Qubit
型の値をエントリ ポイントの引数として渡すことはできません。
Q# の目的はプログラム全体を表し、理解することであるので、この制限は意図的なものです。
代わりに、プログラムは量子ビット、つまり量子メモリの割り当てと解放を行います。
この点で、Q# は量子コンピューターを量子ビット ヒープとしてモデル化します。
Q# は、量子メモリに対する個別の "割り当て" ステートメントと "解放" ステートメントをサポートするのではなく、"ブロック ステートメント" の形式で量子メモリ割り当てをサポートします。この場合、メモリにはそのステートメントのスコープ内でのみアクセスできます。 ステートメント ブロックは、現在のスコープの期間の量子ビットを割り当てるときに暗黙的に定義されます。詳細については、use
ステートメントと borrow
ステートメントに関するセクションを参照してください。 割り当てられた量子ビットに対し、ステートメントの終了後にアクセスしようとすると、ランタイム例外が発生します。
Q# には、量子ビット値、量子ビットの配列、またはそれらの任意の組み合わせをインスタンス化する 2 つのステートメント (use
および borrow
) があります。 これらのステートメントは、操作内でのみ使用できます。 インスタンス化された量子ビット値を収集し、ステートメントで指定された変数にバインドしてから、ステートメントのブロックを実行します。
ブロックの最後に、バインドされた変数がスコープ外に出て、定義されなくなります。
Q# は、"クリーンな" 量子ビットと "ダーティな" 量子ビットとを区別します。 クリーンな量子ビットは、もつれておらず、かつ計算の別の部分で使用されていないものです。 ダーティな量子ビットは、状態が不明で、量子プロセッサのメモリの他の部分ともつれる可能性がある量子ビットです。
Use ステートメント
クリーンな量子ビットは、use
ステートメントによって割り当てられます。
- このステートメントは、キーワード
use
と、その後に続くバインディングと省略可能なステートメント ブロックで構成されます。 - ステートメント ブロックが存在する場合、量子ビットはそのブロック内でのみ使用できます。 そうでない場合、現在のスコープの最後まで量子ビットは使用可能です。
- バインディングは、
let
ステートメントと同じパターンに従います。つまり、1 つのシンボルまたはシンボルのタプルの後に、等号=
と、1 つのタプルまたは一致する "初期化子" のタプルが続きます。
初期化子は、Qubit()
として示される 1 つの量子ビット、または量子ビットの配列 Qubit[n]
(ここで、n
は Int
式) のどちらかに使用できます。
たとえば、次のように入力します。
use qubit = Qubit();
// ...
use (aux, register) = (Qubit(), Qubit[5]);
// ...
use qubit = Qubit() {
// ...
}
use (aux, register) = (Qubit(), Qubit[5]) {
// ...
}
割り当て後、量子ビットは必ず |0⟩ 状態になります。 これらはスコープの最後にリリースされ、リリース時に |0⟩ 状態である必要があります。 この要件はコンパイラによって強制されません。これには、すぐに非常にコスト高になるシンボリック評価が必要であるからです。 シミュレーターで実行する場合、要件を実行時に適用できます。 量子プロセッサでは、要件を実行時に適用することはできません。測定されていない量子ビットは、ユニタリ変換により |0⟩ にリセットできます。 それを実行できないと、正しくない動作が生じます。
use
ステートメントは、量子プロセッサの空き量子ビット ヒープから量子ビットを割り当て、量子ビットがバインドされるスコープの最後までにヒープに返します。
Borrow ステートメント
borrow
ステートメントは、既に割り当てられているものの現時点では使用されていない量子ビットへのアクセスを可能にするものです。 これらの量子ビットは任意の状態でかまいませんが、borrow ステートメントの終了時には再度同じ状態になっている必要があります。
一部の量子アルゴリズムでは、その正確な状態への依存なしで量子ビットを使用できます。システムの残りの部分とのもつれ状態があってもかまいません。 つまり、追加の量子ビットが一時的に必要ですが、どの状態であったかに関係なく、それらの量子ビットが正確に元の状態に戻されるようにすることができます。
使用中であるものの、サブルーチンの中で操作されない量子ビットがある場合、それらの量子ビットは、追加の量子メモリを割り当てるのではなく、このようなアルゴリズムで借用できます。 割り当てる代わりに借用すると、アルゴリズムの全体的な量子メモリ要件を大幅に削減できます。これは、量子の一般的な時空トレードオフの例です。
borrow
ステートメントは、use
ステートメントについて上記で説明したのと同じパターンに従い、同じ初期化子が使用できます。
たとえば、次のように入力します。
borrow qubit = Qubit();
// ...
borrow (aux, register) = (Qubit(), Qubit[5]);
// ...
borrow qubit = Qubit() {
// ...
}
borrow (aux, register) = (Qubit(), Qubit[5]) {
// ...
}
借用された量子ビットは不明な状態であり、ステートメント ブロックの最後にスコープ外に出ます。 借り手は、量子ビットを借用時と同じ状態のままにすることにコミットします。つまり、ステートメント ブロックの最初と最後の状態は同じであると想定されます。
borrow
ステートメントが取得する使用中の量子ビットは、量子ビットがバインドされた時点から、その量子ビットが最後に使用されるまで、プログラムによって使用されないことが保証されます。
借用できる十分な量子ビットがない場合、量子ビットは、use
ステートメントのようにヒープから割り振られ、ヒープに返されます。
Note
ダーティな量子ビットの既知のユース ケースの中には、ごくわずかの量子ビットを必要とするマルチ制御 CNOT ゲートの実装や増分器の実装があります。 量子ビットでの因数分解に関するドキュメントには、借用された量子ビットを利用するアルゴリズムの例が紹介されています。