Skip to Content
文档UnitaryLab 模拟器用户手册线路执行与工具流程

线路执行与工具流程

概述

本页整合了线路执行、结果查看、线路分析与绘图、以及 OpenQASM 导入导出的核心用法,适合作为完整工作流的快速参考。


执行线路与查看结果

普通用户直接调用 Circuit.execute(),返回 ExecutionResult 对象:

from unitarylab import Circuit qc = Circuit(2) qc.h(0) qc.cx(0, 1) result = qc.execute()

ExecutionResult 核心字段与方法

  • result.num_qubits:结果所表示的量子比特数。
  • result.shots:本次线路执行的 shots 数。
  • result.state:最终状态向量,只读的一维 NumPy 数组(每次访问都会从后端状态实时转换,不做缓存);多 shots 执行时表示最后一个 shot 的状态。
  • result.backend_state:底层后端原始状态对象(如 GPU 上的 torch 张量),未做设备拷贝,性能敏感场景可直接使用。
  • result.probabilities:包含零概率结果的完整计算基概率分布字典,键为 little-endian 二进制字符串,值为对应概率。
  • result.probability(bitstring, qubits=None):查询单个计算基态结果的概率。
  • result.marginal_probabilities(qubits=None, threshold=0.0):指定子集比特的边际概率分布;传入正阈值可省略更小的值。
  • result.sample(shots=1, qubits=None, seed=None):不坍缩状态,按概率分布采样若干计算基态结果,返回字符串列表。
  • result.expectation(observable, qubits=None):计算可观测量期望值 ,支持 "Z"、"XX"、完整长度 Pauli 串、或 (系数, 算符, 比特) 项列表等多种输入形式。
  • result.measure(target_indices, seed=None):对指定比特执行投影测量并坍缩内部状态,返回测量结果字符串;这个种子独立于 Circuit.execute(seed=...)。
  • result.counts:汇总所有 shots 的经典比特串计数。
  • result.classical_results_map:最后一个 shot 的经典比特索引到测量值(0 或 1)的字典,仅在线路中添加了 measure 操作后才有值。
  • result.classical_registers:按寄存器名分组的最后一个 shot 测量结果。
print(result.state) # [0.70710678+0.j 0.+0.j 0.+0.j 0.70710678+0.j] print(result.probabilities) # {'00': 0.4999..., '10': 0.0, '01': 0.0, '11': 0.4999...} print(result.expectation("ZZ", qubits=(0, 1))) # Bell 态下 ZZ 期望值应接近 1(两比特完全关联)

Pauli 字符串中的字符按给定的 qubits 顺序逐一对应量子比特;省略 qubits 时,第一个字符作用于 qubit 0,第二个字符作用于 qubit 1,以此类推。该算符顺序不同于概率字符串的显示顺序:概率字符串中 qubit 0 位于最右侧。

后端、设备与执行参数

execute() 支持 backend、device、dtype、shots、seed、backend_options 参数:

result = qc.execute(backend='torch', device='cpu')
参数组合适用场景
backend='torch', device='cpu'(默认)适合大多数情况
backend='torch', device='gpu'使用兼容的 CUDA 或 Apple MPS PyTorch 环境加速
backend='numpy', device='cpu'纯 NumPy 环境
backend='cpp', device='cpu'使用编译的 C++ 门核加速 CPU 执行
backend='cpp', device='gpu'使用可选 CUDA C++ 后端;需安装 unitarylab[cuda]
backend='tensornet', device='cpu'大比特数、低纠缠线路,使用 MPS 表示

通常直接调用 qc.execute() 无需指定参数;Torch 可使用兼容的 CUDA 或 Apple MPS GPU。安装 unitarylab[cuda] 后,C++ 后端也可通过 device='gpu' 使用 CUDA;该 extra 支持 Linux x86_64、Linux aarch64 服务器环境和 Windows x86-64,会安装适配平台的 unitarylab-cu12 wheel。运行需要兼容的 NVIDIA 驱动,但不要求本地安装 CUDA Toolkit。若可选 CUDA 扩展未安装或无法加载,请改用 Torch GPU、C++ CPU、Torch CPU 或 NumPy。比特数很大但纠缠有限时可尝试 backend='tensornet' 并通过 backend_options 控制 max_bond/cutoff/routing。seed 默认固定为 42(结果可复现),需要真正随机采样时传 seed=None。参数完整说明见 快速开始 与 核心线路接口。


密度矩阵与噪声模型

需要模拟混态或噪声时,使用 Circuit.execute_density()。这是独立于 execute() 状态向量后端的密度矩阵接口:device="cpu" 使用原生 cppdensity 后端;安装 CUDA extra 后,device="gpu"、"cuda" 或 "cuda:N" 使用 CUDA 密度矩阵后端。

import numpy as np from unitarylab import Circuit qc = Circuit(2) qc.h(0) qc.cx(0, 1) result = qc.execute_density( initial_state=None, device="cpu", dtype=np.complex128, ) print(result.state) # shape: (2**n, 2**n) print(result.trace) # 约等于 1 print(result.purity) # Bell 纯态为 1 print(result.probabilities) # {'00': 0.5, '10': 0.0, '01': 0.0, '11': 0.5} print(result.expectation("ZZ"))

initial_state 可以是 None、状态向量、密度矩阵或 DensityMatrixState。返回的 DensityMatrixResult 提供 state、backend_state、trace、purity、probabilities、probability()、marginal_probabilities() 和 expectation()。当前密度矩阵后端支持 unitary 演化,但不支持电路测量、状态坍缩或 shots/counts。

内置单量子比特噪声通道包括 BitFlip、PhaseFlip、DepolarizingNoise、AmplitudeDamping 和 PhaseDamping。使用 NoiseOperator 绑定门或目标比特规则,再将 NoiseModel 传给 execute_density():

from unitarylab.backend import ( AmplitudeDamping, BitFlip, NoiseModel, NoiseOperator, ) noise_model = NoiseModel([ NoiseOperator(BitFlip(0.02), gate_ids=("x", "rx")), NoiseOperator(AmplitudeDamping(0.05), qubits=(1,)), ]) noisy_result = qc.execute_density(noise_model=noise_model)

规则固定在匹配的 primitive gate 之后应用。NoiseOperator 的 qubits 过滤条件仅匹配门的目标量子比特,不匹配控制量子比特;对于多目标门,匹配的单量子比特通道会独立应用于每个匹配目标。gate_ids=None 匹配所有实体 primitive gate,qubits=None 表示对匹配门的每个目标应用通道。恒等门(i)和全局相位门(gp、gphase、global_phase)不会触发噪声。当前不支持公开的自定义 Kraus 通道、门前噪声、相关多比特噪声或 readout error。


优化、编译与硬件提交

Circuit 提供常用的优化、门展开、mapping 和硬件提交入口:

from unitarylab import Circuit TOKEN = "your-provider-token" qc = Circuit(2) qc.h(0) qc.cx(0, 1) optimized = qc.optimize(optimization_level=1) transpiled = qc.transpile(basis="default") # 编译到目标硬件格式,但不提交任务 compiled = qc.compile(provider="guodun", token=TOKEN) # 编译并提交真实硬件任务 hardware_result = qc.submit( provider="guodun", machine="gd_qc1", # 国盾量子“骁鸿一号” token=TOKEN, shots=1024, )

optimize() 和 transpile() 返回 Circuit;compile() 返回 CompilationResult,包含映射后线路和 QCIS,但不会提交任务或消耗任务积分;submit() 会提交硬件任务,并统一返回 HardwareResult。传入 machine 可选择目标机器。Guodun 和 Tianyan 省略 machine(或传入 None)时会查询机器列表并自动选择;未匹配首选别名时使用列表中的第一台,例如 gd_qc1 对应国盾量子“骁鸿一号”。其他硬件适配器通常要求显式指定 machine。

compile() 仅支持 local、guodun 和 tianyan;其他 provider adapter 会在 submit() 中完成编译。真机编译和提交需要 provider 凭据,可以通过 token 显式传入。省略时,Guodun 和 Tianyan 分别回退到 GUODUN_LOGIN_KEY 和 TIANYAN_LOGIN_KEY;高级 QCompiler 配置也可使用 hardware.login_key。

需要以 OpenQASM 为输入或精细配置各阶段时,可直接使用顶层延迟导出的 QCompiler:

from unitarylab import QCompiler # 无高级配置时直接构造;也可传入 CompileConfig、配置映射或配置文件路径 compiler = QCompiler() optimized = compiler.optimize(circuit_or_qasm) transpiled = compiler.transpile(qc, basis="default") compiled = compiler.compile(circuit_or_qasm, provider="guodun", token=TOKEN) hardware_result = compiler.submit( circuit_or_qasm, provider="guodun", machine="gd_qc1", token=TOKEN, shots=1024, )

底层产物流为 raw_qasm -> optimized_qasm -> mapped_qcis -> hardware_result。Guodun/Tianyan 与其他厂商均由 QCompiler.submit() 内部分流。LQCloud 需要单独安装 lqcloud SDK,QPanda3 需要 pyqpanda3,Quafu 需要 QuarkStudio(quarkstudio);缺少所需 SDK 时会在提交阶段报错。


线路分析与绘图

draw()

qc.draw() # 弹出图窗(默认 output='mpl') qc.draw(filename='circuit.png') # 保存为文件 qc.draw(filename='circuit.png', title='Bell State') # 添加标题 qc.draw(output='text') # 纯文本线路图 qc.draw(output='latex') # LaTeX(quantikz)线路图 qc.draw(compact=False) # 关闭相邻单比特门合并

在 Jupyter Notebook 中图形会内联显示,在普通脚本中会弹出独立窗口。output 支持 'mpl'(默认,Matplotlib)、'text'、'latex' 三种模式,分别对应内部的 MatplotlibCircuit、TextCircuitDrawer、LatexCircuitDrawer。

CircuitInfo

CircuitInfo 提供线路静态分析,可通过 qc.analyze() 快捷调用:

from unitarylab.circuit_analysis import CircuitInfo info = CircuitInfo(qc) # 等价于 info = qc.analyze(show=False) info.show() # 打印概览、指令列表、层结构

常用方法:

方法说明
size()门总数
depth()build_layers() 贪心分组产生的无比特冲突层数;它是静态并行分组指标,不等同于严格保持原门顺序的数据依赖最长路径
count_ops()各门类型出现次数,返回 dict
count_single_qubit_gates() / count_two_qubit_gates() / count_multi_qubit_gates()按比特数分类的门计数
count_parameterized_gates()带参数(旋转角等)的门数量
get_qubit_usage()各量子比特的操作次数
get_coupling_map()量子比特耦合关系(双比特门连接对),例如 [(0, 1), (1, 2)]
get_qubit_history(qubit)指定比特的完整操作历史
get_instructions() / get_layers() / get_parameters()分别返回指令列表、按 build_layers() 贪心规则分组的门、参数化门的参数汇总
is_parameterized()线路是否包含参数化门
get_summary() / to_dict()结构化概览 / 将分析结果整体导出为字典
show(sections=None, qubit=None)按章节打印分析结果

show() 支持的 sections 值:'overview'(或别名 'summary')、'instructions'、'layers'、'qubit_usage'、'coupling_map'、'parameters'、'qubit_history'(需同时指定 qubit= 参数)。不传 sections 时默认打印 ['overview', 'instructions', 'layers']。

info.show(sections=['overview', 'coupling_map']) info.show(sections='qubit_history', qubit=0)

OpenQASM 导入导出

OpenQASM 2.0 / 3.0 均受支持,适合保存、交换线路,或与其他工具互操作。公开方法与参数速查见 核心线路接口;这里重点说明底层接口和兼容性限制。

# 使用前文已经构建的 qc;默认导出 OpenQASM 3.0 qasm3_str = qc.to_qasm() qasm2_str = qc.to_qasm2() # 导入(自动识别 2.0 / 3.0) qc2 = Circuit.from_qasm(qasm3_str)

底层函数(高级用法)

Circuit.to_qasm() / from_qasm() 内部委托给 unitarylab.backend.qasm 模块的一组函数,直接操作 GateSequence 而非 Circuit。仅在需要脱离 Circuit 单独处理 GateSequence,或需要显式指定寄存器结构时才需要直接调用:

from unitarylab.backend.qasm import ( gate_sequence_to_qasm, # 统一入口,默认导出 QASM 3.0 gate_sequence_to_qasm2, gate_sequence_to_qasm3, gate_sequence_from_qasm, # 统一入口,自动识别版本 qasm2_to_gate_sequence, qasm3_to_gate_sequence, circuit_from_gate_sequence, # 将 GateSequence 重建为 Circuit ) qasm_str = gate_sequence_to_qasm3(qc.gate_sequence, qreg_name='q') gs = qasm3_to_gate_sequence(qasm_str) qc3 = circuit_from_gate_sequence(Circuit, gs)

支持范围与限制

转换器覆盖常用单比特门、参数门、受控门、SWAP、测量和自定义 gate 定义。QASM 3.0 还使用 ctrl @ / negctrl @ 修饰符表示正、负控制;QASM 2.0 会按其可表示范围改写受控门。具体可往返的语法和门集合以两个转换模块 unitarylab.backend.qasm.qasm2、unitarylab.backend.qasm.qasm3 的实现为准,两种版本并非拥有完全相同的表示能力。

主要限制:

  • 同时支持 OpenQASM 2.0 和 3.0,默认导出/自动识别均以 3.0 为准;需要 2.0 时显式调用 to_qasm2() / gate_sequence_to_qasm2()。
  • 门参数必须是数值,不支持符号表达式(如 pi/2 会被数值化)。
  • 不支持经典控制流(if、while 等)。
  • 并非所有自定义门都能完整往返导出;非连续块门会内联展开。
  • 携带矩阵信息的 unitary 门(即通过 qc.unitary(matrix, target) 添加、g.matrix 属性非空的门)会以 UnitaryLab 扩展语句形式导出(矩阵元素编码为交替的实部/虚部参数),并可通过 from_qasm() 完整还原——这是 UnitaryLab 专属扩展,并非标准 OpenQASM 3.0 互操作格式,若目标是导入第三方工具,仍建议先 transpile()。只有当 unitary 门的矩阵信息缺失(g.matrix is None,一般出现在部分中间处理路径)时,to_qasm() 才会抛出 NotImplementedError 并在错误信息中给出重试建议(transpile=True 或 decompose=True, transpile=True)。

综合示例

以下是一个包含执行、查看结果、分析、绘图和导出 OpenQASM 的最小完整示例:

from unitarylab import Circuit # 1. 创建 Bell 线路 qc = Circuit(2) qc.h(0) qc.cx(0, 1) # 2. 执行线路 result = qc.execute() # 3. 查看概率 print(result.probabilities) # {'00': 0.4999..., '10': 0.0, '01': 0.0, '11': 0.4999...} # 4. 线路分析 qc.analyze(show=True, sections=["summary"]) # 5. 绘图 qc.draw(title="Bell State") # 6. 导出 OpenQASM 3.0(详细说明见上文) qasm_str = qc.to_qasm()

注意事项

  • Qubit 顺序:probabilities 的键为 little-endian 二进制字符串,最右位对应 qubit 0;默认结果包含零概率项。
  • 投影测量会坍缩状态:result.measure() 会修改内部状态(投影坍缩)。如需在同一个未坍缩状态上重复查询不同子系统的分布,使用 result.marginal_probabilities() 或 result.sample(),它们都不会修改 result.state;只有 result.measure() 会坍缩。
  • GPU 与后端:默认设置适用于大多数场景,仅在性能调优时需要调整 backend、device、dtype、backend_options。
  • 编译与提交不同:compile() 只生成目标硬件产物,submit() 才会提交真实硬件任务。
  • MDX 特殊字符:在 MDX 文件中,表格单元格内容中的 | 应写为 |;{}、\ 等特殊字符应放入代码块或行内代码。

推荐阅读

最后更新于