Skip to content

Commit c8805e0

Browse files
committed
fix for Yao-0.6.0
1 parent 7d5c239 commit c8805e0

File tree

10 files changed

+118
-313
lines changed

10 files changed

+118
-313
lines changed

examples/Grover/Grover.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ function single_try(oracle, gen::AbstractBlock{N}, nstep::Int; nbatch::Int) wher
6363
return r
6464
end
6565
reg |> checker
66-
res = measure_remove!(reg, (N+1))
66+
res = measure!(RemoveMeasured(), reg, (N+1))
6767
return res, reg
6868
end
6969

@@ -76,7 +76,7 @@ checker = control(num_bit+1,ctrl, num_bit+1=>X)
7676

7777
# The register is batched, with batch dimension `nshot`.
7878
# [`focus!`](@ref Yao.focus!) views the first 1-N qubts as system.
79-
# For a batched register, [`measure_remove!`](@ref Yao.measure_remove!)
79+
# For a batched register, [`measure!`](@ref Yao.measure!)
8080
# returns a vector of bitstring as output.
8181

8282
# #### Run

examples/HHL/HHLlib.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ function hhlcircuit(UG, n_reg::Int, C_value::Real)
5656
n_all = 1 + n_reg + n_b
5757
pe = PEBlock(UG, n_reg, n_b)
5858
cr = HHLCRot{n_reg+1}([2:n_reg+1...], 1, C_value)
59-
chain(n_all, concentrate(n_all, pe, [2:n_all...,]), concentrate(n_all, cr, [1:(n_reg+1)...,]), concentrate(n_all, pe', [2:n_all...,]))
59+
chain(n_all, subroutine(n_all, pe, [2:n_all...,]), subroutine(n_all, cr, [1:(n_reg+1)...,]), subroutine(n_all, pe', [2:n_all...,]))
6060
end
6161

6262
"""

examples/QCBM/Kernels.jl

Lines changed: 0 additions & 38 deletions
This file was deleted.

examples/QCBM/QCBM.jl

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,54 @@
11
# # Quantum Circuit Born Machine
2-
32
using Yao, YaoExtensions
4-
import QuAlgorithmZoo
5-
include("qcbmlib.jl")
3+
import Yao: probs
4+
using QuAlgorithmZoo: Adam, update!
5+
6+
struct QCBM{BT<:AbstractBlock, MT<:MMD}
7+
circuit::BT
8+
mmd::MT
9+
end
10+
11+
"""generated output probability distribution"""
12+
function probs(qcbm::QCBM)
13+
zero_state(qcbm.circuit |> nqubits) |> qcbm.circuit |> probs
14+
end
15+
16+
function loss(qcbm::QCBM)
17+
expect(qcbm.mmd, probs(qcbm) |> as_weights)
18+
end
19+
20+
function getgrad(qcbm::QCBM)
21+
expect'(qcbm.mmd, zero_state(nqubits(qcbm.circuit))=>qcbm.circuit).second
22+
end
623

724
# ## DATA: Target Probability Distribution
825
# The gaussian probability disctribution in phase space of 2^6
926
nbit = 6
1027
N = 1<<nbit
28+
29+
function gaussian_pdf(x, μ::Real, σ::Real)
30+
pl = @. 1 / sqrt(2pi * σ^2) * exp(-(x - μ)^2 / (2 * σ^2))
31+
pl / sum(pl)
32+
end
1133
pg = gaussian_pdf(1:N, N/2-0.5, N/4);
1234

1335
# ## MODEL: Quantum Circuit and Loss
1436
# Using a random differentiable circuit of depth 6 for training, the kernel function is universal RBF kernel
1537
depth = 6
16-
kernel = rbf_kernel(0:N-1, 0.25)
17-
c = variational_circuit(nbit, depth, pair_ring(nbit)) |> autodiff(:QC);
38+
kernel = rbf_kernel(0.25)
39+
c = variational_circuit(nbit, depth, pair_ring(nbit))
1840
dispatch!(c, :random)
19-
qcbm = QCBM(c, kernel, pg);
41+
qcbm = QCBM(c, MMD(kernel, pg))
2042

2143
# ## TRAINING: Adam Optimizer
2244
# We probide the QCBMGo! iterative interface for training
2345
niter = 100
2446
optim = Adam(lr=0.1)
25-
for info in QCBMGo!(qcbm, optim, niter)
26-
curr_loss = loss(qcbm, info["probs"])
27-
println("Step = ", info["step"], ", Loss = ", curr_loss)
47+
48+
params = parameters(qcbm.circuit)
49+
for i=1:niter
50+
# initialize the parameters
51+
update!(params, getgrad(qcbm), optim)
52+
dispatch!(qcbm.circuit, params)
53+
println("Step = $i, Loss = $(loss(qcbm))")
2854
end

examples/QCBM/qcbmlib.jl

Lines changed: 0 additions & 102 deletions
This file was deleted.

examples/QSVD/QSVD.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@ end
3131
function circuit_qsvd(circuit_a::AbstractBlock{Na}, circuit_b::AbstractBlock{Nb}, Nc::Int) where {Na, Nb}
3232
nbit = Na+Nb
3333
cnots = chain(control(nbit, i+Na, i=>X) for i=1:Nc)
34-
c = chain(concentrate(nbit, circuit_a, 1:Na), concentrate(nbit, circuit_b, Na+1:nbit), cnots)
34+
c = chain(subroutine(nbit, circuit_a, 1:Na), subroutine(nbit, circuit_b, Na+1:nbit), cnots)
3535
end
3636

3737
"""read QSVD results"""
3838
function readout_qsvd(reg::AbstractRegister, circuit_a::AbstractBlock{Na}, circuit_b::AbstractBlock{Nb}, Nc::Int) where {Na, Nb}
39-
reg = copy(reg) |> concentrate(Na+Nb, circuit_a, 1:Na) |> concentrate(Na+Nb, circuit_b, Na+1:Na+Nb)
39+
reg = copy(reg) |> subroutine(Na+Nb, circuit_a, 1:Na) |> subroutine(Na+Nb, circuit_b, Na+1:Na+Nb)
4040
_S = [select(reg, b|b<<Na).state[] for b in basis(Nc)]
4141
S = abs.(_S)
4242
order = sortperm(S, rev=true)
@@ -45,7 +45,7 @@ function readout_qsvd(reg::AbstractRegister, circuit_a::AbstractBlock{Na}, circu
4545
end
4646

4747
"""
48-
QuantumSVD(M; kwargs...)
48+
quantumSVD(M; kwargs...)
4949
Quantum SVD.
5050
* `M`, the matrix to decompose, size should be (2^Na × 2^Nb), the sum of squared spectrum must be 1.
5151
kwargs includes
@@ -54,7 +54,7 @@ kwargs includes
5454
* `maxiter`, maximum number of iterations,
5555
* `optimizer`, default is `Adam(lr=0.1)`.
5656
"""
57-
function QuantumSVD(M::AbstractMatrix; Nc::Int=log2i(min(size(M)...)),
57+
function quantumSVD(M::AbstractMatrix; Nc::Int=log2i(min(size(M)...)),
5858
circuit_a=variational_circuit(log2i(size(M, 1))),
5959
circuit_b=variational_circuit(log2i(size(M, 2))),
6060
maxiter=200, optimizer=Adam(lr=0.1))
@@ -76,7 +76,7 @@ end
7676
M = reshape(rand_state(Na+Nb).state, 1<<Na, 1<<Nb)
7777
U_exact, S_exact, V_exact = svd(M)
7878

79-
U, S, V = QuantumSVD(M; maxiter=400)
79+
U, S, V = quantumSVD(M; maxiter=400)
8080

8181
@test isapprox(U*Diagonal(S)*V', M, atol=1e-2)
8282
@test isapprox(abs.(S), S_exact, atol=1e-2)

examples/QuGAN/QuGAN.jl

Lines changed: 73 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,78 @@
1-
# # Quantum GAN
2-
using Yao, YaoExtensions
3-
using Yao.ConstGate: P0
4-
import QuAlgorithmZoo
5-
using Test, Random
1+
using Yao
2+
using YaoExtensions: variational_circuit, Sequence, faithful_grad, numdiff
3+
using QuAlgorithmZoo: Adam, update!
4+
import Yao: tracedist
65

7-
include("QuGANlib.jl")
6+
"""
7+
Quantum GAN.
88
9-
# ## DATA: Target Wave Function
10-
# here we learn a 3 qubit state
11-
nbit = 3
12-
target_state = rand_state(nbit)
9+
Reference:
10+
Benedetti, M., Grant, E., Wossnig, L., & Severini, S. (2018). Adversarial quantum circuit learning for pure state approximation, 1–14.
11+
"""
12+
struct QuGAN{N}
13+
target::ArrayReg
14+
generator::AbstractBlock{N}
15+
discriminator::AbstractBlock
16+
reg0::ArrayReg
17+
witness_op::AbstractBlock
18+
circuit::AbstractBlock
19+
20+
function QuGAN(target::ArrayReg, gen::AbstractBlock, dis::AbstractBlock)
21+
N = nqubits(target)
22+
c = Sequence([gen, addbits!(1), dis])
23+
witness_op = put(N+1, (N+1)=>ConstGate.P0)
24+
new{N}(target, gen, dis, zero_state(N), witness_op, c)
25+
end
26+
end
27+
28+
# INTERFACES
29+
circuit(qg::QuGAN) = qg.circuit
30+
loss(qg::QuGAN) = p0t(qg) - p0g(qg)
31+
32+
function gradient(qg::QuGAN)
33+
grad_gen = faithful_grad(qg.witness_op, qg.reg0 => qg.circuit)
34+
grad_tar = faithful_grad(qg.witness_op, qg.target => qg.circuit[2:end])
35+
ngen = nparameters(qg.generator)
36+
[-grad_gen[1:ngen]; grad_tar - grad_gen[ngen+1:end]]
37+
end
38+
39+
"""probability to get evidense qubit 0 on generation set."""
40+
p0g(qg::QuGAN) = expect(qg.witness_op, qg.reg0 => qg.circuit) |> real
41+
"""probability to get evidense qubit 0 on target set."""
42+
p0t(qg::QuGAN) = expect(qg.witness_op, qg.target => qg.circuit[2:end]) |> real
43+
"""generated wave function"""
44+
outputψ(qg::QuGAN) = copy(qg.reg0) |> qg.generator
1345

14-
# ## MODEL: Quantum Circuit and Loss
15-
# using a 4-layer random differential circuit for both generator and discriminator
16-
# we build the qcgan setup.
46+
"""tracedistance between target and generated wave function"""
47+
tracedist(qg::QuGAN) = tracedist(qg.target, outputψ(qg))[]
48+
49+
using Test, Random
50+
Random.seed!(2)
51+
52+
nbit = 3
1753
depth_gen = 4
18-
generator = dispatch!(variational_circuit(nbit, depth_gen, pair_ring(nbit)), :random) |> autodiff(:QC);
19-
20-
#------------------------------
21-
depth_disc = 4
22-
discriminator = dispatch!(variational_circuit(nbit+1, depth_disc, pair_ring(nbit+1)), :random) |> autodiff(:QC)
23-
qg = QuGAN(target_state, generator, discriminator);
24-
25-
# ## TRAINING: Gradient Descent
26-
# using a proper learning parameters, we perform 1000 steps of training
27-
g_learning_rate=0.2
28-
d_learning_rate=0.5
29-
niter=1000
30-
for info in QuGANGo!(qg, g_learning_rate, d_learning_rate, niter)
31-
i = info["step"]
32-
(i*20)%niter==0 && println("Step = $i, Trace Distance = $(tracedist(qg)), loss = $(qg |> loss)")
54+
depth_dis = 4
55+
56+
# define a QuGAN
57+
target = rand_state(nbit)
58+
generator = dispatch!(variational_circuit(nbit, depth_gen), :random)
59+
discriminator = dispatch!(variational_circuit(nbit+1, depth_dis), :random)
60+
qg = QuGAN(target, generator, discriminator)
61+
62+
# check the gradient
63+
grad = gradient(qg)
64+
numgrad = numdiff(c->loss(qg), qg.circuit)
65+
@test isapprox(grad, numgrad, atol=1e-4)
66+
67+
# learning rates for the generator and discriminator
68+
g_lr = 0.2
69+
d_lr = 0.5
70+
for i=1:300
71+
ng = nparameters(qg.generator)
72+
grad = gradient(qg)
73+
dispatch!(-, qg.generator, grad[1:ng]*g_lr)
74+
dispatch!(-, qg.discriminator, -grad[ng+1:end]*d_lr)
75+
println("Step $i, trace distance = $(tracedist(qg))")
3376
end
77+
78+
@test qg |> loss < 0.1

0 commit comments

Comments
 (0)