{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Qubit mapping and routing\n", "\n", "**Download this notebook - {nb-download}`mapping_example.ipynb`**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this tutorial we will show how the problem of mapping from logical quantum circuits to physically permitted circuits is solved automatically in TKET. The basic examples require only the installation of pytket, ```pip install pytket```." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is a wide variety of different blueprints for realising quantum computers, including the well known superconducting and ion trap devices. Different devices come with different constraints, such as a limited primitive gate set for universal quantum computing. Often this limited gate set accommodates an additional constraint, that two-qubit gates can not be executed between all pairs of qubits." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In software, typically this constraint is presented as a \"connectivity\" graph where vertices connected by an edge represents pairs of physical qubits which two-qubit gates can be executed on. As programmers usually write logical quantum circuits with no sense of architecture (or may want to run their circuit on a range of hardware with different connectivity constraints), most quantum software development kits offer the means to automatically solve this constraint. One common way is to automatically add logical ```SWAP``` gates to a Circuit, changing the position of logical qubits on physical qubits until a two-qubit gate can be realised. This is an active area of research in quantum computing and a problem we discuss in our paper \"On The Qubit Routing Problem\" - arXiv:1902.08091." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In TKET this constraint is represented by the ```Architecture``` class. An Architecture object requires a coupling map to be created, a list of pairs of qubits which defines where two-qubit primitives may be executed. A coupling map can be produced naively by the integer indexing of nodes and edges in some architecture." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from pytket.architecture import Architecture\n", "from pytket.circuit import Node" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import networkx as nx\n", "from typing import List, Union, Tuple" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "def draw_graph(coupling_map: List[Union[Tuple[int, int], Tuple[Node, Node]]]):\n", " coupling_graph = nx.Graph(coupling_map)\n", " nx.draw(coupling_graph, labels={node: node for node in coupling_graph.nodes()})" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "simple_coupling_map = [(0, 1), (1, 2), (2, 3)]\n", "simple_architecture = Architecture(simple_coupling_map)\n", "draw_graph(simple_coupling_map)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively we could use the `Node` class to assign our nodes - you will see why this can be helpful later. Lets create an Architecture with an identical graph:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "node_0 = Node(\"e0\", 0)\n", "node_1 = Node(\"e1\", 1)\n", "node_2 = Node(\"e2\", 2)\n", "node_3 = Node(\"e3\", 3)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "id_coupling_map = [(node_0, node_1), (node_1, node_2), (node_2, node_3)]\n", "id_architecture = Architecture(id_coupling_map)\n", "draw_graph(id_coupling_map)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also create an ID with an arbitrary-dimensional index. Let us make a 2x2x2 cube:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "node_000 = Node(\"cube\", [0, 0, 0])\n", "node_001 = Node(\"cube\", [0, 0, 1])\n", "node_010 = Node(\"cube\", [0, 1, 0])\n", "node_011 = Node(\"cube\", [0, 1, 1])\n", "node_100 = Node(\"cube\", [1, 0, 0])\n", "node_101 = Node(\"cube\", [1, 0, 1])\n", "node_110 = Node(\"cube\", [1, 1, 0])\n", "node_111 = Node(\"cube\", [1, 1, 1])" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "cube_coupling_map = [\n", " (node_000, node_001),\n", " (node_000, node_010),\n", " (node_010, node_011),\n", " (node_001, node_011),\n", " (node_000, node_100),\n", " (node_001, node_101),\n", " (node_010, node_110),\n", " (node_011, node_111),\n", " (node_100, node_101),\n", " (node_100, node_110),\n", " (node_110, node_111),\n", " (node_101, node_111),\n", "]" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAApQAAAHzCAYAAACe1o1DAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAAoSxJREFUeJzs3XdYU2f/BvA7CTMMAUWGAlERtSrito466qh71NECTtx74ai1VdtabbW12tYO9+jPWbet2AqKCxcK+raOVgQZIiiyV3J+f9BEkQ2BA8n9uS6uq5ycnHzx5Q13nvM830ciCIIAIiIiIqJSkopdABERERFVbQyURERERFQmDJREREREVCYMlERERERUJgyURERERFQmDJREREREVCYMlERERERUJgyURERERFQmDJREREREVCYMlERERERUJgyURERERFQmDJREREREVCYMlERERERUJgyURERERFQmDJREREREVCYMlERERERUJgyURERERFQmDJREREREVCYMlERERERUJgyURERERFQmDJREREREVCYMlERERERUJgyURERERFQmDJREREREVCYMlERERERUJgyURERERFQmDJREREREVCYMlERERERUJgyURERERFQmDJREREREVCYMlERERERUJgyURERERFQmDJREREREVCYMlERERERUJgyURERERFQmDJREREREVCYMlERERERUJgZiF0BElUNKRjbC4lOQma2CkYEUiupmMDPmWwQRERWNfy2I9Nj9J0nYHRQO/7uxCH+WCuGVxyQAnG3k6NqgJrzaOqO+nYVYZRIRUSUnEQRBKPo0ItIlEc9S8cGhUAQ+iINMKoFSVfDbgPrxTq41sHJwUzjZyCuwUiIiqgoYKIn0zJ6r4fj46B1kq4RCg+TrZFIJDKQSLB/QGO+1di7HComIqKphoCTSI9/638cav3tlvs78nm6Y3rW+FioiIiJdwFXeRJWIQqFAv379tHa9gIAASCQSzddn209o5bpr/O5h79VwrVxLmwYNGqT5WZs0aSJ2OUREeoOBkkgPTJ/jC/uB82FgZZ/ruCo9GfG/bUDEN54IX/suYn5ZjIyYB8W65kdH7yDiWWqe4xkZGVi4cCEcHR1hamqKtm3b4vTp02Wq/7PPPsOAAQNgZ2cHiUSCZcuW5XvenDlzsHPnTjRs2LBMr0dERCXDQEmk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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "cube_architecture = Architecture(cube_coupling_map)\n", "draw_graph(cube_coupling_map)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To avoid that tedium though we could just use our SquareGrid Architecture:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "from pytket.architecture import SquareGrid" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "image/png": "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Q8/EHEWHq/e5NJYMg66JOYrPRaP4/B5AUQldEwvo20hg3Ou1p9apUIqYPMAWW7/drRbIFi9eDOBRe6aqQFn1SMUntUV63I0bN1Rj/HVMDw+PaoGypKQEnTt3rnVMXV1dHDp0CAsXLsTq1ashk8nQt29fbNmypcbNTkRELYUg1vaRm4galLe3NxITE2u8D7K5mvLdeZy9XgSF8tl/neRtCwCUCliOC4Kg2wZtDI0xyN4CUdP6137xfx06dAheXl64fPlyg/V7fPDgAczNzfHVV19h5syZDTKmKIooKirCzZs30bt3b0RGRmLBggUNMjYRkTbwHkqiRvTXvoNpaWk4dOgQhg0bpp2CGkn4W+7Q0xFqP7EW5beTcWv1JNw5EAk9HQHhb9UvFMbExOC9995r0Obhp06dQteuXfHRRx812JjFxcWwtLRE7969G2xMIiJt4gwlUSOytrbGhx9+CHt7e2RlZWHdunUoLy9HfHx8jb0km7MdcdkI2HP1ma8vz0uH8uGjJWtdQ1Os8n0T7/a1reWq5kkul1e7x7Nnz57VGtUTETU3DJREjcjHxwcxMTHIy8uDvr4+Bg4ciPDw8BY7M7U2Jg1fHkvVeJyFI5wx07PmBvBERNT0MFASUYPaEZeN4AOJkCvFet1TqasjQE9HQNgbkhY7M0lE1FIxUBJRg7t5twyL9l7F6fQ70NURnhosq44PceyI8LfcYWNet8cxEhFR08FASUSNJi3/Abadz0ZMagGyi8rw+C8bAY+alnv27ITJA2zh2KmdtsokIiINMVAS0XNRWi5HZlEpKuRKtNXTgZ2FcbN5Ag4RET0dAyURERERaYR9KImIiIhIIwyURERERKQRBkoiIiIi0ggDJRERERFphIGSiIiIiDTCQElEREREGmGgJCIiIiKNMFASERERkUYYKImIiIhIIwyURERERKQRBkoiIiIi0ggDJRERERFphIGSiIiIiDTCQElEREREGmGgJCIiIiKNMFASERERkUYYKImIiIhIIwyURERERKQRBkoiIiIi0ggDJRERERFphIGSiIiIiDTCQElEREREGmGgJCIiIiKNMFASERERkUYYKImIiIhIIwyURERERKQRBkoiIiIi0ggDJRERERFphIGSiIiIiDTCQElEREREGmGgJCIiIiKNMFASERERkUYYKImIiIhIIwyURERERKQRBkoiIiIi0ggDJRERERFphIGSiIiIiDTy/+D9w1VX3kO3AAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "alternative_cube_architecture = SquareGrid(2, 2, 2)\n", "draw_graph(alternative_cube_architecture.coupling)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The current range of quantum computers are commonly referred to as Noisy-Intermediate-Scale-Quantum devices i.e. NISQ devices. The impact of noise is a primary concern during compilation and incentivizes producing physically permitted circuits that have a minimal number of gates. For this reason benchmarking in this area is often completed by comparing the final number of two-qubit (or particularly SWAP gates) in compiled circuits." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "However it is important to remember that adding logical SWAP gates to minimise gate count is not the only way this constraint can be met, with large scale architecture-aware synthesis methods and fidelity aware methods amongst other approaches producing viable physically permitted circuits. It is likely that no SINGLE approach is better for all circuits, but the ability to use different approaches where best fitted will give the best results during compilation." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Producing physically valid circuits is completed via the `MappingManager` class, which aims to accommodate a wide range of approaches." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "from pytket.mapping import MappingManager" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A `MappingManager` object requires an `Architecture` object at construction." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "mapping_manager = MappingManager(id_architecture)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "All mapping is done through the `MappingManager.route_circuit` method. The `MappingManager.route_circuit` method has two arguments, the first a Circuit to be routed (which is mutated), the second a `List[RoutingMethodCircuit]` object that defines how the mapping is completed." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Later we will look at defining our own `RoutingMethodCircuit` objects, but initially lets consider one thats already available." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "from pytket.mapping import LexiLabellingMethod, LexiRouteRoutingMethod" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "lexi_label = LexiLabellingMethod()\n", "lexi_route = LexiRouteRoutingMethod(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `lexi_route` object here is of little use outside `MappingManager`. Note that it takes a lookahead parameter, which will affect the performance of the method, defining the number of two-qubit gates it considers when finding `SWAP` gates to add." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "from pytket import Circuit, OpType\n", "from pytket.circuit import display" ] }, { "cell_type": "code", "execution_count": 17, "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" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "c = (\n", " Circuit(4)\n", " .CX(0, 1)\n", " .CX(1, 2)\n", " .CX(0, 2)\n", " .CX(0, 3)\n", " .CX(2, 3)\n", " .CX(1, 3)\n", " .CX(0, 1)\n", " .measure_all()\n", ")\n", "display.render_circuit_jupyter(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also look at which logical qubits are interacting." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "from pytket.utils import Graph" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "Qubit connectivity\n", "\n", "\n", "\n", "q[0]\n", "\n", "q[0]\n", "\n", "\n", "\n", "q[1]\n", "\n", "q[1]\n", "\n", "\n", "\n", "q[0]--q[1]\n", "\n", "\n", "\n", "\n", "q[2]\n", "\n", "q[2]\n", "\n", "\n", "\n", "q[0]--q[2]\n", "\n", "\n", "\n", "\n", "q[3]\n", "\n", "q[3]\n", "\n", "\n", "\n", "q[0]--q[3]\n", "\n", "\n", "\n", "\n", "q[1]--q[2]\n", "\n", "\n", "\n", "\n", "q[1]--q[3]\n", "\n", "\n", "\n", "\n", "q[2]--q[3]\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Graph(c).get_qubit_graph()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By running the `MappingManager.route_circuit` method on our circuit `c` with the `LexiLabellingMethod` and `LexiRouteRoutingMethod` objects as an argument, qubits in `c` with some physical requirements will be relabelled and the qubit graph modified (by the addition of SWAP gates and relabelling some CX as BRIDGE gates) such that the qubit graph is isomorphic to some subgraph of the full architecture." ] }, { "cell_type": "code", "execution_count": 20, "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" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "mapping_manager.route_circuit(c, [lexi_label, lexi_route])\n", "display.render_circuit_jupyter(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The graph:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "Qubit connectivity\n", "\n", "\n", "\n", "e1[1]\n", "\n", "e1[1]\n", "\n", "\n", "\n", "e0[0]\n", "\n", "e0[0]\n", "\n", "\n", "\n", "e1[1]--e0[0]\n", "\n", "\n", "\n", "\n", "e2[2]\n", "\n", "e2[2]\n", "\n", "\n", "\n", "e1[1]--e2[2]\n", "\n", "\n", "\n", "\n", "e3[3]\n", "\n", "e3[3]\n", "\n", "\n", "\n", "e2[2]--e3[3]\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Graph(c).get_qubit_graph()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The resulting circuit may also change if we reduce the lookahead parameter." ] }, { "cell_type": "code", "execution_count": 22, "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" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "c = (\n", " Circuit(4)\n", " .CX(0, 1)\n", " .CX(1, 2)\n", " .CX(0, 2)\n", " .CX(0, 3)\n", " .CX(2, 3)\n", " .CX(1, 3)\n", " .CX(0, 1)\n", " .measure_all()\n", ")\n", "mapping_manager.route_circuit(c, [lexi_label, LexiRouteRoutingMethod(1)])\n", "display.render_circuit_jupyter(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also pass multiple `RoutingMethod` options for Routing in a ranked List. Each `RoutingMethod` option has a function for checking whether it can usefully modify a subcircuit at a stage in Routing. To choose, each method in the List is checked in order until one returns True. This will be discussed more later." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can aid the mapping procedure by relabelling qubits in advance. This can be completed using the `Placement` class." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "from pytket.placement import Placement, LinePlacement, GraphPlacement" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The default ```Placement``` assigns logical qubits to physical qubits as they are encountered during routing. ```LinePlacement``` uses a strategy described in https://arxiv.org/abs/1902.08091. ```GraphPlacement``` is described in Section 7.1 of https://arxiv.org/abs/2003.10611. Lets look at how we can use the ```LinePlacement``` class.`" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "line_placement = LinePlacement(id_architecture)" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c = (\n", " Circuit(4)\n", " .CX(0, 1)\n", " .CX(1, 2)\n", " .CX(0, 2)\n", " .CX(0, 3)\n", " .CX(2, 3)\n", " .CX(1, 3)\n", " .CX(0, 1)\n", " .measure_all()\n", ")\n", "line_placement.place(c)" ] }, { "cell_type": "code", "execution_count": 26, "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" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display.render_circuit_jupyter(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that one qubit remains unplaced in this example. `LexiRouteRoutingMethod` will dynamically assign it during mapping." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Different placements will lead to different selections of SWAP gates being added. However each different routed circuit will preserve the original unitary action of the full circuit while respecting connectivity constraints." ] }, { "cell_type": "code", "execution_count": 27, "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" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "mapping_manager.route_circuit(c, [lexi_label, lexi_route])\n", "display.render_circuit_jupyter(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The graph:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "Qubit connectivity\n", "\n", "\n", "\n", "e0[0]\n", "\n", "e0[0]\n", "\n", "\n", "\n", "e1[1]\n", "\n", "e1[1]\n", "\n", "\n", "\n", "e0[0]--e1[1]\n", "\n", "\n", "\n", "\n", "e2[2]\n", "\n", "e2[2]\n", "\n", "\n", "\n", "e0[0]--e2[2]\n", "\n", "\n", "\n", "\n", "e1[1]--e2[2]\n", "\n", "\n", "\n", "\n", "e3[3]\n", "\n", "e3[3]\n", "\n", "\n", "\n", "e2[2]--e3[3]\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Graph(c).get_qubit_graph()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "However, small changes to the depth of lookahead or the original assignment of `Architecture` `Node` can greatly affect the resulting physical circuit for the `LexiRouteRoutingMethod` method. Considering this variance, it should be possible to easily throw additional computational resources at the problem if necessary, which is something TKET is leaning towards with the ability to define custom `RoutingCircuitMethod` objects." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To define a new `RoutingMethodCircuit` method though, we first need to understand how it is used in `MappingManager` and routing. The `MappingManager.route_circuit` method treats the global problem of mapping to physical circuits as many sequential sub-problems. Consider the following problem." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [], "source": [ "from pytket import Circuit" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "from pytket.placement import place_with_map" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "Circuit\n", "\n", "\n", "cluster_q_inputs\n", "\n", "\n", "\n", "cluster_q_outputs\n", "\n", "\n", "\n", "cluster_8\n", "\n", "CX\n", "\n", "\n", "cluster_9\n", "\n", "CX\n", "\n", "\n", "cluster_10\n", "\n", "CX\n", "\n", "\n", "cluster_11\n", "\n", "CX\n", "\n", "\n", "cluster_12\n", "\n", "CX\n", "\n", "\n", "cluster_13\n", "\n", "CX\n", "\n", "\n", "cluster_14\n", "\n", "CX\n", "\n", "\n", "\n", "(0, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(8, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(0, 0)->(8, 0)\n", "\n", "\n", "\n", "\n", "\n", "(2, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(8, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(2, 0)->(8, 1)\n", "\n", "\n", "\n", "\n", "\n", "(4, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(9, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(4, 0)->(9, 1)\n", "\n", "\n", "\n", "\n", "\n", "(6, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(11, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(6, 0)->(11, 1)\n", "\n", "\n", "\n", "\n", "\n", "(1, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(3, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(5, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(7, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(10, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(8, 0)->(10, 0)\n", "\n", "\n", "\n", "\n", "\n", "(9, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(8, 1)->(9, 0)\n", "\n", "\n", "\n", "\n", "\n", "(13, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(9, 0)->(13, 0)\n", "\n", "\n", "\n", "\n", "\n", "(10, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(9, 1)->(10, 1)\n", "\n", "\n", "\n", "\n", "\n", "(11, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(10, 0)->(11, 0)\n", "\n", "\n", "\n", "\n", "\n", "(12, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(10, 1)->(12, 0)\n", "\n", "\n", "\n", "\n", "\n", "(14, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(11, 0)->(14, 0)\n", "\n", "\n", "\n", "\n", "\n", "(12, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(11, 1)->(12, 1)\n", "\n", "\n", "\n", "\n", "\n", "(12, 0)->(5, 0)\n", "\n", "\n", "\n", "\n", "\n", "(13, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(12, 1)->(13, 1)\n", "\n", "\n", "\n", "\n", "\n", "(14, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(13, 0)->(14, 1)\n", "\n", "\n", "\n", "\n", "\n", "(13, 1)->(7, 0)\n", "\n", "\n", "\n", "\n", "\n", "(14, 0)->(1, 0)\n", "\n", "\n", "\n", "\n", "\n", "(14, 1)->(3, 0)\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "circ = Circuit(4).CX(0, 1).CX(1, 2).CX(0, 2).CX(0, 3).CX(2, 3).CX(1, 3).CX(0, 1)\n", "naive_map = {\n", " circ.qubits[0]: node_0,\n", " circ.qubits[1]: node_1,\n", " circ.qubits[2]: node_2,\n", " circ.qubits[3]: node_3,\n", "}\n", "place_with_map(circ, naive_map)\n", "Graph(circ).get_DAG()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So what happens when we run the following?" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "Circuit\n", "\n", "\n", "cluster_q_inputs\n", "\n", "\n", "\n", "cluster_q_outputs\n", "\n", "\n", "\n", "cluster_8\n", "\n", "CX\n", "\n", "\n", "cluster_9\n", "\n", "CX\n", "\n", "\n", "cluster_10\n", "\n", "CX\n", "\n", "\n", "cluster_11\n", "\n", "CX\n", "\n", "\n", "cluster_12\n", "\n", "CX\n", "\n", "\n", "cluster_13\n", "\n", "CX\n", "\n", "\n", "cluster_14\n", "\n", "SWAP\n", "\n", "\n", "cluster_15\n", "\n", "SWAP\n", "\n", "\n", "cluster_16\n", "\n", "BRIDGE\n", "\n", "\n", "\n", "(0, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(8, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(0, 0)->(8, 0)\n", "\n", "\n", "\n", "\n", "\n", "(2, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(8, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(2, 0)->(8, 1)\n", "\n", "\n", "\n", "\n", "\n", "(4, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(9, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(4, 0)->(9, 1)\n", "\n", "\n", "\n", "\n", "\n", "(6, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(15, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(6, 0)->(15, 0)\n", "\n", "\n", "\n", "\n", "\n", "(1, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(3, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(5, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(7, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(14, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(8, 0)->(14, 0)\n", "\n", "\n", "\n", "\n", "\n", "(9, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(8, 1)->(9, 0)\n", "\n", "\n", "\n", "\n", "\n", "(14, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(9, 0)->(14, 1)\n", "\n", "\n", "\n", "\n", "\n", "(10, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(9, 1)->(10, 1)\n", "\n", "\n", "\n", "\n", "\n", "(10, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(11, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(10, 0)->(11, 0)\n", "\n", "\n", "\n", "\n", "\n", "(15, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(10, 1)->(15, 1)\n", "\n", "\n", "\n", "\n", "\n", "(16, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(11, 0)->(16, 1)\n", "\n", "\n", "\n", "\n", "\n", "(11, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(12, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(11, 1)->(12, 1)\n", "\n", "\n", "\n", "\n", "\n", "(12, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(12, 0)->(5, 0)\n", "\n", "\n", "\n", "\n", "\n", "(16, 2)\n", "\n", "2\n", "\n", "\n", "\n", "(12, 1)->(16, 2)\n", "\n", "\n", "\n", "\n", "\n", "(13, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(13, 0)->(1, 0)\n", "\n", "\n", "\n", "\n", "\n", "(13, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(13, 1)->(3, 0)\n", "\n", "\n", "\n", "\n", "\n", "(16, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(14, 0)->(16, 0)\n", "\n", "\n", "\n", "\n", "\n", "(14, 1)->(10, 0)\n", "\n", "\n", "\n", "\n", "\n", "(15, 0)->(12, 0)\n", "\n", "\n", "\n", "\n", "\n", "(15, 1)->(11, 1)\n", "\n", "\n", "\n", "\n", "\n", "(16, 0)->(13, 1)\n", "\n", "\n", "\n", "\n", "\n", "(16, 1)->(13, 0)\n", "\n", "\n", "\n", "\n", "\n", "(16, 2)->(7, 0)\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mapping_manager.route_circuit(circ, [lexi_route])\n", "Graph(circ).get_DAG()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sequential mapping typically works by partitioning the circuit into two, a first partition comprising a connected subcircuit that is physically permitted, a second partition that is not. Therefore, the first thing `MappingManager.route_circuit` does is find this partition for the passed circuit, by iterating through gates in the circuit." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will construct the partitions ourselves for illustrative purposes. Lets assume we are routing for the four qubit line architecture (qubits are connected to adjacent indices) \"simple_architecture\" we constructed earlier." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "Circuit\n", "\n", "\n", "cluster_q_inputs\n", "\n", "\n", "\n", "cluster_q_outputs\n", "\n", "\n", "\n", "cluster_8\n", "\n", "CX\n", "\n", "\n", "cluster_9\n", "\n", "CX\n", "\n", "\n", "\n", "(0, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(8, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(0, 0)->(8, 0)\n", "\n", "\n", "\n", "\n", "\n", "(2, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(8, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(2, 0)->(8, 1)\n", "\n", "\n", "\n", "\n", "\n", "(4, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(9, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(4, 0)->(9, 1)\n", "\n", "\n", "\n", "\n", "\n", "(6, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(7, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(6, 0)->(7, 0)\n", "\n", "\n", "\n", "\n", "\n", "(1, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(3, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(5, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(8, 0)->(1, 0)\n", "\n", "\n", "\n", "\n", "\n", "(9, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(8, 1)->(9, 0)\n", "\n", "\n", "\n", "\n", "\n", "(9, 0)->(3, 0)\n", "\n", "\n", "\n", "\n", "\n", "(9, 1)->(5, 0)\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "circ_first_partition = Circuit(4).CX(0, 1).CX(1, 2)\n", "place_with_map(circ_first_partition, naive_map)\n", "Graph(circ_first_partition).get_DAG()" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "Circuit\n", "\n", "\n", "cluster_q_inputs\n", "\n", "\n", "\n", "cluster_q_outputs\n", "\n", "\n", "\n", "cluster_8\n", "\n", "CX\n", "\n", "\n", "cluster_9\n", "\n", "CX\n", "\n", "\n", "cluster_10\n", "\n", "CX\n", "\n", "\n", "cluster_11\n", "\n", "CX\n", "\n", "\n", "cluster_12\n", "\n", "CX\n", "\n", "\n", "\n", "(0, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(8, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(0, 0)->(8, 0)\n", "\n", "\n", "\n", "\n", "\n", "(2, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(11, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(2, 0)->(11, 0)\n", "\n", "\n", "\n", "\n", "\n", "(4, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(8, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(4, 0)->(8, 1)\n", "\n", "\n", "\n", "\n", "\n", "(6, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(9, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(6, 0)->(9, 1)\n", "\n", "\n", "\n", "\n", "\n", "(1, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(3, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(5, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(7, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(9, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(8, 0)->(9, 0)\n", "\n", "\n", "\n", "\n", "\n", "(10, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(8, 1)->(10, 0)\n", "\n", "\n", "\n", "\n", "\n", "(12, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(9, 0)->(12, 0)\n", "\n", "\n", "\n", "\n", "\n", "(10, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(9, 1)->(10, 1)\n", "\n", "\n", "\n", "\n", "\n", "(10, 0)->(5, 0)\n", "\n", "\n", "\n", "\n", "\n", "(11, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(10, 1)->(11, 1)\n", "\n", "\n", "\n", "\n", "\n", "(12, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(11, 0)->(12, 1)\n", "\n", "\n", "\n", "\n", "\n", "(11, 1)->(7, 0)\n", "\n", "\n", "\n", "\n", "\n", "(12, 0)->(1, 0)\n", "\n", "\n", "\n", "\n", "\n", "(12, 1)->(3, 0)\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "circ_second_partition = Circuit(4).CX(0, 2).CX(0, 3).CX(2, 3).CX(1, 3).CX(0, 1)\n", "place_with_map(circ_second_partition, naive_map)\n", "Graph(circ_second_partition).get_DAG()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that there are gates in the second partition that would be physically permitted, if they were not dependent on other gates that are not." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The next step is to modify the second partition circuit to move it closer being physically permitted. Here the `LexiRouteRoutingMethod` as before will either insert a SWAP gate at the start of the partition, or will substitute a CX gate in the first slice of the partition with a BRIDGE gate." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The option taken by `LexiRouteRoutingethod(1)` is to insert a SWAP gate between the first two nodes of the architecture, swapping their logical states. How does this change the second partition circuit?" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "Circuit\n", "\n", "\n", "cluster_q_inputs\n", "\n", "\n", "\n", "cluster_q_outputs\n", "\n", "\n", "\n", "cluster_8\n", "\n", "SWAP\n", "\n", "\n", "cluster_9\n", "\n", "CX\n", "\n", "\n", "cluster_10\n", "\n", "CX\n", "\n", "\n", "cluster_11\n", "\n", "CX\n", "\n", "\n", "cluster_12\n", "\n", "CX\n", "\n", "\n", "cluster_13\n", "\n", "CX\n", "\n", "\n", "\n", "(0, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(8, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(0, 0)->(8, 0)\n", "\n", "\n", "\n", "\n", "\n", "(2, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(8, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(2, 0)->(8, 1)\n", "\n", "\n", "\n", "\n", "\n", "(4, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(9, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(4, 0)->(9, 1)\n", "\n", "\n", "\n", "\n", "\n", "(6, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(10, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(6, 0)->(10, 1)\n", "\n", "\n", "\n", "\n", "\n", "(1, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(3, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(5, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(7, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(12, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(8, 0)->(12, 0)\n", "\n", "\n", "\n", "\n", "\n", "(9, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(8, 1)->(9, 0)\n", "\n", "\n", "\n", "\n", "\n", "(10, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(9, 0)->(10, 0)\n", "\n", "\n", "\n", "\n", "\n", "(11, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(9, 1)->(11, 0)\n", "\n", "\n", "\n", "\n", "\n", "(13, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(10, 0)->(13, 0)\n", "\n", "\n", "\n", "\n", "\n", "(11, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(10, 1)->(11, 1)\n", "\n", "\n", "\n", "\n", "\n", "(11, 0)->(5, 0)\n", "\n", "\n", "\n", "\n", "\n", "(12, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(11, 1)->(12, 1)\n", "\n", "\n", "\n", "\n", "\n", "(13, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(12, 0)->(13, 1)\n", "\n", "\n", "\n", "\n", "\n", "(12, 1)->(7, 0)\n", "\n", "\n", "\n", "\n", "\n", "(13, 0)->(3, 0)\n", "\n", "\n", "\n", "\n", "\n", "(13, 1)->(1, 0)\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "circ_second_partition = (\n", " Circuit(4).SWAP(0, 1).CX(1, 2).CX(1, 3).CX(2, 3).CX(0, 3).CX(1, 0)\n", ")\n", "place_with_map(circ_second_partition, naive_map)\n", "Graph(circ_second_partition).get_DAG()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Leaving the full circuit as:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "Circuit\n", "\n", "\n", "cluster_q_inputs\n", "\n", "\n", "\n", "cluster_q_outputs\n", "\n", "\n", "\n", "cluster_8\n", "\n", "CX\n", "\n", "\n", "cluster_9\n", "\n", "CX\n", "\n", "\n", "cluster_10\n", "\n", "SWAP\n", "\n", "\n", "cluster_11\n", "\n", "CX\n", "\n", "\n", "cluster_12\n", "\n", "CX\n", "\n", "\n", "cluster_13\n", "\n", "CX\n", "\n", "\n", "cluster_14\n", "\n", "CX\n", "\n", "\n", "cluster_15\n", "\n", "CX\n", "\n", "\n", "\n", "(0, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(8, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(0, 0)->(8, 0)\n", "\n", "\n", "\n", "\n", "\n", "(2, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(8, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(2, 0)->(8, 1)\n", "\n", "\n", "\n", "\n", "\n", "(4, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(9, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(4, 0)->(9, 1)\n", "\n", "\n", "\n", "\n", "\n", "(6, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(12, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(6, 0)->(12, 1)\n", "\n", "\n", "\n", "\n", "\n", "(1, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(3, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(5, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(7, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(10, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(8, 0)->(10, 0)\n", "\n", "\n", "\n", "\n", "\n", "(9, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(8, 1)->(9, 0)\n", "\n", "\n", "\n", "\n", "\n", "(10, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(9, 0)->(10, 1)\n", "\n", "\n", "\n", "\n", "\n", "(11, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(9, 1)->(11, 1)\n", "\n", "\n", "\n", "\n", "\n", "(14, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(10, 0)->(14, 0)\n", "\n", "\n", "\n", "\n", "\n", "(11, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(10, 1)->(11, 0)\n", "\n", "\n", "\n", "\n", "\n", "(12, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(11, 0)->(12, 0)\n", "\n", "\n", "\n", "\n", "\n", "(13, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(11, 1)->(13, 0)\n", "\n", "\n", "\n", "\n", "\n", "(15, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(12, 0)->(15, 0)\n", "\n", "\n", "\n", "\n", "\n", "(13, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(12, 1)->(13, 1)\n", "\n", "\n", "\n", "\n", "\n", "(13, 0)->(5, 0)\n", "\n", "\n", "\n", "\n", "\n", "(14, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(13, 1)->(14, 1)\n", "\n", "\n", "\n", "\n", "\n", "(15, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(14, 0)->(15, 1)\n", "\n", "\n", "\n", "\n", "\n", "(14, 1)->(7, 0)\n", "\n", "\n", "\n", "\n", "\n", "(15, 0)->(3, 0)\n", "\n", "\n", "\n", "\n", "\n", "(15, 1)->(1, 0)\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "full_circuit = (\n", " Circuit(4).CX(0, 1).CX(1, 2).SWAP(0, 1).CX(1, 2).CX(1, 3).CX(2, 3).CX(0, 3).CX(1, 0)\n", ")\n", "place_with_map(full_circuit, naive_map)\n", "Graph(full_circuit).get_DAG()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "After a modification is made the partition is updated." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The first partition:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "Circuit\n", "\n", "\n", "cluster_q_inputs\n", "\n", "\n", "\n", "cluster_q_outputs\n", "\n", "\n", "\n", "cluster_8\n", "\n", "CX\n", "\n", "\n", "cluster_9\n", "\n", "CX\n", "\n", "\n", "cluster_10\n", "\n", "SWAP\n", "\n", "\n", "cluster_11\n", "\n", "CX\n", "\n", "\n", "\n", "(0, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(8, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(0, 0)->(8, 0)\n", "\n", "\n", "\n", "\n", "\n", "(2, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(8, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(2, 0)->(8, 1)\n", "\n", "\n", "\n", "\n", "\n", "(4, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(9, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(4, 0)->(9, 1)\n", "\n", "\n", "\n", "\n", "\n", "(6, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(7, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(6, 0)->(7, 0)\n", "\n", "\n", "\n", "\n", "\n", "(1, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(3, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(5, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(10, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(8, 0)->(10, 0)\n", "\n", "\n", "\n", "\n", "\n", "(9, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(8, 1)->(9, 0)\n", "\n", "\n", "\n", "\n", "\n", "(10, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(9, 0)->(10, 1)\n", "\n", "\n", "\n", "\n", "\n", "(11, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(9, 1)->(11, 1)\n", "\n", "\n", "\n", "\n", "\n", "(10, 0)->(1, 0)\n", "\n", "\n", "\n", "\n", "\n", "(11, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(10, 1)->(11, 0)\n", "\n", "\n", "\n", "\n", "\n", "(11, 0)->(3, 0)\n", "\n", "\n", "\n", "\n", "\n", "(11, 1)->(5, 0)\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "circ_first_partition = Circuit(4).CX(0, 1).CX(1, 2).SWAP(0, 1).CX(1, 2)\n", "place_with_map(circ_first_partition, naive_map)\n", "Graph(circ_first_partition).get_DAG()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The second partition:" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "Circuit\n", "\n", "\n", "cluster_q_inputs\n", "\n", "\n", "\n", "cluster_q_outputs\n", "\n", "\n", "\n", "cluster_8\n", "\n", "CX\n", "\n", "\n", "cluster_9\n", "\n", "CX\n", "\n", "\n", "cluster_10\n", "\n", "CX\n", "\n", "\n", "cluster_11\n", "\n", "CX\n", "\n", "\n", "\n", "(0, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(10, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(0, 0)->(10, 0)\n", "\n", "\n", "\n", "\n", "\n", "(2, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(8, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(2, 0)->(8, 0)\n", "\n", "\n", "\n", "\n", "\n", "(4, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(9, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(4, 0)->(9, 0)\n", "\n", "\n", "\n", "\n", "\n", "(6, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(8, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(6, 0)->(8, 1)\n", "\n", "\n", "\n", "\n", "\n", "(1, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(3, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(5, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(7, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(11, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(8, 0)->(11, 0)\n", "\n", "\n", "\n", "\n", "\n", "(9, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(8, 1)->(9, 1)\n", "\n", "\n", "\n", "\n", "\n", "(9, 0)->(5, 0)\n", "\n", "\n", "\n", "\n", "\n", "(10, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(9, 1)->(10, 1)\n", "\n", "\n", "\n", "\n", "\n", "(11, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(10, 0)->(11, 1)\n", "\n", "\n", "\n", "\n", "\n", "(10, 1)->(7, 0)\n", "\n", "\n", "\n", "\n", "\n", "(11, 0)->(3, 0)\n", "\n", "\n", "\n", "\n", "\n", "(11, 1)->(1, 0)\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "circ_second_partition = Circuit(4).CX(1, 3).CX(2, 3).CX(0, 3).CX(1, 0)\n", "place_with_map(circ_second_partition, naive_map)\n", "Graph(circ_second_partition).get_DAG()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This pattern of modification and updating the partition is repeated until the partition has reached the end of the circuit, i.e. the back side of the partition has no gates in it. Also note that the process of updating the partition has been simplified for this example with \"physically permitted\" encapsulating two-qubit gate constraints only - in the future we expect other arity gates to provide constraints that need to be met. Also note that any modification to the second circuit can willfully modify the qubit labelling and a token swapping network will be automatically added to conform to the new labelling." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We now enough about how `MappingManager` works to add our own `RoutingMethodCircuit`. While `LexiRouteRoutingMethod` is implemented in c++ TKET, giving it some advantages, via lambda functions we can define our own `RoutingMethodCircuit` in python." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A python defined `RoutingMethodCircuit` requires three arguments. The first is a function that given a Circuit (the circuit after the partition) and an Architecture, returns a bool (determining whether the new circuit should be substituted in a full routing process), a new Circuit (a modification of the original circuit such as an added SWAP) a Dict between qubits reflecting any relabelling done in the method, and a Dict between qubits giving any implicit permutation of qubits (such as by adding a SWAP). For some clarity (we will write an example later), lets look at an example function declaration." ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [], "source": [ "from typing import Dict" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [], "source": [ "def route_subcircuit_func(\n", " circuit: Circuit, architecture: Architecture\n", ") -> Tuple[bool, Circuit, Dict[Node, Node], Dict[Node, Node]]:\n", " return ()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The first return is a bool which detemrines if a given `RoutingMethodCircuit` is suitable for providing a solution at a given partition. `MappingManager.route_circuit` accepts a List of of `RoutingMethod` defining how solutions are found. At the point the partition circuit is modified, the circuit is passed to `RoutingMethodCircuit.routing_method` which additionally to finding a subcircuit substitution, should determine whether it can or can't helpfully modify the partition boundary circuit, and return True if it can. The first `RoutingMethodCircuit` to return True is then used for modification - meaning the ordering of List elements is important." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The third argument sets the maximum number of gates given in the passed Circuit and the fourth argument sets the maximum depth in the passed Circuit." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`LexiRouteRoutingMethod` will always return True, because it can always find some helpful SWAP to insert, and it can dynamically assign logical to physical qubits. Given this, lets construct a more specialised modification - an architecture-aware decomposition of a distance-2 CRy gate. Lets write our function type declarations for each method:" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [], "source": [ "def distance2_CRy_decomp(\n", " circuit: Circuit, architecture: Architecture\n", ") -> Tuple[bool, Circuit, Dict[Node, Node], Dict[Node, Node]]:\n", " return (False, Circuit(), {}, {})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Where do we start? Lets define a simple scope for our solution: for a single gate in the passed circuit (the circuit after the partition) that has OpType CRy, if the two qubits it's acting on are at distance 2 on the architecture, decompose the gate using BRIDGE gates." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The first restriction is to only have a single gate from the first slice - we can achieve this by setting both the maximum depth and size parameters to 1." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The second restriction is for the gate to have OpType CRy and for the qubits to be at distance 2 - we can check this restriction in a `distance2_CRy_check` method." ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [], "source": [ "def distance2_CRy_check(circuit: Circuit, architecture: Architecture) -> bool:\n", " if circuit.n_gates != 1:\n", " raise ValueError(\n", " \"Circuit for CRy check should only have 1 gate, please change parameters of method declaration.\"\n", " )\n", " command = circuit.get_commands()[0]\n", " if command.op.type == OpType.CRy:\n", " # Architecture stores qubits under `Node` identifier\n", " n0 = Node(command.qubits[0].reg_name, command.qubits[0].index)\n", " n1 = Node(command.qubits[1].reg_name, command.qubits[1].index)\n", " # qubits could not be placed in circuit, so check before finding distance\n", " if n0 in architecture.nodes and n1 in architecture.nodes:\n", " # means we can run the decomposition\n", " if architecture.get_distance(n0, n1) == 2:\n", " return True\n", " return False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `distance2_CRy_check` confirms whether the required restrictions are respected. Given this, if the `distance2_CRy_decomp` method is called we know where to add the decomposition." ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [], "source": [ "def distance2_CRy_decomp(\n", " circuit: Circuit, architecture: Architecture\n", ") -> Tuple[bool, Circuit, Dict[Node, Node], Dict[Node, Node]]:\n", " worthwhile_substitution = distance2_CRy_check(circuit, architecture)\n", " if worthwhile_substitution == False:\n", " return (False, Circuit(), {}, {})\n", " command = circuit.get_commands()[0]\n", " qubits = command.qubits\n", " # Architecture stores qubits under `Node` identifier\n", " n0 = Node(qubits[0].reg_name, qubits[0].index)\n", " n1 = Node(qubits[1].reg_name, qubits[1].index)\n", "\n", " # need to find connecting node for decomposition\n", " adjacent_nodes_0 = architecture.get_adjacent_nodes(n0)\n", " adjacent_nodes_1 = architecture.get_adjacent_nodes(n1)\n", " connecting_nodes = adjacent_nodes_0.intersection(adjacent_nodes_1)\n", " if len(connecting_nodes) == 0:\n", " raise ValueError(\"Qubits for distance-2 CRy decomp are not at distance 2.\")\n", " connecting_node = connecting_nodes.pop()\n", " c = Circuit()\n", "\n", " # the \"relabelling map\" empty, and the permutation map is qubit to qubit, so add here\n", " permutation_map = dict()\n", " for q in circuit.qubits:\n", " permutation_map[q] = q\n", " c.add_qubit(q)\n", " # rotation, can assume only parameter as CRy\n", " angle = command.op.params[0]\n", " c.Ry(angle, qubits[1])\n", " # distance-2 CX decomp\n", " c.CX(qubits[0], connecting_node).CX(connecting_node, qubits[1])\n", " c.CX(qubits[0], connecting_node).CX(connecting_node, qubits[1])\n", " # rotation\n", " c.Ry(-1 * angle, qubits[1])\n", " # distance-2 CX decomp\n", " c.CX(qubits[0], connecting_node).CX(connecting_node, qubits[1])\n", " c.CX(qubits[0], connecting_node).CX(connecting_node, qubits[1])\n", "\n", " # the \"relabelling map\" is just qubit to qubit\n", " return (True, c, {}, permutation_map)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Before turning this into a `RoutingMethod` we can try it ourselves." ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "Circuit\n", "\n", "\n", "cluster_q_inputs\n", "\n", "\n", "\n", "cluster_q_outputs\n", "\n", "\n", "\n", "cluster_8\n", "\n", "CRy(0.6)\n", "\n", "\n", "\n", "(0, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(8, 0)\n", "\n", "0\n", "\n", "\n", "\n", "(0, 0)->(8, 0)\n", "\n", "\n", "\n", "\n", "\n", "(2, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(3, 0)\n", "\n", "e1[1]\n", "\n", "\n", "\n", "(2, 0)->(3, 0)\n", "\n", "\n", "\n", "\n", "\n", "(4, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(8, 1)\n", "\n", "1\n", "\n", "\n", "\n", "(4, 0)->(8, 1)\n", "\n", "\n", "\n", "\n", "\n", "(6, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(7, 0)\n", "\n", "e3[3]\n", "\n", "\n", "\n", "(6, 0)->(7, 0)\n", "\n", "\n", "\n", "\n", "\n", "(1, 0)\n", "\n", "e0[0]\n", "\n", "\n", "\n", "(5, 0)\n", "\n", "e2[2]\n", "\n", "\n", "\n", "(8, 0)->(1, 0)\n", "\n", "\n", "\n", "\n", "\n", "(8, 1)->(5, 0)\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "test_c = Circuit(4)\n", "test_c.CRy(0.6, 0, 2)\n", "place_with_map(test_c, naive_map)\n", "Graph(test_c).get_DAG()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we can see, our circuit has one CRy gate at distance two away." ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n" ] } ], "source": [ "print(distance2_CRy_check(test_c, id_architecture))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Our method returns True, as expected! We should also test cases where it returns errors or False." ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n" ] } ], "source": [ "test_c_false = Circuit(4)\n", "test_c_false.CRy(0.4, 0, 1)\n", "place_with_map(test_c_false, naive_map)\n", "print(distance2_CRy_check(test_c_false, id_architecture))" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Error reached!\n" ] } ], "source": [ "test_c_error = Circuit(4)\n", "test_c_error.CRy(0.6, 0, 2)\n", "test_c_error.CRy(0.4, 0, 1)\n", "place_with_map(test_c_error, naive_map)\n", "try:\n", " distance2_CRy_check(test_c_error, id_architecture)\n", "except ValueError:\n", " print(\"Error reached!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Does the decomposition work?" ] }, { "cell_type": "code", "execution_count": 48, "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" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "test_c = Circuit(4)\n", "test_c.CRy(0.6, 0, 2)\n", "place_with_map(test_c, naive_map)\n", "decomp = distance2_CRy_decomp(test_c, id_architecture)\n", "display.render_circuit_jupyter(decomp[1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Great! Our check function and decomposition method are both working. Lets wrap them into a `RoutingMethodCircuit` and try them out." ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [], "source": [ "from pytket.mapping import RoutingMethodCircuit" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [], "source": [ "cry_rmc = RoutingMethodCircuit(distance2_CRy_decomp, 1, 1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use our original `MappingManager` object as it is defined for the same architecture. Lets try it out on a range of circumstances." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we pass it a full CX circuit without `LexiRouteRoutingMethod`, we should find that `MappingManager` throws an error, as none of the passed methods can route for the given circuit." ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Error reached!\n" ] } ], "source": [ "c = (\n", " Circuit(4)\n", " .CX(0, 1)\n", " .CX(1, 2)\n", " .CX(0, 2)\n", " .CX(0, 3)\n", " .CX(2, 3)\n", " .CX(1, 3)\n", " .CX(0, 1)\n", " .measure_all()\n", ")\n", "place_with_map(c, naive_map)\n", "try:\n", " mapping_manager.route_circuit(c, [cry_rmc])\n", "except RuntimeError:\n", " print(\"Error reached!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, we can add `LexiRouteRoutingMethod` on top:" ] }, { "cell_type": "code", "execution_count": 52, "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" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "c = (\n", " Circuit(4)\n", " .CX(0, 1)\n", " .CX(1, 2)\n", " .CX(0, 2)\n", " .CX(0, 3)\n", " .CX(2, 3)\n", " .CX(1, 3)\n", " .CX(0, 1)\n", " .measure_all()\n", ")\n", "place_with_map(c, naive_map)\n", "mapping_manager.route_circuit(c, [cry_rmc, LexiRouteRoutingMethod(10)])\n", "display.render_circuit_jupyter(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "However as there are no CRy gates our new method is unused. We can add one:" ] }, { "cell_type": "code", "execution_count": 53, "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" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "c = (\n", " Circuit(4)\n", " .CRy(0.6, 0, 2)\n", " .CX(0, 1)\n", " .CX(1, 2)\n", " .CX(0, 2)\n", " .CX(0, 3)\n", " .CX(2, 3)\n", " .CX(1, 3)\n", " .CX(0, 1)\n", " .measure_all()\n", ")\n", "mapping_manager.route_circuit(c, [lexi_label, cry_rmc, LexiRouteRoutingMethod(10)])\n", "display.render_circuit_jupyter(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This time we can see our decomposition! If we reorder the methods though `LexiRouteRoutingMethod` is checked first (and returns True), so our new method is unused. The order is important!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, lets see what happens if the gate is not at the right distance initially." ] }, { "cell_type": "code", "execution_count": 54, "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" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "c = (\n", " Circuit(4)\n", " .CRy(0.6, 0, 3)\n", " .CX(0, 1)\n", " .CX(1, 2)\n", " .CX(0, 2)\n", " .CX(0, 3)\n", " .CX(2, 3)\n", " .CX(1, 3)\n", " .CX(0, 1)\n", " .measure_all()\n", ")\n", "mapping_manager.route_circuit(c, [lexi_label, cry_rmc, LexiRouteRoutingMethod(10)])\n", "display.render_circuit_jupyter(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Above a SWAP gate is inserted by `LexiRouteRoutingMethod` before anything else." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For anyone interested, a simple extension exercise could be to extend this to additionally work for distance-2 CRx and CRz. Alternatively one could improve on the method itself - this approach always decomposes a CRy at distance-2, but is this a good idea?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Also note that higher performance solutions are coded straight into the TKET c++ codebase. This provides advantages, including that Circuit construction and substitution is unnecessary (as with python) as the circuit can be directly modified, however the ability to produce prototypes at the python level is very helpful. If you have a great python implementation but are finding some runtime bottlenecks, why not try implementing it straight into TKET (the code is open source at https://github.com/Quantinuum/tket)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Besides the `LexiRouteRoutingMethod()` and the `LexiLabellingMethod()` there are other routing methods in pytket, such as the `AASRouteRoutingMethod()` and the corresponding `AASLabellingMethod()`, which are used to route phase-polynomial boxes using architecture-aware synthesis. Usually circuits contain non-phase-polynomial operations as well, so it is a good idea to combine them with the `LexiRouteRoutingMethod()`, as in the following example:" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [], "source": [ "from pytket.mapping import AASRouteRoutingMethod, AASLabellingMethod\n", "from pytket.circuit import PhasePolyBox, Qubit\n", "import numpy as np" ] }, { "cell_type": "code", "execution_count": 56, "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" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "\n", "\n", "\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": [ "c = Circuit(3, 3)\n", "n_qb = 3\n", "qubit_indices = {Qubit(0): 0, Qubit(1): 1, Qubit(2): 2}\n", "phase_polynomial = {(True, False, True): 0.333, (False, False, True): 0.05}\n", "linear_transformation = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])\n", "p_box = PhasePolyBox(n_qb, qubit_indices, phase_polynomial, linear_transformation)\n", "c.add_phasepolybox(p_box, [0, 1, 2])\n", "c.CX(0, 1).CX(0, 2).CX(1, 2)\n", "display.render_circuit_jupyter(c)\n", "nodes = [Node(\"test\", 0), Node(\"test\", 1), Node(\"test\", 2)]\n", "arch = Architecture([[nodes[0], nodes[1]], [nodes[1], nodes[2]]])\n", "mm = MappingManager(arch)\n", "mm.route_circuit(\n", " c,\n", " [\n", " AASRouteRoutingMethod(1),\n", " LexiLabellingMethod(),\n", " LexiRouteRoutingMethod(),\n", " AASLabellingMethod(),\n", " ],\n", ")\n", "display.render_circuit_jupyter(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this case the order of the methods is not very relevant, because in each step of the routing only one of the methods is suitable. In the first part of the circuit the mapping is done without inserting swaps by the AAS method; in the second part one swap gate is added to the circuit." ] } ], "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.11.2" } }, "nbformat": 4, "nbformat_minor": 2 }