From e3fc22b9e37e88a4eb90fc494065416f468440ce Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Thu, 16 Dec 2021 04:24:20 -0500 Subject: [PATCH] add docstrings --- src/EasyBuild/block_extension/FSimGate.jl | 28 +++++++-- src/EasyBuild/block_extension/shortcuts.jl | 18 ++---- src/EasyBuild/general_U4.jl | 6 ++ src/EasyBuild/google53.jl | 6 +- src/EasyBuild/hadamardtest.jl | 18 +++++- src/EasyBuild/hamiltonians.jl | 16 +++-- src/EasyBuild/phaseestimation.jl | 35 ++++++----- src/EasyBuild/qft_circuit.jl | 6 +- src/EasyBuild/supremacy_circuit.jl | 37 ++++-------- src/EasyBuild/variational_circuit.jl | 68 +++++----------------- test/easybuild/hamiltonians.jl | 2 +- test/easybuild/phaseestimation.jl | 3 +- test/easybuild/supremacy_circuit.jl | 1 + test/easybuild/variational_circuit.jl | 10 +--- 14 files changed, 125 insertions(+), 129 deletions(-) diff --git a/src/EasyBuild/block_extension/FSimGate.jl b/src/EasyBuild/block_extension/FSimGate.jl index bfdd88d5b..64525b196 100644 --- a/src/EasyBuild/block_extension/FSimGate.jl +++ b/src/EasyBuild/block_extension/FSimGate.jl @@ -1,7 +1,14 @@ -export FSimGate +export FSimGate, fsim_block -# https://arxiv.org/pdf/1711.04789.pdf -# Google supremacy paper +""" + FSimGate{T<:Number} <: PrimitiveBlock{2} + +The two parameter `FSim` gate. + +References +------------------------- +* Arute, Frank, et al. "Quantum supremacy using a programmable superconducting processor." Nature 574.7779 (2019): 505-510. +""" mutable struct FSimGate{T<:Number} <: PrimitiveBlock{2} theta::T phi::T @@ -28,4 +35,17 @@ function YaoAPI.setiparams!(fs::FSimGate{T}, θ, ϕ) where T end YaoBlocks.@dumpload_fallback FSimGate FSimGate -YaoBlocks.Optimise.to_basictypes(fs::FSimGate) = fsim_block(fs.theta, fs.phi) \ No newline at end of file +YaoBlocks.Optimise.to_basictypes(fs::FSimGate) = fsim_block(fs.theta, fs.phi) + +""" + fsim_block(θ::Real, ϕ::Real) + +The circuit representation of FSim gate. +""" +function fsim_block(θ::Real, ϕ::Real) + if θ ≈ π/2 + return cphase(2,2,1,-ϕ)*SWAP*rot(kron(Z,Z), -π/2)*put(2,1=>phase(-π/4)) + else + return cphase(2,2,1,-ϕ)*rot(SWAP,2*θ)*rot(kron(Z,Z), -θ)*put(2,1=>phase(θ/2)) + end +end \ No newline at end of file diff --git a/src/EasyBuild/block_extension/shortcuts.jl b/src/EasyBuild/block_extension/shortcuts.jl index 153a5c17e..f3f9eae43 100644 --- a/src/EasyBuild/block_extension/shortcuts.jl +++ b/src/EasyBuild/block_extension/shortcuts.jl @@ -1,5 +1,5 @@ -export cphase, ISWAP, SqrtX, SqrtY, SqrtW -export ISWAPGate, SqrtXGate, SqrtYGate, SqrtWGate +export ISWAP, SqrtX, SqrtY, SqrtW, singlet_block +export ISWAPGate, SqrtXGate, SqrtYGate, SqrtWGate, CPhaseGate const CPhaseGate{N, T} = ControlBlock{N,<:ShiftGate{T},<:Any} @@ -9,17 +9,9 @@ const CPhaseGate{N, T} = ControlBlock{N,<:ShiftGate{T},<:Any} # √W is a non-Clifford gate @const_gate SqrtW = mat(rot((X+Y)/sqrt(2), π/2)) -singlet_block() = chain(put(2, 1=>chain(X, H)), control(2, -1, 2=>X)) - """ - fsim_block(θ::Real, ϕ::Real) + singlet_block(θ::Real, ϕ::Real) -The circuit representation of FSim gate. +The circuit block for initialzing a singlet state. """ -function fsim_block(θ::Real, ϕ::Real) - if θ ≈ π/2 - return cphase(2,2,1,-ϕ)*SWAP*rot(kron(Z,Z), -π/2)*put(2,1=>phase(-π/4)) - else - return cphase(2,2,1,-ϕ)*rot(SWAP,2*θ)*rot(kron(Z,Z), -θ)*put(2,1=>phase(θ/2)) - end -end \ No newline at end of file +singlet_block() = chain(put(2, 1=>chain(X, H)), control(2, -1, 2=>X)) \ No newline at end of file diff --git a/src/EasyBuild/general_U4.jl b/src/EasyBuild/general_U4.jl index f411c1a68..64413b8ec 100644 --- a/src/EasyBuild/general_U4.jl +++ b/src/EasyBuild/general_U4.jl @@ -4,6 +4,12 @@ Impliments PRA 69.062321. export general_U2, general_U4 +""" + general_U2(θ1, θ2, θ3; ϕ=nothing) + +A general single qubits gate: ``e^(iϕ)R_z(θ_3)R_y(θ_2)R_z(θ_1)``. +Leave `ϕ` as `nothing` to fix the global phase. +""" function general_U2(θ1, θ2, θ3; ϕ=nothing) gate = Rz(θ3) * Ry(θ2) * Rz(θ1) if ϕ !== nothing diff --git a/src/EasyBuild/google53.jl b/src/EasyBuild/google53.jl index c8fc74f18..b91a274e3 100644 --- a/src/EasyBuild/google53.jl +++ b/src/EasyBuild/google53.jl @@ -78,7 +78,11 @@ end """ rand_google53(depth::Int; nbits=53) -> AbstactBlock -random google supremacy circuit with 53 qubits. +Google supremacy circuit with 53 qubits, also know as the Sycamore quantum supremacy circuits. + +References +------------------------- +* Arute, Frank, et al. "Quantum supremacy using a programmable superconducting processor." Nature 574.7779 (2019): 505-510. """ function rand_google53(depth::Int; nbits::Int=53) c = chain(nbits) diff --git a/src/EasyBuild/hadamardtest.jl b/src/EasyBuild/hadamardtest.jl index 69a86dd42..4af7bd07e 100644 --- a/src/EasyBuild/hadamardtest.jl +++ b/src/EasyBuild/hadamardtest.jl @@ -1,7 +1,13 @@ export hadamard_test, hadamard_test_circuit, swap_test_circuit """ -see WiKi. + hadamard_test_circuit(U::AbstractBlock, ϕ::Real) + +The Hadamard test circuit. + +References +----------------------- +* [Wiki](https://en.wikipedia.org/wiki/Hadamard_test_(quantum_computation)) """ function hadamard_test_circuit(U::AbstractBlock{N}, ϕ::Real) where N chain(N+1, put(N+1, 1=>H), @@ -18,8 +24,14 @@ function hadamard_test(U::AbstractBlock{N}, reg::AbstractRegister, ϕ::Real) whe end """ -Estimation of overlap between multiple density matrices. -PRL 88.217901 + swap_test_circuit(nbit::Int, nstate::Int, ϕ::Real) + +The swap test circuit for computing the overlap between multiple density matrices. +The `nbit` and `nstate` specifies the number of qubit in each state and how many state we want to compare. + +References +----------------------- +* Ekert, Artur K., et al. "Direct estimations of linear and nonlinear functionals of a quantum state." Physical review letters 88.21 (2002): 217901. """ function swap_test_circuit(nbit::Int, nstate::Int, ϕ::Real) N = nstate*nbit + 1 diff --git a/src/EasyBuild/hamiltonians.jl b/src/EasyBuild/hamiltonians.jl index 96a3cd1d6..79510cd76 100644 --- a/src/EasyBuild/hamiltonians.jl +++ b/src/EasyBuild/hamiltonians.jl @@ -3,7 +3,12 @@ export heisenberg, transverse_ising """ heisenberg(nbit::Int; periodic::Bool=true) -1D heisenberg hamiltonian, for its ground state, refer `PRB 48, 6141`. +1D Heisenberg hamiltonian defined as ``\\sum_{i=1}^{n} X_{i}X_{i+1} + Y_{i}Y_{i+1} + Z_{i}Z_{i+1}``, where ``n`` is specified by `nbit`. +`periodic` means the boundary condition is periodic. + +References +---------------------- +* de Oliveira, Mário J. "Ground-state properties of the spin-1/2 antiferromagnetic Heisenberg chain obtained by use of a Monte Carlo method." Physical Review B 48.9 (1993): 6141-6143. """ function heisenberg(nbit::Int; periodic::Bool=true) map(1:(periodic ? nbit : nbit-1)) do i @@ -13,13 +18,14 @@ function heisenberg(nbit::Int; periodic::Bool=true) end """ - transverse_ising(nbit::Int; periodic::Bool=true) + transverse_ising(nbit::Int, h::Number; periodic::Bool=true) -1D transverse ising hamiltonian. +1D transverse Ising hamiltonian defined as ``\\sum_{i=1}^{n} hX_{i} + Z_{i}Z_{i+1}``, where ``n`` is specified by `nbit`. +`periodic` means the boundary condition is periodic. """ -function transverse_ising(nbit::Int; periodic::Bool=true) +function transverse_ising(nbit::Int, h::Number; periodic::Bool=true) ising_term = map(1:(periodic ? nbit : nbit-1)) do i repeat(nbit,Z,(i,i%nbit+1)) end |> sum - ising_term + sum(map(i->put(nbit,i=>X), 1:nbit)) + ising_term + h*sum(map(i->put(nbit,i=>X), 1:nbit)) end diff --git a/src/EasyBuild/phaseestimation.jl b/src/EasyBuild/phaseestimation.jl index f40c2af46..0bfeb307a 100644 --- a/src/EasyBuild/phaseestimation.jl +++ b/src/EasyBuild/phaseestimation.jl @@ -1,12 +1,19 @@ -export phase_estimation_circuit, projection_analysis +export phase_estimation_circuit, phase_estimation_analysis + """ - phase_estimation_circuit(UG, n_reg, n_b) -> ChainBlock -phase estimation circuit. - * `UG`: the input unitary matrix. - * `n_reg`: the number of bits to store phases, - * `n_b`: the number of bits to store vector. + phase_estimation_circuit(unitarygate::GeneralMatrixBlock, n_reg, n_b) -> ChainBlock + +Phase estimation circuit. Input arguments are + +* `unitarygate`: the input unitary matrix. +* `n_reg`: the number of bits to store phases, +* `n_b`: the number of bits to store vector. + +References +---------------------- +[Wiki](https://en.wikipedia.org/wiki/Quantum_phase_estimation_algorithm) """ -function phase_estimation_circuit(UG::GeneralMatrixBlock, n_reg::Int, n_b::Int) +function phase_estimation_circuit(unitarygate::GeneralMatrixBlock, n_reg::Int, n_b::Int) nbit = n_b + n_reg # Apply Hadamard Gate. hs = repeat(nbit, H, 1:n_reg) @@ -14,9 +21,9 @@ function phase_estimation_circuit(UG::GeneralMatrixBlock, n_reg::Int, n_b::Int) # Construct a control circuit. control_circuit = chain(nbit) for i = 1:n_reg - push!(control_circuit, control(nbit, (i,), (n_reg+1:nbit...,)=>UG)) + push!(control_circuit, control(nbit, (i,), (n_reg+1:nbit...,)=>unitarygate)) if i != n_reg - UG = matblock(mat(UG) * mat(UG)) + unitarygate = matblock(mat(unitarygate) * mat(unitarygate)) end end @@ -26,12 +33,14 @@ function phase_estimation_circuit(UG::GeneralMatrixBlock, n_reg::Int, n_b::Int) end """ - projection_analysis(evec::Matrix, reg::ArrayReg) -> Tuple -Analyse using state projection. + phase_estimation_analysis(eigenvectors::Matrix, reg::ArrayReg) -> Tuple + +Analyse phase estimation result using state projection. It returns a tuple of (most probable configuration, the overlap matrix, the relative probability for this configuration) +`eigenvectors` is the eigen vectors of the unitary gate matrix, while `reg` is the result of phase estimation. """ -function projection_analysis(evec::Matrix, reg::ArrayReg) - overlap = evec'*state(reg) +function phase_estimation_analysis(eigenvectors::AbstractMatrix, reg::ArrayReg) + overlap = eigenvectors'*state(reg) amp_relative = Float64[] bs = Int[] diff --git a/src/EasyBuild/qft_circuit.jl b/src/EasyBuild/qft_circuit.jl index 73d542f78..9a5f48104 100644 --- a/src/EasyBuild/qft_circuit.jl +++ b/src/EasyBuild/qft_circuit.jl @@ -10,7 +10,11 @@ cphase(nbits::Int, i::Int, j::Int, θ::T) where T = control(nbits, i, j=>shift( """ qft_circuit(n) -Create a Quantum Fourer Transform circuit. See also [`QFT`](@ref). +The quantum Fourer transformation (QFT) circuit. + +References +------------------------ +* [Wiki](https://en.wikipedia.org/wiki/Quantum_Fourier_transform) """ qft_circuit(n::Int) = chain(n, hcphases(n, i) for i = 1:n) hcphases(n, i) = chain(n, i==j ? put(i=>H) : cphase(n, j, i, 2π/(2^(j-i+1))) for j in i:n); \ No newline at end of file diff --git a/src/EasyBuild/supremacy_circuit.jl b/src/EasyBuild/supremacy_circuit.jl index 351ceaf10..170883755 100644 --- a/src/EasyBuild/supremacy_circuit.jl +++ b/src/EasyBuild/supremacy_circuit.jl @@ -1,16 +1,20 @@ export rand_supremacy2d -export pair_supremacy, print_square_bond, cz_entangler -""" -control-Z entangler. -""" + +# control-Z entangler. cz_entangler(n::Int, pairs) = chain(n, control(n, [ctrl], target=>Z) for (ctrl, target) in pairs) """ rand_supremacy2d(nx::Int, ny::Int, depth::Int) -> AbstactBlock -random supremacy circuit. +The circuit proposed for realizing quantum supermacy in a near-term device. -NOTE: the restriction to `T` gate is removed. +References +------------------------------- +* Boixo, Sergio, et al. "Characterizing quantum supremacy in near-term devices." Nature Physics 14.6 (2018): 595-600. + +!!! note + + Some restrictions are loosed, please check this circuit carefully. """ function rand_supremacy2d(nx::Int, ny::Int, depth::Int) nbits = nx*ny @@ -36,7 +40,7 @@ function rand_supremacy2d(nx::Int, ny::Int, depth::Int) return c end -"""obtain supremacy pairing patterns""" +# obtain supremacy pairing patterns function pair_supremacy(nx::Int, ny::Int; periodic=false) Kx = [0.25 0.5; 0.25 -0.5] Ky = [0.5 0.25; -0.5 0.25] @@ -57,21 +61,4 @@ function pair_supremacy(nx::Int, ny::Int; periodic=false) end return out -end - -print_square_bond(nx::Int, ny::Int, bonds) = print_square_bond(stdout, nx, ny, bonds) -function print_square_bond(io::IO, nx::Int, ny::Int, bonds) - li = LinearIndices((nx, ny)) - for j=1:ny - for i=1:nx - print(io, "∘") - i!=nx && print(io, ((li[i,j] => li[i+1,j]) in bonds || (li[i+1,j] => li[i,j]) in bonds) ? "---" : " ") - end - println(io) - j!=ny && for i=1:nx - print(io, ((li[i,j] => li[i,j+1]) in bonds || (li[i,j] => li[i,j+1]) in bonds) ? "|" : " ") - j!=ny && print(io, " ") - end - println(io) - end -end +end \ No newline at end of file diff --git a/src/EasyBuild/variational_circuit.jl b/src/EasyBuild/variational_circuit.jl index 79bf5796c..7d254ca9d 100644 --- a/src/EasyBuild/variational_circuit.jl +++ b/src/EasyBuild/variational_circuit.jl @@ -1,22 +1,19 @@ using YaoArrayRegister.StatsBase: sample -export pair_ring, pair_square -export rotor, merged_rotor, rotorset export variational_circuit -export rand_single_gate, rand_gate, rand_circuit ################## Entangler ################### """ pair_ring(n::Int) -> Vector -Pair ring. +Pair ring entanglement layout. """ pair_ring(n::Int) = [i=>mod(i, n)+1 for i=1:n] """ pair_square(m::Int, n::Int) -> Vector -Pair square. +Pair square entanglement layout. """ function pair_square(m::Int, n::Int; periodic=false) res = Vector{Pair{Int, Int}}(undef, (m-!periodic)*n+m*(n-!periodic)) @@ -83,17 +80,19 @@ rotorset(mode::Symbol, nbit::Int, noleading::Bool=false, notrailing::Bool=false) variational_circuit(nbit[, nlayer][, pairs]; mode=:Split, do_cache=false, entangler=cnot) A kind of widely used differentiable quantum circuit, angles in the circuit is randomely initialized. - - * pairs: list of `Pair`s for entanglers in a layer, default to `pair_ring` structure, - * mode: :Split or :Merged, - * do_cache: cache the entangler matrix, - * entangler: a constructor returns a two qubit gate, `f(n,i,j) -> gate`. - The default value is `cnot(n,i,j)`. - -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. +Input arguments are + +* `pairs` is list of `Pair`s for entanglers in a layer, default to `pair_ring` structure, +* `mode` can be :Split or :Merged, +* `do_cache` decides whether cache the entangler matrix or not, +* `entangler` is a constructor returns a two qubit gate, `f(n,i,j) -> gate`. + The default value is `cnot(n,i,j)`. + +References +------------------------- +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 variational_circuit(nbit, nlayer, pairs; mode=:Split, do_cache=false, entangler=cnot) circuit = chain(nbit) @@ -112,39 +111,4 @@ end variational_circuit(n::Int; kwargs...) = variational_circuit(n, 3, pair_ring(n); kwargs...) -variational_circuit(nbit::Int, nlayer::Int; kwargs...) = variational_circuit(nbit, nlayer, pair_ring(nbit), kwargs...) - -############### 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 +variational_circuit(nbit::Int, nlayer::Int; kwargs...) = variational_circuit(nbit, nlayer, pair_ring(nbit), kwargs...) \ No newline at end of file diff --git a/test/easybuild/hamiltonians.jl b/test/easybuild/hamiltonians.jl index af1bac017..9f7b482f9 100644 --- a/test/easybuild/hamiltonians.jl +++ b/test/easybuild/hamiltonians.jl @@ -6,6 +6,6 @@ using Yao.ConstGate nbit = 8 h = heisenberg(nbit) |> cache @test ishermitian(h) - h = transverse_ising(nbit) + h = transverse_ising(nbit, 1.0) @test ishermitian(h) end diff --git a/test/easybuild/phaseestimation.jl b/test/easybuild/phaseestimation.jl index 42a6453b1..5d8f2b145 100644 --- a/test/easybuild/phaseestimation.jl +++ b/test/easybuild/phaseestimation.jl @@ -1,5 +1,4 @@ using Yao.EasyBuild -using Yao.EasyBuild: projection_analysis using BitBasis using Test, LinearAlgebra @@ -63,6 +62,6 @@ end apply!(reg, pe) # measure - bs, proj, amp_relative = projection_analysis(evec, focus!(reg, M+1:M+N)) + bs, proj, amp_relative = phase_estimation_analysis(evec, focus!(reg, M+1:M+N)) @test isapprox(ϕs, bfloat.(bs, nbits=M), atol=0.05) end \ No newline at end of file diff --git a/test/easybuild/supremacy_circuit.jl b/test/easybuild/supremacy_circuit.jl index bf2612302..4de922c37 100644 --- a/test/easybuild/supremacy_circuit.jl +++ b/test/easybuild/supremacy_circuit.jl @@ -1,4 +1,5 @@ using Yao.EasyBuild +using Yao.EasyBuild: pair_supremacy, cz_entangler using Test @testset "SqrtX" begin diff --git a/test/easybuild/variational_circuit.jl b/test/easybuild/variational_circuit.jl index 9a47a6e8e..6e4de87a1 100644 --- a/test/easybuild/variational_circuit.jl +++ b/test/easybuild/variational_circuit.jl @@ -1,5 +1,6 @@ using Test using Yao.EasyBuild +using Yao.EasyBuild: pair_ring, pair_square, merged_rotor, rotor, rotorset @testset "pairs geometries" begin @test pair_ring(3) == [1=>2,2=>3,3=>1] @@ -16,15 +17,6 @@ using Yao.EasyBuild end 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.0) @test merged_rotor(false, false) == merged_rotor() == chain(Rz(0.0), Rx(0.0), Rz(0.0))