主路径走读 (Walkthrough)¶
把 构造电路 → 本地模拟 → 提交并后处理 → 配置 → 可视化 五件事按顺序串一遍。
每一节都来自 examples/1_basic_usage/0X_*.py,由文档构建器自动重跑、把输出拼进文档,
所以只要本地能 make html,这些示例就一定是可运行的。
1. 构造电路:原生 Circuit、qreg、OriginIR / QASM 导出¶
01 — Circuit basics: gates, qregs, OriginIR / OpenQASM export¶
Source: examples/1_basic_usage/01_circuit_basics.py
Status: pass
最常用的 Circuit 能力:原生 gate API、寄存器、测量,以及导出到 OriginIR /
OpenQASM 2.0 两种文本格式。
Source code
"""01 — Circuit basics: gates, qregs, OriginIR / OpenQASM export
[doc-require: ]
[doc-output-include: stdout, source]
最常用的 ``Circuit`` 能力:原生 gate API、寄存器、测量,以及导出到 OriginIR /
OpenQASM 2.0 两种文本格式。
"""
from __future__ import annotations
import math
from uniqc import Circuit
def main() -> None:
c = Circuit()
c.h(0)
c.x(1)
c.rx(2, math.pi / 2)
c.cnot(0, 1)
c.cz(1, 2)
c.measure(0, 1, 2)
print("== OriginIR ==")
print(c.originir)
print("== OpenQASM 2.0 ==")
print(c.qasm)
print("== qubit remapping ==")
remapped = c.remapping({0: 100, 1: 101, 2: 102})
print(remapped.originir)
if __name__ == "__main__":
main()
Stdout
== OriginIR ==
QINIT 3
CREG 3
H q[0]
X q[1]
RX q[2], (1.5707963267948966)
CNOT q[0], q[1]
CZ q[1], q[2]
MEASURE q[0], c[0]
MEASURE q[1], c[1]
MEASURE q[2], c[2]
== OpenQASM 2.0 ==
OPENQASM 2.0;
include "qelib1.inc";
qreg q[3];
creg c[3];
h q[0];
x q[1];
rx(1.5707963267948966) q[2];
cx q[0], q[1];
cz q[1], q[2];
measure q[0] -> c[0];
measure q[1] -> c[1];
measure q[2] -> c[2];
== qubit remapping ==
QINIT 103
CREG 3
H q[100]
X q[101]
RX q[102], (1.5707963267948966)
CNOT q[100], q[101]
CZ q[101], q[102]
MEASURE q[100], c[0]
MEASURE q[101], c[1]
MEASURE q[102], c[2]
更深入的电路构建(控制结构、参数化、Named Circuit、酉矩阵提取等)见 构造电路。
2. 本地模拟¶
02 — Local simulation paths¶
Source: examples/1_basic_usage/02_local_simulation.py
Status: pass
UnifiedQuantum 自带几条本地模拟路径:
Simulator— 默认 statevector 模拟器;MPS 后端(线性拓扑 + 中等纠缠下可扩展到上百比特)—— 见
examples/2_advanced/01_mps_simulator.py;C++ 后端
uniqc_cpp— 自动作为Simulator的加速实现(如果已编译)。
这里只演示最直接的 simulate_pmeasure 与 simulate_shots。
Source code
"""02 — Local simulation paths
[doc-require: ]
[doc-output-include: stdout, source]
UnifiedQuantum 自带几条本地模拟路径:
* ``Simulator`` — 默认 statevector 模拟器;
* MPS 后端(线性拓扑 + 中等纠缠下可扩展到上百比特)—— 见
``examples/2_advanced/01_mps_simulator.py``;
* C++ 后端 ``uniqc_cpp`` — 自动作为 ``Simulator`` 的加速实现(如果已编译)。
这里只演示最直接的 ``simulate_pmeasure`` 与 ``simulate_shots``。
"""
from __future__ import annotations
from uniqc import Circuit
from uniqc.simulator import Simulator
def main() -> None:
c = Circuit()
c.h(0)
c.cnot(0, 1)
c.cnot(1, 2)
c.measure(0, 1, 2)
sim = Simulator()
print("== probabilities ==")
probs = sim.simulate_pmeasure(c.originir)
for state, prob in enumerate(probs):
if prob > 1e-9:
print(f" |{state:03b}>: {prob:.4f}")
print("== shots ==")
counts = sim.simulate_shots(c.originir, shots=2000)
print(counts)
if __name__ == "__main__":
main()
Stdout
== probabilities ==
|000>: 0.5000
|111>: 0.5000
== shots ==
{0: 998, 7: 1002}
不同 backend 的语义差异、噪声后端选择见 本地模拟。
3. 通过 submit_task 提交并后处理¶
03 — Submit to dummy + result post-processing¶
Source: examples/1_basic_usage/03_submit_and_postprocess.py
Status: pass
走一遍 submit_task → wait_for_result → query_task 的完整路径,并把结果
喂给 calculate_expectation / shots2prob 等后处理工具。
backend="dummy:local:simulator"表示无约束、无噪声;backend="dummy:local:virtual-line-3"在虚拟线性拓扑上跑同一线路(受相邻约束)。
Source code
"""03 — Submit to dummy + result post-processing
[doc-require: ]
[doc-output-include: stdout, source]
走一遍 ``submit_task`` → ``wait_for_result`` → ``query_task`` 的完整路径,并把结果
喂给 ``calculate_expectation`` / ``shots2prob`` 等后处理工具。
* ``backend="dummy:local:simulator"`` 表示无约束、无噪声;
* ``backend="dummy:local:virtual-line-3"`` 在虚拟线性拓扑上跑同一线路(受相邻约束)。
"""
from __future__ import annotations
import math
from uniqc import (
Circuit,
calculate_expectation,
query_task,
shots2prob,
submit_task,
wait_for_result,
)
def build_circuit() -> Circuit:
c = Circuit()
c.x(0)
c.rx(1, math.pi)
c.ry(2, math.pi / 2)
c.cz(1, 2)
c.measure(0, 1, 2)
return c
def main() -> None:
circuit = build_circuit()
task_id = submit_task(circuit, backend="dummy:local:simulator", shots=1000)
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()})
info = query_task(task_id)
print("status:", info.status)
print(f"<ZII> = {calculate_expectation(result.probabilities, 'ZII'):+.4f}")
print(f"<IIZ> = {calculate_expectation(result.probabilities, 'IIZ'):+.4f}")
print("manual prob conversion:", shots2prob(result.counts))
if __name__ == "__main__":
main()
Stdout
task_id: uqt_d847f0a75a994122a74dc3ce4c156fcd
counts: {'001': 0, '011': 500, '101': 0, '111': 500}
probabilities: {'001': 0.0, '011': 0.5, '101': 0.0, '111': 0.5}
status: success
<ZII> = +0.0000
<IIZ> = -1.0000
manual prob conversion: {'001': np.float64(0.0), '011': np.float64(0.5), '101': np.float64(0.0), '111': np.float64(0.5)}
4. 配置文件 / ~/.uniqc/config.yaml¶
UnifiedQuantum 把 token、proxy、profile 等配置统一存放在 ~/.uniqc/config.yaml,
并通过 UNIQC_PROFILE 环境变量切换 profile。
04 — Configuration: uniqc config + ~/.uniqc/config.yaml¶
Source: examples/1_basic_usage/04_config.py
Status: pass
只演示只读的配置 API:本例不会去碰真实的 ~/.uniqc/config.yaml,而是写到一个
临时文件再读回来。
实际使用时推荐三种方式之一:
uniqc config init+uniqc config set originq.token <YOUR_TOKEN>手动编辑
~/.uniqc/config.yaml用
UNIQC_PROFILE环境变量切换 profile
Source code
"""04 — Configuration: ``uniqc config`` + ``~/.uniqc/config.yaml``
[doc-require: ]
[doc-output-include: stdout, source]
只演示**只读**的配置 API:本例不会去碰真实的 ``~/.uniqc/config.yaml``,而是写到一个
临时文件再读回来。
实际使用时推荐三种方式之一:
1. ``uniqc config init`` + ``uniqc config set originq.token <YOUR_TOKEN>``
2. 手动编辑 ``~/.uniqc/config.yaml``
3. 用 ``UNIQC_PROFILE`` 环境变量切换 profile
"""
from __future__ import annotations
import tempfile
from pathlib import Path
from uniqc.backend_adapter.config import load_config, save_config, validate_config
def main() -> None:
workdir = Path(tempfile.mkdtemp(prefix="uniqc-config-demo-"))
config_path = workdir / "config.yaml"
save_config(
{
"active_profile": "demo",
"demo": {
"originq": {"token": "originq-token-redacted"},
"quafu": {"token": "quafu-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:", config_path)
print("active profile:", loaded["active_profile"])
print("originq token (redacted):", loaded["demo"]["originq"]["token"])
print("validation errors:", errors)
print()
print("CLI equivalents:")
print(" uniqc config init")
print(" uniqc config set originq.token YOUR_TOKEN")
print(" uniqc config set ibm.proxy.http http://proxy.example.com:8080")
print(" uniqc config validate")
if __name__ == "__main__":
main()
Stdout
written to: /tmp/uniqc-config-demo-582yy0l8/config.yaml
active profile: demo
originq token (redacted): originq-token-redacted
validation errors: []
CLI equivalents:
uniqc config init
uniqc config set originq.token YOUR_TOKEN
uniqc config set ibm.proxy.http http://proxy.example.com:8080
uniqc config validate
各平台的配置约定与 chip-id 命名见 平台约定。
5. 可视化¶
05 — Visualize circuits and results¶
Source: examples/1_basic_usage/05_visualize.py
Status: pass
两类常用的可视化:
测量结果直方图(
matplotlib直接画 counts/probabilities);时序图
plot_time_line(如果安装了visualizationextra),用来排查 timeline / 并行度问题。
Uses Simulator (unified simulator class from uniqc.simulator).
Source code
"""05 — Visualize circuits and results
[doc-require: matplotlib]
[doc-output-include: stdout, figures, source]
两类常用的可视化:
* 测量结果直方图(``matplotlib`` 直接画 counts/probabilities);
* 时序图 ``plot_time_line``(如果安装了 ``visualization`` extra),用来排查 timeline /
并行度问题。
Uses ``Simulator`` (unified simulator class from ``uniqc.simulator``).
"""
from __future__ import annotations
import matplotlib.pyplot as plt
from uniqc import Circuit
from uniqc.simulator import Simulator
def main() -> None:
c = Circuit()
c.h(0)
c.cnot(0, 1)
c.cnot(1, 2)
c.measure(0, 1, 2)
counts = Simulator().simulate_shots(c.originir, shots=1024)
total = sum(counts.values()) or 1
n = c.qubit_num
probs = {format(int(k), f"0{n}b"): v / total for k, v in counts.items()}
fig, ax = plt.subplots(figsize=(6, 3.4))
ax.bar(list(probs.keys()), list(probs.values()), color="#2a9d8f")
ax.set_xlabel("bitstring")
ax.set_ylabel("probability")
ax.set_title("3-qubit GHZ probabilities")
ax.grid(axis="y", alpha=0.25)
fig.tight_layout()
print("counts:", counts)
print("probabilities:", probs)
if __name__ == "__main__":
main()
Stdout
counts: {7: 521, 0: 503}
probabilities: {'111': 0.5087890625, '000': 0.4912109375}
Figures
真机提交模板¶
from uniqc import Circuit, dry_run_task, submit_task, wait_for_result
c = Circuit(); c.h(0); c.cnot(0, 1); c.measure(0, 1)
# 1. 离线检查(推荐每次都先 dry_run)
print(dry_run_task(c, backend="originq:WK_C180", shots=1000))
# 2. 真机提交
task_id = submit_task(c, backend="originq:WK_C180", shots=1000)
print(wait_for_result(task_id))
更多真机相关的细节(dummy:<platform>:<backend>、calibration cache、QEM)在
进阶教程。