From 0949e79827d53af99e09255c845f86bf5785dfef Mon Sep 17 00:00:00 2001 From: Katie McCormick Date: Tue, 12 May 2026 13:39:36 -0700 Subject: [PATCH 1/3] update grover's module --- .../modules/computer-science/grovers.ipynb | 507 +++++++++++------- .../grovers/grover-geometric-reflections.avif | Bin 0 -> 20003 bytes .../grovers/grover-geometric-setup.avif | Bin 0 -> 17811 bytes .../grovers/minesweeper-grid-labeled.avif | Bin 0 -> 9034 bytes .../grovers/minesweeper-grid.avif | Bin 0 -> 5855 bytes 5 files changed, 324 insertions(+), 183 deletions(-) create mode 100644 public/learning/images/modules/computer-science/grovers/grover-geometric-reflections.avif create mode 100644 public/learning/images/modules/computer-science/grovers/grover-geometric-setup.avif create mode 100644 public/learning/images/modules/computer-science/grovers/minesweeper-grid-labeled.avif create mode 100644 public/learning/images/modules/computer-science/grovers/minesweeper-grid.avif diff --git a/learning/modules/computer-science/grovers.ipynb b/learning/modules/computer-science/grovers.ipynb index 06b58d88aec..6a563e7406c 100644 --- a/learning/modules/computer-science/grovers.ipynb +++ b/learning/modules/computer-science/grovers.ipynb @@ -95,7 +95,7 @@ "id": "4f900ae6", "metadata": {}, "source": [ - "## Math\n", + "## Theory\n", "Suppose there exists a function $f$ that maps binary strings to a single binary variable, meaning\n", "$$\n", "f: \\Sigma^n \\rightarrow \\Sigma\n", @@ -130,7 +130,7 @@ "id": "a1a51eb6", "metadata": {}, "source": [ - "## Sketch of circuits in Grover's algorithm\n", + "### Sketch of circuits in Grover's algorithm\n", "\n", "A full mathematical walkthrough of Grover's algorithm can be found, for example, in [Fundamentals of quantum algorithms](/learning/courses/fundamentals-of-quantum-algorithms), a course by John Watrous on IBM Quantum Learning. A condensed treatment is provided in an appendix at the end of this module. But for now, we will only review the overall structure of the quantum circuit that implements Grover's algorithm.\n", "\n", @@ -265,22 +265,84 @@ "In the next section, we will put this algorithm into practice using real IBM® quantum computers." ] }, + { + "cell_type": "markdown", + "id": "geo_picture_01", + "metadata": {}, + "source": [ + "### The geometric picture\n", + "\n", + "The two-qubit example above showed how the algebra works out for a small case, but there is a much more intuitive way to understand Grover's algorithm: as a sequence of geometric reflections in a two-dimensional plane. Below we describe this picture. You can also see John Watrous's course [Fundamentals of Quantum Algorithms](/learning/courses/fundamentals-of-quantum-algorithms/grover-algorithm) for more details.\n", + "\n", + "**Setting up the plane.** We can decompose the initial superposition state $|\\psi\\rangle$ into two components. The correct state — the one we're searching for — we call $|A_1\\rangle.$ Every other state, lumped together, we call $|A_0\\rangle.$ By definition, $|A_1\\rangle$ and $|A_0\\rangle$ are orthogonal to one another, so we can plot them as perpendicular axes in an abstract, two-dimensional space. Since $|\\psi\\rangle$ is a linear combination of these two components, it sits at some small angle $\\theta$ to the $|A_0\\rangle$ axis — close to $|A_0\\rangle$, because at the start, only a tiny fraction of the state is in the correct component $|A_1\\rangle.$\n", + "\n", + "\n", + "**Reflections.** The key mathematical fact we need is that an operator of the form\n", + "$$\n", + "2|v\\rangle\\langle v| - I\n", + "$$\n", + "reflects any state about the axis defined by $|v\\rangle.$ To see why, consider two cases: a state along $|v\\rangle$ is left unchanged, and a state perpendicular to $|v\\rangle$ gets its sign flipped. Any other state can be decomposed into these two components, and the operator acts on each accordingly — which is exactly a reflection about $|v\\rangle.$\n", + "\n", + "It turns out that both the oracle and the diffusion steps in Grover's algorithm can be expressed as reflections in this geometric picture.\n", + "\n", + "**The oracle as a reflection.** The oracle flips the sign of the $|A_1\\rangle$ state and leaves everything else alone. That is the same as a reflection about the $|A_0\\rangle$ axis.\n", + "\n", + "![Geometric picture of the quantum state.](/learning/images/modules/computer-science/grovers/grover-geometric-setup.avif)\n", + "\n", + "**Diffusion as a reflection.** It is a little trickier to see how the diffusion operator is also a reflection. The diffusion operator is\n", + "$$\n", + "H^{\\otimes n}\\, Z_{\\text{OR}}\\, H^{\\otimes n}\n", + "$$\n", + "$Z_{\\text{OR}}$ by itself is a reflection about the all-zero state, since it flips the sign of every state that is not $|0\\rangle^{\\otimes n}.$ This can be written as $2|0\\rangle\\langle 0| - I.$ The surrounding Hadamard layers effectively perform a change of basis, transforming the axis of reflection. Recall that $H^{\\otimes n}$ maps $|0\\rangle^{\\otimes n}$ to the uniform superposition $|u\\rangle = \\frac{1}{\\sqrt{N}}\\sum_{x}|x\\rangle.$ Since the Hadamard is its own inverse, the full expression becomes\n", + "$$\n", + "H^{\\otimes n}\\left(2|0\\rangle\\langle 0| - I\\right)H^{\\otimes n} = 2|u\\rangle\\langle u| - I\n", + "$$\n", + "which is a reflection about $|u\\rangle.$ Since $|u\\rangle$ is very close to $|\\psi\\rangle$ (both are nearly along $|A_0\\rangle$), this second reflection sends the state to an angle $2\\theta$ from where it started.\n", + "\n", + "![Geometric interpretation of the Grover operator as a rotation.](/learning/images/modules/computer-science/grovers/grover-geometric-reflections.avif)\n", + "\n", + "**Rotation by $2\\theta$.** The combined effect of these two reflections is a rotation by $2\\theta$ toward $|A_1\\rangle.$ Each successive iteration of the Grover operator rotates the state by another $2\\theta.$\n", + "\n", + "**Optimal number of iterations.** Our goal is to rotate the state as close to $|A_1\\rangle$ as possible, which means rotating by a total of approximately $\\pi/2$ radians (a quarter turn). If each iteration contributes $2\\theta,$ the optimal number of iterations $t$ satisfies\n", + "$$\n", + "(2t + 1)\\theta \\approx \\frac{\\pi}{2}\n", + "$$\n", + "For a single solution among $N$ states, the initial angle is $\\theta \\approx \\sin^{-1}(1/\\sqrt{N}) \\approx 1/\\sqrt{N}$ (for large $N$). Substituting,\n", + "$$\n", + "t \\approx \\frac{\\pi}{4}\\sqrt{N} - \\frac{1}{2}\n", + "$$\n", + "This is where the famous $\\sqrt{N}$ speedup comes from: we only need $O(\\sqrt{N})$ iterations to reach the target, rather than the $O(N)$ checks a classical search would require.\n", + "\n", + "More generally, if there are $|A_1|$ solution states among $N$ total states, the optimal number of iterations is\n", + "$$\n", + "t \\approx \\frac{\\pi}{4}\\sqrt{\\frac{N}{|A_1|}} - \\frac{1}{2}\n", + "$$\n", + "\n", + "Note that if you apply too many iterations, you rotate past $|A_1\\rangle$ and the probability of finding your target state will start to decrease again. Finding the right number of iterations is important, though on noisy quantum hardware the experimentally optimal number may differ from this ideal formula." + ] + }, { "cell_type": "markdown", "id": "3fd8fbb3", "metadata": {}, "source": [ - "## Obvious caveat\n", + "### Why is Grover's algorithm useful?\n", + "\n", + "At this point you may be wondering: we just built an oracle that marks a target state — but to build it, we had to know the target state. So what are we actually searching for?\n", "\n", - "In order to apply Grover's algorithm, we had to build the Grover operator, which means we must be able to flip the phase on states that satisfy our solution criteria. This begs the question: if we know our solution set so well that we can design a quantum circuit to label each one, what are we searching for?! The answer is three-fold, and we will revisit this throughout the tutorial:\n", + "This is a fair question, and there are several good answers.\n", "\n", - "**(1) These kinds of query algorithms often involve two parties**: one who has the oracle that establishes the solution criteria, and another who is trying to guess/find a solution state. The fact that one person can build the oracle does not negate the need for search.\n", + "- **The query model is a theoretical tool.** The query model of computation was never designed to be directly practical. Its purpose is to give us a clean way to analyze algorithmic complexity by separating a problem into two parts: the oracle, and everything else. How hard is the search, given that verification is free? How does the number of queries scale with the size of the input? These are useful questions even if no real system works exactly this way.\n", "\n", - "**(2) There are problems for which it is easier to specify a solution criterion than it is to find the solution.** The best-known example of this is probably identifying prime factors of large numbers. Grover's algorithm is not particularly effective at solving that specific problem; we would use Shor's algorithm for prime factoring. This is just an example to point out that knowing the criterion on the behavior of a state is not always the same as knowing the state.\n", + "- You can also think of it as a **two-party activity**: one person knows the target state and builds the oracle; the other person's job is to find the answer using the oracle as a black box, with no peeking inside. In Activity 2 below, you will do exactly this with a partner.\n", "\n", - "**(3) Grover's algorithm does not only return classical data.** True, if we make a measurement of the final state after $t$ repetitions of the Grover operator, we are likely to obtain classical information identifying the solution state. But what if we don't want classical information; what if we want a solution state prepared on a quantum computer for further use in another algorithm? Grover's algorithm actually produces a quantum state with the solutions heavily weighted. So you may expect to find Grover's algorithm as a subroutine in more complicated quantum algorithms.\n", + "- **Amplitude amplification is a broadly useful subroutine.** Even if this first demonstration seems circular, the underlying mechanism — called *amplitude amplification* — shows up again and again in quantum computing. What we are really building here is an intuition for a tool that appears as a subroutine in many more complex quantum algorithms.\n", "\n", - "With these in mind, let us work through several examples. We'll begin with an example in which the solution state is clearly specified so we can follow the logic of the algorithm, and we will move on to examples in which the usefulness of Grover's algorithm becomes more clear." + "- **There are problems where you can build an oracle without knowing the answer.** The key insight is that there exists a whole class of problems for which it is very hard to *find* a solution, but very easy to *check* that a given solution is correct. Factoring is one example: given a product of two large primes, it is extremely difficult to determine what those primes are, but once you have them, you can easily multiply them together to verify. (We have a better algorithm than Grover's for factoring specifically — see Shor's algorithm — but this is far from the only problem with this feature.) Sudoku, constraint satisfaction, and even the classic game of minesweeper are all problems that are difficult to solve but easy to check.\n", + "\n", + "Why is that relevant? It means we can know all of the *conditions* and *requirements* that a solution must satisfy, and we can encode those requirements into a quantum circuit that serves as the oracle — even though we do not know the solution itself. Grover's algorithm will find it for us.\n", + "\n", + "With these ideas in mind, let us work through several examples. We will begin with an example in which the solution state is clearly specified so we can follow the logic of the algorithm. We will then move on to a two-party activity, and finally to an example in which the oracle is built from problem constraints rather than from knowledge of the answer." ] }, { @@ -288,7 +350,7 @@ "id": "90cfe463", "metadata": {}, "source": [ - "## General imports and approach\n", + "### General imports and approach\n", "\n", "We start by importing several necessary packages." ] @@ -304,7 +366,7 @@ "import math\n", "\n", "# Imports from Qiskit\n", - "from qiskit import QuantumCircuit\n", + "from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister\n", "from qiskit.circuit.library import grover_operator, MCMTGate, ZGate\n", "from qiskit.visualization import plot_distribution\n", "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager" @@ -338,7 +400,7 @@ "id": "23b5217f", "metadata": {}, "source": [ - "## Step 1: Map classical inputs to a quantum problem\n", + "### Step 1: Map classical inputs to a quantum problem\n", "\n", "We need the phase query gate to put an overall phase (-1) on solution states, and leave the non-solution states unaffected. Another way of saying this is that Grover's algorithm requires an oracle that specifies one or more marked computational basis states, where \"marked\" means a state with a phase of -1. This is done using a controlled-Z gate, or its multi-controlled generalization over $N$ qubits. To see how this works, consider a specific example of a bitstring `{110}`. We would like a circuit that acts on a state $|\\psi\\rangle = |q_2,q_1,q_0\\rangle$ and applies a phase if $|\\psi\\rangle = |011\\rangle$ (where we have flipped the order of the binary string, because of the notation in Qiskit, which puts the least significant (often 0) qubit on the right).\n", "\n", @@ -497,12 +559,11 @@ "id": "fb293e00", "metadata": {}, "source": [ - "As we argued above, we may need to apply the Grover operator multiple times. The optimal number of iterations, $t,$ to maximize the amplitude of the target state in the absence of noise can be obtained from this expression:\n", + "As we discussed in the geometric picture above, we may need to apply the Grover operator multiple times. The optimal number of iterations $t$ to maximize the amplitude of the target state in the absence of noise is\n", "$$\n", - "(2t+1)\\theta = (2t+1)\\sin^{-1}\\left( \\sqrt{\\frac{|A_1|}{N}}\\right) \\approx (2t+1)\\sqrt{\\frac{|A_1|}{N}} \\approx \\frac{\\pi}{2}\\\\\n", "t\\approx \\frac{\\pi}{4} \\sqrt{\\frac{N}{|A_1|}}-\\frac{1}{2}\n", "$$\n", - "Here $A_1$ is the number of solutions or target states. On modern noisy quantum computers, the experimentally optimal number of iterations might be different - but here we calculate and use this theoretical, optimal number using $A_1=1$." + "where $|A_1|$ is the number of solution states and $N=2^n$ is the total number of states. On modern noisy quantum computers, the experimentally optimal number of iterations might be different — but here we calculate and use this theoretical, optimal number using $|A_1|=1$." ] }, { @@ -569,7 +630,7 @@ "source": [ "We have constructed our Grover circuit!\n", "\n", - "## Step 2: Optimize problem for quantum hardware execution\n", + "### Step 2: Optimize problem for quantum hardware execution\n", "\n", "We have defined our abstract quantum circuit, but we need to rewrite it in terms of gates that are native to the quantum computer we actually want to use. We also need to specify which qubits on the quantum computer should be used. For these reasons and others, we now must transpile our circuit. First, let us specify the quantum computer we wish to use.\n", "\n", @@ -676,7 +737,7 @@ "source": [ "These are actually quite large numbers, even for this simple case. Since all quantum gates (and especially two-qubit gates) experience errors and are subject to noise, a series of over 100 two-qubit gates would result in nothing but noise if the qubits were not extremely high-performing. Let's see how these perform.\n", "\n", - "## Execute using Qiskit primitives\n", + "### Step 3: Execute using Qiskit primitives\n", "\n", "We want to make many measurements and see which state is the most likely. Such an amplitude amplification is a sampling problem that is suitable for execution with the `Sampler` Qiskit Runtime primitive.\n", "\n", @@ -727,7 +788,7 @@ "id": "f19b1adb", "metadata": {}, "source": [ - "## Step 4: Post-process and return result in desired classical format\n", + "### Step 4: Post-process and return result in desired classical format\n", "\n", "Now we can plot the results of our sampling in a histogram." ] @@ -794,11 +855,11 @@ "\n", "\n", "\n", - "# Activity 2: An accurate query algorithm workflow\n", + "## Activity 2: An accurate query algorithm workflow\n", "\n", "We will start this activity exactly as the first one, except that now you will pair up with another Qiskit enthusiast. You will pick a secret bitstring, and your partner will pick a (generally) different bitstring. You will each generate a quantum circuit that functions as an oracle, and you will exchange them. You will then use Grover's algorithm with that oracle to determine your partner's secret bitstring.\n", "\n", - "## Step 1: Map classical inputs to a quantum problem\n", + "### Step 1: Map classical inputs to a quantum problem\n", "\n", "Using the `grover_oracle` function defined above, construct an oracle circuit for one or more marked states. Make sure you tell your partner how many states you have marked, so they can apply the Grover operator the optimal number of times. **Don't make your bitstring too long. 3-5 bits should work without much difficulty.** Longer bitstrings would result in deep circuits that require more advanced techniques like error mitigation." ] @@ -915,7 +976,7 @@ "id": "37eb709b", "metadata": {}, "source": [ - "## Step 2: Optimize problem for quantum hardware execution\n", + "### Step 2: Optimize problem for quantum hardware execution\n", "\n", "This proceeds exactly as before." ] @@ -942,7 +1003,7 @@ "id": "de2af3e1", "metadata": {}, "source": [ - "## Step 3: Execute using Qiskit primitives\n", + "### Step 3: Execute using Qiskit primitives\n", "\n", "This is also identical to the process in the first activity." ] @@ -969,7 +1030,7 @@ "id": "14bbde32", "metadata": {}, "source": [ - "## Step 4: Post-process and return result in desired classical format\n", + "### Step 4: Post-process and return result in desired classical format\n", "\n", "Now display a histogram of your sampling results. One or more states should have much higher measurement probability than the others. Report these to your partner and check if you correctly determined the target states. By default, the histogram displayed is of the same circuit from the first activity. You should obtain different results from your partner's circuit." ] @@ -1051,184 +1112,232 @@ }, { "cell_type": "markdown", - "id": "8c85ebd9", + "id": "mine_intro_01", "metadata": {}, "source": [ - "## Activity 3: Criterion other than a specific bitstring\n", + "## Activity 3: Solve a minesweeper grid with Grover's algorithm\n", + "\n", + "In the previous section, we noted that Grover's algorithm becomes genuinely useful when we can build an oracle from the *constraints* of a problem, rather than from knowledge of the answer. Minesweeper is a perfect example: the numbered cells tell us how many mines are adjacent, and those constraints fully determine where the mines must be — but finding the configuration requires search.\n", + "\n", + "Minesweeper has been proven to be NP-complete: it is hard to solve but easy to check. That makes it a natural candidate for Grover's algorithm. Of course, we cannot yet solve a full 9$\\times$9 grid on a noisy quantum computer — the circuits would be far too deep. Instead, we will use a tiny grid as a toy demonstration of how one would approach a larger board on a future fault-tolerant machine.\n", + "\n", + "A few important caveats. Grover's algorithm provides only a quadratic speedup over *unstructured* classical search. Minesweeper almost certainly has exploitable structure that a clever classical algorithm could use. And for an exponentially growing search space, even the $\\sqrt{N}$ improvement only goes so far. But let us set those concerns aside and use this toy problem to illustrate how problem constraints get encoded into a quantum oracle.\n", + "\n", + "### The grid\n", + "\n", + "Here is our baby minesweeper grid:\n", + "\n", + "![A simple minesweeper grid with 3 blank cells and 3 numbered cells.](/learning/images/modules/computer-science/grovers/minesweeper-grid.avif)\n", "\n", - "As a final illustration of how Grover's algorithm might be useful in the context of a subroutine, let us imagine that we need quantum states with a certain number of `1` characters in the bitstring representation. This is common in situations where conservation laws are involved. For example, in the context of quantum chemistry, one often maps a `1` state of a qubit to an occupation of an electronic orbital. In order for charge to be conserved, the total number of `1` characters in the bitstring must also stay constant. Constraints like this are so common they have a special name: **Hamming weight constraints**, and the number of `1` characters in the bitstring representation of the state is called the **Hamming weight**.\n", + "Each blank cell can be represented by a binary variable indicating whether it contains a mine. We label these $x_0$, $x_1$, and $x_2$, where $x_i = 1$ means there is a mine on that cell and $x_i = 0$ means there is not:\n", "\n", - "## Step 1:\n", + "![The same minesweeper grid with variables x0, x1, x2 labeling the blank cells.](/learning/images/modules/computer-science/grovers/minesweeper-grid-labeled.avif)\n", "\n", - "Let us first write a function that marks states with the desired Hamming weight. We will write this in general for an unspecified number of qubits `num_qubits` and target Hamming weight `target_weight`." + "We could solve this in our heads in about half a second, but we are using this toy problem to illustrate how a much harder board could be approached with a quantum computer." ] }, { - "cell_type": "code", - "execution_count": null, - "id": "a3bb0650", + "cell_type": "markdown", + "id": "mine_bool_01", "metadata": {}, - "outputs": [], "source": [ - "from qiskit import QuantumCircuit\n", + "### Encode the constraints\n", "\n", + "Each numbered cell places a condition on the adjacent blank cells. We need to express these conditions as Boolean expressions that can be encoded into a quantum circuit.\n", "\n", - "def grover_oracle_hamming_weight(num_qubits, target_weight):\n", - " \"\"\"\n", - " Build a Grover oracle that marks all states with Hamming weight == target_weight.\n", + "The \"1\" cell adjacent to $x_0$ and $x_1$ says that exactly one of them contains a mine. This is precisely the exclusive-OR (XOR) operation, $\\oplus$, which returns true when exactly one of its inputs is true:\n", + "$$\n", + "(x_0 \\oplus x_1)\n", + "$$\n", "\n", - " Parameters:\n", - " num_qubits (int): Number of qubits in the circuit.\n", - " target_weight (int): The Hamming weight to mark.\n", + "Similarly, the other \"1\" cell (adjacent to $x_1$ and $x_2$) gives us:\n", + "$$\n", + "(x_1 \\oplus x_2)\n", + "$$\n", "\n", - " Returns:\n", - " QuantumCircuit: Quantum circuit representing Grover oracle.\n", - " \"\"\"\n", - " qc = QuantumCircuit(num_qubits)\n", - " marked_count = 0\n", - " marked_list = []\n", - " for x in range(2**num_qubits):\n", - " bitstr = format(x, f\"0{num_qubits}b\")\n", - " if bitstr.count(\"1\") == target_weight:\n", - " # Count the number of target states\n", - " marked_count = marked_count + 1\n", - " marked_list.append(bitstr)\n", - " # Reverse for Qiskit bit order (qubit 0 is rightmost)\n", - " rev_target = bitstr[::-1]\n", - " zero_inds = [i for i, b in enumerate(rev_target) if b == \"0\"]\n", - " # Apply X gates to 'open' controls (where bit is 0)\n", - " qc.x(zero_inds)\n", - " # Multi-controlled Z (as MCX conjugated by H)\n", - " if num_qubits == 1:\n", - " qc.z(0)\n", - " else:\n", - " qc.h(num_qubits - 1)\n", - " qc.mcx(list(range(num_qubits - 1)), num_qubits - 1)\n", - " qc.h(num_qubits - 1)\n", - " # Undo X gates\n", - " qc.x(zero_inds)\n", - " return qc, marked_count, marked_list" + "The \"2\" cell says that two of the three blank cells must contain mines. Since XOR is a parity operation, $x_0 \\oplus x_1 \\oplus x_2$ returns true when an *odd* number of the variables are true. We want an *even* number (specifically two) to be true, so we negate with $\\lnot$:\n", + "$$\n", + "\\lnot(x_0 \\oplus x_1 \\oplus x_2)\n", + "$$\n", + "On its own, this expression would be satisfied by either zero or two qubits in the $|1\\rangle$ state, since it is a statement about parity. But combined with the other two clauses, which each require at least one mine, the only satisfying assignment has exactly two mines.\n", + "\n", + "All three conditions must be simultaneously satisfied, so we join them with and symbols $\\land$:\n", + "$$\n", + "(x_0 \\oplus x_1) \\;\\land\\; (x_1 \\oplus x_2) \\;\\land\\; \\lnot(x_0 \\oplus x_1 \\oplus x_2)\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "mine_oracle_01", + "metadata": {}, + "source": [ + "### Step 1: Map classical inputs to a quantum problem\n", + "\n", + "Now we need to encode this Boolean expression into a quantum circuit that serves as the oracle. The quantum version of XOR can be accomplished with CX (CNOT) gates: applying two CX gates from the data qubits to a workspace (ancilla) qubit effectively computes their XOR and stores the result in the ancilla.\n", + "\n", + "We introduce three workspace qubits — one for each clause. We store the result of each Boolean expression in its corresponding workspace qubit, then use a multi-controlled Z gate to flip the phase of the three-qubit state that makes all three workspace qubits $|1\\rangle$ (meaning all clauses are satisfied simultaneously).\n", + "\n", + "In the first code cell below, we build the \"compute\" half of the oracle — the part that evaluates each clause and writes the result into the workspace qubits." ] }, { "cell_type": "code", - "execution_count": 20, - "id": "5f5e4675", + "execution_count": null, + "id": "mine_code_oracle1", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['011', '101', '110']\n" - ] - }, - { - "data": { - "text/plain": [ - "\"Output" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "# Completing step 1\n", - "oracle, num_marked_states, marked_states = grover_oracle_hamming_weight(3, 2)\n", - "print(marked_states)\n", - "oracle.draw(output=\"mpl\", style=\"iqp\")" + "x = QuantumRegister(3, 'x')\n", + "a = QuantumRegister(3, 'a')\n", + "qc = QuantumCircuit(x, a)\n", + "\n", + "# Clause 1: x0 XOR x1 -> stored in a[0]\n", + "qc.cx(x[0], a[0])\n", + "qc.cx(x[1], a[0])\n", + "\n", + "# Clause 2: x1 XOR x2 -> stored in a[1]\n", + "qc.cx(x[1], a[1])\n", + "qc.cx(x[2], a[1])\n", + "\n", + "# Clause 3: NOT(x0 XOR x1 XOR x2) -> stored in a[2]\n", + "qc.cx(x[0], a[2])\n", + "qc.cx(x[1], a[2])\n", + "qc.cx(x[2], a[2])\n", + "qc.x(a[2]) # The NOT\n", + "\n", + "qc.draw('mpl', style='iqp')" ] }, { "cell_type": "markdown", - "id": "f26a8955", + "id": "mine_mcz_01", "metadata": {}, "source": [ - "From here the entire process is identical to that from the previous two activities. For brevity, the Qiskit patterns steps are shown only in code comments here." + "At this point, the result of each clause is stored in its corresponding workspace qubit. Now we need the three-qubit data state that makes all three workspace qubits $|1\\rangle$ to pick up a minus sign. We do this with a multi-controlled Z gate (implemented as an MCX gate sandwiched by Hadamard gates on the target).\n", + "\n", + "After applying the phase flip, we must **uncompute** — undo all the clause-evaluation steps in reverse order — to reset the workspace qubits back to $|0\\rangle.$ This is essential so that the workspace qubits are clean for subsequent iterations of the Grover operator." ] }, { "cell_type": "code", "execution_count": null, - "id": "63034fc7", + "id": "mine_code_oracle2", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "qiskit_runtime_service._resolve_cloud_instances:WARNING:2025-08-08 14:14:51,686: Default instance not set. Searching all available instances.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ibm_brisbane\n" - ] - } - ], + "outputs": [], "source": [ - "from qiskit_ibm_runtime import SamplerV2 as Sampler\n", + "# Multi-controlled Z: flip phase if all workspace qubits are |1>\n", + "qc.h(a[2])\n", + "qc.mcx([a[0], a[1]], a[2])\n", + "qc.h(a[2])\n", "\n", - "# Completing step 1\n", - "oracle, num_marked_states, marked_states = grover_oracle_hamming_weight(4, 2)\n", - "oracle.draw(output=\"mpl\", style=\"iqp\")\n", + "# Uncompute clause 3: NOT(x0 XOR x1 XOR x2)\n", + "qc.x(a[2])\n", + "qc.cx(x[2], a[2])\n", + "qc.cx(x[1], a[2])\n", + "qc.cx(x[0], a[2])\n", "\n", - "grover_op = grover_operator(oracle)\n", - "grover_op.decompose().draw(output=\"mpl\", style=\"iqp\")\n", - "optimal_num_iterations = math.floor(\n", - " math.pi / (4 * math.asin(math.sqrt(len(marked_states) / 2**grover_op.num_qubits)))\n", - ")\n", + "# Uncompute clause 2: x1 XOR x2\n", + "qc.cx(x[2], a[1])\n", + "qc.cx(x[1], a[1])\n", "\n", - "qc = QuantumCircuit(grover_op.num_qubits)\n", - "qc.h(range(grover_op.num_qubits))\n", - "qc.compose(grover_op.power(optimal_num_iterations), inplace=True)\n", - "qc.measure_all()\n", - "qc.draw(output=\"mpl\", style=\"iqp\")\n", + "# Uncompute clause 1: x0 XOR x1\n", + "qc.cx(x[1], a[0])\n", + "qc.cx(x[0], a[0])\n", "\n", - "# Step 2: Optimize for running on real quantum computers\n", + "qc.draw('mpl', style='iqp')" + ] + }, + { + "cell_type": "markdown", + "id": "mine_groverop_01", + "metadata": {}, + "source": [ + "This circuit is our oracle: it flips the phase of the data-qubit state that satisfies all three minesweeper constraints, and leaves the workspace qubits back in $|0\\rangle.$\n", "\n", + "Now we construct the full Grover operator from this oracle. Note the `reflection_qubits` argument: we pass only the data qubits `x`, because the workspace qubits are not part of the search space. Their job is done once the oracle has been applied." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "mine_code_groverop", + "metadata": {}, + "outputs": [], + "source": [ + "grover_op = grover_operator(qc, reflection_qubits=x)\n", + "grover_op.decompose(reps=0).draw(output=\"mpl\", style=\"iqp\")" + ] + }, + { + "cell_type": "markdown", + "id": "mine_circuit_01", + "metadata": {}, + "source": [ + "With 3 data qubits and 1 solution state, the optimal number of Grover iterations is $t \\approx \\frac{\\pi}{4}\\sqrt{8} - \\frac{1}{2} \\approx 1.7,$ so we use 2 iterations. We apply Hadamard gates to the data qubits to create the initial superposition, compose the Grover operator twice, and measure only the data qubits." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "mine_code_circuit", + "metadata": {}, + "outputs": [], + "source": [ + "x = QuantumRegister(3, 'x')\n", + "a = QuantumRegister(4, 'a')\n", + "meas = ClassicalRegister(3, 'meas')\n", + "\n", + "qc = QuantumCircuit(x, a, meas)\n", + "# Create superposition over the data qubits only\n", + "qc.h(x)\n", + "# Apply 2 iterations of the Grover operator\n", + "qc.compose(grover_op.power(2), inplace=True)\n", + "# Measure only the data qubits\n", + "qc.measure(x, meas)\n", + "qc.decompose().draw(output=\"mpl\", style=\"iqp\")" + ] + }, + { + "cell_type": "markdown", + "id": "mine_step2_01", + "metadata": {}, + "source": [ + "### Step 2: Optimize problem for quantum hardware execution\n", + "\n", + "As before, we transpile the circuit for the target backend." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "mine_code_transpile", + "metadata": {}, + "outputs": [], + "source": [ "service = QiskitRuntimeService()\n", "backend = service.least_busy(operational=True, simulator=False)\n", "print(backend.name)\n", "\n", "target = backend.target\n", "pm = generate_preset_pass_manager(target=target, optimization_level=3)\n", - "circuit_isa = pm.run(qc)\n", - "\n", - "# Step 3: Execute using Qiskit primitives\n", - "# To run on a real quantum computer (this was tested on a Heron r2 processor and used 4 seconds of QPU time)\n", - "\n", - "sampler = Sampler(mode=backend)\n", - "sampler.options.default_shots = 10_000\n", - "result = sampler.run([circuit_isa]).result()\n", - "dist = result[0].data.meas.get_counts()\n", - "\n", - "# To run on local simulator:\n", - "# from qiskit.primitives import StatevectorSampler as Sampler\n", - "# sampler = Sampler()\n", - "# result = sampler.run([qc]).result()\n", - "# dist = result[0].data.meas.get_counts()" + "circuit_isa = pm.run(qc)" + ] + }, + { + "cell_type": "markdown", + "id": "mine_depth_01", + "metadata": {}, + "source": [ + "Let us check the depth of the transpiled circuit. Because the minesweeper oracle uses workspace qubits and multiple CX gates, the transpiled circuit will be deeper than those in the previous activities." ] }, { "cell_type": "code", "execution_count": null, - "id": "0f7daf19", + "id": "mine_code_depth", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The total depth is 502\n", - "The depth of two-qubit gates is 130\n" - ] - } - ], + "outputs": [], "source": [ "print(\"The total depth is \", circuit_isa.depth())\n", "print(\n", @@ -1237,54 +1346,71 @@ ")" ] }, + { + "cell_type": "markdown", + "id": "mine_step3_01", + "metadata": {}, + "source": [ + "### Step 3: Execute using Qiskit primitives" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "7c987ff1", + "id": "mine_code_run", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "6" - ] - }, - "execution_count": 150, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "num_marked_states" + "# To run on a real quantum computer (this was tested on a Heron r2 processor and used 4 sec. of QPU time)\n", + "\n", + "from qiskit_ibm_runtime import SamplerV2 as Sampler\n", + "\n", + "sampler = Sampler(mode=backend)\n", + "sampler.options.default_shots = 10_000\n", + "result = sampler.run([circuit_isa]).result()\n", + "dist = result[0].data.meas.get_counts()" ] }, { "cell_type": "code", "execution_count": null, - "id": "cf8b6be8", + "id": "mine_code_sim", + "metadata": {}, + "outputs": [], + "source": [ + "# To run on local simulator:\n", + "# from qiskit.primitives import StatevectorSampler as Sampler\n", + "# sampler = Sampler()\n", + "# result = sampler.run([qc]).result()\n", + "# dist = result[0].data.meas.get_counts()" + ] + }, + { + "cell_type": "markdown", + "id": "mine_step4_01", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"Output" - ] - }, - "execution_count": 151, - "metadata": {}, - "output_type": "execute_result" - } - ], + "source": [ + "### Step 4: Post-process and return result in desired classical format" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "mine_code_plot", + "metadata": {}, + "outputs": [], "source": [ "plot_distribution(dist)" ] }, { "cell_type": "markdown", - "id": "268508ce", + "id": "mine_conclusion_01", "metadata": {}, "source": [ - "Here Grover's algorithm did indeed prepare the states with Hamming weight 2 to be much more likely to be measured than any other states, roughly one order of magnitude more likely." + "The `101` state should appear with far higher probability than any other, indicating that mines are located at $x_0$ and $x_2.$ We have used a quantum computer to solve a tiny game of minesweeper!\n", + "\n", + "Of course, the best classical algorithms for minesweeper are better than a brute-force search through all possible mine configurations — they exploit the structure of the grid. Grover's algorithm would only offer an advantage on extremely difficult boards designed to be maximally ambiguous, and even then, the quadratic speedup means it cannot keep pace with exponential growth indefinitely. But the real takeaway is the technique: encoding problem constraints into a quantum oracle is a powerful pattern that extends to constraint satisfaction, combinatorial optimization, and many other domains." ] }, { @@ -1292,6 +1418,9 @@ "id": "494c1799", "metadata": {}, "source": [ + "## Questions and critical concepts:\n", + "\n", + "\n", "### Critical concepts:\n", "\n", "In this module, we learned some key features of Grover's algorithm:\n", @@ -1299,8 +1428,8 @@ "- Grover's algorithm involves repeating a series of operations (commonly called the \"Grover operator\") a number of times $t,$ chosen to make the target states optimally likely to be measured.\n", "- Grover's algorithm can be run with fewer than $t$ iterations and still amplify the target states.\n", "- Grover's algorithm fits into the query model of computation and makes the most sense when one person controls the search and another controls/constructs the oracle. It may also be useful as a subroutine in other quantum computations.\n", + "- An oracle can be built from *problem constraints* rather than from knowledge of the solution, as demonstrated with the minesweeper example.\n", "\n", - "## Questions\n", "\n", "### T/F questions:\n", "\n", @@ -1342,18 +1471,30 @@ "\n", "### Discussion questions:\n", "\n", - "1. What other conditions might you use in a quantum oracle? Consider conditions that are easy to state or impose on a bitstring but are not merely writing out the marked bitstrings.\n", + "1. What other problems could you formulate as a Grover search? Think of problems where it is difficult to find a solution but easy to verify one.\n", "\n", "\n", "2. Can you see any problems with scaling Grover's algorithm on modern quantum computers?" ] + }, + { + "cell_type": "markdown", + "id": "3cd19a53", + "metadata": {}, + "source": [] + }, + { + "cell_type": "markdown", + "id": "dc4803ec", + "metadata": {}, + "source": [] } ], "metadata": { "in_page_toc_max_heading_level": 2, "in_page_toc_min_heading_level": 2, "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -1367,7 +1508,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3" + "version": "3.12.2" } }, "nbformat": 4, diff --git a/public/learning/images/modules/computer-science/grovers/grover-geometric-reflections.avif b/public/learning/images/modules/computer-science/grovers/grover-geometric-reflections.avif new file mode 100644 index 0000000000000000000000000000000000000000..e4bea19dea0df30e75110fdd0821406d4e238ab1 GIT binary patch literal 20003 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%0A2-hZSZ{-a5`%?zEGGnr%9 z0*AR67a-PP4xEs{iFn=-U{<7m@6(iX@Zi|y>K4!@XA^;&(BnCZ%&K>u< zQbvK*cL=U}e)b+Ebeu{==EKbdVu`CAw%XF`1wG>Lg+T0nD(&78xQs%%8Hx5djYa~G zlFGTEl}N&l0o2jr@q|||aj(T~(?X`;EsOUqlyaeqwcL3`zs$f8Ke-*-keCKXPUIaU z5YHe(IMhBB9m6almYk3@GndwP}4Kz`0U%X+n?f1HIFzM#erpFT+MGHL-k!KI* zAgm2^x~t6a|I|8H+2L{Nxeysp+jJxp8JAasR8?EbKG9zg_0&3@_}4QtI-Px9KV*5k z8lz!2HD!M;?C?(Mhz-KWP$|Xi+R_YE=isKv2e5dXcnXS*PpXR(LlNHdF=|s9{c^21 B<5B7%dj7=N>KwEOKa5wog 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 literal 0 HcmV?d00001 diff --git a/public/learning/images/modules/computer-science/grovers/minesweeper-grid.avif b/public/learning/images/modules/computer-science/grovers/minesweeper-grid.avif new file mode 100644 index 0000000000000000000000000000000000000000..c28293b82efb1372a8b75514d2eae91cf5a03623 GIT binary patch literal 5855 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 Date: Tue, 12 May 2026 14:02:37 -0700 Subject: [PATCH 2/3] oops forgot ./check and ./fix --- .../modules/computer-science/grovers.ipynb | 32 ++++++------------ .../grovers/extracted-outputs/5f5e4675-1.avif | Bin 11721 -> 0 bytes .../grovers/extracted-outputs/cf8b6be8-0.avif | Bin 29112 -> 0 bytes 3 files changed, 10 insertions(+), 22 deletions(-) delete mode 100644 public/learning/images/modules/computer-science/grovers/extracted-outputs/5f5e4675-1.avif delete mode 100644 public/learning/images/modules/computer-science/grovers/extracted-outputs/cf8b6be8-0.avif diff --git a/learning/modules/computer-science/grovers.ipynb b/learning/modules/computer-science/grovers.ipynb index 6a563e7406c..ed83c853a87 100644 --- a/learning/modules/computer-science/grovers.ipynb +++ b/learning/modules/computer-science/grovers.ipynb @@ -272,7 +272,7 @@ "source": [ "### The geometric picture\n", "\n", - "The two-qubit example above showed how the algebra works out for a small case, but there is a much more intuitive way to understand Grover's algorithm: as a sequence of geometric reflections in a two-dimensional plane. Below we describe this picture. You can also see John Watrous's course [Fundamentals of Quantum Algorithms](/learning/courses/fundamentals-of-quantum-algorithms/grover-algorithm) for more details.\n", + "The two-qubit example above showed how the algebra works out for a small case, but there is a much more intuitive way to understand Grover's algorithm: as a sequence of geometric reflections in a two-dimensional plane. Below we describe this picture. You can also see John Watrous's course [Fundamentals of Quantum Algorithms](/learning/courses/fundamentals-of-quantum-algorithms/grover-algorithm/analysis) for more details.\n", "\n", "**Setting up the plane.** We can decompose the initial superposition state $|\\psi\\rangle$ into two components. The correct state — the one we're searching for — we call $|A_1\\rangle.$ Every other state, lumped together, we call $|A_0\\rangle.$ By definition, $|A_1\\rangle$ and $|A_0\\rangle$ are orthogonal to one another, so we can plot them as perpendicular axes in an abstract, two-dimensional space. Since $|\\psi\\rangle$ is a linear combination of these two components, it sits at some small angle $\\theta$ to the $|A_0\\rangle$ axis — close to $|A_0\\rangle$, because at the start, only a tiny fraction of the state is in the correct component $|A_1\\rangle.$\n", "\n", @@ -1188,8 +1188,8 @@ "metadata": {}, "outputs": [], "source": [ - "x = QuantumRegister(3, 'x')\n", - "a = QuantumRegister(3, 'a')\n", + "x = QuantumRegister(3, \"x\")\n", + "a = QuantumRegister(3, \"a\")\n", "qc = QuantumCircuit(x, a)\n", "\n", "# Clause 1: x0 XOR x1 -> stored in a[0]\n", @@ -1206,7 +1206,7 @@ "qc.cx(x[2], a[2])\n", "qc.x(a[2]) # The NOT\n", "\n", - "qc.draw('mpl', style='iqp')" + "qc.draw(\"mpl\", style=\"iqp\")" ] }, { @@ -1245,7 +1245,7 @@ "qc.cx(x[1], a[0])\n", "qc.cx(x[0], a[0])\n", "\n", - "qc.draw('mpl', style='iqp')" + "qc.draw(\"mpl\", style=\"iqp\")" ] }, { @@ -1284,9 +1284,9 @@ "metadata": {}, "outputs": [], "source": [ - "x = QuantumRegister(3, 'x')\n", - "a = QuantumRegister(4, 'a')\n", - "meas = ClassicalRegister(3, 'meas')\n", + "x = QuantumRegister(3, \"x\")\n", + "a = QuantumRegister(4, \"a\")\n", + "meas = ClassicalRegister(3, \"meas\")\n", "\n", "qc = QuantumCircuit(x, a, meas)\n", "# Create superposition over the data qubits only\n", @@ -1476,25 +1476,13 @@ "\n", "2. Can you see any problems with scaling Grover's algorithm on modern quantum computers?" ] - }, - { - "cell_type": "markdown", - "id": "3cd19a53", - "metadata": {}, - "source": [] - }, - { - "cell_type": "markdown", - "id": "dc4803ec", - "metadata": {}, - "source": [] } ], "metadata": { "in_page_toc_max_heading_level": 2, "in_page_toc_min_heading_level": 2, "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -1508,7 +1496,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.2" + "version": "3" } }, "nbformat": 4, diff --git a/public/learning/images/modules/computer-science/grovers/extracted-outputs/5f5e4675-1.avif b/public/learning/images/modules/computer-science/grovers/extracted-outputs/5f5e4675-1.avif deleted file mode 100644 index c9358623b68453d8627f0972877bfe51f43877e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11721 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 Pfv72IDWV@fdG>z*6LdaQ diff --git a/public/learning/images/modules/computer-science/grovers/extracted-outputs/cf8b6be8-0.avif b/public/learning/images/modules/computer-science/grovers/extracted-outputs/cf8b6be8-0.avif deleted file mode 100644 index c732bf555f49cb0fc1a67b0e831d96f403c9d345..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29112 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 From db8e88860990bf3b5bf646735aecd05c71360fdf Mon Sep 17 00:00:00 2001 From: Katie McCormick <162379175+kcmccormibm@users.noreply.github.com> Date: Fri, 15 May 2026 14:40:15 -0700 Subject: [PATCH 3/3] Apply suggestions from code review Co-authored-by: abbycross --- .../modules/computer-science/grovers.ipynb | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/learning/modules/computer-science/grovers.ipynb b/learning/modules/computer-science/grovers.ipynb index ed83c853a87..747f1b6340b 100644 --- a/learning/modules/computer-science/grovers.ipynb +++ b/learning/modules/computer-science/grovers.ipynb @@ -274,14 +274,14 @@ "\n", "The two-qubit example above showed how the algebra works out for a small case, but there is a much more intuitive way to understand Grover's algorithm: as a sequence of geometric reflections in a two-dimensional plane. Below we describe this picture. You can also see John Watrous's course [Fundamentals of Quantum Algorithms](/learning/courses/fundamentals-of-quantum-algorithms/grover-algorithm/analysis) for more details.\n", "\n", - "**Setting up the plane.** We can decompose the initial superposition state $|\\psi\\rangle$ into two components. The correct state — the one we're searching for — we call $|A_1\\rangle.$ Every other state, lumped together, we call $|A_0\\rangle.$ By definition, $|A_1\\rangle$ and $|A_0\\rangle$ are orthogonal to one another, so we can plot them as perpendicular axes in an abstract, two-dimensional space. Since $|\\psi\\rangle$ is a linear combination of these two components, it sits at some small angle $\\theta$ to the $|A_0\\rangle$ axis — close to $|A_0\\rangle$, because at the start, only a tiny fraction of the state is in the correct component $|A_1\\rangle.$\n", + "**Setting up the plane.** We can decompose the initial superposition state $|\\psi\\rangle$ into two components. The correct state — the one we're searching for — we call $|A_1\\rangle$. Every other state, lumped together, we call $|A_0\\rangle$. By definition, $|A_1\\rangle$ and $|A_0\\rangle$ are orthogonal to one another, so we can plot them as perpendicular axes in an abstract, two-dimensional space. Since $|\\psi\\rangle$ is a linear combination of these two components, it sits at some small angle $\\theta$ to the $|A_0\\rangle$ axis — close to $|A_0\\rangle$, because at the start, only a tiny fraction of the state is in the correct component $|A_1\\rangle$.\n", "\n", "\n", "**Reflections.** The key mathematical fact we need is that an operator of the form\n", "$$\n", "2|v\\rangle\\langle v| - I\n", "$$\n", - "reflects any state about the axis defined by $|v\\rangle.$ To see why, consider two cases: a state along $|v\\rangle$ is left unchanged, and a state perpendicular to $|v\\rangle$ gets its sign flipped. Any other state can be decomposed into these two components, and the operator acts on each accordingly — which is exactly a reflection about $|v\\rangle.$\n", + "reflects any state about the axis defined by $|v\\rangle.$ To see why, consider two cases: a state along $|v\\rangle$ is left unchanged, and a state perpendicular to $|v\\rangle$ gets its sign flipped. Any other state can be decomposed into these two components, and the operator acts on each accordingly — which is exactly a reflection about $|v\\rangle$.\n", "\n", "It turns out that both the oracle and the diffusion steps in Grover's algorithm can be expressed as reflections in this geometric picture.\n", "\n", @@ -293,17 +293,17 @@ "$$\n", "H^{\\otimes n}\\, Z_{\\text{OR}}\\, H^{\\otimes n}\n", "$$\n", - "$Z_{\\text{OR}}$ by itself is a reflection about the all-zero state, since it flips the sign of every state that is not $|0\\rangle^{\\otimes n}.$ This can be written as $2|0\\rangle\\langle 0| - I.$ The surrounding Hadamard layers effectively perform a change of basis, transforming the axis of reflection. Recall that $H^{\\otimes n}$ maps $|0\\rangle^{\\otimes n}$ to the uniform superposition $|u\\rangle = \\frac{1}{\\sqrt{N}}\\sum_{x}|x\\rangle.$ Since the Hadamard is its own inverse, the full expression becomes\n", + "$Z_{\\text{OR}}$ by itself is a reflection about the all-zero state, since it flips the sign of every state that is not $|0\\rangle^{\\otimes n}$. This can be written as $2|0\\rangle\\langle 0| - I$. The surrounding Hadamard layers effectively perform a change of basis, transforming the axis of reflection. Recall that $H^{\\otimes n}$ maps $|0\\rangle^{\\otimes n}$ to the uniform superposition $|u\\rangle = \\frac{1}{\\sqrt{N}}\\sum_{x}|x\\rangle$. Since the Hadamard is its own inverse, the full expression becomes\n", "$$\n", "H^{\\otimes n}\\left(2|0\\rangle\\langle 0| - I\\right)H^{\\otimes n} = 2|u\\rangle\\langle u| - I\n", "$$\n", - "which is a reflection about $|u\\rangle.$ Since $|u\\rangle$ is very close to $|\\psi\\rangle$ (both are nearly along $|A_0\\rangle$), this second reflection sends the state to an angle $2\\theta$ from where it started.\n", + "which is a reflection about $|u\\rangle$. Since $|u\\rangle$ is very close to $|\\psi\\rangle$ (both are nearly along $|A_0\\rangle$), this second reflection sends the state to an angle $2\\theta$ from where it started.\n", "\n", "![Geometric interpretation of the Grover operator as a rotation.](/learning/images/modules/computer-science/grovers/grover-geometric-reflections.avif)\n", "\n", - "**Rotation by $2\\theta$.** The combined effect of these two reflections is a rotation by $2\\theta$ toward $|A_1\\rangle.$ Each successive iteration of the Grover operator rotates the state by another $2\\theta.$\n", + "**Rotation by $2\\theta$.** The combined effect of these two reflections is a rotation by $2\\theta$ toward $|A_1\\rangle$. Each successive iteration of the Grover operator rotates the state by another $2\\theta.$\n", "\n", - "**Optimal number of iterations.** Our goal is to rotate the state as close to $|A_1\\rangle$ as possible, which means rotating by a total of approximately $\\pi/2$ radians (a quarter turn). If each iteration contributes $2\\theta,$ the optimal number of iterations $t$ satisfies\n", + "**Optimal number of iterations.** Our goal is to rotate the state as close to $|A_1\\rangle$ as possible, which means rotating by a total of approximately $\\pi/2$ radians (a quarter turn). If each iteration contributes $2\\theta$, the optimal number of iterations $t$ satisfies\n", "$$\n", "(2t + 1)\\theta \\approx \\frac{\\pi}{2}\n", "$$\n", @@ -328,7 +328,7 @@ "source": [ "### Why is Grover's algorithm useful?\n", "\n", - "At this point you may be wondering: we just built an oracle that marks a target state — but to build it, we had to know the target state. So what are we actually searching for?\n", + "At this point you may be wondering: we just built an oracle that marks a target state — but to build it, we had to know the target state. So what are we actually searching for?\n", "\n", "This is a fair question, and there are several good answers.\n", "\n", @@ -336,11 +336,11 @@ "\n", "- You can also think of it as a **two-party activity**: one person knows the target state and builds the oracle; the other person's job is to find the answer using the oracle as a black box, with no peeking inside. In Activity 2 below, you will do exactly this with a partner.\n", "\n", - "- **Amplitude amplification is a broadly useful subroutine.** Even if this first demonstration seems circular, the underlying mechanism — called *amplitude amplification* — shows up again and again in quantum computing. What we are really building here is an intuition for a tool that appears as a subroutine in many more complex quantum algorithms.\n", + "- **Amplitude amplification is a broadly useful subroutine.** Even if this first demonstration seems circular, the underlying mechanism — called *amplitude amplification* — shows up again and again in quantum computing. What we are really building here is an intuition for a tool that appears as a subroutine in many more complex quantum algorithms.\n", "\n", - "- **There are problems where you can build an oracle without knowing the answer.** The key insight is that there exists a whole class of problems for which it is very hard to *find* a solution, but very easy to *check* that a given solution is correct. Factoring is one example: given a product of two large primes, it is extremely difficult to determine what those primes are, but once you have them, you can easily multiply them together to verify. (We have a better algorithm than Grover's for factoring specifically — see Shor's algorithm — but this is far from the only problem with this feature.) Sudoku, constraint satisfaction, and even the classic game of minesweeper are all problems that are difficult to solve but easy to check.\n", + "- **There are problems where you can build an oracle without knowing the answer.** The key insight is that there exists a whole class of problems for which it is very hard to *find* a solution, but very easy to *check* that a given solution is correct. Factoring is one example: given a product of two large primes, it is extremely difficult to determine what those primes are, but once you have them, you can easily multiply them together to verify. (We have a better algorithm than Grover's for factoring specifically — see Shor's algorithm — but this is far from the only problem with this feature.) Sudoku, constraint satisfaction, and even the classic game of Minesweeper are all problems that are difficult to solve but easy to check.\n", "\n", - "Why is that relevant? It means we can know all of the *conditions* and *requirements* that a solution must satisfy, and we can encode those requirements into a quantum circuit that serves as the oracle — even though we do not know the solution itself. Grover's algorithm will find it for us.\n", + "Why is that relevant? It means we can know all of the *conditions* and *requirements* that a solution must satisfy, and we can encode those requirements into a quantum circuit that serves as the oracle — even though we do not know the solution itself. Grover's algorithm will find it for us.\n", "\n", "With these ideas in mind, let us work through several examples. We will begin with an example in which the solution state is clearly specified so we can follow the logic of the algorithm. We will then move on to a two-party activity, and finally to an example in which the oracle is built from problem constraints rather than from knowledge of the answer." ] @@ -559,11 +559,11 @@ "id": "fb293e00", "metadata": {}, "source": [ - "As we discussed in the geometric picture above, we may need to apply the Grover operator multiple times. The optimal number of iterations $t$ to maximize the amplitude of the target state in the absence of noise is\n", + "As we discussed in the geometric picture above, we might need to apply the Grover operator multiple times. The optimal number of iterations $t$ to maximize the amplitude of the target state in the absence of noise is\n", "$$\n", "t\\approx \\frac{\\pi}{4} \\sqrt{\\frac{N}{|A_1|}}-\\frac{1}{2}\n", "$$\n", - "where $|A_1|$ is the number of solution states and $N=2^n$ is the total number of states. On modern noisy quantum computers, the experimentally optimal number of iterations might be different — but here we calculate and use this theoretical, optimal number using $|A_1|=1$." + "where $|A_1|$ is the number of solution states and $N=2^n$ is the total number of states. On modern noisy quantum computers, the experimentally optimal number of iterations might be different — but here we calculate and use this theoretical, optimal number using $|A_1|=1$." ] }, { @@ -1115,11 +1115,11 @@ "id": "mine_intro_01", "metadata": {}, "source": [ - "## Activity 3: Solve a minesweeper grid with Grover's algorithm\n", - "\n", - "In the previous section, we noted that Grover's algorithm becomes genuinely useful when we can build an oracle from the *constraints* of a problem, rather than from knowledge of the answer. Minesweeper is a perfect example: the numbered cells tell us how many mines are adjacent, and those constraints fully determine where the mines must be — but finding the configuration requires search.\n", - "\n", - "Minesweeper has been proven to be NP-complete: it is hard to solve but easy to check. That makes it a natural candidate for Grover's algorithm. Of course, we cannot yet solve a full 9$\\times$9 grid on a noisy quantum computer — the circuits would be far too deep. Instead, we will use a tiny grid as a toy demonstration of how one would approach a larger board on a future fault-tolerant machine.\n", + "## Activity 3: Solve a Minesweeper grid with Grover's algorithm\n", + "\n", + "In the previous section, we noted that Grover's algorithm becomes genuinely useful when we can build an oracle from the *constraints* of a problem, rather than from knowledge of the answer. Minesweeper is a perfect example: the numbered cells tell us how many mines are adjacent, and those constraints fully determine where the mines must be — but finding the configuration requires search.\n", + "\n", + "Minesweeper has been proven to be NP-complete: it is hard to solve but easy to check. That makes it a natural candidate for Grover's algorithm. Of course, we cannot yet solve a full 9$\\times$9 grid on a noisy quantum computer — the circuits would be far too deep. Instead, we will use a tiny grid as a toy demonstration of how one would approach a larger board on a future fault-tolerant machine.\n", "\n", "A few important caveats. Grover's algorithm provides only a quadratic speedup over *unstructured* classical search. Minesweeper almost certainly has exploitable structure that a clever classical algorithm could use. And for an exponentially growing search space, even the $\\sqrt{N}$ improvement only goes so far. But let us set those concerns aside and use this toy problem to illustrate how problem constraints get encoded into a quantum oracle.\n", "\n", @@ -1127,11 +1127,11 @@ "\n", "Here is our baby minesweeper grid:\n", "\n", - "![A simple minesweeper grid with 3 blank cells and 3 numbered cells.](/learning/images/modules/computer-science/grovers/minesweeper-grid.avif)\n", + "![A simple Minesweeper grid with three blank cells and three numbered cells.](/learning/images/modules/computer-science/grovers/minesweeper-grid.avif)\n", "\n", "Each blank cell can be represented by a binary variable indicating whether it contains a mine. We label these $x_0$, $x_1$, and $x_2$, where $x_i = 1$ means there is a mine on that cell and $x_i = 0$ means there is not:\n", "\n", - "![The same minesweeper grid with variables x0, x1, x2 labeling the blank cells.](/learning/images/modules/computer-science/grovers/minesweeper-grid-labeled.avif)\n", + "![The same Minesweeper grid with variables x0, x1, x2 labeling the blank cells.](/learning/images/modules/computer-science/grovers/minesweeper-grid-labeled.avif)\n", "\n", "We could solve this in our heads in about half a second, but we are using this toy problem to illustrate how a much harder board could be approached with a quantum computer." ] @@ -1176,9 +1176,9 @@ "\n", "Now we need to encode this Boolean expression into a quantum circuit that serves as the oracle. The quantum version of XOR can be accomplished with CX (CNOT) gates: applying two CX gates from the data qubits to a workspace (ancilla) qubit effectively computes their XOR and stores the result in the ancilla.\n", "\n", - "We introduce three workspace qubits — one for each clause. We store the result of each Boolean expression in its corresponding workspace qubit, then use a multi-controlled Z gate to flip the phase of the three-qubit state that makes all three workspace qubits $|1\\rangle$ (meaning all clauses are satisfied simultaneously).\n", - "\n", - "In the first code cell below, we build the \"compute\" half of the oracle — the part that evaluates each clause and writes the result into the workspace qubits." + "We introduce three workspace qubits — one for each clause. We store the result of each Boolean expression in its corresponding workspace qubit, then use a multi-controlled Z gate to flip the phase of the three-qubit state that makes all three workspace qubits $|1\\rangle$ (meaning all clauses are satisfied simultaneously).\n", + "\n", + "In the first code cell below, we build the \"compute\" half of the oracle — the part that evaluates each clause and writes the result into the workspace qubits." ] }, { @@ -1216,7 +1216,7 @@ "source": [ "At this point, the result of each clause is stored in its corresponding workspace qubit. Now we need the three-qubit data state that makes all three workspace qubits $|1\\rangle$ to pick up a minus sign. We do this with a multi-controlled Z gate (implemented as an MCX gate sandwiched by Hadamard gates on the target).\n", "\n", - "After applying the phase flip, we must **uncompute** — undo all the clause-evaluation steps in reverse order — to reset the workspace qubits back to $|0\\rangle.$ This is essential so that the workspace qubits are clean for subsequent iterations of the Grover operator." + "After applying the phase flip, we must **uncompute** — undo all the clause-evaluation steps in reverse order — to reset the workspace qubits back to $|0\\rangle.$ This is essential so that the workspace qubits are clean for subsequent iterations of the Grover operator." ] }, { @@ -1253,7 +1253,7 @@ "id": "mine_groverop_01", "metadata": {}, "source": [ - "This circuit is our oracle: it flips the phase of the data-qubit state that satisfies all three minesweeper constraints, and leaves the workspace qubits back in $|0\\rangle.$\n", + "This circuit is our oracle: it flips the phase of the data-qubit state that satisfies all three Minesweeper constraints, and leaves the workspace qubits back in $|0\\rangle.$\n", "\n", "Now we construct the full Grover operator from this oracle. Note the `reflection_qubits` argument: we pass only the data qubits `x`, because the workspace qubits are not part of the search space. Their job is done once the oracle has been applied." ] @@ -1274,7 +1274,7 @@ "id": "mine_circuit_01", "metadata": {}, "source": [ - "With 3 data qubits and 1 solution state, the optimal number of Grover iterations is $t \\approx \\frac{\\pi}{4}\\sqrt{8} - \\frac{1}{2} \\approx 1.7,$ so we use 2 iterations. We apply Hadamard gates to the data qubits to create the initial superposition, compose the Grover operator twice, and measure only the data qubits." + "With three data qubits and one solution state, the optimal number of Grover iterations is $t \\approx \\frac{\\pi}{4}\\sqrt{8} - \\frac{1}{2} \\approx 1.7$, so we use two iterations. We apply Hadamard gates to the data qubits to create the initial superposition, compose the Grover operator twice, and measure only the data qubits." ] }, { @@ -1329,7 +1329,7 @@ "id": "mine_depth_01", "metadata": {}, "source": [ - "Let us check the depth of the transpiled circuit. Because the minesweeper oracle uses workspace qubits and multiple CX gates, the transpiled circuit will be deeper than those in the previous activities." + "Now we can check the depth of the transpiled circuit. Because the Minesweeper oracle uses workspace qubits and multiple CX gates, the transpiled circuit will be deeper than those in the previous activities." ] }, { @@ -1408,9 +1408,9 @@ "id": "mine_conclusion_01", "metadata": {}, "source": [ - "The `101` state should appear with far higher probability than any other, indicating that mines are located at $x_0$ and $x_2.$ We have used a quantum computer to solve a tiny game of minesweeper!\n", - "\n", - "Of course, the best classical algorithms for minesweeper are better than a brute-force search through all possible mine configurations — they exploit the structure of the grid. Grover's algorithm would only offer an advantage on extremely difficult boards designed to be maximally ambiguous, and even then, the quadratic speedup means it cannot keep pace with exponential growth indefinitely. But the real takeaway is the technique: encoding problem constraints into a quantum oracle is a powerful pattern that extends to constraint satisfaction, combinatorial optimization, and many other domains." + "The `101` state should appear with far higher probability than any other, indicating that mines are located at $x_0$ and $x_2$. We have used a quantum computer to solve a tiny game of Minesweeper!\n", + "\n", + "Of course, the best classical algorithms for minesweeper are better than a brute-force search through all possible mine configurations — they exploit the structure of the grid. Grover's algorithm would only offer an advantage on extremely difficult boards designed to be maximally ambiguous, and even then, the quadratic speedup means it cannot keep pace with exponential growth indefinitely. But the real takeaway is the technique: encoding problem constraints into a quantum oracle is a powerful pattern that extends to constraint satisfaction, combinatorial optimization, and many other domains." ] }, { @@ -1428,7 +1428,7 @@ "- Grover's algorithm involves repeating a series of operations (commonly called the \"Grover operator\") a number of times $t,$ chosen to make the target states optimally likely to be measured.\n", "- Grover's algorithm can be run with fewer than $t$ iterations and still amplify the target states.\n", "- Grover's algorithm fits into the query model of computation and makes the most sense when one person controls the search and another controls/constructs the oracle. It may also be useful as a subroutine in other quantum computations.\n", - "- An oracle can be built from *problem constraints* rather than from knowledge of the solution, as demonstrated with the minesweeper example.\n", + "- An oracle can be built from *problem constraints* rather than from knowledge of the solution, as demonstrated with the Minesweeper example.\n", "\n", "\n", "### T/F questions:\n",