{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Unitary Matrix Networks in the Frequency domain" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Imports" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# standard library\n", "from collections import OrderedDict\n", "\n", "# photontorch\n", "import torch\n", "import photontorch as pt\n", "\n", "# other\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "from tqdm.notebook import trange" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Settings" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\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", "\n", "\n", "\n", "\n", "\n", "
keyvaluedescription
nameenvname of the environment
t0.000e+00[s] full 1D time array.
t00.000e+00[s] starting time of the simulation.
t1None[s] ending time of the simulation.
num_t1number of timesteps in the simulation.
dtNone[s] timestep of the simulation
samplerateNone[1/s] samplerate of the simulation.
bitrateNone[1/s] bitrate of the signal.
bitlengthNone[s] bitlength of the signal.
wl1.550e-06[m] full 1D wavelength array.
wl01.550e-06[m] start of wavelength range.
wl1None[m] end of wavelength range.
num_wl1number of independent wavelengths in the simulation
dwlNone[m] wavelength step sizebetween wl0 and wl1.
f1.934e+14[1/s] full 1D frequency array.
f01.934e+14[1/s] start of frequency range.
f1None[1/s] end of frequency range.
num_f1number of independent frequencies in the simulation
dfNone[1/s] frequency step between f0 and f1.
c2.998e+08[m/s] speed of light used during simulations.
freqdomainTrueonly do frequency domain calculations.
gradTruetrack gradients during the simulation
\n", "
" ], "text/plain": [ "Environment(name='env', t=array([0.000e+00]), t0=0.000e+00, t1=None, num_t=1, dt=None, samplerate=None, bitrate=None, bitlength=None, wl=array([1.550e-06]), wl0=1.550e-06, wl1=None, num_wl=1, dwl=None, f=array([1.934e+14]), f0=1.934e+14, f1=None, num_f=1, df=None, c=2.998e+08, freqdomain=True, grad=True)" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%matplotlib inline\n", "DEVICE = 'cpu'\n", "np.random.seed(0)\n", "torch.manual_seed(0)\n", "np.set_printoptions(precision=2, suppress=True)\n", "env = pt.Environment(freqdomain=True, num_t=1, grad=True)\n", "pt.set_environment(env);\n", "pt.current_environment()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Unitary Matrices" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A unitary matrix is a matrix $U$ for which\n", "\\begin{align*}\n", "U\\cdot U^\\dagger = U^\\dagger \\cdot U = I\n", "\\end{align*}\n", "\n", "A unitary matrix is easily implemented in photonics. Indeed, according to the paper *\"[Experimental Realization of Any Discrete Unitary Matrix](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.73.58)\"* by Reck et. al., Any unitary matrix can be written as a combination of phase shifters and directional couplers with variable coupling (or MZI's) (Figure (a))\n", "\n", "However, there exists an alternative approach to achieve any unitary operation, first proposed by Clements et. al. : [Optimal design for universal multiport interferometers](https://www.osapublishing.org/optica/abstract.cfm?uri=optica-3-12-1460) (Figure (b))\n", "\n", "![Unitary Matrix Paper](images/clements.jpeg)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2x2 Unitary matrix (Reck)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Functions" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "def array(tensor):\n", " arr = tensor.data.cpu().numpy()\n", " if arr.shape[0] == 2:\n", " arr = arr[0] + 1j * arr[1]\n", " return arr\n", "\n", "def tensor(array):\n", " if array.dtype == np.complex64 or array.dtype == np.complex128:\n", " array = np.stack([np.real(array), np.imag(array)])\n", " return torch.tensor(array, dtype=torch.get_default_dtype(), device=DEVICE)\n", "\n", "def rand_phase():\n", " return float(2*np.pi*np.random.rand())\n", "\n", "class Network(pt.Network):\n", " def _handle_source(self, matrix, **kwargs):\n", " expanded_matrix = matrix[:,None,None,:,:]\n", " a,b,c,d,e = expanded_matrix.shape\n", " expanded_matrix = torch.cat([\n", " expanded_matrix,\n", " torch.zeros((a,b,c,self.num_mc-d,e), device=expanded_matrix.device),\n", " ], -2)\n", " return expanded_matrix\n", " def forward(self, matrix):\n", " ''' matrix shape = (2, num_sources, num_sources)'''\n", " result = super(Network, self).forward(matrix, power=False)\n", " return result[:,0,0,:,:]\n", " def count_params(self):\n", " num_params = 0\n", " for p in self.parameters():\n", " num_params += int(np.prod(p.shape))\n", " return num_params\n", "\n", "def unitary_matrix(m,n):\n", " real_part = np.random.rand(m,n)\n", " imag_part = np.random.rand(m,n)\n", " complex_matrix = real_part + 1j*imag_part\n", " if m >= n:\n", " unitary_matrix, _, _ = np.linalg.svd(complex_matrix, full_matrices = False)\n", " else:\n", " _, _, unitary_matrix = np.linalg.svd(complex_matrix, full_matrices = False)\n", " return unitary_matrix" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Define Network" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "class Network2x2(Network):\n", " def __init__(self):\n", " super(Network2x2, self).__init__()\n", " self.s1 = pt.Source()\n", " self.s2 = pt.Source()\n", " self.d1 = pt.Detector()\n", " self.d2 = pt.Detector()\n", " self.mzi = pt.Mzi(length=0, phi=rand_phase(), theta=rand_phase(), trainable=True)\n", " self.wg1 = pt.Waveguide(length=0, phase=rand_phase(), trainable=True)\n", " self.wg2 = pt.Waveguide(length=0, phase=rand_phase(), trainable=True)\n", " self.link('s1:0', '0:mzi:1', '0:wg1:1', '0:d1')\n", " self.link('s2:0', '3:mzi:2', '0:wg2:1', '0:d2')\n", " \n", "nw2x2 = Network2x2().to(DEVICE).initialize()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Check unitarity" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To see which unitary matrix the network represents, we search for the result of the propagation of an identity matrix through the network. The power flag was set to false, as we are interested in the full complex output of the system. To show that this matrix is indeed unitary, we multiply with its conjugate transpose:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[1.+0.j 0.+0.j]\n", " [0.+0.j 1.-0.j]]\n" ] } ], "source": [ "def check_unitarity(nw):\n", " matrix = tensor(np.eye(nw.num_sources) + 0j)\n", " result = array(nw(matrix))\n", " print(result@result.T.conj())\n", "\n", "check_unitarity(nw2x2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Check Universality" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "However, it would be more interesting if we can show that this network can act like *any* unitary matrix. We will now train the network to be equal to another unitary matrix by using the unitary property $U\\cdot U^\\dagger=I$: we will train the network to obtain $I$ with $U_0^\\dagger$ as input." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def check_universality(nw, num_epochs=500, lr=0.1):\n", " matrix_to_approximate = unitary_matrix(nw.num_sources, nw.num_sources)\n", " matrix_input = tensor(matrix_to_approximate.T.conj().copy())\n", " eye = tensor(np.eye(nw.num_sources) + 0j)\n", " optimizer = torch.optim.Adam(nw.parameters(), lr=lr)\n", " lossfunc = torch.nn.MSELoss()\n", " epochs = trange(num_epochs)\n", " for i in epochs:\n", " optimizer.zero_grad()\n", " result = nw(matrix_input)\n", " loss = lossfunc(result, eye)\n", " loss.backward()\n", " optimizer.step()\n", " epochs.set_postfix(loss=f'{loss.item():.7f}')\n", " if loss.item() < 1e-6:\n", " break\n", "\n", " matrix_approximated = array(nw(eye))\n", " print(matrix_approximated)\n", " print(matrix_to_approximate)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "f838e0d32ccf4b2fba1d4b5b70d0b8d7", "version_major": 2, "version_minor": 0 }, "text/plain": [ "HBox(children=(FloatProgress(value=0.0, max=500.0), HTML(value='')))" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "[[-0.29-0.62j 0.18+0.71j]\n", " [-0.34-0.65j -0.2 -0.65j]]\n", "[[-0.29-0.62j 0.18+0.71j]\n", " [-0.34-0.65j -0.2 -0.65j]]\n" ] } ], "source": [ "check_universality(nw2x2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3x3 Unitary Matrix (Reck)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "class Reck3x3(Network):\n", " def __init__(self):\n", " super(Reck3x3, self).__init__()\n", " self.s1 = pt.Source()\n", " self.s2 = pt.Source()\n", " self.s3 = pt.Source()\n", " self.d1 = pt.Detector()\n", " self.d2 = pt.Detector()\n", " self.d3 = pt.Detector()\n", " self.mzi1 = pt.Mzi(length=0, phi=rand_phase(), theta=rand_phase(), trainable=True)\n", " self.mzi2 = pt.Mzi(length=0, phi=rand_phase(), theta=rand_phase(), trainable=True)\n", " self.mzi3 = pt.Mzi(length=0, phi=rand_phase(), theta=rand_phase(), trainable=True)\n", " self.wg1 = pt.Waveguide(length=0, phase=rand_phase(), trainable=True)\n", " self.wg2 = pt.Waveguide(length=0, phase=rand_phase(), trainable=True)\n", " self.wg3 = pt.Waveguide(length=0, phase=rand_phase(), trainable=True)\n", " self.link(\"s1:0\", \"0:mzi1:1\", \"0:d1\")\n", " self.link(\"s2:0\", \"0:mzi2:1\", \"3:mzi1:2\", \"0:mzi3:1\", \"0:d2\")\n", " self.link(\"s3:0\", \"0:wg1:1\", \"3:mzi2:2\", \"0:wg2:1\", \"3:mzi3:2\", \"0:wg3:1\", \"0:d3\")\n", "reck3x3 = Reck3x3().to(DEVICE).initialize()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Check Unitarity" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 1.-0.j -0.+0.j 0.+0.j]\n", " [-0.+0.j 1.+0.j -0.+0.j]\n", " [ 0.+0.j -0.-0.j 1.-0.j]]\n" ] } ], "source": [ "check_unitarity(reck3x3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Check Universality" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "b2a0c4e85ade4498aca3a6de04037197", "version_major": 2, "version_minor": 0 }, "text/plain": [ "HBox(children=(FloatProgress(value=0.0, max=500.0), HTML(value='')))" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "[[-0.56-0.24j 0.13-0.51j 0.41-0.43j]\n", " [-0.25-0.25j -0.59+0.6j 0.4 -0.07j]\n", " [-0.56-0.44j 0.03+0.06j -0.62+0.32j]]\n", "[[-0.56-0.24j 0.13-0.51j 0.41-0.43j]\n", " [-0.25-0.25j -0.59+0.6j 0.4 -0.07j]\n", " [-0.56-0.44j 0.03+0.06j -0.62+0.32j]]\n" ] } ], "source": [ "check_universality(reck3x3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3x3 Unitary Matrix (Clements)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "class Clements3x3(Network):\n", " def __init__(self):\n", " super(Clements3x3, self).__init__()\n", " self.s1 = pt.Source()\n", " self.s2 = pt.Source()\n", " self.s3 = pt.Source()\n", " self.d1 = pt.Detector()\n", " self.d2 = pt.Detector()\n", " self.d3 = pt.Detector()\n", " self.mzi1 = pt.Mzi(length=0, phi=rand_phase(), theta=rand_phase(), trainable=True)\n", " self.mzi2 = pt.Mzi(length=0, phi=rand_phase(), theta=rand_phase(), trainable=True)\n", " self.mzi3 = pt.Mzi(length=0, phi=rand_phase(), theta=rand_phase(), trainable=True)\n", " self.wg1 = pt.Waveguide(length=0, phase=rand_phase(), trainable=True)\n", " self.wg2 = pt.Waveguide(length=0, phase=rand_phase(), trainable=True)\n", " self.wg3 = pt.Waveguide(length=0, phase=rand_phase(), trainable=True)\n", " self.link(\"s1:0\", \"0:mzi1:1\", \"0:mzi3:1\", \"0:wg1:1\", \"0:d1\")\n", " self.link(\"s2:0\", \"3:mzi1:2\", \"0:mzi2:1\", \"3:mzi3:2\", \"0:wg2:1\", \"0:d2\")\n", " self.link(\"s3:0\", \"3:mzi2:2\", \"0:wg3:1\", \"0:d3\")\n", "clem3x3 = Clements3x3().to(DEVICE).initialize()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Check Unitarity" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 1.-0.j -0.+0.j -0.-0.j]\n", " [-0.+0.j 1.-0.j 0.+0.j]\n", " [-0.+0.j 0.-0.j 1.+0.j]]\n" ] } ], "source": [ "check_unitarity(clem3x3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Check Universality" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "d8390b313bc64ccc811a62b24eb6a1cf", "version_major": 2, "version_minor": 0 }, "text/plain": [ "HBox(children=(FloatProgress(value=0.0, max=1000.0), HTML(value='')))" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "[[-0.45-0.27j 0.05+0.52j 0.52+0.42j]\n", " [-0.64-0.35j 0.19-0.6j -0.24+0.1j ]\n", " [-0.4 -0.16j -0.37+0.43j -0.33-0.62j]]\n", "[[-0.45-0.27j 0.05+0.52j 0.52+0.42j]\n", " [-0.64-0.35j 0.19-0.6j -0.24+0.1j ]\n", " [-0.4 -0.16j -0.37+0.43j -0.33-0.62j]]\n" ] } ], "source": [ "check_universality(clem3x3, num_epochs=1000)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## NxN Unitary Matrix (Reck)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Creating those networks is quite cumbersome. However they are also implemented by photontorch, which then handles the creation of the networks:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "reck2x2 = pt.ReckNxN(N=2).to(DEVICE).terminate().initialize()\n", "reck5x5 = pt.ReckNxN(N=5).to(DEVICE).terminate().initialize()\n", "# quick monkeypatch to have the same behavior as the classes defined above\n", "reck5x5.__class__ = Network" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Check Unitarity" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 1.+0.j -0.+0.j 0.+0.j -0.-0.j 0.+0.j]\n", " [-0.-0.j 1.+0.j 0.-0.j 0.+0.j 0.+0.j]\n", " [ 0.-0.j 0.+0.j 1.-0.j 0.+0.j -0.-0.j]\n", " [-0.+0.j 0.-0.j 0.-0.j 1.+0.j 0.+0.j]\n", " [ 0.-0.j 0.-0.j -0.+0.j 0.-0.j 1.+0.j]]\n" ] } ], "source": [ "check_unitarity(reck5x5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Check Universality" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "fff538b41740444eb0b75ae5607a33c8", "version_major": 2, "version_minor": 0 }, "text/plain": [ "HBox(children=(FloatProgress(value=0.0, max=500.0), HTML(value='')))" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "[[-0.1 -0.4j -0.15+0.52j -0.03+0.63j -0.01-0.06j 0.16+0.33j]\n", " [-0.28-0.28j -0.12+0.42j -0.09-0.57j 0.56-0.01j 0.02-0.05j]\n", " [-0.25-0.29j 0.24-0.54j -0.23-0.07j 0.11+0.21j 0.35+0.51j]\n", " [-0.24-0.4j -0.02-0.4j 0.27+0.23j 0.26-0.37j -0.52-0.16j]\n", " [-0.28-0.47j -0.07+0.01j -0.24-0.16j -0.64+0.1j 0.04-0.43j]]\n", "[[-0.1 -0.4j -0.15+0.52j -0.03+0.63j -0. -0.06j 0.16+0.33j]\n", " [-0.28-0.28j -0.12+0.42j -0.09-0.57j 0.56-0.01j 0.02-0.05j]\n", " [-0.25-0.29j 0.24-0.54j -0.23-0.07j 0.11+0.21j 0.35+0.51j]\n", " [-0.24-0.4j -0.02-0.4j 0.27+0.23j 0.26-0.37j -0.52-0.16j]\n", " [-0.29-0.47j -0.07+0.01j -0.24-0.16j -0.64+0.1j 0.04-0.43j]]\n" ] } ], "source": [ "check_universality(reck5x5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## NxN Unitary Matrix (Clements)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "clem5x5 = pt.ClementsNxN(N=5).to(DEVICE).terminate().initialize()\n", "clem6x6 = pt.ClementsNxN(N=6).to(DEVICE).terminate().initialize()\n", "# quick monkeypatch to have the same behavior as the classes defined above\n", "clem5x5.__class__ = clem6x6.__class__ = Network" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Check Unitarity" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 1.+0.j 0.+0.j -0.-0.j -0.+0.j -0.-0.j]\n", " [ 0.-0.j 1.-0.j 0.-0.j 0.+0.j -0.-0.j]\n", " [-0.+0.j 0.+0.j 1.+0.j -0.+0.j 0.+0.j]\n", " [-0.-0.j 0.-0.j -0.+0.j 1.+0.j 0.+0.j]\n", " [-0.+0.j -0.+0.j 0.-0.j 0.-0.j 1.+0.j]]\n", "[[ 1.+0.j 0.-0.j -0.+0.j 0.-0.j -0.+0.j -0.+0.j]\n", " [ 0.+0.j 1.-0.j 0.+0.j 0.+0.j -0.+0.j -0.+0.j]\n", " [-0.-0.j 0.-0.j 1.-0.j 0.-0.j -0.+0.j -0.-0.j]\n", " [ 0.+0.j 0.-0.j 0.+0.j 1.+0.j 0.-0.j 0.+0.j]\n", " [-0.-0.j -0.-0.j -0.-0.j 0.+0.j 1.+0.j -0.-0.j]\n", " [-0.-0.j -0.+0.j -0.+0.j 0.-0.j -0.+0.j 1.-0.j]]\n" ] } ], "source": [ "check_unitarity(clem5x5)\n", "check_unitarity(clem6x6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Check Universality" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "a97916fd8a924aa18eb1f2716a1d9223", "version_major": 2, "version_minor": 0 }, "text/plain": [ "HBox(children=(FloatProgress(value=0.0, max=1000.0), HTML(value='')))" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "[[-0.21-0.33j 0.37+0.33j -0.41+0.21j 0.46+0.36j -0.03+0.23j]\n", " [-0.4 -0.33j -0.13+0.27j 0.21-0.15j 0.21-0.14j -0.1 -0.71j]\n", " [-0.34-0.33j -0.2 +0.15j 0.16+0.57j -0.54-0.06j -0.13+0.24j]\n", " [-0.28-0.41j -0.21-0.49j 0.16-0.44j 0.2 +0.04j -0.17+0.42j]\n", " [-0.15-0.29j 0.56-0.06j -0.18-0.36j -0.48-0.17j 0.39-0.06j]]\n", "[[-0.21-0.32j 0.36+0.33j -0.41+0.22j 0.46+0.36j -0.03+0.23j]\n", " [-0.4 -0.33j -0.13+0.27j 0.21-0.15j 0.21-0.14j -0.1 -0.71j]\n", " [-0.34-0.33j -0.2 +0.15j 0.16+0.57j -0.54-0.06j -0.13+0.24j]\n", " [-0.28-0.42j -0.21-0.49j 0.16-0.43j 0.2 +0.04j -0.17+0.42j]\n", " [-0.15-0.29j 0.56-0.06j -0.19-0.35j -0.48-0.17j 0.39-0.06j]]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "366570d395a845c5b12feba21df54dc4", "version_major": 2, "version_minor": 0 }, "text/plain": [ "HBox(children=(FloatProgress(value=0.0, max=1000.0), HTML(value='')))" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "[[-0.19-0.48j -0.3 +0.26j 0.2 -0.31j -0.03+0.12j -0.12+0.6j 0.23-0.02j]\n", " [-0.31-0.25j -0.36-0.11j -0.23+0.33j 0.14+0.13j 0.05-0.41j 0.56-0.13j]\n", " [-0.37-0.3j -0.18+0.13j -0.15+0.43j -0.13-0.03j -0.01+0.02j -0.62+0.33j]\n", " [-0.11-0.34j 0.09+0.24j 0.3 -0.41j -0.26-0.35j 0.08-0.59j -0.03+0.04j]\n", " [-0.2 -0.27j 0.5 -0.21j -0.04+0.11j 0.45-0.52j -0.23+0.16j 0.13+0.09j]\n", " [-0.15-0.28j 0.41-0.35j 0.44+0.16j -0.1 +0.5j 0.14-0.02j -0.12-0.29j]]\n", "[[-0.19-0.48j -0.3 +0.26j 0.2 -0.31j -0.03+0.12j -0.12+0.6j 0.23-0.03j]\n", " [-0.31-0.25j -0.36-0.11j -0.23+0.33j 0.14+0.13j 0.06-0.41j 0.56-0.13j]\n", " [-0.37-0.3j -0.18+0.13j -0.15+0.43j -0.13-0.03j -0.01+0.02j -0.62+0.33j]\n", " [-0.11-0.34j 0.09+0.24j 0.3 -0.41j -0.26-0.35j 0.08-0.59j -0.03+0.04j]\n", " [-0.21-0.27j 0.5 -0.21j -0.04+0.11j 0.45-0.52j -0.23+0.16j 0.13+0.09j]\n", " [-0.15-0.28j 0.41-0.35j 0.44+0.16j -0.1 +0.5j 0.14-0.02j -0.12-0.29j]]\n" ] } ], "source": [ "check_universality(clem5x5, num_epochs=1000)\n", "check_universality(clem6x6, num_epochs=1000)" ] } ], "metadata": { "kernelspec": { "display_name": "ptdev", "language": "python", "name": "ptdev" }, "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.7.7" } }, "nbformat": 4, "nbformat_minor": 4 }