|
| 1 | +# # [Grover Search](@id Grover) |
| 2 | +using Yao |
| 3 | +using YaoExtensions: variational_circuit |
| 4 | +using LinearAlgebra |
| 5 | + |
| 6 | +# ## Grover Step |
| 7 | +# A single grover step is consist of applying oracle circuit and reflection circuit. |
| 8 | +# The `reflection_circuit` function takes the wave function generator `U` as the input and returns `U|0><0|U'`. |
| 9 | +function grover_step!(reg::AbstractRegister, oracle, U::AbstractBlock) |
| 10 | + apply!(reg |> oracle, reflect_circuit(U)) |
| 11 | +end |
| 12 | + |
| 13 | +function reflect_circuit(gen::AbstractBlock{N}) where N |
| 14 | + reflect0 = control(N, -collect(1:N-1), N=>-Z) |
| 15 | + chain(gen', reflect0, gen) |
| 16 | +end |
| 17 | + |
| 18 | +# Compute the propotion of target states to estimate the number of iterations, |
| 19 | +# which requires computing the output state. |
| 20 | +function solution_state(oracle, gen::AbstractBlock{N}) where N |
| 21 | + reg= zero_state(N) |> gen |
| 22 | + reg.state[real.(statevec(ArrayReg(ones(ComplexF64, 1<<N)) |> oracle)) .> 0] .= 0 |
| 23 | + normalize!(reg) |
| 24 | +end |
| 25 | + |
| 26 | +function num_grover_step(oracle, gen::AbstractBlock{N}) where N |
| 27 | + reg = zero_state(N) |> gen |
| 28 | + ratio = abs2(solution_state(oracle, gen)'*reg) |
| 29 | + Int(round(pi/4/sqrt(ratio)))-1 |
| 30 | +end |
| 31 | + |
| 32 | +# #### Run |
| 33 | +# First, we define the problem by an oracle, it finds bit string `bit"000001100100"`. |
| 34 | +num_bit = 12 |
| 35 | +oracle = matblock(Diagonal((v = ones(ComplexF64, 1<<num_bit); v[Int(bit"000001100100")+1]*=-1; v))) |
| 36 | + |
| 37 | +# then solve the above problem |
| 38 | +gen = repeat(num_bit, H, 1:num_bit) |
| 39 | +reg = zero_state(num_bit) |> gen |
| 40 | + |
| 41 | +target_state = solution_state(oracle, gen) |
| 42 | + |
| 43 | +for i = 1:num_grover_step(oracle, gen) |
| 44 | + grover_step!(reg, oracle, gen) |
| 45 | + overlap = abs(reg'*target_state) |
| 46 | + println("step $(i-1), overlap = $overlap") |
| 47 | +end |
| 48 | + |
| 49 | +# ## Rejection Sampling |
| 50 | +# In practise, it is often not possible to determine the number of iterations before actual running. |
| 51 | +# we can use rejection sampling technique to avoid estimating the number of grover steps. |
| 52 | + |
| 53 | +using Random; Random.seed!(2) #src |
| 54 | + |
| 55 | +# In a single try, we `apply` the grover algorithm for `nstep` times. |
| 56 | +function single_try(oracle, gen::AbstractBlock{N}, nstep::Int; nbatch::Int) where N |
| 57 | + reg = zero_state(N+1; nbatch=nshot) |
| 58 | + focus!(reg, 1:N) do r |
| 59 | + r |> gen |
| 60 | + for i = 1:nstep |
| 61 | + grover_step!(r, oracle, gen) |
| 62 | + end |
| 63 | + return r |
| 64 | + end |
| 65 | + reg |> checker |
| 66 | + res = measure_remove!(reg, (N+1)) |
| 67 | + return res, reg |
| 68 | +end |
| 69 | + |
| 70 | +# After running the grover search, we have a checker program that flips the ancilla qubit |
| 71 | +# if the output is the desired value, we assume the checker program can be implemented in polynomial time. |
| 72 | +# to gaurante the output is correct. |
| 73 | +# We contruct a checker "program", if the result is correct, flip the ancilla qubit |
| 74 | +ctrl = -collect(1:num_bit); ctrl[[3,6,7]] *= -1 |
| 75 | +checker = control(num_bit+1,ctrl, num_bit+1=>X) |
| 76 | + |
| 77 | +# The register is batched, with batch dimension `nshot`. |
| 78 | +# [`focus!`](@ref Yao.focus!) views the first 1-N qubts as system. |
| 79 | +# For a batched register, [`measure_remove!`](@ref Yao.measure_remove!) |
| 80 | +# returns a vector of bitstring as output. |
| 81 | + |
| 82 | +# #### Run |
| 83 | +maxtry = 100 |
| 84 | +nshot = 3 |
| 85 | + |
| 86 | +for nstep = 0:maxtry |
| 87 | + println("number of iter = $nstep") |
| 88 | + res, reg = single_try(oracle, gen, nstep; nbatch=3) |
| 89 | + |
| 90 | + ## success! |
| 91 | + if any(==(1), res) |
| 92 | + overlap_final = viewbatch(reg, findfirst(==(1), res))'*target_state |
| 93 | + println("success, overlap = $(overlap_final)") |
| 94 | + break |
| 95 | + end |
| 96 | +end |
| 97 | + |
| 98 | +# The final state has an overlap of `1` with the target state. |
| 99 | + |
| 100 | +# ## Amplitude Amplification |
| 101 | +# Given a circuit to generate a state, |
| 102 | +# 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. |
| 103 | +# We can construct an oracle |
| 104 | +evidense = [1, 3, -4, 5, -6, 8, 9, 11, 12] |
| 105 | +function inference_oracle(nbit::Int, locs::Vector{Int}) |
| 106 | + control(nbit, locs[1:end-1], abs(locs[end]) => (locs[end]>0 ? Z : -Z)) |
| 107 | +end |
| 108 | +oracle = inference_oracle(nqubits(reg), evidense) |
| 109 | + |
| 110 | +# We use a variational circuit generator defined in `YaoExtensions` |
| 111 | +gen = dispatch!(variational_circuit(num_bit), :random) |
| 112 | +reg = zero_state(num_bit) |> gen |
| 113 | + |
| 114 | +# #### Run |
| 115 | +solution = solution_state(oracle, gen) |
| 116 | +for i = 1:num_grover_step(oracle, gen) |
| 117 | + grover_step!(reg, oracle, gen) |
| 118 | + println("step $(i-1), overlap = $(abs(reg'*solution))") |
| 119 | +end |
0 commit comments