量子计算入门:用Qiskit实现第一个可验证的量子算法

说实话,第一次接触量子计算时,我也被那些复杂的数学符号和物理概念劝退过。但后来发现,其实借助IBM的Qiskit框架,我们完全可以在模拟器上跑通一个真正的量子算法——哪怕你只是个刚入门的Python开发者。今天我就带大家实现一个经典且可验证的量子算法:Deutsch-Jozsa算法。它能判断一个未知函数是“常数函数”(输出固定)还是“平衡函数”(一半输入输出0,一半输出1),而且只需要一次量子查询,经典计算则需要多次。
我的环境是Python 3.10 + Qiskit 1.0,如果你还没安装,先跑下面这行命令:
pip install qiskit qiskit-aer
注意:Qiskit 1.0之后,模拟器需要单独安装 qiskit-aer,别漏了。
第一步:理解量子比特与量子门的基础
在看代码之前,先花30秒理解核心概念。经典比特只有0或1,但量子比特(qubit)可以处于0和1的叠加态。我们常用的量子门有:
- Hadamard门(H门):把确定的|0⟩或|1⟩变成叠加态。
- X门:类似经典的非门,翻转比特。
- CNOT门:受控非门,控制比特为1时翻转目标比特。
Deutsch-Jozsa算法的核心就是利用H门制造叠加态,一次查询就能提取函数的全局性质。
第二步:定义我们要验证的“黑箱函数”
假设我们有一个黑箱函数f(x),输入x是0或1,输出也是0或1。我们需要判断它是常数函数(f(0)=f(1))还是平衡函数(f(0)≠f(1))。在量子电路里,我们用一个“Oracle”(预言机)来实现这个函数。这里我构造一个平衡函数:f(0)=0,f(1)=1。
在Qiskit中,Oracle其实就是一个自定义的量子门。对于平衡函数,我们可以用CNOT门实现:控制比特是输入x,目标比特是输出y,当x=1时翻转y。这样如果初始y=0,最终y就等于x的值,恰好是平衡函数。
from qiskit import QuantumCircuit
def balanced_oracle():
"""实现一个平衡函数的Oracle: f(0)=0, f(1)=1"""
oracle = QuantumCircuit(2) # 两个量子比特:输入x和输出y
# 平衡函数:当x=1时翻转y,即CNOT门
oracle.cx(0, 1) # 控制比特是0号,目标比特是1号
return oracle
这里有个坑:很多人会忘记量子比特的编号是从0开始的,而且Oracle电路必须和主电路的大小一致,否则后面组合时会报错。
第三步:构建完整的Deutsch-Jozsa算法电路
算法步骤很清晰:
- 初始化两个量子比特:第一个是输入|x⟩,第二个是输出|y⟩。把y置为|1⟩(因为算法需要利用相位反冲)。
- 对两个量子比特都应用H门。
- 应用Oracle。
- 对第一个量子比特再应用H门。
- 测量第一个量子比特。如果结果为0,则是常数函数;如果为1,则是平衡函数。
下面是完整代码:
from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator
def deutsch_jozsa_circuit(oracle):
"""构建Deutsch-Jozsa算法电路"""
circuit = QuantumCircuit(2, 1) # 2个量子比特,1个经典比特用于测量
# 步骤1:初始化输出比特为|1⟩
circuit.x(1) # 把第二个量子比特从|0⟩翻转为|1⟩
# 步骤2:应用H门到所有量子比特
circuit.h(0)
circuit.h(1)
# 步骤3:应用Oracle
circuit.compose(oracle, inplace=True)
# 步骤4:对第一个量子比特再应用H门
circuit.h(0)
# 步骤5:测量第一个量子比特
circuit.measure(0, 0)
return circuit
# 使用我们定义的平衡Oracle
oracle = balanced_oracle()
circuit = deutsch_jozsa_circuit(oracle)
# 在模拟器上运行
simulator = AerSimulator()
compiled_circuit = transpile(circuit, simulator)
result = simulator.run(compiled_circuit, shots=1024).result()
counts = result.get_counts()
print("测量结果:", counts)
如果你运行这段代码,会看到类似输出:
测量结果: {'1': 1024}
结果全部是’1’,说明这是平衡函数。如果你把Oracle换成常数函数(比如什么都不做,或者加两个X门让输出恒为0),结果就会变成全部’0’。
第四步:验证算法的正确性——对比经典方法
为了确保不是玄学,我特意用经典方法验证一下。对于这个两输入的函数,经典计算需要查询f(0)和f(1)两次才能判断。而量子算法只运行了一次电路(虽然内部有多次操作,但Oracle只被调用一次)。
我们可以写个简单的测试来确认:
def classical_check(f):
"""经典方法:调用两次函数判断类型"""
return f(0) == f(1) # True表示常数,False表示平衡
def f_balanced(x):
return x # 平衡函数:f(0)=0, f(1)=1
print("经典判断结果:", "常数" if classical_check(f_balanced) else "平衡")
输出:
经典判断结果: 平衡
完全一致。但经典方法调用了两次函数,量子方法只调用一次Oracle——这就是量子优越性的雏形,虽然在这个简单例子里优势不明显,但扩展到多比特时,量子算法的查询次数始终为1,而经典算法需要2^(n-1)+1次。
踩坑记录与实用提示
我在写这个教程时遇到了几个问题,分享给你:
- 模拟器版本兼容性:Qiskit 0.x时代的
Aer.get_backend('qasm_simulator')在1.0之后已经废弃,必须用AerSimulator并显式安装qiskit-aer。 - Oracle的qubit映射:如果你的Oracle内部用了多个量子比特,一定要确保它的量子比特数与主电路匹配。我在一开始把Oracle写成2比特电路,但主电路是3比特,结果compose时报错。
- 测量结果的解读:由于模拟器有随机性,shots次数太少时可能偶尔出现错误结果。建议至少用1024次,确保统计稳定性。
扩展思考:下一步可以做什么?
Deutsch-Jozsa算法虽然简单,但它展示了量子计算的核心思想:利用叠加和干涉来提取全局信息。你可以尝试:
- 把输入从1比特扩展到3比特,实现真正的多量子比特版本(Oracle会复杂一些,但原理一样)。
- 用真实量子硬件运行(需要IBM Quantum账号,但模拟器已经足够验证)。
- 尝试其他算法,比如Grover搜索算法或Shor算法的简化版。
最后,记住量子编程和经典编程最大的不同:你不仅要考虑逻辑正确性,还要理解量子态的演化。但别怕,多写几个电路,你就能找到感觉了。下次我会带来更复杂的量子相位估计,敬请期待。


qiskit-aer这个坑真有人会漏装,我之前就卡这一步
compose报错那段太真实了,量子比特数对不上真的烦