{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Quantum Processes and Computation (with PyZX!)\n", "\n", "_Aleks Kissinger | 2020_\n", "\n", "\n", "Welcome to the first in a series of labs (or \"practicals\" in UK parlance) which will build up from basics to using the ZX calculus to do some interesting and potentially useful stuff on a real quantum computer.\n", "\n", "These practicals are designed to go with the [Quantum Processes and Computation](https://www.cs.ox.ac.uk/teaching/courses/2020-2021/quantum/) course taught in Oxford, but if you came across these another way, or just happened up them, you are more than welcome to give them a go! The primary goals of these practicals are:\n", "1. construct quantum circuits and ZX-diagrams programmatically\n", "2. evaluate/simulate them numerically\n", "3. do basic diagrammatic reasoning with software\n", "4. apply 1-3 to a practical (but very small!) example of a quantum computation\n", "\n", "Along the way, we'll achieve some secondary goals:\n", "5. learn a bit about [NISQ](https://arxiv.org/abs/1801.00862) quantum hardware available today, and how to make use of it via cloud quantum computing\n", "6. learn about the [one-way model of measurement-based quantum computation](https://en.wikipedia.org/wiki/One-way_quantum_computer), and do some experiments with ZX/pyzx\n", "\n", "If you are following the QPC course at Oxford, you probably have (or will shortly have) a good idea of what _ZX-diagrams_ and the _ZX-calculus_ are. If not, these are covered in detail in Chapter 9 of the course textbook [Picturing Quantum Processes](https://cambridge.org/pqp). A short tutorial and pretty comprehensive list of references can also be found at [zxcalculus.com](http://www.zxcalculus.com). Everything you need to know about the PyZX library should be introduced as we go, but if you need more, the full code documentation is at [pyzx.readthedocs.io](https://pyzx.readthedocs.io/en/latest/).\n", "\n", "We will only be scratching the surface on quantum hardware and software in these practicals. To learn more about the big picture, a great place to get started is [fullstackquantumcomputation.tech](https://fullstackquantumcomputation.tech/).\n", "\n", "_These practicals, like PyZX itself are released under the [Apache 2](https://github.com/Quantomatic/pyzx/blob/master/LICENSE) open-source license. Feel free to use, copy, and modify them at will, e.g. to use your own course._" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Part 1\n", "\n", "Alright, lets get stuck in! This is a [Jupyter](https://jupyter.org/) notebook, which is a place for running bits of python code and seeing (and saving) pretty output. Some of the code is written for you, and some of it you will write yourself. As you go through, you will find code cells marked `In [ ]:`. Click inside of these cells and press `SHIFT+ENTER` to run the code. Some code defines variables used by other code, so make sure you do this in the right order. To answer the questions, you will need to insert new cells yourself, using the `Insert` menu.\n", "\n", "The first thing we'll do is install the PyZX library if we don't have it already. Jupyter notebooks have a \"magic\" command for installing libraries called `%pip`. So, run this first to install PyZX. You should only need to do it once. (You can delete the command later if you like.)\n", "\n", "If it claims you need to \"restart the kernel\" click the refresh-looking button in the Jupyter toolbar, or go to `Kernel > Restart`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%pip install pyzx" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, we'll import some stuff from the Python standard library. In particular, we'll use the `Fraction` type for expressing phases later." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import sys, os, math\n", "from fractions import Fraction" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And now we import `pyzx` itself. To save us some extra typing, we'll abbreviate the name to `zx`, import all the basic rules, and make some other useful abbreviations." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sys.path.insert(0,os.path.expanduser('~/git/pyzx')) # git version\n", "import pyzx as zx\n", "from pyzx import print_matrix\n", "from pyzx.basicrules import *\n", "\n", "Z = zx.VertexType.Z\n", "X = zx.VertexType.X\n", "B = zx.VertexType.BOUNDARY\n", "SE = zx.EdgeType.SIMPLE\n", "HE = zx.EdgeType.HADAMARD" ] }, { "attachments": { "spiders.png": { "image/png": "iVBORw0KGgoAAAANSUhEUgAABZkAAACFCAIAAAC2fWFPAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAgAElEQVR4nO3deVxM7f8/8DNt2mSXLImSstwtiPZFSaiEIpTKTcl2k7jvW4jbei8+wk1CixJKKqWQSgtSIgpFiISE9r1pfn/M59vPJ60zZ+bM1Ov58Mc8Zs5c5zXHXOdcveecc9EYDAYBAAAAAAAAAMAnBKgOAAAAAAAAAADQDahlAAAAAAAAAAA/QS0DAAAAAAAAAPgJahkAAAAAAAAAwE9QywAAAAAAAAAAfoJaBgAAAAAAAADwE9QyAAAAAAAAAICfoJYBAAAAAAAAAPwEtQwAAAAAAAAA4CeoZQAAAAAAAAAAP0EtAwAAAAAAAAD4CWoZAAAAAAAAAMBPUMsAAAAAAAAAAH6CWgYAAAAAAAAA8BPUMgAAAAAAAACAn6CWAQAAAAAAAAD8RKi7bzh48CCNRpORkRk7duykSZP69+/PiVi9UHl5+dOnT1+9evXx48e6urqdO3dSnQgAAIBd7969CwwMFBMTGzVqlLy8/MSJE/v06UN1qB7i/fv3ubm5r1+/Li0tlZGRsbe3pzoRAAAA99AYDEa33qCqqvr169fPnz83NDTQaDQlJSUDA4P58+cbGhoKCwtzKGVP1dTUdPv27atXr8bHx+fm5jY3NwsLCw8dOlRUVDQ/P5/qdAAAAOzKyspauHBhdXX158+fGQyGiIiIurq6qamppaWlmpoa1en4T3l5eUxMzNWrV1NSUoqKigiCEBcXHzp0qIGBgZ+fH9XpAAAAuKfbtQwmOp1eWFj46NGju3fv3rhxIzs7e/jw4c7OzqtXrx42bBjpKXuez58/nzlz5uTJk+/fv58wYcLs2bO1tLTU1NRkZWWFhLp9sgwAAACPq6ury8/Pf/DgQWpq6rVr1z59+qSurr5u3TpbW1tRUVGq0/GBnJyc48ePBwUF1dXV6ejoGBsbz5gxY9KkSRh3AQBA78RiLaOV/Px8Hx+fs2fPVlVVWVtbe3h4KCkpsd9sj/Ty5cu9e/deunRJVFTU0dHR2dkZ2woAAHqV5ubmO3fu/Pvvv1euXOnXr9/q1avd3d1x1Wp7bty4cejQocTERHl5+bVr19rb2w8aNIjqUAAAABQjp5bBVFtbe/78+SNHjrx48cLFxcXT03PgwIFkNd4DlJWV/fHHH8ePH5eTk9u0adPy5cslJSWpDgUAAECZDx8+eHt7nzhxgkaj7d69e/Xq1Tg58Xu5ublubm4xMTEmJiYbN240MzMTEMBd2wEAAAiC3FoGE51OP3369M6dO+l0uqenp6urq6CgILmr4DsMBsPHx2fHjh10On3Xrl1r1qzBvUUAAACYSktLd+/efeLECUVFRS8vr5kzZ1KdiHoVFRU7d+5kbpPDhw/PmjWL6kQAAAC8hfzqvqCgoIuLy4sXLxwcHNzc3IyMjAoKCkhfCx95//69iYnJunXrFi9e/OLFiw0bNqCQAQAA0GLAgAFHjhx58uSJrKysiYnJ+vXra2trqQ5FpeTkZBUVlaCgoP/85z9ZWVkoZAAAAPyIU2cq9u/f/59//snMzCwrK1NRUfHx8eHQinhcaGioiorK69evExISjh07hgtcAQAA2qSkpBQTE3Pp0qXz58+rq6tnZmZSnYgCjY2Nnp6eRkZGioqKjx8/Xrt2LS66AQAAaBNnr7qcPHlyWlqavb29i4uLra1tdXU1R1fHU2pra+3t7W1sbBYtWvTkyRNdXV2qEwEAAPA6a2vrhw8fDhkyRFNT8/Dhw1TH4ao3b95oaGj89ddfx44du379+ogRI6hOBAAAwLvIv19Gm2JjY5cvXz5q1KiIiAg5OTkurJFa79+/t7Kyys/PDwgIsLCwoDoOAAAAP6HT6QcOHNi1a9eyZct8fHx6w6StiYmJ1tbWw4cPv3z5sqKiItVxAAAAeB2X7oZtZmaWkZFBp9OnTp0aHx/PnZVS5d69e9OmTSsvL7979y4KGQAAAN0lKCjo4eFx7dq1qKgoLS2td+/eUZ2Is3x8fExNTTU1NVNTU1HIAAAA6Aruzew1duzYu3fv6unpmZmZnTlzhmvr5bKgoCBDQ0N1dfWMjAxlZWWq4wAAAPCr2bNn37t3r6amZsaMGQ8fPqQ6DkfQ6XQXFxcXF5ft27dfvXpVSkqK6kQAAAD8gauzlPft2zcsLMzd3X316tX79u3j5qq54/Dhw/b29q6urlFRUf369aM6DgAAAH9TUlJKS0tTVlY2NDRMSEigOg7J6urqrK2tAwICQkNDd+3aRaPRqE4EAADANwQ9PT25uT4ajTZz5szBgwdv3bq1pKRk9uzZPePIzWAwdu/evX379p07dx44cKBnfCgAAADKiYqK2tra5uTkeHh4KCoqTpo0iepE5CgrK5s7d+6dO3ciIiLmzZtHdRwAAAA+Q81EX2vXrh00aNCKFSu+fv167tw5YWFhSmKQhU6n//zzz0FBQb6+vg4ODlTHAQAA6FFERESCg4PXrVu3dOnS0tJSFxcXqhOx69OnT6ampiUlJampqSoqKlTHAQAA4D+UTVq+ZMmSgQMHWllZLVmy5OLFi/xbzqDT6XZ2duHh4eHh4fhdBQAAgBMEBAROnDgxdOhQV1fXhoaGDRs2UJ2IdZ8+fTIyMmpoaLhz586YMWOojgMAAMCXuH2Nyffk5eX19fX/+OOPe/fuLVq0SEiIssIKy+h0uoODQ1hY2OXLl1HIAAAA4CgDAwNxcXE3N7c+ffro6upSHYcVxcXFM2fOrK2tTUhIQCEDAACAZRSXD3R0dGJjY83MzKysrK5cucJfE8jT6fQVK1ZcuXIlKirKxMSE6jgAAAA9n7u7O41Gc3d3ZzAYv//+O9VxuufTp08zZ85sbGxMTU0dMWIE1XEAAAD4GPWnQmhra8fExMyZM8fW1jY0NJRfzs5obm62s7OLjIy8evWqsbEx1XEAAAB6iy1bthAE4e7uLiEhsXHjRqrjdNXnz58NDAwYDMbt27eHDx9OdRwAAAD+RuU1Ji1kZWW1tbV3796dn58/f/583p8EhMFguLq6BgcHR0ZG4owMAAAALtPS0hIREdm2bZucnJyqqirVcTpXXl5ubGxcU1OTlJSEMzIAAADYxysnQejp6UVGRpqbm0tKSv77779Ux+nEb7/9dubMmeDg4FmzZlGdBQAAoDf6/fffy8vLV65cKS4ubm1tTXWcjtTW1lpYWHz48CE5ORmFDAAAAFLwSi2DIAgTE5Pg4GAbG5vBgwfv3r2b6jjtOnDgwJ9//unj42NjY0N1FgAAgN7r4MGDZWVly5cv79u37+zZs6mO07bGxsZFixY9efIkMTFx/PjxVMcBAADoIXjiGpMWysrKsrKybm5uEhISWlpaVMdpg7e39+bNm//6669169ZRnQUAAKBXo9Foc+fOff78+R9//KGvry8rK0t1otbodPry5ctv3rwZGxuroaFBdRwAAICeg8ZgMKjO0NrBgwd///13Hx+fn3/+meos/yMsLGzx4sUeHh48VQACAADozRobG+fPn3/nzp3ExEQ1NTWq4/x/DAbD2dk5ICDg6tWrpqamVMcBAADoUbpdy9i3b5+wsHD//v379+8/duxYRUVFKSkp0mP9+uuvf//9N/OSE9IbZ83NmzfNzc1XrVp1/Phx0huvrKx8+fLl69evv337Vl5eXlVVxctX2QAAAHTRu3fvAgICJCUlJSUlpaWlx40bJy8vLyIiQu5aamtrZ8+enZubm5yczDvXcWzduvXw4cMXL15ctGgR6Y1//vw5Ly/v7du3lZWVFRUV0tLSDg4OpK8FAACAZ3W7ljFlypTi4uKqqqry8nLmM9LS0mpqalpaWtra2hoaGpKSkuzHYjAYLi4uAQEB0dHRvDDjaXJy8uzZs62trf39/UmZZqW6ujojI+POnTt379599OjRx48fmc9LSUlJSkr27ds3NzeX/bUAAABQKzs728rKqrKysqqqqqamhiAIQUHB0aNHa2hoaGlpaWlpqaiokDIde1lZmaGhYXl5eWpqKi/MeLpv374dO3b4+/vb29uT0mBxcfG9e/eYI4enT58yh2ECAgL9+vWTkpIyMTE5ffo0KSsCAADgC6xfY9LQ0PDq1au8vLyXL19mZGTcvXu3qKhIWFhYT09v3rx55ubm8vLy7CSj0+lLly6NjY29ffu2uro6O02xKTs7W09PT19f//Lly2yOt968eRMdHR0VFZWUlNTQ0CAjI6OpqamhoaGoqKioqKigoNCnTx+yYgMAAPCUioqKFy9evHz58vnz52lpaWlpaZWVlf379zc1NTU3NzczMxs4cCA77X/+/FlHR0dMTCw5Oblfv35kxWbB2bNnV61adeTIkQ0bNrDTTnNzc2ZmZlRUVHR09KNHj2g0mpKSkqamprq6+rhx48aNGzd69GgBAQGyYgMAAPARMu+X8fbt29u3b0dHR9+8ebOiomLy5MnLly+3tbUdNWoUaw02NDTMmzcvKysrNTVVUVGRrJzd8v79ey0treHDhyckJIiLi7PWSFFR0cWLF8+fP//o0SNJSclZs2bNnTvX0NBwzJgx5KYFAADgF3Q6PScnJy4u7tq1a6mpqQwGw9jYeOnSpVZWVn379mWtzTdv3mhpaY0fP/769euioqLkBu6i6OhoKyurrVu37tu3j+VGHj16dP78+YsXLxYVFY0YMWLu3Llz587V0dFhs9wDAADQY3Dk3p8NDQ1JSUmXLl0KCwurqKjQ1dX9+eefFy1axMKooqKiwsDAoLy8/M6dO8OGDSM9ase+fv2qq6tLo9FSUlJYGD3U19dfuXLl7NmziYmJkpKSCxYsWLx4saGhIU6+AOBrX79+/fvvvxcsWDBt2jSqswD0EKWlpTExMRcuXLh586awsPD8+fNXrVqlr6/PwnWdLWdThoWFCQoKciJtB9LT042MjObPnx8YGMhC+JKSEn9/f39//2fPno0ePXrp0qULFy5UV1cn5fpWAOglMFCBXoKz85jU19dfu3bt3Llz165d69evn4ODg7Oz87hx47rVSElJiba2dtdPGaXT6VlZWQ8ePMjNzS0qKqqqqiIIQlJSUkZGRklJacqUKVOmTOnK4Ka2ttbExKSgoODOnTujR4/uVubXr1+fOnXKz8/v27dvZmZm9vb28+bNExMT61YjAMCb9uzZs2vXLg8Pjz/++IPqLAA9TUlJyaVLl/z9/TMzM5WUlJydnVesWDFgwIBuNXL79u3Zs2c7OjqePHmyK8vX1NTcu3cvKysrLy+vrKys7Ns3UTExCUnJMWPGKCsra2pqKigodKWdly9famtrT5s2LTIysrsXpaakpHh7e4eFhfXp08fW1nb58uXa2tooYQAACzBQgV6CS3Oyfvz48dy5cydPniwsLJwzZ86vv/6qra3d9be/evVKW1t7woQJsbGxHZzUkJSU5O/vHxEZUVZaJiEpMUZxjIysjJi4GI1Gq62p/VT46XXe66rKKql+UpYWlitWrDAyMmpvlECn062trRMSEpKTk3/66aeuR83Kyjp8+PCFCxcGDx68YsUKFxcXOTm5rr8dAHjfq1evYmNjV6xYwfJp8ADQqczMTB8fn+DgYIIgnJyc3NzcZGVlu/72S5cuLV26dM+ePdu3b29vmfr6+suXLwcGBCTevt3Q2DhESmr84MEyEhLiIiJ1jY3VjY2vyspelZQ0NDWNHjly8dKljo6OSkpK7bX24cMHLS2toUOHJiQkdP0+6M3NzdeuXdu/f39aWpqysrKzs/PKlStJuY06APRaGKhAL8GlWgZTU1NTWFjYX3/9lZmZqaOjs3Xr1nnz5nXxN4cHDx4YGhrOmzfv/PnzP97mKjo62nO3Z+aDTGUVZctlltom2ko/Kf24GIPByMvOS41Ljb4QnZ2ZraKqsmvnLisrqx8XW7VqVXBw8I0bN3R1dbsSj8Fg3Lhx488//0xMTFRRUXF3d7exsREWFu7KewEAAKBN5eXl3t7eXl5eX758WbJkyZYtW7r+A8OJEyfWrVt3+vTplStXtnqpoaHh+PHj//z1V/Hnz6bjx1tPmmQkLy/bv/+PjdQ3NaW9exeTlxf85ElRWZmlhcXuPXt+zFBRUaGnp1ddXX3nzp2hQ4d2JV5tbW1AQMA///zz+vVrc3Nzd3f3bv3MAwAA0Mtx9d7XQkJCixcvfvDgQUpKSv/+/S0tLRUVFb28vOrq6jp979SpU0NDQ8PCwtzd3b9/vrCwkDltyoDhA8LSwqKzole5r5qgOqHN23rTaDSln5R+dvs54kFE5IPIYWOGLVy4cJbprIKCgu8X27lzp7+/f3BwcFcKGc3NzVFRUdOnTzczM2toaLh69eqjR4+WLVuGQgYLCgoKuFlc44InT56w84keP35MYhjK9bz/X87pedsKfeF7Pe//l3P69eu3bdu2goKCM2fOZGZmqqio6OjoREVFdeW9rq6uW7dudXFxiY6O/v755OTknyZN8vjtNxsFhYJt266tWOEwZUqbhQyCIPoICemPHXvIzOzt1q2hy5YVZGZOUVfftGlTbW1tyzJ1dXXm5uafP3+Oi4vrSiGjoqLCy8tLQUFh48aNmpqa2dnZERERKGSwBr2JCftYUuDr1C3YXEzofexj+btEzTxezIHIo0ePpk+fvmXLFgUFhaNHj3Za0Zg9e/aZM2f+85//HDhwgPnMtWvXVNVUn714Fngr8FTkKdXpql3PMGnKpBNXTgTfDi54X6CqphoREcF83svLa+/evf/+++/8+fM7bqGhocHb23vs2LFWVlZjxozJyMhITU01NzfH1a0sU1VVjYyMpDoFaWpqatTU1Lo45v5RWlqaqqpqYWEhuako1AP+f1+8eBEUFJSTk9PxYkVFRREREefPn3/48CFru+YesK2+h77QSg/7/+UCERERe3t75t/8BEFYWFhMnz49Jiam0zceOHBg2bJlNjY2ycnJBEE0Nzfv3r3byNBQXkjo6S+//GfevJFdnrpVgEZbOGlS5tq1xy0s/H18NKZOzc3NJQiiqalp8eLFjx8/jo2N7fSq0pKSEnd39xEjRuzatWv58uVv3rw5d+7chAkTupgBfoTeRGAfS54e8HXi2kCF6BGbi33ofaRg+btE5ZzkKioqQUFB+fn5zKnLxo0bd+LEiYaGhg7eYm9vf/To0d9///0///nPqVOnLC0tdWfrXn14VWumFmsZNPQ0wjPCTaxMFi5cePTo0XPnzm3evHn//v3Ozs4dvKuxsfHMmTOKioobN240NTXNy8u7dOnS1KlTWcsALaqrq6urq6lOQRpxcXE9Pb2zZ8+y9vYzZ84oKyuzPKUxD+L3/9/AwMB9+/YJCAgw911tLvP58+dFixYtWbLk3bt3IiIiu3btmjFjxrNnz1oWyMvL68q6+H1btYK+0EoP+//lGgEBAUtLy9TU1NTU1EGDBs2dO1dTU/PmzZsdvIVGo509e3bu3Lnm5uZpaWl2y5fv27v3n7lzo+3tx7A0uakAjeY8ffrDdetEq6q0NTXv3LmzevXquLi4yMhIFRWVDt749evXX3/9dezYsQEBAR4eHu/evTt06NDw4cNZyADfQ28isI8lD79/nbg5UCH4f3ORAr2PFCx/l6isZTCNHj362LFj+fn5CxYscHNzU1BQ8PLyqq+vb2/5devWeXp6urm5ubi4uPzqcjjosLikODsBxMTFDvke2vTHpl9++cXR0XHDhg2//fZbews3NzeHhoZOnDjR1dVVT0/v6dOnp06dkpeXZycAdEtBQUFISMjx48fDwsLKysp4PIajo2NMTExxcXF326+urg4JCXFycmIzAKfxSAwuyMrKCg8PDwgIYN5hJzAw8Mdlbty4MXHiRAUFheTk5A0bNlhbW0dERAgJCc2bN6+0tJQgiIqKihUrVpAbrKSk5MqVK+S2yYkYnOsLXQzAHTwSo8fT1taOiYm5d+/e4MGDTU1NtbS0OvhNTFBQ8Pz585qamkaGhhFXrkTa2W1ke36QMQMHJq1apSkjY2RoGBgYGBoaqq+v397ClZWVhw4dkpeXP336tJub28uXL7dt2yYlJcVOAIBWOL2PBd7HswOVHg+9j0LU1zKYRo4c6eXllZuba2pq6u7urqys7Ofn19TU1ObCqqqqBEGs37l+897NZAVw/d3V/YA7g8HQ1NRscwE6nR4YGKikpLR06VItLa3nz5+fO3eui5O0ASk+fvw4b968OXPmfPz4ccSIEY8fP54wYcK6deu6cr8VqmIsWrRITEyszcNJxy5fvlxbW2tnZ8dmAM7hkRhcs2/fvp07dxIEcfPmzebm5h/nMnjz5s3ixYtVVFQOHjzY8meSoKCgi4vLmzdvAgICCIIIDg62tLQkMdWNGzdUVVU3bNhAYpscisGJvtCtAFzAIzF6jxkzZkRFRSUnJ4uKilpYWBgYGDAvJPmRiIjIGDm5psbGKHt7s/HjSVm7uLBw+PLlBnJy4qKi7U1uUlZW5unpOWrUqEOHDrm5uRUUFHh6enZldnmA7uLoPhb4Am8OVHoD9D4K8Uotg2n06NGnT59++fKliYnJ6tWrx40b5+PjQ6fTv1/mzZs3KxxWLFyx8Jfdv5C7dudtzrbOtitXrvzx3Kpbt26pq6s7ODioqqrm5OT4+/vjXAwuy8vLmzZt2tevXzMzMzdu3GhlZbVnz5709PTIyEhNTU2uneHW3Rji4uKLFy/28/Pr7op8fX3nzJkjLS3NZgAO4ZEY3GRtbc2sojJPI3RwcPj+VQaDsXTp0vLy8v3797d6I/Pqs2vXrjU3NwcFBf04n0J3RUZG+vr6btmyZdy4cebm5h8+fGi1k+SO7sYgvS/w6XYA0unq6iYkJKSkpAgKCurr65uYmGRkZLRa5tKlS96nTgXY2BiReuwWFhS8Ymc3pl8/m0WLWp1PWlNT4+XlNX78+H/++cfFxeX169c7duzA5IjAOaTvY4Hv8M5ApbdB76MQb9UymEaPHn3q1Klnz55pamquWbNGXV295dxRBoPhtNJJeoS057+enFj1jiM75BTlVjisaG5uZj5z/fr1qVOnzpo1S1FRMScnJyQkZDxJP+lA1zEYDCcnp69fv0ZERIiJibU8P3LkSF9f36ysrC1btvBsDCcnp2fPnt2/f7/rK3r16lVKSsqPp5zx9XYgV3p6enBwMKfX8j0bGxuCIIqKimJiYtTU1NTU1L5/NTU1NS0tTV5eXkNDo9UbBw8eTBBESUnJ0aNHZ86c2cXJGjtw9OjR69evS0pKnjt3bvXq1Wy2xs0YJPYF1gJwAo/EAB0dnfj4+Bs3bpSXl0+fPn3BggVPnz5lvvT58+c1zs7O06fbdng/C9ZIiIiE2Nq+yM3dt28f8xnmbK/y8vLbt293cnJ69+7dwYMH+7czSQpQhfsHke5iISG5+1hys3Ef5SF780ClF+Ja74NWeLGWwTRu3Ljg4OAnT56MHz/e0tJyxowZ8fHxFy5cSE5K3n96v5i4WOdNdJ9IH5EDZw48yHjg5+d37949IyMjMzOzAQMGpKenh4aGKisrc2Kl0Klz587dvXvX0tLyx8rlzJkzR40a5e3tnZ6ezpsxNDU1x48f361irZ+f35AhQ+bMmUNKANLxQoxLly4dPXqUo6tok6+vL51O//Eni7S0NIIgDAwMfnwL83zywsLC8PDw33//nf0M8fHxISEhnp6empqaFM6axEIMEvsCawE4gUdiANOsWbPS09Nv3rz55s2bn376ycbGJj8/f9vWreICAn+19S0iheLgwbuMjP48dOjFixehoaETJkzYvHmzhYXFy5cvDxw4MGDAAA6tF9hB1UGk61hISO4+ltxs3Ed5yN48UOmFuNb7oBXerWUwTZw4MSQk5O7duxISEsbGxi5rXCyWWqhpqnX+TlZNUJtg7WT9y6ZftLS0Ghsbk5OT4+LiMEcJtby9vQmC0NHR+fElAQEBU1NTgiB8fX15Noajo+PFixdra2u7spbm5uZz587Z2dkJCwuTFYBcvBCjubmZ+2fyNzc3+/r6iouLM69svHDhwps3b75fQFFR8cd3iYiIiIiIVFVVBQQE9OnTh0tZeRVZfQGgA8bGxpmZmf7+/pmZmcrKyufOndtnbNyXk71vo7b2CCmp6dOn29ra6unpvXz58tSpUzIyMpxbI7CJkoNIt7CWkDv7WN7fegQPhMRApbfBCIcSvF7LYGKelLF79+6qyqo1v63h9OpcfnWpqanZunVrSkqKrq4up1cHHXv//j2zljxy5Mg2F2DOaRcWFsazMezt7auqqro4u0FcXFxhYaGjoyOJAUjEIzEokZ6eXlBQYG5uLiUlxWAwDh8+3HJmCrPc2eYB7OnTpwICAs3NzXJyctxMy5tI6QsAnRIQELCzs8vNzdXW1h4uJbVMjYM/gRAEISwo+Ju+fmVFRUJCgq+v7+jRozm6OoD2YB/by2GgQiH0PkrwRy2DKTMzU9NQU2ECx6cOGTV2lJ6p3qOsR5xeEXRFy9UKQ4YMaXOBYcOGEQTx5cuXVrVn3okhIyMze/bsLp545uvrO3369IkTJ5IYgEQ8EoMSnz9/JgiCWd88duzYsmXLxMX/OyG0oaHh7NmzQ0JCGhoaWpavqKjYv3//n3/+OWvWrKampk+fPlVXV2/fvp2S8DyClL4A0EUMBiPnyRPXGTOEBDg+2lmupiYpKvrjbUcBuAn72F4OAxUKofdRQojqAF1VVVV1/fr1PSf3cGd185fPd7Nz+/bt28CBA7mzRs4pLCw8f/78lClTTExMqM7CitzcXOaDQYMGtbkA85ZFBEE8e/ZszJgxvBnDyclp0aJFBQUFHde8v337FhkZ6eXlRXoAsvBIDNIxGIzo6Ojw8PDc3FxhYWExMTFHR8fFixd/v8ysWbO0tbUjIyOzs7MlJSX//vvv718NCQlxd3fX0dGxsLAQFBR89uxZfX39xo0bf//993fv3uXm5m7btu3z58/Lly/n7ifjOez3BYAuiouL+1ZWxumTMphEhXwK55cAACAASURBVISsJkwIvXTJzc2NC6vjNH4fOfRm2Mf2YJ2OVTBQoRZ6H/fxTS0jJSWloaFBd1ZXr/hIvJZ4NfhqTmZOdVW1qJiovJK8zUobk/ldPSTrztJlMBhJSUlWVlasRuYJDAbDwMDg9evXBEEkJyfz4yUz5eXlzAftXcInIiLCfFBWVsazMczNzQcNGhQQELBr164O1hIcHCwgILBkyRLSA5CFR2KQKzk52dXVtba21sPDw9vbW0RE5OPHj9bW1u/evXN3d29ZTFRUNDk5+fnz51JSUqNGjWrVSN++fb29vRsbG5kjjF9++aVlkhdZWdm8vLzc3FxpaWncCJD9vgDQRQkJCcrDhsl2eQ6Ra7m5wVlZmUVFVfX1YsLCSkOHrpw6dX6XfzebNW5cYEhIWVkZv89a0gNGDr0Z9rE9VVfGKhioUAu9j/v4ppaRnp4+asyoYSOHdbpkeWn5jjU7rl26NstqlneEt7yS/MunLzfabnSxclmyask+n30EQRR/KN69fveJsBPtNdJ/UH8FZYW0tDR+r2XU1ta2nOr/7NmzViOSW7duFRUVsdy4uLj4woULBTh87m5FRQXzQXsrEhQUZD5o+TObB2MICwsvW7bMz89v586dHUx24Ofnt3DhQuYNpckNQBYeiUGiI0eObNmyZdq0aampqS1/gcjIyPz55582Njbf1zIIghAQEOj4hEBhYeHJkye3+ZKSkhJZmfka+30BoIvu37un88Novk2ltbVrwsMvPXliNXFihL290pAhT4uLbS9csAoMXKWh4bNgAUEQHyoq1l+9Gtb+L5Z6Y8bQ6fQHDx4YGxuT9hmo0MHIgS+GDb0c9rE9UtfHKhioUAi9j/v4ppaRm5srryzf6WLFH4qtNKyKi4rnLp579OJ/Z0IaN3HcHyf/sNGxuXj64qQpk2ydba8EXKksr+y4qbFKY/Py8kiITilxcfGdO3fu379fTU2t1QnzTU1Nrq6uhYWF7DSurq4uL9/5/ws7Wv4kbvkjuZWW51v+zObNGE5OTl5eXomJiUZGRm0u8Pjx44cPH/71118cCkAKHolBlrNnz27atGngwIERERGtfkptbm6ur6+nKljPxmZfAOii3NzcRdranS72oaJC4/jxooqKxT/9dHHpUuaTE6WlT1pZ6Zw8eTo9fcqIEc7TpwdkZpbX1XXQzggpKSkxsby8PH6vZbQ3cuCXYQNgH9vDYKzCR9D7uIxvSuOF7wtHjB7R6WI7XXcWFxULiwjv9Nr5/fPqWupS/aUIggg4FkAQRKhv6EKHhR03NVJu5Nt3b9mIzCs8PT3r6uru37/favcnJCT04sWLWjZ8/fqVCyOSxsZG5oP2CpwMBoP54Pu7GfFgjJ9++kldXb2DyUr9/Pzk5OQMDQ05FIAUPBKDFAUFBevXrycIYvv27S03+m5x6tSppf/3Vw2Qi82+ANAVtbW1X0tLR3fhZGnXiIiiigoRQUEvC4vvn9eSle0vJkYQxLG7dwmC8H3wwGHKlI6bkhs0iJ0/9XlHmyMHfhk2APaxPQnGKvwFvY/L+Oa8jMrKSkkpyY6XiY+KvxV5iyAIYwvjwdKDv3+JRqMpTFB4ePdhwcuCiKAIgiDMbc07bk1SSrKyspNzN/gFX5/P2XIKVnNzc5sLtEzfLSUlxeMxnJyc3N3dy8vLfzyvrKGhISgoaMOGDe3VCHrSduiKqqqqDq5SqaysbGho6OBUZzExsU5v3Ltjx47a2lphYeFWc2Ldu3dv+/btdDr91KlT3Y0NXcROXwDoCuYRvG87d/ZpEfX8eeSzZwRBWEyYIC35P8MMGo02YejQu2/fvvzyJejRI4IgbFVUOm6tr4gIRg48ggsHETZxNCGb+1je33oED4TkTgB+HKuUl5dXVVWx8MY+ffq03EKeoziakP0RTi/fgN1Cfi0jISEhPz/f1ta2b9++JDZLp9M7PawmX09mPjCa18ZZPQMHDyQIorGhce+mvYcDD7d3hnwLAUGBlr/KSMSh7dODtewIWs4IaKWpqYn5gDt/w7MTw9LSct26dbdv37a0tGz1Unp6+tevXy3+91dB0gOwjzsxmpqaRo8e/e3bt44XGzlyZAev5uXlKSoqtvdqTU1NeHg4QRCDBg36888/GQxGdXX1q1evysvLR44cuWLFCnt7e/wtzTns9AXoeThxZGTWWwU768XXX7xgPpjX1oXigyUkCIJooNM3RUcHLl4s2Nk4REgAIweewIWDCJs4nZCdfSzvbz2CB0JyJwA/jlXKysqkpaVZPjmXC/cb5nRCNkc42IDdQnItIzw8fMGCBQRBXLp0KT4+nsSWJSUla6prOl4m+0E288FUnak/vtq3/39HAAvsF+jN1ut0jdWV1aQPGji3fXqwlhNc69q5ULnlQkGO3kSHlBjx8fFCQkLTp0//8SVVVVUJCYmEhARVVVXOBWAfd2IICQmlpqYyp0lv0/Hjx7Ozszv4LUJcXLzj8cG9e/eqq6sJgli6dOn8+fNpNJqoqKi0tPSPJ3ACJ7DTF6CH4dCRUVJSkiCIqs4GWw/ev2c+0GlrCr3+oqLMB/bq6rO78DdPRX09Rg68gAsHETZxOiE7+1je33oED4TkTgB+HKv0798/IyOjtLSUhff26dNn2rRppEdqhdMJ2RzhYAN2C8m1jAcPHjAfZGZmktuy9FDpzx/a3V8wMS/UFxUTlZWX/fFVyb7/PXfUYmmXfu77/PHz0KFDuxmzE5zbPj3Y8OHDmQ/au5dkcXEx88GIEZ3fUYXaGH5+fnPmzBk2rI3peCQlJW1sbHx9fTdv3sy5AOzjWgxlZWVlZeX2Xo2IiCgoKNDX12e5/ff/9wfM/Pnz2zzeAEex0xegh+HQkVFCQkJCXPxjZ1d8MEcOYsLC8oMG/fhqyyUqS7tWWftYUYGRA4/g9EGEfRxNyOY+lve3HsEDIbkQgE/HKj/99BPVETrB0YTsj3B6+QbsFpJrGY6OjkFBQUVFRdu3bye3ZSUlpauxVzteRnW66pOMJwwGg06nt7qEpPRL6eP0x8zHnc5gwlSQV6A9rfP7n3cL57YPC5qamiwsLNi8Ifnly5d/nL+aXBoaGswHJSUlbS7w8eNHgiCEhIRUOruSmdoYr169Sk5OvnLlSnurcHR09PPzy8jIaLNg2WO2A4+ora1lPuhgIAIcwmZfgB6GQ0dGGo2mqKCQ2/6vpkzTZWUz3r9nMBj05uZWl5B8qa5O/79DZMczmLQs86m8fPz48SxnbhPvjBz4ZdgA2Mf2GBir8B30Pi4juZahoKBQUFBQV1cnJiZGbstqamqHDx+uqqjq4A6g63asuxF+o7ioONQ3dMmqJcwnPxZ+jAiKCD8XbmVvVfCyoKKs4nXea7lxcjvW7PAO9xYSbnsL1NXWPXv8bN3qdeR+Cs5tHxYICQlZWFiwM1G8mJjYkCFDSIzUpokTJ0pLSxcXFxcUFLS5wIcPHwiC0NXV5ehWZT+Gv7//kCFD5s6d294qdHV1x40b5+vr2+bercdsBx6hoKBAEASNRuPOTZLge2z2BehhODhymDr1fmJix8vsMDIKz8kpqqjwffBg1f/VagvLy4MePjz38KG9uvrLr1/LamvzSkrGDR68Jjw83M5OuJ37baW9e0cQhLq6OrmfgndGDvwybADsY3sMjFX4Dnofl5F/708ajcaJw62BgQGdTk+7nWZs0e607YOGDgq9E3p099E/Nv5x/uT5IcOGfHr/iSCIeUvmRWREiEuKT5oyafPyzV6eXv/u+3e56/L2ChkEQWSkZNTX1bc3MzA7OLR9OvDq1Ss/P7+pU6fOnz+/1UsuLi7cTMIaAQGBlStX7t+///bt28xZqVpJTk4mCMLe3r7V8x18cBZeYjkGU3Nzc0BAgJ2dnbCwcAcf1sHB4c8//zx8+PCPXxIub4f2XmVzO/COCRMm0Gg0BoNRWVnZ3vXt27dvV1dXX7iwk/mbeR+5fYFN7PcFlvHUdoDvcejIaGhoGBgQUFFfL9X+bCZDJSXvrFmzOz5+Y1TUybS0YX37vi8vJwhiiYpKxvr1kiIiU0aOXH7xouetW/sSElw1NdsrZBAEEffy5bixYzu+1R9reGfkwBfDBg4h92DKORTuYzuGPTALetVYpT0s9y/uf3l4s/fxy76LRQz+oTFdw9zW/BXjVaf/8pvz7xbdvZV3K7syu9VLeQ158S/in1Q86bgFayfryT9NpvoTk6C5uVlW9r93D4mPj6c6TieEhISCgoJ+fL6oqGjAgAGioqIVFRWtXmJeSKymptbY2Pj98x18cNZeYi1Gixs3bhAEkZOT0/6nZzAYjMLCQgEBgfPnz7f5Kte2Q8evsrwd2vv/ZcEvv/wydepUNhtZtmwZQRCxsbE/vkSn07dt2+bk5ESn09lcC2u6uK2cnZ0Jghg0aFAHy3CiL7AQowUpfYGFADy1HUjsC9CBkpISEWFh30WLGAcPdvqv+cCBot9/z9uypXLPnlYvNezb92LLlorduzt4O/3AAdmBA7ds2UL1hyZBzxg5dKy7BxFOHEzJTdiCE/tY9rNxYQ/MfkgG7w1UGD1irMIOlvsXJfsxLvS+7uL+vos1LH+X+Gny8BX2K+Ii4kq/dH7TVBqNJj1ceoziGHFJ8VYvCQkLyY2Tk+gr0cHbK8srr1++bm/H6z8sd0VdXV3LfYPy8/OpDcOy4cOH+/r61tXVbdiw4fvnGxsbXV1dRUVFfX19hYT+5yybDj44ay+xFqOFn5+fhobGxIkTO/6kI0eOnDVrlq+vb5uvcm07dPwqO9uBp+zdu3fw4MF79uxpNa1UbGysiYlJv379zp492+lU0NxXW1tbVVVVUlKSkJBw/fp1giC+ffvm4+Pz/v37ioqK6upqBoPx/fKc6AssxGhBSl9gIQCvbQfggsGDB8+ZM+dM126ZSaPRhktJKQ4eLCki0uolYUHBcYMH923/5A6CIOJevnz37ZudnR3rcXlGzxg5kIsTB1MOIWsfSy4O7YF7Az4dq5CF5f5FyZeHB3sfH+27WMNPX307OztxMXE/Lz9Oryjw30AaQVu5ciWnV8QFYmJiBw8elJKSMjIysrW1pToO6+bPn3/58uWrV68uW7bs2bNn1dXVd+7cMTIyKi4uTk1N/XFmow4+OGsvsRaDqaysLCIiwtHRsSuf1NHRMSEh4e3btxRuh05fZW078Bo5ObmHDx/SaDQNDY09e/Z4e3uvXbt2+vTpUVFR58+f/+2336gO2DZDQ8Phw4crKSktWbKktrZWWlp6yJAhHh4eampqsrKyAwcOfPfu3ffLc6gvdDcGE4l9ga+3A3DNL5s23X3zJun1a06v6EBSkpGBAe/c2p0dPWbkQCIOHUxJR+I+llwc2gP3Bnw6ViELy/2L+18e3ux9/LLvYhmNv34y2rt378FDB288uyEzSoZDq/hS/MVEyWSd67p9+/ZxaBXQHmFhYX9/f+bZdG0qLS0NCQlJSUkpLS0dNmzYrFmzLC0tRUVFuRmShRgnTpxwc3P7+PFj//79O228vr5++PDhGzZs2LVrF1kBOKS7MTr9/+26TZs2paamZmRksN8UQRDFxcUZGRmNjY0jRoxQU1Pr+CpH7iBxW/EU0vsCn+qp/7+8SV9Xt66w8J6LiwCNxqFVRD1/bhEQcPv2bcpnqeyFWOtN5B5EOIG1hNzZx/L+1iNYDcmzAxUCYxWehxEOO1j+LpF/HnhCQkJ+fr6trW17t6hhh5ubm6+fr+c6T+8IbxpnBiV/bPyjr2RfzpU5Obp9erwBAwY4OzszL0rnoxh+fn4LFizoyq6NIIg+ffosXbrU399/586d7X3J+XQ7kIhGo5G4B5CWlp43bx5ZrUEHSO8L0DNw9Mh49PjxqVOmnLh3b52WFumNEwRRUV+/ITraxtqac4UMjBxIR+5BhBNYS8idfSzvbz2CB0KSHgBjFR6HEQ4lSL7GJDw8fObMmc7Ozhy636mYmNiZ02cSohPOHTvHifYvnr54LeSazykfScl2Z35lB6e3D/CgnJycBw8eODk5df0tTk5OBQUFiZ1NJdibmZiYWFtbU50Cugd9AdrE6SOjioqK+9at7rGxWR8+cKL9VVeu1NBoR7y8ONE4gZEDZ/D+QYSFhFzbx/L+1iN4ICTlAYCbMMKhCsm1DOYsBgRBZHbtVlssMDIy2rFjx363/bdjbpPb8t34u55rPbdu3TpnzhxyW27Bhe0DvMbX13f06NHdmt9XTU1NRUXFz4/jt4bhX2ZmZu7u7lSngO5BX4A2ceHIuGfPHo3p0+cGBBSWl5Pb8q64uLDs7MDz52VkOHXpK0YOnMD7BxEWEnJtH8v7W4/ggZCUBwBuwgiHKiTXMhwdHWVlZQUFBbdv305uy9/T1tYmCMJ1oWvyjWSy2kxLTHO2dG5ublZXVyerzR9xZ/sA72hsbAwKCnJwcOju+WNOTk5hYWHlZA+7AaiCvgDt4cKRUUhISG3KlJKqqplnzrwrKyOr2QOJiXvi4/tKSY0bN46sNn+EkQN0BfaxAFRB76MQybUMBQWFgoKCyspKzlUi7927Z2VlZW5uvnDBwtXmqy/6XGS/zSsBVxzNHE1NTVesWGFnZ8ecV48TuLB9gKdcu3bty5cvDg4O3X3jsmXL6HT6xYskfL0BeAH6ArSHC0fGI0eOHD16dO/+/SKDB2udOpVeWMhmg/VNTa4REdtv3ty/f/+YMWNMTEw+cOYCFgIjB+ga7GMBqILeRyHy52Sl0WhiYmKkN8uUlZVlZmZmZGR06dKloKAgNzc3DxePX5b+8q3kG2sNln0rc3dw3+q4da3r2tCQUB8fH0tLS2tr6/v375ObvAVHtw/wGj8/P0NDQzk5ue6+cdCgQRYWFjjxDHoM9AXoAEePjKdOndq8efM///yzdevW5NRUJVVV3VOnDiUlNdLprDWYU1ys4+MT+OTJhQsXfvvtt5iYGAEBAVNT09LSUnKTt8DIATqFfSwAVdD7KER+LYNz3rx5Y2ZmpqqqGhISIiwsTKPRDhw4EBUVlXE7w0TJxPc/vjXVNV1vra627tyxcybjTVJiU8LCwg4fPiwoKCgoKBgUFKStrT1v3ry8vDzOfRZok4iISJ8+fahOQZqampqYmJhu3Qfoe05OTvfv3y8qKiI3FYV62P8vR/WwbYW+0EoP+//lZeHh4WvXrt2+ffumTZsIghg4cODNW7d27Nq1Kz5e/d9/I58969bM9B8qKjZGRakfO8YYNCj9wYPFixcTBDFs2LC4uLjS0lILC4va2lpOfRJoB3oTgX0sefB16hZsLgK9jyQsf5do3TqKU+jLly86OjrCwsLJyckDBgz4/qWKiordu3efPHlSTELMYpmFxVKLyVMnCwi0XaZpbm5+9uhZ1IWoyKDIyvLK1atX7969u9X0OTU1NcbGxoWFhXfv3h01ahQHPxX8r6SkpGnTpomLi1MdhDRXrlwxNzdnbQ5wBoNx5coVKyur9r7MfKfn/f9yTs/bVugL3+t5/7+8KS0tbebMmUuXLj19+nSrl168eLFl8+bomBglaWkHNTXryZPHDBzYXjt1TU2Jr16dz8q6nJMzYMCAHbt2OTs7CwoKfr/M06dPdXV1tbW1w8PDhYTIn/Ae2oPexIR9LCnwdeoWbC4m9D72sfxd4o9aRleKC58/fz5x4sS5wHNvXr/pP7C/6gzVcRPGDRs5TFxSnEaj1VTVfHz/8dXzV1lpWd++fJMdLWtvZ+/q6trejcc7KJ0AAAAAj+tKceHx48fHjx+/HBJSVlExdsiQqTIy44cMGSYpKSEiUk+nV9TVvf727dmXL/ffvq1rbJw+bZqDk5ODg4OoqGibrSUnJ5uamtrZ2fn4+HDykwEAAABBcKKWkZCQkJ+fb2tr27dvX1IabGxstLCwyMjISE1NVVJS6nhhBoORlZWVkJCQnp6e9yLv/fv31VXVDAZDQlJixIgRSuOVpk6damRkNGXKlE7vNPvmzRstLa3x48dfv369vYELC0jfPgAAAHyN9CPj+/fvtbW1ZWRk4uPjJSQkOl64rq7uzp07iYmJWY8evczLK/nypaKqSqxPH0kJCTk5OeVJk7S0tGbOnDlmzJhO13v16tUFCxZ4eHh4enqS8kGYMHIAAAD4Ecm1jPDw8AULFhAEYWRkFB8fz36DDAbDyckpJCQkLi5OS0uL/Qa7JTs7W09PT19fPywsrNXZpKwhffsAAADwNdKPjF+/ftXV1aXRaCkpKQPbv3KEQ06dOuXi4nL06NH169eT0iBGDgAAAG0i+cqcBw8eMB9kZmaS0uDWrVsDAwODg4O5X8ggCGLy5MlXrly5fv36unXrSGmQ9O0DAADA18g9MtbW1lpaWlZUVMTExHC/kEEQhLOzs4eHx6ZNm8LCwkhpECMHAACANpFcy3B0dJSVlRUUFNy+fTv7rR0+fPiff/45c+aMpaUl+62xxtDQ0N/f38fHZ//+/ey3Ru72AQAA4HckHhmbmpoWL1787NmzGzdujB49mpR4LNizZ4+Dg4OdnV1KSgr7rWHkAAAA0Cby75fBYDDq6urYnwg9ICDA0dFx//79v/76KynB2HHkyJHNmzefPHnS2dmZzabI2j4AAAA9AylHRgaD4eDgEBoaevPmTR0dHbKysaapqWnBggUpKSmJiYmqqqpstoaRAwAAwI94dB6TyMjIRYsWubq6enl5UZ3lv3bu3Llv377z588vWbKE6iwAAADwP9zc3I4dOxYeHj537lyqsxAEQdTW1s6ZM+fp06fJycmd3rkcAAAAuosXaxkJCQlz585dvHixn59fp7ONcBOvjZMAAACAIIhdu3bt3bs3KCjI1taW6iz/X2VlpZGR0adPn1JSUuTk5KiOAwAA0KPwXC0jPT3d2NjY2Ng4JCSkvQnhqcJgMFatWhUcHBwbG6uvr091HAAAACCOHz++fv36I0eObNy4keosrX358kVfX7+hoSElJWXYsGFUxwEAAOg5eKuWkZOTY2BgoKamFh0d3adPH6rjtIFOpy9ZsuTmzZsJCQlTpkyhOg4AAECvFhgY6ODgsG/fPl64u1abPnz4oKOj07dv39u3bw8YMIDqOAAAAD0ED9UyXr9+raurKysrGxcXJykpSXWcdjU0NFhYWGRmZiYlJU2YMIHqOAAAAL0U8+5aa9euPXLkCNVZOvLq1StdXV05Obm4uDgJCQmq4wAAAPQEvFLL+PDhg66uroSERFJSEu//alFTUzNr1qyCgoLU1FRcAQsAAMB9PHt3rTbl5OTo6+urq6vz7JmnAAAA/IUnahmfPn2aOXNmY2NjSkqKtLQ01XG65Nu3b/r6+nV1dYmJiSNHjqQ6DgAAQC+SnJw8d+7cOXPmBAcHCwoKUh2nS9LS0kxMTExNTS9cuCAsLEx1HAAAAP4mQHUA4uPHj4aGhvX19bdu3eKXQgZBEAMHDoyLixMWFjYwMHj37h3VcQAAAHqLxMTEOXPmGBsbBwYG8kshgyCIGTNmREVFXb9+3cbGpqGhgeo4AAAA/I3iWsanT5+MjY3pdPrt27dlZWWpDdNdw4YNu337tpiYmJ6e3uvXr6mOAwAA0PMlJSVZWFjMnj07JCRERESE6jjdY2BgcP369fj4eCsrq7q6OqrjAAAA8DEqaxmFhYV6enrMQgafXqYxdOjQ+Pj4vn37zpw5E+UMAAAAjrpx44aZmdmcOXMuXrzIp5dp6OjoXLt2LSUlxdraGuUMAAAAllFWy3j27Jm2trawsHBiYuLw4cOpisG+oUOHJiQk9OvXT0dH5/Hjx1THAQAA6JkuXLhgYWFhZWV1/vx5ISEhquOwTldXNzY2NiUlZfbs2eXl5VTHAQAA4EvU1DIyMjL09fWHDRuWlJQkIyNDSQYSDRkyJDU1ddKkSTo6OnFxcVTHAQAA6Gn+/fff5cuXr1q1KjAwkK8LGUza2tqpqan5+fna2tpFRUVUxwEAAOA/FNQyYmJiDA0NNTQ0EhMTBw8ezP0AnCApKXn16lUTExMLC4vw8HCq4wAAAPQQDAbDw8Nj/fr1e/bsOX78uIAA9bctJ8WkSZOSk5Pr6+v19PRevnxJdRwAAAA+w+0BwZEjRywtLRcsWBARESEhIcHltXOUqKhoaGionZ3dokWLDh06xAuT3QIAAPC1mpoaW1vbgwcP+vj4bN++neo4JBs7duydO3cGDBigqakZHx9PdRwAAAB+wr1aRn19/cqVKzdv3uzm5ubv78+nt+zqmKCgoI+Pz8mTJz08PGxtbWtqaqhOBAAAwK/ev3+vr68fGxsbERHx888/Ux2HI4YOHZqUlGRoaGhqanro0CGq4wAAAPANGndOHygqKlq4cOHz58+DgoLMzc25sEZq3bhxw9bWdsyYMeHh4Xw31ywAAADlkpKSrK2thwwZEhkZqaCgQHUczmIwGHv37vX09FyxYsWJEydERUWpTgQAAMDruHFeRlhYmIqKyrdv3+7du9cbChkEQZiamqalpdXW1qqoqFy4cIHqOAAAAHyjsbHRw8Nj5syZmpqaaWlpPb6QQRAEjUbbsWPHlStXLl++PG3aNEyLBgAA0CnO1jIqKyudnZ0XLVpkZGSUnp4+YcIEjq6OpygqKmZmZtrb2y9btszGxubbt29UJwIAAOB1r1+/NjAw+Oeff/bt2xceHt63b1+qE3GPpaXlkydPBgwYMG3aNE9PTzqdTnUiAAAA3sXBWsa1a9dUVFTCwsIuX74cEhLSv39/zq2LN4mJiXl5eUVGRiYlJamqqmJ+EwAAgPY0NDT8/fffkydPrq2tzczM3LZtW4+ZsqTr5OTkEhISduzYsX//fiMjo+zsbKoTAQAA8CiOjBJycnJMTU3nzZunoqKSnZ29cOFCTqyFX5ibm2dnZ2tqai5YsMDIyCgrK4vqRAAAALwlIiJi4sSJHh4emzZtSktL61UncrYiJCS0Y8eOO3fuVFRUqKmprVmzpqSkhOpQEmNdggAAA1lJREFUAAAAPIfkWsaLFy+cnZ3V1NSKi4vj4+PDw8NlZGTIXQU/Gjp06KVLl1JSUiorK6dOnbpy5crc3FyqQwEAAFAvISHByMjIyspKVVX1+fPne/fuFRERoToU9aZNm5aZment7R0REaGoqHjgwIGvX79SHQoAAICHkFPLaG5ujo2NNTMzU1ZWvn79+okTJzIzM42MjEhpvMfQ0dG5f//+2bNnExMTJ0yYMGvWrKioqObmZqpzAQAAcFt1dfWpU6cmTZo0c+bM+vr65OTk0NDQMWPGUJ2LhwgICPz8888vXrxYs2bNwYMHR40a9fPPP+PsTgAAACa25mQtLS29d+/ejRs3IiMj3759a2BgsG7dOktLSyEhIRIj9jzNzc3R0dHHjh2Lj48fOXKkubn5nDlzZsyYMWjQIKqjAQAAcNDbt29TU1Ojo6NjY2Pr6upsbGzWr18/bdo0qnPxusrKyoCAgOPHj+fl5amrq1tYWBgbG0+ZMgWztwIAQK/V7VrGxo0bS0tLP336lJ+fX1BQwGAwlJWVLSwsli1bNnnyZA6l7KmeP38eFBR09erVnJwcGo02evRoeXl5GRkZCQkJb29vqtMBAACw682bNwcPHqyoqCgsLHzx4kVJSYmgoKC2tralpeXy5cuHDh1KdUB+wmAwbt26FRoaGhUV9enTJ2FhYQUFBXl5+SFDhqioqGzcuJHqgAAAANzT7VqGmZkZg8EYNmyYvLz8pEmTZsyYgTtisK+4uDgtLS07O/vVq1efPn2qqalJSkqiOhQAAAC7srOzN27cKCEhMXLkSHl5eXV1dQ0NDUlJSapz8b28vLz79+/n5uYWFBSUlJRMnjz58OHDVIcCAADgHrauMQEAAAAAAAAA4LJeN3M7AAAAAAAAAPA11DIAAAAAAAAAgJ+glgEAAAAAAAAA/AS1DAAAAAAAAADgJ6hlAAAAAAAAAAA/QS0DAAAAAAAAAPgJahkAAAAAAAAAwE9QywAAAAAAAAAAfoJaBgAAAAAAAADwE9QyAAAAAAAAAICfoJYBAAAAAAAAAPwEtQwAAAAAAAAA4CeoZQAAAAAAAAAAP0EtAwAAAAAAAAD4CWoZAAAAAAAAAMBPUMsAAAAAAAAAAH6CWgYAAAAAAAAA8JP/Byi7F6IpNCFEAAAAAElFTkSuQmCC" } }, "cell_type": "markdown", "metadata": {}, "source": [ "ZX-diagrams are string diagrams (aka tensor networks) made up of 2 special generators: _Z-spiders_ and _X-spiders_.\n", "\n", "![spiders.png](attachment:spiders.png)\n", "\n", "A useful thing about these generators is they are invariant under changing the order of inputs/outputs, or even changing an input to an output. Hence, in PyZX, we represent ZX-diagrams as indirected graphs.\n", "\n", "In the previous code block, you saw there were 3 kinds of `VertexType`s we use in graphs: `Z`, `X`, and `B(OUNDARY)`. The first two correspond to Z and X (i.e. green and red) spiders, whereas the third one is a dummy type we use for representing inputs and outputs of the diagram, i.e. wires which are not connected to a spider at one end.\n", "\n", "To get started, lets make a Z-copy spider, i.e. a Z-spider with 1 input, 2 outputs, and no phase." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# create a new, empty graph\n", "zcopy = zx.Graph()\n", "\n", "# add_vertex adds a vertex of a given type and returns an id that we\n", "# can refer to later\n", "in1 = zcopy.add_vertex(B, qubit=1, row=0)\n", "z1 = zcopy.add_vertex(Z, qubit=1, row=1)\n", "out1 = zcopy.add_vertex(B, qubit=0, row=2)\n", "out2 = zcopy.add_vertex(B, qubit=2, row=2)\n", "\n", "# add_edge takes a pair of vertex id's and creates an edge. Note the\n", "# double-parentheses!\n", "zcopy.add_edge((in1,z1))\n", "zcopy.add_edge((z1,out1))\n", "zcopy.add_edge((z1,out2))\n", "\n", "# tell pyzx which boundary vertices should count as 'inputs' and which\n", "# as 'outputs', and in what order. This only matters for sequential\n", "# composition.\n", "zcopy.inputs = [in1]\n", "zcopy.outputs = [out1,out2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Most of the time, we won't be building graphs by hand, but it's useful to get an idea of how the data structure works. One thing to note is `add_vertex` takes two parameters `row` and `qubit` which tell PyZX where that vertex should be drawn. These names make sense in the context of a ZX-diagram that came from a quantum circuit, as we'll see later. However, for generic ZX-diagrams, it suffices to think of `row` and `qubit` as X and Y coordinates for positioning vertices on the screen.\n", "\n", "Speaking of drawing, we do that with `zx.draw`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "zx.draw(zcopy)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note you can move vertices around by clicking and dragging. This comes in handy when the graphs get more complicated.\n", "\n", "Now, lets make graphs that correspond to a single wire (i.e. the identity process) and the swap. We use a convenience method called `auto_detect_io`, which tries to guess which boundaries should be inputs and outputs, and orders them from top to bottom." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false }, "outputs": [], "source": [ "wire = zx.Graph()\n", "in1 = wire.add_vertex(B, qubit=0, row=0)\n", "out1 = wire.add_vertex(B, qubit=0, row=1)\n", "wire.add_edge((in1,out1))\n", "wire.auto_detect_io()\n", "\n", "print(\"wire :=\")\n", "zx.draw(wire)\n", "\n", "swap = zx.Graph()\n", "in1 = swap.add_vertex(B, qubit=0, row=0)\n", "in2 = swap.add_vertex(B, qubit=1, row=0)\n", "out1 = swap.add_vertex(B, qubit=0, row=1)\n", "out2 = swap.add_vertex(B, qubit=1, row=1)\n", "swap.add_edge((in1,out2))\n", "swap.add_edge((in2,out1))\n", "swap.auto_detect_io()\n", "\n", "print(\"swap :=\")\n", "zx.draw(swap)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Rather than starting from scratch, we can make an X-merge by taking the adjoint of Z-copy, then changing the Z vertex to an X vertex with `set_type`. Note: we needed to know that the id of the Z vertex is equal to 1." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "xmerge = zcopy.adjoint()\n", "z1 = 1\n", "xmerge.set_type(z1, X)\n", "zx.draw(xmerge)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can set the phase of a spider with `set_phase`, or use the optional `phase=` paremeter to `add_vertex`. It is given as a rational multiple of pi, so we use Python's built-in `Fraction` type for this." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "xmerge_pi4 = xmerge.copy()\n", "xmerge_pi4.set_phase(z1, Fraction(1,4))\n", "zx.draw(xmerge_pi4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Question 1.1\n", "\n", "Make an X-merge operation that takes 3 inputs instead of two and has a phase of pi/3 and draw it.\n", "\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Unless you have a really crazy keyboard, you probably don't have keys for ⊗ and ∘. But, you probably have `@` and `*`, so these will have to do." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "g = zcopy @ xmerge # parallel composition\n", "zx.draw(g)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "g = zcopy * xmerge # sequential composition\n", "zx.draw(g)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's see what happens if we compose the other way around:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "g = xmerge * zcopy\n", "zx.draw(g)" ] }, { "attachments": { "parallel-edges.png": { "image/png": "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" } }, "cell_type": "markdown", "metadata": {}, "source": [ "Where did the edges go? To keep things simple, the `Graph` type does not allow more than one edge between a pair of vertices. This means if we _do_ produce a situation where there would have been more than one edge, PyZX fixes this up automatically, using the spider fusion rule (if the colours are the same) or complementarity rule (if the colours are different):\n", "\n", "![parallel-edges.png](attachment:parallel-edges.png)\n", "\n", "Note the `add_edge` method is too dumb to do this: calling it multiple times for the same vertices has the same effect as calling it once. On the other hand, `add_edge_smart` will automatically \"Do the Right Thing\" when there is already an edge there." ] }, { "attachments": { "3cnot.png": { "image/png": "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" }, "cnot.png": { "image/png": "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" }, "parity.png": { "image/png": "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" }, "reverse.png": { "image/png": "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" }, "tonc.png": { "image/png": "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" } }, "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Question 1.2\n", "\n", "Produce the following diagrams using parallel and sequential compositions of the generators we have already:\n", "\n", "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "_Note: if you compose things in a different order, your diagram might look a little bit different. Remember only connectivity matters!_\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Particularly when we are interested in quantum circuits, it is often more convenient to input them using a simple textual format called [OpenQASM](https://en.wikipedia.org/wiki/OpenQASM). This stands for Open Quantum ASseMbly language. We can produce a circuit by passing a bit of QASM code to the `zx.qasm` function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "circ = zx.qasm(\"\"\"\n", "qreg q[3];\n", "\n", "cx q[0], q[1];\n", "s q[1];\n", "h q[1];\n", "cz q[1], q[2];\n", "rz(0.1*pi) q[2];\n", "\"\"\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "PyZX doesn't implement everything in OpenQASM, but enough to make circuits from basic gates. The command `qreg` says create a register of qubits of the given size. Gates then take as parameters which qubits to act on. Like lists in Python, qubits are indexed from 0. So `cx q[0], q[1];` says apply a CNOT gate between the first and second qubits.\n", "\n", "Some of the gates that PyZX knows about are:\n", "\n", " * `h` - Hadamard\n", " * `s` - S-gate (pi/2 Z-phase gate)\n", " * `sdg` - adjoint of an S gate (`dg` := \"dagger\")\n", " * `t` - T-gate (pi/2 Z-phase gate)\n", " * `tdg` - adjoint of a T gate\n", " * `rz(N)` - Z-phase of N, where N is given as a decimal or decimal * pi\n", " * `rx(N)` - X-phase of N\n", " * `cx` - CNOT gate\n", " * `cz` - controlled-Z gate\n", " * `ccz` - controlled-controlled-Z gate\n", " * `tof` - Tofolli gate\n", " \n", "Qubits should be separated by commas, and every line of QASM code ends with a semicolon.\n", "\n", "`zx.qasm` produces a `Circuit` object, which is basically just a list gates. The `Gate` object consists of a name and the qubits it applies to, and possibly another piece of data, like a `phase`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(circ.gates)\n", "\n", "# the first gate is a CNOT\n", "print(circ.gates[0].name, circ.gates[0].control, circ.gates[0].target)\n", "\n", "# the second gate is an S gate\n", "print(circ.gates[1].name, circ.gates[1].target)\n", "\n", "# ...and so on" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can turn this circuit into a ZX-diagram by called `to_graph`, and draw it. We can also just call `zx.draw(circ)` to do the conversion automatically." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "g = circ.to_graph()\n", "zx.draw(g) # equivalently: zx.draw(circ)" ] }, { "attachments": { "blue-edge.png": { "image/png": "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" } }, "cell_type": "markdown", "metadata": {}, "source": [ "You'll notice a couple of blue edges in the diagram. This is a useful shorthand for a Hadmard gate on a wire:\n", "![blue-edge.png](attachment:blue-edge.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Question 1.3\n", "\n", "Produce a circuit involving multiple CNOT gates in a variety of positions using QASM. Produce the same circuit as a composition of `zcopy`, `xmerge`, `swap`, and `wire` and draw both to compare.\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can print out the matrix of a picture by writing `print_matrix`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lhs = zcopy * xmerge\n", "zx.draw(lhs)\n", "print_matrix(lhs)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "rhs = (xmerge @ xmerge) * (wire @ swap @ wire) * (zcopy @ zcopy)\n", "zx.draw(rhs)\n", "print_matrix(rhs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we want to check if two matrices are equal, it's best to use `zx.compare_tensors` (n.b. a \"tensor\" is another name for a matrix with multiple input/output indices, not to be confused with ⊗). This has a convenient extra argument called `preserve_scalar`, which when set to false, compares matrices up to a number." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(zx.compare_tensors(lhs, rhs, preserve_scalar=True))\n", "print(zx.compare_tensors(lhs, rhs, preserve_scalar=False))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The matrix or tensor of a graph `g` can be obtained directly by calling `g.to_matrix()` or `g.to_tensor()`. These consist of floating point numbers, so comparing them with `==` is generally not a good idea, due to rounding errors.\n", "\n", "Finally, note the `Graph` type has a `scalar` property, which holds an overall scalar factor, which is used when computing the matrix. It is equal to 1 (actually `zx.ONE`) by default." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "rhs1 = rhs.copy()\n", "rhs1.scalar = zx.SQRT_TWO\n", "print(zx.compare_tensors(lhs, rhs1, preserve_scalar=True))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Scalars are of type `Scalar`, which represents common scalars exactly (rather than as floating point). Some ready-made scalars are:\n", " * `zx.ONE`\n", " * `zx.TWO`\n", " * `zx.TWO_INV`, i.e. $\\frac 1 2$\n", " * `zx.SQRT_TWO`\n", " * `zx.SQRT_TWO_INV`, i.e. $\\frac{1}{\\sqrt{2}}$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Question 1.4\n", "\n", "Use `compare_tensors` to check your work on Question 1.3. Are the matrices of the two diagrams equal exactly, or up to a number? Why?\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Question 1.5\n", "\n", "Create ZX-diagrams corresponding to the basis states for the Z basis (a.k.a. the \"computational\" or \"standard\" basis) and X basis (a.k.a. the \"plus\" basis). Use the `scalar` property to normalise them, and verify they produce the correct matrices.\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Question 1.6\n", "\n", "Use `zx.qasm` to produce a 3-qubit circuit containing a variety of gates. By plugging the states from Question 1.5 into the inputs and their adjoints into their outputs, evaluate the complex amplitudes and the probabilities associated with several different inputs and measurement outcomes for this circuit. Choose a circuit and measurements so that at least some of these probabilities are different from 0 or 1.\n", "\n", "Hint: If a graph `g` has a 1x1 matrix, you can get the complex number out by calling `c = g.to_matrix()[0,0]`, and you can get its complex conjugate with `c.conjugate()`.\n", "\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, let's apply some rules to ZX-diagrams. All of the rules we will use take a graph and one or more vertex id's as indices. We can see which vertices are where if we set `labels=True` on in `zx.draw`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "g = zcopy * xmerge * (wire @ xmerge)\n", "g.set_phase(3, 1)\n", "zx.draw(g, labels=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Recall we included all of the rules in `pyzx.basicrules`. Notaby, these rules include:\n", " * `fuse(g, v1, v2)` - spider fusion\n", " * `color_change(g, v)` - color change a single spider\n", " * `strong_comp(g, v1, v2)` - strong complementarity\n", " * `remove_id(g, v)` - replace 1-to-1 spider with wire\n", "\n", "Calling these functions will check whether a rule applies to the given vertices, apply it and return `True` (if it applies) or do nothing and return `False` (otherwise). There are also functions called `check_RULENAME(g, ...)` which will check if a rule applies without applying it." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "g1 = g.copy()\n", "zx.draw(g1, labels=True)\n", "fuse(g1, 4, 1)\n", "zx.draw(g1, labels=True)\n", "strong_comp(g1, 4, 5)\n", "zx.draw(g1, labels=True)\n", "zx.compare_tensors(g, g1, preserve_scalar=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that `strong_comp` is a bit more general than the normal strong complementarity rule, because it allows 0 or $\\pi$ phases on either of the spiders, which get copied through.\n", "\n", "Like with composition, rule applications are smart enough to remove parallel edges using the complementarity law." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "g = xmerge * (xmerge @ wire) * (wire @ zcopy)\n", "g1 = g.copy()\n", "zx.draw(g, labels=True)\n", "fuse(g, 4, 6)\n", "zx.draw(g, labels=True)\n", "zx.compare_tensors(g, g1, preserve_scalar=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Question 1.7\n", "\n", "Using the functions in `pyzx.basicrules`, show that 3 alternating CNOT gates is equal to a swap gate.\n", "\n", "Note: we can only apply the rules in one direction, so this proof will need to be different from the one given in Picturing Quantum Processes.\n", "\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Question 1.8\n", "\n", "Compose the circuit you made in Question 1.6 with its adjoint, and use ZX rules to prove the result is equal to the identity.\n", "\n", "\n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.8.5" } }, "nbformat": 4, "nbformat_minor": 4 }