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

已完成

在本單元中,您會實作量子亂數產生器的第二個階段:結合多個隨機位元來形成更大的隨機數字。 此階段是以您在上一個單元中建立的隨機位元產生器為基礎。

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

在上一個單元中,您已建立隨機位元產生器,其會產生隨機位元,方法是將量子位元放入疊加並加以測量。

當您測量量子位元時,您會收到 0 或 1 的隨機位元,機率等於 50%。 此位元的值是真正隨機的,我們無法知道測量之後將會得到哪個數值。 但是,您可以如何使用此行為來產生較大的亂數?

假設您重複該程序四次,產生此二進位數字序列:

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

如果您將這些位串連或結合成位元字串,則可以形成更大的數字。 在此範例中,位元序列 ${0110}$ 相當於十進位中的六。

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

如果您多次重複此程式,便能結合多個位元來形成任何更大的數字。

定義亂數產生器邏輯

首先來概述亂數產生器應有的邏輯,假設在前一個單元中已建立隨機位元產生器:

  1. max 定義為您想要產生的最大數字。
  2. 定義您要產生的隨機位元數目,方法是計算若要表達最多 max 的整數所需的位元 nBits
  3. 產生長度為 nBits 的隨機位元字串。
  4. 如果位元字串代表的數字大於 max,則回到步驟三。
  5. 否則,程序即完成。 以整數形式傳回產生的數字。

舉例來說,讓我們將 max 設定為 12。 也就是說,12 是您想要從隨機數產生器取得的最大數。

您需要 ${\lfloor ln(12) / ln(2) + 1 \rfloor}$,或 4 位元來表示 0 與 12 之間的每個數字。 (為求簡單明瞭,我們會略過得到此方程式的方法。)

假設您產生位元字串 ${1101_{\ binary}}$,這相當於 ${13_{\ decimal}}$。 因為 13 大於 12,所以您重複該程序。

接下來,您產生位元字串 ${0110_{\ binary}}$,這相當於 ${6_{\ decimal}}$。 因為 6 小於 12,所以程序完成。

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

建立完整的隨機數產生器

在這裡,您可以展開 Main.qs 檔案以建立較大的隨機數。

匯入必要的程式庫

首先,您必須將所需的命名空間從 Q# Standard 連結庫匯入程式。 Q# 編譯程式會自動載入許多常見的函式和作業,不過針對完整的量子隨機數產生器,您需要兩個 Q# 命名空間的一些額外函式和作業: Microsoft.Quantum.MathMicrosoft.Quantum.Convert

將下列 import 指示詞複製並貼到 Main.qs 檔案頂端:

import Microsoft.Quantum.Convert.*;
import Microsoft.Quantum.Math.*;

Main 作業重新命名為 GenerateRandomBit

針對完整的隨機數產生器,您將重複使用上一個單元中定義的作業。 不過,作業名稱 Main 是程式的進入點,而且應該是唯一的。 若要避免混淆,您必須將 Main 作業重新命名為 GenerateRandomBit

GenerateRandomBit 作業看起來應該像這樣:

    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 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 程式庫。 此函式會將位元字串轉換成正整數。

新增輸入點

最後,您會將進入點新增至程式。 根據預設,無論作業位於何處,Q# 編譯流程會尋找 Main 作業並開始處理該作業。 作業會 Main 呼叫 GenerateRandomNumberInRange 作業,以產生介於 0 與 max 數字之間的隨機數。 在此範例中,您會將最大值定義為 100。

將下列程式碼複製並貼到 Main.qs 檔案中:

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

最終程式

您的 Main.qs 檔案看起來應該像這樣:

import Microsoft.Quantum.Convert.*;
import Microsoft.Quantum.Math.*;

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

執行程式

讓我們試試新的亂數產生器!

  1. 在執行程式之前,您必須將目標設定檔設為 [不受限制]。 選取 [檢視]>[命令選擇區]、搜尋 QIR,然後選取 [Q#:設定 Azure Quantum QIR 目標設定檔],然後選取 [Q#:不受限制]
  2. 若要執行程式,請從 Main 作業上方命令清單中選取 [執行],或按 Ctrl+F5。 您的輸出會出現在偵錯控制台中。
  3. 再次執行程式以查看不同的結果。

注意

如果目標設定檔未設定為 [不受限制],當您執行程式時會收到錯誤。

恭喜! 現在,您已經知道如何結合傳統邏輯與 Q# 來建立量子亂數產生器。

額外練習

嘗試將程式修改為也要求產生的亂數大於最小數字 min,而不是零。