チュートリアル: Q# で量子乱数ジェネレーターを実装する

注意

Microsoft Quantum Development Kit (クラシック QDK) は、2024 年 6 月 30 日以降はサポートされなくなります。 既存の QDK 開発者の場合は、量子ソリューションの開発を続けるために、新しい Azure Quantum Development Kit (モダン QDK) に移行することをお勧めします。 詳細については、「 コードを Q# モダン QDK に移行する」を参照してください。

量子力学の性質を活用して乱数を生成する基本的な量子プログラムを Q# で作成する方法について学習します。

このチュートリアルでは、次のことについて説明します。

  • プログラムをCreateしますQ#。
  • プログラムのメインコンポーネントをQ#確認します。
  • 問題のロジックを定義します。
  • 古典的操作と量子演算を組み合わせて問題を解決します。
  • 量子ビットと重ね合わせを使用して、量子乱数ジェネレーターを構築します。

ヒント

量子コンピューティングの取り組みを加速する場合は、Azure Quantum Web サイトのユニークな機能である Azure Quantum を使用してコードをチェックします。 ここでは、組み込みのサンプルまたは独自Q#のQ#プログラムを実行し、プロンプトから新しいQ#コードを生成し、ワンクリックで VS Code for the Web でコードを開いて実行し、Copilot に量子コンピューティングについて質問することができます。

前提条件

  • Azure Quantum の Copilot でコード サンプルを実行するには:

    • Microsoft (MSA) メール アカウント。
  • Visual Studio Code でコード サンプルを開発して実行するには、

問題の定義

従来のコンピューターでは、乱数ではなく、"擬似乱数" が生成されます。 擬似乱数ジェネレーターでは、"シード" と呼ばれる初期値に基づいて、決定論的な数列が生成されます。 ランダムな値に近づけるために、このシードは CPU のクロックの現在時刻になることがよくあります。

一方、量子コンピューターは真に乱数を生成できます。 これは、重ね合わせでの量子ビットの測定は確率論的プロセスであるためです。 測定の結果はランダムであり、結果を予測する方法はありません。 これは、量子乱数ジェネレーターの基本的な原則です。

量子ビットは、重ね合わせにできる量子情報の単位です。 測定された場合、量子ビットは 0 の状態または 1 の状態のいずれかになります。 ただし測定の前において、量子ビットの状態は測定で 0 または 1 を読み取る ”可能性” を表わします。

まず、0 などの基礎状態で量子ビットを取得します。 乱数ジェネレーターの最初のステップは、Hadamard 演算を使用して量子ビットを等しい重ね合わせに配置することです。 この状態を測定すると、各結果の確率が 50% (真にランダムなビット) の 0 または 1 になります。

重ね合わせでの量子ビットの測定後に何が得られるかを知る方法はなく、コードが呼び出されるたびに結果は異なる値になります。 しかし、この動作を使用して、より大きな乱数を生成するにはどうすればよいですか?

このプロセスを 4 回繰り返すと、次のような 2 進数の数列が生成されます。

$${0, 1, 1, 0}$$

これらのビットをビット文字列に連結 (結合) すると、より大きな数値を使用できます。 この例では、ビット シーケンス ${0110}$ は 10 進数の 6 に相当します。

$${0110_{\ 2 進} \equiv 6_{\ 10 進}}$$

このプロセスを何度も繰り返すと、複数のビットを組み合わせてあらゆる大きな数値を形成できます。 これで、その数値を安全なパスワードとして上司に提供できるようになりました。どんな宇宙のハッカーも連続する測定の結果を特定することはできないからです。

乱数ジェネレーターのロジックを定義する

ランダム ビット ジェネレーターがある場合、乱数ジェネレーターのロジックの概要を説明します。

  1. 生成する最大数として max を定義します。
  2. 生成する必要がある乱数ビットの数を定義します。 これは、max までの整数を表現するために必要なビット数 nBits を計算することによって行われます。
  3. 長さが nBits の乱数ビット文字列を生成します。
  4. ビット文字列が max より大きい数値を表す場合、ステップ 3 に戻ります。
  5. それ以外の場合、プロセスは終了です。 生成された数値を整数として返します。

例として、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 つの値を使用できます。
  • キーワード (keyword)を使用して 1 つの量子ビットをuse割り当てます。 割り当て後、量子ビットは常に Zero 状態になります。
  • 演算を H 使用して、量子ビットを等しい重ね合わせに配置します。
  • 演算を M 使用して量子ビットを測定し、測定値 (Zero または One) を返します。
  • 操作を Reset 使用して、量子ビットを |0〉 状態にリセットします。

H 操作を使用して量子ビットを重ね合わせに入れ、それを M 操作で測定することで、コードを呼び出すたびに結果は異なる値になります。

Bloch 球を Q# 使用してコードを視覚化する

ブロッホ球では、北極は古典的な値 0 を表し、南極は古典的な値 1 を表します。 重ね合わせは球上の点で表わすことができます (矢印で表わされています)。 矢印の端が極に近づけば近づくほど、測定時、その極に割り当てられる古典的な値にキュービットがなる確率が高くなります。 たとえば、次の図の矢印で表わされているキュービットの状態では、測定したとき、値 0 が与えられる可能性が高くなります。

ゼロを測定する確率が高い量子ビット状態を示す図。

この表現を利用し、コードの動作を視覚化できます。

  1. まず、状態 0 で初期化された量子ビットから始め、H 操作を適用し、01 の確率が同じになる同等の重ね合わせを作成します。

    hadamard ゲートを適用した重ね合わせでの量子ビットの準備を示す図。
  2. 次に、量子ビットを測定し、出力を保存します。

    量子ビットの測定と出力の保存を示す図。

測定の結果はランダムであり、01 を測定する確率が同じであるため、完全にランダムなビットを取得しています。 この操作を複数回呼び出し、整数を作成できます。 たとえば、操作を 3 回呼び出してランダム ビットを 3 つ取得する場合、ランダムの 3 ビット数 (つまり、0 から 7 までの乱数) を構築できます。

完全な乱数ジェネレーターを記述する

  1. まず、必要な名前空間をプログラムに追加する必要 Q# があります。 完全な乱数ジェネレーターの場合は、および Microsoft.Quantum.Convertの 3 つのQ#名前空間をMicrosoft.Quantum.MathMicrosoft.Quantum.Intrinsic含める必要があります。

    open Microsoft.Quantum.Convert;
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Math;
    
  2. 次に、操作を定義します 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 。 この関数は、ビット文字列を正の整数に変換します。
  3. 最後に、エントリ ポイントを追加します。 この例では、 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 として定義します。

  4. 乱数ジェネレーターの完全なコードは次のとおりです。

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

乱数ジェネレータープログラムを実行する

このプログラムは、 Azure Quantum の Copilot で、Visual Studio Code ではスタンドアロン Q# アプリケーションとして実行することも、Python ホスト プログラムを使用して実行することもできます。

コードは、Azure Quantum の Copilot で無料でテスト Q# できます。必要なのは Microsoft (MSA) のメール アカウントです。 Azure Quantum の Copilot の詳細については、「Azure Quantum の 探索」を参照してください。

  1. ブラウザーで Azure Quantum で Copilot を開きます。

  2. 次のコードをコピーしてコード エディターに貼り付けます。

    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.
        }
    }
    
  3. 実行するショットの数を選択し、[ 実行] をクリックします。

  4. 結果はヒストグラムと [結果 ] フィールドに表示されます。

  5. [ コードの説明 ] をクリックして、コードを説明するように Copilot に求めるメッセージを表示します。

ヒント

Azure Quantum の Copilot から、コード エディターの右上隅にある [VS Code ロゴ] ボタンをクリックして、VS Code for the Web でプログラムを開くことができます。

注意

呼び出し可能には完全な計算プロファイルを持つ QPU が必要なため、このコード スニペットは現在、使用可能な ResultArrayAsInt Azure Quantum ハードウェアtargetsでは実行されません。

次のステップ

Q# のその他のチュートリアルを確認します。