Skip to content

量子计算基础

本教程介绍量子计算的基本构建模块:量子比特(qubit)、量子门(quantum gate)和测量(measurement)。你将学习数学基础以及如何在 pyqpanda3 中应用它们。

前置要求: 入门指南 -- 确保 pyqpanda3 已安装并正常工作。


目录


1. 什么是量子比特?

1.1 经典比特与量子比特

经典比特(classical bit)可以处于两种状态之一:01。量子比特(qubit)也有两个基态(basis state),用狄拉克符号(Dirac notation)表示为 |0|1,但它还可以存在于两者的线性组合中。

属性经典比特量子比特
状态0 或 1|0|1 或任意叠加态
符号二进制数字右矢(ket)向量 |ψ
同时状态每次只能处于一种两种同时(叠加)
测量不改变状态坍缩到基态
表示电压电平希尔伯特空间(Hilbert space)中的向量

1.2 叠加态

处于任意态的量子比特可以描述为:

|ψ=α|0+β|1

其中 αβ 是复数,称为振幅(amplitude),满足归一化条件(normalization condition):

|α|2+|β|2=1

测量量子比特得到状态 |0 的概率为 |α|2,测量得到 |1 的概率为 |β|2

用列向量形式表示,基态为:

|0=(10),|1=(01)

因此一般量子比特态可以写为:

|ψ=(αβ)

关键洞见在于:量子比特在被测量之前同时持有两种可能性。这不等于"处于未知状态"——振幅 αβ 携带了相位信息,使得量子干涉(quantum interference)成为可能。

python
from pyqpanda3 import core

# 分配量子比特时,|0> 状态是默认的
# 让我们通过测量一个全新的量子比特来验证
prog = core.QProg()
prog << core.measure(0, 0)

machine = core.CPUQVM()
machine.run(prog, shots=1000)
counts = machine.result().get_counts()
print(counts)
# 输出: {'0': 1000}  -- 由于没有施加任何门,总是 |0>

1.3 布洛赫球

任何单量子比特纯态(pure state)都可以用布洛赫球(Bloch sphere)上的两个角度 θϕ 参数化:

|ψ=cosθ2|0+eiϕsinθ2|1

其中 0θπ0ϕ<2π。单位球面上的每个点对应一个唯一的量子比特态。

布洛赫球上的关键点:

  • 北极 (θ=0):|0
  • 南极 (θ=π):|1
  • 正 X 轴 (θ=π/2,ϕ=0):|+=12(|0+|1)
  • 负 X 轴 (θ=π/2,ϕ=π):|=12(|0|1)
  • 正 Y 轴 (θ=π/2,ϕ=π/2):|+i=12(|0+i|1)
  • 负 Y 轴 (θ=π/2,ϕ=3π/2):|i=12(|0i|1)

布洛赫向量(Bloch vector) r=(sinθcosϕ,sinθsinϕ,cosθ) 从原点指向球面上的状态。量子门旋转这个向量。

pyqpanda3 通过 visualization 模块提供布洛赫球可视化:

python
from pyqpanda3.visualization import plot_bloch_vector

# 绘制 |+> 态(沿 +X 轴方向)
# 布洛赫向量: [sin(pi/2)*cos(0), sin(pi/2)*sin(0), cos(pi/2)] = [1, 0, 0]
plot_bloch_vector([1, 0, 0], title="|+> state")

2. 量子门

2.1 酉变换

量子门是演化量子比特态的酉变换(unitary transformation)。如果矩阵 U 满足以下条件,则称其为酉矩阵(unitary):

UU=UU=I

其中 UU 的共轭转置(conjugate transpose)。这个条件确保:

  • 总概率守恒(|α|2+|β|2=1
  • 门是可逆的(每个门都有逆)

当门 U 作用于态 |ψ 时,新态为:

|ψ=U|ψ

对于多量子比特系统,作用于特定量子比特的门通过门矩阵与其他量子比特上的恒等矩阵的张量积(tensor product)来表示。

2.2 单量子比特门

pyqpanda3 提供以下无参数的单量子比特门:

泡利 X 门(NOT 门)

X 门翻转计算基态,类似于经典的 NOT 门。

X=(0110)X|0=|1,X|1=|0

在布洛赫球上,X 是绕 X 轴的 π 旋转。

泡利 Y 门

Y=(0ii0)Y|0=i|1,Y|1=i|0

在布洛赫球上,Y 是绕 Y 轴的 π 旋转。

泡利 Z 门

Z=(1001)Z|0=|0,Z|1=|1

Z 门对 |1 施加相位翻转。它是绕 Z 轴的 π 旋转。

Hadamard 门(H)

Hadamard 门创建等概率叠加(equal superposition):

H=12(1111)H|0=12(|0+|1)=|+,H|1=12(|0|1)=|

这是创建叠加态最常用的门。连续施加两次 H 恢复原始状态:HH=I

S 门(相位门)

S=(100i)=Z1/2S|0=|0,S|1=i|1

S 门是 Z 的平方根。它对 |1 施加 90 相位。

T 门(π/8 门)

T=(100eiπ/4)=S1/2=Z1/4T|0=|0,T|1=eiπ/4|1

T 门是 Z 的四次方根。它是非 Clifford 门,对通用量子计算(universal quantum computation)至关重要。

I 门(恒等门)

I=(1001)

恒等门不改变状态。它用于填充线路或作为占位符。

python
from pyqpanda3 import core

# 对量子比特 0 施加单量子比特门
prog = core.QProg()
prog << core.H(0)       # 量子比特 0 上的 Hadamard
prog << core.X(0)       # 量子比特 0 上的泡利-X
prog << core.Y(0)       # 量子比特 0 上的泡利-Y
prog << core.Z(0)       # 量子比特 0 上的泡利-Z
prog << core.S(0)       # 量子比特 0 上的 S 门
prog << core.T(0)       # 量子比特 0 上的 T 门
prog << core.I(0)       # 量子比特 0 上的恒等门

print(prog)

无参数单量子比特门总结

矩阵|0 的效果|1 的效果
X(0110)|1|0
Y(0ii0)i|1i|0
Z(1001)|0|1
H12(1111)|+|
S(100i)|0i|1
T(100eiπ/4)|0eiπ/4|1
I(1001)|0|1

2.3 旋转门

旋转门由角度 θ 参数化,并绕布洛赫球的特定轴旋转状态。

RX 门(绕 X 轴旋转)

RX(θ)=(cosθ2isinθ2isinθ2cosθ2)=eiθX/2

RY 门(绕 Y 轴旋转)

RY(θ)=(cosθ2sinθ2sinθ2cosθ2)=eiθY/2

RZ 门(绕 Z 轴旋转)

RZ(θ)=(eiθ/200eiθ/2)=eiθZ/2

P 门(相位门)

P(θ)=(100eiθ)

注意 P(π/2)=SP(π/4)=T,因此 P 推广了 S 和 T 门。还要注意 P(θ)=RZ(θ) 仅差一个全局相位 eiθ/2

python
import math
from pyqpanda3 import core

# 旋转门接受 (量子比特索引, 弧度角度)
prog = core.QProg()
prog << core.RX(0, math.pi / 4)    # 绕 X 旋转 pi/4
prog << core.RY(1, math.pi / 2)    # 绕 Y 旋转 pi/2
prog << core.RZ(2, math.pi)        # 绕 Z 旋转 pi(等于 Z 门,仅差相位)
prog << core.P(0, math.pi / 4)     # 相位门,角度 pi/4(等于 T 门)

# 验证 RX(pi) 的行为与 X 类似(仅差全局相位)
# RX(pi) = [[0, -i], [-i, 0]] -- 相对于 X 乘以 -i
prog_rx = core.QProg()
prog_rx << core.RX(0, math.pi)
prog_rx << core.measure(0, 0)

machine = core.CPUQVM()
machine.run(prog_rx, shots=1000)
print(machine.result().get_counts())
# 输出: {'1': 1000}  -- 与 X|0> 的测量统计相同

2.4 两量子比特门

两量子比特门作用于一对量子比特,可以创建纠缠(entanglement)——一种独特的量子现象,两个量子比特的状态以经典物理无法描述的方式关联在一起。

CNOT 门(受控非门)

最基本的两量子比特门。当且仅当控制量子比特(control qubit)处于 |1 时,它翻转目标量子比特(target qubit)。

CNOT=(1000010000010010)

基态作用(第一个量子比特是控制,第二个是目标):

|00|00,|01|01,|10|11,|11|10

在 pyqpanda3 中:core.CNOT(控制, 目标)

CZ 门(受控 Z 门)

当控制量子比特处于 |1 时,对目标量子比特施加 Z 门。CZ 门是对称的——两个量子比特扮演相同角色。

CZ=(1000010000100001)|11|11,其余不变

在 pyqpanda3 中:core.CZ(量子比特1, 量子比特2)

SWAP 门

交换两个量子比特的状态。

SWAP=(1000001001000001)|01|10,|10|01,|00|00,|11|11

在 pyqpanda3 中:core.SWAP(量子比特1, 量子比特2)

参数化两量子比特门

pyqpanda3 还提供参数化两量子比特门:

语法描述
CRXcore.CRX(控制, 目标, theta)受控 RX 旋转
CRYcore.CRY(控制, 目标, theta)受控 RY 旋转
CRZcore.CRZ(控制, 目标, theta)受控 RZ 旋转
CPcore.CP(控制, 目标, theta)受控相位
CUcore.CU(控制, 目标, theta, phi, lam, gamma)通用受控酉门
RXXcore.RXX(q1, q2, theta)XX 相互作用
RYYcore.RYY(q1, q2, theta)YY 相互作用
RZZcore.RZZ(q1, q2, theta)ZZ 相互作用
RZXcore.RZX(q1, q2, theta)ZX 相互作用
python
from pyqpanda3 import core

# 两量子比特门示例
prog = core.QProg()
prog << core.CNOT(0, 1)    # CNOT: 控制=0, 目标=1
prog << core.CZ(1, 2)      # 量子比特 1 和 2 之间的 CZ
prog << core.SWAP(0, 1)    # 交换量子比特 0 和 1

# 参数化两量子比特门
import math
prog << core.CRX(0, 1, math.pi / 4)   # 受控 RX,角度 pi/4
prog << core.RZZ(0, 1, math.pi / 2)   # ZZ 旋转,角度 pi/2

print(prog)

2.5 多量子比特门

TOFFOLI 门(CCNOT)

TOFFOLI 门是一个三量子比特门,有两个控制量子比特和一个目标量子比特。当且仅当两个控制量子比特都处于 |1 时,它翻转目标量子比特。

TOFFOLI|a,b,c=|a,b,c(ab)

用矩阵形式(8x8),它除了交换最后两行/列外,其余等同于恒等矩阵:

TOFFOLI=(1000000001000000001000000001000000001000000001000000000100000010)

在 pyqpanda3 中:core.TOFFOLI(控制1, 控制2, 目标)

python
from pyqpanda3 import core

# TOFFOLI: 仅当量子比特 0 和 1 都为 |1> 时翻转量子比特 2
prog = core.QProg()
prog << core.X(0)                  # 将控制量子比特 0 设为 |1>
prog << core.X(1)                  # 将控制量子比特 1 设为 |1>
prog << core.TOFFOLI(0, 1, 2)     # 目标量子比特 2 翻转为 |1>
prog << core.measure([0, 1, 2], [0, 1, 2])

machine = core.CPUQVM()
machine.run(prog, shots=1000)
print(machine.result().get_counts())
# 输出: {'111': 1000}  -- 三个量子比特都是 |1>

量子门分类


3. pyqpanda3 中的门操作

pyqpanda3 的门支持四种强大的操作:伴随、受控、幂运算和矩阵提取。这些操作允许你从简单的构建块构造复杂的线路。

3.1 伴随 (.dagger())

.dagger() 方法返回门的伴随(adjoint)(共轭转置)。对于酉门,伴随就是逆。这在以下场景中很有用:

  • 撤销中间结果(反计算)
  • 实现需要逆向步骤的量子算法
  • 构造反射算符
U=(U)T
python
from pyqpanda3 import core
import math
import numpy as np

# H 的 dagger 是 H 本身(H 是自伴随的)
h_gate = core.H(0)
h_dagger = h_gate.dagger()

# 验证:H.dagger() 矩阵应等于 H 矩阵
h_mat = np.array(h_gate.matrix())
hd_mat = np.array(h_dagger.matrix())
print("H == H.dagger():", np.allclose(h_mat, hd_mat))
# 输出: H == H.dagger(): True

# 验证:H·H = I(连续施加两次 H 恢复原始状态)
h_h = np.array(h_gate.matrix()) @ np.array(h_gate.matrix())
print("H·H == I:", np.allclose(h_h, np.eye(2)))
# 输出: H·H == I: True

# S 的 dagger 是 S^\dagger(即 S^3 或 Z*S)
s_gate = core.S(0)
s_dagger = s_gate.dagger()
s_mat = np.array(s_gate.matrix())
sd_mat = np.array(s_dagger.matrix())
print("S:\n", s_mat)
print("S.dagger():\n", sd_mat)
# S = [[1,0],[0,i]], S.dagger() = [[1,0],[0,-i]]

# 实际应用:施加 S 然后用 S.dagger() 撤销
prog = core.QProg()
prog << core.H(0)           # 创建叠加态 |+>
prog << core.S(0)            # 施加 S 门
prog << core.S(0).dagger()   # 撤销 S 门(回到 |+>)
prog << core.H(0)            # 回到 |0>
prog << core.measure(0, 0)

machine = core.CPUQVM()
machine.run(prog, shots=1000)
print(machine.result().get_counts())
# 输出: {'0': 1000}  -- S 和 S.dagger() 相互抵消

3.2 受控门 (.control())

.control(量子比特) 方法将任何门转换为其受控版本。原始门仅在指定的控制量子比特处于 |1 态时才作用于其目标量子比特。

这非常强大:你可以创建任何门的受控版本,包括已经有控制的门。

python
from pyqpanda3 import core

# 从 X 门创建受控 X(等价于 CNOT)
x_gate = core.X(1)
controlled_x = x_gate.control(0)  # 以量子比特 0 为控制

# 在线路中使用
prog = core.QProg()
prog << core.X(0)              # 将控制设为 |1>
prog << controlled_x           # 量子比特 1 上的 X 被激活
prog << core.measure([0, 1], [0, 1])

machine = core.CPUQVM()
machine.run(prog, shots=1000)
print(machine.result().get_counts())
# 输出: {'11': 1000}

# 创建受控 Hadamard
h_gate = core.H(1)
controlled_h = h_gate.control(0)

# 创建受控 SWAP(Fredkin 门)
swap_gate = core.SWAP(1, 2)
fredkin = swap_gate.control(0)  # 仅当量子比特 0 为 |1> 时交换量子比特 1, 2

# 创建双重受控门(如从 X 构建 TOFFOLI)
x_gate = core.X(2)
toffoli = x_gate.control(0).control(1)  # 量子比特 0 和 1 都为 |1> 时对量子比特 2 施加 X

# 验证双重受控门
prog2 = core.QProg()
prog2 << core.X(0)             # 将第一个控制设为 |1>
prog2 << core.X(1)             # 将第二个控制设为 |1>
prog2 << toffoli                # 量子比特 2 上的 X 被激活
prog2 << core.measure([0, 1, 2], [0, 1, 2])

machine2 = core.CPUQVM()
machine2.run(prog2, shots=1000)
print(machine2.result().get_counts())
# 输出: {'111': 1000}

3.3 幂运算 (.power())

.power(k) 方法将门提升到 k 次幂:Uk=UUUk 次)。对于 k<0,它计算 (U)|k|

这对于门的小数幂特别有用:

python
from pyqpanda3 import core
import math
import numpy as np

# X^2 = I(施加两次 NOT 回到原始状态)
x_gate = core.X(0)
x_squared = x_gate.power(2)

# 验证:X^2 应该等于恒等矩阵 I
identity = np.eye(2, dtype=complex)
print("X^2 == I:", np.allclose(np.array(x_squared.matrix()), identity))
# 输出: X^2 == I: True

# Z^{1/2} = S 门(注意:S 有两个平方根,结果取决于实现选取的分支)
z_gate = core.Z(0)
z_half = z_gate.power(0.5)

# 验证:Z^{1/2} 应该与 S 门矩阵匹配
z_half_mat = np.array(z_half.matrix())
s_mat = np.array(core.S(0).matrix())
print("Z^{1/2} == S:", np.allclose(z_half_mat, s_mat))
# 输出: Z^{1/2} == S: True
# 注意:若输出为 False,说明实现选取了另一个平方根 -S,这也是正确的

# Z^{1/4} = T 门
z_quarter = z_gate.power(0.25)
z_quarter_mat = np.array(z_quarter.matrix())
t_mat = np.array(core.T(0).matrix())
print("Z^{1/4} == T:", np.allclose(z_quarter_mat, t_mat))
# 输出: Z^{1/4} == T: True

# 负幂:U^{-1} = U.dagger()
s_inv = core.S(0).power(-1)
s_dag = core.S(0).dagger()
print("S^{-1} == S.dagger():", np.allclose(
    np.array(s_inv.matrix()),
    np.array(s_dag.matrix())
))
# 输出: S^{-1} == S.dagger(): True

3.4 矩阵表示 (.matrix())

.matrix() 方法返回门的酉矩阵作为二维数组。这对于调试、验证和教学目的很有用。

python
from pyqpanda3 import core
import numpy as np

# 获取任何门的矩阵
h_matrix = core.H(0).matrix()
print("H 矩阵:")
print(np.array(h_matrix))
# [[ 0.707  0.707]
#  [ 0.707 -0.707]]

x_matrix = core.X(0).matrix()
print("\nX 矩阵:")
print(np.array(x_matrix))
# [[0 1]
#  [1 0]]

# 两量子比特门矩阵是 4x4
cnot_matrix = core.CNOT(0, 1).matrix()
print("\nCNOT 矩阵:")
print(np.array(cnot_matrix))
# [[1 0 0 0]
#  [0 1 0 0]
#  [0 0 0 1]
#  [0 0 1 0]]

# 验证酉性:U^\dagger U = I
h_arr = np.array(h_matrix)
should_be_identity = h_arr.conj().T @ h_arr
print("\nH^\dagger H (应为 I):")
print(np.round(should_be_identity, 10))

# 受控门的矩阵
controlled_h = core.H(0).control(2)
ch_matrix = np.array(controlled_h.matrix())
print("\n受控 H 矩阵 (4x4):")
print(np.round(ch_matrix, 3))
# [[ 0.707  0.     0.707  0.   ]
#  [ 0.     0.707  0.     0.707]
#  [ 0.707  0.    -0.707  0.   ]
#  [ 0.     0.707  0.    -0.707]]

4. 测量

4.1 投影测量

测量(measurement)是观测量子态的过程,它将量子态从叠加态坍缩为确定的经典结果。在计算基(computational basis)中,测量处于态 |ψ=α|0+β|1 的量子比特产生:

  • 结果 0,概率为 |α|2
  • 结果 1,概率为 |β|2

测量后,量子比特处于被测量的基态。这种坍缩是不可逆的——叠加信息已经丢失。

对于处于以下态的 n 量子比特系统:

|ψ=i=02n1ci|i

测量所有量子比特得到比特串(bitstring) |i 的概率为 |ci|2

4.2 在 pyqpanda3 中测量

pyqpanda3 提供两种形式的测量:

单量子比特测量:

python
core.measure(量子比特索引, 经典比特索引)

多量子比特测量:

python
core.measure([量子比特_0, 量子比特_1, ...], [经典比特_0, 经典比特_1, ...])

每个量子比特的测量结果存储在对应的经典比特(cbit)中。

python
from pyqpanda3 import core

# 单量子比特测量
prog1 = core.QProg()
prog1 << core.H(0)                 # 创建叠加态
prog1 << core.measure(0, 0)        # 测量量子比特 0 存入经典比特 0

machine = core.CPUQVM()
machine.run(prog1, shots=1000)
print("单量子比特:", machine.result().get_counts())
# 输出: {'0': 498, '1': 502}

# 多量子比特测量
prog2 = core.QProg()
prog2 << core.H(0)                 # 量子比特 0 叠加
prog2 << core.X(1)                 # 量子比特 1 处于 |1>
prog2 << core.measure([0, 1], [0, 1])  # 测量两者

machine.run(prog2, shots=1000)
print("两量子比特:", machine.result().get_counts())
# 输出: {'01': 502, '11': 498}
# 量子比特 0 是随机的,量子比特 1 始终为 1

4.3 基于采样的测量

量子测量本质上是概率性的。为了积累统计信息,我们多次运行同一线路(称为"采样(shots)")。大数定律保证随着采样次数增加,观测频率收敛到真实概率。

python
from pyqpanda3 import core
import math

# 演示基于采样的测量收敛
prog = core.QProg()
prog << core.H(0)       # 创建 |+> = (|0> + |1>)/sqrt(2)
prog << core.measure(0, 0)

machine = core.CPUQVM()

# 少量采样:高方差
machine.run(prog, shots=10)
counts_10 = machine.result().get_counts()
print(f"10 次采样:   {counts_10}")

# 中等采样
machine.run(prog, shots=100)
counts_100 = machine.result().get_counts()
print(f"100 次采样:  {counts_100}")

# 大量采样:更接近 50/50
machine.run(prog, shots=10000)
counts_10000 = machine.result().get_counts()
print(f"10000 次采样: {counts_10000}")

# 概率趋近于每个结果 0.5
total = sum(counts_10000.values())
for key, val in sorted(counts_10000.items()):
    print(f"  P({key}) = {val/total:.4f}")

下图说明了测量过程:

4.4 完整示例:贝尔态

让我们将所有内容组合起来创建贝尔态(Bell State)——最简单的纠缠态之一:

|Φ+=12(|00+|11)

线路为:量子比特 0 上的 H,然后是以 0 为控制、1 为目标的 CNOT。

python
from pyqpanda3 import core

# 第 1 步:构建贝尔态线路
prog = core.QProg()
prog << core.H(0)                    # Hadamard 在量子比特 0 上创建叠加
prog << core.CNOT(0, 1)              # 纠缠量子比特 0 和 1
prog << core.measure([0, 1], [0, 1]) # 测量两个量子比特

# 第 2 步:在 CPU 模拟器上运行
machine = core.CPUQVM()
machine.run(prog, shots=10000)

# 第 3 步:获取测量结果
counts = machine.result().get_counts()
print("贝尔态结果:")
print(counts)
# 预期输出: {'00': ~5000, '11': ~5000}
# 注意:'01' 和 '10' 不应出现(或由于数值精度极少出现)

# 第 4 步:分析结果
total = sum(counts.values())
for bitstring in ['00', '01', '10', '11']:
    count = counts.get(bitstring, 0)
    probability = count / total
    print(f"  |{bitstring}>: {count} 次计数 ({probability:.4f})")

为什么只有 0011 H 门将量子比特 0 置于 |+=12(|0+|1) 态。CNOT 将量子比特 0 的状态复制到量子比特 1:

CNOT(H|0|0)=12(|00+|11)

两个量子比特现在纠缠了:测量一个立即确定另一个,无论它们之间的物理距离多远。这是量子隐形传态(quantum teleportation)、超密编码(superdense coding)和量子纠错(quantum error correction)的资源。


5. 总结

本教程涵盖了量子计算的三个基础概念:

概念核心思想pyqpanda3 API
量子比特|0|1 的叠加分配时的默认状态
量子门量子比特态的酉变换core.H(0)core.X(0)core.CNOT(0,1)
测量将叠加态坍缩为经典比特core.measure(量子比特, 经典比特)

门操作扩展了门库:

操作方法描述
伴随.dagger()返回逆门 U
受控.control(量子比特)添加控制量子比特
幂运算.power(k)计算 Uk(支持小数 k)
矩阵.matrix()返回酉矩阵

下一步:

  • 线路构建 -- 学习如何使用 QProgQCircuit<< 运算符将门组合成复杂线路
  • 模拟 -- 探索不同的模拟器(CPUQVM、DensityMatrixSimulator、Stabilizer)
  • 可视化 -- 学习绘制线路和在布洛赫球上绘制量子态

快速参考

python
from pyqpanda3 import core
import math

# ===================
# 单量子比特门
# ===================
core.H(0)           # Hadamard
core.X(0)           # 泡利-X (NOT)
core.Y(0)           # 泡利-Y
core.Z(0)           # 泡利-Z
core.S(0)           # S 门(Z 的平方根)
core.T(0)           # T 门(Z 的四次方根)
core.I(0)           # 恒等门

# ===================
# 旋转门
# ===================
core.RX(0, math.pi / 4)   # 绕 X 旋转
core.RY(0, math.pi / 2)   # 绕 Y 旋转
core.RZ(0, math.pi)       # 绕 Z 旋转
core.P(0, math.pi / 4)    # 相位门

# ===================
# 两量子比特门
# ===================
core.CNOT(0, 1)            # 受控非门
core.CZ(0, 1)              # 受控 Z 门
core.SWAP(0, 1)            # 交换门

# ===================
# 多量子比特门
# ===================
core.TOFFOLI(0, 1, 2)     # 双重受控非门

# ===================
# 门操作
# ===================
gate = core.H(0)
gate.dagger()               # 伴随(逆)
gate.control(2)             # 受控版本(以量子比特 2 为控制)
gate.power(0.5)             # 小数幂
gate.matrix()               # 酉矩阵

# ===================
# 测量
# ===================
core.measure(0, 0)                       # 单量子比特
core.measure([0, 1], [0, 1])             # 多量子比特

# ===================
# 运行线路
# ===================
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1)
prog << core.measure([0, 1], [0, 1])

machine = core.CPUQVM()
machine.run(prog, shots=1000)
counts = machine.result().get_counts()
print(counts)

知识检查

测试你对使用 pyqpanda3 的量子计算基础的理解。

Q1: 量子比特态 |ψ=α|0+β|1 的归一化约束是什么?

A1: 振幅必须满足 |α|2+|β|2=1。这确保所有测量结果的总概率等于 1,这是量子力学的基本要求。

Q2: Hadamard 门对基态 |0|1 的作用是什么?

A2: H|0=12(|0+|1)=|+H|1=12(|0|1)=|。它从计算基态创建等概率叠加,在 Z 基和 X 基之间映射。

Q3: 阐述玻恩法则(Born rule)。如果量子比特处于态 |ψ=12|0+32|1,测量概率是多少?

A3: 玻恩法则指出 P(x)=|αx|2。这里,P(0)=|1/2|2=1/4P(1)=|3/2|2=3/4

Q4: 可分态(product state)与纠缠态(entangled state)有什么区别?

A4: 可分态可以分解为 |ψ=|ϕ1|ϕ2,意味着每个量子比特有独立的状态。纠缠态无法分解——量子比特展现出无法用独立状态描述的关联。贝尔态 |Φ+=12(|00+|11) 是纠缠态。

Q5: S 门、T 门和 Z 门之间有什么关系?

A5: S2=ZT2=S,因此 T4=S2=ZT8=I。S 门是 Z 的平方根,T 门是 Z 的四次方根。

Q6: 写出 RX(π/2) 的矩阵并解释它对 |0 的作用。

A6: RX(θ)=(cos(θ/2)isin(θ/2)isin(θ/2)cos(θ/2))。对于 θ=π/2RX(π/2)=12(1ii1)。作用于 |0 时,产生 12(|0i|1),即布洛赫球上的 |i 本征态。

Q7: 结合连续施加两个 Hadamard 门的场景,解释量子干涉(quantum interference)。

A7: HH|0=|0HH|1=|1。第一个 H 创建 12(|0+|1),然后第二个 H 产生 12(|0+|1+|0|1)=|0|1 的振幅相消(相消干涉(destructive interference)),而 |0 的振幅相加(相长干涉(constructive interference))。


练习 1:态制备

编写一个 pyqpanda3 程序,制备态 |ψ=cos(π/6)|0+sin(π/6)|1。验证测量概率符合玻恩法则预测:P(0)=cos2(π/6)=3/4P(1)=sin2(π/6)=1/4

解答:

python
import numpy as np
from pyqpanda3.core import CPUQVM, QProg, RY, measure

qvm = CPUQVM()

# 态 cos(θ/2)|0⟩ + sin(θ/2)|1⟩ 由 RY(θ) 制备
# 我们想要 cos(π/6)|0⟩ + sin(π/6)|1⟩
# 所以 θ/2 = π/6 → θ = π/3
theta = np.pi / 3

prog = QProg()
prog << RY(0, theta)
prog << measure([0], [0])

qvm.run(prog, shots=10000)
result = qvm.result()
counts = result.get_counts()

p0_measured = counts.get("0", 0) / 10000
p1_measured = counts.get("1", 0) / 10000
p0_expected = np.cos(np.pi/6)**2  # 0.75
p1_expected = np.sin(np.pi/6)**2  # 0.25

print(f"P(|0⟩) 测量值: {p0_measured:.4f}, 期望值: {p0_expected:.4f}")
print(f"P(|1⟩) 测量值: {p1_measured:.4f}, 期望值: {p1_expected:.4f}")
assert abs(p0_measured - p0_expected) < 0.03
assert abs(p1_measured - p1_expected) < 0.03
print("验证通过!")

练习 2:纠缠验证

制备所有四个贝尔态并验证其测量统计。四个贝尔态为:

|Φ+=12(|00+|11),|Φ=12(|00|11)|Ψ+=12(|01+|10),|Ψ=12(|01|10)

解答:

python
from pyqpanda3.core import CPUQVM, QProg, H, X, Z, CNOT, measure

qvm = CPUQVM()
shots = 5000

def run_and_print(name, prog):
    prog << measure([0, 1], [0, 1])
    qvm.run(prog, shots=shots)
    counts = qvm.result().get_counts()
    print(f"{name}: {counts}")
    return counts

# |Φ+⟩ = (|00⟩ + |11⟩) / √2
prog_pp = QProg()
prog_pp << H(0) << CNOT(0, 1)
c1 = run_and_print("|Φ+⟩", prog_pp)
assert c1.get("01", 0) < 100 and c1.get("10", 0) < 100

# |Φ-⟩ = (|00⟩ - |11⟩) / √2
prog_pm = QProg()
prog_pm << H(0) << Z(0) << CNOT(0, 1)
c2 = run_and_print("|Φ-⟩", prog_pm)
assert c2.get("01", 0) < 100 and c2.get("10", 0) < 100

# |Ψ+⟩ = (|01⟩ + |10⟩) / √2
prog_mp = QProg()
prog_mp << H(0) << X(1) << CNOT(0, 1)
c3 = run_and_print("|Ψ+⟩", prog_mp)
assert c3.get("00", 0) < 100 and c3.get("11", 0) < 100

# |Ψ-⟩ = (|01⟩ - |10⟩) / √2
prog_mm = QProg()
prog_mm << X(0) << H(0) << X(1) << CNOT(0, 1)
c4 = run_and_print("|Ψ-⟩", prog_mm)
assert c4.get("00", 0) < 100 and c4.get("11", 0) < 100

print("\n所有四个贝尔态验证完成!")

练习 3:自定义门矩阵验证

2×2 矩阵创建自定义酉门,并验证其对基态的作用是否符合预期的矩阵乘法。

解答:

python
import numpy as np
from pyqpanda3.core import CPUQVM, QProg, Oracle, measure

# 定义自定义酉门:RY(π/4) 矩阵
theta = np.pi / 4
matrix = np.array([
    [np.cos(theta/2), -np.sin(theta/2)],
    [np.sin(theta/2),  np.cos(theta/2)]
], dtype=complex)

# 从矩阵创建预言机(Oracle)并验证
qvm = CPUQVM()

# 作用于 |0⟩:期望 cos(π/8)|0⟩ + sin(π/8)|1⟩
prog = QProg()
oracle = Oracle([0], matrix)
prog << oracle << measure([0], [0])
qvm.run(prog, shots=10000)
counts = qvm.result().get_counts()
p0 = counts.get("0", 0) / 10000
expected_p0 = np.cos(np.pi/8)**2
print(f"P(|0⟩) 测量值: {p0:.4f}, 期望值: {expected_p0:.4f}")
assert abs(p0 - expected_p0) < 0.03
print("自定义门验证通过!")

Released under the MIT License.