你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
了解如何使用 azure-quantumPython 包提交 Qiskit 量子线路。 可以使用 Visual Studio Code 中的 Azure Quantum 开发工具包(QDK)和 Jupyter Notebook(VS Code)将 Qiskit 线路提交到 Azure Quantum。 还可以使用本地稀疏模拟器测试线路。
有关详细信息,请参阅量子线路。
先决条件
有关安装详细信息,请参阅设置 QDK 扩展。
Azure 订阅中的 Azure Quantum 工作区。 若要创建工作区,请参阅创建 Azure Quantum 工作区。
Python安装了 Python Pip 的环境。
库
qdkPython,具有qiskit额外包的azure-quantumPython 包,以及ipykernel包。注意
如果未检测到 Jupyter Python 内核
ipykernel,VS Code 将提示你安装它。python -m pip install --upgrade azure-quantum[qiskit] qdk ipykernel重要
确保你拥有最新版本的 Qiskit。 有关详细信息,请参阅 更新 azure-quantum Python 包。
创建新的 Jupyter Notebook
- 在 VS Code 中,打开 “视图 ”菜单,然后选择 “命令面板”。
- 输入并选择“ 创建:新建 Jupyter Notebook”。
- VS Code 检测并显示笔记本选择的 Python 版本以及虚拟 Python 环境。 如果有多个 Python 环境,则可能需要使用右上角的内核选取器选择内核。 如果未检测到任何环境,请参阅 VS Code 中的 Jupyter Notebook 以获取设置信息。
加载所需的导入项
在笔记本的第一个单元中,运行以下代码以加载所需的导入:
import azure.quantum
from azure.quantum import Workspace
from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram
from azure.quantum.qiskit import AzureQuantumProvider
连接到 Azure Quantum 服务
若要连接到 Azure Quantum 服务,你需要使用 Azure Quantum 工作区的资源 ID 和位置。
登录到 Azure 帐户, https://portal.azure.com
选择 Azure Quantum 工作区,然后导航到 “概述”。
复制字段中的参数。
在笔记本中添加一个新单元格,并使用帐户信息创建 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.qpu
- ionq.qpu.aria-1
- ionq.simulator
- microsoft.estimator
- quantinuum.hqs-lt-s1
- quantinuum.hqs-lt-s1-apival
- quantinuum.hqs-lt-s2
- quantinuum.hqs-lt-s2-apival
- quantinuum.hqs-lt-s1-sim
- quantinuum.hqs-lt-s2-sim
- quantinuum.qpu.h2-1
- quantinuum.sim.h2-1sc
- quantinuum.sim.h2-1e
- rigetti.sim.qvm
- rigetti.qpu.ankaa-3
运行简单的线路
首先,创建要运行的简单 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 后端支持定义的门集中的门,这些门经过编译,可在硬件上以最佳方式运行。 如果线路包含不在此列表中的入口,则需要使用 gateset Qiskit 提供的函数转译到支持的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 包的原生对象,你可以使用 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 的环境。
qdkPython包含可选qiskit和jupyter附加项的包。python pip install "qdk[qiskit,jupyter]"重要
确保你拥有最新版本的 Qiskit。 有关详细信息,请参阅 更新 azure-quantum Python 包。
运行基本线路
在 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_RITargetProfile.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}
并非所有程序都可以在所有硬件上运行。 在这里,如果尝试处理target配置文件Base,那么会获得详细的错误信息,说明程序哪些部分不受支持。
try:
backend.qir(qc, target_profile=TargetProfile.Base)
except QSharpError as e:
print(e)