教學課程:在 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 關於量子運算的任何問題。
必要條件
若要在 Azure Quantum 的 Copilot 中執行程式代碼範例:
- Microsoft (MSA) 電子郵件帳戶。
若要在 Visual Studio Code 中開發和執行程式碼範例:
最新版的 Visual Studio Code 或開啟 Web 上的 VS Code。
最新版的 Azure Quantum Development Kit 擴充功能。 如需安裝詳細數據,請參閱 在 VS Code 上安裝新式 QDK。
如果您想要使用 Jupyter Notebook,您也需要安裝 Python 和 Jupyter 擴充功能,以及最新的
qsharp
Python 套件。 若要這樣做,請開啟終端機並執行下列命令:$ pip install --upgrade qsharp
定義問題
傳統電腦不會產生真正的亂數,而是產生出「偽亂數」。 偽亂數產生器會根據某個初始值 (稱為「種子」) 產生決定性的數字序列。 為了更精確地估計隨機值,此種子通常是 CPU 時鐘的目前時間。
另一方面,量子計算機可以產生真正的隨機數。 這是因為在迭加中測量量子位是一種可預測性程式。 測量的結果是隨機的,而且沒有任何方法可以預測結果。 這是量子隨機數產生器的基本準則。
量子位是可迭加的量子信息單位。 測量時,量子位元只能處於 0 的狀態或 1 的狀態。 但測量前,量子位元的狀態代表透過測量讀取到 0 或 1 的機率。
首先在基礎狀態(例如零)配置量子位元。 隨機數產生器的第一個步驟是使用 Hadamard 運算,將量子位放入相等迭加。 此狀態的測量會產生零個或一個機率為 50% 的每個結果,也就是真正的隨機位。
在迭加中測量量子位之後,無法得知您將取得的內容,而且每次叫用程式代碼時,結果都會是不同的值。 但是,如何使用此行為來產生較大的隨機數?
假設您重複該程序四次,產生此二進位數字序列:
$${0, 1, 1, 0}$$
如果您將這些位串連或結合成位元字串,則可以形成更大的數字。 在此範例中,位元序列 ${0110}$ 相當於十進位中的六。
$${0110_{\ binary} \equiv 6_{\ decimal}}$$
如果您多次重複此程式,便能結合多個位元來形成任何更大的數字。 現在您可以將該數字作為安全密碼提供給您的上司,因為您可以確定沒有任何的星際駭客能能判斷測量序列的結果。
定義亂數產生器邏輯
讓我們概述隨機數產生器的邏輯,前提是我們有隨機位產生器:
- 將
max
定義為您想要產生的最大數字。 - 定義您必須產生的隨機位元數目。 這是透過計算有多少位元 (
nBits
) 來完成,我們所需要表示整數的上限為max
。 - 產生長度為
nBits
的隨機位元字串。 - 如果位元字串代表的數字大於
max
,則回到步驟三。 - 否則,程序即完成。 以整數形式傳回產生的數字。
舉例來說,讓我們將 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
類型代表測量的結果,而且可以有兩個可能值:Zero
或One
。 - 您可以使用 關鍵詞來配置單一量子位
use
。 配置後,量子位元一律處於Zero
狀態。 - 您可以使用
H
作業將量子位放在相等迭加中。 - 您可以使用
M
作業來測量量子位、傳回測量值 (Zero
或One
) 。 - 您可以使用
Reset
作業將量子位重設為 |0} 狀態。
使用 H
作業在疊加中放置量子位元,並使用 M
作業測量,每次叫用程式碼時,結果都是不同的值。
使用 Bloch 球體將程式 Q# 代碼可視化
在布洛赫球體中,北極點代表古典值 0,而南極點代表古典值 1。 任何疊加都可以用球體上的點表示 (以箭頭表示)。 箭頭末端愈接近極點時,量子位元在測量時塌縮為指派給該極點的古典值的機率愈高。 例如,下圖箭頭表示的量子位元狀態,如經測量,即有較高的機率是指定的 0 值。
您可使用此圖示,以視覺化的方式呈現程式碼的作用:
首先,將量子位元初始化為 0 的狀態,然後套用
H
作業建立相等疊加,這時 0 和 1 的機率相同。接著測量量子位元並儲存輸出:
因為測量結果是隨機,且 0 和 1 測量的機率相同,所以您已取得完全隨機的位元。 您可以多次呼叫此作業建立整數。 例如,如果您呼叫此作業三次,取得三個隨機位元,即可建立隨機的 3 位元數字 (即介於 0 和 7 間的亂數)。
撰寫完整的隨機數產生器
首先,您必須將必要的 Q# 命名空間新增至程式。 針對完整的隨機數產生器,您必須包含三個 Q# 命名空間:
Microsoft.Quantum.Math
、Microsoft.Quantum.Intrinsic
和Microsoft.Quantum.Convert
。open Microsoft.Quantum.Convert; open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Math;
接下來,您要定義
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
命名空間。 此函式會將位元字串轉換成正整數。
- 您必須計算最多表示整數
最後,您會新增進入點。 在此範例中
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。隨機數產生器的完整程式碼如下所示:
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。
將下列程式代碼複製並貼到程式碼編輯器中。
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. } }
選取要執行的快照數目,然後按兩下 [ 執行]。
結果會顯示在直方圖和 [ 結果] 欄位中。
按兩下 [說明程式代碼 ] 以提示 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#程序設計的專案。
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應