主路径走读 (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_pmeasuresimulate_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_taskwait_for_resultquery_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)}

各平台特有 kwarg、批量提交、错误处理见 提交任务任务管理器

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,而是写到一个 临时文件再读回来。

实际使用时推荐三种方式之一:

  1. uniqc config init + uniqc config set originq.token <YOUR_TOKEN>

  2. 手动编辑 ~/.uniqc/config.yaml

  3. 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(如果安装了 visualization extra),用来排查 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

05 — Visualize circuits and results — figure-01.svg

真机提交模板

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)在 进阶教程