2. 量子比特与量子门基础

在 Cirq 中,量子程序的最小组成单位不是“线路”,而是量子比特对象与量子门操作。理解这两类对象如何被创建、如何被组合,是后续构建量子线路、模拟与运行实验的前提。本节围绕 Cirq 中最常用的量子比特类型(Qubit、LineQubit、GridQubit)以及基本门(X、Y、Z、H、CNOT)展开,重点说明它们的创建方式、矩阵表示与在电路中的实际用法。

一、量子比特:从抽象 Qubit 到带拓扑的 LineQubit 与 GridQubit

Cirq 中的量子比特是“带标签的对象”,标签本身不携带物理状态,只用于在电路中唯一标识一个比特。最基础的类是 cirq.Qubit,它接受一个可哈希的标签,例如字符串或整数:

import cirq

q0 = cirq.Qubit("q0")
q1 = cirq.Qubit("q1")
print(q0, q1)   # q0 q1

这种写法灵活,但缺少“位置”信息。当我们需要在二维网格或一维链上安排比特时,Cirq 提供了两个更具体的子类:

  • LineQubit:用整数索引表示一维链上的位置,适合线性排列的量子寄存器。例如 cirq.LineQubit(0)、cirq.LineQubit(1)。
  • GridQubit:用 (row, col) 表示二维网格坐标,适合超导量子芯片常见的方格拓扑。例如 cirq.GridQubit(0, 0)、cirq.GridQubit(0, 1)。

三者的关系可以这样理解:Qubit 是通用基类,LineQubit 与 GridQubit 是带拓扑语义的特化版本。它们都继承自 cirq.Qid,因此可以混用在同一电路中,但实际硬件通常要求使用与芯片拓扑一致的比特类型。下面这张图展示了三种比特的创建方式与拓扑关系:

cirq.Qubit 任意可哈希标签 "q0" / 0 / "ancilla" cirq.LineQubit 一维整数索引 LineQubit(0), (1), (2) cirq.GridQubit 二维 (row, col) 坐标 GridQubit(0,0), (0,1) 继承 继承 LineQubit 一维链 0 1 2 GridQubit 二维网格 0,0 0,1 0,2 1,0 1,1 1,2

选择哪种比特类型,取决于目标后端。若只是本地模拟,LineQubit 最简洁;若要对齐 Google 超导芯片的方格拓扑,则应使用 GridQubit,因为两比特门通常只允许作用在相邻的网格比特上。

二、基本门:X、Y、Z、H 与 CNOT 的矩阵表示

Cirq 中的门是“可作用于一个或多个 Qid 的酉操作”。单比特门作用于一个比特,两比特门作用于两个比特。下面给出五个最基础门的矩阵形式(按计算基 |0⟩、|1⟩ 排列):

门 Cirq 写法 矩阵 作用
X cirq.X [[0,1],[1,0]] 比特翻转,|0⟩↔|1⟩
Y cirq.Y [[0,-i],[i,0]] 比特翻转并带相位
Z cirq.Z [[1,0],[0,-1]] 相位翻转,|1⟩→−|1⟩
H cirq.H 1/√2·[[1,1],[1,-1]] 生成叠加态
CNOT cirq.CNOT 4×4 受控 X 矩阵 控制比特为 1 时翻转目标比特

在 Cirq 中,门本身是“无比特”的对象,必须通过 on() 或直接调用绑定到具体比特上,才成为可放入电路的操作(Operation)。例如:

q0, q1 = cirq.LineQubit.range(2)

op_x  = cirq.X(q0)          # X 门作用在 q0
op_h  = cirq.H(q1)          # H 门作用在 q1
op_cx = cirq.CNOT(q0, q1)   # CNOT,q0 控制,q1 目标

print(cirq.unitary(cirq.X))   # 查看 X 的酉矩阵
print(cirq.unitary(cirq.CNOT))

这里有一个容易混淆的点:cirq.X 是门,cirq.X(q0) 是操作。门可以复用,操作则绑定到具体比特。矩阵表示可以通过 cirq.unitary() 直接获取,用于验证门是否符合预期,也便于与教科书中的矩阵对照。

三、把门放进电路:从操作到 Moment 与 Circuit

Cirq 的电路由 Moment 组成,每个 Moment 是一组“可以并行执行、互不冲突”的操作。把操作追加到电路中时,Cirq 会自动安排 Moment:如果两个操作作用于不同比特,它们可以放进同一个 Moment;如果作用于同一比特,则必须分到不同 Moment。

circuit = cirq.Circuit()
circuit.append([cirq.H(q0), cirq.H(q1)])   # 同一 Moment
circuit.append([cirq.CNOT(q0, q1)])        # 下一 Moment
circuit.append([cirq.measure(q0, q1, key='m')])

print(circuit)

运行后会看到类似下面的结构:

0: ───H───@───M('m')───
          │   │
1: ───H───X───M────────

其中 @ 表示控制比特,X 表示目标比特,M 表示测量。这个文本图是 Cirq 电路最直观的表示方式,也是调试时最常用的观察手段。若想验证电路是否等价于某个目标酉矩阵,可以用 cirq.unitary(circuit) 获取整体矩阵,再与手算结果比较。

实用提示:当电路包含测量时,cirq.unitary() 会报错,因为测量不是酉操作。此时应先用 cirq.Circuit(circuit.all_operations()) 去掉测量,或只对酉部分求矩阵。

四、一个可运行的小例子:制备 Bell 态并测量

下面用 H + CNOT 制备 Bell 态 (|00⟩+|11⟩)/√2,并统计测量结果。示例参数为 1000 次采样,属于教学演示,实际运行结果会因随机性略有波动。

import cirq

q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit([
    cirq.H(q0),
    cirq.CNOT(q0, q1),
    cirq.measure(q0, q1, key='result')
])

simulator = cirq.Simulator()
result = simulator.run(circuit, repetitions=1000)
print(result.histogram(key='result'))

预期输出中,0(即 |00⟩)与 3(即 |11⟩)应各占约一半,而 1(|01⟩)与 2(|10⟩)几乎不出现。若出现明显偏离,通常说明 CNOT 的控制/目标顺序写反,或 H 门没有正确作用在控制比特上。这个例子把“比特创建—门作用—电路组装—测量统计”串成了一条完整链路,也是后续更复杂实验的基础模板。

注意:CNOT 的第一个参数是控制比特,第二个是目标比特。写成 cirq.CNOT(q1, q0) 会得到不同的纠缠方向,虽然 Bell 态本身对称,但在更复杂的电路中会导致逻辑错误。

掌握以上内容后,你已经可以用 Cirq 表达任意由 X、Y、Z、H、CNOT 组成的量子线路,并通过矩阵与测量统计验证其行为。下一阶段将在此基础上引入旋转门、参数化电路与更复杂的多比特门。