1. 量子退火求解组合优化问题的建模与求解

问题定义与建模:5 节点最大割

最大割(Max-Cut)的目标是把无向图的顶点分成两组,使跨越两组的边权之和最大。选一个 5 节点、6 条边的小图作为教学对象,边权如下:

边(0,1)(0,2)(1,2)(1,3)(2,4)(3,4)
权重121321

用自旋变量 s_i ∈ {−1, +1} 表示顶点归属(+1 与 −1 分属两组)。一条边 (i,j) 被割断当且仅当 s_i ≠ s_j,此时 (1 − s_i s_j)/2 = 1。因此最大化割值等价于最小化下面的伊辛能量:

E(s) = Σ_(i,j) w_ij · (1 − s_i s_j) / 2
     = 常数 − (1/2) · Σ w_ij s_i s_j

量子退火器(如 D-Wave)求解的是 E = Σ J_ij s_i s_j + Σ h_i s_i 形式。对照可得耦合系数 J_ij = −w_ij/2,局部场 h_i = 0。常数项不影响最优解位置,可忽略。于是建模只需给出 J 矩阵与 h 向量。

最大割 → 伊辛模型映射 原图(边权标注) 1 2 1 3 2 1 0 1 2 3 4 映射 伊辛参数(J = −w/2, h = 0) 耦合矩阵 J J₀₁ = −0.5 J₀₂ = −1.0 J₁₂ = −0.5 J₁₃ = −1.5 J₂₄ = −1.0 J₃₄ = −0.5 局部场 hᵢ = 0(全部) E(s) = Σ J_ij s_i s_j = −0.5·s₀s₁ − 1.0·s₀s₂ − 0.5·s₁s₂ − 1.5·s₁s₃ − 1.0·s₂s₄ − 0.5·s₃s₄ 最小化 E 即最大化割值;常数项 Σw/2 = 5 不影响最优自旋配置

量子退火求解流程与参数设置

量子退火的核心是让系统从初始哈密顿量 H_init = −Σ σ_i^x 缓慢演化到问题哈密顿量 H_problem = Σ J_ij σ_i^z σ_j^z。演化时间(annealing time)越长,系统越可能停留在基态,但受噪声与退相干限制,并非越长越好。关键参数:

  • 退火时间:本例取 20 μs,属于小规模问题的常用量级。
  • 读取次数(num_reads):每个退火周期结束后测量一次,取 1000 次以统计解分布。
  • 链强度(chain_strength):本例 5 节点图可完整嵌入,无需链,设为默认。

若使用 D-Wave 的 Ocean SDK,建模与提交代码如下(dimod 的 BQM 接口同时兼容模拟器与真实退火器):

import dimod
from dwave.system import DWaveSampler, EmbeddingComposite

# 1. 构造 BQM:J 为耦合,h 为局部场
J = {(0,1): -0.5, (0,2): -1.0, (1,2): -0.5,
     (1,3): -1.5, (2,4): -1.0, (3,4): -0.5}
h = {i: 0.0 for i in range(5)}
bqm = dimod.BinaryQuadraticModel(h, J, 0.0, dimod.SPIN)

# 2. 提交到量子退火器(需配置 D-Wave 凭证)
sampler = EmbeddingComposite(DWaveSampler())
sampleset = sampler.sample(bqm, num_reads=1000, annealing_time=20)

# 3. 读取最优解
best = sampleset.first
print(best.sample, best.energy)

没有 D-Wave 访问权限时,用 dimod.ExactSolver() 或 neal.SimulatedAnnealingSampler() 替代 sampler 即可跑通同一套建模代码,验证 BQM 构造是否正确。

经典模拟退火对比验证

为判断量子退火结果是否可信,用经典模拟退火在同一 BQM 上求解并对比。经典模拟退火通过温度参数 beta(逆温度)控制接受劣解的概率,从高温逐步降温:

import neal

sa = neal.SimulatedAnnealingSampler()
sa_sampleset = sa.sample(bqm, num_reads=1000, beta_range=[0.1, 5.0])

sa_best = sa_sampleset.first
print("SA 最优:", sa_best.sample, sa_best.energy)

# 穷举验证(5 节点仅 32 种自旋配置)
exact = dimod.ExactSolver().sample(bqm)
print("精确最优能量:", exact.first.energy)

5 节点问题共 2⁵ = 32 种自旋配置,穷举可得到精确基态能量,作为两种退火方法的上界参照。预期现象:精确解能量应为 −3.0(对应割值 8),量子退火与经典模拟退火在 1000 次读取中应大概率命中该能量;若量子退火的最优能量高于精确值,说明退火时间不足或噪声导致未收敛。

结果解读与判读要点

拿到 sampleset 后,不要只看 first,应统计能量分布与解的出现频率:

import collections
energies = sampleset.record.energy
counts = collections.Counter(energies)
for e, c in sorted(counts.items()):
    print(f"能量 {e:+.1f}: {c} 次")

判读逻辑:

  • 最优能量等于精确值:建模正确,退火参数合理。
  • 最优能量高于精确值但差距小:退火时间偏短,可增大 annealing_time 或 num_reads。
  • 最优能量明显偏高:检查 J 符号是否写反(最大化割值对应负 J),或链强度不足导致嵌入失败。
  • 最优解出现频率极低:说明基态与激发态能量间隙小,属于问题本身的难度,不是参数错误。
把量子退火与经典模拟退火的最优能量、命中基态次数并列记录,是验证建模正确性最直接的手段。两者一致且等于穷举值时,可认为建模与参数设置均通过。