{ "cells": [ { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "# Grover's Algorithm\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "---\n", "\n", "## Overview\n", "\n", "This notebook demonstrates Grover's algorithm applied to an example of searching for 2 marked items in a small unsorted database. Grover's algorithm illustrates patterns and structure that are also used in other quantum algorithms, such as:\n", "\n", "- [Deutsch-Jozsa algorithm](https://nvidia.github.io/cuda-quantum/latest/applications/python/deutsch_jozsa.html) (distinguishing constant from balanced functions)\n", "- Simon’s algorithm (finding hidden periodicity)\n", "- [Shor’s algorithm](https://nvidia.github.io/cuda-quantum/latest/applications/python/shors.html) (factoring via [quantum Fourier transform](https://nvidia.github.io/cuda-quantum/latest/applications/python/quantum_fourier_transform.html)).\n", "\n", "For a more thorough explanation of Grover's algorithm, check out the [CUDA-Q Academic repository](https://github.com/NVIDIA/cuda-q-academic/blob/main/qis-examples/grovers.ipynb).\n", "\n", "Before we get started, we will need to import a few libraries:\n" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import cudaq\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", "#cudaq.set_target(\"nvidia\")" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "---\n", "\n", "## Problem\n", "\n", "We consider the problem of searching for a marked element or a set of marked elements in an unstructured database. We can make this explicit by considering a database made up of binary strings of length $n$. Let $\\mathbb{B}^n$ denote the set of binary strings of length $n$. A Boolean function\n", "$$f: \\mathbb{B}^n\n", "\\to \\{0,1\\}$$\n", "encodes the marked elements, where $f(x) =1$ if $x$ is a marked string. Our goal is to find all strings $x$ such that $f(x) = 1$.\n", "\n", "Classically, if we have no prior knowledge about $f$ (i.e., it is given as a black-box oracle), the best strategy requires $O(N)$ evaluations, where $N = 2^n$ is the total number of binary strings. However, there exists a quantum algorithm due to L. Grover that finds a solution using only $O(\\sqrt{N})$ oracle queries ([Grover, 1996](https://arxiv.org/abs/quant-ph/9605043)). \n", "\n", "We will use computational basis states on $n$ qubits to represent the $2^n$ elements in the database $B^n$. Our goal is to create a quantum kernel that separates the marked states from the non-marked states. That is, sampling from the kernel yields a marked state with high probability and a non-marked state with low probability. \n", "\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "\n", "\n", "In this notebook, we will use a specific example to illustrate the steps and key concepts of Grover's algorithm. \n", "\n", "Let $n=4$ and mark the states `1001` and `1111`. \n", "\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "## Structure of Grover's Algorithm\n", "\n", "Grover's Algorithm can be broken down into the following steps:\n", "\n", "1. Preparation: Initialize $n$ qubits in an equal superposition state. \n", "2. Oracle Application: Apply the oracle operator to flip the phase of the marked states (i.e., multiply them by $-1$).\n", "3. Amplitude Amplification: Use the diffusion operator to amplify the amplitudes of the marked states.\n", "4. Iteration: Repeat Steps 2 and 3 a specified number of times, which depends on the number of marked elements and $n$.\n", "5. Measurement: Measure the qubits. With high probability, the result will be one of the marked states.\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "### Step 1: Preparation\n", "The first step of Grover's algorithm requires initializing $n$ qubits in a state of equal superposition:\n", "\n", "$$\n", "\\ket{\\xi}:= H^{\\otimes n} (|0\\rangle^{\\otimes n}) = \\frac{1}{\\sqrt{N}} \\sum\\limits_{i=0}^{N-1} |i\\rangle,\n", "$$\n", "where each binary string is identified with the integer it represents (e.g., $|5\\rangle = |0101\\rangle$).\n", "\n", "The kernel in the code block below places the $n$ qubits in an equal superposition state.\n" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Kernel to create an equal superposition state of qubits initialized to |0>\n", "@cudaq.kernel\n", "def equal_superposition(qubits_in_zero_state : cudaq.qview):\n", " h(qubits_in_zero_state)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "### Good and Bad States\n", "\n", "We can simplify our analysis of Grover's Algorithm by focusing on two useful quantum states, which we'll refer to as the \"good\" and \"bad\" states. The \"good\" state captures the marked bitstrings and the \"bad\" state is orthogonal to the \"good\" state.\n", "\n", "Suppose there are $t$ marked states, i.e., there are $t$ elements $x \\in \\mathbb{B}^n$ with $f(x) = 1$. Letting $N=2^n$, we introduce the following quantum states:\n", "\n", "$$\n", "|G\\rangle := \\frac{1}{\\sqrt{t}} \\sum\\limits_{i, f(i) = 1} |i\\rangle, \\quad |B\\rangle := \\frac{1}{\\sqrt{N - t}} \\sum\\limits_{i, f(i) = 0} |i\\rangle.\n", "$$\n", "\n", "These are the uniform superpositions of marked and unmarked states, referred to as the \"good\" and \"bad\" states, respectively. \n", "\n", "Rewriting the uniform superposition state $\\ket{\\xi}$ in terms of $|G\\rangle$ and $|B\\rangle$, we obtain:\n", "\n", "$$\n", "\\ket{\\xi} = \\frac{1}{\\sqrt{N}} \\sum\\limits_{i, f(i) = 1} |i\\rangle + \\frac{1}{\\sqrt{N}} \\sum\\limits_{i, f(i) = 0} |i\\rangle\n", "= \\frac{\\sqrt{t}}{\\sqrt{N}} |G\\rangle + \\frac{\\sqrt{N - t}}{\\sqrt{N}} |B\\rangle.\n", "$$\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "\n", "\n", "Let's see what this look likes for our example of $n=4$ and marked states `1001` and `1111`. Here $\\ket{\\xi} = \\frac{1}{16}\\sum_{k=0}^{15}\\ket{k}$ since there are 4 qubits and 16 computational basis states with $\\ket{0} = \\ket{0000}, \\ket{1} = \\ket{0001}, \\cdots \\ket{15} = \\ket{1111}$. The good state is a equal superposition of the states $\\ket{9} =\\ket{1001}$ and $\\ket{15} =\\ket{1111}$: \n", "$$\\ket{G} = \\frac{1}{\\sqrt{2}}(\\ket{9}+\\ket{15} )= \\frac{1}{\\sqrt{2}}(\\ket{1001}+\\ket{1111}).$$\n", "\n", "The bad state is an equal superposition of the remaining states:\n", "$$\\ket{B} = \\frac{1}{\\sqrt{14}}(\\ket{0}+\\ket{1}+\\ket{2}+\\cdots+\\ket{8}+\\ket{10}+\\cdots+\\ket{14}) = \\frac{1}{\\sqrt{14}}\\sum_{x\\in B^4}f(x)\\ket{x}. $$\n", "\n", "Notice that $\\ket{G}$ and $\\ket{B}$ are orthogonal. \n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "\n", "Next, we observe that the coefficients $\\frac{\\sqrt{t}}{\\sqrt{N}}$ and $\\frac{\\sqrt{N - t}}{\\sqrt{N}}$ are real numbers satisfying:\n", "\n", "$$\n", "\\left(\\frac{\\sqrt{t}}{\\sqrt{N}}\\right)^2 + \\left(\\frac{\\sqrt{N - t}}{\\sqrt{N}}\\right)^2 = 1.\n", "$$\n", "\n", "This naturally leads us to apply a trigonometry identity to define an angle $\\theta$ such that:\n", "\n", "$$\n", "\\theta = \\arcsin\\left(\\frac{\\sqrt{t}}{\\sqrt{N}}\\right).\n", "$$\n", "\n", "With this notation, we can rewrite $\\ket{\\xi}$ as:\n", "\n", "$$\n", "\\ket{\\xi} = \\sin(\\theta) |G\\rangle + \\cos(\\theta) |B\\rangle.\n", "$$\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "For our example, we have 2 marked states and 4 qubits, in other words $t =2$ and $ N = 2^4 = 16$.\n", "In this case, $\\theta = \\arcsin(\\frac{\\sqrt{2}}{\\sqrt{16}}) = \\arcsin(\\frac{1}{\\sqrt{8}}))\\approx 21^\\circ$. " ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "Let us now examine the geometric picture behind our current discussion. We'll consider the ambient Hilbert space to be spanned by the standard basis vectors $|0\\rangle, |1\\rangle, \\dots, |N-1\\rangle$, where the full dimension is $N = 2^n$. Since the uniform superposition state $|\\xi\\rangle$ can be expressed as a linear combination of the states $|G\\rangle$ and $|B\\rangle$ with real coefficients, all three states $|\\xi\\rangle, |G\\rangle,$ and $|B\\rangle$ reside in a two-dimensional real subspace of the ambient Hilbert space, which we can visualize as a 2D plane as in the image below. Since, $|G\\rangle$ and $|B\\rangle$ are orthogonal, we can imagine them graphed as unit vectors in the positive $y$ and positive $x$ directions, respectively. From our previous expression, $\\ket{\\xi} = \\sin(\\theta) |G\\rangle + \\cos(\\theta) |B\\rangle,$ we see that the state $|\\xi\\rangle$ forms an angle $\\theta$ with $|B\\rangle$.\n", "\n", "
\n", " \n", "
\n", "\n", "Given that the number of marked states $t$ is typically small compared to $N$, it follows that $\\theta = \\arcsin\\left(\\sqrt{\\frac{t}{N}}\\right)$ is a small angle. This assumption is reasonable, as otherwise, a sufficient number of independent queries to the oracle would likely yield a solution through classical search methods.\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "### Step 2: Oracle application\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "After we have created a state of equal superposition, the good state is marked by flipping its phase. This is done with a **phase oracle**. A phase oracle $U$ is a unitary operation that has the property that for a computational basis state $\\ket{x}$\n", "\n", "$$\n", "U |x\\rangle = \n", "\\begin{cases} \n", "-|x\\rangle & \\text{if } |x\\rangle \\text{ is marked} \\\\\n", "|x\\rangle & \\text{if } |x\\rangle \\text{ is not marked}\n", "\\end{cases}\n", "$$\n", "\n", "Let's consider our example of the two marked states $\\ket{9} =\\ket{1001}$ and $\\ket{15} =\\ket{1111}$. We'll first write a unitary matrix $U_{15}$ that flips the computational basis state $\\ket{15}$ but keeps all other computational basis states fixed. We work through this marked state first because we have a built-in gate that carries out the required action, and we'll see how we can adapt it to mark other marked states. In particular, the multi-controlled Z gate applies a phase flip (-1) when all control qubits are in state |1⟩, and does nothing otherwise. Let's see this in action:\n" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Define U_15 so that U_15|1111> = -|1111> but fixes \n", "# all other computational basis states |x>\n", "\n", "# Set the number of qubits for the computational basis states\n", "num_qubits = 4\n", "\n", "\n", "# Using phase kickback, apply a multi-controlled Z gate\n", "# with the auxiliary qubit as the target and all other qubits\n", "# as the control\n", "@cudaq.kernel\n", "def U15(qubits: cudaq.qvector):\n", " z.ctrl(qubits.front(len(qubits) - 1), qubits.back())\n", "\n", "# Define U_9 so that U_9|1001> = -|1001> but fixes \n", "# all other computational basis states |x>\n", "# By wrapping the U15 kernel with x gates applied to \n", "# qubits 1 and 2 we're able to mark the state |1001> similarly\n", "@cudaq.kernel\n", "def U9(qubits: cudaq.qvector):\n", "\n", " x(qubits[1])\n", " x(qubits[2])\n", " z.ctrl(qubits.front(len(qubits) - 1), qubits.back())\n", " x(qubits[1])\n", " x(qubits[2])\n", " \n", "# Define a phase oracle that flips the phase of both 1111 and 1001, fixing all other computational basis states\n", "# assuming that the aux_qubit is initialized in the minus state\n", "@cudaq.kernel\n", "def phase_oracle(qubits: cudaq.qvector):\n", " U9(qubits)\n", " U15(qubits)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "### Step 3: Amplitude amplification\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "The main idea behind Grover's algorithm is to construct an operator that performs a clockwise rotation by $2\\theta$ in the two-dimensional plane spanned by the state vectors $|G\\rangle$ and $|B\\rangle$. This is carried out through a composition of two rotations. First $|\\xi\\rangle$ is reflected over $|B\\rangle$ (by a rotation operation $r_B$) and then this state is reflected over $|\\xi\\rangle$ by a rotation operation $r_\\xi$, as depicted in the animation below.\n", "\n", "![](https://raw.githubusercontent.com/NVIDIA/cuda-q-academic/refs/heads/main/images/grovers.gif)\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "#### Reflecting over the |0000> State\n", "\n", "Before defining $r_\\xi$, we'll first define a gate sequence that will reflect a state over the all zero state.\n", "\n", "For \\( n = 4 \\), the reflection operator \n", "$$\n", "r_0 = 2 |0^{\\otimes 4} \\rangle \\langle 0^{\\otimes 4} | - \\text{Id}\n", "$$\n", "acts as the identity on $|0000\\rangle$ and multiplies all other computational basis states by $ -1 $, or equivalently flips the phase of $|0000\\rangle$ fixing all other computational basis states.\n", "\n", "This is coded in the cell block below." ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Reflection about the all zero state\n", "\n", "@cudaq.kernel\n", "def all_zero_reflection(qubits: cudaq.qview):\n", " num_qubits = len(qubits)\n", " x(qubits) \n", " z.ctrl(qubits[0:num_qubits-1], qubits[num_qubits-1])\n", " x(qubits)\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "#### Reflecting over the equal superposition state\n", "\n", "Now let's adapt the `all_zero_reflection` to instead reflect about the equal superposition state. To do this we'll wrap the `all_zero_reflection` kernel with Hadamard gates which will transform the qubits from the equal superposition state to the all zero state and back.\n", "\n" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [], "source": [ "# Reflection about the equal superposition state\n", "\n", "# Wrap the all_zero_reflection kernel with hadamard gates applied to the n qubits\n", "@cudaq.kernel\n", "def reflection_about_xi(qubits : cudaq.qview):\n", " h(qubits)\n", " all_zero_reflection(qubits)\n", " h(qubits)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "Now that we've defined $r_\\xi$, we're only left with defining $r_B$. But we've actually already done that! Notice that the controlled-phase oracle that we discussed earlier has the effect of reflecting the state $\\ket{\\xi}$ over the state $\\ket{B}$, which is exactly what we need for $r_B$." ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "#### Completing Step 3\n", "\n", "\n", "We are now able to realize the iterated operator in Grover's algorithm, which we will denote by $\\mathcal{G}$.\n", "\n", "$$\n", "\\mathcal{G} = r_\\xi \\circ r_B = H^{\\otimes n} \\big( 2|0^{\\otimes n} \\rangle \\langle 0^{\\otimes n}| - \\text{Id} \\big) H^{\\otimes n} \\mathcal{O}_f.\n", "$$\n", "The circuit diagram below puts together steps 1 through 3:\n", "
\n", " \n", "
\n", "\n", "Running this circuit initializes $\\ket{\\xi}$ and performs a rotation by $2\\theta$ \\(twice the angle between $|\\xi\\rangle$ and $|B\\rangle$\\) in the direction from $|B\\rangle$ to $|G\\rangle$.\n", "\n", "
\n", " \n", "
\n", "\n", "Let's verify that the state resulting from one iteration of Grover's algorithm brings us closer to the good state, $\\ket{G}$. In particular, notice that the amplitudes of `1001` and `1111` in the resulting state have been amplified compared to the equal superposition of states.\n" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false }, "outputs": [ { "data": { "image/png": "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8Pvvv79w/4iIiIhKkyKtsbt48aK++0FERERExVSkYFe7dm107NgR//nPf/Dw4UN994mIiIiIiqBIwe748eNo1KgRwsLC4OrqinfffReHDx/Wd9+IiIiI6AUUKdg1adIEixYtwo0bN7BixQokJiaiTZs2aNiwIRYuXIhbt27pu59ERERE9AzFuo6dhYUF+vTpg02bNuHf//43Lly4gIkTJ8LDwwODBw9GYmKivvpJRERERM9QrGB39OhRvPfee3Bzc8PChQsxceJExMfHY+fOnbhx4wZeffVVffWTiIiIiJ6hSJc7WbhwIVauXIm4uDh0794dq1evRvfu3WFm9ign1qhRA6tWrUL16tX12VciIiIieooiBbsvv/wSw4cPx9ChQ+Hm5lZoG2dnZyxfvrxYnSMiIiKi51ekYHf+/PlntrG0tMSQIUOK8vREREREVARFWmO3cuVKbNq0qcD2TZs24bvvvit2p4iIiIjoxRUp2M2ZMweVK1cusN3Z2RmffPJJsTtFRERERC+uSMEuISEBNWrUKLDd09MTCQkJxe4UEREREb24IgU7Z2dnxMTEFNh+8uRJVKpUqdidIiIiIqIXV6Rg99Zbb2Hs2LHYu3cvcnJykJOTgz179uD9999H//799d1HIiIiInoORTordvbs2bh8+TI6d+4MC4tHT5Gbm4vBgwdzjR0RERGRkRQp2FlaWmLjxo2YPXs2Tp48ifLly8PHxweenp767h8RERERPaciBbs8Xl5e8PLy0ldfiIiIiKgYihTscnJysGrVKuzevRs3b95Ebm6uzv49e/bopXNERERE9PyKFOzef/99rFq1Cj169EDDhg2h0Wj03S8iIiIiekFFCnYbNmzA//3f/6F79+767g8RERERFVGRLndiaWmJ2rVr67svRERERFQMRQp2EyZMwKJFiyAi+u4PERERERVRkQ7F/vHHH9i7dy+2bduGBg0aoFy5cjr7N2/erJfOEREREdHzK1Kwc3BwwGuvvabvvhARERFRMRQp2K1cuVLf/SAiIiKiYirSGjsAyM7Oxq5du/DVV18hNTUVAHDjxg2kpaXprXNERERE9PyKNGN35coVBAUFISEhARkZGejatStsbW3x73//GxkZGVi2bJm++0lEREREz1CkGbv3338fzZo1w927d1G+fHll+2uvvYbdu3frrXNERERE9PyKNGP3+++/4+DBg7C0tNTZXr16dVy/fl0vHSMiIiKiF1OkGbvc3Fzk5OQU2H7t2jXY2toWu1NERERE9OKKFOwCAgLw2WefKfc1Gg3S0tIwY8YMfswYERERkZEU6VDsggULEBgYiPr16+Phw4cYMGAAzp8/j8qVK2P9+vX67iMRERERPYciBbtq1arh5MmT2LBhA2JiYpCWlobg4GAMHDhQ52QKIiIiIio5Rb6OnYWFBQYNGoTIyEgsXboUI0aMeOFQd+DAAfTq1Qvu7u7QaDTYsmWLzn4RwfTp0+Hm5oby5cujS5cuOH/+vE6bO3fuYODAgbCzs4ODgwOCg4MLXEsvJiYGbdu2hbW1NTw8PBAZGVmkMRMRERGZsiLN2K1evfqp+wcPHvxcz5Oeno7GjRtj+PDh6NOnT4H9kZGRWLx4Mb777jvUqFEDH330EQIDA3HmzBlYW1sDAAYOHIjExETs3LkTWVlZGDZsGEaOHIl169YBALRaLQICAtClSxcsW7YMp06dwvDhw+Hg4ICRI0e+4MiJiIiITJdGRORFH+To6KhzPysrC/fv34elpSUqVKiAO3fuvHhHNBr897//Re/evQE8mq1zd3fHhAkTMHHiRABASkoKXFxcsGrVKvTv3x9nz55F/fr1ceTIETRr1gwAsH37dnTv3h3Xrl2Du7s7vvzyS3z44YdISkpSLs8yefJkbNmyBX///fdz9U2r1cLe3h4pKSmws7N74bEREZmS8B0ag9f4d8ALv7UQGYQaft5fJIcU6VDs3bt3dW5paWmIi4tDmzZt9HbyxKVLl5CUlIQuXboo2+zt7eHn54eoqCgAQFRUFBwcHJRQBwBdunSBmZkZDh06pLRp166dzjX3AgMDERcXh7t37xZaOyMjA1qtVudGREREZOqKvMbucXXq1MHcuXPx/vvv6+X5kpKSAAAuLi46211cXJR9SUlJcHZ21tlvYWEBJycnnTaFPUf+Go+bM2cO7O3tlZuHh0fxB0RERERkYHoLdsCjUHXjxg19PqVRTJkyBSkpKcrt6tWrxu4SERER0TMV6eSJn376See+iCAxMRFffPEFWrdurZeOubq6AgCSk5Ph5uambE9OTkaTJk2UNjdv3tR5XHZ2Nu7cuaM83tXVFcnJyTpt8u7ntXmclZUVrKys9DIOIiIiopJSpGCXd4JDHo1GgypVqqBTp05YsGCBPvqFGjVqwNXVFbt371aCnFarxaFDhzB69GgAgL+/P+7du4djx47B19cXALBnzx7k5ubCz89PafPhhx8iKysL5cqVAwDs3LkTdevWLXASCBEREVFpVqRgl5ubq5fiaWlpuHDhgnL/0qVLiI6OhpOTE1566SWMGzcOH3/8MerUqaNc7sTd3V0Jlt7e3ggKCsI777yDZcuWISsrC6Ghoejfvz/c3d0BAAMGDEBERASCg4MRHh6O06dPY9GiRfj000/1MgYiIiIiU1GkYKcvR48eRceOHZX7YWFhAIAhQ4Zg1apV+OCDD5Ceno6RI0fi3r17aNOmDbZv365cww4A1q5di9DQUHTu3BlmZmbo27cvFi9erOy3t7fHjh07EBISAl9fX1SuXBnTp0/nNeyIiIhIdYp0Hbu8APY8Fi5c+KJPb3J4HTsiUhM1XNeL6Hmp4ef9RXJIkWbsTpw4gRMnTiArKwt169YFAJw7dw7m5uZo2rSp0k6jMfyLSURERESPFCnY9erVC7a2tvjuu++UExDu3r2LYcOGoW3btpgwYYJeO0lEREREz1ak69gtWLAAc+bM0Tmr1NHRER9//LHezoolIiIiohdTpGCn1Wpx69atAttv3bqF1NTUYneKiIiIiF5ckYLda6+9hmHDhmHz5s24du0arl27hh9++AHBwcHo06ePvvtIRERERM+hSGvsli1bhokTJ2LAgAHIysp69EQWFggODsa8efP02kEiIiIiej5FCnYVKlTA0qVLMW/ePMTHxwMAatWqBRsbG712joiIiIieX5EOxeZJTExEYmIi6tSpAxsbGxThknhEREREpCdFCna3b99G586d4eXlhe7duyMxMREAEBwczEudEBERERlJkYLd+PHjUa5cOSQkJKBChQrK9jfffBPbt2/XW+eIiIiI6PkVaY3djh078Ntvv6FatWo62+vUqYMrV67opWNERERE9GKKNGOXnp6uM1OX586dO7Cysip2p4iIiIjoxRUp2LVt2xarV69W7ms0GuTm5iIyMhIdO3bUW+eIiIiI6PkV6VBsZGQkOnfujKNHjyIzMxMffPABYmNjcefOHfz555/67iMRERERPYcizdg1bNgQ586dQ5s2bfDqq68iPT0dffr0wYkTJ1CrVi1995GIiIiInsMLz9hlZWUhKCgIy5Ytw4cffmiIPhERERFREbzwjF25cuUQExNjiL4QERERUTEU6VDsoEGDsHz5cn33hYiIiIiKoUgnT2RnZ2PFihXYtWsXfH19C3xG7MKFC/XSOSIiIiJ6fi8U7C5evIjq1avj9OnTaNq0KQDg3LlzOm00Go3+ekdEREREz+2Fgl2dOnWQmJiIvXv3Anj0EWKLFy+Gi4uLQTpHRERERM/vhdbYiYjO/W3btiE9PV2vHSIiIiKioinSyRN5Hg96RERERGQ8LxTsNBpNgTV0XFNHREREZBpeaI2diGDo0KGwsrICADx8+BCjRo0qcFbs5s2b9ddDIiIiInouLxTshgwZonN/0KBBeu0MERERERXdCwW7lStXGqofRERERFRMxTp5goiIiIhMB4MdERERkUow2BERERGpBIMdERERkUow2BERERGpBIMdERERkUqYfLCrXr268okX+W8hISEAgA4dOhTYN2rUKJ3nSEhIQI8ePVChQgU4Oztj0qRJyM7ONsZwiIiIiAzmha5jZwxHjhxBTk6Ocv/06dPo2rUrXn/9dWXbO++8g1mzZin3K1SooHydk5ODHj16wNXVFQcPHkRiYiIGDx6McuXK4ZNPPimZQRARERGVAJMPdlWqVNG5P3fuXNSqVQvt27dXtlWoUAGurq6FPn7Hjh04c+YMdu3aBRcXFzRp0gSzZ89GeHg4Zs6cCUtLS4P2n4iIiKikmPyh2PwyMzPxn//8B8OHD4dGo1G2r127FpUrV0bDhg0xZcoU3L9/X9kXFRUFHx8fuLi4KNsCAwOh1WoRGxtbov0nIiIiMiSTn7HLb8uWLbh37x6GDh2qbBswYAA8PT3h7u6OmJgYhIeHIy4uDps3bwYAJCUl6YQ6AMr9pKSkQutkZGQgIyNDua/VavU8EiIiIiL9K1XBbvny5ejWrRvc3d2VbSNHjlS+9vHxgZubGzp37oz4+HjUqlWrSHXmzJmDiIiIYveXiIiIqCSVmkOxV65cwa5duzBixIintvPz8wMAXLhwAQDg6uqK5ORknTZ595+0Lm/KlClISUlRblevXi1u94mIiIgMrtQEu5UrV8LZ2Rk9evR4arvo6GgAgJubGwDA398fp06dws2bN5U2O3fuhJ2dHerXr1/oc1hZWcHOzk7nRkRERGTqSsWh2NzcXKxcuRJDhgyBhcX/uhwfH49169ahe/fuqFSpEmJiYjB+/Hi0a9cOjRo1AgAEBASgfv36ePvttxEZGYmkpCRMmzYNISEhsLKyMtaQiIiIiPSuVAS7Xbt2ISEhAcOHD9fZbmlpiV27duGzzz5Deno6PDw80LdvX0ybNk1pY25ujq1bt2L06NHw9/eHjY0NhgwZonPdOyIiIiI1KBXBLiAgACJSYLuHhwf279//zMd7enri119/NUTXiIiIiExGqVljR0RERERPx2BHREREpBIMdkREREQqwWBHREREpBIMdkREREQqwWBHREREpBIMdkREREQqwWBHREREpBIMdkREREQqwWBHREREpBIMdkREREQqwWBHREREpBIMdkREREQqwWBHREREpBIMdkREREQqwWBHREREpBIMdkREREQqwWBHREREpBIMdkREREQqwWBHREREpBIMdkREREQqwWBHREREpBIMdkREREQqwWBHREREpBIMdkREREQqwWBHREREpBIMdkREREQqwWBHREREpBIMdkREREQqwWBHREREpBIMdkREREQqwWBHREREpBIMdkREREQqwWBHREREpBImHexmzpwJjUajc6tXr56y/+HDhwgJCUGlSpVQsWJF9O3bF8nJyTrPkZCQgB49eqBChQpwdnbGpEmTkJ2dXdJDISIiIjI4C2N34FkaNGiAXbt2KfctLP7X5fHjx+OXX37Bpk2bYG9vj9DQUPTp0wd//vknACAnJwc9evSAq6srDh48iMTERAwePBjlypXDJ598UuJjISIiIjIkkw92FhYWcHV1LbA9JSUFy5cvx7p169CpUycAwMqVK+Ht7Y2//voLLVu2xI4dO3DmzBns2rULLi4uaNKkCWbPno3w8HDMnDkTlpaWJT0cIiIiIoMx6UOxAHD+/Hm4u7ujZs2aGDhwIBISEgAAx44dQ1ZWFrp06aK0rVevHl566SVERUUBAKKiouDj4wMXFxelTWBgILRaLWJjY59YMyMjA1qtVudGREREZOpMOtj5+flh1apV2L59O7788ktcunQJbdu2RWpqKpKSkmBpaQkHBwedx7i4uCApKQkAkJSUpBPq8vbn7XuSOXPmwN7eXrl5eHjod2BEREREBmDSh2K7deumfN2oUSP4+fnB09MT//d//4fy5csbrO6UKVMQFham3NdqtQx3REREZPJMesbucQ4ODvDy8sKFCxfg6uqKzMxM3Lt3T6dNcnKysibP1dW1wFmyefcLW7eX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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Define the Grover diffusion operator\n", "\n", "@cudaq.kernel\n", "def diffusion_operator(qubits: cudaq.qview):\n", "\n", " # Apply Hadamard gates\n", " h(qubits)\n", " # Apply rotation about the all zero state\n", " all_zero_reflection(qubits)\n", " # Apply Hadamard gates\n", " h(qubits)\n", "\n", "num_qubits = 4 \n", "\n", "# Apply the Grover diffusion operation to the equal superposition state\n", "@cudaq.kernel\n", "def one_iteration(num_qubits: int):\n", " qubits = cudaq.qvector(num_qubits)\n", " \n", " # Initialize qubits in an equal superposition state\n", " equal_superposition(qubits)\n", " \n", " # Apply the phase oracle once\n", " phase_oracle(qubits)\n", " # Apply one iteration of the diffusion operator\n", " diffusion_operator(qubits)\n", " \n", " # Measure all qubits, except the auxillary qubit\n", " mz(qubits)\n", "\n", "# Sample \n", "sample_result = cudaq.sample(one_iteration, num_qubits, shots_count = 5000)\n", "\n", "\n", "# Plot the histogram of sampling results\n", "\n", "# Define a function to draw the histogram of the results of sampling a kernel\n", "def plot_results(result, num_qubits):\n", " # Define a dictionary of results \n", "\n", " # Initialize the dictionary with all possible bit strings of length 4 for the x axis\n", " result_dictionary = {}\n", "\n", " # Generate all possible bit strings of length num_qubits\n", " for i in range(2**num_qubits):\n", " bitstr = bin(i)[2:].zfill(num_qubits)\n", " result_dictionary[bitstr] = 0\n", "\n", " # Update the results dictionary of results from the circuit sampling\n", " for k,v in result.items():\n", " result_dictionary[k] = v\n", "\n", " # Convert the dictionary to lists for x and y values\n", " x = list(result_dictionary.keys())\n", " y = list(result_dictionary.values())\n", "\n", " # Create the histogram\n", " plt.bar(x, y, color='#76B900')\n", "\n", " # Add title and labels\n", " plt.title(\"Sampling\")\n", " plt.xlabel(\"Bitstrings\")\n", " plt.ylabel(\"Frequency\")\n", "\n", " # Rotate x-axis labels for readability\n", " plt.xticks(rotation=45)\n", "\n", " # Show the plot\n", " plt.tight_layout()\n", " plt.show()\n", "\n", "\n", "plot_results(sample_result, num_qubits)\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "### Steps 4 and 5: Iteration and measurement\n", "\n", "Depending on $n$ and the number of marked states $t$, one iteration of the gate sequence $\\mathcal{G}$ may not amplifiy the good states enough to distinguish them from the bad states. However, iterating this sequence one more time will result in a vector $\\pi-3\\theta$ radians away from the state $\\ket{G}$, further amplifying the good states. We can repeat this until we are close enough to the good state. But we have to be careful not to repeat this gate sequence too many times as we may overshoot the good state. \n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "\n", "Edit the `num_iterations` variable in the code block below to compute the angle between the resulting state of `num_iterations` of $\\mathcal{G}$ and the state $\\ket{G}$ along with the histogram of the resulting sampling distribution. Notice how increasing the number of iterations beyond a certain point produces states with lower probability amplitudes of the marked states than desired. Why might this happen? What number of iterations results in a better chance of sampling a marked state? How does this compare from the number of iterations that are prescribed by the formula: \n", "$\n", "m \\approx \\left\\lfloor \\frac{\\pi}{4} \\sqrt{\\frac{N}{t}} \\right\\rfloor?\n", "$\n" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{ 0000:10 0001:31 0010:14 0011:15 0100:23 0101:19 0110:12 0111:18 1000:16 1001:2321 1010:25 1011:20 1100:13 1101:19 1110:15 1111:2429 }\n", "\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAnYAAAHWCAYAAAD6oMSKAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAATUpJREFUeJzt3XlYlPX+//HXoIJmsqmIJqHmhuZy3HHLLXEtUytLS8vy2NHKLLeOJzM7Waaess1WzY6WbadTluaupzI100ws3HdAcwFBBYH37w9/zNdRc4GBwZvn47rmupx77uH1+YzAvLi3cZmZCQAAAFc9P18PAAAAAN5BsQMAAHAIih0AAIBDUOwAAAAcgmIHAADgEBQ7AAAAh6DYAQAAOATFDgAAwCEodgAAAA5BsQOAAsTlcunpp5923585c6ZcLpd27drlszEBuHpQ7AA40q+//qrevXsrMjJSxYsX13XXXaebb75Zr7zyiq+HBgB5xsVnxQJwmh9++EFt27bV9ddfr/79+ys8PFx79+7Vjz/+qO3bt2vbtm2+HuKfcrlcGjdunHurXWZmpk6fPq2AgAC5XC7fDg5AgVfU1wMAAG/75z//qaCgIK1du1bBwcEejx08eNA3g8qhIkWKqEiRIr4eBoCrBLtiATjO9u3bVbt27fNKnSSFhYW5/z1jxgy1a9dOYWFhCggIUK1atfTGG2+c95xKlSqpW7duWr58uRo1aqQSJUqoTp06Wr58uSTp888/V506dVS8eHE1bNhQ69ev93j+gAEDdO2112rHjh2KiYlRyZIlVaFCBT3zzDO61E6TCx1jlz2e7777Tk2aNFHx4sVVpUoVzZo167znb9y4UTfddJNKlCihihUr6tlnn9WMGTM4bg9wKIodAMeJjIzUunXrtGnTpouu98YbbygyMlJPPvmkpkyZooiICP3tb3/Ta6+9dt6627Zt0913363u3btr4sSJOnr0qLp3767Zs2frscceU79+/TR+/Hht375dd9xxh7Kysjyen5mZqU6dOqlcuXKaNGmSGjZsqHHjxmncuHE5muO2bdvUu3dv3XzzzZoyZYpCQkI0YMAAxcbGutfZv3+/2rZtq9jYWI0ZM0aPPfaYZs+erZdffjlHmQCuAgYADrNw4UIrUqSIFSlSxKKjo23kyJH27bffWnp6usd6J06cOO+5MTExVqVKFY9lkZGRJsl++OEH97Jvv/3WJFmJEiVs9+7d7uVvvvmmSbJly5a5l/Xv398k2cMPP+xelpWVZV27djV/f387dOiQe7kkGzdunPv+jBkzTJLt3LnzvPGsXLnSvezgwYMWEBBgjz/+uHvZww8/bC6Xy9avX+9edvjwYQsNDT3vawJwBrbYAXCcm2++WatWrdItt9yiX375RZMmTVJMTIyuu+46ffnll+71SpQo4f53UlKS/vjjD910003asWOHkpKSPL5mrVq1FB0d7b7ftGlTSVK7du10/fXXn7d8x44d541r6NCh7n+7XC4NHTpU6enpWrx48RXPsVatWmrVqpX7ftmyZVWjRg2P3AULFig6Olr169d3LwsNDVXfvn2vOA/A1YFiB8CRGjdurM8//1xHjx7VmjVrNGbMGB0/fly9e/fW5s2bJUnff/+9OnTooJIlSyo4OFhly5bVk08+KUnnFbuzy5skBQUFSZIiIiIuuPzo0aMey/38/FSlShWPZdWrV5ekHB3rdu54JCkkJMQjd/fu3apatep5611oGQBn4KxYAI7m7++vxo0bq3Hjxqpevbruu+8+ffLJJ+rXr5/at2+vmjVraurUqYqIiJC/v7+++eYb/etf/zrvGLk/OzP1z5ZbHl9Jyle5AAo2ih2AQqNRo0aSpPj4eH311VdKS0vTl19+6bH1a9myZXmSnZWVpR07dri30knSli1bJJ05yzUvREZGXvCafQX5On4AcoddsQAcZ9myZRfccvXNN99IkmrUqOHe4nX2eklJSZoxY0aejevVV191/9vM9Oqrr6pYsWJq3759nuTFxMRo1apV2rBhg3vZkSNHNHv27DzJA+B7bLED4DgPP/ywTpw4odtuu001a9ZUenq6fvjhB82dO1eVKlXSfffdp8TERPn7+6t79+7661//qpSUFL399tsKCwtTfHy818dUvHhxLViwQP3791fTpk01f/58ff3113ryySdVtmxZr+dJ0siRI/Xvf/9bN998sx5++GGVLFlS77zzjq6//nodOXKET7IAHIgtdgAcZ/LkyWrbtq2++eYbDR8+XMOHD9eaNWv0t7/9TatXr1ZwcLBq1KihTz/9VC6XS0888YSmT5+uQYMG6dFHH82TMRUpUkQLFixQQkKCRowYobVr12rcuHGaMGFCnuRJZ07sWLZsmaKiovTcc8/ppZdeUv/+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6HIn/v7+qlq1qrfHAgAAgFzIUbF7/PHH9fLLL8vMvD0eAAAA5FCOdsV+9913WrZsmebPn6/atWurWLFiHo9//vnnXhkcAAAALl+Oil1wcLBuu+02b48FAAAAuZCjYjdjxgxvjwMAAAC5lKNj7CQpIyNDixcv1ptvvqnjx49Lkg4cOKCUlBSvDQ4AAACXL0db7Hbv3q1OnTppz549SktL080336xSpUrphRdeUFpamqZPn+7tcQIAAOAScrTF7tFHH1WjRo109OhRlShRwr38tttu05IlS7w2OAAAAFy+HG2x+9///qcffvhB/v7+HssrVaqk/fv3e2VgAAAAuDI52mKXlZWlzMzM85bv27dPpUqVyvWgAAAAcOVyVOw6duyol156yX3f5XIpJSVF48aN42PGAAAAfCRHu2KnTJmimJgY1apVS6dOndLdd9+trVu3qkyZMvrwww+9PUYAAABchhwVu4oVK+qXX37RRx99pI0bNyolJUUDBw5U3759PU6mAAAAQP7JUbGTpKJFi6pfv37eHAsAAAByIUfFbtasWRd9/N57783RYAAAAJBzOSp2jz76qMf906dP68SJE/L399c111xDsQMAAPCBHJ0Ve/ToUY9bSkqK4uLi1LJlS06eAAAA8JEcf1bsuapVq6bnn3/+vK15AAAAyB9eK3bSmRMqDhw44M0vCQAAgMuUo2PsvvzyS4/7Zqb4+Hi9+uqratGihVcGBgAAgCuTo2LXo0cPj/sul0tly5ZVu3btNGXKFG+MCwAAAFcoR8UuKyvL2+MAAABALnn1GDsAAAD4To622A0fPvyy1506dWpOIgAAAHCFclTs1q9fr/Xr1+v06dOqUaOGJGnLli0qUqSIGjRo4F7P5XJ5Z5QAAAC4pBwVu+7du6tUqVJ6//33FRISIunMRYvvu+8+tWrVSo8//rhXBwkAAIBLy9ExdlOmTNHEiRPdpU6SQkJC9Oyzz3JWLAAAgI/kqNglJyfr0KFD5y0/dOiQjh8/nutBAQAA4MrlqNjddtttuu+++/T5559r37592rdvnz777DMNHDhQPXv29PYYAQAAcBlydIzd9OnT9cQTT+juu+/W6dOnz3yhokU1cOBAvfjii14dIAAAAC5PjordNddco9dff10vvviitm/fLkm64YYbVLJkSa8ODgAAAJcvVxcojo+PV3x8vKpVq6aSJUvKzLw1LgAAAFyhHBW7w4cPq3379qpevbq6dOmi+Ph4SdLAgQO51AkAAICP5KjYPfbYYypWrJj27Nmja665xr38zjvv1IIFC7w2OAAAAFy+HB1jt3DhQn377beqWLGix/Jq1app9+7dXhkYAAAArkyOttilpqZ6bKnLduTIEQUEBOR6UAAAALhyOSp2rVq10qxZs9z3XS6XsrKyNGnSJLVt29ZrgwMAAMDly9Gu2EmTJql9+/b66aeflJ6erpEjRyo2NlZHjhzR999/7+0xAgAA4DLkaIvdjTfeqC1btqhly5a69dZblZqaqp49e2r9+vW64YYbvD1GAAAAXIYr3mJ3+vRpderUSdOnT9ff//73vBgTAAAAcuCKt9gVK1ZMGzduzIuxAAAAIBdytCu2X79+evfdd709FgAAAORCjk6eyMjI0HvvvafFixerYcOG531G7NSpU70yOAAAAFy+Kyp2O3bsUKVKlbRp0yY1aNBAkrRlyxaPdVwul/dGBwAAgMt2RcWuWrVqio+P17JlyySd+QixadOmqVy5cnkyOAAAAFy+KzrGzsw87s+fP1+pqaleHRAAAAByJkcnT2Q7t+gBAADAd66o2LlcrvOOoeOYOgAAgILhinfFDhgwQD179lTPnj116tQpDR482H0/+3a5Vq5cqe7du6tChQpyuVz64osvzst76qmnVL58eZUoUUIdOnTQ1q1bPdY5cuSI+vbtq8DAQAUHB2vgwIFKSUnxWGfjxo1q1aqVihcvroiICE2aNOlKpg0AAHBVuKJi179/f4WFhSkoKEhBQUHq16+fKlSo4L6ffbtcqampqlevnl577bULPj5p0iRNmzZN06dP1+rVq1WyZEnFxMTo1KlT7nX69u2r2NhYLVq0SPPmzdPKlSs1aNAg9+PJycnq2LGjIiMjtW7dOr344ot6+umn9dZbb13J1AEAAAq8KzordsaMGV4N79y5szp37nzBx8xML730ksaOHatbb71VkjRr1iyVK1dOX3zxhfr06aPffvtNCxYs0Nq1a9WoUSNJ0iuvvKIuXbpo8uTJqlChgmbPnq309HS999578vf3V+3atbVhwwZNnTrVowACAABc7XJ18kRe2rlzpxISEtShQwf3sqCgIDVt2lSrVq2SJK1atUrBwcHuUidJHTp0kJ+fn1avXu1ep3Xr1vL393evExMTo7i4OB09evSC2WlpaUpOTva4AQAAFHQFttglJCRI0nnXyCtXrpz7sYSEBIWFhXk8XrRoUYWGhnqsc6GvcXbGuSZOnOixazkiIiL3EwIAAMhjBbbY+dKYMWOUlJTkvu3du9fXQwIAALikAlvswsPDJUmJiYkeyxMTE92PhYeH6+DBgx6PZ2Rk6MiRIx7rXOhrnJ1xroCAAAUGBnrcAAAACroCW+wqV66s8PBwLVmyxL0sOTlZq1evVnR0tCQpOjpax44d07p169zrLF26VFlZWWratKl7nZUrV+r06dPudRYtWqQaNWooJCQkn2YDAACQ93xa7FJSUrRhwwZt2LBB0pkTJjZs2KA9e/bI5XJp2LBhevbZZ/Xll1/q119/1b333qsKFSqoR48ekqSoqCh16tRJDz74oNasWaPvv/9eQ4cOVZ8+fVShQgVJ0t133y1/f38NHDhQsbGxmjt3rl5++WUNHz7cR7MGAADIG1d0uRNv++mnn9S2bVv3/eyy1b9/f82cOVMjR45UamqqBg0apGPHjqlly5ZasGCBihcv7n7O7NmzNXToULVv315+fn7q1auXpk2b5n48KChICxcu1JAhQ9SwYUOVKVNGTz31FJc6AQAAjuMyPvD1kpKTkxUUFKSkpCSOtwNw1Ru1MO8/CvKFjry1oGBwwvf7lfSQAnuMHQAAAK4MxQ4AAMAhKHYAAAAOQbEDAABwCIodAACAQ1DsAAAAHIJiBwAA4BAUOwAAAIeg2AEAADgExQ4AAMAhKHYAAAAOQbEDAABwCIodAACAQ1DsAAAAHIJiBwAA4BAUOwAAAIeg2AEAADgExQ4AAMAhKHYAAAAOQbEDAABwCIodAACAQ1DsAAAAHIJiBwAA4BAUOwAAAIeg2AEAADgExQ4AAMAhKHYAAAAOQbEDAABwCIodAACAQ1DsAAAAHIJiBwAA4BAUOwAAAIeg2AEAADgExQ4AAMAhKHYAAAAOQbEDAABwCIodAACAQ1DsAAAAHIJiBwAA4BAUOwAAAIeg2AEAADgExQ4AAMAhKHYAAAAOQbEDAABwCIodAACAQ1DsAAAAHIJiBwAA4BAUOwAAAIeg2AEAADgExQ4AAMAhKHYAAAAOQbEDAABwCIodAACAQ1DsAAAAHIJiBwAA4BAUOwAAAIeg2AEAADgExQ4AAMAhKHYAAAAOQbEDAABwiAJd7J5++mm5XC6PW82aNd2Pnzp1SkOGDFHp0qV17bXXqlevXkpMTPT4Gnv27FHXrl11zTXXKCwsTCNGjFBGRkZ+TwUAACDPFfX1AC6ldu3aWrx4sft+0aL/N+THHntMX3/9tT755BMFBQVp6NCh6tmzp77//ntJUmZmprp27arw8HD98MMPio+P17333qtixYrpueeey/e5AAAA5KUCX+yKFi2q8PDw85YnJSXp3Xff1Zw5c9SuXTtJ0owZMxQVFaUff/xRzZo108KFC7V582YtXrxY5cqVU/369TVhwgSNGjVKTz/9tPz9/fN7OgAAAHmmQO+KlaStW7eqQoUKqlKlivr27as9e/ZIktatW6fTp0+rQ4cO7nVr1qyp66+/XqtWrZIkrVq1SnXq1FG5cuXc68TExCg5OVmxsbF/mpmWlqbk5GSPGwAAQEFXoItd06ZNNXPmTC1YsEBvvPGGdu7cqVatWun48eNKSEiQv7+/goODPZ5Trlw5JSQkSJISEhI8Sl3249mP/ZmJEycqKCjIfYuIiPDuxAAAAPJAgd4V27lzZ/e/69atq6ZNmyoyMlIff/yxSpQokWe5Y8aM0fDhw933k5OTKXcAAKDAK9Bb7M4VHBys6tWra9u2bQoPD1d6erqOHTvmsU5iYqL7mLzw8PDzzpLNvn+h4/ayBQQEKDAw0OMGAABQ0F1VxS4lJUXbt29X+fLl1bBhQxUrVkxLlixxPx4XF6c9e/YoOjpakhQdHa1ff/1VBw8edK+zaNEiBQYGqlatWvk+fgAAgLxUoHfFPvHEE+revbsiIyN14MABjRs3TkWKFNFdd92loKAgDRw4UMOHD1doaKgCAwP18MMPKzo6Ws2aNZMkdezYUbVq1dI999yjSZMmKSEhQWPHjtWQIUMUEBDg49kBAAB4V4Eudvv27dNdd92lw4cPq2zZsmrZsqV+/PFHlS1bVpL0r3/9S35+furVq5fS0tIUExOj119/3f38IkWKaN68eXrooYcUHR2tkiVLqn///nrmmWd8NSUAAIA84zIz8/UgCrrk5GQFBQUpKSmJ4+0AXPVGLXTlecYLHXlrQcHghO/3K+khV9UxdgAAAPhzFDsAAACHoNgBAAA4BMUOAADAISh2AAAADkGxAwAAcAiKHQAAgENQ7AAAAByCYgcAAOAQFDsAAACHoNgBAAA4BMUOAADAISh2AAAADkGxAwAAcAiKHQAAgENQ7AAAAByCYgcAAOAQFDsAAACHoNgBAAA4BMUOAADAISh2AAAADkGxAwAAcAiKHQAAgENQ7AAAAByCYgcAAOAQFDsAAACHoNgBAAA4BMUOAADAISh2AAAADkGxAwAAcAiKHQAAgENQ7AAAAByCYgcAAOAQFDsAAACHoNgBAAA4BMUOAADAISh2AAAADkGxAwAAcAiKHQAAgENQ7AAAAByCYgcAAOAQFDsAAACHoNgBAAA4BMUOAADAISh2AAAADkGxAwAAcAiKHQAAgENQ7AAAAByCYgcAAOAQFDsAAACHoNgBAAA4BMUOAADAISh2AAAADkGxAwAAcAiKHQAAgENQ7AAAAByCYgcAAOAQFDsAAACHoNgBAAA4BMUOAADAIYr6egD56bXXXtOLL76ohIQE1atXT6+88oqaNGni62EVGKMWuvI844WOlucZAAAUVoWm2M2dO1fDhw/X9OnT1bRpU7300kuKiYlRXFycwsLCfD08FGIUahQmfL8DeavQFLupU6fqwQcf1H333SdJmj59ur7++mu99957Gj16tI9HB/hGYX6T9eXcC/Pr7muF9bUvrPMujApFsUtPT9e6des0ZswY9zI/Pz916NBBq1at8uHIPBXmHzzeZAsnXnsUJoX5+70wzz2/FYpi98cffygzM1PlypXzWF6uXDn9/vvv562flpamtLQ09/2kpCRJUnJycp6OMy01T7+8pIvPwZf5hTXb1/nMvfBl+zqfuRe+bF/n+3ru3vz6ZpdRXq0Q2L9/v0myH374wWP5iBEjrEmTJuetP27cOJPEjRs3bty4ceNWYG579+69ZOcpFFvsypQpoyJFiigxMdFjeWJiosLDw89bf8yYMRo+fLj7flZWlo4cOaLSpUvL5cr7zcmXKzk5WREREdq7d68CAwMLTbav8wtrtq/zmXvhy/Z1fmHN9nV+YZ77nzEzHT9+XBUqVLjkuoWi2Pn7+6thw4ZasmSJevToIelMWVuyZImGDh163voBAQEKCAjwWBYcHJwPI82ZwMBAn33z+TLb1/mFNdvX+cy98GX7Or+wZvs6vzDP/UKCgoIua71CUewkafjw4erfv78aNWqkJk2a6KWXXlJqaqr7LFkAAICrXaEpdnfeeacOHTqkp556SgkJCapfv74WLFhw3gkVAAAAV6tCU+wkaejQoRfc9Xq1CggI0Lhx487bbez0bF/nF9ZsX+cz98KX7ev8wprt6/zCPHdvcJldzrmzAAAAKOj8fD0AAAAAeAfFDgAAwCEodgAAAA5BsQMAAHAIih0cqTCfE1RY515Y5w0AZ6PYOdC5b3CF6Q0vMzPT435WVla+j8FXr3dhnXtaWpokKT093Wdj8GVuQRuDrxTWuRfWeUuFe+4Xw+VOHCYuLk6zZ8/Wnj171LJlS7Vs2VI1a9ZUVlaW/PzytscnJiYqKSlJ1atXz9OcP/Pbb7/plVde0YEDBxQVFaXevXurYcOG+ZK9b98+JSYm5lveuQrr3Ddv3qzx48frjz/+UOnSpTV48GC1a9cu3/J37typ3bt3q02bNpLOvNHk5+dJJycn6+TJk/L391dISIhPxpAfv1su5MiRI0pKSpKZqUqVKvmeL535Y6pIkSL5mlkQ5i35Zu4HDx5UYmKiTp48qSZNmuRrdvbPVUZGhooWLdiXAGaLnYNs3rxZTZs21ebNm7V161a98847uvnmm7VkyRL5+fnl6V83v/32m5o0aaJ//OMfio2NzbOcP/P777+rWbNmOnHihIoWLap169apRYsW+uCDD/I8Oy4uTo0aNdJDDz2k7777Ls/zzlVY575lyxZFR0crODhYtWrVkp+fnzp06KBnn31WR48ezZf8xo0b6/bbb9e8efMkSS6XK9+2Ivz666/q3LmzmjdvrpiYGN1///3KyMjIl1K3bds2jR8/XidOnJCfn1++bx3euHGj2rVrp7Zt26pjx47q1KmT9uzZky/Zv//+uwYNGqTjx4+rSJEi520pz0u+nLfk27n/8ssvatmypW699Vbdcsstatiwob777judOHEiz7NjY2PVrVs3HTt2TEWLFlVGRkaeZ+aKwREyMjKsX79+1rdvX/ey9evX28CBA61IkSI2b948MzPLzMz0evb+/futefPmVq9ePWvSpIkNHDjQfv31V6/nXMzf/vY369Gjh/t+YmKijR071ooUKWKvv/66mZllZWV5PTc+Pt7atGljLVq0sM6dO1vHjh1t5cqVXs+5mMI697///e928803eyx76623zOVy2ejRoy01NTXPshMTE61Tp07WsWNH69u3r9WqVcv++9//uh/Pi9f7bLt27bKyZcva448/bp999plNmjTJqlWrZnXq1LGtW7fmafbWrVstLCzMSpcubcOHD3e/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5Po95s+y/8zJkyeta9euFhoa6pX3N2+i2F1lTp48aQ0aNDjv+Jm4uDgrU6aMdevWzb0sMTHR5s+fb999953t3bs3z7N79Ojh8Wa3Zs0ac7lctnbt2lxnZ2Vl2QsvvGBdunSxhQsX2rhx46xmzZp/Wu7Mzhx3Fxsbm+utVZeTfe6b/MaNG+26667z+EWYWy1atHDvgsne1bF//36rW7eutWjRwn3wcEZGhtfmfjnZN910k8f316+//uqVuWdlZdm7775rPXv2tGXLltmMGTOsXLlyHuXq3N1Ev/32m+3du9dj12le5p+7y2nLli3WvHlzr5RKM7OxY8dax44dPZZNmzbNQkND7YknnrD09HQ7cOCAvfPOO9agQQNr3LixtW3b1itbiP8su3Tp0jZq1ChLSEhwL09LS7Nhw4bZNddc45VSd+jQIevWrZt17drV7r77bgsJCbElS5aYmWe5O3LkiC1evNg6duxo7dq1s1tuuSXXW0kvlX2u06dP29ixY6148eJeed0nT55srVu39lg2e/Zsq1OnjvXt29d2795tqampXp/3pfLr1q1r9957r0d5S09P99rcjx49ar1797ZevXrZww8/bH5+fjZ37lwz8yx3aWlptn37dhswYIDdfvvt540pL7LPlZGRYc8//7z5+/vn2/HLV4Jid5VJSUmx6667zqNUZO+W+uWXX6xkyZL29NNP+yx7woQJHs85+5i03IqPj7eZM2ea2ZnSml2wzp7vuccB5Wf2ub/0vXUQcVZWlp08edIaNWpkgwcPdi/PLrLx8fEWGhpqDz30kFfycpI9dOhQj+d5a+6HDh2yTz/91MzO/GHx3nvvWbly5Tx2xZx9ML+3XU7+uaU+JSXFa/mPP/64u1ydXSKnT59u11xzjb322mse6588edJOnjyZ59klS5a0N954w8z+7/v+4Ycf9tofMhs3brS+ffvawoULbevWrXbfffdZSEiILV682MzOvOYXKlne+Pm/VPaFcv/5z396tVjVr1/fjh8/7pH1ySefWNWqVW3MmDHnPcebv/cull+tWjX7+9//7rHL87nnnvPK3Ldv326PPvqoffXVV3b8+HEbPXq0+fn5uTck/NluVm+clXqp7Avlvvfee7Z58+ZcZ+cFit1VaMqUKVaxYkWPA8Ozf7CfffZZa9q0qR0+fDhPztC53OzsN4K8PP3+wIED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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "num_qubits = 4 \n", "num_iterations = 2 # CHANGE ME\n", "\n", "# Apply the Grover diffusion operation to the equal superposition state\n", "@cudaq.kernel\n", "def grovers(num_qubits: int, num_iterations : int):\n", " qubits = cudaq.qvector(num_qubits)\n", "\n", " # Initialize qubits in an equal superposition state\n", " equal_superposition(qubits)\n", " \n", " # Apply num_iteration iterations of the diffusion operator\n", " for _ in range(num_iterations):\n", " phase_oracle(qubits)\n", " diffusion_operator(qubits)\n", " \n", " # Measure all qubits, except the auxillary qubit\n", " mz(qubits)\n", "\n", "\n", "# Sample\n", "sample_result = cudaq.sample(grovers, num_qubits, num_iterations, shots_count = 5000)\n", "\n", "print(sample_result)\n", "\n", "# Plot the histogram of sampling results\n", "plot_results(sample_result, num_qubits)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "As an exercise, adapt the code to search for a different set of unmarked elements on another unstructured database." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.12" } }, "nbformat": 4, "nbformat_minor": 4 }