五. 量子近似优化算法 (QAOA)
量子近似优化算法 (Quantum Approximate Optimization Algorithm) 可以处理的问题中最著名的一个是名为 MaxCut 的图论问题
给定一个图,求一个图的最大分割。
此处分割的大小定义为将图划分为两部分,割过边的数目的多少。它的判定版本被证明是 NP-Complete 问题
给定一个图和整数 k,问是否有存在一个分割大于等于 k。
它可以被翻译为求解经典Ising模型基态的问题,其Hamiltonian如下
E 是一个图中边的集合,可以把定义在顶角 V 上的自旋 理解为一种将图的二分割,+1 和 -1 分别代表了分割后的两部分,分割的大小为所有端点自旋符号相反的边的数目。根据上面的Hamiltonian形式,实际程序的 loss函数可以被定义为
这里去掉了常数项,并且取反号使目标变成求极小。这里引入了权重 ,将MaxCut问题拓展到了带权重版本。特别的地方在于,它通过参数化量子波函数 来变分求解经典Hamilton的基态(是个直积态),避免了直接操作离散数据。
求解这个问题,QAOA 采用了经典量子混合算法,量子部分负责构造量子线路 ansatz ,计算loss。作为一个可以在D-wave 这种量子模拟器上跑的算法,它的 ansatz 的设计是受量子退火算法影响的,其参数化形式为
其中 为 和 的集合,是需要优化的参数。 , , 为横场Hamiltonian。 为各种构型均匀叠加的初始态。简而言之,就是依次作用系统Hamiltonian和横场项到量子态上,以作用时间为优化参数,希望最后能演化到目标经典Hamiltonian基态。经典部分负责优化,可以基于梯度也可以不基于梯度。简单起见,我们采用不基于梯度的方式去模拟,文中采用的是COBYLA算法。
参考文献:
A Quantum Approximate Optimization Algorithm首先导入一些包,其中 NLopt 是非线性优化器的包,在这个例子面我们将会使用基于单纯形法的 COBYLA 优化算法作为我们的经典优化部分。同时我们引入maxcut_gw.jl
这个文件,它包含了 MaxCut 问题的经典解法 - Goemans-Williamson 算法,具体见目录。
首先,我们构造两个Hamiltonian构造方法 HB 和 HC。
using Yao, BitBasis
using NLopt
include("maxcut_gw.jl")
"""
Transverse field term
"""
HB(nbit::Int) = sum([put(nbit, i=>X) for i=1:nbit])
"""
Target Hamiltonian.
"""
function HC(W::AbstractMatrix)
nbit = size(W, 1)
ab = Any[]
for i=1:nbit,j=i+1:nbit
if W[i,j] != 0
push!(ab, 0.5*W[i,j]*repeat(nbit, Z, [i,j]))
end
end
sum(ab)
end
对于三个角的图,HB 定义的含时演化如下
julia> TimeEvolution(HB(3), 0.1)
Time Evolution Total: 3, DataType: Complex{Float64}
+
├─ put on (1)
│ └─ X gate
├─ put on (2)
│ └─ X gate
└─ put on (3)
└─ X gate
Δt = 0.1, tol = 1.0e-7
HC通过权重矩阵生成,比如如下的 3 个角的的全连接图
julia> W = [0 1 3; 1 0 1; 3 1 0] # 3x3 的全连接图
3×3 Array{Int64,2}:
0 1 3
1 0 1
3 1 0
julia> hc = HC(W)
Total: 3, DataType: Complex{Float64}
+
├─ [0.5] repeat on (1, 2)
│ └─ Z gate
├─ [1.5] repeat on (1, 3)
│ └─ Z gate
└─ [0.5] repeat on (2, 3)
└─ Z gate
julia> ishermitian(hc)
true
下来可以构造 QAOA 整体的线路图,此处depth
定义为 , 的重复次数。可选参数use_cache
如果为true
,则可以把Hamiltonian的矩阵形式缓存下来加速含时演化操作。
function qaoa_circuit(W::AbstractMatrix, depth::Int; use_cache::Bool=false)
nbit = size(W, 1)
hb = HB(nbit)
hc = HC(W)
use_cache && (hb = hb |> cache; hc = hc |> cache)
c = chain(nbit, [repeat(nbit, H, 1:nbit)])
append!(c, [chain(nbit, [time_evolve(hc, 0.0, tol=1e-5),
time_evolve(hb, 0.0, tol=1e-5)]) for i=1:depth])
end
可以看到对于3个node的全连接图,两层的结构最后得到的线路图如下
julia> qaoa_circuit(W, 2)
Total: 3, DataType: Complex{Float64}
chain
├─ repeat on (1, 2, 3)
│ └─ H gate
├─ chain
│ ├─ Time Evolution Total: 3, DataType: Complex{Float64}
│ │ +
│ │ ├─ [0.5] repeat on (1, 2)
│ │ │ └─ Z gate
│ │ ├─ [1.5] repeat on (1, 3)
│ │ │ └─ Z gate
│ │ └─ [0.5] repeat on (2, 3)
│ │ └─ Z gate
│ │ Δt = 0.0, tol = 1.0e-5
│ └─ Time Evolution Total: 3, DataType: Complex{Float64}
│ +
│ ├─ put on (1)
│ │ └─ X gate
│ ├─ put on (2)
│ │ └─ X gate
│ └─ put on (3)
│ └─ X gate
│ Δt = 0.0, tol = 1.0e-5
└─ chain
├─ Time Evolution Total: 3, DataType: Complex{Float64}
│ +
│ ├─ [0.5] repeat on (1, 2)
│ │ └─ Z gate
│ ├─ [1.5] repeat on (1, 3)
│ │ └─ Z gate
│ └─ [0.5] repeat on (2, 3)
│ └─ Z gate
│ Δt = 0.0, tol = 1.0e-5
└─ Time Evolution Total: 3, DataType: Complex{Float64}
+
├─ put on (1)
│ └─ X gate
├─ put on (2)
│ └─ X gate
└─ put on (3)
└─ X gate
Δt = 0.0, tol = 1.0e-5
训练采用COBYLA算法,是基于单纯形方法的优化算法中比较好用的。用法请参见NLopt的文档。
function cobyla_optimize(circuit::MatrixBlock{N}, hc::MatrixBlock; niter::Int) where N
function f(params, grad)
reg = zero_state(N) |> dispatch!(circuit, params)
loss = expect(hc, reg) |> real
#println(loss)
loss
end
opt = Opt(:LN_COBYLA, nparameters(circuit))
min_objective!(opt, f)
maxeval!(opt, niter)
cost, params, info = optimize(opt, parameters(circuit))
pl = zero_state(N) |> circuit |> probs
cost, params, pl
end
作为测试,我们构造一个5个节点的图
nbit = 5
W = [0 5 2 1 0;
5 0 3 2 0;
2 3 0 0 0;
1 2 0 0 4;
0 0 0 4 0]
# the exact solution
exact_cost, sets = goemansWilliamson(W)
hc = HC(W)
# the cut is -<Hc> + sum(wij)/2
@test -expect(hc, product_state(5, bmask(sets[1]...)))+sum(W)/4 ≈ exact_cost
这里我们会得到严格解[1, 3, 4],[2, 5]
, 此分割大小为14
. 这里我们测试了目标 Hamiltonian的正确性,注意这里符号和常数的差别。
# build a QAOA circuit and start training.
qc = qaoa_circuit(W, 20; use_cache=false)
opt_pl = nothing
opt_cost = Inf
for i = 1:10
dispatch!(qc, :random)
cost, params, pl = cobyla_optimize(qc, hc; niter=2000)
@show cost
cost < opt_cost && (opt_pl = pl)
end
输入如下:
cost=-5.056439885146659
cost=-5.3148313277163455
cost=-5.314515402351343
cost=-5.27061216619153
cost=-5.218577446603341
cost=-5.140030583281352
cost=-4.859469398853606
cost=-5.445797991390686
cost=-5.2074338799039
cost=-4.971171116896116
对于严格解,cost应该是-5.5,可见经过充分优化,很多情况QAOA都可以得到足够好的解。
检查输出是否正确
# check the correctness of result
config = argmax(opt_pl)-1
@test config in [bmask(set...) for set in sets]
大家有没有发现其实QAOA优化有时候不稳定,经常得到的结果是错的?一个可以优化的地方是用基于梯度的优化器,但是这需要很特别的构造。大家可以去尝试哦~
Goemans-Williamson 算法
该算法用于求解Max-Cut问题,原算法在 https://github.com/ericproffitt/MaxCut, 但是由于很久没更新已经不再兼容Julia 1.0以上版本。如下是适用于Julia1.x的代码,需要提前安装CSC和Convex两个包来使用。
using Convex
using SCS
using LinearAlgebra
"
The Goemans-Williamson algorithm for the MAXCUT problem.
Adapted From: https://github.com/ericproffitt/MaxCut
"
function goemansWilliamson(W::Matrix{T}; tol::Real=1e-1, iter::Int=100) where T<:Real
"Partition a graph into two disjoint sets such that the sum of the edge weights
which cross the partition is as large as possible (known to be NP-hard)."
"A cut of a graph can be produced by assigning either 1 or -1 to each vertex. The Goemans-Williamson
algorithm relaxes this binary condition to allow for vector assignments drawn from the (n-1)-sphere
(choosing an n-1 dimensional space will ensure seperability). This relaxation can then be written as
an SDP. Once the optimal vector assignments are found, origin centered hyperplanes are generated and
their corresponding cuts evaluated. After 'iter' trials, or when the desired tolerance is reached,
the hyperplane with the highest corresponding binary cut is used to partition the vertices."
"W: Adjacency matrix."
"tol: Maximum acceptable distance between a cut and the MAXCUT upper bound."
"iter: Maximum number of hyperplane iterations before a cut is chosen."
LinearAlgebra.checksquare(W)
@assert LinearAlgebra.issymmetric(W) "Adjacency matrix must be symmetric."
@assert all(W .>= 0) "Entries of the adjacency matrix must be nonnegative."
@assert all(diag(W) .== 0) "Diagonal entries of adjacency matrix must be zero."
@assert tol > 0 "The tolerance 'tol' must be positive."
@assert iter > 0 "The number of iterations 'iter' must be a positive integer."
"This is the standard SDP Relaxation of the MAXCUT problem, a reference can be found at
http://www.sfu.ca/~mdevos/notes/semidef/GW.pdf."
k = size(W, 1)
S = Semidefinite(k)
expr = dot(W, S)
constr = [S[i,i] == 1.0 for i in 1:k]
problem = minimize(expr, constr...)
solve!(problem, SCSSolver(verbose=0))
### Ensure symmetric positive-definite.
A = 0.5 * (S.value + S.value')
A += (max(0, -eigmin(A)) + eps(1e3))*I
X = Matrix(cholesky(A))
### A non-trivial upper bound on MAXCUT.
upperbound = (sum(W) - dot(W, S.value)) / 4
"Random origin-centered hyperplanes, generated to produce partitions of the graph."
maxcut = 0
maxpartition = nothing
for i in 1:iter
gweval = X' * randn(k)
partition = (findall(x->x>0, gweval), findall(x->x<0, gweval))
cut = sum(W[partition...])
if cut > maxcut
maxpartition = partition
maxcut = cut
end
upperbound - maxcut < tol && break
i == iter && println("Max iterations reached.")
end
return round(maxcut; digits=3), maxpartition
end
using Test
@testset "max cut" begin
W = [0 5 2 1 0;
5 0 3 2 0;
2 3 0 0 0;
1 2 0 0 4;
0 0 0 4 0]
maxcut, maxpartition = goemansWilliamson(W)
@test maxcut == 14
@test [2,5] in maxpartition
end
热门文章排行
- 共享,正从风口到风险
- 走进涂料市场的秘密
- 在人工智能炒热机器人时,也被人把风带进了
- 生物涂料有什么好处?
- 智能音箱,正走在智能手表的老路上
- “去乐视化”之后,新易到的机会在哪儿?
- 日本十大波涛汹涌巨乳美少女第5名,凶悍!
- 涂料行业未来走势 品质与个性化不可少
- 打造时尚靓丽居室 油漆选购注意三点
- AI在内容分发上的绊脚石
最新资讯文章
- 英文留学推荐信范文
- 本科会计,出国读研读什么好?给点好建议啊
- 美国大学6大类共45个专业详细解读和就业
- 英文工作推荐信_2
- 意大利都灵美术学院—唯一拥有美术馆的美院
- 鐩稿叧瑙嗛
- 专四优秀范文:如何看待出国留学
- 2023英语专业哪个学校最好?全国英语专
- 出国留学美术专业院校有哪些
- 出国留学五十年数据汇总:我国留学人员累计
- 【留学指南】欧洲英语系「人工智能专业硕士
- 留学个人陈述(留学PS)模版
- 艺术治疗专业院校推荐及申请条件!
- 意大利威尼斯美术学院申请条件
- 园艺专业出国留学哪个学校好?
- 2024年世界大学学科排名:心理学
- 留学推荐信(通用14篇)
- 互助交流|想看看大家在大学毕业后通过自己
- 2023留学推荐信你必须知道的六件事
- 苏州大学