A vault has N = 2^n possible codes, numbered 0 to N-1, and exactly one opens it: the marked item. You cannot see which. You get a sealed phase oracle oracle(state): give it a state (a list of N amplitudes, normalised so that the sum of |a_i|^2 is 1) and it returns a new list in which the amplitude of the marked item has changed sign. In formula: it multiplies the amplitude of item x by (-1)^{f(x)}, where f(x) = 1 only for the marked item. A state of the wrong length or not normalised raises ValueError.
Every oracle call is expensive, and a real chip lets you measure but never read its amplitudes. Play by those rules, with this exact procedure. Write grover_search(n, oracle, seed):
- Create one random generator for the whole search:
rng = random.Random(seed). - Search. Start with every amplitude equal to 1/\sqrt N. Run R = \lfloor \frac{\pi}{4}\sqrt N \rfloor rounds (
math.floor(math.pi / 4 * math.sqrt(N))). One round: call the oracle on the state, then replace every amplitude a by 2m - a, where m is the mean of the N amplitudes the oracle returned. - Measure once, by the Born rule: outcome i has probability p_i = |a_i|^2. Draw
r = rng.random()and pick the first outcomeiwhose running totalp[0] + ... + p[i]is greater thanr(if rounding leaves no suchi, pick the last outcome with nonzero probability). - Check the outcome with exactly one more oracle call (think about which state to give it). If it is the marked item, return it. Otherwise go back to step 2 with a fresh start state, using the same
rng.
The tests call with_box(grover_search, n, seed), which hides the marked item, runs your function and returns {"answer": ..., "calls": ..., "rounds": R, "marked": ...}. A test passes when your answer is the marked item and you used exactly as many oracle calls as the procedure above needs for that seed (so every attempt costs R + 1 calls). Far too many calls raise TooManyCalls. Try it with Run: print(with_box(grover_search, 3, 31)).
Examples
Input: with_box(grover_search, 2, 1)
Output: correct with 2 oracle calls: one round always finds the code among 4
Input: with_box(grover_search, 3, 31)
Output: correct with 6 oracle calls: the first measurement (success 94.5%) misses,
the second attempt finds the code
Input: with_box(grover_search, 1, 11)
Output: correct with 4 oracle calls: with 2 codes each attempt succeeds only half the time
Constraints
1 <= n <= 10randomandmathare available; use only the one generatorrandom.Random(seed)for the draws
Goals
- Run Grover's search against a sealed phase oracle, with the prescribed number of rounds
- Measure the final state with a reproducible seeded draw
- Check the measured item with one more oracle call and repeat the whole search when it is wrong