Skip to content
首页/博客/量子退火详解:用 D-Wave Ocean SDK 求解 Max-Cut
AlgorithmsOptimizationHardware

量子退火详解:用 D-Wave Ocean SDK 求解 Max-Cut

把一个 Max-Cut 问题表述为 QUBO,用 D-Wave 免费的模拟退火采样器求解,并理解量子退火与门模型量子计算相比能做什么、不能做什么。

FreeQuantumComputing
·· 9 min read

量子退火是与本站其他内容完全不同的一种量子计算模型。这里没有电路,没有量子门,硬件上也不会运行 Grover 算法Shor 算法。退火机只解决一类问题——优化问题,它把问题直接编码进硬件的物理机制,让系统自行弛豫到一个低能量的答案上。

本指南把我们的 QAOA 教程中同样的 Max-Cut 问题表述为一个退火问题,用 D-Wave 的 Ocean SDK 免费求解,并讲解几乎所有人从玩具示例迁移到真实硬件时都会踩的那个坑。

物理原理

一个优化问题被映射到一个量子比特系统上,使得系统能量最低的构型——即基态——对应最优解。量子比特从一个容易制备的状态出发,缓慢演化到问题的能量曲面上。绝热定理正是让这一切成立的原因:只要演化速度相对于系统的能隙足够缓慢,一个从基态出发的量子系统就会在整个演化过程中一直停留在基态。最后读出量子比特,得到的就是一个低能量、有望是最优的解。

这与门模型计算有着根本性的不同。门模型 QPU 执行你指定的任意操作序列。退火机执行的是单一固定过程——朝着最小值物理弛豫——你唯一能影响的是问题如何被编码进这个能量曲面。

把 Max-Cut 表述为 QUBO

退火机求解的是以 QUBO(二次无约束二元优化)形式表达的问题:最小化一个只含线性项和成对二次项、不含更高阶交互项的二元变量 x_i ∈ {0, 1} 表达式。

对于 Max-Cut,每条边 (i, j) 对目标函数的贡献是 2·x_i·x_j − x_i − x_j。逐一分析四种情况:当 x_ix_j 相同(在同一侧)时,这一项为 0;当两者不同(该边被切割)时,这一项为 −1。因此最小化所有边上的总和,就等价于最大化被切割的边数,这正是 Max-Cut 目标,只是被改写成了最小化形式。

使用与 QAOA 指南相同的四节点环形图:

import dimod
from neal import SimulatedAnnealingSampler

edges = [(0, 1), (1, 2), (2, 3), (3, 0)]

Q = {}
for i, j in edges:
    Q[(i, i)] = Q.get((i, i), 0) - 1
    Q[(j, j)] = Q.get((j, j), 0) - 1
    Q[(i, j)] = Q.get((i, j), 0) + 2

bqm = dimod.BinaryQuadraticModel.from_qubo(Q)

这个图中的每条边都能同时被切割——该图是二分图:{0, 2}{1, 3}——因此基态能量恰好为 −4,每条边贡献 −1。这个数字直接来自 QUBO 的构造过程,并非来自任何已经运行过的计算,而这正是下面的采样器要努力达到的目标。

用模拟退火免费求解

D-Wave 的 Ocean SDK 内置了 neal,一个完全在你自己机器上运行的经典模拟退火采样器,不需要 QPU 账户,没有排队,也没有费用。这也是开发退火问题时的标准第一步,在真正接触实体硬件之前先用它调试,扮演的角色和本站其他地方 AerSimulator 对门模型电路的作用一样。

sampler = SimulatedAnnealingSampler()
sampleset = sampler.sample(bqm, num_reads=1000)

best = sampleset.first
print(best.sample, best.energy)

num_reads=1000 会独立运行退火过程 1000 次,并保留每一次的结果,因为无论是模拟退火还是量子退火本质上都是启发式的:没有任何一次运行能保证落在基态上,因此标准做法是运行一批读数,取其中能量最低的结果。对于这个图,可以预期 best.energy 会落在 −4,而 best.sample 会读出两种等价二分方案之一:{0, 2} 在一侧、{1, 3} 在另一侧,或者相反。两者都是有效解:Max-Cut 本身并不区分哪一侧是"第一"侧,所以这是问题本身真实存在的对称性,而不是采样器的错误。

常见错误:忽视嵌入问题

以上内容都运行在一个没有连接性限制的经典模拟退火机上:任意变量都可以自由地与任意其他变量交互。真实的 D-Wave 硬件则完全不同。物理量子比特分布在一个固定且稀疏的拓扑结构上(视代数不同为 Pegasus 或 Zephyr),大多数量子比特对之间根本没有直接连线。

要放置一个变量 i 需要与变量 j 交互、但没有任何物理量子比特对提供这种连接的问题,Ocean 的最小嵌入步骤会把若干个物理量子比特串成一条链,让它们共同充当一个逻辑变量。这个过程是自动完成的,由 dwave-systemEmbeddingComposite 负责处理,但这个过程并非没有代价:链需要额外的量子比特,而且链有时会"断裂"——原本应当保持一致的物理量子比特在退火结束后出现了分歧,从而悄无声息地破坏了那个变量的读数。问题越大、越密集,所需的链就越长,断裂也就越频繁;密度足够高的问题最终会在给定芯片上完全无法嵌入。这是几乎所有人第一次把一个能正常工作的模拟退火问题迁移到真实硬件上时都会遇到的最常见意外:算法本身并没有变差,是芯片的物理连接性成为了瓶颈。

退火不能做什么

退火机不能运行 Grover 搜索,不能运行 Shor 分解,也完全没有"电路"这种通用概念。它的量子比特无法与门模型量子比特直接比较:D-Wave 的系统拥有超过 5000 个量子比特,远多于任何门模型 QPU,但这个数字描述的具体是在 QUBO/Ising 这类问题上的优化能力,而不是通用计算能力。退火相对于最好的经典优化启发式算法,在实际问题上是否真的存在速度优势,这在学术文献中仍然存在真正的争议,而且似乎高度依赖具体问题的结构,不应该被默认为理所当然。

在真实 D-Wave 硬件上运行

只需替换采样器,其余代码保持不变:

from dwave.system import DWaveSampler, EmbeddingComposite

sampler = EmbeddingComposite(DWaveSampler())
sampleset = sampler.sample(bqm, num_reads=1000)

D-Wave 的 Leap 云服务每月提供免费的 QPU 时长配额,专门用于这类实验,这可以看作是门模型硬件领域IBM Quantum 免费套餐在退火领域的对应物。EmbeddingComposite 会自动处理最小嵌入步骤,但在信任任何超出简单玩具问题规模的结果之前,请先检查返回的 sampleset.info 中关于链断裂的统计信息。

下一步