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

2026.5.19 杂七杂八 914
33BLOG智能摘要
你打开量子计算的文档,满屏的狄拉克符号和矩阵方程瞬间劝退——但真相是,你只需要会Python,就能用IBM的Qiskit在半小时内跑通第一个可验证的量子算法。这篇文章带你实现Deutsch-Jozsa算法:用一个Oracle(预言机)电路,一次量子查询就能判断一个未知函数是“常数”还是“平衡”,而经典计算至少需要两次。关键是,代码里藏着一个几乎所有人都踩过的坑——Qiskit 1.
— 此摘要由33BLOG基于AI分析文章内容生成,仅供参考。

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

量子计算入门:用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算法电路

算法步骤很清晰:

  1. 初始化两个量子比特:第一个是输入|x⟩,第二个是输出|y⟩。把y置为|1⟩(因为算法需要利用相位反冲)。
  2. 对两个量子比特都应用H门。
  3. 应用Oracle。
  4. 对第一个量子比特再应用H门。
  5. 测量第一个量子比特。如果结果为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报错那段太真实了,量子比特数对不上真的烦