{ "cells": [ { "cell_type": "markdown", "id": "275dc7b20c7a685e", "metadata": {}, "source": [ "# Optical Circuits" ] }, { "cell_type": "markdown", "id": "9939669dd5f675f", "metadata": {}, "source": [ "This tutorial covers Perceval Circuit build, display and usage.\n", "\n", "In Perceval, a *circuit* represents a setup of linear optics (LO) components, used\n", "to guide and act on photons. Simple examples of circuits are common optical devices such as beam\n", "splitters or phase shifters.\n", "\n", "A circuit has a fixed number of *spatial modes* (sometimes also called\n", "*paths*) $m$, which is the same for input as for output\n", "spatial modes.\n", "\n", "In particular, note that:\n", "\n", "* *single photon sources* aren't circuits, since they do not have input spatial\n", " modes (they don't guide or act on incoming photons, but *produce*\n", " photons that are sent into a circuit),\n", "* *photon detectors* aren't circuits either, for similar reasons" ] }, { "cell_type": "markdown", "id": "344937564c8718a0", "metadata": {}, "source": [ "## I. LO-components\n", "\n", "The linear optics components are the elementary blocks which act on Perceval quantum states.\n", "\n", "It's important to know how to handle the most basic components and understand their effects.\n", "\n", "At first, let's see what's possible with a `PERM` instance (permutation), a `BS` (beam splitter) and a `PS` (phase shifter).\n", "\n", "

All circuits and components can be displayed with `pcvl.pdisplay`

" ] }, { "cell_type": "code", "execution_count": 1, "id": "993339f1eecb9630", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "PERM\n", "PERM([2, 0, 1])\n" ] }, { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}0 & 1 & 0\\\\0 & 0 & 1\\\\1 & 0 & 0\\end{matrix}\\right]$" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "1\n", "2\n", "0\n", "1\n", "2\n", "" ], "text/plain": [ "" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import perceval as pcvl\n", "import numpy as np\n", "from perceval.components import PS, BS, PERM\n", "\n", "## Permutation\n", "perm = PERM([2, 0, 1])\n", "\n", "print(perm.name)\n", "print(perm.describe())\n", "pcvl.pdisplay(perm.definition())\n", "pcvl.pdisplay(perm)" ] }, { "cell_type": "code", "execution_count": 2, "id": "91dec3b5a482de7e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "PS\n", "PS(phi=pi)\n" ] }, { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}e^{i \\left(max_{error} \\operatorname{Uniform}{\\left(-1,1 \\right)} + \\phi\\right)}\\end{matrix}\\right]$" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Φ=pi\n", "\n", "0\n", "0\n", "" ], "text/plain": [ "" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "## Phase shifter\n", "ps = PS(phi=np.pi)\n", "\n", "print(ps.name)\n", "print(ps.describe())\n", "pcvl.pdisplay(ps.definition())\n", "pcvl.pdisplay(ps) # A pdisplay call on a circuit/processor needs to be the last line of a cell in a notebook" ] }, { "cell_type": "code", "execution_count": 3, "id": "97932b67e0b75319", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "BS.Rx() unitary matrix\n" ] }, { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}e^{i \\left(\\phi_{tl} + \\phi_{tr}\\right)} \\cos{\\left(\\frac{\\theta}{2} \\right)} & i e^{i \\left(\\phi_{bl} + \\phi_{tr}\\right)} \\sin{\\left(\\frac{\\theta}{2} \\right)}\\\\i e^{i \\left(\\phi_{br} + \\phi_{tl}\\right)} \\sin{\\left(\\frac{\\theta}{2} \\right)} & e^{i \\left(\\phi_{bl} + \\phi_{br}\\right)} \\cos{\\left(\\frac{\\theta}{2} \\right)}\\end{matrix}\\right]$" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "BS.H() unitary matrix\n" ] }, { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}e^{i \\left(\\phi_{tl} + \\phi_{tr}\\right)} \\cos{\\left(\\frac{\\theta}{2} \\right)} & e^{i \\left(\\phi_{bl} + \\phi_{tr}\\right)} \\sin{\\left(\\frac{\\theta}{2} \\right)}\\\\e^{i \\left(\\phi_{br} + \\phi_{tl}\\right)} \\sin{\\left(\\frac{\\theta}{2} \\right)} & - e^{i \\left(\\phi_{bl} + \\phi_{br}\\right)} \\cos{\\left(\\frac{\\theta}{2} \\right)}\\end{matrix}\\right]$" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "BS.Ry() unitary matrix\n" ] }, { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}e^{i \\left(\\phi_{tl} + \\phi_{tr}\\right)} \\cos{\\left(\\frac{\\theta}{2} \\right)} & - e^{i \\left(\\phi_{bl} + \\phi_{tr}\\right)} \\sin{\\left(\\frac{\\theta}{2} \\right)}\\\\e^{i \\left(\\phi_{br} + \\phi_{tl}\\right)} \\sin{\\left(\\frac{\\theta}{2} \\right)} & e^{i \\left(\\phi_{bl} + \\phi_{br}\\right)} \\cos{\\left(\\frac{\\theta}{2} \\right)}\\end{matrix}\\right]$" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "BS displays its convention as a small label\n" ] }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\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": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "## Beam splitters\n", "bs_rx = BS.Rx() # By default, a beam splitter follows the Rx gate convention, so bs=BS() has the same matrix\n", "\n", "# But other conventions exist too:\n", "bs_h = BS.H()\n", "bs_ry = BS.Ry()\n", "\n", "## Check the difference in the unitary definition:\n", "print(\"BS.Rx() unitary matrix\")\n", "pcvl.pdisplay(bs_rx.definition())\n", "print(\"BS.H() unitary matrix\")\n", "pcvl.pdisplay(bs_h.definition())\n", "print(\"BS.Ry() unitary matrix\")\n", "pcvl.pdisplay(bs_ry.definition())\n", "print(\"BS displays its convention as a small label\")\n", "pcvl.pdisplay(bs_ry)" ] }, { "cell_type": "code", "execution_count": 4, "id": "5362e58546be0273", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}e^{0.392699081698724 i}\\end{matrix}\\right]$" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}0.92388 + 0.382683 i\\end{matrix}\\right]$" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "A Phase Shifter with a symbolic value for phi:\n" ] }, { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}e^{i \\psi}\\end{matrix}\\right]$" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# You can ask for the symbolic matrix value of your component with the attribute U\n", "my_ps = PS(phi=np.pi/8)\n", "pcvl.pdisplay(my_ps.U)\n", "# And for the numerical value with the method compute_unitary\n", "pcvl.pdisplay(my_ps.compute_unitary())\n", "\n", "# - by using the syntax pcvl.P to create a symbolic variable\n", "# (note that you cannot compute the numerical value of your component anymore)\n", "print(\"A Phase Shifter with a symbolic value for phi:\")\n", "ps = PS(phi=pcvl.P(r'\\psi')) # Note the use of a raw string to be able to get a Latex visualization of the variable\n", "pcvl.pdisplay(ps.U)" ] }, { "cell_type": "code", "execution_count": 5, "id": "25d4e21b9c871e2e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "A default Beam Splitter:\n" ] }, { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}\\frac{\\sqrt{2}}{2} & \\frac{\\sqrt{2} i}{2}\\\\\\frac{\\sqrt{2} i}{2} & \\frac{\\sqrt{2}}{2}\\end{matrix}\\right]$" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "A Beam Splitter with a numerical value for theta:\n" ] }, { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}\\cos{\\left(5 \\right)} & i \\sin{\\left(5 \\right)}\\\\i \\sin{\\left(5 \\right)} & \\cos{\\left(5 \\right)}\\end{matrix}\\right]$" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}0.283662 & - 0.958924 i\\\\- 0.958924 i & 0.283662\\end{matrix}\\right]$" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "A Phase Shifter with a symbolic value for phi:\n" ] }, { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}e^{i \\psi}\\end{matrix}\\right]$" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "A Beam Splitter with a symbolic variable...\n" ] }, { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}\\cos{\\left(\\frac{toto}{2} \\right)} & i \\sin{\\left(\\frac{toto}{2} \\right)}\\\\i \\sin{\\left(\\frac{toto}{2} \\right)} & \\cos{\\left(\\frac{toto}{2} \\right)}\\end{matrix}\\right]$" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "... set to a numerical value\n" ] }, { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}0.283662 & - 0.958924 i\\\\- 0.958924 i & 0.283662\\end{matrix}\\right]$" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# If you do it for a Beam Splitter, you can see that, by default, theta = pi/2 and the phi angles are 0\n", "print(\"A default Beam Splitter:\")\n", "pcvl.pdisplay(BS().compute_unitary()) # this is a balanced beam splitter\n", "print(\"\")\n", "\n", "# To control the value of the parameters of a component, several choices are possible:\n", "# - by setting a numerical value during the component creation\n", "print(\"A Beam Splitter with a numerical value for theta:\")\n", "bs_rx = BS.Rx(theta=10)\n", "pcvl.pdisplay(bs_rx.U)\n", "pcvl.pdisplay(bs_rx.compute_unitary())\n", "print(\"\")\n", "\n", "# - by using the syntax pcvl.P (or its alias pcvl.Parameter) to create a symbolic variable\n", "# (note that you cannot compute the numerical value of your component anymore)\n", "print(\"A Phase Shifter with a symbolic value for phi:\")\n", "ps = PS(phi=pcvl.P(r'\\psi'))\n", "pcvl.pdisplay(ps.U)\n", "print(\"\")\n", "\n", "# - you can still modify the value of a symbolic variable after its creation\n", "# This is not true for a numerical variable!\n", "print(\"A Beam Splitter with a symbolic variable...\")\n", "bs_rx = BS(theta=pcvl.P('toto'))\n", "pcvl.pdisplay(bs_rx.U)\n", "bs_rx.assign({'toto': 10})\n", "print(\"... set to a numerical value\")\n", "pcvl.pdisplay(bs_rx.compute_unitary())" ] }, { "cell_type": "code", "execution_count": 6, "id": "b63da7b78ae01866", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}e^{i \\left(\\phi_{tl} + \\phi_{tr}\\right)} \\cos{\\left(\\frac{\\theta}{2} \\right)} & i e^{i \\left(\\phi_{bl} + \\phi_{tr}\\right)} \\sin{\\left(\\frac{\\theta}{2} \\right)}\\\\i e^{i \\left(\\phi_{br} + \\phi_{tl}\\right)} \\sin{\\left(\\frac{\\theta}{2} \\right)} & e^{i \\left(\\phi_{bl} + \\phi_{br}\\right)} \\cos{\\left(\\frac{\\theta}{2} \\right)}\\end{matrix}\\right]$" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Φ=phi_tl\n", "\n", "\n", "Φ=phi_bl\n", "\n", "\n", "\n", "\n", "\n", "\n", "Θ=theta\n", "\n", "\n", "Rx\n", "\n", "\n", "Φ=phi_tr\n", "\n", "\n", "Φ=phi_br\n", "\n", "\n", "0\n", "1\n", "0\n", "1\n", "" ], "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "## to understand the conventions, you can note that a BS.Rx with the 4 phases phi (top left/right and bottom left/right) can be represented like that\n", "\n", "## For this cell, we needed the syntax to builds circuits... Good transition !\n", "\n", "bs_rx_circuit=pcvl.Circuit(2) // (0, PS(phi=pcvl.P(\"phi_tl\"))) // (1, PS(phi=pcvl.P(\"phi_bl\"))) // BS(theta=pcvl.P('theta')) // (0, PS(phi=pcvl.P(\"phi_tr\"))) // (1, PS(phi=pcvl.P(\"phi_br\")))\n", "\n", "pcvl.pdisplay(bs_rx_circuit.U)\n", "\n", "# we can check it's the same as bs_rx.definition()\n", "pcvl.pdisplay(bs_rx_circuit)" ] }, { "cell_type": "markdown", "id": "baed21bbcbe62da4", "metadata": {}, "source": [ "## II. LO-circuits\n", "\n", "From the LO-components, we can build a LO-circuit, i.e. a sequence of those components acting on our different modes.\n", "\n", "

\n", "A *LO circuit* (just called \"circuit\" here) isn't the same as a\n", "*quantum circuit*. Quantum circuits act on *qubits*, i.e. abstract systems in a 2-dimensional\n", "Hilbert space (or \"computational space\"); while optical circuits act on *photons*\n", "distributed in spatial modes (in the \"Fock space\"). It is possible to simply encode\n", "qubits with photons in an optical circuit; some encodings are\n", "presented in a later tutorial.

\n", "\n", "\n", "\n", "\n", "
![grover-circuit.png](../_static/img/grover-circuit.png)![grover-perceval.png](../_static/img/grover-perceval.png)
\n", "Optimized Grover algorithm (on the left) converted to a Perceval circuit (on the right).\n", "\n", "### 1. Syntax" ] }, { "cell_type": "code", "execution_count": 7, "id": "379106e56a5cf643", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}\\frac{\\sqrt{2} e^{1.5707963267949 i}}{2} & \\frac{\\sqrt{2} i e^{1.5707963267949 i}}{2} & 0\\\\\\frac{i e^{i \\phi}}{2} & \\frac{e^{i \\phi}}{2} & \\frac{\\sqrt{2} i}{2}\\\\- \\frac{e^{i \\phi}}{2} & \\frac{i e^{i \\phi}}{2} & \\frac{\\sqrt{2}}{2}\\end{matrix}\\right]$" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Rx\n", "\n", "\n", "Φ=pi/2\n", "\n", "\n", "Φ=phi\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Rx\n", "\n", "\n", "\n", "\n", "0\n", "1\n", "2\n", "0\n", "1\n", "2\n", "" ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "circuit = pcvl.Circuit(3) # Create an empty 3 mode circuit\n", "\n", "circuit.add(0, BS()) # The beam splitter is added to the circuit on mode 0 and 1\n", " # even though only the first mode is required in `add` method\n", "circuit.add(0, PS(phi=np.pi/2)).add(1, PS(phi=pcvl.P('phi'))).add(1, BS())\n", "\n", "# Equivalent syntax:\n", "# circuit // BS() // PS(phi=np.pi/2) // (1, PS(phi=pcvl.P('phi'))) // (1, BS())\n", "\n", "pcvl.pdisplay(circuit.U)\n", "pcvl.pdisplay(circuit)" ] }, { "cell_type": "markdown", "id": "c7dfe008a08f3fab", "metadata": {}, "source": [ "In the circuit rendering above, the red lines, corresponding to spatial modes, are representing optical\n", "fibers on which photons are sent from the left to the right.\n", "\n", "The syntax ``pcvl.P('phi')`` allows you to use parameters in the circuit, where you can assign a value or not. The behavior of the parameters of a circuit is similar to the case of the components.\n", "\n", "For instance, you can use :" ] }, { "cell_type": "code", "execution_count": 8, "id": "e312d4d89758b996", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[Parameter(name='phi', value=None, min_v=0.0, max_v=6.283185307179586)]\n" ] }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Rx\n", "\n", "\n", "Φ=pi/2\n", "\n", "\n", "Φ=pi\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Rx\n", "\n", "\n", "\n", "\n", "0\n", "1\n", "2\n", "0\n", "1\n", "2\n", "" ], "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "params = circuit.get_parameters()\n", "print(params) # list of the parameters\n", "\n", "# the value is not set, but we can change that with:\n", "params[0].set_value(np.pi)\n", "pcvl.pdisplay(circuit)" ] }, { "cell_type": "markdown", "id": "371e62737ee99bb6", "metadata": {}, "source": [ "### 2. Mach-Zehnder Interferometers\n", "\n", "The beamsplitter's angle $\\theta$ can also be defined as a parameter.\n", "\n", "However, as the reflexivity depends on the mirror, it's hard to have adaptibility on the angle.\n", "Therefore, in practice, we use a [Mach-Zehnder Interferometer](https://en.wikipedia.org/wiki/Mach%E2%80%93Zehnder_interferometer).\n", "\n", "The beamsplitter with a parameterised $\\theta$ is therefore implemented with a parameterised phase shifter $\\phi$ between two fixed beamsplitters.\n", "\n" ] }, { "cell_type": "code", "execution_count": 9, "id": "827e5e9c11411c41", "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "## Exercise: build a circuit implementing the mzi\n", "\n", "## Solution:\n", "mzi = pcvl.Circuit(2) // BS() // (1,PS(phi=pcvl.P(\"phi\"))) // BS()\n", "pcvl.pdisplay(mzi)\n", "\n", "\n", "## Exercise: Check that the parameterised phase allows you to change the reflexivity of your MZI\n", "\n", "## Solution:\n", "import matplotlib.pyplot as plt\n", "\n", "X = np.linspace(0, 2*np.pi, 1000) # We create a list of all different values for theta\n", "Y = []\n", "for theta in X:\n", " phase = mzi.get_parameters()[0]\n", " phase.set_value(theta)\n", " Y.append(abs(mzi.compute_unitary()[0,0])**2) # compute_unitary is numerical, so far faster that mzi.U, which uses symbolic expressions.\n", "\n", "plt.plot(X, Y)\n", "plt.xlabel(\"phi\")\n", "plt.ylabel(\"R\")\n", "plt.show()\n", "\n", "## Note: If you need to create a BS directly from the reflexivity value, please use:\n", "## BS(BS.r_to_theta(reflectivity_value))\n", "## However, be aware that only theta value is stored inside the BS object" ] }, { "cell_type": "markdown", "id": "1b86a736d827c8cd", "metadata": {}, "source": [ "### 3. Universal Circuits\n", "\n", "An operation on the modes of our circuit can also be expressed as a unitary matrix.\n", "\n", "For three modes, the unitary $U=\\begin{pmatrix}\n", "a_{1,1} & a_{1,2} & a_{1,3}\\\\\n", "a_{2,1} & a_{2,2} & a_{2,3} \\\\\n", "a_{3,1} & a_{3,2} & a_{3,3}\n", "\\end{pmatrix}$ performs the following operation on the Fock state basis:\n", "\n", "$$\\begin{array}{rcl}\n", "|1,0,0\\rangle & \\mapsto& a_{1,1}|1,0,0\\rangle + a_{1,2}|0,1,0\\rangle + a_{1,3}|0,0,1\\rangle\\\\\n", "|0,1,0\\rangle & \\mapsto& a_{2,1}|1,0,0\\rangle + a_{2,2}|0,1,0\\rangle + a_{2,3}|0,0,1\\rangle\\\\\n", "|0,0,1\\rangle & \\mapsto& a_{3,1}|1,0,0\\rangle + a_{3,2}|0,1,0\\rangle + a_{3,3}|0,0,1\\rangle\n", "\\end{array}$$" ] }, { "cell_type": "markdown", "id": "f6d508c7a906c732", "metadata": {}, "source": [ "Since 1994, we know that any $U$ on the modes can be implemented as an LO-circuit [Reck's et al](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.73.58).\n", "\n", "This decomposition can be done easily in Perceval using beamsplitters and phase-shifters as follows." ] }, { "cell_type": "code", "execution_count": 10, "id": "84057abdefd0967a", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Φ=3.470785\n", "\n", "\n", "Φ=3.855175\n", "\n", "\n", "Φ=3.790181\n", "\n", "\n", "Φ=5.832253\n", "\n", "\n", "\n", "\n", "\n", "Φ_tr=2.53698\n", "Θ=8.697508\n", "\n", "\n", "Rx\n", "\n", "\n", "\n", "\n", "\n", "\n", "Φ_tr=1.955288\n", "Θ=4.92665\n", "\n", "\n", "Rx\n", "\n", "\n", "\n", "\n", "\n", "\n", "Φ_tr=4.845186\n", "Θ=7.650621\n", "\n", "\n", "Rx\n", "\n", "\n", "\n", "\n", "\n", "\n", "Φ_tr=1.445961\n", "Θ=10.421964\n", "\n", "\n", "Rx\n", "\n", "\n", "\n", "\n", "\n", "Φ_tr=4.56874\n", "Θ=0.894228\n", "\n", "\n", "Rx\n", "\n", "\n", "\n", "\n", "\n", "\n", "Φ_tr=1.626368\n", "Θ=8.638851\n", "\n", "\n", "Rx\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": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "## From any unitary\n", "n = 4\n", "U = pcvl.Matrix.random_unitary(n)\n", "\n", "decomposed_circuit = pcvl.Circuit.decomposition(U, BS(theta=pcvl.P('theta'), phi_tr=pcvl.P('phi')), phase_shifter_fn=PS)\n", "pcvl.pdisplay(decomposed_circuit)" ] }, { "cell_type": "code", "execution_count": 11, "id": "bff6374dc7cf4db", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The error between the two unitaries is 1.1428982927935346e-08\n" ] } ], "source": [ "print(\"The error between the two unitaries is\", np.linalg.norm(U - decomposed_circuit.compute_unitary()))" ] }, { "cell_type": "code", "execution_count": 12, "id": "daf77b8d5ca300ee", "metadata": {}, "outputs": [], "source": [ "## Exercise: decompose your unitary with only phase shifters and balanced beamsplitters.\n", "\n", "## Solution:\n", "mzi = pcvl.Circuit(2) // BS() // PS(pcvl.P(\"phi1\")) // BS() // PS(pcvl.P(\"phi2\"))\n", "\n", "circuit_u = pcvl.Circuit.decomposition(U, mzi, phase_shifter_fn=PS)\n", "\n", "## Note: you can use a MZI. Be careful to put the phase on the right, as the full layer of phase_shifter_fn is on the left of the circuit" ] }, { "cell_type": "code", "execution_count": 13, "id": "27eaed7eb54279e5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The error between the two unitaries is 9.693396401890419e-09\n" ] } ], "source": [ "## Exercise: check the norm of the difference to be sure it has worked well\n", "\n", "## Solution:\n", "print(\"The error between the two unitaries is\", np.linalg.norm(U - circuit_u.compute_unitary()))" ] }, { "cell_type": "markdown", "id": "6592d5435524e1c8", "metadata": {}, "source": [ "

\n", "Even if it is a good example to show how to decompose an arbitrary unitary matrix to a generic interferometer using Perceval, it is also possible to compute results without doing so. As the decomposition step is quite time-consuming, it's often better to skip this step when you're not sure if you require it.

" ] }, { "cell_type": "markdown", "id": "210491d7cc3bb832", "metadata": {}, "source": [ "### 4. Black Box\n", "\n", "To improve readability, the circuit can be constructed in different steps, combined with multiple hierarchy levels. The higher level circuit then treat their complex components as black boxes. Writing black boxes helps writing generic reusable operations.\n" ] }, { "cell_type": "code", "execution_count": 14, "id": "d054d0c2488bf8d8", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "BELL STATE PREPAR.\n", "\n", "\n", "\n", "UPPER MZI\n", "\n", "\n", "\n", "LOWER MZI\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": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pre_MZI = (pcvl.Circuit(4, name=\"Bell State Prepar.\")\n", " .add(0, BS())\n", " .add(2, BS())\n", " .add(1, PERM([1, 0])))\n", "\n", "upper_MZI = (pcvl.Circuit(2, name=\"upper MZI\")\n", " .add(0, PS(phi=pcvl.P('phi_0')))\n", " .add(0, BS())\n", " .add(0, PS(phi=pcvl.P('phi_2')))\n", " .add(0, BS()))\n", "\n", "lower_MZI = (pcvl.Circuit(2, name=\"lower MZI\")\n", " .add(0, PS(phi=pcvl.P('phi_1')))\n", " .add(0, BS())\n", " .add(0, PS(phi=pcvl.P('phi_3')))\n", " .add(0, BS()))\n", "\n", "chip = (pcvl.Circuit(4)\n", " .add(0, pre_MZI)\n", " .add(0, upper_MZI, merge=False)\n", " .add(2, lower_MZI, merge=False))\n", "\n", "pcvl.pdisplay(chip)" ] }, { "cell_type": "code", "execution_count": 15, "id": "8c9f4d442f6501df", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "BELL STATE PREPAR.\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Rx\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Rx\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "UPPER MZI\n", "\n", "\n", "Φ=phi_0\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Rx\n", "\n", "\n", "Φ=phi_2\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Rx\n", "\n", "LOWER MZI\n", "\n", "\n", "Φ=phi_1\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Rx\n", "\n", "\n", "Φ=phi_3\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Rx\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": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "## You can still display the inside of black boxes with:\n", "pcvl.pdisplay(chip, recursive=True)" ] }, { "cell_type": "markdown", "id": "da8e743391f0fb41", "metadata": {}, "source": [ "## III. Experiments\n", "\n", "More than just defining a LO circuit, it could be interesting to build what is around the unitary components. Setuping the input state, noise, post-selection functions, detectors, etc. is important in real world computations. Great news: that's exactly what an `Experiment` is made for." ] }, { "cell_type": "code", "execution_count": 16, "id": "2c7a2e927be63ad3", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "CPLX\n", "\n", "\n", "\n", "\n", "\n", "\n", "1\n", "\n", "\n", "0\n", "\n", "\n", "1\n", "\n", "\n", "0\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": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Define your experiment\n", "experiment = pcvl.Experiment(4, pcvl.NoiseModel(brightness= 0.8, indistinguishability=0.9))\n", "experiment.add(0, chip) # Those two lines could also be replaced by experiment = pcvl.Experiment(chip, NoiseModel(...))\n", "\n", "# Define your input\n", "experiment.with_input(pcvl.BasicState([1, 0, 1, 0]))\n", "\n", "# Define conditions on the output\n", "experiment.min_detected_photons_filter(2) # Postselection on the number of photons of the output\n", "experiment.set_postselection(pcvl.PostSelect(\"[0, 1] == 1 & [2, 3] == 1\")) # Postselection using logical conditions\n", "\n", "pcvl.pdisplay(experiment) # chip is now a black box for the experiment" ] }, { "cell_type": "code", "execution_count": 17, "id": "def7d64fdaca0dc2", "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", "CPLX\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", "4\n", "5\n", "0\n", "1\n", "2\n", "3\n", "4\n", "5\n", "" ], "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Experiments can be composed more freely than circuits\n", "expe = pcvl.Experiment(6)\n", "expe.add({0: 1, 1: 3, 2: 2, 4: 0}, experiment) # Only the inner components are added\n", "\n", "pcvl.pdisplay(expe)" ] }, { "cell_type": "code", "execution_count": 18, "id": "169746f165657793", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'phi': Parameter(name='phi', value=None, min_v=0.0, max_v=6.283185307179586)}\n", "[[-1.000000e+00+6.123234e-17j -6.123234e-17+0.000000e+00j]\n", " [-6.123234e-17+0.000000e+00j 1.000000e+00-6.123234e-17j]]\n" ] }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Rx\n", "\n", "\n", "Φ=pi\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Rx\n", "\n", "\n", "0\n", "1\n", "0\n", "1\n", "" ], "text/plain": [ "" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Variables are still accessible through experiment\n", "experiment = pcvl.Experiment(2).add(0, pcvl.BS()).add(0, pcvl.PS(pcvl.P(\"phi\"))).add(0, pcvl.BS())\n", "\n", "print(experiment.get_circuit_parameters())\n", "experiment.get_circuit_parameters()[\"phi\"].set_value(np.pi)\n", "\n", "# In case the Experiment describes a unitary circuit, this circuit can be retrieved using\n", "circ = experiment.unitary_circuit()\n", "\n", "print(circ.compute_unitary())\n", "\n", "pcvl.pdisplay(circ)" ] }, { "cell_type": "markdown", "id": "40f730b57e2df667", "metadata": {}, "source": [ "Experiments can also handle a few non-unitary components, which is not possible in the `Circuit` class. A tutorial part for advanced users covers this use case." ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }