{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "# Circuit Building\n", "\n", "This tutorial demonstrates how circuits can be built up from the set of fundamental components included within Lightworks. It aims to act as a basic reference, with a much more detailed description of each component and functionality included in the SDK PhotonicCircuit section. " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "import lightworks as lw" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic circuit\n", "\n", "Start with a basic circuit, consisting only of beam splitters and phase shifters." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "1\n", "2\n", "3\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "PS\n", "φ = 1\n", "\n", "\n", "\n", "PS\n", "φ = π\n", "\n", "\n", "\n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "circuit = lw.PhotonicCircuit(4)\n", "\n", "# Beam splitters\n", "circuit.bs(0)\n", "circuit.bs(2)\n", "\n", "# Phase shifters\n", "circuit.ps(1, 1)\n", "circuit.ps(3, np.pi)\n", "\n", "circuit.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Mode swaps\n", "\n", "It is also possible to use the mode swap component to quickly switch modes." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "1\n", "2\n", "3\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "PS\n", "φ = 1\n", "\n", "\n", "\n", "PS\n", "φ = π\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Map mode 0 -> 2, 2 -> 3 & 3 -> 0\n", "\n", "circuit.mode_swaps({0: 2, 2: 3, 3: 0})\n", "\n", "circuit.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Loss\n", "\n", "When simulating, loss can be introduced to each of the circuit modes, either alongside components or directly. The loss value should be given as a decimal value." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# Add loss through beam splitter\n", "circuit.bs(1, loss=0.1)\n", "\n", "# Add directly\n", "circuit.loss(0, 0.3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The display_loss option is required for these to be shown." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "1\n", "2\n", "3\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "PS\n", "φ = 1\n", "\n", "\n", "\n", "PS\n", "φ = π\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "L\n", "loss = 0.1\n", "\n", "\n", "\n", "L\n", "loss = 0.1\n", "\n", "\n", "\n", "L\n", "loss = 0.3\n", "\n", "\n", "\n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "circuit.display(display_loss=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Parameterization\n", "\n", "Circuits can be parameterized using the included Parameter objects." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "1\n", "2\n", "3\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "PS\n", "φ = 1\n", "\n", "\n", "\n", "PS\n", "φ = π\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.2\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.2\n", "\n", "\n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "ref = lw.Parameter(0.2)\n", "\n", "circuit.bs(0, reflectivity=ref)\n", "circuit.bs(2, reflectivity=ref)\n", "\n", "circuit.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This can be updated with the set method to alter the circuit without having to redefine it." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "1\n", "2\n", "3\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "PS\n", "φ = 1\n", "\n", "\n", "\n", "PS\n", "φ = π\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.7\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.7\n", "\n", "\n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "ref.set(0.7)\n", "\n", "circuit.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Adding circuits\n", "\n", "It is also possible to combine circuits using either + or add. The former requires both circuits be the same size, whereas the latter does not." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "1\n", "2\n", "3\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "PS\n", "φ = 1\n", "\n", "\n", "\n", "PS\n", "φ = π\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.7\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.7\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "PS\n", "φ = 1\n", "\n", "\n", "\n", "PS\n", "φ = π\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.7\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.7\n", "\n", "\n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Add the created circuit to itself\n", "new_circuit = circuit + circuit\n", "\n", "new_circuit.display()" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Sub-circuit:\n" ] }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "1\n", "2\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "PS\n", "φ = 0.6\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Combined circuit:\n" ] }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "1\n", "2\n", "3\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "PS\n", "φ = 1\n", "\n", "\n", "\n", "PS\n", "φ = π\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.7\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.7\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "PS\n", "φ = 0.6\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Define a smaller circuit and add to mode 1 of the original circuit\n", "\n", "circuit2 = lw.PhotonicCircuit(3)\n", "circuit2.bs(1)\n", "circuit2.ps(1, 0.6)\n", "circuit2.bs(1)\n", "circuit2.mode_swaps({0: 1, 1: 2, 2: 0})\n", "\n", "print(\"Sub-circuit:\")\n", "circuit2.display()\n", "\n", "circuit.add(circuit2, 1)\n", "\n", "print(\"Combined circuit:\")\n", "circuit.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Heralds\n", "Heralds can also be included as part of the circuit, which means that these modes do not need to be specifed in the simulation objects." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "1\n", "2\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "PS\n", "φ = 1\n", "\n", "\n", "\n", "PS\n", "φ = π\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.7\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.7\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "PS\n", "φ = 0.6\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "\n", "0\n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "circuit.herald(0, 2, 0)\n", "\n", "circuit.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is also possible to add heralds to sub-circuits and then include these within a larger circuit. \n", "\n", "Note: heralds on the smaller circuit, will be added to new dedicated modes in the larger circuit and cannot be interacted with in any way. This can be seen from the display of the created circuit below." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "1\n", "2\n", "-\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "PS\n", "φ = 1\n", "\n", "\n", "\n", "PS\n", "φ = π\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.7\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.7\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "PS\n", "φ = 0.6\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Circuit\n", "\n", "\n", "\n", "\n", "0\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "0\n", "\n", "0\n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "circuit2.herald(0, 1, 1)\n", "\n", "circuit.add(circuit2, 2)\n", "circuit.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Unitary Matrices\n", "Unitary transformations can also be implemented across a set of modes.\n", "These are defined with the Unitary object and can be added to the existing circuit.\n", "The included random_unitary function allows for a random transformation to be configured." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "1\n", "2\n", "-\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "PS\n", "φ = 1\n", "\n", "\n", "\n", "PS\n", "φ = π\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.7\n", "\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.7\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "PS\n", "φ = 0.6\n", "\n", "\n", "\n", "\n", "\n", "BS\n", "r = 0.5\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Circuit\n", "\n", "\n", "\n", "\n", "0\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "U\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "\n", "0\n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "U = lw.random_unitary(3)\n", "unitary = lw.Unitary(U, label=\"U\")\n", "\n", "circuit.add(unitary, 1)\n", "circuit.display()" ] } ], "metadata": { "kernelspec": { "display_name": "venv", "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.11.6" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }