{ "cells": [ { "attachments": {}, "cell_type": "markdown", "id": "3a271506", "metadata": {}, "source": [ "# 2-mode Grover's search algorithm" ] }, { "attachments": {}, "cell_type": "markdown", "id": "34fa32af", "metadata": {}, "source": [ "We implement in this notebook a 2-mode optical realization of Grover's search algorithm, based on Kwiat et al. (2000). Grover’s search algorithm: An optical approach. [Journal of Modern Optics](https://doi.org/10.1080/09500340008244040), 47(2–3), 257–266." ] }, { "attachments": {}, "cell_type": "markdown", "id": "e22c5dde", "metadata": {}, "source": [ "## Introduction" ] }, { "attachments": {}, "cell_type": "markdown", "id": "c04c528f", "metadata": {}, "source": [ "### Motivation\n", "\n", "Searching for a specific item (called the marked item) in an unstructured list of $N$ items requires $O(N)$ accesses to the list classically. Grover showed in 1996 that is possible for a quantum computer to achieve this using only $O\\left(\\sqrt{N}\\right)$ iterations." ] }, { "attachments": {}, "cell_type": "markdown", "id": "08145e4a", "metadata": {}, "source": [ "### Algorithm summary\n", "\n", "For a list of size $N$, Grover's algorithm requires $\\log (N)$ qubits. The algorithm starts by setting each qubit in the superposition state $\\frac{1}{\\sqrt{2}}\\left(|0\\rangle+|1\\rangle\\right)$. Then it applies $O\\left(\\sqrt{N}\\right)$ iterations of a subroutine called inversion-about-mean, whose goal is to skew this initial uniform superposition state towards the desired marked state such the probability of measuring the marked state is amplified. This subroutine requires the application of an oracle unitary, which applies a relative $\\pi$ phase shift only to the quantum state encoding the item we are looking for in the database." ] }, { "attachments": {}, "cell_type": "markdown", "id": "5690fa9d", "metadata": {}, "source": [ "### Kwiat et al. implementation details\n", "\n", "The optical implementation of Kwiat et al. uses the polarization and path degree of freedom of a single beam to achieve a 2-qubit optical implementation of Grover's search algorithm. Although $N=4$ here, calculations show that only a single application of the inversion-about-mean subroutine is required.\n", "\n", "In an effort to reduce the number of optical components used in the experimental setup, the authors work with a compiled version of the circuit, which we will reproduce here using Perceval." ] }, { "attachments": {}, "cell_type": "markdown", "id": "7bc2f8dc", "metadata": {}, "source": [ "## Perceval implementation" ] }, { "attachments": {}, "cell_type": "markdown", "id": "904f535e", "metadata": {}, "source": [ "### Initialisation" ] }, { "cell_type": "code", "execution_count": 1, "id": "4d4c8ff1", "metadata": {}, "outputs": [], "source": [ "import math\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "import perceval as pcvl\n", "from perceval.algorithm import Analyzer" ] }, { "attachments": {}, "cell_type": "markdown", "id": "09fa856a", "metadata": {}, "source": [ "We create in Perceval a circuit with two spatial modes, $a$ and $b$ denoting resapectively the lower and upper spatial modes. For clarity, the different equivalent encodings for each of the four basis states are given below in order:\n", "- marked item encoding: $\\left|\"00\"\\right\\rangle$, $\\left|\"01\"\\right\\rangle$, $\\left|\"10\"\\right\\rangle$, $\\left|\"11\"\\right\\rangle$\n", "- Kwiat et al. path and polarization encoding: $\\left|aH\\right\\rangle$, $\\left|aV\\right\\rangle$, $\\left|bH\\right\\rangle$, $\\left|bV\\right\\rangle$\n", "- Perceval path and polarization encoding: $\\left|0, 1:H\\right\\rangle$, $\\left|0, 1:V\\right\\rangle$, $\\left|1:H, 0\\right\\rangle$, $\\left|1:V, 0\\right\\rangle$\n", "\n", "We first define these states and their mode equivalent in Perceval:" ] }, { "cell_type": "code", "execution_count": 2, "id": "b8084f08", "metadata": {}, "outputs": [], "source": [ "states = [pcvl.BasicState(\"|0,{P:H}>\"),\n", " pcvl.BasicState(\"|0,{P:V}>\"),\n", " pcvl.BasicState(\"|{P:H},0>\"),\n", " pcvl.BasicState(\"|{P:V},0>\"),\n", " ]\n", "\n", "states_modes = [\n", " pcvl.BasicState([0, 0, 0, 1]),\n", " pcvl.BasicState([0, 0, 1, 0]),\n", " pcvl.BasicState([0, 1, 0, 0]),\n", " pcvl.BasicState([1, 0, 0, 0])\n", "]" ] }, { "attachments": {}, "cell_type": "markdown", "id": "fab191db", "metadata": {}, "source": [ "We use the following unitary matrix to represent the beamsplitters:" ] }, { "cell_type": "code", "execution_count": 3, "id": "a3560b8f", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}\\frac{\\sqrt{2}}{2} & - \\frac{\\sqrt{2}}{2}\\\\\\frac{\\sqrt{2}}{2} & \\frac{\\sqrt{2}}{2}\\end{matrix}\\right]$" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "bsry = pcvl.BS.Ry()\n", "pcvl.pdisplay(bsry.U)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "54638f8d", "metadata": {}, "source": [ "The half-wave plates are defined in the article as:" ] }, { "cell_type": "code", "execution_count": 4, "id": "54d17968", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "ξ=pi/2\n", "δ=pi/2\n", "\n", "\n", "Φ=3*pi/2\n", "\n", "0\n", "0\n", "" ], "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def HWP(xsi):\n", " hwp = pcvl.Circuit(m=1)\n", " hwp.add(0, pcvl.HWP(xsi)).add(0, pcvl.PS(-math.pi/2))\n", " return hwp\n", "\n", "pcvl.pdisplay(HWP(math.pi/2))" ] }, { "attachments": {}, "cell_type": "markdown", "id": "3d3c98ab", "metadata": {}, "source": [ "### Circuit Construction" ] }, { "attachments": {}, "cell_type": "markdown", "id": "b2c267cb", "metadata": {}, "source": [ "We divide the compiled circuit of Kwiat et al. in three parts: [state initialization](#state-initialization-circuit), [oracle](#oracle) and [inversion about mean](#inversion-about-mean). However, due to the compilation, each individual part does not act exactly as described in the introduction." ] }, { "attachments": {}, "cell_type": "markdown", "id": "14ee9683", "metadata": {}, "source": [ "\n", "#### State initialization circuit" ] }, { "cell_type": "code", "execution_count": 5, "id": "f6718866", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "ξ=pi/8\n", "δ=pi/2\n", "\n", "\n", "Φ=3*pi/2\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Ry\n", "\n", "\n", "Φ=pi\n", "\n", "\n", "\n", "0\n", "1\n", "0\n", "1\n", "" ], "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "init_circuit = (pcvl.Circuit(m=2, name=\"Initialization\")\n", " // HWP(math.pi / 8)\n", " // bsry\n", " // pcvl.PS(-math.pi))\n", "\n", "pcvl.pdisplay(init_circuit)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "e8278f70", "metadata": {}, "source": [ "#### Oracle\n", "\n", "The oracle circuit can be initialised so that any one of the four list elements are marked. This is controlled via the integer parameter $mark \\in [0, 3]$." ] }, { "cell_type": "code", "execution_count": 6, "id": "96aba62a", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "ξ=0\n", "δ=pi/2\n", "\n", "\n", "Φ=3*pi/2\n", "\n", "\n", "\n", "\n", "δ=pi/2\n", "\n", "\n", "\n", "ξ=0\n", "δ=pi/2\n", "\n", "\n", "Φ=3*pi/2\n", "\n", "\n", "\n", "0\n", "1\n", "0\n", "1\n", "" ], "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def oracle(mark: int):\n", " \"\"\"Values 0, 1, 2 and 3 for parameter 'mark' respectively mark the elements \"00\", \"01\", \"10\" and \"11\" of the list.\"\"\"\n", " oracle_circuit = pcvl.Circuit(m=2, name='Oracle')\n", " # The following dictionary translates n into the corresponding component settings\n", " oracle_dict = {0: (1, 0), 1: (0, 1), 2: (1, 1), 3: (0, 0)}\n", " PC_state, LC_state = oracle_dict[mark]\n", " # Mode b\n", " if PC_state == 1:\n", " oracle_circuit //= HWP(0)\n", " oracle_circuit.add(0, pcvl.PR(math.pi/2))\n", " if LC_state == 1:\n", " oracle_circuit //= HWP(0)\n", " # Mode a\n", " if LC_state == 1:\n", " oracle_circuit //= (1, HWP(0))\n", " if PC_state == 1:\n", " oracle_circuit //= (1, HWP(0))\n", " return oracle_circuit\n", "\n", "pcvl.pdisplay(oracle(0))" ] }, { "attachments": {}, "cell_type": "markdown", "id": "50596a16", "metadata": {}, "source": [ "#### Inversion about mean" ] }, { "cell_type": "code", "execution_count": 7, "id": "ef839994", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Ry\n", "\n", "\n", "\n", "ξ=pi/4\n", "δ=pi/2\n", "\n", "\n", "Φ=3*pi/2\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Ry\n", "\n", "\n", "0\n", "1\n", "0\n", "1\n", "" ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "inversion_circuit = (pcvl.Circuit(m=2, name='Inversion')\n", " // bsry\n", " // HWP(math.pi / 4)\n", " // bsry)\n", "\n", "pcvl.pdisplay(inversion_circuit)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "4daf70f2", "metadata": {}, "source": [ "#### Detection\n", "\n", "The article also uses a detection circuit of the form:" ] }, { "cell_type": "code", "execution_count": 8, "id": "31ad50c7", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "1\n", "2\n", "3\n", "0\n", "1\n", "2\n", "3\n", "" ], "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "detection_circuit = pcvl.Circuit(m=4, name='Detection')\n", "detection_circuit.add((0, 1), pcvl.PBS())\n", "detection_circuit.add((2, 3), pcvl.PBS())\n", "\n", "pcvl.pdisplay(detection_circuit)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "76acc62f", "metadata": {}, "source": [ "However, Perceval allows us to filter out the photon's polarization state, meaning that there is no need to expand the circuit to four output spatial modes.\n", "\n", "For now, we will need this particular circuit." ] }, { "attachments": {}, "cell_type": "markdown", "id": "2326568e", "metadata": {}, "source": [ "#### Final circuit setup \n", "\n", "As above, the value of parameter 'mark' indicates which element of the list needs to be found." ] }, { "cell_type": "code", "execution_count": 9, "id": "1b0bffde", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Grover optical circuit for searching database element \"00\":\n" ] }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "INITIALIZATION\n", "\n", "\n", "\n", "ξ=pi/8\n", "δ=pi/2\n", "\n", "\n", "Φ=3*pi/2\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Ry\n", "\n", "\n", "Φ=pi\n", "\n", "\n", "ORACLE\n", "\n", "\n", "\n", "ξ=0\n", "δ=pi/2\n", "\n", "\n", "Φ=3*pi/2\n", "\n", "\n", "\n", "\n", "δ=pi/2\n", "\n", "\n", "\n", "ξ=0\n", "δ=pi/2\n", "\n", "\n", "Φ=3*pi/2\n", "\n", "\n", "INVERSION\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Ry\n", "\n", "\n", "\n", "ξ=pi/4\n", "δ=pi/2\n", "\n", "\n", "Φ=3*pi/2\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Ry\n", "\n", "\n", "\n", "\n", "\n", "\n", "DETECTION\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "1\n", "2\n", "3\n", "0\n", "1\n", "2\n", "3\n", "" ], "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def grover_circuit(mark: int):\n", " grover = pcvl.Circuit(m=4, name='Grover')\n", " grover.add(0, init_circuit).add(0, oracle(mark)).add(0, inversion_circuit)\n", " grover.add(1, pcvl.PERM([1, 0])).add(0, detection_circuit)\n", " return grover\n", "\n", "print('Grover optical circuit for searching database element \"00\":')\n", "pcvl.pdisplay(grover_circuit(0), recursive=True)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "922a8f12", "metadata": {}, "source": [ "## Grover algorithm execution\n", "\n", "We can finally simulate Grover's algorithm for marked database elements \"00\", \"01\", \"10\" and \"11\"." ] }, { "cell_type": "code", "execution_count": 10, "id": "0f000dac", "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Circuit simulation\n", "input_state = pcvl.BasicState(\"|{P:H},0, 0, 0>\")\n", "results_list = [] # probability amplitudes storage\n", "\n", "for mark in range(4):\n", " p = pcvl.Processor(\"SLOS\", grover_circuit(mark))\n", " a = Analyzer(p, input_states=[input_state], output_states=states_modes)\n", " results_list.append(a.distribution[0])\n", "\n", "# Plot data\n", "labels = ['\"00\"', '\"01\"', '\"10\"', '\"11\"']\n", "x = np.arange(4) # label locations\n", " \n", "fig, ax = plt.subplots(dpi=150)\n", "for result, state in zip(results_list, states):\n", " ax.bar(x, result.real, 0.1, label=str(state))\n", "\n", "ax.set_xlabel('Marked database element')\n", "ax.set_ylabel('Detection probability') \n", "ax.set_xticks(x, labels)\n", "ax.legend()\n", "ax.grid(True, axis='x')\n", "plt.show()" ] }, { "attachments": {}, "cell_type": "markdown", "id": "659482dd", "metadata": {}, "source": [ "As demonstrated by the graph above, Grover's algorithm indeed finds the marked database element!" ] }, { "attachments": {}, "cell_type": "markdown", "id": "d32d028f", "metadata": {}, "source": [ "## Reference\n", "\n", "> Kwiat et al. Grover’s search algorithm: An optical approach. [Journal of Modern Optics](https://doi.org/10.1080/09500340008244040), 47(2–3), 257–266 (2000).\n" ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }