教學課程:在 Q# 中實作量子亂數產生器

注意

2024 年 6 月 30 日之後,將不再支援 Microsoft Quantum Development Kit (傳統 QDK) 。 如果您是現有的 QDK 開發人員,建議您轉換至新的 Azure Quantum Development Kit (Modern QDK) ,以繼續開發量子解決方案。 如需詳細資訊,請參閱 將您的程式 Q# 代碼移轉至新式 QDK

了解如何在 Q# 中撰寫基本的量子程式,利用量子機制的本質產生亂數。

在本教學課程中,您將:

  • Q#Create 程式。
  • 檢閱程式的主要元件 Q# 。
  • 定義問題的邏輯。
  • 結合傳統和量子運算來解決問題。
  • 使用量子位元與疊加來建置量子亂數產生器。

提示

如果您想要加速量子運算旅程,請參閱 使用 Azure Quantum 撰寫程式代碼這是 Azure Quantum 網站的獨特功能。 在這裡,您可以執行內 Q# 建範例或自己的 Q# 程式、從提示產生新的 Q# 程式代碼、在 VS Code for the Web 中開啟並執行程式碼,按下即可詢問 Copilot 關於量子運算的任何問題。

必要條件

定義問題

傳統電腦不會產生真正的亂數,而是產生出「偽亂數」。 偽亂數產生器會根據某個初始值 (稱為「種子」) 產生決定性的數字序列。 為了更精確地估計隨機值,此種子通常是 CPU 時鐘的目前時間。

另一方面,量子計算機可以產生真正的隨機數。 這是因為在迭加中測量量子位是一種可預測性程式。 測量的結果是隨機的,而且沒有任何方法可以預測結果。 這是量子隨機數產生器的基本準則。

量子位是可迭加的量子信息單位。 測量時,量子位元只能處於 0 的狀態或 1 的狀態。 但測量前,量子位元的狀態代表透過測量讀取到 01機率

首先在基礎狀態(例如零)配置量子位元。 隨機數產生器的第一個步驟是使用 Hadamard 運算,將量子位放入相等迭加。 此狀態的測量會產生零個或一個機率為 50% 的每個結果,也就是真正的隨機位。

在迭加中測量量子位之後,無法得知您將取得的內容,而且每次叫用程式代碼時,結果都會是不同的值。 但是,如何使用此行為來產生較大的隨機數?

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

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

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

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

如果您多次重複此程式,便能結合多個位元來形成任何更大的數字。 現在您可以將該數字作為安全密碼提供給您的上司,因為您可以確定沒有任何的星際駭客能能判斷測量序列的結果。

定義亂數產生器邏輯

讓我們概述隨機數產生器的邏輯,前提是我們有隨機位產生器:

  1. max 定義為您想要產生的最大數字。
  2. 定義您必須產生的隨機位元數目。 這是透過計算有多少位元 (nBits) 來完成,我們所需要表示整數的上限為 max
  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 作為密碼。 在實務上,通常會將較大的數字設定為最大值,因為只要嘗試所有可能的密碼,就能輕鬆破解較小的數字。 事實上,若要提高猜測或破解密碼的困難,您可以使用 ASCII 碼將二進位碼轉換成文字,並使用數字、符號和混合大小寫字母來產生密碼。

寫入隨機位產生器

第一個步驟是撰寫 Q# 產生隨機位的作業。 這項作業將是隨機數產生器的其中一個建置組塊。

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 類型代表測量的結果,而且可以有兩個可能值:ZeroOne
  • 您可以使用 關鍵詞來配置單一量子位 use 。 配置後,量子位元一律處於 Zero 狀態。
  • 您可以使用 H 作業將量子位放在相等迭加中。
  • 您可以使用 M 作業來測量量子位、傳回測量值 (ZeroOne) 。
  • 您可以使用 Reset 作業將量子位重設為 |0} 狀態。

使用 H 作業在疊加中放置量子位元,並使用 M 作業測量,每次叫用程式碼時,結果都是不同的值。

使用 Bloch 球體將程式 Q# 代碼可視化

在布洛赫球體中,北極點代表古典值 0,而南極點代表古典值 1。 任何疊加都可以用球體上的點表示 (以箭頭表示)。 箭頭末端愈接近極點時,量子位元在測量時塌縮為指派給該極點的古典值的機率愈高。 例如,下圖箭頭表示的量子位元狀態,如經測量,即有較高的機率是指定的 0 值。

此圖顯示具有高機率測量零的量子位狀態。

您可使用此圖示,以視覺化的方式呈現程式碼的作用:

  1. 首先,將量子位元初始化為 0 的狀態,然後套用 H 作業建立相等疊加,這時 01 的機率相同。

    此圖顯示藉由套用 hadamard 閘道來準備迭加中的量子位。
  2. 接著測量量子位元並儲存輸出:

    顯示量子位測量和儲存輸出的圖表。

因為測量結果是隨機,且 01 測量的機率相同,所以您已取得完全隨機的位元。 您可以多次呼叫此作業建立整數。 例如,如果您呼叫此作業三次,取得三個隨機位元,即可建立隨機的 3 位元數字 (即介於 0 和 7 間的亂數)。

撰寫完整的隨機數產生器

  1. 首先,您必須將必要的 Q# 命名空間新增至程式。 針對完整的隨機數產生器,您必須包含三個 Q# 命名空間: Microsoft.Quantum.MathMicrosoft.Quantum.IntrinsicMicrosoft.Quantum.Convert

    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.MathBitSizeI式會將整數轉換成表示它所需的位數。
    • 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 標誌按鈕,在 Web 的 VS Code 中開啟程式。

注意

此代碼段目前不會在任何可用的 Azure Quantum 硬體 targets上執行,因為可 ResultArrayAsInt 呼叫者需要具有 完整計算配置檔的 QPU。

後續步驟

探索其他 Q# 教學課程:

  • 量子糾纏 示範如何撰寫 Q# 可操作和測量量子位的程式,並示範迭加和糾纏的效果。
  • Grover 的搜尋演算法 示範如何撰寫 Q# 使用 Grover 搜尋演算法的程式。
  • Quantum Fourier Transforms 會探索如何撰寫 Q# 直接解決特定量子位的程式。
  • Quantum Katas 是自我步調教學課程和程序設計練習,旨在同時教學量子運算和Q#程序設計的專案。