qalgora-Q Docs Hub量子文档 ✦ Ask AI✦ 问问文档

ADAPT-QAOA Algorithm

◐ Design-level API
This page documents qalgora-Q API design, architecture, or adaptation workflows. Code examples illustrate intended usage and are not guaranteed to run in the current reference implementation.

A variant of QAOA that, like ADAPT-VQE, grows its mixer adaptively — picking the operator with the largest gradient at each layer instead of a fixed mixer. Understand first why it does this, then see how qalgora-Q expresses the whole loop in a few lines of code.

The problem it solves — a fixed mixer is too rigid

Standard QAOA alternates two kinds of operator: the cost Hamiltonian HC that encodes the problem, and a mixing operator that drives transitions between states — the latter usually fixed to a transverse field Σ Xi on every qubit. That fixed mixer treats every problem, and every layer, identically; it pays no attention to which direction the current state most needs to be stirred. The result is that reaching a good solution often demands many layers — and depth is exactly the scarcest resource on shallow, near-term hardware.

Intuition — pick the best way to stir at every layer

ADAPT-QAOA stops fixing the mixer and instead chooses it adaptively, layer by layer. Prepare a pool of candidate mixing operators, and whenever a new layer is to be added, ask the same old question: which operator drives the energy down fastest? The gradient answers it. Pick the largest-gradient operator as this layer's mixer, re-optimize all the angles, then move on to the next layer. This way the stirring at each layer is tailored to the current state, and a good solution is usually reached in far fewer layers.

The math — measuring mixer gradients with a commutator

The criterion is the same as in ADAPT-VQE: in the current state, the gradient of the energy with respect to the angle of a candidate mixer Aj, once it is switched in, is given by the expectation of its commutator with the cost Hamiltonian

gj = −i⟨ [HC, Aj] ⟩.

The −i makes the gradient real-valued: for Hermitian HC and Aj the commutator is anti-Hermitian, so −i[HC, Aj] is Hermitian and its expectation is real.

The derivative is taken on the current optimized state p at the candidate mixer parameter β=0:

gj = d/dβ ⟨ψp| e(iβ Aj) HC e(−iβ Aj)p⟩|β=0 = −i⟨ψp|[HC, Aj]|ψp

so the operator actually measured is the Hermitian −i[HC, Aj], not the non-Hermitian product HC·Aj.

The operator with the largest absolute gradient is the stirring direction that currently pushes the energy down hardest — so it is chosen as this layer's mixer. The only difference is what the criterion is used for: ADAPT-VQE uses it to grow a chemistry ansatz, while ADAPT-QAOA uses it to select QAOA's mixer one layer at a time.

How it works — the layer-by-layer iteration

  1. Start from the uniform superposition and a given cost Hamiltonian HC.
  2. For each operator Aj in the pool, measure the gradient −i⟨[HC, Aj]⟩.
  3. Add the highest-gradient operator to the circuit as the next mixer layer.
  4. Re-optimize all angles, then return to step 2 to grow the next layer.

The initial state is not always the uniform superposition: constrained problems need a feasible reference state and a constraint-preserving mixer pool. And on re-optimization, all γl and βl are optimized together.

Honest limits

  • Per-layer screening costs measurements. Each new layer requires measuring the gradient of every candidate in the pool — this is precisely the price paid in exchange for shallower circuits.
  • It is still greedy. Each layer takes only the locally steepest direction; there is no guarantee of the globally optimal layer ordering or the minimum total number of layers.
  • The mixer pool design is critical. If the pool contains no suitable operator, adaptivity cannot conjure a good mixer; if the pool is too large, the screening cost climbs.
  • Re-optimization grows more expensive with depth. Every added layer means re-optimizing all existing angles together, so each later round costs progressively more.

Seeing it in code

Read this code against the explanation above. pool collects the candidate mixers — both single-qubit spin.x(i) and the two-qubit spin.y(i) * spin.y(j) acting along the graph's edges. Each pass of the loop first computes the gradients grads for every operator in the pool (the −i⟨[HC, Aj]⟩ values), uses max(..., key=lambda k: abs(grads[k])) to select the operator with the largest absolute gradient and append it as a new layer, then calls reoptimize(...) to re-optimize all the angles. One pass, one layer — exactly matching the iteration above. Note that commutator(cost, a) builds the actual commutator [HC, Aj], and the measured operator is the Hermitian −i[HC, Aj], not the non-Hermitian product HC·Aj.

import qalgora
from qalgora import spin

cost = build_maxcut_cost(graph)
pool = [spin.x(i) for i in range(n)] + \
       [spin.y(i) * spin.y(j) for i, j in edges]

def commutator(h, a):
    return h * a - a * h          # [H_C, A_j] = H_C·A_j − A_j·H_C

layers = []
for _ in range(depth):
    # g_j = -i<[H_C, A_j]> — measure the Hermitian observable -i[H_C, A_j]
    grads = [(-1j * qalgora.observe(commutator_kernel,
                                    commutator(cost, a), params).expectation()).real
             for a in pool]
    layers.append(pool[max(range(len(pool)), key=lambda k: abs(grads[k]))])
    params = reoptimize(cost, layers)
Why adaptive?
A problem-tailored mixer reaches good solutions at lower depth than standard QAOA — important for shallow, near-term hardware.

ADAPT-QAOA 算法

◐ 设计接口
本页描述的是 qalgora-Q 的接口设计、架构设计或适配工作流。相关代码用于说明预期用法,当前参考实现不保证可以直接运行。

QAOA 的一种变体,与 ADAPT-VQE 类似,以自适应方式生长混合层——在每一层选取梯度最大的混合算符,而非沿用固定的混合层。先理解它为何这样做,再看 qalgora-Q 如何把这套循环写成几行代码。

它解决的问题 固定混合层不够灵活

标准 QAOA 交替施加两类算符:把问题编码的代价哈密顿量 HC,和一个用来制造态间跃迁的混合算符——后者通常固定为所有比特上的横场 Σ Xi。这个固定混合层对每个问题、每一层都一视同仁,并不关心当前态最需要往哪个方向被搅动。结果是:要达到好解往往得堆很多层,而层数正是近期浅层硬件最稀缺的资源。

直觉 每一层都挑最合适的搅动方式

ADAPT-QAOA 不再固定混合层,而是逐层自适应地挑选。准备一池候选混合算符,每要加新一层时,问的还是那个老问题:哪个算符能让能量下降得最快?答案由梯度给出。把梯度最大的算符选作这一层的混合算符,再重新优化所有角度,然后进入下一层。这样每一层的搅动方式都是针对当前态量身挑的,往往用更少的层就能逼近好解。

数学 用对易子衡量混合层梯度

沿用与 ADAPT-VQE 相同的判据:在当前态下,把候选混合算符 Aj 接入后能量对其角度的梯度,由它与代价哈密顿量的对易子期望给出

gj = −i⟨ [HC, Aj] ⟩

其中 −i 使梯度为实数:当 HCAj 为厄米算符时,对易子为反厄米算符,故 −i[HC, Aj] 为厄米算符,其期望为实数。

该导数是在当前已优化态 p 上、于候选混合参数 β=0 处取得的:

gj = d/dβ ⟨ψp| e(iβ Aj) HC e(−iβ Aj)p⟩|β=0 = −i⟨ψp|[HC, Aj]|ψp

因此实际测量的算符是厄米的 −i[HC, Aj],而不是非厄米的乘积 HC·Aj

梯度绝对值最大的算符,就是当下最能推动能量下降的搅动方向——把它选作这一层的混合层。区别仅在于:ADAPT-VQE 用它来生长一个化学拟设,ADAPT-QAOA 用它来逐层选 QAOA 的混合算符。

机制 逐层迭代

  1. 从均匀叠加态出发,给定代价哈密顿量 HC
  2. 对算符池中的每个算符 Aj,测量梯度 −i⟨[HC, Aj]⟩
  3. 将梯度最大的算符作为下一个混合层加入线路。
  4. 重新优化全部角度,然后回到第二步继续生长下一层。

初态不一定总是均匀叠加态;带约束的问题需要可行的参考态和保持约束的 mixer pool。重新优化时同时优化所有 γl 与 βl

诚实的边界

  • 逐层筛选有测量开销。每加一层都要把池中所有候选算符的梯度测一遍——这正是它换取浅线路所付的代价。
  • 它依然是贪心的。每层只取当前最陡的方向,不保证全局最优的层序或最少的总层数。
  • 混合算符池的设计很关键。池子里若没有合适的算符,自适应也挑不出好混合层;池子太大则筛选成本上升。
  • 重优化随层数累积变贵。每加一层都要把已有角度一并重优化,后期每轮成本递增。

对照代码理解

请对照上文来读这段代码。pool 收集候选混合算符——既有单比特的 spin.x(i),也有沿图的边作用的两比特 spin.y(i) * spin.y(j)。循环每一轮先对池中每个算符算出梯度 grads(即 −i⟨[HC, Aj]⟩ 的值),用 max(..., key=lambda k: abs(grads[k])) 选出梯度绝对值最大的算符追加为新的一层,再调用 reoptimize(...) 重新优化全部角度。一轮一层,恰好对应上面的迭代流程。注意 commutator(cost, a) 构造的是真正的对易子 [HC, Aj],实际测量的算符是厄米的 −i[HC, Aj],而不是非厄米的乘积 HC·Aj

示例代码

import qalgora
from qalgora import spin

cost = build_maxcut_cost(graph)
pool = [spin.x(i) for i in range(n)] + \
       [spin.y(i) * spin.y(j) for i, j in edges]

def commutator(h, a):
    return h * a - a * h          # [H_C, A_j] = H_C·A_j − A_j·H_C

layers = []
for _ in range(depth):
    # g_j = -i<[H_C, A_j]> — 测量厄米可观测量 -i[H_C, A_j]
    grads = [(-1j * qalgora.observe(commutator_kernel,
                                    commutator(cost, a), params).expectation()).real
             for a in pool]
    layers.append(pool[max(range(len(pool)), key=lambda k: abs(grads[k]))])
    params = reoptimize(cost, layers)
为何自适应
针对问题定制的混合层,能以更低深度达到较优解,这对近期浅层硬件尤为重要。