Skip to content

Commit 7ccbdcf

Browse files
committed
new vqe and hadamard test
1 parent 074ced9 commit 7ccbdcf

File tree

9 files changed

+145
-5
lines changed

9 files changed

+145
-5
lines changed

examples/VQE.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using Yao, Yao.Blocks
2+
using QuAlgorithmZoo
3+
using KrylovKit
4+
5+
function ed_groundstate(h::MatrixBlock)
6+
E, V = eigsolve(h |> mat, 1, :SR, ishermitian=true)
7+
println("Ground State Energy is $(E[1])")
8+
register(V[1])
9+
end
10+
11+
N = 5
12+
c = random_diff_circuit(N, N, [i=>mod(i,N)+1 for i=1:N], mode=:Merged) |> autodiff(:QC)
13+
dispatch!(c, :random)
14+
hami = heisenberg(N)
15+
ed_groundstate(hami)
16+
17+
vqe_solve(c, hami)

src/HadamardTest.jl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
export hadamard_test, hadamard_test_circuit, swap_test, swap_test_circuit, singlet_block, state_overlap_circuit
2+
3+
"""
4+
see WiKi.
5+
"""
6+
function hadamard_test_circuit(U::MatrixBlock{N}) where N
7+
chain(N+1, put(N+1, 1=>H),
8+
control(N+1, 1, 2:N+1=>U), # get matrix first, very inefficient
9+
put(N+1, 1=>H)
10+
)
11+
end
12+
13+
function hadamard_test(U::MatrixBlock{N}, reg::AbstractRegister) where N
14+
c = hadamard_test_circuit(U)
15+
reg = join(reg, zero_state(1))
16+
expect(put(N+1, 1=>Z), reg |> c)
17+
end
18+
19+
swap_test_circuit() = hadamard_test_circuit(SWAP)
20+
swap_test(reg::AbstractRegister) = hadamard_test(SWAP, reg)
21+
22+
function singlet_block(::Type{T}, nbit::Int, i::Int, j::Int) where T
23+
unit = chain(nbit)
24+
push!(unit, put(nbit, i=>chain(XGate{T}(), HGate{T}())))
25+
push!(unit, control(nbit, -i, j=>XGate{T}()))
26+
end
27+
28+
singlet_block(nbit::Int, i::Int, j::Int) = singlet_block(ComplexF64, nbit, i, j)
29+
singlet_block() = singlet_block(2,1,2)
30+
31+
"""
32+
Estimation of overlap between multiple density matrices.
33+
34+
PRL 88.217901
35+
"""
36+
function state_overlap_circuit(nbit::Int, nstate::Int, ϕ::Real)
37+
N = nstate*nbit + 1
38+
39+
chain(N, put(N, 1=>H),
40+
put(N, 1=>shift(ϕ)),
41+
chain(N, [chain(N, [control(N, 1, (i+(k*nbit-nbit)+1, i+k*nbit+1)=>SWAP) for i=1:nbit]) for k=1:nstate-1]), # get matrix first, very inefficient
42+
put(N, 1=>H)
43+
)
44+
end
45+
46+
Yao.mat::DensityMatrix{1}) = dropdims(state(ρ), dims=3)

src/QCBM.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ gradient of MMD two sample test loss, `db` must be contained in qcbm.
4646
`p0` is current probability distribution.
4747
"""
4848
function mmdgrad(qcbm::QCBM, db::AbstractDiff; p0::Vector)
49-
vstatdiff(()->psi(qcbm), db, Vstat(kmat(qcbm.kernel)), p0=p0) - 2*vstatdiff(()->psi(qcbm), db, Vstat(kmat(qcbm.kernel)*qcbm.ptrain))
49+
statdiff(()->probs(qcbm) |> as_weights, db, StatFunctional(kmat(qcbm.kernel)), initial=p0 |> as_weights) -
50+
2*statdiff(()->probs(qcbm) |> as_weights, db, StatFunctional(kmat(qcbm.kernel)*qcbm.ptrain))
5051
end
5152

5253
"""

src/QuAlgorithmZoo.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ include("Grover.jl")
2828
include("PhaseEstimation.jl")
2929
include("HHL.jl")
3030
include("hamiltonian_solvers.jl")
31+
include("HadamardTest.jl")
3132

3233

3334
end # module

src/hamiltonian_solvers.jl

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export heisenberg, iter_groundstate!, itime_groundstate!
1+
export heisenberg, iter_groundstate!, itime_groundstate!, vqe_solve!
22

33
"""
44
heisenberg(nbit::Int; periodic::Bool=true)
@@ -29,7 +29,7 @@ end
2929
"""
3030
itime_groundstate!({reg::AbstractRegister}, h::MatrixBlock; τ::Int=20, tol=1e-4) -> AbstractRegister
3131
32-
project wave function to ground state by exp(-hτ). `tol` is for `expmv`.
32+
Imaginary time evolution method to get ground state, i.e. by projecting wave function to ground state by exp(-hτ). `tol` is for `expmv`.
3333
"""
3434
itime_groundstate!(h::MatrixBlock; τ::Real=20, tol=1e-4) = reg -> itime_groundstate!(reg, h; τ=τ, tol=tol)
3535
function itime_groundstate!(reg::AbstractRegister, h::MatrixBlock; τ::Int=20, tol=1e-4)
@@ -44,3 +44,24 @@ function itime_groundstate!(reg::AbstractRegister, h::MatrixBlock; τ::Int=20, t
4444
reg
4545
end
4646

47+
# a patch for Yao.expect, to make it faster
48+
function Yao.expect(op::AddBlock, reg::AbstractRegister{1})
49+
sum(opi->expect(opi, reg), op)
50+
end
51+
52+
"""
53+
vqe_solve!(circuit::MatrixBlock{N}, hamiltonian::AbstractBlock; niter::Int=100) -> circuit
54+
55+
variational quantum eigensolver, faithful simulation with optimizer Adam(lr=0.01).
56+
"""
57+
function vqe_solve!(circuit::MatrixBlock{N}, hamiltonian::AbstractBlock; niter::Int=100) where N
58+
optimizer = Adam(lr=0.01)
59+
dbs = collect(circuit, AbstractDiff)
60+
params = parameters(circuit)
61+
for i = 1:niter
62+
grad = opdiff.(()->zero_state(N) |> circuit, dbs, Ref(hamiltonian))
63+
dispatch!(circuit, update!(params, grad, optimizer))
64+
println("Step $i, Energy = $(expect(hamiltonian, zero_state(N) |> circuit))")
65+
end
66+
circuit
67+
end

test/HadamardTest.jl

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using Yao, Yao.Blocks
2+
using Test
3+
using LinearAlgebra
4+
using QuAlgorithmZoo
5+
6+
@testset "state overlap" begin
7+
reg1 = rand_state(3) |> focus!(1,2)
8+
rho1 = reg1 |> ρ
9+
reg2 = rand_state(3) |> focus!(1,2)
10+
rho2 = reg2 |> ρ
11+
reg3 = rand_state(3) |> focus!(1,2)
12+
rho3 = reg3 |> ρ
13+
desired = tr(mat(rho1)*mat(rho2))
14+
c = state_overlap_circuit(2, 2, 0)
15+
res = expect(put(5, 1=>Z), join(join(reg2, reg1), zero_state(1)) |> c) |> tr
16+
@test desired res
17+
desired = tr(mat(rho1)*mat(rho2)*mat(rho3)) |> real
18+
c = state_overlap_circuit(2, 3, 0)
19+
res = expect(put(7, 1=>Z), reduce(, [reg3, reg2, reg1, zero_state(1)]) |> c) |> tr |> real
20+
@test desired res
21+
desired = tr(mat(rho1)*mat(rho2)*mat(rho3)) |> imag
22+
c = state_overlap_circuit(2, 3, -π/2)
23+
res = expect(put(7, 1=>Z), reduce(, [reg3, reg2, reg1, zero_state(1)]) |> c) |> tr |> real
24+
@test desired res
25+
end
26+
27+
@testset "hadamard test" begin
28+
nbit = 4
29+
U = put(nbit, 2=>Rx(0.2))
30+
reg = rand_state(nbit)
31+
32+
@test hadamard_test(U, reg) real(expect(U, reg))
33+
34+
reg = zero_state(2) |> singlet_block()
35+
@test swap_test(reg) -1
36+
37+
reg = zero_state(2)
38+
@test swap_test(reg) 1
39+
reg = product_state(2, 0b11)
40+
@test swap_test(reg) 1
41+
end

test/PhaseEstimation.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ end
4040
reg = apply!(join(reg2, reg1), circuit)
4141

4242
# measure
43-
res = breflect(M, measure(focus!(copy(reg), 1:M), 10)[1]) / (1<<M)
43+
res = breflect(M, measure(focus!(copy(reg), 1:M); nshot=10)[1]) / (1<<M)
4444

4545
@test res ϕ
4646
@test apply!(reg, circuit |> adjoint) join(reg2, reg1)

test/hamiltonian_solvers.jl

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,14 @@ using QuAlgorithmZoo
1818
reg |> itime_groundstate!(h, τ=20)
1919
EG = expect(h, reg)/nbit/4
2020
@test isapprox(EG, -0.4564, atol=1e-4)
21-
end
2221

22+
# using VQE
23+
N = 4
24+
h = heisenberg(N)
25+
E = eigen(h |> mat |> Matrix).values[1]
26+
c = random_diff_circuit(N, 5, [i=>mod(i,N)+1 for i=1:N], mode=:Merged) |> autodiff(:QC)
27+
dispatch!(c, :random)
28+
vqe_solve!(c, h)
29+
E2 = expect(h, zero_state(N) |> c)
30+
@test isapprox(E, E2, atol=1e-1)
31+
end

test/runtests.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,7 @@ end
3636
@testset "hamiltonian solvers" begin
3737
include("hamiltonian_solvers.jl")
3838
end
39+
40+
@testset "hadamard test" begin
41+
include("HadamardTest.jl")
42+
end

0 commit comments

Comments
 (0)