共用方式為


教學課程:在 中實作 Quantum Fourier 轉換 Q#

本教學課程說明如何撰寫和模擬在個別量子位上運作的基本量子程式。

雖然 Q# 主要是建立為大規模量子程式的高階程序設計語言,但它也可以用來探索較低層級的量子程序設計,也就是直接尋址特定的量子位。 具體而言,本教學課程會進一步瞭解 Quantum Fourier Transform (QFT),這是許多較大量子演算法不可或缺的子程式。

在本教學課程中,您將了解如何:

  • 在中 Q#定義量子作業。
  • 撰寫 Quantum Fourier 轉換線路
  • 模擬量子位配置到測量輸出的量子運算。
  • 觀察量子系統的模擬 wavefunction 在整個作業中如何演進。

注意

這個較低層級的量子資訊處理檢視通常描述於量子電路這代表系統特定量子位的循序應用網關或作業。 因此,您循序套用的單一和多量子位作業可以在電路圖中輕鬆表示。 例如,本教學課程中使用的完整三量子四進位量子轉換具有下列表示法作為線路: Quantum Fourier 轉換線路的圖表。

提示

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

必要條件

建立新 Q# 檔案

  1. 在 VS Code 中,選取 [ 檔案 > 新文本檔]
  2. 將檔案儲存為 QFTcircuit.qs。 此檔案將包含 Q# 程式的程序代碼。
  3. 開啟 QFTcircuit.qs

在中寫入 QFT 線路 Q#

本教學課程的第一個部分是由定義 Q# 作業 Main所組成,其會在三個量子位上執行量子 Fourier 轉換。 函 DumpMachine 式可用來觀察三量子位系統的模擬 wavefunction 如何在整個作業中演進。 在本教學課程的第二個部分中,您將新增測量功能,並比較量子位的測量前和後置狀態。

您將逐步建置作業。 將下列各節中的程式代碼複製並貼到 QFTcircuit.qs 檔案中。

您可以檢視 此區段的完整 Q# 程式代碼 作為參考。

匯入必要的 Q# 連結庫

在您的 Q# 檔案內,匯入相關的 Microsoft.Quantum.* 命名空間。

import Microsoft.Quantum.Diagnostics.*;
import Microsoft.Quantum.Math.*;
import Microsoft.Quantum.Arrays.*;

// operations go here

使用自變數和傳回定義作業

接下來,定義 Main 作業:

operation Main() : Unit {
    // do stuff
}

作業 Main() 永遠不會接受自變數,而且現在會傳回 Unit 物件,這類似於在 C# 或 Python 中傳回 void 空的 Tuple Tuple[()]。 稍後,您將修改作業以傳回度量結果的陣列。

配置量子位

在作業中 Q# ,使用 關鍵詞配置三個量子位的 use 緩存器。 使用 use時,量子位會自動以 $\ket{0}$ 狀態配置。

use qs = Qubit[3]; // allocate three qubits

Message("Initial state |000>:");
DumpMachine();

如同實際的量子計算, Q# 不允許您直接存取量子位狀態。 不過,此 DumpMachine 作業會 target 列印機器的目前狀態,因此當與完整狀態模擬器搭配使用時,它可以提供偵錯和學習的寶貴見解。

套用單一量子位和受控制作業

接下來,您會套用組成作業本身的 Main 作業。 Q# 已在命名空間中包含 Microsoft.Quantum.Intrinsic 其中許多基本量子作業。

注意

請注意, Microsoft.Quantum.Intrinsic 未在其他命名空間的先前代碼段中匯入,因為編譯程式會自動載入所有 Q# 程式。

套用的第一個作業是第 H 一個量子位的 (Hadamard) 作業:

此圖顯示三個量子位 QFT 到第一個 Hadamard 的線路。

若要將作業套用至緩存器中的特定量子位(例如數位中的Qubit[]Qubit一 ),請使用標準索引表示法。 因此,將 H 作業套用至緩存器 qs 的第一個量子位會採用下列格式:

H(qs[0]);

除了將 H 作業套用至個別量子位之外,QFT 線路主要包含受控 R1 旋轉。 一 R1(θ, <qubit>) 般作業會將量子位的 $\ket{0}$ 元件維持不變,同時將$e^{i\theta}$ 的旋轉套用至 $\ket{1}$ 元件。

Q# 可讓您輕鬆地在一或多個控制量子位上設定作業執行的條件。 一般而言,呼叫前面會加上 Controlled,而作業自變數會變更,如下所示:

Op(<normal args>) $\to$ Controlled Op([<control qubits>], (<normal args>))

請注意,控件量子位自變數必須是數位,即使它適用於單一量子位也一樣。

QFT 中的受控制作業是 R1 針對第一個量子位執行的作業(並由第二個和第三個量子位控制):

此圖顯示三個量子位 Quantum Fourier 轉換到第一個量子位的電路。

在您的 Q# 檔案中,使用下列語句呼叫這些作業:

Controlled R1([qs[1]], (PI()/2.0, qs[0]));
Controlled R1([qs[2]], (PI()/4.0, qs[0]));

PI() 式用來定義 pi 弧度的旋轉。

套用 SWAP 作業

將相關 H 作業和受控制的旋轉套用至第二和第三個量子位之後,線路看起來會像這樣:

//second qubit:
H(qs[1]);
Controlled R1([qs[2]], (PI()/2.0, qs[1]));

//third qubit:
H(qs[2]);

最後,您會將作業套用至第一個和第三個 SWAP 量子位,以完成線路。 這是必要的,因為量子 Fourier 轉換的本質會以反向順序輸出量子位,因此交換允許將子程式無縫整合至較大的演算法。

SWAP(qs[2], qs[0]);

現在,您已完成將量子 Fourier 轉換的量子位層級作業寫入您的 Q# 作業:

此圖顯示三個量子位 Quantum Fourier 轉換的電路。

解除分配量子位

最後一個步驟是再次呼叫 DumpMachine() 以查看作業后狀態,以及解除分配量子位。 當您配置量子位時,量子位處於 $\ket{0}$ 狀態,且需要使用作業重設為其初始狀態 ResetAll

要求將所有量子位明確重設為 $\ket{0}$ 是 的基本功能 Q#,因為它可讓其他作業在開始使用這些相同量子位(稀缺資源)時精確地知道其狀態。 此外,這可確保它們不會與系統中的任何其他量子位糾纏。 如果未在配置區塊結尾 use 執行重設,可能會擲回運行時錯誤。

將下列幾行新增至您的 Q# 檔案:

Message("After:");
DumpMachine();

ResetAll(qs); // deallocate qubits

完整的 QFT 作業

程式 Q# 已完成。 您的 QFTcircuit.qs 檔案現在看起來應該像這樣:

import Microsoft.Quantum.Diagnostics.*;
import Microsoft.Quantum.Math.*;
import Microsoft.Quantum.Arrays.*;

operation Main() : Unit {

    use qs = Qubit[3]; // allocate three qubits

    Message("Initial state |000>:");
    DumpMachine();

    //QFT:
    //first qubit:
    H(qs[0]);
    Controlled R1([qs[1]], (PI()/2.0, qs[0]));
    Controlled R1([qs[2]], (PI()/4.0, qs[0]));

    //second qubit:
    H(qs[1]);
    Controlled R1([qs[2]], (PI()/2.0, qs[1]));

    //third qubit:
    H(qs[2]);

    SWAP(qs[2], qs[0]);

    Message("After:");
    DumpMachine();

    ResetAll(qs); // deallocate qubits

}                                                                                                                                                                               

執行QFT線路

目前, Main 作業不會傳回任何值 - 作業會傳 Unit 回值。 稍後,您將修改作業以傳回度量結果陣列(Result[])。

  1. 在執行程式之前,請在 VS Code target 底部的狀態列中確認設定檔設定為 Q#:不受限制。 若要變更 target 配置檔,請選取 target 狀態列中的配置檔,然後從下拉功能表中選取 [不受限制 ]。 target如果設定檔未設定為 [不受限制],當您執行程式時會收到錯誤。
  2. 若要執行程式,請從右上方的播放圖示下拉式清單中選取 [執行檔案],或按 Ctrl+F5 Q# 程式會在預設模擬器上執行 Main() 作業。
  3. Message DumpMachine 輸出會出現在偵錯控制台中。

如果您對其他輸入狀態有何影響感到好奇,建議您在轉換之前嘗試套用其他量子位作業。

將度量新增至 QFT 線路

函式的 DumpMachine 顯示顯示顯示作業結果,但不幸的是,量子力學的基石指出真正的量子系統不能有這樣的 DumpMachine 函式。 相反地,資訊會透過測量來擷取,這通常不只會提供完整量子狀態的資訊,也可以大幅改變系統本身。

量子測量有許多種,但這裡的範例著重於最基本的:單一量子位的投影量值。 在指定基礎測量時(例如,計算基礎 $ { \ket, \ket{0}{1} } $),量子位狀態會投影到測量的基底狀態,因此會終結兩者之間的任何迭加。

修改 QFT 作業

若要在程式內 Q# 實作度量,請使用傳 M 回型別的 Result 作業。

首先,修改 Main 作業以傳回度量結果陣列, Result[]而不是 Unit

operation Main() : Result[] {

定義和初始化 Result[] 陣列

配置量子位之前,請宣告並系結三個元素陣列(每個量子位各一個 Result ):

mutable resultArray = [Zero, size = 3];

關鍵詞 mutable 前置 resultArray 詞可讓您稍後在程式碼中修改變量,例如,新增您的度量結果時。

在迴圈中 for 執行測量,並將結果新增至陣列

在 QFT 轉換作業之後,插入下列程式代碼:

for i in IndexRange(qs) {
    set resultArray w/= i <- M(qs[i]);
}

IndexRange在陣列上呼叫的函式(例如量子位數組)qs會傳回陣列索引的範圍。 在此,它會在迴圈中使用 for ,以循序測量每個量子位,並使用 M(qs[i]) 語句。 然後,使用 update-and-reassign 語句,將每個測量 Result 型別 (或 ZeroOne新增至 中 resultArray 對應的索引位置。

注意

此語句的語法對 是唯 Q#一的,但會對應至其他語言中所看到的類似變數重新指派 resultArray[i] <- M(qs[i]) ,例如 F# 和 R。

關鍵詞 set 一律用來重新指派使用 系結的 mutable變數。

返回 resultArray

測量了所有三個量子位,並將結果新增至 resultArray,您就可以放心地重設和解除分配量子位。 若要傳回度量,請插入:

return resultArray;

使用測量執行 QFT 線路

現在,變更函式的位置 DumpMachine ,以在測量前後輸出狀態。 您的最終程式 Q# 代碼看起來應該像這樣:

import Microsoft.Quantum.Diagnostics.*;
import Microsoft.Quantum.Math.*;
import Microsoft.Quantum.Arrays.*;

operation Main() : Result[] {

    mutable resultArray = [Zero, size = 3];

    use qs = Qubit[3];

    //QFT:
    //first qubit:
    H(qs[0]);
    Controlled R1([qs[1]], (PI()/2.0, qs[0]));
    Controlled R1([qs[2]], (PI()/4.0, qs[0]));

    //second qubit:
    H(qs[1]);
    Controlled R1([qs[2]], (PI()/2.0, qs[1]));

    //third qubit:
    H(qs[2]);

    SWAP(qs[2], qs[0]);

    Message("Before measurement: ");
    DumpMachine();

    for i in IndexRange(qs) {
        set resultArray w/= i <- M(qs[i]);
    }

    Message("After measurement: ");
    DumpMachine();

    ResetAll(qs);
    Message("Post-QFT measurement results [qubit0, qubit1, qubit2]: ");
    return resultArray;

}

提示

請記得在每次您引入程式碼變更之前儲存盤案,然後再再次執行。

  1. 在執行程式之前,請在 VS Code target 底部的狀態列中確認設定檔設定為 Q#:不受限制。 若要變更 target 配置檔,請選取 target 狀態列中的配置檔,然後從下拉功能表中選取 [不受限制 ]。 target如果設定檔未設定為 [不受限制],當您執行程式時會收到錯誤。
  2. 若要執行程式,請從右上方的播放圖示下拉式清單中選取 [ 執行 Q# 檔案 ],或按 Ctrl+5。 程式會在預設模擬器上執行 Main() 作業。
  3. Message DumpMachine 輸出會出現在偵錯控制台中。

您的輸出看起來應該如下所示:

Before measurement: 

 Basis | Amplitude      | Probability | Phase
 -----------------------------------------------
 |000⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
 |001⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
 |010⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
 |011⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
 |100⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
 |101⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
 |110⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
 |111⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000

After measurement: 

 Basis | Amplitude      | Probability | Phase
 -----------------------------------------------
 |010⟩ |  1.0000+0.0000𝑖 |   100.0000% |   0.0000

Post-QFT measurement results [qubit0, qubit1, qubit2]: 

[Zero, One, Zero]

此輸出說明一些不同的事項:

  1. 將傳回的結果與預先測量DumpMachine進行比較,這顯然不會說明 QFT 后迭加與基礎狀態。 測量只會傳回單一基礎狀態,機率取決於系統波浪函數中該狀態的幅度。
  2. 從測量后,您會看到度量DumpMachine變更狀態本身,並將它從基礎狀態的初始迭加投影到對應至測量值的單一基礎狀態。

如果您多次重複此作業,您會看到結果統計數據開始說明 QFT 后狀態的同樣加權迭加,這會導致每個鏡頭產生隨機結果。 不過,除了效率低下,仍然不完善,這隻會重現基礎狀態的相對幅度,而不是它們之間的相對階段。 後者在此範例中不是問題,但如果向 QFT 提供比 $\ket{000}$ 更複雜的輸入,您會看到相對階段出現。

Q#使用作業來簡化 QFT 線路

如簡介中所述,大部分 Q#的權力都在於它可讓您抽象化處理個別量子位的憂慮。 事實上,如果您想要開發完整規模、適用的量子程式,擔心作業在 H 特定輪替之前或之後,只會減緩您的速度。 Azure Quantum 提供 ApplyQFT 作業,可供您使用並套用任意數目的量子位。

  1. 以下列方式取代第一個 H 作業到 SWAP 作業的所有專案:

    ApplyQFT(qs);
    
  2. 您的程式代碼現在看起來應該像這樣

    import Microsoft.Quantum.Diagnostics.*;
    import Microsoft.Quantum.Math.*;
    import Microsoft.Quantum.Arrays.*;
    
    operation Main() : Result[] {
    
        mutable resultArray = [Zero, size = 3];
    
        use qs = Qubit[3];
    
        //QFT:
        //first qubit:
    
        ApplyQFT(qs);
    
        Message("Before measurement: ");
        DumpMachine();
    
        for i in IndexRange(qs) {
            set resultArray w/= i <- M(qs[i]);
        }
    
        Message("After measurement: ");
        DumpMachine();
    
        ResetAll(qs);
        Message("Post-QFT measurement results [qubit0, qubit1, qubit2]: ");
        return resultArray;
    
    }
    
  3. Q#再次執行程式,並注意到輸出與之前相同。

  4. 若要查看使用 Q# 作業的實際優點,請將量子位數目變更為 以外的 3專案:

mutable resultArray = [Zero, size = 4];

use qs = Qubit[4];
//...

因此,您可以針對任何指定數目的量子位套用適當的 QFT,而不必擔心在每個量子位上新增作業 H 和輪替。

探索其他 Q# 教學課程:

  • 量子隨機數產生器 示範如何撰寫程式 Q# ,以在迭加中產生量子位的隨機數。
  • Grover 的搜尋演算法 示範如何撰寫 Q# 使用 Grover 搜尋演算法的程式。
  • 量子糾纏 示範如何撰寫 Q# 程式,以操作和測量量子位,並示範迭加和糾纏的效果。
  • Quantum Katas 是自我節奏的教學課程和程序設計練習,旨在同時教學量子運算和Q#程序設計元素。