云执行:把线路交给量子平台¶
本地模拟回答"线路对不对",云执行回答"线路在真实平台上跑出来是什么样"。本章走通 UnifiedQuantum 的远端任务主链路:submit_task 提交 → wait_for_result 取结果 → query_task 查状态,讲清后端命名规则、异步轮询、统一结果的后处理、批量提交、凭据配置,最后用 uniqc 命令行把整套流程串起来。
本页示例基于 unified-quantum 0.1.0,所有输出均为实际运行结果。本章约定:可运行的示例全部跑在 dummy 后端家族上(不需要任何 token、不联网);涉及真实云平台的代码以"模板"标注呈现,需要你先配置平台凭据(见第 6 节)才能运行。
测量统计与期望值的理论背景见量子计算算法教程·量子计算基础。如果你还没读过快速开始第 5 节的统一执行入口,建议先补上。
本课知识点
云执行工作流——能写出
submit_task → wait_for_result → query_task的完整调用链,并解释每一步的返回值。后端命名与平台选择——能解释
provider:chip-name规范格式与 dummy 家族各成员的语义,为给定线路选择合适的后端。异步轮询与任务状态——能用
poll_result与TaskStatus构造非阻塞轮询循环,并正确处理失败任务。统一结果与期望值后处理——能从
UnifiedResult读取计数并计算 Pauli 期望值,解释 bitstring 的 LSB 约定。批量提交——能用
submit_batch一次提交整组线路,并按提交顺序收集各线路的结果。凭据与配置管理——能写出配置各平台 token 的命令,描述
~/.uniqc/config.yaml的 profile 结构。命令行工作流——能用
uniqc submit/result/task完成"提交—取结果—管理"的命令行闭环。
1. 云执行工作流:submit → wait → query¶
三个函数构成主链路:submit_task 把线路交给后端并立即返回任务号(uqt_ 开头);wait_for_result 阻塞等待任务完成并返回统一结果;query_task 查询任务的元信息。先用最熟悉的 Bell 线路在 dummy 后端上走一遍:
from uniqc import Circuit, submit_task, wait_for_result, query_task
circuit = Circuit()
circuit.h(0)
circuit.cnot(0, 1)
circuit.measure(0, 1)
task_id = submit_task(circuit, backend="dummy:local:simulator", shots=1024)
print("task_id:", task_id)
result = wait_for_result(task_id, timeout=60)
print("counts:", dict(result.counts))
print("probabilities:", {k: round(v, 4) for k, v in result.probabilities.items()})
print("platform:", result.platform, "| backend:", result.backend_name)
info = query_task(task_id)
print("status:", info.status)
task_id: uqt_d05cefcee20a442dad63f0eb4f40408e
counts: {'00': 512, '11': 512}
probabilities: {'00': 0.5, '11': 0.5}
platform: dummy | backend: dummy:local:simulator
status: success
(task_id 每次运行都不同;dummy 后端按态矢量的精确概率确定性生成计数,所以同一线路的计数可复现。)
调用链的设计是异步的:submit_task 只负责登记任务,不等结果。dummy 后端在本地同步执行、瞬间完成,所以上面的 wait_for_result 立刻返回;真实云平台则要排队,可能等几秒到几小时。
circuit 参数除了 Circuit 对象,也接受 OriginIR 字符串(QINIT 开头)、OpenQASM 2.0 字符串(OPENQASM 开头)或 qiskit.QuantumCircuit,提交时自动检测转换——任意工具产出的线路文本都能走这个入口。
提交到真实云平台,调用链完全相同,只换 backend(以下为模板,本页未运行,需要真实 token):
# 模板:提交到 OriginQ 真机(需要先配置 token,见第 6 节)
task_id = submit_task(circuit, backend="originq:WK_C180", shots=1024)
result = wait_for_result(task_id, timeout=600, poll_interval=5)
print(result.counts)
2. 后端命名与平台选择¶
backend 参数是字符串,两种形态:
云平台后端:
provider:chip-name规范格式,如originq:WK_C180、ibm:ibm_brisbane。仅传裸平台名('originq')会被拒绝,错误信息会列出本地缓存里可用的 chip。本地 dummy 后端:以
dummy开头,不联网、不需要凭据,是本章的主角。
后端 ID |
含义 |
|---|---|
|
无约束、无噪声的本地虚拟机 |
|
N 比特线性拓扑(链),无噪声 |
|
R×C 网格拓扑,无噪声 |
|
N 比特 MPS 模拟器(线性链) |
|
复用真实芯片的拓扑与标定数据,本地含噪模拟(规则型写法,不在后端列表中) |
|
OriginQ 180 比特真机(需 token) |
|
OriginQ 全振幅云模拟器(需 token) |
|
IBM 真机(需 token) |
同一份代码换后端即可迁移。dummy 家族内部对比:
from uniqc import Circuit, submit_task, wait_for_result
from uniqc import list_backends
print("registered backends:", list_backends())
bell = Circuit()
bell.h(0)
bell.cnot(0, 1)
bell.measure(0, 1)
for backend_id in ["dummy:local:simulator", "dummy:local:virtual-line-3"]:
task_id = submit_task(bell, backend=backend_id, shots=1024)
result = wait_for_result(task_id)
print(f"{backend_id:32s} -> {dict(result.counts)}")
registered backends: ['dummy', 'ibm', 'logicalqubit', 'originq', 'quark', 'tianyan']
dummy:local:simulator -> {'00': 512, '11': 512}
dummy:local:virtual-line-3 -> {'00': 512, '11': 512}
两个后端计数相同,因为 CNOT q[0], q[1] 恰好落在链 0–1–2 的相邻边上;virtual-line-3 与 simulator 的区别在于它强制执行拓扑约束——双比特门只能落在相邻比特对上,第 3 节会看到违反约束的下场。
各平台定位速览:
平台 |
定位 |
额外依赖 |
|---|---|---|
OriginQ Cloud |
主生产路径 |
无 |
IBM Quantum |
国际平台 |
无(qiskit 是核心依赖) |
Tianyan(天衍) |
国内平台(QCIS 格式) |
无 |
LogicalQubit |
逻辑比特平台 |
无 |
QuarkStudio / Quark |
第三方云平台 |
|
Dummy |
本地模拟 |
无 |
dummy:<platform>:<backend>(如 dummy:originq:WK_C180)是一类特别的成员:先用真实芯片的拓扑与标定数据做编译,再在本地注入该芯片的噪声执行,让你在花真机额度之前预估线路在该芯片上的表现。它需要本地已有对应平台的芯片缓存(配置 token 后运行 uniqc backend list -p originq 会自动拉取),含噪模拟的细节见第 3 章。
3. 异步轮询与任务状态¶
任务有五种状态:
|
含义 |
|---|---|
|
已登记、尚未开始 |
|
执行中 |
|
成功完成 |
|
执行失败 |
|
已取消 |
poll_result 是非阻塞查询:立即返回当前状态,适合放进自己的循环里;wait_for_result 与 get_result 是阻塞接口,内部替你轮询到终态:
import time
from uniqc import Circuit, submit_task, poll_result, wait_for_result, TaskStatus
circuit = Circuit()
circuit.h(0)
circuit.cnot(0, 1)
circuit.measure(0, 1)
task_id = submit_task(circuit, backend="dummy:local:simulator", shots=1024)
info = poll_result(task_id) # 非阻塞:立即返回当前状态
print("poll:", info.status)
while info.status in (TaskStatus.PENDING, TaskStatus.RUNNING):
time.sleep(0.5)
info = poll_result(task_id)
print("final:", info.status)
result = wait_for_result(task_id) # 已完成的任务立刻返回结果
print(dict(result.counts))
poll: success
final: success
{'00': 512, '11': 512}
注意第一次 poll_result 就返回 success——dummy 在提交时就同步算完了。真实云平台上这段循环会先看到 running、转若干圈后到 success,这正是轮询模式存在的意义:你可以在等待间隙做别的事(提交下一批线路、写文件)。
再看失败路径。把一个双比特门放到 virtual-line-3 的不相邻比特对上:
from uniqc import Circuit, submit_task, poll_result, wait_for_result, TaskFailedError
bad = Circuit()
bad.h(0)
bad.cnot(0, 2) # q[0] 与 q[2] 在 line-3 拓扑上不相邻
bad.measure(0, 1, 2)
task_id = submit_task(bad, backend="dummy:local:virtual-line-3", shots=100)
print("poll:", poll_result(task_id).status)
try:
wait_for_result(task_id)
except TaskFailedError as e:
print("TaskFailedError:", str(e)[:110], "…")
poll: failed
TaskFailedError: Task 'uqt_3e43e1439c4d4c85b232946256924267' failed on backend 'dummy:local:virtual-line-3': shard 0: Error in …
拓扑违规不会在提交时被拦下,而是在执行时失败:poll_result 给出 failed,wait_for_result 默认抛 TaskFailedError(传 raise_on_failure=False 则返回 None,适合批量任务"先收尸、后分析");等超时则抛 TaskTimeoutError。错误信息里带着后端名、分片号与出错的门,足以定位问题。
所有任务(含结果与元数据)都落在本地缓存 ~/.uniqc/cache/tasks.sqlite 里,进程退出、机器重启都不丢:
from uniqc import list_tasks
for t in list_tasks(limit=3):
print(t.task_id[:16] + "…", t.status, t.backend)
uqt_4993d4da58b4… failed dummy:local:virtual-line-3
uqt_e1b1a204e677… failed dummy:local:virtual-line-3
uqt_8af4519d11a9… success dummy:local:virtual-grid-2x2
(列表内容取决于本机任务历史,每次运行略有不同。)配套的清理函数是 clear_completed_tasks() 与 clear_cache()。
4. 统一结果与期望值后处理¶
各平台原生结果格式五花八门(IBM 的小端 BitArray、天衍的测量比特标签序……),UnifiedResult 把它们全部归一:counts 是 {bitstring: 计数},probabilities 是归一化概率,另有 shots、platform、backend_name、task_id、execution_time、error_message 等元信息字段。
先跑一个三比特线路,再做两类后处理:
import math
from uniqc import (
Circuit,
calculate_expectation,
shots2prob,
submit_task,
wait_for_result,
)
circuit = Circuit()
circuit.x(0) # q[0] -> |1>
circuit.rx(1, math.pi) # q[1] -> |1>(相位无关)
circuit.ry(2, math.pi / 2)
circuit.cz(1, 2) # q[1]=|1> 时对 q[2] 加 Z
circuit.measure(0, 1, 2)
result = wait_for_result(submit_task(circuit, backend="dummy:local:simulator", shots=1000))
print("counts:", dict(result.counts))
print("probabilities:", {k: round(v, 4) for k, v in result.probabilities.items()})
print(f"<ZII> = {calculate_expectation(result.probabilities, 'ZII'):+.4f}")
print(f"<IIZ> = {calculate_expectation(result.probabilities, 'IIZ'):+.4f}")
print("shots2prob:", {k: round(float(v), 4) for k, v in shots2prob(result.counts).items()})
counts: {'001': 0, '011': 500, '101': 0, '111': 500}
probabilities: {'001': 0.0, '011': 0.5, '101': 0.0, '111': 0.5}
<ZII> = +0.0000
<IIZ> = -1.0000
shots2prob: {'001': 0.0, '011': 0.5, '101': 0.0, '111': 0.5}
三个值得停下来说的细节:
bitstring 的 LSB 约定。 c[0](第一次 measure 的结果)永远是 bitstring 最右侧字符,c[N-1] 在最左侧。本例 measure(0, 1, 2) 依次把 q[0]、q[1]、q[2] 写入 c[0]、c[1]、c[2],所以 '011' 读作 c[2]=0、c[1]=1、c[0]=1。这条约定对所有平台生效(由发布测试强制保护),下游代码不需要做 [::-1] 之类的手工翻转。自检探针:x(0) 后先测 q[0] 再测 q[1],任何后端的支配性结果都必须是 '01'——
probe = Circuit()
probe.x(0)
probe.measure(0) # -> c[0],bitstring 最右字符
probe.measure(1) # -> c[1]
probe_result = wait_for_result(submit_task(probe, backend="dummy:local:simulator", shots=1024))
print("endianness probe:", dict(probe_result.counts))
endianness probe: {'01': 1024}
期望值。 calculate_expectation(probabilities, 'IIZ') 按 Pauli 串计算 ⟨Z⟩ 型期望值,Pauli 串与 bitstring 同序(最左字符对应最高位)。本例 q[0] 恒为 |1⟩,故 ⟨IIZ⟩ = −1;q[2] 处在 (|0⟩−|1⟩)/√2 上完全随机,故 ⟨ZII⟩ = 0。期望值是变分算法的燃料——为什么 VQE 需要反复测 ⟨H⟩,见量子计算算法教程·VQE与本站第 7 章实操。
0 计数的键。 counts 里出现了 '001'、'101' 两个 0 计数键:RX(math.pi) 中浮点数 π 让 cos(π/2) ≈ 6×10⁻¹⁷ ≠ 0,q[1]=0 的分支留下了微小振幅,态矢量模拟器便把它计入支集。真实硬件只返回实际测到的结果,通常不会出现 0 计数键;后处理代码不应假设键集合等于支集。
5. 批量提交:submit_batch¶
参数扫描、变分算法的每个迭代步都要提交一组线路。submit_batch 接受线路列表,返回一个 uqt_* 批任务号;wait_for_result 对批任务返回 list[UnifiedResult],顺序与提交顺序一致:
import math
from uniqc import Circuit, submit_batch, wait_for_result
circuits = []
for i in range(3):
c = Circuit()
c.h(0)
c.rx(1, i * math.pi / 4)
c.cnot(0, 1)
c.measure(0, 1)
circuits.append(c)
batch_id = submit_batch(circuits, backend="dummy:local:simulator", shots=1000)
print("batch_id:", batch_id)
results = wait_for_result(batch_id) # 批量任务返回 list[UnifiedResult]
print("results:", len(results))
for i, r in enumerate(results):
print(i, dict(r.counts))
batch_id: uqt_d68a16dc528942b4b54b3dec68981af9
results: 3
0 {'00': 500, '11': 500}
1 {'00': 427, '01': 73, '10': 73, '11': 427}
2 {'00': 250, '01': 250, '10': 250, '11': 250}
顺手笔算验证 i=1:线路是 H(0)、RX(1, π/4)、CNOT,末态为 \(\frac{1}{\sqrt2}\left(\cos\frac{\pi}{8}(|00\rangle+|10\rangle) - i\sin\frac{\pi}{8}(|01\rangle+|11\rangle)\right)\),四个结果的概率为 \(\frac{\cos^2(\pi/8)}{2} \approx 0.427\) 与 \(\frac{\sin^2(\pi/8)}{2} \approx 0.073\)——与 427/73 精确吻合。i=2 时 RX(π/2) 把 q[1] 变成均匀叠加,四个结果各 1/4。
批量下的单一句柄语义在所有平台一致:对支持原生批量的平台(OriginQ、IBM)线路会打包成一个平台任务;对 dummy 这类"批量能力为 1"的平台,uniqc 内部逐条循环执行,但你始终只管理一个 uqt_* 号。注意批次是"一荣俱荣、一损俱损":任何一条线路失败,整个批任务转为 failed,错误信息会指出出错的是第几个分片(shard)。
6. 凭据与配置管理¶
所有用户状态集中在 ~/.uniqc/,凭据在 ~/.uniqc/config.yaml,按 profile 分组,active_profile 指明当前生效的组:
active_profile: default
default:
originq:
token: "your-originq-token"
ibm:
token: "your-ibm-token"
proxy:
http: "http://proxy:8080" # 可选:内网访问 IBM 时需要
https: "http://proxy:8080"
tianyan:
login_key: "your-tianyan-login-key"
logicalqubit:
api_key: "your-logicalqubit-api-key"
各平台凭证字段:OriginQ 用 originq.token,IBM 用 ibm.token(可选 proxy),天衍用 tianyan.login_key,LogicalQubit 用 logicalqubit.api_key,Quark 用 quark.QUARK_API_KEY(可选 quark.host)。
日常推荐用 CLI 配置(以下为模板,本页未运行,请替换成你自己的 token):
uniqc config init # 生成默认配置文件
uniqc config set originq.token <YOUR_TOKEN> # 写入 token
uniqc config set ibm.proxy.http http://proxy.example.com:8080
uniqc config validate # 校验配置格式
uniqc config profile list # 多账号隔离:列出/切换 profile
uniqc config profile use work
也可以临时用环境变量 UNIQC_PROFILE=work 切换 profile,或直接手动编辑 YAML 文件。
下面这段只读演示在临时目录里完整走一遍"写入配置 → 加载 → 校验",不触碰真实的 ~/.uniqc/config.yaml(token 均为脱敏占位符):
import tempfile
from pathlib import Path
from uniqc.backend_adapter.config import load_config, save_config, validate_config
workdir = Path(tempfile.mkdtemp(prefix="uniqc-config-demo-"))
config_path = workdir / "config.yaml"
save_config(
{
"active_profile": "demo",
"demo": {
"originq": {"token": "originq-token-redacted"},
"quark": {"QUARK_API_KEY": "quark-token-redacted"},
"ibm": {
"token": "ibm-token-redacted",
"proxy": {"http": "", "https": ""},
},
},
},
config_path=config_path,
)
loaded = load_config(config_path=config_path)
errors = validate_config(config_path=config_path)
print("written to: <temporary-directory>/config.yaml")
print("active profile:", loaded["active_profile"])
print("originq token (redacted):", loaded["demo"]["originq"]["token"])
print("validation errors:", errors)
written to: <temporary-directory>/config.yaml
active profile: demo
originq token (redacted): originq-token-redacted
validation errors: []
配置好 token 之后,先 uniqc backend list -p originq 拉取可用芯片列表(顺带填充本地芯片缓存),再挑一个 chip 提交——provider:chip-name 里的 chip 名就来自这个列表。
7. 命令行工作流:uniqc CLI¶
unified-quantum 安装后自带 uniqc 命令。uniqc --help 列出全部子命令(节选):
╭─ Commands ───────────────────────────────────────────────────────────────────╮
│ circuit Circuit format conversion (OriginIR <-> QASM) │
│ simulate Local circuit simulation │
│ submit Submit circuits to quantum cloud platforms │
│ result Query task results from quantum cloud platforms │
│ doctor Run diagnostics to verify your uniqc installation │
│ config Manage API key and configuration │
│ task Manage submitted tasks │
│ backend List, update, and inspect quantum cloud backends │
│ calibrate Run chip calibration experiments — XEB benchmarking │
╰──────────────────────────────────────────────────────────────────────────────╯
命令行与 Python API 共享同一套任务缓存,所以 CLI 提交的任务能用 API 查,反之亦然。先看本机有哪些后端:
uniqc backend list --platform dummy
Available Backends
╭────────────┬──────────────────────────────┬──────────┬──────────────┬────────╮
│ Platform │ Name │ Qubits │ Status │ Type │
├────────────┼──────────────────────────────┼──────────┼──────────────┼────────┤
│ dummy │ dummy:local:simulator │ - │ available │ sim │
│ dummy │ dummy:local:virtual-line-3 │ 3 │ available │ sim │
│ dummy │ dummy:local:virtual-grid-2x2 │ 4 │ available │ sim │
│ dummy │ dummy:local:mps-linear-3 │ 3 │ available │ sim │
╰────────────┴──────────────────────────────┴──────────┴──────────────┴────────╯
(输出还会列出本机各平台的芯片缓存状态;virtual:* 开头的条目是用户自定义噪声虚拟机,见第 3 章。)
把 Bell 线路存成 OriginIR 文件 bell.originir,先本地模拟、再提交:
QINIT 2
CREG 2
H q[0]
CNOT q[0], q[1]
MEASURE q[0], c[0]
MEASURE q[1], c[1]
uniqc simulate bell.originir --shots 256
Simulation Results
┏━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━┓
┃ State ┃ Count ┃ Probability ┃
┡━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━┩
│ 00 │ 127 │ 50.0% │
│ 11 │ 127 │ 50.0% │
└───────┴───────┴─────────────┘
(simulate 走随机采样,计数每次运行略有不同。)
提交并等待结果,--format json 方便脚本消费:
uniqc submit bell.originir --backend dummy -s 64 --wait --format json
{
"task_id": "uqt_19391564e0294b108980e7e1c124997e",
"backend": "dummy:local:simulator",
"shots": 64
}
{
"counts": {
"00": 32,
"11": 32
},
"probabilities": {
"00": 0.5,
"11": 0.5
},
"shots": 64,
"platform": "dummy",
"task_id": "uqt_19391564e0294b108980e7e1c124997e",
"backend_name": "dummy:local:simulator",
"execution_time": null,
"error_message": null
}
第一个 JSON 是提交回执,第二个是 --wait 等到的结果。之后随时可以凭 task_id 回查或管理:
uniqc result uqt_19391564e0294b108980e7e1c124997e
uniqc task list --limit 5
Result for
uqt_19391564e0294b108980e7e1c12
4997e
┏━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━┓
┃ State ┃ Count ┃ Probability ┃
┡━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━┩
│ 00 │ 32 │ 50.0% │
│ 11 │ 32 │ 50.0% │
└───────┴───────┴─────────────┘
Tasks
┏━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┓
┃ Task ID ┃ Platform ┃ Status ┃ Shots ┃ Submit Time ┃
┡━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━━━━━━━┩
│ uqt_19391564e029… │ dummy:local:simu… │ success │ 64 │ 2026-09-05T03:30:… │
└───────────────────┴───────────────────┴─────────┴───────┴─────────────────────┘
(task list 的行数与内容取决于本机任务历史,每次运行略有不同;此处只保留了一行。)
提交前想确认线路与目标后端兼容,--dry-run 只做本地翻译与兼容性检查、不发任何网络请求:
uniqc submit bell.originir --backend dummy --dry-run
✓ [DRY-RUN PASSED] Dry-run passed for dummy simulator: OriginIR is valid.
Qubits=2, shots=1000
Circuit qubits: 2
Backend: dummy:local:simulator
真机路径同样是换 --backend(以下为模板,本页未运行,需要先 uniqc config set originq.token <YOUR_TOKEN>):
uniqc submit bell.originir --backend originq:WK_C180 --shots 1024 --wait
下一步¶
线路在真机上跑歪了怎么办?继续第 6 章:芯片校准与误差缓解,用 XEB 与 M3 把噪声"量出来、除回去"
想看统一结果如何直接变成图表,见第 4 章:可视化
期望值后处理是变分算法的地基,实战见第 7 章:VQE 实操;理论推导读量子计算算法教程·VQE
练习题¶
练习 1【云执行工作流】(→ 第 1 节)
把第 1 节线路里的
cnot(0, 1)改成cz(0, 1),先笔算测量分布是否变化(注意 CZ 只给 |11⟩ 加相位),再运行验证你的预测。提交任务后不调用
wait_for_result,直接query_task(task_id)打印info.status与info.task_id,确认与UnifiedResult携带的task_id一致,并解释为什么 task_id 是任务的唯一句柄。
练习 2【后端命名与平台选择】(→ 第 2 节)
把第 2 节脚本中的
virtual-line-3换成virtual-grid-2x2,预测 Bell 线路能否成功、计数是多少,再运行验证。解释
submit_task(circuit, backend="originq")为什么会失败;正确的写法是什么,可用 chip 列表从哪里获得?
提示:backend 需要
provider:chip-name规范格式,错误信息会列出本地缓存里可用的 chip。
练习 3【异步轮询与任务状态】(→ 第 3 节)
把第 3 节轮询循环里的
time.sleep(0.5)改成time.sleep(0.1),观察 dummy 后端下循环体执行了几次,并解释在真实云平台上这个循环为什么通常会转很多圈。构造一个必定失败的任务(参考拓扑违规线路),先用
poll_result确认状态为failed,再用wait_for_result(task_id, raise_on_failure=False)调用一次,观察返回值是什么。
练习 4【统一结果与期望值后处理】(→ 第 4 节)
删掉第 4 节线路里的
circuit.x(0),先笔算新的 counts 支集与 ⟨IIZ⟩ 的值,再运行验证。先预测
calculate_expectation(result.probabilities, 'IZI')的值(q[1] 恒为 |1⟩),再运行验证;随后把测量顺序改成circuit.measure(2, 1, 0),解释 counts 键为什么变了。
提示:Pauli 串与 bitstring 同序,c[i] 记录第 i 次 measure 的结果,与 qubit 编号无关。
练习 5【批量提交】(→ 第 5 节)
把第 5 节的
range(3)改成range(5),先笔算 i=3、i=4 两个线路(RX 角分别为 3π/4 与 π)的计数分布,再运行验证。在批次中间插入一条拓扑违规线路(
cnot(0, 2)提交到virtual-line-3),预测整批任务的行为再运行验证。
提示:批次一损俱损,错误信息里的 shard 编号指出出错的是第几条线路。
练习 6【凭据与配置管理】(→ 第 6 节)
把第 6 节只读演示里的 profile 名从
demo改成prod,运行并观察load_config返回结构与active_profile字段的变化。运行
uniqc config profile --help,写出列出与切换 profile 的命令,并解释多 profile 适合什么场景。
提示:环境变量
UNIQC_PROFILE可以临时切换 profile,不改动配置文件。
练习 7【命令行工作流】(→ 第 7 节)
写一个三比特 GHZ 线路的 OriginIR 文件(H、CNOT(0,1)、CNOT(0,2)、测量),先写出你预期
uniqc simulate --shots 256的计数表,再运行对比(注意 simulate 是随机采样)。把
uniqc submit bell.originir --backend dummy的--shots改成 10,预测--wait --format json输出的 counts 是否仍精确等于 5/5,运行验证并解释。
提示:dummy 后端按精确概率确定性生成计数,10 × 0.5 = 5。