你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
使用 Microsoft Quantum 开发工具包(QDK)将逻辑Q#或OpenQASM程序编译为Quantum Intermediate Representation(QIR),然后使用qdk.simulation.run_qir通过qodec运行该程序。 设置噪音模型,然后选择内置 syndrome 解码器或可选的 deq 线路级解码器。
Prerequisites
在开始之前完成这些任务:
- 安装 QDK 以更正错误。
- 开发并验证 QEC 协议,或从其他来源获取完整的 qodec。
- 使用
qdk.ec.audit审核qodec。
这些Q#示例使用名为C4的qodec,其中包含protocol代码的说明。 若要创建一个,请参阅 开发和验证 QEC 协议。
import qodec
from qdk import ec
c4 = qodec.Code(
"C4",
stabilizers=["X_0 X_1 X_2 X_3", "Z_0 Z_1 Z_2 Z_3"],
x=["X_0 X_1", "X_0 X_2"],
z=["Z_0 Z_2", "Z_0 Z_1"],
)
protocol = ec.build_qodec(
c4,
strategy="bare-css/v1",
strict=False,
)
report = ec.audit(protocol)
if report.errors or report.warnings:
raise ValueError(str(report))
在运行之前对qodec进行检查。 运行时信任 qodec 的检查、读数、标志和帧方程,因此无效声明可能会导致不正确的逻辑结果或解码器失败。
此工作流使用 qdk.simulation.run_qir 并配合 qodec。 该工具 qodec 使用单独的 StimPython 包 来分析 Stim 格式的小工具线路。 它不调用 qdk.stim.run。 在 LinuxArm64 或 WindowsArm64 上,从源代码安装 Stim,然后在运行具有 Stim-format 线路的 qodec 之前重启 Python 或 Jupyter 内核。
将 QIR 调用与 qodec 指令匹配
将 QIR 程序中的每个量子调用与 qodec 的顶层指令集中的一个指令匹配。 指令助记必须与 QIR 被调用方名称完全匹配。
下表显示了示例映射:
| 源调用 | 必需的 qodec 助记符 |
|---|---|
Q#
X(q) 或 OpenQASMx q; |
__quantum__qis__x__body |
Q#
H(q) 或 OpenQASMh q; |
__quantum__qis__h__body |
Q#
CNOT(a, b) 或 OpenQASMcx a, b; |
__quantum__qis__cx__body |
Q#
Adjoint S(q) 或 OpenQASMsdg q; |
__quantum__qis__s__adj |
Q#
M(q) 或 OpenQASMc = measure q; |
__quantum__qis__m__body |
Q# 固有操作 Foo |
Foo |
OpenQASM 内部网关或命名的 deffoo |
foo |
QIR 参数按以下顺序绑定到 qodec 指令元素:
- 量子位指针参数绑定到块操作数。
- 标量参数绑定到指令参数。
- 结果指针参数接收指令结果和返回的任何标志。
如果量子调用与顶部指令集中的指令不匹配,编译器将引发错误。
在 中声明逻辑指令
基于C4代码构建的qodec提供自定义指令,例如prepare_z_all、measure_z_all、syndrome和cx_all。 使用相同的名称声明 Q# 内部操作。
使用自适应目标配置文件进行初始化 Q# ,因为自定义度量操作需要它。
from qdk import TargetProfile, qsharp
qsharp.init(target_profile=TargetProfile.Adaptive_RI)
将 C4 指令声明为 Q# 操作。
qsharp.eval("""
@Measurement()
operation prepare_z_all(block : Qubit) : Result { body intrinsic; }
@Measurement()
operation prepare_x_all(block : Qubit) : Result { body intrinsic; }
@Measurement()
operation measure_z_all(block : Qubit) : (Result, Result) { body intrinsic; }
@Measurement()
operation measure_x_all(block : Qubit) : (Result, Result) { body intrinsic; }
operation cx_all(control : Qubit, target : Qubit) : Unit { body intrinsic; }
operation syndrome(block : Qubit) : Unit { body intrinsic; }
""")
在此程序中,每个 Q#Qubit 都表示一个编码块。 该 C4 块有两个逻辑量子比特,因此每个度量操作返回两个逻辑结果。 每个准备操作返回一个拒绝标志。
编译逻辑 Q# 实验
定义状态准备和测量(SPAM)实验。
qsharp.eval("""
operation TestSpamZ() : (Result[], Result[]) {
use block = Qubit();
let reject = prepare_z_all(block);
let (left, right) = measure_z_all(block);
([reject], [left, right])
}
""")
将 TestSpamZ 操作编译为 QIR.
qir = str(qsharp.compile("TestSpamZ()"))
QIR 保留了对 prepare_z_all 和 measure_z_all 的调用。 当程序运行时,qodec 运行时将这些名称与顶层指令集匹配,并将每个逻辑调用替换为其小工具。
使用内置解码器运行
调用 run_qir 并传递 qodec。
None如果是decoder,运行时使用内置的最小权重Pauli解码器。
from qdk.simulation import run_qir
results = run_qir(
qir,
qodec=protocol,
type="stabilizer",
shots=100,
seed=42,
)
print(results[:5])
若要运行一个 qodec,请使用以下模拟器选项:
type 值 |
Behavior |
|---|---|
None 或 "stabilizer" |
使用稳定子后端 |
"cpu" |
对受支持的程序使用状态向量后端 |
"gpu" |
不支持与 qodec 一起使用 |
运行时在首次使用每个程序量子位之前准备它,除非第一条指令创建其块。 准备指令具有输出块,没有输入块,以及稳定逻辑 Z 的操作。
单量子位 Pauli 解码器校正和 qodec 帧更新使用无噪声 Pauli 帧,而不是有噪声的物理门。
配置模拟器噪声
在模拟器操作上定义噪声,而不是在 qodec 指令名称上。 运行时将每个底层指令转换为一个或多个模拟器操作,因此噪声设置适用于这些操作。
该 C4 演练指南使用以下映射:
| 底层指令 | 模拟器操作 |
NoiseConfig 字段 |
|---|---|---|
R |
准备或重置为 Z+ | mresetz |
H |
Hadamard | h |
CX |
Controlled X | cx |
M |
Z 基测量 | mresetz |
创建简单的 1% 干扰模型:
from qdk.simulation import NoiseConfig
noise = NoiseConfig()
for gate in (noise.h, noise.cx):
gate.set_depolarizing(0.01)
noise.mresetz.x = 0.01
使用噪声运行试验:
results = run_qir(
qir,
qodec=protocol,
noise=noise,
type="stabilizer",
shots=1000,
seed=42,
on_shot_failure="discard",
)
mresetz 上的噪声在测量或准备后作用于量子位。 它不会翻转模拟器已记录的测量位。 要研究记录的位翻转,请使用 qodec 读出故障模型和小工具分析。
控制拍摄失败
使用 on_shot_failure 选择当 qodec 标志、解码器或读出未产生可接受的拍摄时运行时的响应方式。
| Value | Behavior |
|---|---|
"discard" |
从返回的列表中省略失败的拍摄。 此值为默认值。 |
"raise" |
在第一次拍摄失败时停止。 |
"retry" |
重启失败的拍摄,最多 max_retries 次额外尝试。 |
使用 "discard" 策略,shots 参数计算尝试的拍摄次数,因此返回的列表中的项目数可能少于 shots。
仅当逻辑程序未接收到该标志时,标志才会触发拍摄策略。 如果 Q#@Measurement() 操作返回额外的 Result 作为标志,程序会接收该标志并决定是否拒绝拍摄。
在此 TestSpamZ 示例中,程序返回第一个数组中的准备标志。 因此,该 on_shot_failure="discard" 设置不会删除返回的标志为 One 的行。
选择解码器
若要选择如何解码错误,请使用 decoder 参数为每个编码层传入用于准备解码器的可调用对象。
QDK 具有以下解码器:
| 解码器 | 使用它来 |
|---|---|
| 默认综合征解码器 | 从综合征证据推断最小权重 Pauli 校正。 使用 decoder=None。 |
| 帧解码器 | 跟踪无噪音帧,而不会推断物理故障。 使用 prepare_frame_decoder。 |
| deq 解码器 | 使用 deq 解码线路级故障模型。 使用 prepare_deq_decoder。 |
使用默认 deq 配置
安装 deq 和 deq-runtime,然后传入 prepare_deq_decoder。
from qdk.simulation.decoders import prepare_deq_decoder
results = run_qir(
qir,
qodec=protocol,
decoder=prepare_deq_decoder,
noise=noise,
type="stabilizer",
shots=1000,
seed=42,
on_shot_failure="discard",
)
默认情况下, deq 适配器使用中继信念传播和窗口协调器。 若要更改这些设置,请使用运行时工厂。
配置单体 deq 运行时
若要直接选择 deq 设置,请将运行时工厂传递给 prepare_deq_decoder。
from functools import partial
from deq.runtime import Runtime
from qdk.simulation import decoders
def make_runtime(seed: int) -> Runtime:
return Runtime(
decoder="black-box-relay-bp",
decoder_config={"parallel": 1, "seed": seed},
coordinator="monolithic",
controller="jit",
)
results = run_qir(
qir,
qodec=protocol,
decoder=partial(
decoders.prepare_deq_decoder,
runtime_factory=make_runtime,
),
noise=noise,
type="stabilizer",
shots=1000,
seed=42,
on_shot_failure="discard",
)
从每个工厂调用中返回一个新 Runtime 值。
QDK 启动并关闭每个运行时。
Note
适配器 deq 需要:
- 一个编码层
- 与度量无关 Clifford 的执行跟踪
- 稳定子后端
- 无量子比特丢失的干扰模型
适配器 deq 不支持重试策略。 不支持的程序会引发错误,而不是回退到另一个解码器。
拒绝低置信度 deq 结果
适配器 deq 为每个逻辑读数返回一个分数。 较低的分数表示对所选更正的偏好更强。 这些分数并不是经校准的失效概率。
若要拒绝低置信度结果,在准备解码器时传递 max_readout_score ,如以下示例所示:
from functools import partial
from qdk.simulation import decoders
scored_decoder = partial(
decoders.prepare_deq_decoder,
max_readout_score=0.2,
)
results = run_qir(
qir,
qodec=protocol,
decoder=scored_decoder,
noise=noise,
type="stabilizer",
shots=1000,
on_shot_failure="discard",
)
仅当每个返回的逻辑读出的分数在阈值或低于阈值时,运行时才接受拍摄。 阈值不适用于原始标志或未使用的中间读取。
基于分数的拒绝可以降低可接受拍摄的逻辑错误率。 但它也会减少可接受的镜头数量,并增加解码器的工作量。
编译 OpenQASM 程序
标准OpenQASM操作使用与标准Q#操作相同的QIR助记规则。
from qdk import TargetProfile, openqasm
source = """
OPENQASM 3.0;
include "stdgates.inc";
qubit q;
bit c;
x q;
c = measure q;
"""
qir = openqasm.compile(
source,
target_profile=TargetProfile.Adaptive_RI,
)
print(qir)
要通过 qodec 运行此程序,请确保 qodec 的顶层指令集具有 __quantum__qis__x__body 和 __quantum__qis__m__body,并具有兼容的块操作数和一个测量结果。
OpenQASM 名为foo的内在门或子例程使用助记符foo。 量子位参数绑定到块操作数。
float、int 和 bool 参数按声明顺序绑定到指令参数。
OpenQASM 对 qodec 调用有以下限制:
- 自定义内部函数不能返回 QIR
Result。 要获得一个测量结果,请使用标准measure语句。 -
OpenQASM 程序无法运行自定义度量、从一次调用接收多个结果或接收返回的标志。 在这些情况下,请使用 Q#
@Measurement()操作。 - 运行时控制 OpenQASM 程序无法接收的任何标志,并且这些标志可以拒绝拍摄。
有关详细映射示例,请参阅以下 QDK 笔记本:
查看要求和限制
在运行大型试验之前,请查看这些要求、限制和结果差异。
要求:
- 每个 QIR 量子调用都必须解析为顶层 qodec 指令。
- 在运行流程之前对其进行审核。 运行时 qodec 信任你编写的公式,并且不检查它们。
Limitations:
- GPU 模拟不支持 qodec 执行。
- 默认构件故障集可以呈指数级增长,因此确切的距离搜索可能需要很长时间。
- deq 和 Stim 包具有平台限制。 有关详细信息,请参阅安装 QDK 以进行错误更正。
结果差异:
- 确切的输出计数可能因解码器而异。
- 放弃和重试策略可以更改返回的结果分布。
有关噪音扫描、deq解码和基于置信度拒绝的完整Q#试验,请参阅 QEC 协议演练。