學習如何使用 Azure Quantum Development Kit(QDK)提交 Qiskit 量子電路。 您可以使用 Visual Studio Code (VS Code) 中的 Azure Quantum 開發套件 (QDK) 和 Jupyter Notebook 將 Qiskit 線路提交至 Azure Quantum。 您也可以使用本機稀疏模擬器來測試電路。 QDK 支援 Qiskit 的第 1 與第 2 版本。
如需詳細資訊,請參閱 量子電路。
必要條件
如需安裝詳細資料,請參閱 設定 QDK 擴充功能。
Azure 訂用帳戶中的 Azure Quantum 工作區。 若要建立工作區,請參閱 建立 Azure Quantum 工作區。
Python已安裝 Python 和 Pip 的環境。
已安裝 Azure Quantum Development Kit、Python和 Jupyter 擴充功能的 VS Code。
函式庫
qdkPython包含azureqiskit額外功能,以及套件ipykernel。python -m pip install --upgrade qdk[azure,qiskit] ipykernel
建立新的 Jupyter Notebook
- 在 VS Code 中,開啟 [檢視] 功能表,然後選擇 [命令面板]。
- 輸入並選取 [建立:新增 Jupyter Notebook]。
- VS Code 會偵測並顯示為筆記本選擇的Python版本和Python虛擬環境。 如果您有多個 Python 環境,則可能需要使用右上角的核心選擇器來選取核心。 如果未偵測到任何環境,請參閱 VS Code 中的 Jupyter Notebook 以取得設定資訊。
載入必要的匯入
在筆記本的第一個儲存格中,執行下列程式碼以載入必要的匯入項目:
from qdk.azure import Workspace
from qdk.azure.qiskit import AzureQuantumProvider
from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram
聯機到 Azure Quantum 服務
若要連線到 Azure Quantum 服務,您需要 Azure Quantum 工作區的資源識別碼和位置。
- 登入你的 Azure 帳號。 https://portal.azure.com
- 選擇你的 Azure Quantum 工作區,然後進入 概覽。
- 複製 資源 ID 和 Location 參數。
在您的筆記本中新增一個儲存格,並使用您的帳戶資訊來建立 Workspace 和 AzureQuantumProvider 物件,連線至您的 Azure Quantum 工作區。
workspace = Workspace(
resource_id = "", # Add the resourceID of your workspace
location = "" # Add the location of your workspace (for example "westus")
)
provider = AzureQuantumProvider(workspace)
列出所有後端
您現在可以列印工作區上所有可用的量子運算後端:
print("This workspace's targets:")
for backend in provider.backends():
print("- " + backend.name)
This workspace's targets:
- ionq.simulator
- ionq.qpu.aria-1
- ionq.qpu.forte-1
- ionq.qpu.forte-enterprise-1
- quantinuum.sim.h2-1sc
- quantinuum.sim.h2-2sc
- quantinuum.sim.h2-1e
- quantinuum.sim.h2-2e
- quantinuum.qpu.h2-1
- quantinuum.qpu.h2-2
- rigetti.sim.qvm
- rigetti.qpu.ankaa-3
- rigetti.qpu.cepheus-1-36q
運行簡單的電路
在新的儲存單元中,建立一個簡單的 Qiskit 電路。
# Create a Quantum Circuit acting on the q register
circuit = QuantumCircuit(3, 3)
circuit.name = "Qiskit Sample - 3-qubit GHZ circuit"
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.measure([0,1,2], [0, 1, 2])
# Print out the circuit
circuit.draw()
┌───┐ ┌─┐
q_0: ┤ H ├──■───────┤M├──────
└───┘┌─┴─┐ └╥┘┌─┐
q_1: ─────┤ X ├──■───╫─┤M├───
└───┘┌─┴─┐ ║ └╥┘┌─┐
q_2: ──────────┤ X ├─╫──╫─┤M├
└───┘ ║ ║ └╥┘
c: 3/════════════════╩══╩══╩═
0 1 2
target選取 以執行程式
在 IonQ 模擬器上執行
在你用實體硬體運行電路之前,先在模擬器裡測試電路。 用來 get_backend 建立 Backend 物件以連線到 IonQ 模擬器後端:
simulator_backend = provider.get_backend("ionq.simulator")
IonQ 後端支援來自已定義 網關集的閘道,這些閘道集會編譯為在硬體上以最佳方式執行。 如果您的線路包含不在此清單中的閘道,您需要使用 Qiskit 提供的 gateset 函式,將它們轉譯為支援的 transpile。
from qiskit import transpile
circuit = transpile(circuit, simulator_backend)
Transpile 函式會傳回新的線路物件,其中閘道會分解成指定後端支援的閘道。
您現在可以透過 Azure Quantum 服務執行程式,並取得結果。 下列單元格會提交一個作業,該作業將執行線路 100 次:
job = simulator_backend.run(circuit, shots=8)
job_id = job.id()
print("Job id", job_id)
Job id 00000000-0000-0000-0000-000000000000
若要等候作業完成並傳回結果,請執行:
result = job.result()
print(result)
Result(backend_name='ionq.simulator', backend_version='1', qobj_id='Qiskit Sample - 3-qubit GHZ circuit', job_id='00000000-0000-0000-0000-000000000000', success=True, results=[ExperimentResult(shots=8, success=True, meas_level=2, data=ExperimentResultData(counts={'000': 4, '111': 4}, memory=['000', '000', '000', '000', '111', '111', '111', '111'], probabilities={'000': 0.5, '111': 0.5}), header=QobjExperimentHeader(name='Qiskit Sample - 3-qubit GHZ circuit', num_qubits=3, metadata={}), status=JobStatus.DONE, name='Qiskit Sample - 3-qubit GHZ circuit')], date=None, status=None, header=None, error_data=None)
由於結果是 Qiskit 套件專屬的物件型別,請使用 result.get_counts 和 plot_histogram 來視覺化結果。 要表示所有可能的位元串標籤,請將標籤加入counts。
counts = {format(n, "03b"): 0 for n in range(8)}
counts.update(result.get_counts(circuit))
print(counts)
plot_histogram(counts)
{'000': 4, '001': 0, '010': 0, '011': 0, '100': 0, '101': 0, '110': 0, '111': 4}
您也可以使用 get_memory 功能顯示工作中的個別拍攝資料:
result.get_memory(circuit)
['000', '000', '000', '000', '111', '111', '111', '111']
注意
在 IonQ targets上,如果您提交的任務具有奇數次數,則執行次數會向下取整到最接近的偶數。 例如,如果你指定 9 發,那麼結果就會顯示 8 發的資料。
預估作業成本
在你執行 QPU 工作之前,先估算執行一個工作的成本。
如需最新的定價詳細資料,請參閱 IonQ 定價,或透過以下方式在工作區的 [提供者] 索引標籤中尋找您的工作區並檢視定價選項: aka.ms/aq/myworkspaces。
在 IonQ QPU 上執行
若要連線到實際硬體(量子處理器單元 (QPU)),只需將target"ionq.qpu.aria-1"的名稱提供給get_backend方法:
qpu_backend = provider.get_backend("ionq.qpu.aria-1")
提交電路在 Azure Quantum 上執行,取得結果,然後執行 plot_histogram 以繪製結果。
注意
在 QPU 上執行線路所需的時間取決於目前的佇列時間。
# Submit the circuit to run on Azure Quantum
job = qpu_backend.run(circuit, shots=100)
job_id = job.id()
print("Job id", job_id)
# Get the job results (this method waits for the Job to complete):
result = job.result()
print(result)
counts = {format(n, "03b"): 0 for n in range(8)}
counts.update(result.get_counts(circuit))
print(counts)
plot_histogram(counts)
Job id 00000000-0000-0000-0000-000000000000
Job Status: job has successfully run
Result(backend_name='ionq.qpu.aria-1', backend_version='1', qobj_id='Qiskit Sample - 3-qubit GHZ circuit', job_id='00000000-0000-0000-0000-000000000000', success=True, results=[ExperimentResult(shots=1024, success=True, meas_level=2, data=ExperimentResultData(counts={'0': 505, '1': 6, '2': 1, '3': 1, '4': 1, '5': 10, '6': 11, '7': 488}, probabilities={'0': 0.4932, '1': 0.0059, '2': 0.001, '3': 0.001, '4': 0.001, '5': 0.0098, '6': 0.0117, '7': 0.4766}), header=QobjExperimentHeader(name='Qiskit Sample - 3-qubit GHZ circuit', num_qubits='3', qiskit='True'))])
{'000': 505, '001': 6, '010': 1, '011': 1, '100': 1, '101': 10, '110': 11, '111': 488}
重要
你不能在同一個工作中提交多個電路。 作為一個變通方法,你可以呼叫 backend.run 方法非同步提交每個電路,然後取得每個工作的結果。 例如:
jobs = []
for circuit in circuits:
jobs.append(backend.run(circuit, shots=N))
results = []
for job in jobs:
results.append(job.result())
必要條件
如需安裝詳細資料,請參閱 設定 QDK 擴充功能。
Python已安裝 Python 和 Pip 的環境。
已安裝了 VS Code 與Azure Quantum 開發工具包及Python。
包含
qdkPython附加內容的qiskitjupyter包裹。python pip install "qdk[qiskit,jupyter]"
執行基本線路
在 VS Code 中,開啟一個新 Python 檔案,使用模組內建的稀疏模擬器 qsharp 建立並執行一個基本電路。
# load the required imports
from qdk import qsharp
from qsharp.interop.qiskit import QSharpBackend
from qiskit.circuit.random import random_circuit
# define and display the circuit
circuit = random_circuit(2, 2, measure=True)
print(circuit)
# run the circuit using the built-in sparse simulator
backend = QSharpBackend()
job = backend.run(circuit)
counts = job.result().get_counts()
print(counts)
若要執行程式,請選取右上方的 [執行] 圖示,然後選取 [ 執行 Python 檔案]。 輸出會顯示在新終端機視窗中。
┌─────────────────────────┐┌─┐
q_0: ─■───────────┤0 ├┤M├───
│P(0.79983) │ (XX-YY)(1.9337,1.7385) │└╥┘┌─┐
q_1: ─■───────────┤1 ├─╫─┤M├
└─────────────────────────┘ ║ └╥┘
c: 2/═════════════════════════════════════════╩══╩═
0 1
{'11': 680, '00': 344}
產生線路的 QIR
從同一電路中,您可以產生用於在量子硬體上運行的 QIR。
注意
要生成 QIR,必須將所有寄存器中的數據進行量測。 如果有任何未使用的暫存器,則會引發錯誤。 此外,當您嘗試使用 Unrestrictedtarget 設定檔產生 QIR 時,您會收到錯誤。 該Unrestricted配置檔僅適用於模擬。 您必須使用 TargetProfile.Base、 TargetProfile.Adaptive_RI或 TargetProfile.Adaptive_RIF。 您可以在target_profile呼叫中覆寫backend.qir(...)以切換設定檔。
匯入
QSharpError和TargetProfilefrom qdk.qsharp import QSharpError, TargetProfile若要產生 QIR,請修改輸出:
print(backend.qir(circuit, target_profile=TargetProfile.Adaptive_RI))
您的程式代碼現在看起來應該像這樣:
# load the required imports
from qdk import qsharp
from qsharp import QSharpError, TargetProfile
from qsharp.interop.qiskit import QSharpBackend
from qiskit.circuit.random import random_circuit
# define and display the circuit
circuit = random_circuit(2, 2, measure=True)
print(circuit)
# generate QIR for the circuit
print(backend.qir(circuit, target_profile=TargetProfile.Adaptive_RI))
您的程式碼輸出應如下所示:
┌────────────┐ ┌─┐
q_0: ┤ Rx(2.7195) ├─■───────────┤M├───
└──┬─────┬───┘ │U1(5.5924) └╥┘┌─┐
q_1: ───┤ Tdg ├─────■────────────╫─┤M├
└─────┘ ║ └╥┘
c: 2/════════════════════════════╩══╩═
0 1
%Result = type opaque
%Qubit = type opaque
define void @ENTRYPOINT__main() #0 {
block_0:
call void @__quantum__qis__rx__body(double 2.7194945105768586, %Qubit* inttoptr (i64 0 to %Qubit*))
call void @__quantum__qis__rz__body(double 2.796204066686262, %Qubit* inttoptr (i64 0 to %Qubit*))
call void @__quantum__qis__t__adj(%Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__rz__body(double -2.796204066686262, %Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__rz__body(double 2.796204066686262, %Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
call void @__quantum__rt__array_record_output(i64 2, i8* null)
call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
ret void
}
declare void @__quantum__qis__rx__body(double, %Qubit*)
declare void @__quantum__qis__rz__body(double, %Qubit*)
declare void @__quantum__qis__t__adj(%Qubit*)
declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
declare void @__quantum__rt__array_record_output(i64, i8*)
declare void @__quantum__rt__result_record_output(%Result*, i8*)
attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" }
attributes #1 = { "irreversible" }
; module flags
!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
!0 = !{i32 1, !"qir_major_version", i32 1}
!1 = !{i32 7, !"qir_minor_version", i32 0}
!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
!3 = !{i32 1, !"dynamic_result_management", i1 false}
!4 = !{i32 1, !"classical_ints", i1 true}
!5 = !{i32 1, !"qubit_resetting", i1 true}
!6 = !{i32 1, !"classical_floats", i1 false}
!7 = !{i32 1, !"backwards_branching", i1 false}
!8 = !{i32 1, !"classical_fixed_points", i1 false}
!9 = !{i32 1, !"user_functions", i1 false}
!10 = !{i32 1, !"multiple_target_branching", i1 false}
並非所有程式都可以在所有硬體上執行。 在這裡,如果您嘗試對targetBase這個配置檔案進行操作,您將收到有關程序中哪些部分不受支持的詳細錯誤信息。
try:
backend.qir(qc, target_profile=TargetProfile.Base)
except QSharpError as e:
print(e)