演習 - 量子乱数ジェネレーターを作成する

完了

このユニットでは、量子乱数ジェネレーターの第 2 フェーズを実装します。つまり、複数の乱数ビットを組み合わせて、より大きな乱数を形成します。 このフェーズは、既に作成した乱数ビット ジェネレーターに基づいています。 このフェーズでは、いくつかの古典的なコードを記述する必要があります。

Q# で従来のコードを記述することはできますか。

はい、できます。 量子コンピューターは特殊なタスクを実行します。 多くのタスクは従来のコンピューターで十分に動作するため、あらゆる用途に量子コンピューターを使用することはありません。

グラフィックス処理装置 (GPU) やその他の特殊なハードウェアと同じように、量子コンピューターは最も相応しいタスクに使用する必要があります。 この場合は単に乱数ビットを生成します。

このため、Q# では、既に知られているプログラミング言語に似た従来のコードが記述できるようになっています。

Q# の機能を使って完全な乱数ジェネレーターを構築する方法を見てみましょう。

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

前のユニットで乱数ビット ジェネレーターを構築したという前提で、乱数ジェネレーターのロジックがどうあるべきかの概要について説明します。

  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 を返します。

完全な乱数ジェネレーターを作成する

ここでは、RandomNumberGenerator.qs ファイルを拡張して、より大きな乱数を構築します。

必要なライブラリを追加する

完全な乱数ジェネレーターを使うには、Microsoft.Quantum.MathMicrosoft.Quantum.IntrinsicMicrosoft.Quantum.Convert の 3 つの Q# ライブラリを含める必要があります。 以下のように、次の open ディレクティブを RandomNumberGenerator.qs に追加します。

namespace QuantumRandomNumberGenerator {
open Microsoft.Quantum.Convert;
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Math;

// The rest of the code goes here.

}

量子乱数演算を定義する

ここでは、GenerateRandomNumberInRange 演算を定義します。 この演算は GenerateRandomBit 演算を繰り返し呼び出して、ビット文字列を構築します。

次のように RandomNumberGenerator.qs を変更します。

namespace QuantumRandomNumberGenerator {
    open Microsoft.Quantum.Convert;
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Math;

    /// 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 関数は、整数を、その表現に必要なビット数に変換します。
  • GenerateRandomNumberInRange 演算は for ループを使用して、max 以下の乱数を生成するまで乱数を生成します。 for ループは、他のプログラミング言語の for ループとまったく同じように動作します。
  • 変数 bits は変更可能な変数です。 変更可能な変数は、計算中に変更できる変数です。 set ディレクティブを使用して、変更可能な変数の値を変更することができます。
  • ResultArrayAsInt 関数は Microsoft.Quantum.Convert ライブラリに付属しています。 この関数は、ビット文字列を正の整数に変換します。

エントリ ポイントを定義する

プログラムで乱数を生成できるようになりました。 ここでは、プログラムのエントリ ポイントを定義します。

RandomNumberGenerator.qs ファイルを次のように変更します。

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

let ディレクティブは、計算中に変更されない変数を宣言します。 学習の目的上、ここでは最大値を 100 として定義します。

Note

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

プログラムを実行する

新しい乱数ジェネレーターを試してみましょう。

  1. プログラムを実行する前に、ターゲット プロファイルを "無制限" に設定する必要があります。 [表示] -> [コマンド パレット] を選び、QIR を検索して、[Q#:Azure Quantum QIR ターゲット プロファイルの設定] を選び、次に [Q#: 無制限] を選びます。
  2. 組み込みのシミュレーターでプログラムをローカルにテスト実行するには、右上隅の再生アイコン ドロップダウンから [Q# ファイルの実行] を選ぶか、Ctrl + F5 キーを押します。 出力がデバッグ コンソールに表示されます。
  3. プログラムを再度実行すると、異なる結果が表示されます。

Note

ターゲット プロファイルが "無制限" に設定されていない場合、プログラムを実行するとエラーが発生します。

お疲れさまでした。 これで、従来のロジックを Q# と組み合わせて、量子乱数ジェネレーターを作成する方法がわかりました。

ボーナス演習

生成される乱数が、ゼロではなく特定の最小値 min よりも大きくなる必要があるようにプログラムを変更してください。