2. 量子程序执行模型与测试对象界定
量子程序并不是“写一段线路然后跑一次”这么简单。它在不同抽象层次上对应不同的执行模型:最上层是量子线路模型,描述门与测量的时序;往下是脉冲级模型,描述微波或激光波形如何驱动量子比特;再往下还有动态电路模型,允许在运行中根据测量结果实时改变后续门操作。单元测试要做的第一件事,就是明确“我测的到底是哪一层的东西”,否则测试用例会写得含糊,失败时也说不清是门逻辑错了、脉冲标定错了,还是经典控制流错了。
三种执行模型及其可观测对象
线路模型是最常见的执行模型。一个线路由量子比特寄存器、若干量子门和末端测量组成,执行时按“从左到右”的时间顺序施加门,最后在测量指令处把量子态坍缩为经典比特串。它的可观测对象是概率分布、期望值、态向量(模拟器)或采样计数(真机)。线路模型适合测试门级逻辑、子线路组合和测量映射。
脉冲模型把每个门展开为具体的控制波形。例如一个超导比特上的 X 门,实际是一段约 20–30 ns 的微波脉冲,带有特定的振幅、频率和相位参数。脉冲级执行模型的可观测对象是波形采样点、脉冲包络、I/Q 分量以及由此产生的布洛赫球演化。测试脉冲层时,关注点不再是“门矩阵对不对”,而是“这段波形是否把比特从 |0⟩ 转到 |1⟩,误差是否在容限内”。
动态电路模型则引入了运行时的经典反馈。典型例子是“测量比特 A,若结果为 1 则对比特 B 施加 X 门”。这种模型下,执行路径依赖中间测量结果,测试对象从静态线路变成了带分支的执行轨迹。它的可观测对象包括分支覆盖率、各分支下的条件态以及反馈延迟是否满足时序约束。
单元测试的边界划分
执行模型清楚了,接下来要回答“一个单元到哪里为止”。量子程序里,单元边界通常按三种方式切分。第一种是按门切分:把单个量子门当作待测单元,输入是已知量子态,输出是门作用后的态,用态层析或模拟器比对目标矩阵。第二种是按子线路切分:把一段有明确功能的门序列(如一个 GHZ 态制备子线路、一个量子傅里叶变换块)当作单元,测试它的整体输出分布是否符合预期。第三种是按测量过程切分:把测量本身当作待测对象,关注测量基选择、经典寄存器映射、读出误差是否在可接受范围。
边界划分的核心原则是“接口清晰、依赖可控”。如果一个子线路内部依赖了外部传入的量子态,那这个态就是它的输入接口,测试时必须显式构造;如果它依赖了某个脉冲标定参数,那这个参数就是外部依赖,测试时应固定或隔离。边界模糊的典型症状是:测试失败时无法判断是门本身错了,还是上游态制备错了,或者测量映射错了。
待测单元的识别方法
实际工程中,识别待测单元可以借助“变更影响面”来反推。假设你修改了一个 CNOT 门的脉冲参数,哪些测试应该重跑?至少包括:该 CNOT 门本身的脉冲级测试、包含该门的子线路功能测试、以及依赖该门产生纠缠态的后续测量测试。这个影响面就是单元边界的自然轮廓。
另一个实用方法是“可独立构造输入”检验。如果一个模块的输入态可以在不依赖其他待测模块的情况下独立制备,它就是一个合格的待测单元。例如测试一个两比特纠缠子线路时,输入 |00⟩ 可以直接由初始化得到,不需要先跑另一个子线路,因此它可以独立成单元。反之,如果某段逻辑必须依赖前一段线路的输出才能构造输入,那这两段更适合合并为一个单元,或者把前一段替换为测试桩(stub)。
一个可执行的测试对象清单示例
下面给出一个针对小型超导线路的测试对象界定示例,参数为教学假设值,用于说明字段如何填写,不代表真实设备实测结果。
| 待测单元 | 执行模型层 | 输入接口 | 观测对象 | 判定依据(示例) |
|---|---|---|---|---|
| 单比特 X 门 | 脉冲级 | |0⟩ 初态 | |1⟩ 态布居数 | 布居数 ≥ 0.98 |
| 两比特 CNOT | 线路级 | |10⟩ 初态 | 输出分布 | |11⟩ 概率 ≥ 0.95 |
| GHZ 子线路 | 线路级 | |000⟩ 初态 | 三比特联合分布 | |000⟩ 与 |111⟩ 合计 ≥ 0.90 |
| 条件反馈分支 | 动态电路 | q0 制备为 |1⟩ | q1 末态 | q1 为 |1⟩ 概率 ≥ 0.95 |
| 测量读出 | 测量过程 | 已知 |0⟩/|1⟩ 态 | 经典比特串 | 读出错误率 ≤ 2% |
这张表的价值不在于阈值本身,而在于它强迫每个待测单元都回答三个问题:输入从哪来、观测什么、凭什么判通过。凡是答不上来的条目,说明边界还没划清,应该继续拆分或补充测试桩。把这张表作为测试计划的起点,后续写测试用例时就不会出现“测了但不知道测的是什么”的情况。