量子位元的穩定性是量子計算發展的關鍵挑戰。本篇將探討如何利用 Qiskit 工具比較 IBM Quantum 後端中不同量子位元對的 CX 門錯誤率。藉由選取最佳和最差的量子位元對,並執行相同的量子程式,我們可以觀察到量子硬體的效能差異,並理解如何針對特定硬體特性最佳化量子程式。
from qiskit import IBMQ, Aer, QuantumCircuit, ClassicalRegister, QuantumRegister, execute
from qiskit.tools.monitor import job_monitor
from qiskit.visualization import plot_histogram
from IPython.core.display import display
# ... (省略載入帳號與供應商程式碼)
內容解密:
此段程式碼匯入了必要的 Qiskit 模組,包含用於量子電路建構、執行和視覺化的工具。同時,也初始化了與 IBM Quantum 後端的連線。
def select_backend():
available_backends = provider.backends(filters=lambda b: not b.configuration().simulator and b.configuration().n_qubits > 1 and b.status().operational)
# ... (省略印出後端資訊與選擇程式碼)
return backend
內容解密:
select_backend() 函式用於篩選可用的 IBM Quantum 後端,排除模擬器,並確保所選後端至少具有兩個量子位元且處於運作狀態。
def get_gate_info(backend):
gates = backend.properties().gates
cx_best_worst = [[[0, 0], 1], [[0, 0], 0]]
# ... (省略CX門資訊擷取程式碼)
return cx_best_worst
內容解密:
get_gate_info() 函式用於取得指定後端的 CX 門錯誤率資訊,並找出最佳和最差的量子位元對。
def create_circuits(backend, cx_best_worst):
q1 = QuantumRegister(backend.configuration().n_qubits)
c1 = ClassicalRegister(backend.configuration().n_qubits)
qc_best = QuantumCircuit(q1, c1)
qc_worst = QuantumCircuit(q1, c1)
# ... (省略量子線路建構程式碼)
return qc_best, qc_worst
內容解密:
create_circuits() 函式根據最佳和最差的 CX 門資訊,建立兩個量子線路,分別應用於對應的量子位元對。
def compare_cx(backend, qc_best, qc_worst):
job_best = execute(qc_best, backend, shots=8192)
job_monitor(job_best)
job_worst = execute(qc_worst, backend, shots=8192)
job_monitor(job_worst)
# ... (省略結果處理與視覺化程式碼)
內容解密:
compare_cx() 函式在指定的後端上執行兩個量子線路,並將結果與模擬器結果進行比較,最後以直方圖呈現,方便觀察不同量子位元對的效能差異。
透過以上步驟,我們可以清楚地比較不同量子位元對的 CX 門錯誤率,並藉此評估量子硬體的效能。這對於設計更穩健的量子演算法至關重要,因為選擇適當的量子位元可以有效降低錯誤率,提高計算結果的可靠性。
8.3 比較同一塊晶片上的量子位元
本文將在一個選定的後端上實際比較同一個後端上的不同量子位元。示例將根據3種不同的設定,即理想量子電腦(qasm_simulator)、最空閒的5量子位元IBM Quantum裝置上的最佳量子位元對和最差量子位元對,執行同一個貝爾態量子程式。
8.3.1 準備工作
可以從本文 GitHub 倉函式庫中對應第8章的目錄中下載本文示例的 Python 檔案 ch8_r2_compare_qubits.py。
示例程式碼
-
匯入所需的Qiskit類別和方法,並登入自己的帳號:
from qiskit import IBMQ, Aer, QuantumCircuit, ClassicalRegister, QuantumRegister, execute from qiskit.tools.monitor import job_monitor from qiskit.visualization import plot_histogram, plot_error_map from IPython.core.display import display print("Getting provider...") if not IBMQ.active_account(): IBMQ.load_account() provider = IBMQ.get_provider() -
使用函式
select_backend()選擇一個可用的後端:def select_backend(): available_backends = provider.backends(filters=lambda b: not b.configuration().simulator and b.configuration().n_qubits > 1 and b.status().operational) print("{0:20} {1:<10} {2:<10}".format("Name", "#Qubits", "Pending jobs")) print("{0:20} {1:<10} {2:<10}".format("----", "-------", "------------")) for n in range(0, len(available_backends)): # ...
透過比較理想量子電腦和真實IBM Quantum裝置上的量子位元效能,可以深入理解當前NISQ機器的本質和侷限性,並進一步探索如何最佳化量子程式以適應真實量子硬體的特性。#### 內容解密: 此段程式碼的主要功能是選擇一個可用的量子計算後端,並顯示其相關資訊。以下將逐行詳細解析程式碼的作用、設計邏輯及技術原理:
-
def select_backend():- 定義了一個名為
select_backend的函式,用於選擇一個可用的量子計算後端。 - 設計邏輯:封裝後端選擇的邏輯,使其可重複呼叫。
- 技術原理:利用 Qiskit 的
provider.backends()方法取得可用後端列表。
- 定義了一個名為
-
available_backends = provider.backends(filters=lambda b: not b.configuration().simulator and b.configuration().n_qubits > 1 and b.status().operational)- 取得所有可用的、非模擬器且具有多於1個量子位元的後端,並且這些後端必須處於可操作狀態。
- 作用:篩選出符合條件的後端,以供使用者選擇。
- 技術原理:使用 Qiskit 的
backends()方法並結合 lambda 函式進行篩選。
-
print("{0:20} {1:<10} {2:<10}".format("Name", "#Qubits", "Pending jobs"))- 列印預表頭,顯示後端名稱、量子位元數量和待處理任務數。
- 作用:提供清晰的輸出格式,方便使用者理解後端資訊。
- 設計邏輯:使用字串格式化來對齊輸出,使資訊更易讀。
-
for n in range(0, len(available_backends)):- 遍歷所有可用的後端,並逐一顯示其名稱、量子位元數量等資訊。
- 作用:列出所有符合條件的後端供使用者選擇。
- 技術原理:利用迴圈遍歷後端列表,並使用
get_backend()方法取得後端物件。
-
select_backend = input("Select a backend ('exit' to end): ")- 提示使用者輸入想要選擇的後端名稱,或輸入 ’exit’ 以離開。
- 作用:允許使用者根據顯示的資訊選擇特定的後端。
- 設計邏輯:使用
input()函式取得使用者輸入,並提供離開選項。
-
if select_backend != "exit": backend = provider.get_backend(select_backend)- 如果使用者輸入的不是 ’exit’,則根據輸入的名稱取得對應的後端物件。
- 作用:將使用者選擇的後端名稱對映到實際的後端物件。
- 技術原理:使用
provider.get_backend()方法根據名稱取得後端。
-
return backend- 傳回使用者選擇的後端物件。
- 作用:將選擇的後端傳回給呼叫者,以便進一步操作。
- 設計邏輯:封裝選擇邏輯,使呼叫者可以直接使用傳回的後端物件。
圖表翻譯:
此圖展示了使用者如何透過 select_backend() 函式選擇一個可用的量子計算後端。下面是對圖表的詳細解釋:
-
取得可用後端列表:
- 程式碼首先呼叫
provider.backends()方法,並使用 lambda 函式篩選出所有可用的、非模擬器且具有多於1個量子位元的後端。 - 作用:列出當前可用的量子計算後端。
- 程式碼首先呼叫
-
顯示後端資訊:
- 對每個可用的後端,程式碼列印其名稱、量子位元數量和待處理任務數。
- 作用:為使用者提供詳細的後端資訊,以便做出選擇。
-
使用者輸入:
- 使用者根據顯示的後端列表輸入想要選擇的後端名稱,或輸入 ’exit’ 以離開程式。
- 作用:允許使用者選擇特定的後端進行進一步操作。
-
取得選擇的後端:
- 如果使用者輸入的不是 ’exit’,程式碼根據輸入的名稱取得對應的後端物件。
- 作用:將使用者的選擇對映到實際的後端物件。
-
傳回後端物件:
- 最終,程式碼傳回使用者選擇的後端物件。
- 作用:供呼叫者使用選擇的後端進行後續的量子計算操作。
圖表關鍵點:
- 可用後端列表:顯示所有符合條件的後端。
- 使用者選擇:使用者根據列表選擇一個後端。
- 後端資訊:包括後端名稱、量子位元數量和待處理任務數。
透過這個過程,使用者可以方便地選擇一個合適的量子計算後端,以進行接下來的量子程式執行和測試。
量子錯誤率分析與比較
實驗目的與步驟
本實驗旨在探討IBM Quantum後端中,不同量子位元對之間的CX門錯誤率差異。透過選取效能最佳和最差的量子位元對,執行相同的量子程式,並比較其輸出結果,以直觀瞭解量子硬體的效能差異。
步驟1:選擇後端
首先,我們需要選擇一個可用的IBM Quantum後端。以下程式碼片段展示瞭如何列出可用的後端並選擇一個進行測試:
backend = provider.get_backend(str(available_backends[n]))
print("{0:20} {1:<10}".format(backend.name(), backend.configuration().n_qubits), backend.status().pending_jobs)
select_backend = input("Select a backend ('LB' for least busy): ")
if select_backend not in ["LB", "lb"]:
backend = provider.get_backend(str(select_backend))
else:
from qiskit.providers.ibmq import least_busy
backend = least_busy(provider.backends(filters=lambda b: not b.configuration().simulator and b.configuration().n_qubits > 1 and b.status().operational))
print("Selected backend:", backend.status().backend_name)
return backend
內容解密:
此段程式碼首先列出所有可用的後端及其相關資訊,包括名稱、量子位元數量和待處理的工作數量。使用者可以輸入後端名稱或輸入’LB’選擇最不繁忙的後端。
步驟2:取得CX門資訊
接下來,我們需要取得所選後端中CX門的錯誤率資訊,並找出效能最佳和最差的CX門。以下程式碼片段展示瞭如何實作這一步驟:
def get_gate_info(backend):
gates = backend.properties().gates
cx_best_worst = [[[0, 0], 1], [[0, 0], 0]]
for n in range(0, len(gates)):
if gates[n].gate == "cx":
print(gates[n].name, ":", gates[n].parameters[0].name, "=", gates[n].parameters[0].value)
if cx_best_worst[0][1] > gates[n].parameters[0].value:
cx_best_worst[0][1] = gates[n].parameters[0].value
cx_best_worst[0][0] = gates[n].qubits
if cx_best_worst[1][1] < gates[n].parameters[0].value:
cx_best_worst[1][1] = gates[n].parameters[0].value
cx_best_worst[1][0] = gates[n].qubits
print("Best cx gate:", cx_best_worst[0][0], ",", round(cx_best_worst[0][1] * 100, 3), "%")
print("Worst cx gate:", cx_best_worst[1][0], ",", round(cx_best_worst[1][1] * 100, 3), "%")
return cx_best_worst
內容解密:
此函式遍歷後端的所有門操作,找出錯誤率最低和最高的CX門,並傳回相關資訊。
步驟3:建立量子線路
根據所選後端和取得的CX門資訊,我們建立兩個量子線路,分別對應效能最佳和最差的CX門。以下程式碼片段展示瞭如何建立這些量子線路:
def create_circuits(backend, cx_best_worst):
q1 = QuantumRegister(backend.configuration().n_qubits)
c1 = ClassicalRegister(backend.configuration().n_qubits)
qc_best = QuantumCircuit(q1, c1)
qc_worst = QuantumCircuit(q1, c1)
# Best circuit
qc_best.h(q1[cx_best_worst[0][0][0]])
qc_best.cx(q1[cx_best_worst[0][0][0]], q1[cx_best_worst[0][0][1]])
qc_best.measure(q1[cx_best_worst[0][0][0]], c1[0])
qc_best.measure(q1[cx_best_worst[0][0][1]], c1[1])
# Worst circuit
qc_worst.h(q1[cx_best_worst[1][0][0]])
qc_worst.cx(q1[cx_best_worst[1][0][0]], q1[cx_best_worst[1][0][1]])
qc_worst.measure(q1[cx_best_worst[1][0][0]], c1[0])
qc_worst.measure(q1[cx_best_worst[1][0][1]], c1[1])
return qc_best, qc_worst
內容解密:
此函式根據效能最佳和最差的CX門資訊,建立兩個量子線路,並對其進行測量。
步驟4:比較CX門效能
最後,我們在所選後端上執行這兩個量子線路,並比較其輸出結果。以下程式碼片段展示瞭如何實作這一步驟:
def compare_cx(backend, qc_best, qc_worst):
job_best = execute(qc_best, backend, shots=8192)
job_monitor(job_best)
job_worst = execute(qc_worst, backend, shots=8192)
job_monitor(job_worst)
# 取得結果並繪製直方圖
best_result = job_best.result()
counts_best = best_result.get_counts(qc_best)
worst_result = job_worst.result()
counts_worst = worst_result.get_counts(qc_worst)
# 模擬結果作為對照
backend_sim = Aer.get_backend('qasm_simulator')
job_sim = execute(qc_best, backend_sim)
sim_result = job_sim.result()
counts_sim = sim_result.get_counts(qc_best)
display(plot_histogram([counts_best, counts_worst, counts_sim], title="Best and worst qubit pair for: " + backend.name(),
legend=["Best qubit pair", "Worst qubit pair", "Simulated baseline"], sort='desc', figsize=(15, 12),
color=['green', 'red', 'blue'], bar_labels=True))
內容解密:
此函式在所選後端上執行兩個量子線路,並將結果與模擬結果進行比較,最終繪製直方圖展示差異。