Grover Search
The Grover.jl module implements a Grover's search use-case. Assisted by Oracle.jl and Diffusion.jl, the appropriate chosen test state is marked by applying an $n$CZ gate, and appropriately amplified through the required number of iterations $r\approx \pi\sqrt{2^{n+1}}/4$.
To apply the Grover search algorithm, we require additional functionalities in the form an oracle to select the required state, and a diffusion operator to shift the state ampltiudes.
API
QXZoo.Grover.bitstring_ncu!
— Functionbitstring_ncu(cct::Circuit.Circ, bitstring::Integer, ctrl_indices::Vector, tgt_idx::Int, U::GateOps.GateSymbol, aux_indices::Vector=Int[])
Takes bitstring as the binary pattern and indices as the qubits to operate upon. Applies the appropriate PauliX gates to the control lines to call the NCU with the given matrix. Uses aux_indices to reduce Circuit depth by expanding width if |aux|+2 >= |ctrl|. If not specified, uses default quadratic gate expansion.
QXZoo.Grover.bitstring_phase_oracle!
— Functionbitstring_phase_oracle(cct::Circuit.Circ, bitstring::Integer, ctrl_indices::Vector, tgt_idx::Int, aux_indices::Vector=Int[])
Applies PauliX gates to the appropriate lines in the Circuit, then applies a n-controlled PauliZ to mark the state. Uses aux qubits to reduce circuit depth if |aux|+2 >= |ctrl|. If not provided, uses quadratic gate expansion
QXZoo.Grover.apply_diffusion!
— Functionapply_diffusion(cct::Circuit.Circ, ctrl_indices::Vector, tgt_index::Int, aux_indices::Vector=Int[] )
Application of the Grover diffusion operator to marked register. Uses additionally provided auxiliary qubits to reduce depth.
QXZoo.Grover.run_grover!
— Methodrun_grover!(cct::Circuit.Circ, qubit_indices::Vector, state::Integer=1, qubit_aux_indices::Vector=Int[])
Generates a Grover search Circuit sample, marking the state defined by state
and performing iterations to amplify the desired result upon measurement.
QXZoo.Grover.mark_state!
— Methodmark_state!(cct::Circuit.Circ, state::Integer, qubit_indices::Vector, qubit_aux_indices::Vector)
Applies the state marking procedure of the Grover iteration.
QXZoo.Grover.apply_grover_iteration!
— Methodapply_grover_iteration!(cct::Circuit.Circ, qubit_indices::Vector, qubit_aux_indices::Vector)
Applies a single Grover iteration. To be used following mark_state!
QXZoo.Grover.state_init!
— Methodstate_init!(cct::Circuit.Circ, qubit_indices::Vector)
Initialises the state to the required target; defaults to $H^{\otimes n}\vert \psi \rangle$ . Override for custom initialisation.
QXZoo.Grover.calc_iterations
— Methodcalc_iterations(num_qubits::Integer)
Calculate the required number of iterations to maximise the state's amplitude.
Example
To use the Grover module, we provide example code below to search for a state in a 5-qubit quantum register marked by bit-pattern 11 (0b01011).
using QXZoo
# Set 10-qubit limit on circuit
num_qubits = 10
# Set bit-pattern to 11 (0b01011)
bit_pattern = 11
# Create empty circuit with qiven qubit count
cct = QXZoo.Circuit.Circ(num_qubits)
# Run Grover algorithm for given oracle bit-pattern
QXZoo.Grover.run_grover!(cct, collect(1:num_qubits), bit_pattern)
println(cct)
10 qubits with 349554 gate-calls using 31 unique gates.
Similarly, for an optimised variant of the same operations using more qubits:
using QXZoo
# Set 10-qubit limit on Grover circuit (aux assisted)
num_qubits = 17
qubits_range = 1:Int((num_qubits+1)/2) + 1
aux_range = Int((num_qubits+1)/2 + 2):num_qubits
# Set bit-pattern to 11 (0b01011)
bit_pattern = 11
# Create empty circuit with qiven qubit count
cct = QXZoo.Circuit.Circ(num_qubits)
# Run Grover algorithm for given oracle bit-pattern
QXZoo.Grover.run_grover!(cct, collect(qubits_range), bit_pattern, collect(aux_range))
println(cct)
17 qubits with 8798 gate-calls using 5 unique gates.