{ "cells": [ { "cell_type": "markdown", "id": "29990c15", "metadata": {}, "source": [ "# Getting started with Perceval" ] }, { "cell_type": "markdown", "id": "c1e5e2ac", "metadata": {}, "source": [ "In this notebook, we aim to reproduce the $\\mathsf{CNOT}$ Gate to \n", "evaluate its performance while demonstrating key features of Perceval. We use as basis the implementation from [[1]](#Reference)." ] }, { "cell_type": "code", "execution_count": 1, "id": "bb751c13", "metadata": {}, "outputs": [], "source": [ "import perceval as pcvl\n", "import sympy as sp\n", "import numpy as np" ] }, { "cell_type": "markdown", "id": "cb91de5c", "metadata": {}, "source": [ "### Ralph CNOT Gate" ] }, { "cell_type": "markdown", "id": "d1d6cd32", "metadata": {}, "source": [ "We start by describing the circuit as defined by the paper above- it is a circuit on six modes (labelled from 0 to 5 from top to bottom) consisting of five beam splitters. Modes 1 and 2 contain the control system while modes 3 and 4 encode the target system. Modes 0 and 5 are unoccupied ancillary modes." ] }, { "cell_type": "code", "execution_count": 2, "id": "83ff4732", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Φ_tl=3*pi/2Φ_bl=piΦ_tr=pi/2\n", "Θ=1.910633\n", "\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "\n", "Φ_tl=3*pi/2Φ_bl=piΦ_tr=pi/2\n", "Θ=1.910633\n", "\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Θ=1.910633\n", "\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "1\n", "2\n", "3\n", "4\n", "5\n", "0\n", "1\n", "2\n", "3\n", "4\n", "5\n", "" ], "text/plain": [ "" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cnot = pcvl.Circuit(6, name=\"Ralph CNOT\")\n", "cnot.add((0, 1), pcvl.BS.H(pcvl.BS.r_to_theta(1/3), phi_tl = -np.pi/2, phi_bl = np.pi, phi_tr = np.pi / 2))\n", "cnot.add((3, 4), pcvl.BS.H())\n", "cnot.add((2, 3), pcvl.BS.H(pcvl.BS.r_to_theta(1/3), phi_tl = -np.pi/2, phi_bl = np.pi, phi_tr = np.pi / 2))\n", "cnot.add((4, 5), pcvl.BS.H(pcvl.BS.r_to_theta(1/3)))\n", "cnot.add((3, 4), pcvl.BS.H())\n", "pcvl.pdisplay(cnot)" ] }, { "cell_type": "markdown", "id": "ed7b0498", "metadata": {}, "source": [ "We can then simulate this circuit using the `Naive` backend on four different input states corresponding to the two-qubit computational basis states. We use `Analyzer` to analyse the performance of the gate. Using heralds, we can get a better visualisation of what the circuit actually does." ] }, { "cell_type": "code", "execution_count": 3, "id": "edafa605", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "RALPH CNOT\n", "\n", "\n", "\n", "\n", "\n", "Φ_tl=3*pi/2Φ_bl=piΦ_tr=pi/2\n", "Θ=1.910633\n", "\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "\n", "Φ_tl=3*pi/2Φ_bl=piΦ_tr=pi/2\n", "Θ=1.910633\n", "\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "\n", "Θ=1.910633\n", "\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "[herald0]\n", "0\n", "\n", "[herald1]\n", "0\n", "\n", "[herald0]\n", "0\n", "\n", "[herald1]\n", "0\n", "" ], "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p = pcvl.Processor(\"Naive\", cnot)\n", "p.set_postselection(pcvl.PostSelect(\"[1,2]==1 & [3,4]==1\"))\n", "p.add_herald(0, 0)\n", "p.add_herald(5, 0)\n", "\n", "pcvl.pdisplay(p, recursive=True)" ] }, { "cell_type": "code", "execution_count": 4, "id": "87a00b53", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
00 01 10 11
00 1 0 0 0
01 0 1 0 0
10 0 0 0 1
11 0 0 1 0
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "performance=1/9, fidelity=100.000%\n" ] } ], "source": [ "states = {\n", " pcvl.BasicState([1, 0, 1, 0]): \"00\",\n", " pcvl.BasicState([1, 0, 0, 1]): \"01\",\n", " pcvl.BasicState([0, 1, 1, 0]): \"10\",\n", " pcvl.BasicState([0, 1, 0, 1]): \"11\"\n", "}\n", "\n", "ca = pcvl.algorithm.Analyzer(p, states)\n", "ca.compute(expected={\"00\": \"00\", \"01\": \"01\", \"10\": \"11\", \"11\": \"10\"})\n", "pcvl.pdisplay(ca)\n", "print(\"performance=%s, fidelity=%.3f%%\" % (pcvl.simple_float(ca.performance)[1], ca.fidelity * 100))" ] }, { "cell_type": "markdown", "id": "0cd5fcf4", "metadata": {}, "source": [ "Beyond the actual logic function, what is interesting with this gate us that it produces entangled states that we will be trying to check with CHSH experiment when the source is not perfect." ] }, { "cell_type": "markdown", "id": "c0fb4c12", "metadata": {}, "source": [ "### Checking for entanglement with CHSH experiment\n", "![https://en.wikipedia.org/wiki/File:Two_channel_bell_test.svg](https://upload.wikimedia.org/wikipedia/commons/thumb/3/39/Two_channel_bell_test.svg/1340px-Two_channel_bell_test.svg.png)\n", "*https://en.wikipedia.org/wiki/File:Two_channel_bell_test.svg*" ] }, { "cell_type": "markdown", "id": "4e523cfc", "metadata": {}, "source": [ "To reproduce this Bell test protocol, we define a new circuit which uses the $\\mathsf{CNOT}$ gate implemented above as a sub-circuit. The parameters $a$ and $b$ describe the measurement bases used by players $A$ and $B$ in the runs of the Bell-test. We define a photon source with a brightness of 40% and a purity of 99% that will be used by the `Processor`." ] }, { "cell_type": "code", "execution_count": 5, "id": "6b889867", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "RALPH CNOT\n", "\n", "\n", "\n", "\n", "\n", "Φ_tl=3*pi/2Φ_bl=piΦ_tr=pi/2\n", "Θ=1.910633\n", "\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "\n", "Φ_tl=3*pi/2Φ_bl=piΦ_tr=pi/2\n", "Θ=1.910633\n", "\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "\n", "Θ=1.910633\n", "\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Θ=a\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "\n", "Θ=b\n", "\n", "H\n", "\n", "\n", "\n", "\n", "\n", "[herald0]\n", "0\n", "\n", "[herald1]\n", "0\n", "\n", "[herald0]\n", "0\n", "\n", "[herald1]\n", "0\n", "" ], "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "source = pcvl.Source(emission_probability=0.40, multiphoton_component=0.01)\n", "\n", "QPU = pcvl.Processor(\"SLOS\", 4, source)\n", "QPU.add(0, pcvl.BS.H())\n", "\n", "# Remove postprocess function as it would mean nothing to the new QPU\n", "p.clear_postselection()\n", "\n", "QPU.add(0, p)\n", "\n", "a = pcvl.Parameter(\"a\")\n", "b = pcvl.Parameter(\"b\")\n", "\n", "QPU.add(0, pcvl.BS.H(theta=a))\n", "QPU.add(2, pcvl.BS.H(theta=b))\n", "\n", "pcvl.pdisplay(QPU, recursive=True)" ] }, { "cell_type": "markdown", "id": "1c96eaec", "metadata": {}, "source": [ "We start by setting the values of the two parameters to 0, meaning that the beam splitters after the $\\mathsf{CNOT}$ effectively act as the identity. " ] }, { "cell_type": "code", "execution_count": 6, "id": "1e935739", "metadata": {}, "outputs": [], "source": [ "a.set_value(0)\n", "b.set_value(0)" ] }, { "cell_type": "markdown", "id": "3451e7d1", "metadata": {}, "source": [ "We now state that our photons will be inputted on ports 1 and 2 (using the 0-index convention, and not counting heralded modes)." ] }, { "cell_type": "code", "execution_count": 7, "id": "1b626655", "metadata": {}, "outputs": [], "source": [ "QPU.with_input(pcvl.BasicState([0, 1, 1, 0]))" ] }, { "cell_type": "markdown", "id": "fcdef3f6", "metadata": {}, "source": [ "We now detail the different state vectors that are the probabilistic inputs to the circuit. The most frequent input is the empty state, followed by two states with only a single photon on either of the input ports, then by the expected nominal input $|0,1,1,0,0,0\\rangle$. Here, the heralded modes are shown because if there were a photon on them, they would also have the imperfect source. They are represented at the end of the state (the two last modes) as they have been added after the declaration of the processor." ] }, { "cell_type": "code", "execution_count": 8, "id": "e8af01a9", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
state probability
|0,0,0,0,0,0> 9/25
|0,0,{_:0},0,0,0> 0.2395
|0,{_:0},0,0,0,0> 0.2395
|0,{_:0},{_:0},0,0,0> 0.1594
|0,0,{_:0}{_:1},0,0,0> 4.8193e-4
|0,{_:0}{_:1},0,0,0,0> 4.8193e-4
|0,{_:0}{_:1},{_:0},0,0,0> 3.2064e-4
|0,{_:0},{_:0}{_:1},0,0,0> 3.2064e-4
|0,{_:0}{_:1},{_:0}{_:2},0,0,0>0
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "pcvl.pdisplay(QPU.source_distribution, precision=1e-4)" ] }, { "cell_type": "markdown", "id": "73af9f32", "metadata": {}, "source": [ "We can then check the output state distribution corresponding to this input distribution. By default, since our input state had 2 photons, only states having at least 2 detected photons are kept. This can be changed using `min_detected_photons_filter`." ] }, { "cell_type": "code", "execution_count": 9, "id": "cbee9802", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
state probability
|0,0,2,0> 0.248773
|0,2,0,0> 0.248773
|0,1,0,1> 0.124293
|0,0,1,1> 0.124293
|1,1,0,0> 0.124293
|1,0,1,0> 0.124293
|0,1,1,0> 0.001874
|1,0,0,1> 0.000374752
|0,0,3,0> 0.000249333
|0,1,1,1> 0.000249333
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "output_distribution=QPU.probs()[\"results\"]\n", "pcvl.pdisplay(output_distribution, max_v=10)" ] }, { "cell_type": "markdown", "id": "3cda6b52", "metadata": {}, "source": [ "Let us run now the experiment with increasing value of g2 in the range $[0, 0.2]$ with a brightness of $0.15$ and check the CHSH inequality." ] }, { "cell_type": "code", "execution_count": 10, "id": "3f29137a", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "9de3d33bbfa243e98e85492ca2e993fc", "version_major": 2, "version_minor": 0 }, "text/plain": [ " 0%| | 0/40 [00:00" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", "plt.title(\"CHSH value with purity\")\n", "plt.xlabel(\"g2 (%)\")\n", "plt.ylabel(\"bell inegality\")\n", "plt.axhline(y=2, linewidth=2, color=\"red\", label= 'horizontal-line')\n", "plt.plot(x, y, color =\"green\")\n", "plt.grid(color='b', dashes=(3, 2, 1, 2))\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "1329a625", "metadata": {}, "source": [ "Beyond 13% of g2, we are crossing the value $2$, i.e. not violating anymore the $|CHSH|\\le 2$ inegality!" ] }, { "cell_type": "markdown", "id": "e55db30c", "metadata": {}, "source": [ "## Reference\n", "\n", "> [1] T. C. Ralph, N. K. Langford, T. B. Bell, and A. G. White. Linear optical controlled-NOT gate in the coincidence basis. [Physical Review A](https://link.aps.org/doi/10.1103/PhysRevA.65.062324), 65(6):062324, June 2002. Publisher: American Physical Society." ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }