チュートリアル: Q# で量子乱数ジェネレーターを実装する
このチュートリアルでは、量子力学の性質を利用して乱数を生成する基本的な量子プログラムを Q# で記述する方法について説明します。
このチュートリアルでは、次のことについて説明します。
- Q# プログラムを作成します。
- Q# プログラムの主要なコンポーネントを確認します。
- 問題のロジックを定義する。
- 従来の演算と量子演算を組み合わせて問題を解決する。
- 量子ビットと重ね合わせを使用して、量子乱数ジェネレーターを構築します。
ヒント
量子コンピューティングの取り組みを加速させる場合は、Azure Quantum Web サイトのユニークな機能である Azure Quantum を使用した Codeをご覧ください。 ここでは、組み込みの Q# サンプルまたは独自の Q# プログラムを実行し、プロンプトから新しい Q# コードを生成し、 VS Code for the Web でコードを開いて実行し ワンクリックで Copilot に量子コンピューティングに関する質問を行うことができます。
前提条件
Azure Quantum の Copilot でコード サンプルを実行するには:
- Microsoft (MSA) メール アカウント。
Visual Studio Code でコード サンプルを開発して実行するには:
最新バージョンの Visual Studio Code または VS Code on the Web を開きます。
Azure Quantum Development Kit拡張機能の最新バージョン。 インストールの詳細については、「 VS Code での QDK のインストールを参照してください。
Jupyter Notebooks を使用する場合は、 Python および Jupyter 拡張機能、および最新の
qsharp
Python パッケージもインストールする必要があります。 これを行うには、ターミナルを開き、次のコマンドを実行します。$ pip install --upgrade qsharp
問題を定義する
従来のコンピューターでは、乱数ではなく、"擬似乱数" が生成されます。 擬似乱数ジェネレーターでは、"シード" と呼ばれる初期値に基づいて、決定論的な数列が生成されます。 ランダムな値に近づけるために、このシードは CPU のクロックの現在時刻になることがよくあります。
一方、量子コンピューターは真の乱数を生成できます。 これは、重ね合わせにおける量子ビットの測定が確率的プロセスであるためです。 測定の結果はランダムであり、結果を予測する方法はありません。 これが量子乱数ジェネレーターの基本原則です。
量子ビットは、重ね合わせ可能な量子情報の単位です。 測定された場合、量子ビットは 0 の状態または 1 の状態のいずれかになります。 ただし測定の前において、量子ビットの状態は測定で 0 または 1 を読み取る ”可能性” を表わします。
まず、0 などの基礎状態で量子ビットを取得します。 乱数ジェネレーターの最初の手順は、Hadmard 演算を使用して量子ビットを等しい重ね合わせに配置することです。 この状態を測定すると、各結果の確率が 50% の 0 または 1 が生じ、真にランダムなビットになります。
重ね合わせでの量子ビットの測定後に何が得られるかを知る方法はなく、コードが呼び出されるたびに結果は異なる値になります。 しかし、この動作をどのように使えば、より大きな乱数を生成できるのでしょうか?
このプロセスを 4 回繰り返すと、次のような 2 進数の数列が生成されます。
$${0, 1, 1, 0}$$
これらのビットをビット文字列に連結 (結合) すると、より大きな数値を使用できます。 この例では、ビット シーケンス ${0110}$ は 10 進数の 6 に相当します。
$${0110_{\ 2 進} \equiv 6_{\ 10 進}}$$
このプロセスを何度も繰り返すと、複数のビットを組み合わせてあらゆる大きな数値を形成できます。 これで、その数値を安全なパスワードとして上司に提供できるようになりました。どんな宇宙のハッカーも連続する測定の結果を特定することはできないからです。
乱数ジェネレーターのロジックを定義する
ランダム ビット ジェネレーターがある場合、乱数ジェネレーターのロジックの概要を説明します。
- 生成する最大数として
max
を定義します。 - 生成する必要がある乱数ビットの数を定義します。 これは、
max
までの整数を表現するために必要なビット数nBits
を計算することによって行われます。 - 長さが
nBits
の乱数ビット文字列を生成します。 - ビット文字列が
max
より大きい数値を表す場合、ステップ 3 に戻ります。 - それ以外の場合、プロセスは終了です。 生成された数値を整数として返します。
例として、max
を 12 に設定します。 つまり、安全なパスワードとして使用する最大の数値は 12 になります。
0 から 12 までの数値を表すには、${\lfloor ln(12) / ln(2) + 1 \rfloor}$ ビット、つまり 4 ビットが必要です。 (簡潔にするために、この式の導出方法は省略します)。
たとえば、ビット文字列 ${1101_{\ binary}}$ を生成したとします。これは ${13_{\ decimal}}$ と等価です。 13 は 12 より大きいため、この処理を繰り返します。
次に、ビット文字列 ${0110_{\ binary}}$ を生成したとします。これは ${6_{\ decimal}}$ と等価です。 6 は 12 未満であるため、この処理を終了します。
量子乱数ジェネレーターは、パスワードとして数値 6 を返します。 実際には、最大としてより大きな数値を設定します。小さい数値だと、使用可能な全パスワードを試すだけで簡単に解読できるためです。 実際、パスワードの推測や解析をより困難にするために、ASCII コードを使用してバイナリをテキストに変換し、数字、記号、および大文字と小文字が混在した文字を使用してパスワードを生成することもできます。
ランダム ビット ジェネレーターを書き込む
最初の手順では、ランダム ビットを生成する Q# 操作を記述します。 この操作は、乱数ジェネレーターの構成要素の 1 つになります。
operation GenerateRandomBit() : Result {
// Allocate a qubit.
use q = Qubit();
// Set the qubit into superposition of 0 and 1 using the Hadamard
H(q);
// At this point the qubit `q` has 50% chance of being measured in the
// |0〉 state and 50% chance of being measured in the |1〉 state.
// Measure the qubit value using the `M` operation, and store the
// measurement value in the `result` variable.
let result = M(q);
// Reset qubit to the |0〉 state.
// Qubits must be in the |0〉 state by the time they are released.
Reset(q);
// Return the result of the measurement.
return result;
}
次に、新しいコードを見てみます。
GenerateRandomBit
操作を定義します。これには入力が不要であり、型Result
の値が生成されます。Result
型は測定の結果を表し、Zero
またはOne
の 2 つの値を使用できます。use
キーワードを使用して 1 つの量子ビットを割り当てます。 割り当て後、量子ビットは常にZero
状態になります。H
演算を使用して、量子ビットを等しい重ね合わせに配置します。M
演算を使用して量子ビットを測定し、測定値 (Zero
またはOne
) を返します。Reset
操作を使用して、量子ビットを |0〉 状態にリセットします。
H
操作を使用して量子ビットを重ね合わせに入れ、それを M
操作で測定することで、コードを呼び出すたびに結果は異なる値になります。
Bloch 球を使用して Q# コードを視覚化する
ブロッホ球では、北極は古典的な値 0 を表し、南極は古典的な値 1 を表します。 重ね合わせは球上の点で表わすことができます (矢印で表わされています)。 矢印の端が極に近づけば近づくほど、測定時、その極に割り当てられる古典的な値にキュービットがなる確率が高くなります。 たとえば、次の図の矢印で表わされているキュービットの状態では、測定したとき、値 0 が与えられる可能性が高くなります。
この表現を利用し、コードの動作を視覚化できます。
まず、状態 0 で初期化された量子ビットから始め、
H
操作を適用し、0 と 1 の確率が同じになる同等の重ね合わせを作成します。次に、量子ビットを測定し、出力を保存します。
測定の結果はランダムであり、0 と 1 を測定する確率が同じであるため、完全にランダムなビットを取得しています。 この操作を複数回呼び出し、整数を作成できます。 たとえば、操作を 3 回呼び出してランダム ビットを 3 つ取得する場合、ランダムの 3 ビット数 (つまり、0 から 7 までの乱数) を構築できます。
完全な乱数ジェネレーターを書き込む
まず、必要な Q# 名前空間をプログラムに追加する必要があります。 完全な乱数ジェネレーターには、
Microsoft.Quantum.Math
、Microsoft.Quantum.Intrinsic
、Microsoft.Quantum.Convert
の 3 つのQ#名前空間を含める必要があります。open Microsoft.Quantum.Convert; open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Math;
次に、
GenerateRandomNumberInRange
操作を定義します。 この演算はGenerateRandomBit
演算を繰り返し呼び出して、ビット文字列を構築します。/// Generates a random number between 0 and `max`. operation GenerateRandomNumberInRange(max : Int) : Int { // Determine the number of bits needed to represent `max` and store it // in the `nBits` variable. Then generate `nBits` random bits which will // represent the generated random number. mutable bits = []; let nBits = BitSizeI(max); for idxBit in 1..nBits { set bits += [GenerateRandomBit()]; } let sample = ResultArrayAsInt(bits); // Return random number if it is within the requested range. // Generate it again if it is outside the range. return sample > max ? GenerateRandomNumberInRange(max) | sample; }
少し時間を取って新しいコードを確認してみましょう。
- 最大
max
の整数を表現するために必要なビット数を計算する必要があります。Microsoft.Quantum.Math
名前空間のBitSizeI
関数は、整数を表すために必要なビット数に変換します。 SampleRandomNumberInRange
演算はfor
ループを使用して、max
以下の乱数を生成するまで乱数を生成します。for
ループは、他のプログラミング言語のfor
ループとまったく同じように動作します。- 変数
bits
は変更可能な変数です。 変更可能な変数は、計算中に変更できる変数です。set
ディレクティブを使用して、変更可能な変数の値を変更することができます。 ResultArrayAsInt
関数は、Microsoft.Quantum.Convert
名前空間から取得されます。 この関数は、ビット文字列を正の整数に変換します。
- 最大
最後に、エントリ ポイントを追加します。 この例では、
Main
操作はプログラムのエントリ ポイントです。GenerateRandomNumberInRange
操作を呼び出して、0 ~ 100 の乱数を生成します。@EntryPoint() operation Main() : Int { let max = 100; Message($"Sampling a random number between 0 and {max}: "); // Generate random number in the 0..max range. return GenerateRandomNumberInRange(max); }
let
ディレクティブは、計算中に変更されない変数を宣言します。 ここでは、最大値を 100 として定義します。乱数ジェネレーターの完全なコードは次のとおりです。
namespace QuantumRandomNumberGenerator {
open Microsoft.Quantum.Convert;
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Math;
@EntryPoint()
operation Main() : Int {
let max = 100;
Message($"Sampling a random number between 0 and {max}: ");
// Generate random number in the 0..max range.
return GenerateRandomNumberInRange(max);
}
/// Generates a random number between 0 and `max`.
operation GenerateRandomNumberInRange(max : Int) : Int {
// Determine the number of bits needed to represent `max` and store it
// in the `nBits` variable. Then generate `nBits` random bits which will
// represent the generated random number.
mutable bits = [];
let nBits = BitSizeI(max);
for idxBit in 1..nBits {
set bits += [GenerateRandomBit()];
}
let sample = ResultArrayAsInt(bits);
// Return random number if it is within the requested range.
// Generate it again if it is outside the range.
return sample > max ? GenerateRandomNumberInRange(max) | sample;
}
operation GenerateRandomBit() : Result {
// Allocate a qubit.
use q = Qubit();
// Set the qubit into superposition of 0 and 1 using the Hadamard
H(q);
// At this point the qubit `q` has 50% chance of being measured in the
// |0〉 state and 50% chance of being measured in the |1〉 state.
// Measure the qubit value using the `M` operation, and store the
// measurement value in the `result` variable.
let result = M(q);
// Reset qubit to the |0〉 state.
// Qubits must be in the |0〉 state by the time they are released.
Reset(q);
// Return the result of the measurement.
return result;
}
}
乱数ジェネレータープログラムを実行する
Copilot で Azure Quantum で、Visual Studio Code でスタンドアロン Q# アプリケーションとして、または Python ホスト プログラムを使用してプログラムを実行できます。
Azure Quantum の Copilot を使用して Q# コードを無料でテストできます。必要なのは、Microsoft (MSA) メール アカウントのみです。 Azure Quantum の Copilot の詳細については、「 Explore Azure Quantum」を参照してください。
ブラウザーで Azure Quantum で Copilot を開きます。
次のコードをコピーしてコード エディターに貼り付けます。
namespace Tutorial { open Microsoft.Quantum.Convert; open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Math; @EntryPoint() operation Main() : Int { let max = 100; Message($"Sampling a random number between 0 and {max}: "); // Generate random number in the 0..max range. return GenerateRandomNumberInRange(max); } /// # Summary /// Generates a random number between 0 and `max`. operation GenerateRandomNumberInRange(max : Int) : Int { // Determine the number of bits needed to represent `max` and store it // in the `nBits` variable. Then generate `nBits` random bits which will // represent the generated random number. mutable bits = []; let nBits = BitSizeI(max); for idxBit in 1..nBits { set bits += [GenerateRandomBit()]; } let sample = ResultArrayAsInt(bits); // Return random number if it is within the requested range. // Generate it again if it is outside the range. return sample > max ? GenerateRandomNumberInRange(max) | sample; } /// # Summary /// Generates a random bit. operation GenerateRandomBit() : Result { // Allocate a qubit. use q = Qubit(); // Set the qubit into superposition of 0 and 1 using the Hadamard // operation `H`. H(q); // At this point the qubit `q` has 50% chance of being measured in the // |0〉 state and 50% chance of being measured in the |1〉 state. // Measure the qubit value using the `M` operation, and store the // measurement value in the `result` variable. let result = M(q); // Reset qubit to the |0〉 state. // Qubits must be in the |0〉 state by the time they are released. Reset(q); // Return the result of the measurement. return result; // Note that Qubit `q` is automatically released at the end of the block. } }
実行するショットの数を選択し、 実行をクリックします。
結果はヒストグラムと Results フィールドに表示されます。
[ Explain code をクリックして、コードを説明するように Copilot に求めるメッセージを表示します。
Note
このコード スニペットは現在、使用可能な Azure Quantum ハードウェア targetsでは実行されません。呼び出し可能な ResultArrayAsInt
には、 完全な計算プロファイルを持つ QPU が必要です。
関連するコンテンツ
Q# のその他のチュートリアルを確認します。
- 量子エンタングルメント は、量子ビットを操作および測定し、重ね合わせとエンタングルメントの効果を示す Q# プログラムを記述する方法を示します。
- グローバーの検索アルゴリズム グローバーの検索アルゴリズムを使用する Q# プログラムを記述する方法を示します。
- Quantum フーリエ変換 では、特定の量子ビットに直接対処する Q# プログラムを記述する方法について説明します。
- Quantum Katasは、量子コンピューティングとQ#プログラミングの要素を同時に教えることを目的とした、自習型のチュートリアルとプログラミング演習です。