量子計算中,多量子位元門是實作複雜量子操作的關鍵,Toffoli、MCX 和 Fredkin 門是其典型代表,它們透過控制位和目標位之間的相互作用,實作特定邏輯功能。理解這些門的操作原理對於設計量子演算法至關重要。此外,量子線路的轉譯是將抽象的量子線路轉換為可在特定量子硬體上執行的物理操作的過程。Qiskit 提供了轉譯工具,可以將量子線路對映到目標後端的物理量子位元和可用門操作上。這對於在真實量子電腦上執行量子演算法至關重要。

6.9 多量子位元門

多量子位元門是量子計算中的另一類別重要操作,用於實作多個量子位元之間的複雜相互作用。本文將介紹Toffoli門、MCX門和Fredkin門的基本原理及其在Qiskit中的實作。

6.9.1 Toffoli門

Toffoli門是一種三量子位元門,當兩個控制位量子位元都為(|1\rangle)時,受控位量子位元的狀態會被翻轉。

Toffoli門的矩陣表示

[ Toffoli = \begin{pmatrix} 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \ 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \end{pmatrix} ]

Toffoli門的實作

from qiskit import QuantumCircuit

qc = QuantumCircuit(3)
qc.ccx(2, 1, 0)
print(qc.draw())

內容解密:

  1. 建立一個3量子位元的量子線路。
  2. 應用Toffoli門,將兩個控制位量子位元的狀態傳遞給受控位量子位元。

6.9.2 MCX門

MCX門是一種多控制位量子位元受控非門,當所有控制位量子位元都為(|1\rangle)時,受控位量子位元的狀態會被翻轉。

MCX門的實作

from qiskit import QuantumCircuit

qc = QuantumCircuit(4)
qc.mcx([1, 2, 3], 0)
print(qc.draw())

內容解密:

  1. 建立一個4量子位元的量子線路。
  2. 應用MCX門,將多個控制位量子位元的狀態傳遞給受控位量子位元。

6.9.3 Fredkin門

Fredkin門是一種受控交換門,當控制位量子位元為(|1\rangle)時,交換兩個受控位量子位元的狀態。

Fredkin門的矩陣表示

[ Fredkin = \begin{pmatrix} 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \ 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \end{pmatrix} ]

Fredkin門的實作

from qiskit import QuantumCircuit

qc = QuantumCircuit(3)
qc.cswap(2, 1, 0)
print(qc.draw())

內容解密:

  1. 建立一個3量子位元的量子線路。
  2. 應用Fredkin門,根據控制位量子位元的狀態交換兩個受控位量子位元的狀態。

6.10 量子線路的轉譯

在量子計算中,轉譯(Transpilation)是指將量子線路轉換為可在特定量子硬體上執行的過程。本文將介紹量子線路轉譯的基本原理及其在Qiskit中的實作。

6.10.1 準備工作

  1. 匯入必要的Qiskit類別和方法
from qiskit import QuantumCircuit, IBMQ
from qiskit.compiler import transpile
from qiskit.providers.ibmq import least_busy
  1. 載入IBM Quantum賬戶並建立後端
if not IBMQ.active_account():
    IBMQ.load_account()
provider = IBMQ.get_provider()
backend = least_busy(provider.backends(n_qubits=5, operational=True, simulator=False))

6.10.2 操作步驟

  1. 搭建量子線路
def build_circuit(choice):
    qc = QuantumCircuit(5, 5)
    if choice == "1":
        qc.x(0)
    elif choice == "2":
        qc.x(0)
        qc.barrier(0)
        qc.h(0)
    # 其他選擇...
    return qc
  1. 轉譯量子線路
trans_qc = transpile(qc, backend)
  1. 列印轉譯前後的量子線路
print("Circuit:")
display(qc.draw())
print("Transpiled circuit:")
display(trans_qc.draw())

內容解密:

  1. 搭建一個簡單的X門量子線路。
  2. 將量子線路轉譯為可在特定後端上執行的形式。
  3. 列印轉譯前後的量子線路及其深度和尺寸。

7.2 瞭解量子模擬器的用法

量子電腦模擬器(quantum computer simulator)是一種用於模擬真實量子電腦的量子力學行為的軟體程式。在透過雲端存取IBM Quantum後端並執行量子線路之前,用模擬器在本地環境中測試一下十分必要。如果讀者需要編寫規模更大的量子線路,但它無法在實體量子電腦上執行,或是在本地模擬器上執行時間過長,也可以使用根據雲端服務的模擬器進行測試。

7.2.1 準備工作

檢查一下是否已完成第1章中的相關操作。可以從本文GitHub倉函式庫中對應第7章的目錄中下載本文示例的Python檔案ch7_r1_aer.py

7.2.2 操作步驟

讓我們來看一下程式碼。

(1)匯入所需的Qiskit類別

因為本示例既要用到本地模擬器,也要用到雲端模擬器,所以需要同時匯入AerIBMQ。如有需要,也可以登入自己的帳號,連線到供應商。

from qiskit import Aer, IBMQ

if not IBMQ.active_account():
    IBMQ.load_account()
provider = IBMQ.get_provider()

(2)查詢可用的本地Qiskit Aer後端

使用backends()方法簡單查詢可用的本地Qiskit Aer後端。

backends = Aer.backends()
print("\nAer backends:\n\n", backends)

上述程式碼的結果如圖7-1所示。

(3)儲存模擬器組態細節

可以將模擬器組態細節儲存在一個名為simulators的列表中,以供進一步處理。使用backend.configuration()方法提取該資訊,依次查詢所有可用的後端,並將查詢到的每一個資料追加到該列表中。

simulators = []
for sim in range(0, len(backends)):
    backend = Aer.get_backend(str(backends[sim]))
    simulators.append(backend.configuration())

(4)追加IBM Quantum模擬器的組態細節

完整起見,本示例會把包含IBM Quantum模擬器的組態細節的資訊追加到該列表中。

ibmq_simulator = provider.backends(simulator=True)
simulators.append(provider.get_backend(str(ibmq_simulator[0])).configuration())

(5)顯示原始模擬器的組態細節

迴圈輸出simulators列表,檢視可用模擬器的組態資訊。

# Display the raw simulator configuration details
print("\nSimulator configuration details:")
for sim in range(0, len(simulators)):
    print("\n")
    print(simulators[sim].backend_name)
    print(simulators[sim].to_dict())

上述程式碼用於查詢每個可用模擬器的組態資訊,其輸出大致如圖7-2所示。

7.2.3 比較模擬器

每個模擬器的相關組態資訊都非常多。要對模擬器進行比較,讀者可以抓取一些感興趣的引數,並將每個模擬器的這些引數羅列一下。考慮到本章的目的,我們選取了如下引數。

  • 名稱(Name):用於在執行量子線路時,將特定的模擬器設定為後端。
  • 量子位元的數量(Number of qubits):每個模擬器所支援的量子位元的數量。
  • 最大執行次數(Max shots):使用者執行量子線路的最大次數。
  • 描述(Description):IBM Quantum提供的模擬器的描述資訊。

仔細觀察ibmq_qasm_simulator的細節(見圖7-3),就會發現這個非本地的IBM Quantum模擬器沒有對應的描述資訊。

# Fish out criteria to compare
print("\n")
print("{0:25} {1:<10} {2:<10} {3:<10}".format("Name", "#Qubits", "Max shots", "Description"))
print("{0:25} {1:<10} {2:<10} {3:<10}".format("----", "-------", "--------", "------------"))
description = []

內容解密:

這段程式碼主要用於比較不同的量子模擬器的組態引數。首先,它匯入了必要的 Qiskit 類別並載入了 IBMQ 帳戶。然後,它查詢了可用的本地 Qiskit Aer 後端和 IBM Quantum 模擬器,並將其組態詳細資訊儲存在 simulators 列表中。接著,它迴圈輸出 simulators 列表,顯示每個模擬器的原始組態詳細資訊。最後,它提取了一些關鍵引數(如名稱、量子位元數量、最大執行次數和描述),並將這些引數格式化輸出,以便於比較。

程式碼重點:

  1. 匯入必要的 Qiskit 類別:AerIBMQ
  2. 載入 IBMQ 帳戶並取得提供者。
  3. 查詢可用的本地 Qiskit Aer 後端和 IBM Quantum 模擬器。
  4. 儲存模擬器的組態詳細資訊。
  5. 顯示原始模擬器組態詳細資訊。
  6. 提取和比較關鍵引數。
  graph LR
    A[開始] --> B[匯入 Qiskit 類別]
    B --> C[載入 IBMQ 帳戶]
    C --> D[查詢本地 Qiskit Aer 後端]
    D --> E[查詢 IBM Quantum 模擬器]
    E --> F[儲存模擬器組態詳細資訊]
    F --> G[顯示原始組態詳細資訊]
    G --> H[提取和比較關鍵引數]

圖表翻譯:
此圖表展示了比較量子模擬器的流程。首先,匯入必要的 Qiskit 類別並載入 IBMQ 帳戶。然後,查詢可用的本地 Qiskit Aer 後端和 IBM Quantum 模擬器。接著,儲存這些模擬器的組態詳細資訊,並顯示原始組態詳細資訊。最後,提取並比較關鍵引數,如名稱、量子位元數量、最大執行次數和描述。

7.2 深入瞭解Qiskit Aer模擬器

Qiskit Aer模擬器是Qiskit框架中用於模擬量子電腦的重要工具。本文將探討Qiskit Aer模擬器的各種模擬器及其特性。

7.2.1 Qiskit Aer模擬器概覽

Qiskit Aer提供了多種模擬器,用於模擬不同型別的量子計算。這些模擬器包括:

程式碼範例1:列出可用的模擬器

for sim in range(0,len(simulators)):
    if simulators[sim].local==True:
        description.append(simulators[sim].description)
    elif simulators[sim].local==False:
        description.append("Non-local IBM Quantum simulator")
    print("{0:25} {1:<10} {2:<10} {3:<10}".format(
        simulators[sim].backend_name,
        simulators[sim].n_qubits,
        simulators[sim].max_shots, 
        description[sim]))

內容解密:

此程式碼用於遍歷所有可用的模擬器,並根據其是否為本地模擬器新增相應的描述。然後,列印預出每個模擬器的名稱、量子位元數、最大執行次數和描述。

7.2.2 各類別模擬器詳解

1. qasm_simulator

  • 用途:模擬理想量子電腦或包含誤差和噪聲的NISQ後端。
  • 特點:用C++編寫,可在本地裝置上執行。
  • 功能:可模擬理想量子電腦的輸出,或透過新增誤差和噪聲組態檔案模擬NISQ後端。

2. statevector_simulator

  • 用途:模擬量子位元在量子線路中的態向量。
  • 特點:同樣用C++編寫,適用於本地執行。
  • 功能:能夠提供量子線路中任意位置的量子位元態向量資訊。

3. unitary_simulator

  • 用途:計算量子線路的麼正矩陣。
  • 特點:以本地Python模擬器的形式執行。
  • 功能:對於理解量子演算法的麼正演化非常有用。

4. pulse_simulator

  • 用途:根據脈衝的哈密頓量模擬器,用於脈衝Qobj類別檔案。
  • 特點:允許使用者繞過標準量子門,直接測試與後端量子位元的互動。
  • 功能:適用於需要精確控制量子位元的實驗。

5. ibmq_qasm_simulator

  • 用途:非本地模擬器,功能類別似於本地的qasm_simulator,但效能更強。
  • 特點:執行在IBM POWER9伺服器上,支援最高32個量子位元。
  • 功能:適合執行大規模量子線路。

7.2.3 模擬器效能比較

觀察兩個QASM模擬器的效能引數,可以發現它們都支援大約30個量子位元,每次可執行幾千次。然而,它們之間存在關鍵差異:

  1. 本地模擬器(qasm_simulator):其效能取決於本地硬體。隨著量子位元數量的增加,模擬的複雜度呈指數增長,可能導致效能下降。

  2. 非本地模擬器(ibmq_qasm_simulator):執行在IBM的強大伺服器上,能夠支援更大規模的量子線路模擬。

程式碼範例2:比較本地和非本地模擬器

# 在本地qasm_simulator上執行量子線路
simulator = Aer.get_backend('qasm_simulator')
result = execute(circ, simulator, shots=simulator.configuration().max_shots).result()
counts = result.get_counts(circ)
print("Simulated SWAP counts:", counts)
display(plot_histogram(counts, title='Simulated counts for '+str(n_gates)+' SWAP gates.'))

內容解密:

此程式碼展示瞭如何在本地的qasm_simulator上執行一個包含多個SWAP門的量子線路,並取得測量結果。

7.3 比較Qiskit Aer模擬器與IBM量子電腦

本文將透過一個具體示例,比較在Qiskit Aer模擬器和真實IBM量子電腦上執行同一量子線路的結果差異。

7.3.1 準備工作

下載對應的Python檔案ch7_r2_ootb.py

7.3.2 操作步驟

  1. 匯入必要的Qiskit類別和方法,並登入IBM Quantum帳戶。

  2. 構建一個包含多個SWAP門的量子線路。

  3. 分別在本地Qiskit Aer模擬器和IBM Quantum後端上執行該量子線路。

程式碼範例3:在不同後端執行SWAP門量子線路

# 在IBM Quantum後端上執行量子線路
backend = least_busy(provider.backends(n_qubits=5, operational=True, simulator=False))
job = execute(circ, backend, shots=backend.configuration().max_shots)
job_monitor(job)
nisq_result = job.result()
nisq_counts = nisq_result.get_counts(circ)
print("NISQ SWAP counts:", nisq_counts)
display(plot_histogram(nisq_counts, title='Counts for '+str(n_gates)+' SWAP gates on '+str(backend)))

內容解密:

此程式碼選擇一個最不繁忙的IBM Quantum後端來執行構建的量子線路,並取得測量結果。

7.3.3 結果分析

  • 在理想的Qiskit Aer模擬器上,量子線路的輸出結果非常完美,符合預期。

  • 在真實的IBM Quantum裝置上,由於NISQ硬體的誤差和噪聲,輸出結果出現了偏差。

程式碼範例4:比較原始和轉譯後的量子線路

# 比較原始量子線路與轉譯後的線路
trans_swap = transpile(circ, backend)
print("Basis gates:", backend.configuration().basis_gates)
print("SWAP circuit depth:", circ.depth(), "gates")
print("Transpiled SWAP circuit depth:", trans_swap.depth(), "gates")

內容解密:

此程式碼展示瞭如何將原始量子線路轉譯為後端支援的基礎門,並比較轉譯前後的門數量和深度。

7.4 將IBM Quantum後端的噪聲組態檔案新增到本地模擬器

透過取得IBM Quantum後端的噪聲資料,可以建立噪聲組態檔案,並將其應用於本地模擬器,使模擬結果更接近真實的NISQ後端。

程式碼範例5:選擇後端並取得噪聲組態檔案

def select_backend():
    available_backends = provider.backends(filters=lambda b: not b.configuration().simulator and b.configuration().n_qubits > 1)
    # ... 後續程式碼用於選擇後端並取得噪聲組態檔案

內容解密:

此函式用於列出所有可用的、非模擬器的後端,並選擇一個後端用於後續的噪聲組態檔案取得。