練習 (第 2 部分) - 建立量子亂數產生器

已完成

在本單元中,您將實作量子隨機數產生器的第二部分。 您可以組合多個隨機位元以形成更大的隨機數。 此部分建立在您在上一個單元中已建立的隨機位元產生器之上。

結合多個隨機位元以形成較大的數字

在上一個單元中,您建立了一個隨機位元生成器,將量子位元置於量子疊加狀態,然後測量該量子位元以生成隨機位元值,可能是 0 或 1,每种結果的機率均為 50%。 該位的值確實是隨機的,無法提前知道測量結果是什麼。 但是,您可以如何使用此行為來產生較大的亂數?

如果您重複此程序四次,則可能會產生下列二進位數字序列:

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

如果將這些位組合成一個位串,那麼您可以形成一個更大的數字。 在此範例中,二進位的位序列 ${0110}$ 相當於十進位的數字 6。

$${0110_{\ binary} \equiv 6_{\ decimal}}$$

要產生任意大的隨機數,只需重複此過程多次即可。 然後,將所有位元組合成一個二進位數,並將該二進位數轉換為十進位數。

定義亂數產生器邏輯

在撰寫 Q# 程式碼之前,讓我們先概述產生隨機數的邏輯:

  1. 定義 max 為您要產生的最大十進位數。
  2. 確定產生max所需的nBits隨機位元數。
  3. 產生長度為 nBits 的隨機位元字串。
  4. 如果位字串代表大於 max的數字,則返回上一步。
  5. 否則,程序即完成。 將產生的數字傳回為十進位整數。

例如,讓我們定義 max 為 12。 也就是說,12 是隨機數產生器應輸出的最大數字。

使用下列方程式來判斷以二進位表示數字 12 所需的位元數:

$${\lfloor ln(12) / ln(2) + 1 \rfloor}$$

根據這個方程,您需要 4 位來表示 0 到 12 之間的數字。

例如,假設您產生隨機位元四次,並取得位元字串 ${1101_{\ binary}}$。 此二進位值等於十進位數的 13。 因為 13 大於 12,所以您重複該程序。

接下來,您產生位字串 ${0110_{\ 二進位}}$,它等於 ${6_{\ 十進制}}$。 因為 6 小於 12,所以程序完成。

量子隨機數產生器會傳回數位 6。

在 Q 中創建一個完整的隨機數生成器#

在這裡,您將擴展 Main.qs 上一課中的文件以構建您的隨機數生成器。

匯入必要的程式庫

首先,從 Q# 標準程式庫匯入命名空間,其中包含撰寫程式所需的函式和作業。 Q# 編譯器會自動載入許多常見的函式和作業。 但針對量子隨機數產生器,您需要兩個 Q# 命名空間的一些其他函式和作業: Microsoft.Quantum.MathMicrosoft.Quantum.Convert

將下列import指示詞複製並貼上至您的Main.qs檔案開頭:

import Std.Convert.*;
import Std.Math.*;

注意

您可以使用 Std 代替 Microsoft.Quantum 從標準程式庫匯入函數和操作。

Main 作業重新命名為 GenerateRandomBit

隨機數產生器程式使用您在上一個單元中編寫的運算來 Main 產生隨機位元。 將作業重新命名 Main 為 , GenerateRandomBit 讓此作業具有更具描述性的名稱,而且不是程式的進入點。

將以下程式碼複製並貼上到 Main.qs

import Std.Convert.*;
import Std.Math.*;

operation GenerateRandomBit() : Result {
    // Allocate a qubit.
    use q = Qubit();
    
    // Set the qubit into superposition of 0 and 1 using the Hadamard 
    H(q);
    
    // Measure the qubit and store the result.    
    let result = M(q);
    
    // Reset qubit to the |0〉 state.
    Reset(q);
    
    // Return the result of the measurement.
    return result;
}

定義隨機數產生器作業

建立名為 GenerateRandomNumberInRange的新作業。 此作業會重複呼叫 GenerateRandomBit 作業,以建立位元字串。

複製下列程式碼,並將其直接放在 GenerateRandomBit 操作之前的 Main.qs 檔案中。

/// 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's within the requested range.
    // Generate it again if it's outside the range.
    return sample > max ? GenerateRandomNumberInRange(max) | sample;
}

以下是程式碼 GenerateRandomNumberInRange的概述:

  • Std.Math 函式庫中呼叫 BitSizeI 函式來計算表示儲存在 max 中的整數所需的位元數。
  • 使用 for 迴圈來產生等於 nBits 的隨機位數。 呼叫您的 GenerateRandomBit 作業來產生隨機位元。
  • for 的循環中,使用 set 語句將 bits 變數更新為每個新的隨機位元。 變數 bits 是可變變量,這意味著 的 bits 值可以在計算過程中發生變化。
  • Std.Convert函式庫呼叫ResultArrayAsInt函數,將bits中的位元陣列轉換為儲存在sample的正整數。
  • 在陳述式中 return ,檢查 sample 是否大於 max。 如果 sample 大於 max,則再次呼叫 GenerateRandomNumberInRange 並重新開始。 否則,傳回儲存在 sample中的隨機數。

新增輸入點

最後,將入口點操作新增至程式碼,以便編譯器可以執行您的程式。 根據預設,Q# 編譯器會尋找 Main 作業,並用 Main 作為進入點,無論 Main 位於檔案的何處。 在這裡,操作將一個值設定為 max,並呼叫 GenerateRandomNumberInRange 操作以產生一個介於 0 和 max之間的隨機數。

例如,若要產生 0 到 100 之間的隨機數,請將下列程式碼複製到檔案 Main.qs 中:

operation Main() : Int {
    let max = 100;
    Message($"Generating a random number between 0 and {max}: ");

    // Generate random number in the 0..max range.
    return GenerateRandomNumberInRange(max);
}

最終程式

以下是您在 Main.qs 中的程式的完整 Q# 程式碼:

import Std.Convert.*;
import Std.Math.*;

operation Main() : Int {
    let max = 100;
    Message($"Generating 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's within the requested range.
    // Generate it again if it's 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);
    
    // 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.
    Reset(q);
    
    // Return the result of the measurement.
    return result;
}

執行程式

試試您的新量子隨機數生成器!

若要執行您的程式,請從 Main 作業上方的命令清單中選擇 Run 程式碼鏡頭。 或者,按 Ctrl + F5。 您的輸出會顯示在偵錯控制台中。 多次運行該程序並注意結果如何變化。

恭喜! 您在 Q# 中建立了真正的隨機量子數產生器。

額外練習

嘗試修改程序,使其也要求產生的隨機數大於某個最小正數, min而不是零。