diff --git a/.gitignore b/.gitignore index 8e512f4..334a91a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.jl.*.cov *.jl.mem +build/ docs/build/ docs/site/ docs/src/tutorial/ diff --git a/Project.toml b/Project.toml index 60d7322..a5f8bbd 100644 --- a/Project.toml +++ b/Project.toml @@ -4,25 +4,19 @@ version = "0.1.0" [deps] BitBasis = "50ba71b6-fa0f-514d-ae9a-0916efc90dcf" -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" -FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -LuxurySparse = "d05aeea4-b7d4-55ac-b691-9e7fabb07ba2" -MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" -SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Yao = "5872b779-8223-5990-8dd0-5abbb0748c8c" YaoArrayRegister = "e600142f-9330-5003-8abb-0ebd767abc51" YaoBlocks = "418bc28f-b43b-5e0b-a6e7-61bbc1a2c1df" +YaoExtensions = "7a06699c-c960-11e9-3c98-9f78548b5f0f" [compat] -julia = ">=1.0.0" Yao = ">=0.4.0" +julia = ">=1.0.0" [extras] -MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" -OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Test", "OrdinaryDiffEq"] +test = ["Test"] diff --git a/README.md b/README.md index 433f5de..9639d1a 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ A curated implementation of quantum algorithms with [Yao.jl](https://github.com/QuantumBFS/Yao.jl) +*Note*: part of functionalities has been moved to [YaoExtensions](https://github.com/QuantumBFS/YaoExtensions.jl). + ## Installation QuAlgorithmZoo.jl is not registered yet, please use the following command: @@ -19,22 +21,26 @@ Disclaimer: **this package is still under development and needs further polish.* ## Contents -- [x] Quantum Circuit Born Machine +- [x] [QFT](https://github.com/QuantumBFS/YaoExtensions.jl) - [x] Grover search -- [x] HHL -- [x] QFT - [x] Phase Estimation -- [x] QuGAN -- [x] QCBM -- [x] Hamiltonian Solver -- [x] QAOA -- [x] Variational quantum eigensolver -- [x] QuODE +- [x] Imaginary Time Evolution Quantum Eigensolver +- [x] Variational Quantum Eigensolver - [x] Hadamard Test - [x] State Overlap Algorithms - [x] Quantum SVD + +In examples folder, you will find + +- [x] HHL +- [x] QAOA +- [x] Quantum Circuit Born Machine +- [x] QuGAN - [x] Shor +- [x] [QuODE](https://github.com/QuantumBFS/QuDiffEq.jl) +- [x] [TensorNetwork Inspired Circuits](https://github.com/GiggleLiu/QuantumPEPS.jl) + ## License QuAlgorithmZoo.jl is released under Apache License 2.0. diff --git a/docs/Project.toml b/docs/Project.toml new file mode 100644 index 0000000..df7e879 --- /dev/null +++ b/docs/Project.toml @@ -0,0 +1,12 @@ +[deps] +BitBasis = "50ba71b6-fa0f-514d-ae9a-0916efc90dcf" +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" +Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c" +KrylovKit = "0b1a1467-8014-51b9-945f-bf0ae24f4b77" +Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" +Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" +Weave = "44d3d7a6-8a23-5bf8-98c5-b353f8df5ec9" +YaoArrayRegister = "e600142f-9330-5003-8abb-0ebd767abc51" +YaoBase = "a8f54c17-34bc-5a9d-b050-f522fe3f755f" +YaoBlocks = "418bc28f-b43b-5e0b-a6e7-61bbc1a2c1df" diff --git a/docs/make.jl b/docs/make.jl index 56e95da..1c709bf 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -6,54 +6,56 @@ add Documenter Literate Plots Yao using Documenter, Literate, QuAlgorithmZoo +const Examples = ["Grover", "VQE", "Shor"] + const PATH = ( tutorial = joinpath(@__DIR__, "src/tutorial"), examples = joinpath(@__DIR__, "..", "examples") ) -function process_literate_scripts(;excludes=["make.jl", "README.md"]) +function process_literate_scripts() TUTORIALS = [] - for (root, dirs, files) in walkdir(PATH.examples) - for file in files - file in excludes && continue - filepath = joinpath(root, file) - Literate.markdown(filepath, PATH.tutorial) - - filename, _ = splitext(file) - mdfile = join([filename, ".md"]) - # TODO: use PATH.tutorial rather then manual path - push!(TUTORIALS, relpath(joinpath("tutorial", mdfile))) - end + for token in Examples + file = "$token.jl" + filepath = joinpath(PATH.examples, token, file) + Literate.markdown(filepath, PATH.tutorial) + + filename, _ = splitext(file) + mdfile = join([filename, ".md"]) + # TODO: use PATH.tutorial rather then manual path + push!(TUTORIALS, relpath(joinpath("tutorial", mdfile))) end TUTORIALS end -const TUTORIALS = process_literate_scripts() - #----------------------------------------------- -makedocs( - modules = [QuAlgorithmZoo], - clean = false, - format = :html, - sitename = "Quantum Algorithm Zoo", - linkcheck = !("skiplinks" in ARGS), - analytics = "UA-89508993-1", - pages = [ - "Home" => "index.md", - "Tutorial" => TUTORIALS, - "Manual" => Any[ - "man/zoo.md", +function generate(islocal::Bool="local" in ARGS) + makedocs( + modules = [QuAlgorithmZoo], + clean = false, + format = :html, + sitename = "Quantum Algorithm Zoo", + linkcheck = !("skiplinks" in ARGS), + analytics = "UA-89508993-1", + pages = [ + "Home" => "index.md", + "Algorithms" => process_literate_scripts(), + "Manual" => Any[ + "man/zoo.md", + ], ], - ], - html_prettyurls = !("local" in ARGS), - html_canonical = "https://quantumbfs.github.io/QuAlgorithmZoo.jl/latest/", -) + html_prettyurls = !islocal, + html_canonical = "https://quantumbfs.github.io/QuAlgorithmZoo.jl/latest/", + ) + + deploydocs( + repo = "github.com/QuantumBFS/QuAlgorithmZoo.jl.git", + target = "build", + julia = "1.0", + deps = nothing, + make = nothing, + ) +end -deploydocs( - repo = "github.com/QuantumBFS/QuAlgorithmZoo.jl.git", - target = "build", - julia = "1.0", - deps = nothing, - make = nothing, -) +generate(true) diff --git a/docs/src/index.md b/docs/src/index.md index 5d4d05b..208ea36 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -9,9 +9,8 @@ A curated implementation of quantum algorithms with [Yao.jl](https://github.com/ ## Tutorial ```@contents Pages = [ - "tutorial/Grover.md", - "tutorial/QCBM.md", - "tutorial/QuGAN.md", + "tutorial/VQE.md", + "tutorial/Shor.md", ] Depth = 1 ``` diff --git a/docs/src/man/zoo.md b/docs/src/man/zoo.md index ff1ede4..672f4fe 100644 --- a/docs/src/man/zoo.md +++ b/docs/src/man/zoo.md @@ -4,3 +4,8 @@ Modules = [QuAlgorithmZoo] Order = [:module, :constant, :type, :macro, :function] ``` + +```@autodocs +Modules = [QuAlgorithmZoo.NumberTheory] +Order = [:module, :constant, :type, :macro, :function] +``` diff --git a/examples/Grover.jl b/examples/Grover.jl deleted file mode 100644 index 891a560..0000000 --- a/examples/Grover.jl +++ /dev/null @@ -1,35 +0,0 @@ -# # Grover Search -using Yao -using LinearAlgebra -using QuAlgorithmZoo: groveriter, inference_oracle, prob_match_oracle - -# ## Target Space and Evidense -num_bit = 12 -oracle = matblock(Diagonal((v = ones(1<<0|U'`. +function grover_step!(reg::AbstractRegister, oracle, U::AbstractBlock) + apply!(reg |> oracle, reflect_circuit(U)) +end + +function reflect_circuit(gen::AbstractBlock{N}) where N + reflect0 = control(N, -collect(1:N-1), N=>-Z) + chain(gen', reflect0, gen) +end + +# Compute the propotion of target states to estimate the number of iterations, +# which requires computing the output state. +function solution_state(oracle, gen::AbstractBlock{N}) where N + reg= zero_state(N) |> gen + reg.state[real.(statevec(ArrayReg(ones(ComplexF64, 1< oracle)) .> 0] .= 0 + normalize!(reg) +end + +function num_grover_step(oracle, gen::AbstractBlock{N}) where N + reg = zero_state(N) |> gen + ratio = abs2(solution_state(oracle, gen)'*reg) + Int(round(pi/4/sqrt(ratio)))-1 +end + +# #### Run +# First, we define the problem by an oracle, it finds bit string `bit"000001100100"`. +num_bit = 12 +oracle = matblock(Diagonal((v = ones(ComplexF64, 1< gen + +target_state = solution_state(oracle, gen) + +for i = 1:num_grover_step(oracle, gen) + grover_step!(reg, oracle, gen) + overlap = abs(reg'*target_state) + println("step $(i-1), overlap = $overlap") +end + +# ## Rejection Sampling +# In practise, it is often not possible to determine the number of iterations before actual running. +# we can use rejection sampling technique to avoid estimating the number of grover steps. + +using Random; Random.seed!(2) #src + +# In a single try, we `apply` the grover algorithm for `nstep` times. +function single_try(oracle, gen::AbstractBlock{N}, nstep::Int; nbatch::Int) where N + reg = zero_state(N+1; nbatch=nshot) + focus!(reg, 1:N) do r + r |> gen + for i = 1:nstep + grover_step!(r, oracle, gen) + end + return r + end + reg |> checker + res = measure_remove!(reg, (N+1)) + return res, reg +end + +# After running the grover search, we have a checker program that flips the ancilla qubit +# if the output is the desired value, we assume the checker program can be implemented in polynomial time. +# to gaurante the output is correct. +# We contruct a checker "program", if the result is correct, flip the ancilla qubit +ctrl = -collect(1:num_bit); ctrl[[3,6,7]] *= -1 +checker = control(num_bit+1,ctrl, num_bit+1=>X) + +# The register is batched, with batch dimension `nshot`. +# [`focus!`](@ref Yao.focus!) views the first 1-N qubts as system. +# For a batched register, [`measure_remove!`](@ref Yao.measure_remove!) +# returns a vector of bitstring as output. + +# #### Run +maxtry = 100 +nshot = 3 + +for nstep = 0:maxtry + println("number of iter = $nstep") + res, reg = single_try(oracle, gen, nstep; nbatch=3) + + ## success! + if any(==(1), res) + overlap_final = viewbatch(reg, findfirst(==(1), res))'*target_state + println("success, overlap = $(overlap_final)") + break + end +end + +# The final state has an overlap of `1` with the target state. + +# ## Amplitude Amplification +# Given a circuit to generate a state, +# now we want to project out the subspace with [1,3,5,8,9,11,12] fixed to 1 and [4,6] fixed to 0. +# We can construct an oracle +evidense = [1, 3, -4, 5, -6, 8, 9, 11, 12] +function inference_oracle(nbit::Int, locs::Vector{Int}) + control(nbit, locs[1:end-1], abs(locs[end]) => (locs[end]>0 ? Z : -Z)) +end +oracle = inference_oracle(nqubits(reg), evidense) + +# We use a variational circuit generator defined in `YaoExtensions` +gen = dispatch!(variational_circuit(num_bit), :random) +reg = zero_state(num_bit) |> gen + +# #### Run +solution = solution_state(oracle, gen) +for i = 1:num_grover_step(oracle, gen) + grover_step!(reg, oracle, gen) + println("step $(i-1), overlap = $(abs(reg'*solution))") +end diff --git a/test/Grover.jl b/examples/Grover/tests.jl similarity index 50% rename from test/Grover.jl rename to examples/Grover/tests.jl index 968808d..a9ba1e0 100644 --- a/test/Grover.jl +++ b/examples/Grover/tests.jl @@ -1,25 +1,23 @@ -using Test, Random, LinearAlgebra, SparseArrays -using BitBasis +include("Grover.jl") +using Test, BitBasis -using QuAlgorithmZoo -import QuAlgorithmZoo: _num_grover_step -using Yao - -function GroverSearch(oracle, num_bit::Int; psi::DefaultRegister = uniform_state(num_bit)) - it = groveriter(psi, oracle) - for l_psi in it psi = l_psi end - return (it.niter, psi) +"""traditional grover search algorithm.""" +function grover_search(oracle::AbstractBlock{N}, gen::AbstractBlock{N}=repeat(N,H,1:N)) where N + reg = zero_state(N) |> gen + for i = 1:num_grover_step(oracle, gen) + grover_step!(reg, oracle, gen) + end + return reg end -function inference(psi::DefaultRegister, evidense::Vector{Int}, num_iter::Int) - oracle = inference_oracle(evidense)(nqubits(psi)) - it = groveriter(psi, oracle) - for l_psi in it psi = l_psi end - it.niter, psi +function grover_circuit(oracle::AbstractBlock{N}, gen::AbstractBlock{N}, niter::Int=num_grover_step(oracle, gen)) where {N} + chain(N, chain(oracle, reflect_circuit(gen)) for i = 1:niter) end +#################### Tests ################## + @testset "oracle" begin - oracle = inference_oracle([2,-1,3])(3) + oracle = inference_oracle(3, [2,-1,3]) # ≈ method for Identity/PermuteMultiply/Sparse # add and mimus between sparse matrices. # alway use sorted CSC format. @@ -32,26 +30,25 @@ end @testset "Grover Search" begin ####### Construct Grover Search Using Reflection Block num_bit = 12 - oracle = inference_oracle(push!(collect(Int, 1:num_bit-1), num_bit))(num_bit) + oracle = inference_oracle(num_bit, push!(collect(Int, 1:num_bit-1), num_bit)) - niter, psi = GroverSearch(oracle, 12) + psi = grover_search(oracle) target_state = zeros(1< gen, gb) == grover_search(or) end @testset "test inference" begin + Random.seed!(2) num_bit = 12 - psi0 = rand_state(num_bit) + gen = dispatch!(variational_circuit(num_bit), :random) + psi0 = zero_state(num_bit) |> gen #psi0 = uniform_state(num_bit) evidense = [1, 2, 3, 4, 5, 6, 7, 8, 9] #evidense = collect(1:num_bit) @@ -65,7 +62,6 @@ end v_desired[:] ./= sqrt(p) # search the subspace - num_iter = _num_grover_step(p) - niter, psi = inference(psi0, evidense, num_iter) + psi = grover_search(inference_oracle(num_bit, evidense), gen) @test isapprox((psi.state[subinds .+ 1]'*v_desired) |> abs2, 1, atol=3e-2) end diff --git a/test/HHL.jl b/examples/HHL/HHL.jl similarity index 96% rename from test/HHL.jl rename to examples/HHL/HHL.jl index 287c9c0..27822ef 100644 --- a/test/HHL.jl +++ b/examples/HHL/HHL.jl @@ -1,7 +1,10 @@ using Yao using BitBasis -using QuAlgorithmZoo +using YaoArrayRegister using Test, LinearAlgebra +using QuAlgorithmZoo: PEBlock + +include("HHLlib.jl") function crot(n_reg::Int, C_value::Real) n_rot = n_reg + 1 diff --git a/src/HHL.jl b/examples/HHL/HHLlib.jl similarity index 94% rename from src/HHL.jl rename to examples/HHL/HHLlib.jl index c364fe8..a4318ff 100644 --- a/src/HHL.jl +++ b/examples/HHL/HHLlib.jl @@ -22,7 +22,7 @@ end a, -b, b, a end -function apply!(reg::ArrayReg, hr::HHLCRot{N, NC, T}) where {N, NC, T} +function Yao.apply!(reg::ArrayReg, hr::HHLCRot{N, NC, T}) where {N, NC, T} mask = bmask(hr.ibit) step = 1<<(hr.ibit-1) step_2 = step*2 @@ -32,7 +32,7 @@ function apply!(reg::ArrayReg, hr::HHLCRot{N, NC, T}) where {N, NC, T} λ = bfloat(readbit(i-1, hr.cbits...), nbits=nbit-1) if λ >= hr.C_value u = hhlrotmat(λ, hr.C_value) - u1rows!(state(reg), i, i+step, u...) + YaoArrayRegister.u1rows!(state(reg), i, i+step, u...) end end end diff --git a/test/lin_diffEq_test.jl b/examples/HHL/lin_diffEq_HHL.jl similarity index 100% rename from test/lin_diffEq_test.jl rename to examples/HHL/lin_diffEq_HHL.jl diff --git a/src/lin_diffEq_HHL.jl b/examples/HHL/lin_diffEq_HHLlib.jl similarity index 100% rename from src/lin_diffEq_HHL.jl rename to examples/HHL/lin_diffEq_HHLlib.jl diff --git a/examples/QAOA.jl b/examples/QAOA/QAOA.jl similarity index 100% rename from examples/QAOA.jl rename to examples/QAOA/QAOA.jl diff --git a/examples/maxcut_gw.jl b/examples/QAOA/maxcut_gw.jl similarity index 100% rename from examples/maxcut_gw.jl rename to examples/QAOA/maxcut_gw.jl diff --git a/src/Kernels.jl b/examples/QCBM/Kernels.jl similarity index 100% rename from src/Kernels.jl rename to examples/QCBM/Kernels.jl diff --git a/examples/QCBM.jl b/examples/QCBM/QCBM.jl similarity index 62% rename from examples/QCBM.jl rename to examples/QCBM/QCBM.jl index cb2e408..c6ef9ff 100644 --- a/examples/QCBM.jl +++ b/examples/QCBM/QCBM.jl @@ -1,19 +1,11 @@ # # Quantum Circuit Born Machine -using Yao -using QuAlgorithmZoo +using Yao, YaoExtensions +import QuAlgorithmZoo +include("qcbmlib.jl") # ## DATA: Target Probability Distribution # The gaussian probability disctribution in phase space of 2^6 -""" - gaussian_pdf(x, μ::Real, σ::Real) - -gaussian probability density function. -""" -function gaussian_pdf(x, μ::Real, σ::Real) - pl = @. 1 / sqrt(2pi * σ^2) * exp(-(x - μ)^2 / (2 * σ^2)) - pl / sum(pl) -end nbit = 6 N = 1< autodiff(:QC); -dispatch!(circuit, :random) -qcbm = QCBM(circuit, kernel, pg); +c = variational_circuit(nbit, depth, pair_ring(nbit)) |> autodiff(:QC); +dispatch!(c, :random) +qcbm = QCBM(c, kernel, pg); # ## TRAINING: Adam Optimizer # We probide the QCBMGo! iterative interface for training diff --git a/src/QCBM.jl b/examples/QCBM/qcbmlib.jl similarity index 71% rename from src/QCBM.jl rename to examples/QCBM/qcbmlib.jl index 51bd947..79a5620 100644 --- a/src/QCBM.jl +++ b/examples/QCBM/qcbmlib.jl @@ -4,7 +4,7 @@ export QCBM, QCBMGo!, psi, mmdgrad include("Kernels.jl") ##### QCBM methods ##### -struct QCBM{BT<:AbstractBlock, KT<:AbstractKernel} <: QCOptProblem +struct QCBM{BT<:AbstractBlock, KT<:AbstractKernel} circuit::BT kernel::KT ptrain::Vector{Float64} @@ -53,7 +53,7 @@ end """ quantum circuit born machine trainer. """ -struct QCBMGo!{QT<:QCBM, OT} <: QCOptGo!{QT} +struct QCBMGo!{QT<:QCBM, OT} qcbm::QT optimizer::OT niter::Int @@ -67,7 +67,36 @@ function Base.iterate(qo::QCBMGo!, state=(1, parameters(qo.qcbm.circuit))) # initialize the parameters p0 = qo.qcbm |> probs grad = gradient(qo.qcbm, p0) - update!(state[2], grad, qo.optimizer) + QuAlgorithmZoo.update!(state[2], grad, qo.optimizer) dispatch!(qo.qcbm.circuit, state[2]) Dict("probs"=>p0, "step"=>state[1], "gradient"=>grad), (state[1]+1, state[2]) end + +""" + gaussian_pdf(x, μ::Real, σ::Real) + +gaussian probability density function. +""" +function gaussian_pdf(x, μ::Real, σ::Real) + pl = @. 1 / sqrt(2pi * σ^2) * exp(-(x - μ)^2 / (2 * σ^2)) + pl / sum(pl) +end + +@testset "qcbm" begin + # problem setup + n = 6 + depth = 6 + + N = 1< autodiff(:QC) + dispatch!(circuit, :random) + qcbm = QCBM(circuit, kernel, pg) + + # training + niter = 100 + optim = QuAlgorithmZoo.Adam(lr=0.1) + for info in QCBMGo!(qcbm, optim, niter) end + @test qcbm |> loss < 1e-4 +end diff --git a/examples/QuGAN.jl b/examples/QuGAN/QuGAN.jl similarity index 77% rename from examples/QuGAN.jl rename to examples/QuGAN/QuGAN.jl index e06aaab..5ec7795 100644 --- a/examples/QuGAN.jl +++ b/examples/QuGAN/QuGAN.jl @@ -1,6 +1,10 @@ # # Quantum GAN -using Yao -using QuAlgorithmZoo +using Yao, YaoExtensions +using Yao.ConstGate: P0 +import QuAlgorithmZoo +using Test, Random + +include("QuGANlib.jl") # ## DATA: Target Wave Function # here we learn a 3 qubit state @@ -11,11 +15,11 @@ target_state = rand_state(nbit) # using a 4-layer random differential circuit for both generator and discriminator # we build the qcgan setup. depth_gen = 4 -generator = dispatch!(random_diff_circuit(nbit, depth_gen, pair_ring(nbit)), :random) |> autodiff(:QC); +generator = dispatch!(variational_circuit(nbit, depth_gen, pair_ring(nbit)), :random) |> autodiff(:QC); #------------------------------ depth_disc = 4 -discriminator = dispatch!(random_diff_circuit(nbit+1, depth_disc, pair_ring(nbit+1)), :random) |> autodiff(:QC) +discriminator = dispatch!(variational_circuit(nbit+1, depth_disc, pair_ring(nbit+1)), :random) |> autodiff(:QC) qg = QuGAN(target_state, generator, discriminator); # ## TRAINING: Gradient Descent diff --git a/src/QuGAN.jl b/examples/QuGAN/QuGANlib.jl similarity index 71% rename from src/QuGAN.jl rename to examples/QuGAN/QuGANlib.jl index 26d3049..1d1aaae 100644 --- a/src/QuGAN.jl +++ b/examples/QuGAN/QuGANlib.jl @@ -1,4 +1,3 @@ -using MacroTools: @forward import Yao: tracedist export QuGAN, psi, toy_qugan, QuGANGo! @@ -9,7 +8,7 @@ Quantum GAN. Reference: Benedetti, M., Grant, E., Wossnig, L., & Severini, S. (2018). Adversarial quantum circuit learning for pure state approximation, 1–14. """ -struct QuGAN{N} <: QCOptProblem +struct QuGAN{N} target::ArrayReg generator::AbstractBlock{N} discriminator::AbstractBlock @@ -60,8 +59,8 @@ Construct a toy qugan. """ function toy_qugan(target::ArrayReg, depth_gen::Int, depth_disc::Int) n = nqubits(target) - generator = dispatch!(random_diff_circuit(n, depth_gen, pair_ring(n)), :random) |> autodiff(:QC) - discriminator = dispatch!(random_diff_circuit(n+1, depth_disc, pair_ring(n+1)), :random) |> autodiff(:QC) + generator = dispatch!(variational_circuit(n, depth_gen, pair_ring(n)), :random) |> autodiff(:QC) + discriminator = dispatch!(variational_circuit(n+1, depth_disc, pair_ring(n+1)), :random) |> autodiff(:QC) return QuGAN(target, generator, discriminator) end @@ -73,7 +72,7 @@ Iterative training of quantum generative optimization problem, QT is the type of quantum optimization problem, OT is the optimizer/learning_rate parameter type. """ -struct QuGANGo!{QT<:QuGAN, OT} <: QCOptGo!{QT} +struct QuGANGo!{QT<:QuGAN, OT} qop::QT goptim::OT doptim::OT @@ -93,13 +92,35 @@ function Base.iterate(qgg::QuGANGo!{<:Any, <:Real}, state=1) Dict("step"=>state,"gradient"=>grad), state+1 end -function Base.iterate(qgg::QuGANGo!{<:Any, <:Adam}, state=(1, parameters(qgg.qop.generator), parameters(qgg.qop.discriminator))) +function Base.iterate(qgg::QuGANGo!{<:Any, <:QuAlgorithmZoo.Adam}, state=(1, parameters(qgg.qop.generator), parameters(qgg.qop.discriminator))) state[1] > qgg.niter && return nothing qg = qgg.qop ng = length(qg.gdiffs) grad = gradient(qg) - dispatch!(qg.generator, update!(state[2], grad[1:ng], qgg.goptim)) - dispatch!(qg.discriminator, update!(state[3], -grad[ng+1:end], qgg.doptim)) + dispatch!(qg.generator, QuAlgorithmZoo.update!(state[2], grad[1:ng], qgg.goptim)) + dispatch!(qg.discriminator, QuAlgorithmZoo.update!(state[3], -grad[ng+1:end], qgg.doptim)) Dict("step"=>state[1], "gradient"=>grad), (state[1]+1, state[2], state[3]) end + +function run_test(nbit::Int, depth_gen::Int, depth_disc::Int; g_lr=0.1, d_lr=0.2, niter=1000) + qg = toy_qugan(rand_state(nbit), depth_gen, depth_disc) + for info in QuGANGo!(qg, g_lr, d_lr, niter) end + qg +end + +num_gradient(qop::QuGAN) = numdiff.(()->loss(qop), qop |> diff_blocks) + +# to fix +@testset "quantum circuit gan - opdiff" begin + Random.seed!(2) + N = 3 + target = rand_state(N) + qcg = toy_qugan(target, 2, 2) + grad = gradient(qcg) + @test isapprox(grad, num_gradient(qcg), atol=1e-4) + qg = run_test(3, 4, 4, g_lr=0.2, d_lr=0.5, niter=300) + @test qg |> loss < 0.1 + qg = run_test(3, 4, 4, g_lr=QuAlgorithmZoo.Adam(lr=0.005), d_lr=QuAlgorithmZoo.Adam(lr=0.5), niter=1000) + @test qg |> loss < 0.1 +end diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index 2a27f34..0000000 --- a/examples/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Quantum Algorithm Zoo - -This folder contains the examples of the quantum algorithms implemented in the Zoo -in jupyter notebook form. - -## Usage - -1. Install IJulia for jupyter notebook kernels - -```julia -pkg> add IJulia -``` - -If you have IJulia installed. - -```julia -julia> using IJulia - -julia> notebook() -``` diff --git a/examples/Shor/Shor.jl b/examples/Shor/Shor.jl new file mode 100644 index 0000000..bcf8294 --- /dev/null +++ b/examples/Shor/Shor.jl @@ -0,0 +1,125 @@ +# # [Shor's Algorithm](@id Shor) + +# ## References +# * [Neilsen](https://aapt.scitation.org/doi/abs/10.1119/1.1463744?journalCode=ajp) +# * [An Insightful Blog](https://algassert.com/post/1718) + +# ## Main Program +# The main program of a Shor's algorithm can be summrized in several lines of code. +# For the theory part, please refer the reference materials above. +# It factorize an integer `L`, and returns one of the factors. +# Here, the input `ver` can be either `Val(:quantum)` or `Val(:classical)`, +# where the classical version is for comparison. + +using Yao, BitBasis +using YaoExtensions: KMod, QFTCircuit +using QuAlgorithmZoo: NumberTheory + +function shor(L::Int, ver=Val(:quantum); maxtry=100) + L%2 == 0 && return 2 + + ## find short cut solutions like `a^b` + res = NumberTheory.factor_a_power_b(L) + res !== nothing && return res[1] + + for i in 1:maxtry + ## step 1 + x = NumberTheory.rand_primeto(L) + + ## step 2 + r = get_order(ver, x, L; ) + if r%2 == 0 && powermod(x, r÷2, L) != L-1 + ## step 3 + f1, f2 = gcd(powermod(x, r÷2, L)-1, L), gcd(powermod(x, r÷2, L)+1, L) + if f1!=1 + return f1 + elseif f2!=1 + return f2 + else + error("Algorithm Fail!") + end + end + end +end + +# Except some shortcuts, in each try, the main program can be summarized in several steps +# 1. randomly pick a number that prime to the input numebr `L`, i.e. `gcd(x, L) = 1`. +# The complexity of this algorithm is polynoial. +# 2. get the order `x`, i.e. finding a number `r` that satisfies `mod(x^r, L) = 1`. +# If `r` is even and `x^(r÷2)` is non-trivil, go on, otherwise start another try. +# Here, trivil means equal to `L-1 (mod L)`. +# 3. According to Theorem 5.2 in Neilsen book, +# one of `gcd(x^(r÷2)-1, L)` and `gcd(x^(r÷2)+1, L)` must be a non-trivil (`!=1`) factor of `L`. +# Notice `powermod(x, r÷2, L)` must be `-1` rather than `1`, +# otherwise the order should be `r/2` according to definition. + +# The only difference between classical and quantum version is the order finding algorithm. + +# ## Order Finding +# We provided a classical order finding algorithm in `NumberTheory`, +# here we focus on the quantum version. +# The algorithm is consisted +# 1. run the circuit to get a bitstring, +# 2. interpret this bitstring in output register as a rational number `s/r`. +# To achieve this, we first interpret it as a floating point number, +# then the continued fraction algorithm can find the best match for us. +# +# When using the quantum version, we have the flexibility to set key word arguments `nshot`, +# `nbit` (size of input data register) and `ncbit` (size of control register, or output register). +# `nbit` can be simply chosen as the minimum register size to store input, +# while `ncbit` can be estimated with the following function +"""estimate the required size of the output register.""" +estimate_ncbit(nbit::Int, ϵ::Real) = 2*nbit + 1 + ceil(Int,log2(2+1/2ϵ)) + +get_order(::Val{:classical}, x::Int, L::Int; kwargs...) = NumberTheory.find_order(x, L) +function get_order(::Val{:quantum}, x::Int, L::Int; nshots::Int=10, + nbit::Int=bit_length(L-1), ncbit::Int=estimate_ncbit(nbit, 0.25)) + c = order_finding_circuit(x, L; nbit=nbit, ncbit=ncbit) + reg = join(product_state(nbit, 1), zero_state(ncbit)) + + res = measure(copy(reg) |> c; nshots=nshots) + for r in res + ## split bit string b into lower bits `k` and higher bits `r`. + mask = bmask(1:ncbit) + k,i = r&mask, r>>ncbit + ## get s/r + ϕ = bfloat(k) # + ϕ == 0 && continue + + ## order_from_float: given a floating point number, + ## return the closest rational number with bounded number of continued fraction steps. + order = NumberTheory.order_from_float(ϕ, x, L) + if order === nothing + continue + else + return order + end + end + return nothing +end + +# #### The circuit used for finding order +""" + order_finding_circuit(x::Int, L::Int; nbit::Int=bit_length(L-1), ncbit::Int=estimate_ncbit(nbit, 0.25)) -> AbstractBlock + +Returns the circuit for finding the order of `x` to `L`, +feeding input `|1>⊗|0>` will get the resulting quantum register with the desired "phase" information. +""" +function order_finding_circuit(x::Int, L::Int; nbit::Int, ncbit::Int) + N = nbit+ncbit + chain(N, repeat(N, H, 1:ncbit), KMod{N, ncbit}(x, L), + concentrate(N, QFTCircuit(ncbit)', 1:ncbit)) +end + +# The circuit for order finding is consisted of three parts +# 1. Hadamard gates, +# 2. `KMod` that computes a classical function `mod(a^k*x, L)`. +# `k` is the integer stored in first `K` (or `ncbit`) qubits and the rest `N-K` qubits stores `a`. +# Notice it is not a basic gate, it should have been compiled to multiple gates, which is not implemented in `Yao` for the moment. +# To learn more about implementing arithmatics on a quantum circuit, please read [this paper](https://arxiv.org/abs/1805.12445). +# 3. Inverse quantum fourier transformation. + +# ## Run +# Factorizing `15`, you should see `3` or `5`, please report a bug if it is not... +using Random; Random.seed!(129) #src +shor(15, Val(:quantum)) diff --git a/test/shor.jl b/examples/Shor/tests.jl similarity index 52% rename from test/shor.jl rename to examples/Shor/tests.jl index b909d26..8c0c104 100644 --- a/test/shor.jl +++ b/examples/Shor/tests.jl @@ -1,10 +1,9 @@ -using Test, QuAlgorithmZoo, Yao -using Random -using QuAlgorithmZoo.NumberTheory +include("Shor.jl") +using Test """Euler theorem states that the order is a devisor of Eulerφ (or the size of Z* group of `N`)""" function check_Euler_theorem(N::Int) - Z = Z_star(N) + Z = NumberTheory.Z_star(N) Nz = length(Z) # Eulerφ for x in Z @test powermod(x,Nz,N) == 1 # the order is a devisor of Eulerφ @@ -15,26 +14,6 @@ end check_Euler_theorem(150) end -@testset "Mod" begin - @test_throws AssertionError Mod{4}(4,10) - @test_throws AssertionError Mod{2}(3,10) - m = Mod{4}(3,10) - @test mat(m) ≈ applymatrix(m) - @test isunitary(m) - @test isunitary(mat(m)) - @test m' == Mod{4}(7,10) -end - -@testset "KMod" begin - @test_throws AssertionError KMod{6, 2}(4,10) - @test_throws AssertionError KMod{4, 2}(3,10) - m = KMod{6, 2}(3,10) - @test mat(m) ≈ applymatrix(m) - @test isunitary(m) - @test isunitary(mat(m)) - @test m' == KMod{6, 2}(7,10) -end - @testset "shor_classical" begin Random.seed!(129) L = 35 @@ -53,8 +32,8 @@ end f = shor(L, Val(:classical)) @test f == 2 || f == 7 - @test factor_a_power_b(25) == (5, 2) - @test factor_a_power_b(15) == nothing + @test NumberTheory.factor_a_power_b(25) == (5, 2) + @test NumberTheory.factor_a_power_b(15) == nothing end @testset "shor quantum" begin diff --git a/examples/VQE.jl b/examples/VQE.jl deleted file mode 100644 index f6f4df2..0000000 --- a/examples/VQE.jl +++ /dev/null @@ -1,17 +0,0 @@ -using Yao -using QuAlgorithmZoo -using KrylovKit - -function ed_groundstate(h::AbstractBlock) - E, V = eigsolve(h |> mat, 1, :SR, ishermitian=true) - println("Ground State Energy is $(E[1])") - ArrayReg(V[1]) -end - -N = 5 -c = random_diff_circuit(N, N, [i=>mod(i,N)+1 for i=1:N], mode=:Merged) |> autodiff(:QC) -dispatch!(c, :random) -hami = heisenberg(N) - -# vqe ground state -vqe_solve!(c, hami) diff --git a/examples/VQE/H2.jl b/examples/VQE/H2.jl new file mode 100644 index 0000000..604a7d8 --- /dev/null +++ b/examples/VQE/H2.jl @@ -0,0 +1,40 @@ +using Yao + +using YaoExtensions + +# arXiv: 1704.05018, table S2 +function hydrogen_hamiltonian() + Z1 = put(2,1=>Z) + Z2 = put(2,2=>Z) + X1 = put(2,1=>X) + X2 = put(2,2=>X) + 0.011280*Z1*Z2 + 0.397936*Z1 + 0.397936*Z2 + 0.180931*X1*X2 +end + +function get_gradient(circ, hamiltonian) + ψ = zero_state(2) |> circ + dψ = copy(ψ) |> hamiltonian + backward!((copy(ψ), dψ), circ) + gradient(circ) +end + +using Flux: Optimise +function train!(circ, hamiltonian; optimizer, niter::Int=100) + circ = circ |> autodiff(:BP) + params = parameters(circ) + dispatch!(circ, :random) + for i=1:niter + Optimise.update!(optimizer, params, get_gradient(circ, hamiltonian)) + dispatch!(circ, params) + println("Energy = $(expect(hamiltonian, zero_state(nqubits(h)) |> circ))") + end + return expect(hamiltonian, zero_state(nqubits(h)) |> circ) +end + +h = hydrogen_hamiltonian() +c = variational_circuit(2) +emin_vqe = train!(c, h; optimizer=Optimise.ADAM(0.1)) + +using LinearAlgebra +emin = eigvals(Matrix(mat(h)))[1] +@assert isapprox(emin, emin, atol=1e-1) diff --git a/examples/VQE/README.md b/examples/VQE/README.md new file mode 100644 index 0000000..3ab48ae --- /dev/null +++ b/examples/VQE/README.md @@ -0,0 +1,14 @@ +# Variational Quantum Eigensolver + +## Start + +1. install [Julia 1.1](https://julialang.org/downloads/) +2. type `]` in julia REPL to enter `pkg` mode, and install packages with +```julia +pkg> add Yao KrylovKit +pkg> dev git@github.com:QuantumBFS/YaoExtensions.jl.git +``` +3. run H2 example with +```bash +julia examples/VQE/H2.jl +``` diff --git a/examples/VQE/VQE.jl b/examples/VQE/VQE.jl new file mode 100644 index 0000000..0d27a58 --- /dev/null +++ b/examples/VQE/VQE.jl @@ -0,0 +1,64 @@ +# # [Variational Quantum Eigensolver](@id VQE) + +# ## References +# * [A variational eigenvalue solver on a quantum processor](https://arxiv.org/abs/1304.3061) +# * [Variational Quantum Eigensolver with Fewer Qubits](https://arxiv.org/abs/1902.02663) + +# ## Define a hamiltonian + +# construct a 5-site heisenberg hamiltonian + +using Yao, YaoExtensions + +N = 5 +hami = heisenberg(N) + +# The ground state can be obtained by a sparse matrix ground state solver. +# The high performance `mat` function in `Yao.jl` makes computation time lower than `10s` +# to construct a `20` site Heisenberg hamltonian +using KrylovKit: eigsolve + +function ed_groundstate(h::AbstractBlock) + E, V = eigsolve(h |> mat, 1, :SR, ishermitian=true) + E[1], V[1] +end + +ed_groundstate(hami) + +# Here we use the `heisenberg` hamiltonian that defined in [`YaoExtensions.jl`](https://github.com/QuantumBFS/YaoExtensions.jl), +# for tutorial purpose, we pasted the code for construction here. +# ```julia +# function heisenberg(nbit::Int; periodic::Bool=true) +# sx = i->put(nbit, i=>X) +# sy = i->put(nbit, i=>Y) +# sz = i->put(nbit, i=>Z) +# map(1:(periodic ? nbit : nbit-1)) do i +# j=i%nbit+1 +# sx(i)*sx(j)+sy(i)*sy(j)+sz(i)*sz(j) +# end |> sum +# end +# ``` + +# ## Define an ansatz +# As an ansatz, we use the canonical circuit for demonstration [`variational_circuit`](@ref YaoExtensions.variational_circuit) +# defined in [`YaoExtensions.jl`](https://github.com/QuantumBFS/YaoExtensions.jl). +c = variational_circuit(N) +dispatch!(c, :random) + +# ## Run +# Use the [`Adam`](@ref) optimizer for parameter optimization, +# we provide a poorman's implementation in `QuAlgorithmZoo` +using QuAlgorithmZoo: Adam, update! + +optimizer = Adam(lr=0.01) +params = parameters(c) +niter = 100 + +for i = 1:niter + ## `expect'` gives the gradient of an observable. + grad_input, grad_params = expect'(hami, zero_state(N) => c) + + ## feed the gradients into the circuit. + dispatch!(c, update!(params, grad_params, optimizer)) + println("Step $i, Energy = $(expect(hami, zero_state(N) |> c))") +end diff --git a/examples/run_examples.jl b/examples/run_examples.jl new file mode 100644 index 0000000..222510d --- /dev/null +++ b/examples/run_examples.jl @@ -0,0 +1,9 @@ +# run this file to make sure all examples work +# Note: running all these examples are too heavy for CI. +include("../examples/Grover/Grover.jl") +include("../examples/QAOA/QAOA.jl") +include("../examples/HHL/HHL.jl") +include("../examples/QCBM/QCBM.jl") +include("../examples/QuGAN/QuGAN.jl") +include("../examples/Shor/Shor.jl") +include("../examples/VQE/VQE.jl") diff --git a/src/CircuitBuild.jl b/src/CircuitBuild.jl deleted file mode 100644 index 86808c9..0000000 --- a/src/CircuitBuild.jl +++ /dev/null @@ -1,140 +0,0 @@ -using StatsBase: sample - -export pair_ring, pair_square, cnot_entangler -export rotor, merged_rotor, rotorset -export random_diff_circuit -export rand_single_gate, rand_gate, rand_circuit - -################## Entangler ################### -""" - pair_ring(n::Int) -> Vector - -Pair ring. -""" -pair_ring(n::Int) = [i=>mod(i, n)+1 for i=1:n] - -""" - pair_square(m::Int, n::Int) -> Vector - -Pair square. -""" -function pair_square(m::Int, n::Int) - nsite = m*n - res = Vector{Pair{Int, Int}}(undef, 2*nsite) - li = LinearIndices((m, n)) - k = 1 - for i = 1:2:m, j=1:n - res[k] = li[i, j] => li[i%m+1, j] - k+=1 - end - for i = 2:2:m, j=1:n - res[k] = li[i, j] => li[i%m+1, j] - k+=1 - end - for i = 1:m, j=1:2:n - res[k] = li[i, j] => li[i, j%n+1] - k+=1 - end - for i = 1:m, j=2:2:n - res[k] = li[i, j] => li[i, j%n+1] - k+=1 - end - res -end - -""" - cnot_entangler([n::Int, ] pairs::Vector{Pair}) = ChainBlock - -Arbitrary rotation unit, support lazy construction. -""" -cnot_entangler(n::Int, pairs) = chain(n, control(n, [ctrl], target=>X) for (ctrl, target) in pairs) -cnot_entangler(pairs) = n->cnot_entangler(n, pairs) - -###################### rotor and rotorset ##################### -""" - merged_rotor(noleading::Bool=false, notrailing::Bool=false) -> ChainBlock{1, ComplexF64} - -Single qubit arbitrary rotation unit, set parameters notrailing, noleading true to remove trailing and leading Z gates. - -!!! note - - Here, `merged` means `Rz(η)⋅Rx(θ)⋅Rz(ξ)` are multiplied first, this kind of operation if now allowed in differentiable - circuit with back-propagation (`:BP`) mode (just because we are lazy to implement it!). - But is a welcoming component in quantum differentiation. -""" -merged_rotor(noleading::Bool=false, notrailing::Bool=false) = noleading ? (notrailing ? Rx(0) : chain(Rx(0), Rz(0))) : (notrailing ? chain(Rz(0), Rx(0)) : chain(Rz(0), Rx(0), Rz(0))) - -""" - rotor(nbit::Int, ibit::Int, noleading::Bool=false, notrailing::Bool=false) -> ChainBlock{nbit, ComplexF64} - -Arbitrary rotation unit (put in `nbit` space), set parameters notrailing, noleading true to remove trailing and leading Z gates. -""" -function rotor(nbit::Int, ibit::Int, noleading::Bool=false, notrailing::Bool=false) - rt = chain(nbit, [put(nbit, ibit=>Rz(0.0)), put(nbit, ibit=>Rx(0.0)), put(nbit, ibit=>Rz(0.0))]) - noleading && popfirst!(rt) - notrailing && pop!(rt) - rt -end - -rotorset(::Val{:Merged}, nbit::Int, noleading::Bool=false, notrailing::Bool=false) = chain(nbit, [put(nbit, j=>merged_rotor(noleading, notrailing)) for j=1:nbit]) -rotorset(::Val{:Split}, nbit::Int, noleading::Bool=false, notrailing::Bool=false) = chain(nbit, [rotor(nbit, j, noleading, notrailing) for j=1:nbit]) -rotorset(mode::Symbol, nbit::Int, noleading::Bool=false, notrailing::Bool=false) = rotorset(Val(mode), nbit, noleading, notrailing) - -""" - random_diff_circuit(nbit, nlayer, pairs; mode=:Split, do_cache=false) - -A kind of widely used differentiable quantum circuit, angles in the circuit is randomely initialized. - -ref: - 1. Kandala, A., Mezzacapo, A., Temme, K., Takita, M., Chow, J. M., & Gambetta, J. M. (2017). - Hardware-efficient Quantum Optimizer for Small Molecules and Quantum Magnets. Nature Publishing Group, 549(7671), 242–246. - https://doi.org/10.1038/nature23879. -""" -function random_diff_circuit(nbit, nlayer, pairs; mode=:Split, do_cache=false) - circuit = chain(nbit) - - ent = cnot_entangler(pairs) - if do_cache - ent = ent |> cache - end - for i = 1:(nlayer + 1) - i!=1 && push!(circuit, ent) - push!(circuit, rotorset(mode, nbit, i==1, i==nlayer+1)) - end - circuit -end - -############### Completely random circuits (for testing and demo) ################ -randlocs(nbit::Int, mbit::Int) = sample(1:nbit, mbit, replace=false) -const SINGLE_GATES = [X, Y, Z, H, Rx, Ry, Rz, shift, phase] - -rand_single_gate(ngate::Int) = [rand_single_gates() for i=1:ngate] -function rand_single_gate() - gate = rand(SINGLE_GATES) - gate isa AbstractBlock ? gate : gate(rand()*2π) -end - -""" - rand_gate(nbit::Int, mbit::Int, [ngate::Int]) -> AbstractBlock - -random nbit gate. -""" -rand_gate(nbit::Int, mbit::Int) = rand_gate(nbit, Val(mbit)) -rand_gate(nbit::Int, mbit::Int, ngate::Int) = [rand_gate(nbit, mbit) for i=1:ngate] -rand_gate(nbit::Int, ::Val{1}) = put(nbit, rand(1:nbit)=>rand_single_gate()) -function rand_gate(nbit::Int, ::Val{M}) where M - locs = randlocs(nbit, M) - control(nbit, locs[1:M-1], last(locs)=>rand_single_gate()) -end - -function rand_circuit(nbit::Int; p1 = (nbit==1 ? 1.0 : 0.66), ngate=5*nbit) - c = chain(nbit) - for i=1:ngate - if rand() < p1 - push!(c, rand_gate(nbit, 1)) - else - push!(c, rand_gate(nbit, 2)) - end - end - c -end diff --git a/src/Diff.jl b/src/Diff.jl deleted file mode 100644 index f54a895..0000000 --- a/src/Diff.jl +++ /dev/null @@ -1,220 +0,0 @@ -export Rotor, generator, Diff, backward!, gradient, CPhaseGate, DiffBlock -import Yao: expect, content, chcontent, mat, apply! -using StatsBase - -############# General Rotor ############ -const Rotor{N, T} = Union{RotationGate{N, T}, PutBlock{N, <:Any, <:RotationGate{<:Any, T}}} -const CphaseGate{N, T} = ControlBlock{N,<:ShiftGate{T},<:Any} -const DiffBlock{N, T} = Union{Rotor{N, T}, CphaseGate{N, T}} -""" - generator(rot::Rotor) -> AbstractBlock - -Return the generator of rotation block. -""" -generator(rot::RotationGate) = rot.block -generator(rot::PutBlock{N, C, GT}) where {N, C, GT<:RotationGate} = PutBlock{N}(generator(rot|>content), rot |> occupied_locs) -generator(c::CphaseGate{N}) where N = ControlBlock{N}(c.ctrl_locs, c.ctrl_config, Z, c.locs) - -#################### The Basic Diff ################# -""" - Diff{GT, N, T} <: TagBlock{GT, N} - Diff(block) -> Diff - -Mark a block as quantum differentiable. -""" -mutable struct Diff{GT, N, T} <: TagBlock{GT, N} - block::GT - grad::T - Diff(block::DiffBlock{N, T}) where {N, T} = new{typeof(block), N, T}(block, T(0)) -end -content(cb::Diff) = cb.block -chcontent(cb::Diff, blk::DiffBlock) = Diff(blk) - -istraitkeeper(::Diff) = Val(true) - -@forward Diff.block apply! -mat(::Type{T}, df::Diff) where T = mat(T, df.block) -Base.adjoint(df::Diff) = chcontent(df, content(df)') - -function YaoBlocks.print_annotation(io::IO, df::Diff) - printstyled(io, "[∂] "; bold=true, color=:yellow) -end - -#### interface ##### -export autodiff, numdiff, opdiff, StatFunctional, statdiff, as_weights - -as_weights(probs::AbstractVector{T}) where T = Weights(probs, T(1)) -""" - autodiff(mode::Symbol, block::AbstractBlock) -> AbstractBlock - autodiff(mode::Symbol) -> Function - -automatically mark differentiable items in a block tree as differentiable. -""" -function autodiff end -autodiff(mode::Symbol) = block->autodiff(mode, block) -autodiff(mode::Symbol, block::AbstractBlock) = autodiff(Val(mode), block) - -# for BP -autodiff(::Val{:BP}, block::DiffBlock) = Diff(block) -autodiff(::Val{:BP}, block::AbstractBlock) = block -# Sequential, Roller and ChainBlock can propagate. -function autodiff(mode::Val{:BP}, blk::Union{ChainBlock, Sequential}) - chsubblocks(blk, autodiff.(mode, subblocks(blk))) -end - -# for QC -autodiff(::Val{:QC}, block::Union{RotationGate, CphaseGate}) = Diff(block) -# escape control blocks. -autodiff(::Val{:QC}, block::ControlBlock) = block - -function autodiff(mode::Val{:QC}, blk::AbstractBlock) - blks = subblocks(blk) - isempty(blks) ? blk : chsubblocks(blk, autodiff.(mode, blks)) -end - -@inline function _perturb(func, gate::Diff{<:DiffBlock}, δ::Real) - dispatch!(-, gate, (δ,)) - r1 = func() - dispatch!(+, gate, (2δ,)) - r2 = func() - dispatch!(-, gate, (δ,)) - r1, r2 -end - -@inline function _perturb(func, gate::Diff{<:Rotor}, δ::Real) # for put - dispatch!(-, gate, (δ,)) - r1 = func() - dispatch!(+, gate, (2δ,)) - r2 = func() - dispatch!(-, gate, (δ,)) - r1, r2 -end - -""" - numdiff(loss, diffblock::Diff; δ::Real=1e-2) - -Numeric differentiation. -""" -@inline function numdiff(loss, diffblock::Diff; δ::Real=1e-2) - r1, r2 = _perturb(loss, diffblock, δ) - diffblock.grad = (r2 - r1)/2δ -end - -""" - opdiff(psifunc, diffblock::Diff, op::AbstractBlock) - -Operator differentiation. -""" -@inline function opdiff(psifunc, diffblock::Diff, op::AbstractBlock) - r1, r2 = _perturb(()->expect(op, psifunc()) |> real, diffblock, π/2) - diffblock.grad = (r2 - r1)/2 -end - -""" - StatFunctional{N, AT} - StatFunctional(array::AT<:Array) -> StatFunctional{N, <:Array} - StatFunctional{N}(func::AT<:Function) -> StatFunctional{N, <:Function} - -statistic functional, i.e. - * if `AT` is an array, A[i,j,k...], it is defined on finite Hilbert space, which is `∫A[i,j,k...]p[i]p[j]p[k]...` - * if `AT` is a function, F(xᵢ,xⱼ,xₖ...), this functional is `1/C(r,n)... ∑ᵢⱼₖ...F(xᵢ,xⱼ,xₖ...)`, see U-statistics for detail. - -References: - U-statistics, http://personal.psu.edu/drh20/asymp/fall2006/lectures/ANGELchpt10.pdf -""" -struct StatFunctional{N, AT} - data::AT - StatFunctional{N}(data::AT) where {N, AT<:Function} = new{N, AT}(data) - StatFunctional(data::AT) where {N, AT<:AbstractArray{<:Real, N}} = new{N, AT}(data) -end - -@forward StatFunctional.data Base.ndims -Base.parent(stat::StatFunctional) = stat.data - -expect(stat::StatFunctional{2, <:AbstractArray}, px::Weights, py::Weights=px) = px.values' * stat.data * py.values -expect(stat::StatFunctional{1, <:AbstractArray}, px::Weights) = stat.data' * px.values -function expect(stat::StatFunctional{2, <:Function}, xs::AbstractVector{T}) where T - N = length(xs) - res = zero(stat.data(xs[1], xs[1])) - for i = 2:N - for j = 1:i-1 - @inbounds res += stat.data(xs[i], xs[j]) - end - end - res/binomial(N,2) -end -function expect(stat::StatFunctional{2, <:Function}, xs::AbstractVector, ys::AbstractVector) - M = length(xs) - N = length(ys) - ci = CartesianIndices((M, N)) - @inbounds mapreduce(ind->stat.data(xs[ind[1]], ys[ind[2]]), +, ci)/M/N -end -expect(stat::StatFunctional{1, <:Function}, xs::AbstractVector) = mean(stat.data.(xs)) -Base.ndims(stat::StatFunctional{N}) where N = N - -""" - statdiff(probfunc, diffblock::Diff, stat::StatFunctional{<:Any, <:AbstractArray}; initial::AbstractVector=probfunc()) - statdiff(samplefunc, diffblock::Diff, stat::StatFunctional{<:Any, <:Function}; initial::AbstractVector=samplefunc()) - -Differentiation for statistic functionals. -""" -@inline function statdiff(probfunc, diffblock::Diff, stat::StatFunctional{2}; initial::AbstractVector=probfunc()) - r1, r2 = _perturb(()->expect(stat, probfunc(), initial), diffblock, π/2) - diffblock.grad = (r2 - r1)*ndims(stat)/2 -end -@inline function statdiff(probfunc, diffblock::Diff, stat::StatFunctional{1}) - r1, r2 = _perturb(()->expect(stat, probfunc()), diffblock, π/2) - diffblock.grad = (r2 - r1)*ndims(stat)/2 -end - -""" - backward!(state, circuit::AbstractBlock) -> AbstractRegister - -back propagate and calculate the gradient ∂f/∂θ = 2*Re(∂f/∂ψ*⋅∂ψ*/∂θ), given ∂f/∂ψ*. -`state` is a pair of output_register => the corresponding adjoint. - -Note: -Here, the input circuit should be a matrix block, otherwise the back propagate may not apply (like Measure operations). -""" -function backward!(state, block::AbstractBlock) - out, outδ = state - adjblock = block' - backward_params!((out, outδ), block) - in = apply!(out, adjblock) - inδ = apply!(outδ, adjblock) - return (in, inδ) -end - -function backward!(state, circuit::Union{ChainBlock, Concentrator}) - for blk in Base.Iterators.reverse(subblocks(circuit)) - state = backward!(state, blk) - end - return state -end - -backward!(state, block::Measure) = throw(MethodError(backward!, (state, block))) - -backward_params!(state, block::AbstractBlock) = nothing -function backward_params!(state, block::Diff{<:DiffBlock}) - in, outδ = state - Σ = generator(content(block)) - block.grad = -statevec(in |> Σ)' * statevec(outδ) |> imag - in |> Σ - nothing -end - -""" - gradient(circuit::AbstractBlock, mode::Symbol=:ANY) -> Vector - -collect all gradients in a circuit, mode can be :BP/:QC/:ANY, they will collect `grad` from Diff respectively. -""" -gradient(circuit::AbstractBlock) = gradient!(circuit, parameters_eltype(circuit)[]) - -function gradient!(circuit::AbstractBlock, grad) - for block in subblocks(circuit) - gradient!(block, grad) - end - grad -end - -gradient!(circuit::Diff, grad) = append!(grad, circuit.grad) diff --git a/src/Grover.jl b/src/Grover.jl deleted file mode 100644 index a17d50c..0000000 --- a/src/Grover.jl +++ /dev/null @@ -1,86 +0,0 @@ -export num_grover_step, inference_oracle, GroverIter, groverblock, groveriter, prob_match_oracle - -""" - inference_oracle([nbit::Int,] locs::Vector{Int}) -> ControlBlock - -A simple inference oracle, e.g. inference([-1, -8, 5]) is a control block that flip the bit if values of bits on position [1, 8, 5] match [0, 0, 1]. -""" -inference_oracle(locs::Vector{Int}) = control(locs[1:end-1], abs(locs[end]) => (locs[end]>0 ? Z : chain(phase(π), Z))) -inference_oracle(nbit::Int, locs::Vector{Int}) = inference_oracle(locs)(nbit) - -""" - target_space(oracle) -> Vector{Bool} - -Return a mask, that disired subspace of an oracle are masked true. -""" -function target_space(nbit::Int, oracle) - r = ArrayReg(ones(ComplexF64, 1< oracle - real(statevec(r)) .< 0 -end - -prob_inspace(psi::ArrayReg, ts) = norm(statevec(psi)[ts])^2 - -""" - prob_match_oracle(psi, oracle) -> Float64 - -Return the probability that `psi` matches oracle. -""" -prob_match_oracle(psi::ArrayReg, oracle) = prob_inspace(psi, target_space(nqubits(psi), oracle)) - -""" - num_grover_step(psi::ArrayReg, oracle) -> Int - -Return number of grover steps needed to match the oracle. -""" -num_grover_step(psi::ArrayReg, oracle) = _num_grover_step(prob_match_oracle(psi, oracle)) - -_num_grover_step(prob::Real) = Int(round(pi/4/sqrt(prob)))-1 - -""" - GroverIter{N} - - GroverIter(oracle, ref::ReflectBlock{N}, psi::ArrayReg, niter::Int) - -an iterator that perform Grover operations step by step. -An Grover operation consists of applying oracle and Reflection. -""" -struct GroverIter{N} - psi::ArrayReg - oracle - ref::ReflectBlock{N} - niter::Int -end - -groveriter(psi::ArrayReg, oracle, ref::ReflectBlock{N}, niter::Int) where {N} = GroverIter{N}(psi, oracle, ref, niter) -groveriter(psi::ArrayReg, oracle, niter::Int) = groveriter(psi, oracle, ReflectBlock(psi |> copy), niter) -groveriter(psi::ArrayReg, oracle) = groveriter(psi, oracle, ReflectBlock(psi |> copy), num_grover_step(psi, oracle)) - -function Base.iterate(it::GroverIter, st=1) - if it.niter + 1 == st - nothing - else - apply!(it.psi, it.oracle) - apply!(it.psi, it.ref), st+1 - end -end - -Base.length(it::GroverIter) = it.niter - -""" - groverblock(oracle, ref::ReflectBlock{N}, niter::Int=-1) - groverblock(oracle, psi::ArrayReg, niter::Int=-1) - -Return a ChainBlock/Sequential as Grover Iteration, the default `niter` will stop at the first optimal step. -""" -function groverblock(oracle::AbstractBlock{N}, ref::ReflectBlock{N}, niter::Int=-1) where {N} - if niter == -1 niter = num_grover_step(ref.psi, oracle) end - chain(N, chain(oracle, ref) for i = 1:niter) -end - -function groverblock(oracle, ref::ReflectBlock{N}, niter::Int=-1) where {N} - if niter == -1 niter = num_grover_step(ref.psi, oracle) end - sequence(sequence(oracle, ref) for i = 1:niter) -end - -groverblock(oracle, psi::ArrayReg, niter::Int=-1) = groverblock(oracle, ReflectBlock(psi |> copy), niter) diff --git a/src/Miscellaneous.jl b/src/Miscellaneous.jl deleted file mode 100644 index 570a8c6..0000000 --- a/src/Miscellaneous.jl +++ /dev/null @@ -1,27 +0,0 @@ -export inverselines, singlet_block - -""" - inverselines(nbit::Int; n_reg::Int=nbit) -> ChainBlock - -inverse first `n_reg` lines - -TODO: -deprecate this function, it is not used. -""" -function inverselines(nbit::Int; n_reg::Int=nbit) - c = chain(nbit) - for i = 1:(n_reg ÷ 2) - push!(c, swap(i,(n_reg-i+1))) - end - c -end - -function singlet_block(nbit::Int, i::Int, j::Int) - unit = chain(nbit) - push!(unit, put(nbit, i=>chain(X, H))) - push!(unit, control(nbit, -i, j=>X)) -end - -singlet_block() = singlet_block(2,1,2) - -Yao.mat(ρ::DensityMatrix{1}) = dropdims(state(ρ), dims=3) diff --git a/src/Mod.jl b/src/Mod.jl deleted file mode 100644 index cdd07df..0000000 --- a/src/Mod.jl +++ /dev/null @@ -1,105 +0,0 @@ -# TODO -# compile Mod and KMod to elementary gates. - -export Mod, KMod - -""" - Mod{N} <: PrimitiveBlock{N} - -calculates `mod(a*x, L)`, notice `gcd(a, L)` should be 1. -""" -struct Mod{N} <: PrimitiveBlock{N} - a::Int - L::Int - function Mod{N}(a, L) where N - @assert gcd(a, L) == 1 && L<=1<= m.L ? i+1 : mod(i*m.a, m.L)+1 - for j in 1:B - @inbounds nstate[_i,j] = reg.state[i+1,j] - end - end - reg.state = nstate - reg -end - -function Yao.mat(::Type{T}, m::Mod{N}) where {T, N} - perm = Vector{Int}(undef, 1<= m.L ? i+1 : mod(i*m.a, m.L)+1] = i+1 - end - PermMatrix(perm, ones(T, 1< (b&mask, b>>k) -end - -function Yao.apply!(reg::ArrayReg{B}, m::KMod{N, K}) where {B, N, K} - YaoBlocks._check_size(reg, m) - nstate = zero(reg.state) - - reader = bint2_reader(Int, K) - for b in basis(reg) - k, i = reader(b) - _i = i >= m.L ? i : mod(i*powermod(m.a, k, m.L), m.L) - _b = k + _i<= m.L ? i : mod(i*powermod(m.a, k, m.L), m.L) - _b = k + _i< AbstractBlock - -circuit to optimize -""" -function circuit end - -""" - loss(qop::QCOptProblem) -> Real - -Return the loss. -""" -function loss end - -##################################################### - -""" - gradient(qop::QCOptProblem) -> Vector - -the gradients with respect to `diff_blocks`. -""" -function gradient end - -""" - diff_blocks(qop::QCOptProblem) -> iterable - -collection of all differentiable units. -""" -diff_blocks(qop::QCOptProblem) = collect_blocks(Diff, qop |> circuit) - -""" - num_gradient(qop::QCOptProblem) -> Vector - -obtain the gradient numerically -""" -num_gradient(qop::QCOptProblem) = numdiff.(()->loss(qop), qop |> diff_blocks) - -################# Optimization ################### -""" - QCOptGo!{QT} - -quantum circuit optimization problem optimizer. -""" -abstract type QCOptGo!{QT} end - -include("QuGAN.jl") -include("QCBM.jl") diff --git a/src/QFT.jl b/src/QFT.jl deleted file mode 100644 index 47cd061..0000000 --- a/src/QFT.jl +++ /dev/null @@ -1,54 +0,0 @@ -@static if VERSION >= v"0.7-" - using FFTW -end - -export QFTCircuit, QFTBlock, invorder_firstdim - -CRk(i::Int, j::Int, k::Int) = control([i, ], j=>shift(2π/(1<H) : CRk(j, i, j-i+1) for j = i:n) -QFTCircuit(n::Int) = chain(n, CRot(n, i) for i = 1:n) - -struct QFTBlock{N} <: PrimitiveBlock{N} end -mat(::Type{T}, q::QFTBlock{N}) where {T, N} = T.(applymatrix(q)) - -apply!(reg::DefaultRegister{B}, ::QFTBlock) where B = (reg.state = ifft!(invorder_firstdim(reg |> state), 1)*sqrt(1<state, 1)/sqrt(1< log2i - n_2 = n ÷ 2 - mask = [bmask(i, n-i+1) for i in 1:n_2] - @simd for b in basis(n) - @inbounds w[breflect(b, mask; nbits=n)+1,:] = v[b+1,:] - end - w -end - -function invorder_firstdim(v::Vector) - n = length(v) |> log2i - n_2 = n ÷ 2 - w = similar(v) - #mask = SVector{n_2, Int}([bmask(i, n-i+1)::Int for i in 1:n_2]) - mask = [bmask(i, n-i+1)::Int for i in 1:n_2] - @simd for b in basis(n) - @inbounds w[breflect(b, mask; nbits=n)+1] = v[b+1] - end - w -end diff --git a/src/QSVD.jl b/src/QSVD.jl index 1a8d828..29705b3 100644 --- a/src/QSVD.jl +++ b/src/QSVD.jl @@ -54,8 +54,8 @@ kwargs includes * `optimizer`, default is `Adam(lr=0.1)`. """ function QuantumSVD(M::AbstractMatrix; Nc::Int=log2i(min(size(M)...)), - circuit_a=random_diff_circuit(log2i(size(M, 1)), 5, pair_ring(log2i(size(M, 1)))), - circuit_b=random_diff_circuit(log2i(size(M, 2)), 5, pair_ring(log2i(size(M, 2)))), + circuit_a=variational_circuit(log2i(size(M, 1)), 5, pair_ring(log2i(size(M, 1)))), + circuit_b=variational_circuit(log2i(size(M, 2)), 5, pair_ring(log2i(size(M, 2)))), maxiter=200, optimizer=Adam(lr=0.1)) dispatch!(circuit_a, :random) diff --git a/src/QuAlgorithmZoo.jl b/src/QuAlgorithmZoo.jl index 5f04589..b434d9e 100644 --- a/src/QuAlgorithmZoo.jl +++ b/src/QuAlgorithmZoo.jl @@ -1,38 +1,16 @@ module QuAlgorithmZoo -using LuxurySparse, LinearAlgebra -using MacroTools: @forward -using Yao, YaoBlocks.ConstGate, BitBasis -using YaoArrayRegister: u1rows! -import Yao: mat, dispatch!, niparams, getiparams, setiparams!, cache_key, print_block, apply!, PrimitiveBlock, ishermitian, isunitary, isreflexive -import YaoBlocks: render_params -import Base: ==, copy, hash +using LinearAlgebra +using Yao, BitBasis +using YaoExtensions -export openbox - -""" - openbox(block::AbstractBlock) -> AbstractBlock - -For a black box, like QFTBlock, you can get its white box (loyal simulation) using this function. -""" -function openbox end - -include("Miscellaneous.jl") -include("sequence.jl") -include("Diff.jl") include("Adam.jl") -include("QFT.jl") -include("CircuitBuild.jl") -include("QCOptProblem.jl") -include("RotBasis.jl") -include("Grover.jl") include("PhaseEstimation.jl") -include("HHL.jl") include("hamiltonian_solvers.jl") include("HadamardTest.jl") -include("lin_diffEq_HHL.jl") include("QSVD.jl") -include("shor.jl") +include("number_theory.jl") +@deprecate random_diff_circuit variational_circuit end # module diff --git a/src/RotBasis.jl b/src/RotBasis.jl deleted file mode 100644 index 2c9cdb1..0000000 --- a/src/RotBasis.jl +++ /dev/null @@ -1,76 +0,0 @@ -export RotBasis, randpolar, polar2u, u2polar, rot_basis - -""" - RotBasis{T} <: PrimitiveBlock{1, Complex{T}} - -A special rotation block that transform basis to angle θ and ϕ in bloch sphere. -""" -mutable struct RotBasis{T} <: PrimitiveBlock{1} - theta::T - phi::T -end - -_make_rot_mat(I, block, theta) = I * cos(theta / 2) - im * sin(theta / 2) * block -# chain -> * -# mat(rb::RotBasis{T}) where T = mat(Ry(-rb.theta))*mat(Rz(-rb.phi)) -function mat(::Type{TM}, x::RotBasis{T}) where {TM, T} - R1 = _make_rot_mat(IMatrix{2, Complex{T}}(), mat(TM, Z), -x.phi) - R2 = _make_rot_mat(IMatrix{2, Complex{T}}(), mat(TM, Y), -x.theta) - R2 * R1 -end - -==(rb1::RotBasis, rb2::RotBasis) = rb1.theta == rb2.theta && rb1.phi == rb2.phi - -copy(block::RotBasis{T}) where T = RotBasis{T}(block.theta, block.phi) -dispatch!(block::RotBasis, params::Vector) = ((block.theta, block.phi) = params; block) - -getiparams(rb::RotBasis) = (rb.theta, rb.phi) -function setiparams!(rb::RotBasis, θ::Real, ϕ::Real) - rb.theta, rb.phi = θ, ϕ - rb -end -niparams(::Type{<:RotBasis}) = 2 -niparams(::RotBasis) = 2 -render_params(r::RotBasis, ::Val{:random}) = rand()*π, rand()*2π - -function print_block(io::IO, R::RotBasis) - print(io, "RotBasis($(R.theta), $(R.phi))") -end - -function hash(gate::RotBasis, h::UInt) - hash(hash(gate.theta, gate.phi, objectid(gate)), h) -end - -cache_key(gate::RotBasis) = (gate.theta, gate.phi) - -rot_basis(num_bit::Int) = dispatch!(chain(num_bit, put(i=>RotBasis(0.0, 0.0)) for i=1:num_bit), randpolar(num_bit) |> vec) - -""" - u2polar(vec::Array) -> Array - -transform su(2) state vector to polar angle, apply to the first dimension of size 2. -""" -function u2polar(vec::Vector) - ratio = vec[2]/vec[1] - [atan(abs(ratio))*2, angle(ratio)] -end - -""" - polar2u(vec::Array) -> Array - -transform polar angle to su(2) state vector, apply to the first dimension of size 2. -""" -function polar2u(polar::Vector) - theta, phi = polar - [cos(theta/2)*exp(-im*phi/2), sin(theta/2)*exp(im*phi/2)] -end - -u2polar(arr::Array) = mapslices(u2polar, arr, dims=[1]) -polar2u(arr::Array) = mapslices(polar2u, arr, dims=[1]) - -""" - randpolar(params::Int...) -> Array - -random polar basis, number of basis -""" -randpolar(params::Int...) = rand(2, params...)*pi diff --git a/src/hamiltonian_solvers.jl b/src/hamiltonian_solvers.jl index d344692..7b5b71d 100644 --- a/src/hamiltonian_solvers.jl +++ b/src/hamiltonian_solvers.jl @@ -1,16 +1,4 @@ -export heisenberg, iter_groundstate!, itime_groundstate!, vqe_solve! - -""" - heisenberg(nbit::Int; periodic::Bool=true) - -heisenberg hamiltonian, for its ground state, refer `PRB 48, 6141`. -""" -function heisenberg(nbit::Int; periodic::Bool=true) - sx = i->put(nbit, i=>X) - sy = i->put(nbit, i=>Y) - sz = i->put(nbit, i=>Z) - mapreduce(i->(j=i%nbit+1; sx(i)*sx(j)+sy(i)*sy(j)+sz(i)*sz(j)), +, 1:(periodic ? nbit : nbit-1)) -end +export iter_groundstate!, itime_groundstate!, vqe_solve! """ iter_groundstate!({reg::AbstractRegister}, h::AbstractBlock; niter::Int=100) -> AbstractRegister diff --git a/src/sequence.jl b/src/sequence.jl deleted file mode 100644 index a19822a..0000000 --- a/src/sequence.jl +++ /dev/null @@ -1,39 +0,0 @@ -export Sequence -import YaoBlocks: subblocks, chsubblocks, apply! -using YaoBlocks: _check_size - -struct Sequence <: CompositeBlock{Any} - blocks::Vector -end - -Sequence(args...) = Sequence(collect(AbstractBlock, args)) - -subblocks(seq::Sequence) = filter(x->x isa AbstractBlock, seq.blocks) -chsubblocks(pb::Sequence, blocks::Vector) = Sequence(blocks) - -function apply!(reg::ArrayReg, seq::Sequence) - for x in seq.blocks - reg |> x - end - reg -end - -for PROP in [:lastindex, :firstindex, :getindex, :length, :eltype, :iterate, :eachindex, :popfirst!, :pop!] - @eval Base.$PROP(c::Sequence, args...; kwargs...) = $PROP(c.blocks, args...; kwargs...) -end - -function Base.:(==)(lhs::Sequence, rhs::Sequence) - (length(lhs.blocks) == length(rhs.blocks)) && all(lhs.blocks .== rhs.blocks) -end - -Base.copy(c::Sequence) = Sequence(copy(c.blocks)) -Base.similar(c::Sequence) = Sequence(empty!(similar(c.blocks))) -Base.getindex(c::Sequence, index::Union{UnitRange, Vector}) = Sequence(getindex(c.blocks, index)) - -Base.setindex!(c::Sequence, val::AbstractBlock{N}, index::Integer) where N = (setindex!(c.blocks, val, index); c) -Base.insert!(c::Sequence, index::Integer, val::AbstractBlock{N}) where N = (insert!(c.blocks, index, val); c) -Base.push!(c::Sequence, m) where N = (push!(c.blocks, m); c) -Base.append!(c::Sequence, list::Vector) where N = (append!(c.blocks, list); c) -Base.append!(c1::Sequence, c2::Sequence) where N = (append!(c1.blocks, c2.blocks); c1) -Base.prepend!(c1::Sequence, list::Vector{<:AbstractBlock{N}}) where N = (prepend!(c1.blocks, list); c1) -Base.prepend!(c1::Sequence, c2::Sequence) where N = (prepend!(c1.blocks, c2.blocks); c1) diff --git a/src/shor.jl b/src/shor.jl deleted file mode 100644 index c64fe89..0000000 --- a/src/shor.jl +++ /dev/null @@ -1,80 +0,0 @@ -include("number_theory.jl") -include("Mod.jl") - -export shor, order_finding_circuit, get_order - -""" - shor(L::Int, ver=Val(:quantum); maxtry=100) - -factorize an integer `L`, `ver` can be either `Val(:quantum)` or `Val(:classical)`. -""" -function shor(L::Int, ver=Val(:quantum); maxtry=100) - L%2 == 0 && return 2 - - # find solutions like `a^b` - res = NumberTheory.factor_a_power_b(L) - res !== nothing && return res[1] - - for i in 1:maxtry - x = NumberTheory.rand_primeto(L) - r = get_order(ver, x, L) - # if `x^(r/2)` is non-trivil, go on. - # Here, we do not condsier `powermod(x, r÷2, L) == 1`, since in this case the order should be `r/2` - if r%2 == 0 && powermod(x, r÷2, L) != L-1 - f1, f2 = gcd(powermod(x, r÷2, L)-1, L), gcd(powermod(x, r÷2, L)+1, L) - if f1!=1 - return f1 - elseif f2!=1 - return f2 - else - error("Algorithm Fail!") - end - end - end -end - -"""estimate the required size of the output register.""" -estimate_ncbit(nbit::Int, ϵ::Real) = 2*nbit + 1 + ceil(Int,log2(2+1/2ϵ)) - -""" - order_finding_circuit(x::Int, L::Int; nbit::Int=bit_length(L-1), ncbit::Int=estimate_ncbit(nbit, 0.25)) -> AbstractBlock - -Returns the circuit for finding the order of `x` to `L`, -feeding input `|1>⊗|0>` will get the resulting quantum register with the desired "phase" information. -""" -function order_finding_circuit(x::Int, L::Int; nbit::Int=bit_length(L-1), ncbit::Int=estimate_ncbit(nbit, 0.25)) - N = nbit+ncbit - chain(N, repeat(N, H, 1:ncbit),KMod{N, ncbit}(x, L), concentrate(N, QFTBlock{ncbit}()', 1:ncbit)) -end - -""" - find_order([ver], x::Int, N::Int; nshots=10) -> Union{Int, Nothing} - -Get the order of `x`, `ver` can be `Val(:classical)` (default) or `Val(:quantum)`, -when using the quantum approach, we can set key word arguments `nshot`, -`nbit` (size of input data register) and `ncbit` (size of control register, or output register). -""" -get_order(::Val{:classical}, x::Int, N::Int; kwargs...) = NumberTheory.find_order(x, N) -function get_order(::Val{:quantum}, x::Int, N::Int; nshots=10, kwargs...) - c = order_finding_circuit(x, N; kwargs...) - n = nqubits_data(c[2]) - ncbit = nqubits_control(c[2]) - reg = join(product_state(n, 1), zero_state(ncbit)) - - res = measure(copy(reg) |> c; nshots=nshots) - reader = bint2_reader(Int, ncbit) - for r in res - k, i = reader(r) - # get s/r - ϕ = bfloat(k) # - ϕ == 0 && continue - - order = NumberTheory.order_from_float(ϕ, x, N) - if order === nothing - continue - else - return order - end - end - return nothing -end diff --git a/test/CircuitBuild.jl b/test/CircuitBuild.jl deleted file mode 100644 index 4e078e2..0000000 --- a/test/CircuitBuild.jl +++ /dev/null @@ -1,65 +0,0 @@ -using Test -using Yao, QuAlgorithmZoo - -@testset "pairs geometries" begin - @test pair_ring(3) == [1=>2,2=>3,3=>1] - ps = pair_square(2, 2) - @test length(ps) == 8 - for item in [1=>2, 3=>4, 2=>1, 4=>3, 1=>3, 2=>4, 3=>1, 4=>2] - @test item in ps - end - @test cnot_entangler(4, ps) isa ChainBlock - @test cnot_entangler(4, ps) |> length == 8 -end - -@testset "random circuit" begin - c = rand_circuit(1) - @test c isa ChainBlock - @test length(c) == 5 - c = rand_circuit(9) - @test c isa ChainBlock - @test length(c) == 45 -end - -@testset "rotter, collect_blocks, num_gradient, opgrad" begin - @test merged_rotor(true, true) == Rx(0) - @test merged_rotor(false, false) == merged_rotor() == chain(Rz(0), Rx(0), Rz(0)) - @test merged_rotor(false, true) == chain(Rz(0), Rx(0)) - @test merged_rotor(true, false) == chain(Rx(0), Rz(0)) - @test collect_blocks(RotationGate, rotorset(:Merged, 5, true, false)) |> length == 10 - - @test rotor(5, 2, true, true) isa ChainBlock - @test rotor(5, 2, true, true) |> length == 1 - @test rotor(5, 2, true, true) |> nqubits == 5 - @test collect_blocks(PutBlock{<:Any, <:Any, <:RotationGate}, rotorset(:Split, 5, true, false)) |> length == 10 -end - -@testset "random diff circuit" begin - c = random_diff_circuit(4, 3, [1=>3, 2=>4, 2=>3, 4=>1]) - rots = collect_blocks(RotationGate, c) - @test length(rots) == nparameters(c) == 40 - @test dispatch!(+, c, ones(40)*0.1) |> parameters == ones(40)*0.1 - @test dispatch!(+, c, :random) |> parameters != ones(40)*0.1 - - nbit = 4 - c = random_diff_circuit(nbit, 1, pair_ring(nbit), mode=:Split) |> autodiff(:BP) - reg = rand_state(4) - dispatch!(c, randn(nparameters(c))) - - dbs = collect_blocks(Diff, c) - op = kron(4, 1=>Z, 2=>X) - loss1z() = expect(op, copy(reg) |> c) # return loss please - - # back propagation - ψ = copy(reg) |> c - δ = copy(ψ) |> op - backward!((ψ, δ), c) - bd = gradient(c) - - # get num gradient - nd = numdiff.(loss1z, dbs) - ed = opdiff.(()->copy(reg)|>c, dbs, Ref(op)) - - @test isapprox.(nd, ed, atol=1e-4) |> all - @test isapprox.(nd, bd, atol=1e-4) |> all -end diff --git a/test/Diff.jl b/test/Diff.jl deleted file mode 100644 index 164fcbb..0000000 --- a/test/Diff.jl +++ /dev/null @@ -1,173 +0,0 @@ -using Yao, QuAlgorithmZoo -using YaoBlocks.ConstGate -using LinearAlgebra, Test, Random - -@testset "BP diff" begin - reg = rand_state(4) - block = put(4, 2=>rot(X, 0.3)) - df = Diff(block) - @test df.grad == 0 - @test nqubits(df) == 4 - - df2 = Diff(rot(CNOT, 0.3)) - @test df2.grad == 0 - @test nqubits(df2) == 2 - @test_throws MethodError backward!((reg, reg), Measure(4)) -end - -@testset "Qi diff" begin - reg = rand_state(4) - df2 = Diff(rot(CNOT, 0.3)) - @test df2.grad == 0 - @test nqubits(df2) == 2 - - @test df2' isa Diff - @test mat(df2) == mat(df2')' -end - -""" - loss_expect!(circuit::AbstractBlock, op::AbstractBlock) -> Function - -Return function "loss!(ψ, θ) -> Vector" -""" -function loss_expect!(circuit::AbstractBlock, op::AbstractBlock) - N = nqubits(circuit) - function loss!(ψ::AbstractRegister, θ::Vector) - params = parameters(circuit) - dispatch!(circuit, θ) - ψ |> circuit - popdispatch!(circuit, params) - expect(op, ψ) - end -end - -""" - loss_Z1!(circuit::AbstractBlock; ibit::Int=1) -> Function - -Return the loss function f = (means measuring the ibit-th bit in computation basis). -""" -loss_Z1!(circuit::AbstractBlock; ibit::Int=1) = loss_expect!(circuit, put(nqubits(circuit), ibit=>Z)) - -_cnot_entangler(n::Int, pairs) = chain(n, control(n, [ctrl], target=>X) for (ctrl, target) in pairs) - -function _rotor(nbit::Int, ibit::Int, noleading::Bool=false, notrailing::Bool=false) - rt = chain(nbit, [put(nbit, ibit=>Rz(0.0)), put(nbit, ibit=>Rx(0.0)), put(nbit, ibit=>Rz(0.0))]) - noleading && popfirst!(rt) - notrailing && pop!(rt) - rt -end - -rset(nbit::Int, noleading::Bool=false, notrailing::Bool=false) = chain(nbit, [_rotor(nbit, j, noleading, notrailing) for j=1:nbit]) - -function ibm_diff_circuit(nbit, nlayer, pairs) - circuit = chain(nbit) - - ent = _cnot_entangler(nbit, pairs) - for i = 1:(nlayer + 1) - i!=1 && push!(circuit, ent) - push!(circuit, rset(nbit, i==1, i==nlayer+1)) - end - circuit -end - -@testset "BP diff" begin - c = put(4, 3=>Rx(0.5)) |> autodiff(:BP) - cad = c' - @test mat(cad) == mat(c)' - - circuit = chain(4, repeat(4, H, 1:4), put(4, 3=>Rz(0.5)) |> autodiff(:BP), control(4, 2, 1=>shift(0.4)) |> autodiff(:BP), control(2, 1=>X), put(4, 4=>Ry(0.2)) |> autodiff(:BP)) - op = put(4, 3=>Y) - θ = [0.9, 0.2, 0.3] - dispatch!(circuit, θ) - loss! = loss_expect!(circuit, op) - ψ0 = rand_state(4) - ψ = copy(ψ0) |> circuit - - # get gradient - δ = copy(ψ) |> op - in, inδ = backward!((ψ, δ), circuit) - @test in ≈ ψ0 - g1 = gradient(circuit) - - g2 = zero(θ) - η = 1e-5 - for i in 1:length(θ) - θ1 = copy(θ) - θ2 = copy(θ) - θ1[i] -= 0.5η - θ2[i] += 0.5η - g2[i] = (loss!(copy(ψ0), θ2) - loss!(copy(ψ0), θ1))/η |> real - end - g3 = opdiff.(() -> copy(ψ0) |> circuit, collect_blocks(Diff, circuit), Ref(op)) - @test isapprox.(g1, g2, atol=1e-5) |> all - @test isapprox.(g2, g3, atol=1e-5) |> all -end - -@testset "constructor" begin - @test generator(put(4, 1=>Rx(0.1))) == put(4, 1=>X) - @test generator(Rx(0.1)) == X - circuit = chain(put(4, 1=>Rx(0.1)), control(4, 2, 1=>Ry(0.3))) - c2 = circuit |> autodiff(:BP) - @test c2[1] isa Diff - @test !(c2[2] isa Diff) -end - -@testset "numdiff & opdiff" begin - @test collect_blocks(XGate, chain([X, Y, Z])) == [X] - - c = chain(put(4, 1=>Rx(0.5))) |> autodiff(:QC) - nd = numdiff(c[1].content) do - expect(put(4, 1=>Z), zero_state(4) |> c) |> real # return loss please - end - - ed = opdiff(c[1].content, put(4, 1=>Z)) do - zero_state(4) |> c # a function get output - end - @test isapprox(nd, ed, atol=1e-4) - - reg = rand_state(4) - c = chain(put(4, 1=>Rx(0.5)), control(4, 1, 2=>Ry(0.5)), control(4, 1, 2=>shift(0.3)), kron(4, 2=>Rz(0.3), 3=>Rx(0.7))) |> autodiff(:QC) - dbs = collect_blocks(Diff, c) - loss1z() = expect(kron(4, 1=>Z, 2=>X), copy(reg) |> c) |> real # return loss please - nd = numdiff.(loss1z, dbs) - ed = opdiff.(()->copy(reg) |> c, dbs, Ref(kron(4, 1=>Z, 2=>X))) - gd = gradient(c) - @test gradient(c) == gd - @test isapprox(nd, ed, atol=1e-4) - @test ed == gd -end - -@testset "stat" begin - nbit = 3 - f(x::Number, y::Number) = Float64(abs(x-y) < 1.5) - x = 0:1<2, 2=>3, 3=>1] - c = ibm_diff_circuit(nbit, 2, prs) |> autodiff(:QC) - dispatch!(c, :random) - dbs = collect_blocks(Diff,c) - - p0 = zero_state(nbit) |> c |> probs - sample0 = measure(zero_state(nbit) |> c; nshots=5000) - loss0 = expect(V, p0 |> as_weights) - gradsn = numdiff.(()->expect(V, zero_state(nbit) |> c |> probs |> as_weights), dbs) - gradse = statdiff.(()->zero_state(nbit) |> c |> probs |> as_weights, dbs, Ref(V), initial=p0 |> as_weights) - gradsf = statdiff.(()->measure(zero_state(nbit) |> c; nshots=5000), dbs, Ref(VF), initial=sample0) - @test all(isapprox.(gradse, gradsn, atol=1e-4)) - @test norm(gradsf-gradse)/norm(gradsf) <= 0.2 - - # 1D - h = randn(1< autodiff(:QC) - dispatch!(c, :random) - dbs = collect_blocks(Diff, c) - - p0 = zero_state(nbit) |> c |> probs |> as_weights - loss0 = expect(V, p0 |> as_weights) - gradsn = numdiff.(()->expect(V, zero_state(nbit) |> c |> probs |> as_weights), dbs) - gradse = statdiff.(()->zero_state(nbit) |> c |> probs |> as_weights, dbs, Ref(V)) - @test all(isapprox.(gradse, gradsn, atol=1e-4)) -end diff --git a/test/HadamardTest.jl b/test/HadamardTest.jl index edb4b02..0a5a43d 100644 --- a/test/HadamardTest.jl +++ b/test/HadamardTest.jl @@ -14,15 +14,15 @@ single_swap_test(reg::AbstractRegister, ϕ::Real) = hadamard_test(SWAP, reg, ϕ) rho2 = reg2 |> ρ reg3 = rand_state(3) |> focus!(1,2) rho3 = reg3 |> ρ - desired = tr(mat(rho1)*mat(rho2)) + desired = tr(Matrix(rho1)*Matrix(rho2)) c = swap_test_circuit(2, 2, 0) res = expect(put(5, 1=>Z), join(join(reg2, reg1), zero_state(1)) |> c) |> tr @test desired ≈ res - desired = tr(mat(rho1)*mat(rho2)*mat(rho3)) |> real + desired = tr(Matrix(rho1)*Matrix(rho2)*Matrix(rho3)) |> real c = swap_test_circuit(2, 3, 0) res = expect(put(7, 1=>Z), reduce(⊗, [reg3, reg2, reg1, zero_state(1)]) |> c) |> tr |> real @test desired ≈ res - desired = tr(mat(rho1)*mat(rho2)*mat(rho3)) |> imag + desired = tr(Matrix(rho1)*Matrix(rho2)*Matrix(rho3)) |> imag c = swap_test_circuit(2, 3, -π/2) res = expect(put(7, 1=>Z), reduce(⊗, [reg3, reg2, reg1, zero_state(1)]) |> c) |> tr |> real @test desired ≈ res diff --git a/test/QCBM.jl b/test/QCBM.jl deleted file mode 100644 index 0f523ec..0000000 --- a/test/QCBM.jl +++ /dev/null @@ -1,32 +0,0 @@ -using Test -using Yao -using QuAlgorithmZoo - -""" - gaussian_pdf(x, μ::Real, σ::Real) - -gaussian probability density function. -""" -function gaussian_pdf(x, μ::Real, σ::Real) - pl = @. 1 / sqrt(2pi * σ^2) * exp(-(x - μ)^2 / (2 * σ^2)) - pl / sum(pl) -end - -@testset "qcbm" begin - # problem setup - n = 6 - depth = 6 - - N = 1< autodiff(:QC) - dispatch!(circuit, :random) - qcbm = QCBM(circuit, kernel, pg) - - # training - niter = 100 - optim = Adam(lr=0.1) - for info in QCBMGo!(qcbm, optim, niter) end - @test qcbm |> loss < 1e-4 -end diff --git a/test/QCOptProblem.jl b/test/QCOptProblem.jl deleted file mode 100644 index 153ba97..0000000 --- a/test/QCOptProblem.jl +++ /dev/null @@ -1,7 +0,0 @@ -@testset "QuGAN" begin - include("QuGAN.jl") -end - -@testset "QCBM" begin - include("QCBM.jl") -end diff --git a/test/QFT.jl b/test/QFT.jl deleted file mode 100644 index a2961fe..0000000 --- a/test/QFT.jl +++ /dev/null @@ -1,51 +0,0 @@ -using Test, Random, LinearAlgebra, SparseArrays, LuxurySparse - -using Yao -using YaoArrayRegister: invorder -using QuAlgorithmZoo -using FFTW - -@testset "QFT" begin - num_bit = 5 - fftblock = QFTCircuit(num_bit) - ifftblock = fftblock' - reg = rand_state(num_bit) - rv = copy(statevec(reg)) - - @test Matrix(mat(chain(3, QFTCircuit(3) |> adjoint, QFTCircuit(3)))) ≈ IMatrix(1<<3) - - # test ifft - reg1 = apply!(copy(reg), ifftblock) - - # permute lines (Manually) - kv = fft(statevec(reg))/sqrt(length(rv)) - @test statevec(reg1) ≈ invorder(kv) - - # test fft - reg2 = apply!(invorder!(copy(reg)), fftblock) - kv = ifft(rv) * sqrt(length(rv)) - @test statevec(reg2) ≈ kv -end - - -@testset "QFTBlock" begin - num_bit = 5 - qft = QFTCircuit(num_bit) - iqft = adjoint(qft) - qftblock = QFTBlock{num_bit}() - iqftblock = QFTBlock{num_bit}() |> adjoint - @test openbox(qftblock) == qft - @test openbox(iqftblock) == iqft - reg = rand_state(num_bit) - - @test Matrix(mat(chain(3, QFTBlock{3}() |> adjoint, QFTBlock{3}()))) ≈ IMatrix(1<<3) - - # permute lines (Manually) - @test apply!(copy(reg), iqft) ≈ apply!(copy(reg), QFTBlock{num_bit}() |> adjoint) - - # test fft - @test apply!(copy(reg), qft) ≈ apply!(copy(reg), qftblock) - - # regression test for nactive - @test apply!(focus!(copy(reg), 1:3), QFTBlock{3}()) |> isnormalized -end diff --git a/test/QuGAN.jl b/test/QuGAN.jl deleted file mode 100644 index 17c81e2..0000000 --- a/test/QuGAN.jl +++ /dev/null @@ -1,24 +0,0 @@ -using Test -using Yao -using QuAlgorithmZoo -using Random - -function run_test(nbit::Int, depth_gen::Int, depth_disc::Int; g_lr=0.1, d_lr=0.2, niter=1000) - qg = toy_qugan(rand_state(nbit), depth_gen, depth_disc) - for info in QuGANGo!(qg, g_lr, d_lr, niter) end - qg -end - -# to fix -@testset "quantum circuit gan - opdiff" begin - Random.seed!(2) - N = 3 - target = rand_state(N) - qcg = toy_qugan(target, 2, 2) - grad = gradient(qcg) - @test isapprox(grad, num_gradient(qcg), atol=1e-4) - qg = run_test(3, 4, 4, g_lr=0.2, d_lr=0.5, niter=300) - @test qg |> loss < 0.1 - qg = run_test(3, 4, 4, g_lr=Adam(lr=0.005), d_lr=Adam(lr=0.5), niter=1000) - @test qg |> loss < 0.1 -end diff --git a/test/RotBasis.jl b/test/RotBasis.jl deleted file mode 100644 index dad47af..0000000 --- a/test/RotBasis.jl +++ /dev/null @@ -1,38 +0,0 @@ -using Test, Random, LinearAlgebra, SparseArrays - -using Yao -using QuAlgorithmZoo - -@testset "RotBasis" begin - rt = RotBasis(0.5, 0.4) - crt = chain(rt) - - dispatch!(crt, [2., 3.]) - @test nparameters(crt) == 2 - - for (t1, t2, t3) in zip(parameters(rt), (2, 3), parameters(crt)) - @test t1 == t2 == t3 - end - - # check consistency - rb = put(1, 1=>RotBasis(0.1, 0.3))#rot_basis(1) - angles = randpolar(1) - # prepair a state in the angles direction. - psi = angles |> polar2u |> ArrayReg - - # rotate to the same direction for measurements. - dispatch!(rb, vec(angles)) - @test state(apply!(psi, rb)) ≈ [1, 0] - - @test nparameters(rot_basis(3)) == 6 - dispatch!(rb, :zero) - @test parameters(rb)[1] == 0 - dispatch!(rb, :random) - @test parameters(rb)[1] != 0 -end - -@testset "polar and u" begin - polar = randpolar(10) - @test size(polar) == (2, 10) - @test polar |> polar2u |> u2polar ≈ polar -end diff --git a/test/Sequence.jl b/test/Sequence.jl deleted file mode 100644 index 35feb76..0000000 --- a/test/Sequence.jl +++ /dev/null @@ -1,62 +0,0 @@ -using Test - -using Yao -using QuAlgorithmZoo - -@testset "constructor" begin - - g = Sequence( - kron(2, X, Y), - kron(2, 1=>phase(0.1)), - ) - - @test g isa Sequence - @test g.blocks == [kron(2, X, Y), kron(2, 1=>phase(0.1))] -end - -@testset "apply" begin - g = Sequence( - kron(2, X, Y), - kron(2, 1=>phase(0.1)), - ) - - reg = rand_state(2) - @test statevec(apply!(copy(reg), g)) ≈ mat(chain(g...)) * reg.state -end - -@testset "iteration" begin - test_list = [X, Y, phase(0.1), rot(X, 0.0)] - g = Sequence(test_list) - - for (src, tg) in zip(g, test_list) - @test src == tg - end - - for (src, tg) in zip(eachindex(g), 1:length(test_list)) - @test src == tg - end -end - -@testset "additional" begin - g = Sequence(X, Y) - push!(g, Z) - @test g[3] == Z - - append!(g, [rot(X, 0.0), rot(Y, 0.0)]) - @test g[4] == rot(X, 0.0) - @test g[5] == rot(Y, 0.0) - - prepend!(g, [phase(0.1)]) - @test g[1] == phase(0.1) - @test g[2] == X - @test g[end] == rot(Y, 0.0) - gg = insert!(g, 4, Z) - @test gg[4] == Z -end - -@testset "traits" begin - # TODO: check traits when primitive blocks' traits are all defined - g = Sequence(X, Y) - @test length(g) == 2 - @test eltype(g) == eltype(g.blocks) -end diff --git a/test/hamiltonian_solvers.jl b/test/hamiltonian_solvers.jl index 897b105..c5476c4 100644 --- a/test/hamiltonian_solvers.jl +++ b/test/hamiltonian_solvers.jl @@ -1,7 +1,7 @@ using Yao using LinearAlgebra using Test -using QuAlgorithmZoo +using QuAlgorithmZoo, YaoExtensions using YaoBlocks: ConstGate @testset "solving hamiltonian" begin @@ -24,7 +24,7 @@ using YaoBlocks: ConstGate N = 4 h = heisenberg(N) E = eigen(h |> mat |> Matrix).values[1] - c = random_diff_circuit(N, 5, [i=>mod(i,N)+1 for i=1:N], mode=:Merged) |> autodiff(:QC) + c = YaoExtensions.variational_circuit(N, 5, [i=>mod(i,N)+1 for i=1:N], mode=:Merged) |> autodiff(:QC) dispatch!(c, :random) vqe_solve!(c, h) E2 = expect(h, zero_state(N) |> c) diff --git a/test/runtests.jl b/test/runtests.jl index b540221..1bf9b29 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,39 +1,12 @@ using Test, Random, LinearAlgebra, SparseArrays using Yao +using YaoExtensions using QuAlgorithmZoo - -@testset "QFT" begin - include("QFT.jl") -end - -@testset "CircuitBuild" begin - include("CircuitBuild.jl") -end - -@testset "RotBasis" begin - include("RotBasis.jl") -end - -@testset "Grover" begin - include("Grover.jl") -end - @testset "PhaseEstimation" begin include("PhaseEstimation.jl") end -@testset "HHL" begin - include("HHL.jl") -end -@testset "diff Eq" begin - include("lin_diffEq_test.jl") -end - -@testset "QCOptProblem" begin - include("QCOptProblem.jl") -end - @testset "hamiltonian solvers" begin include("hamiltonian_solvers.jl") end @@ -42,14 +15,6 @@ end include("HadamardTest.jl") end -@testset "Sequence" begin - include("Sequence.jl") -end - -@testset "Diff" begin - include("Diff.jl") -end - -@testset "Shore" begin - include("shor.jl") +@testset "QSVD" begin + include("QSVD.jl") end