Grover’s Algorithm#
- grovers_alg(qv_list, oracle_function, kwargs={}, iterations=0, winner_state_amount=None, exact=False)[source]#
Applies Grover’s algorithm to a given oracle (in the form of a Python function).
- Parameters:
- qv_listQuantumVariable or list[QuantumVariable]
A (list of) QuantumVariables on which to execute Grover’s algorithm.
- oracle_functionfunction
A Python function tagging the winner states.
- kwargsdict, optional
A dictionary containing keyword arguments for the oracle. The default is {}.
- iterationsint, optional
The amount of Grover iterations to perfrom.
- winner_state_amountint, optional
If not given the amount of iterations, the established formula will be used based on the amount of winner states. The default is 1.
- exactbool, optional
If set to True, the exact version <https://arxiv.org/pdf/quant-ph/0106071.pdf> of Grover’s algorithm will be evaluated. For this, the correct
winner_state_amount
has to be supplied and the oracle has to support the keyword argumentphase
which specifies how much the winner states are phaseshifted (in standard Grover this would be \(\pi\)).
- Raises:
- Exception
Applied oracle introducing new QuantumVariables without uncomputing/deleting
Examples
We construct an oracle that tags the states -3 and 2 on two QuantumFloats and apply Grover’s algorithm to it.
from qrisp import QuantumFloat #Create list of QuantumFloats qf_list = [QuantumFloat(2, signed = True), QuantumFloat(2, signed = True)] from qrisp.grover import tag_state, grovers_alg def test_oracle(qf_list): tag_dic = {qf_list[0] : -3, qf_list[1] : 2} tag_state(tag_dic) grovers_alg(qf_list, test_oracle)
>>> from qrisp.misc import multi_measurement >>> print(multi_measurement(qf_list)) {(-3, 2): 0.9966, (0, 0): 0.0001, (0, 1): 0.0001, (0, 2): 0.0001, (0, 3): 0.0001, (0, -4): 0.0001, (0, -3): 0.0001, (0, -2): 0.0001, (0, -1): 0.0001, (1, 0): 0.0001, (1, 1): 0.0001, (1, 2): 0.0001, (1, 3): 0.0001, (1, -4): 0.0001, (1, -3): 0.0001, (1, -2): 0.0001, (1, -1): 0.0001, (2, 0): 0.0001, (2, 1): 0.0001, (2, 2): 0.0001, (2, 3): 0.0001, (2, -4): 0.0001, (2, -3): 0.0001, (2, -2): 0.0001, (2, -1): 0.0001, (3, 0): 0.0001, (3, 1): 0.0001, (3, 2): 0.0001, (3, 3): 0.0001, (3, -4): 0.0001, (3, -3): 0.0001, (3, -2): 0.0001, (3, -1): 0.0001, (-4, 0): 0.0001, (-4, 1): 0.0001, (-4, 2): 0.0001, (-4, 3): 0.0001, (-4, -4): 0.0001, (-4, -3): 0.0001, (-4, -2): 0.0001, (-4, -1): 0.0001, (-3, 0): 0.0001, (-3, 1): 0.0001, (-3, 3): 0.0001, (-3, -4): 0.0001, (-3, -3): 0.0001, (-3, -2): 0.0001, (-3, -1): 0.0001, (-2, 0): 0.0001, (-2, 1): 0.0001, (-2, 2): 0.0001, (-2, 3): 0.0001, (-2, -4): 0.0001, (-2, -3): 0.0001, (-2, -2): 0.0001, (-2, -1): 0.0001, (-1, 0): 0.0001, (-1, 1): 0.0001, (-1, 2): 0.0001, (-1, 3): 0.0001, (-1, -4): 0.0001, (-1, -3): 0.0001, (-1, -2): 0.0001, (-1, -1): 0.0001}
Exact Grovers Algorithm
In the next example, we will showcase the
exact
functionality. For this we create an oracle, which tags all the states of a QuantumVariable, that contain 3 ones and 2 zeros.To count the amount of ones we use quantum phase estimation on the operator
\[U = \text{exp}\left(\frac{i 2 \pi}{2^k} \sum_{i = 0}^{n-1} ( 1 - \sigma_{z}^i )\right)\]from qrisp import QPE, p, QuantumVariable, lifted from qrisp.grover import grovers_alg, tag_state import numpy as np def U(qv, prec = None, iter = 1): for i in range(qv.size): p(iter*2*np.pi/2**prec, qv[i]) @lifted def count_ones(qv): prec = int(np.ceil(np.log2(qv.size+1))) res = QPE(qv, U, precision = prec, iter_spec = True, kwargs = {"prec" : prec}) return res<<prec
Quick test:
>>> qv = QuantumVariable(5) >>> qv[:] = {"11000" : 1, "11010" : 1, "11110" : 1} >>> count_qf = count_ones(qv) >>> count_qf.qs.statevector() sqrt(3)*(|11000>*|2> + |11010>*|3> + |11110>*|4>)/3
We now define the oracle
def counting_oracle(qv, phase = np.pi, k = 1): count_qf = count_ones(qv) tag_state({count_qf : k}, phase = phase) count_qf.uncompute()
And evaluate Grover’s algorithm
n = 5 k = 3 qv = QuantumVariable(n) import math grovers_alg(qv, counting_oracle, exact = True, winner_state_amount = math.comb(n,k), kwargs = {"k" : k}) # noqa
>>> print(qv) {'11100': 0.1, '11010': 0.1, '10110': 0.1, '01110': 0.1, '11001': 0.1, '10101': 0.1, '01101': 0.1, '10011': 0.1, '01011': 0.1, '00111': 0.1}
We see that contrary to regular Grover’s algorithm, the states which have not been tagged by the oracle have 0 percent measurement probability.