3. 量子线路参数化与参数绑定实践

参数化线路的构建与批量绑定

参数化线路的核心是把“门的角度”从固定数值变成可替换的符号变量。Qiskit 用 Parameter 表示这种符号,用 QuantumCircuit.assign_parameters 或 bind_parameters 把具体数值代入,得到可执行的线路。这样一条线路模板就能在不同参数下反复执行,而不必每次重建门序列。

下面构建一个两量子比特的可复用模板:第一个量子比特先绕 X 轴旋转 θ,再绕 Y 轴旋转 φ;随后用 CNOT 把信息耦合到第二个量子比特。θ 与 φ 都是 Parameter,线路结构在绑定前后保持不变。

from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
from qiskit.quantum_info import Statevector
import numpy as np

theta = Parameter("θ")
phi = Parameter("φ")

template = QuantumCircuit(2)
template.rx(theta, 0)
template.ry(phi, 0)
template.cx(0, 1)

print("参数列表:", template.parameters)
print("门数量:", len(template.data))

模板本身不能直接交给模拟器执行,因为 θ、φ 尚未赋值。绑定方式有两种:assign_parameters 接受字典或列表,返回新线路;bind_parameters 是它的旧别名,行为一致。推荐用字典按参数对象绑定,避免顺序错位。

param_sets = [
    {theta: 0.0,        phi: 0.0},
    {theta: np.pi,      phi: 0.0},
    {theta: np.pi / 2,  phi: np.pi / 2},
]

bound_circuits = [template.assign_parameters(p) for p in param_sets]

for i, qc in enumerate(bound_circuits):
    sv = Statevector(qc)
    print(f"组{i}: 门数量={len(qc.data)}, 参数剩余={len(qc.parameters)}")
    print("  概率:", np.round(sv.probabilities(), 4))

三组参数对应的预期行为如下:第一组 θ=0、φ=0 时两个旋转门都退化为单位操作,线路等效于恒等,测量结果集中在 |00⟩;第二组 θ=π 使第一个量子比特翻转到 |1⟩,CNOT 后得到 |11⟩;第三组 θ=φ=π/2 产生叠加与耦合,概率分布在 |00⟩、|01⟩、|10⟩、|11⟩ 之间展开。这些是可由给定输入直接推出的结果,用于检验绑定是否真正生效。

参数化模板 → 绑定 → 结构一致性检查 模板 template(含符号参数) q0 q1 RX(θ) RY(φ) 门数 = 3,参数 = {θ, φ} assign_parameters 绑定后线路(结构不变,数值替换) 组0: θ=0, φ=0 RX(0) RY(0) → |00⟩ 组1: θ=π, φ=0 RX(π) RY(0) → |11⟩ 组2: θ=π/2, φ=π/2 RX(π/2) RY(π/2) → 叠加分布 结构一致性检查(绑定前后对比) 检查项 模板 组0 组1 组2 门数量 3 3 3 3 剩余参数 {θ, φ} 0 0 0 门序列 RX·RY·CX RX·RY·CX RX·RY·CX RX·RY·CX

绑定后结构一致性的验证方法

“结构一致”指绑定只替换参数数值,不改变门的种类、顺序和量子比特连接关系。可用三个可观察量交叉确认:len(qc.data) 门数量、qc.parameters 剩余参数集合、以及门序列的指令名列表。绑定后剩余参数应为空集,门数量与指令名序列应与模板完全一致。

def structure_signature(qc):
    return (
        len(qc.data),
        [inst.operation.name for inst in qc.data],
        [tuple(qc.find_bit(q).index for q in inst.qubits) for inst in qc.data],
    )

base_sig = structure_signature(template)
for i, qc in enumerate(bound_circuits):
    sig = structure_signature(qc)
    assert sig == base_sig, f"组{i} 结构发生变化"
    assert len(qc.parameters) == 0, f"组{i} 仍有未绑定参数"
print("三组绑定线路结构一致,参数已全部绑定")

若绑定后门数量变化,通常是因为把参数绑定到了条件门或自定义指令内部,或误用了 assign_parameters 的 inplace=True 覆盖了模板。若剩余参数不为空,说明参数字典缺少某个 Parameter 对象,或键用了字符串名而线路中参数对象不同名。用 template.parameters 打印实际参数对象,再据此构造字典即可定位。

批量执行时,把 bound_circuits 直接传给 transpile 或模拟器的 run 列表接口,可一次提交多组参数。若参数组合很多,可考虑 ParameterVector 配合 assign_parameter_values 做向量化绑定,但结构一致性检查逻辑不变。
不要对同一个模板反复调用 assign_parameters(..., inplace=True),否则模板会被就地改写,后续绑定将基于已替换的线路,导致批量结果互相污染。需要保留模板时始终使用默认的非就地绑定。