{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "# Qubit Mapping\n", "\n", "[![Download Notebook](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/r2.7.0rc1/resource/_static/logo_notebook_en.svg)](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/r2.7.0rc1/mindquantum/en/middle_level/mindspore_qubit_mapping.ipynb) \n", "[![Download Code](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/r2.7.0rc1/resource/_static/logo_download_code_en.svg)](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/r2.7.0rc1/mindquantum/en/middle_level/mindspore_qubit_mapping.py) \n", "[![View Source On Gitee](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/r2.7.0rc1/resource/_static/logo_source_en.svg)](https://gitee.com/mindspore/docs/blob/r2.7.0rc1/docs/mindquantum/docs/source_en/middle_level/qubit_mapping.ipynb)\n", "\n", "When designing quantum circuits, users often design them based on their algorithmic requirements. However, current quantum chips often struggle to achieve coupling between all qubits. Therefore, when executing quantum circuits on quantum computing hardware, we need to rearrange the qubits used in the quantum algorithm or add some [SWAP](https://www.mindspore.cn/mindquantum/docs/en/r0.11/core/gates/mindquantum.core.gates.SWAPGate.html) gates to coupe qubits that were originally uncoupled. This is known as qubit mapping algorithm.\n", "\n", "In this tutorial, we will first introduce the qubit node object [QubitNode](https://mindspore.cn/mindquantum/docs/en/r0.11/device/mindquantum.device.QubitNode.html) and qubit topology object [QubitsTopology](https://mindspore.cn/mindquantum/docs/en/r0.11/device/mindquantum.device.QubitsTopology.html). Then, we will explain how to compile quantum circuits using the qubit mapping algorithm.\n", "\n", "## Qubit Node\n", "\n", "[QubitNode](https://mindspore.cn/mindquantum/docs/en/r0.11/device/mindquantum.device.QubitNode.html) represents the qubit in quantum chip. Currently, it has four properties:\n", "\n", "- qubit_id: The unique id of quantum qubit.\n", "- color: The face color when drawing qubit, default value is #000000.\n", "- poi_x: The x position when drawing qubit, default value is 0.0\n", "- poi_y: The y position when drawing qubit, default value is 0.0\n", "\n", "Here, we are going to initialize a qubit node:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "qubit id: 0, with color: #121212, and position (0, 0)\n" ] } ], "source": [ "from mindquantum.device import QubitNode\n", "\n", "q0 = QubitNode(0, '#121212', 0, 0)\n", "\n", "print(f\"qubit id: {q0.qubit_id}, with color: {q0.color}, and position ({q0.poi_x}, {q0.poi_y})\")" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "QubitNode can be connected by operator `>>` or `<<`. Also you can disconnect them by `>` or `<`. The different operator for connecting or disconnecting will return different QubitNode.\n", "\n", "|lhs|op|rhs|Effect|Return|\n", "| --|--|-- |-- |--|\n", "|q0 |`>>`|q1 |Connect tow qubits|q1|\n", "|q0 |`<<`|q1 |Connect tow qubits|q0|\n", "|q0 |`>`|q1 |Disconnect tow qubits|q1|\n", "|q0 |`<`|q1 |Disconnect tow qubits|q0|\n", "\n", "Based on the operation we defined above, we can quickly connect qubits like this:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q0, q1, q2 = QubitNode(0), QubitNode(1), QubitNode(2)\n", "\n", "q0 >> q1 >> q2" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "In the above code, `q0 >> q1` will connect the bits `q0` and `q1`, and return the bit `q1`, and then through `>> q2` you can connect `q1` and `q2`." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### QubitsTopology\n", "\n", "The [QubitsTopology](https://mindspore.cn/mindquantum/docs/en/r0.11/device/mindquantum.device.QubitsTopology.html) class is a container for qubits, which can effectively organize and manipulate them. For example, when we want to build a one-dimensional chain of qubits, we can do the following:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "from mindquantum.device import QubitsTopology, QubitNode\n", "\n", "n = 5\n", "\n", "topology = QubitsTopology([QubitNode(i, poi_x=i) for i in range(n)])\n", "print(topology)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "MindQuantum also provides a method to show the topology:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "0 1 2 3 4 " ], "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from mindquantum.io.display import draw_topology\n", "\n", "draw_topology(topology)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "From above, we successfully generate 5 qubits, but not connected them yet. Now we are going to connect them:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "0 1 2 3 4 " ], "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "left_node = topology[0]\n", "for i in range(1, n):\n", " left_node = left_node << topology[i]\n", "\n", "draw_topology(topology)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "In above code, we get the qubit with its qubit_id with operation `[]`, and connect then with operation `<<`.\n", "\n", "In MindQuantum, we already designed some qubit topology, such as [LinearQubits](https://mindspore.cn/mindquantum/docs/en/r0.11/device/mindquantum.device.LinearQubits.html) and [GradQubits](https://mindspore.cn/mindquantum/docs/en/r0.11/device/mindquantum.device.GridQubits.html#mindquantum.device.GridQubits):" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "0 1 2 " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/svg+xml": [ "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from mindquantum.device import LinearQubits, GridQubits\n", "from IPython.display import display_svg\n", "\n", "t1 = LinearQubits(3)\n", "t2 = GridQubits(4, 5)\n", "\n", "display_svg(draw_topology(t1))\n", "display_svg(draw_topology(t2))" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "We can also perform more operations on qubit topology, such as delete som qubit node:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "0 1 2 3 4 5 7 8 9 10 11 12 13 14 15 16 17 18 19 " ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t2.remove_qubit_node(6)\n", "\n", "draw_topology(t2)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "isolate some qubit node:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "0 1 2 3 4 5 7 8 9 10 11 12 13 14 15 16 17 18 19 " ], "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t2.isolate_with_near(13)\n", "\n", "draw_topology(t2)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "change the color of some qubit note:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "0 1 2 3 4 5 7 8 9 10 11 12 13 14 15 16 17 18 19 " ], "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t2.set_color(7, '#ff0000')\n", "\n", "draw_topology(t2)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "change the position of some qubit node:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "0 1 2 3 4 5 7 8 9 10 11 12 13 14 15 16 17 18 19 " ], "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t2.set_position(4, 5.0, 0.5)\n", "\n", "draw_topology(t2)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "or re-coupling with other qubit node:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "0 1 2 3 4 5 7 8 9 10 11 12 13 14 15 16 17 18 19 " ], "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t2[4] << t2[14]\n", "\n", "draw_topology(t2)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "We can also get all coupled edges of the qubit topology:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{(0, 1),\n", " (0, 5),\n", " (1, 2),\n", " (2, 3),\n", " (2, 7),\n", " (3, 4),\n", " (3, 8),\n", " (4, 9),\n", " (4, 14),\n", " (5, 10),\n", " (7, 8),\n", " (7, 12),\n", " (8, 9),\n", " (9, 14),\n", " (10, 11),\n", " (10, 15),\n", " (11, 12),\n", " (11, 16),\n", " (12, 17),\n", " (14, 19),\n", " (15, 16),\n", " (16, 17),\n", " (17, 18),\n", " (18, 19)}" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t2.edges_with_id()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Qubit Mapping\n", "\n", "When we run quantum circuits on real quantum hardware, we often cannot run them directly, because the qubit topology in the real hardware and the quantum circuit structure given by the user may not match. Then qubit mapping technology comes in. We can remap the quantum bits or insert some [SWAP](https://mindspore.cn/mindquantum/docs/en/r0.11/core/mindquantum.core.gates.html#pre-instantiated-gate) gates to make the circuit run successfully.\n", "\n", "We give a quantum circuit:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: q1: q2: RX a RX b RX c " ], "text/plain": [ "" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from mindquantum.core.circuit import Circuit\n", "\n", "circ = Circuit().rx('a', 0).rx('b', 1).rx('c', 2).x(1, 0).x(2, 1).x(0, 2)\n", "circ.svg()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "following a 2x2 grid qubit topology:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "0 1 2 3 " ], "text/plain": [ "" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t = GridQubits(2, 2)\n", "\n", "draw_topology(t)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Because the qubits in the above quantum circuit have interactions with each other, it cannot be directly run on the above quantum hardware. We introduce the [SABER](https://mindspore.cn/mindquantum/docs/en/r0.11/algorithm/mapping/mindquantum.algorithm.mapping.SABRE.html#mindquantum.algorithm.mapping.SABRE) algorithm to solve this problem. For more algorithm details, please refer to the paper: [Tackling the Qubit Mapping Problem for NISQ-Era Quantum Devices](https://arxiv.org/abs/1809.02573)." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "from mindquantum.algorithm.mapping import SABRE\n", "\n", "solver = SABRE(circ, t)\n", "new_circ, init_mapping, final_mapping = solver.solve(5, 0.5, 0.3, 0.2)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The new quantum circuit after compiling is:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: q1: q2: q3: RX a RX b RX c " ], "text/plain": [ "" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "new_circ.svg()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "By comparing the old quantum circuit, we know that the algorithm reassigns the qubit id and inserts [SWAP](https://mindspore.cn/mindquantum/docs/en/r0.11/core/mindquantum.core.gates.html#pre-instantiated-gate) gates at appropriate positions, making the circuit run normally." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: q1: q2: RX a RX b RX c " ], "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "circ.svg()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Here `init_mapping` and `final_mapping` tells us how to run the circuit at very begin and what is the relationship with the origin qubit id and final qubit id after running the circuit." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "initial mapping: [3, 2, 0, 1]\n", " final mapping: [1, 2, 0, 3]\n" ] } ], "source": [ "print(f\"initial mapping: {init_mapping}\")\n", "print(f\" final mapping: {final_mapping}\")" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "We can also use `draw_topology` to show which edges will be used when running the compiled circuit." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "0 1 2 3 " ], "text/plain": [ "" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "draw_topology(t, new_circ)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "From the above result, all four edges in qubit topology are all used." ] }, { "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", "
SoftwareVersion
mindquantum0.9.11
scipy1.10.1
numpy1.24.4
SystemInfo
Python3.8.17
OSLinux x86_64
Memory16.62 GB
CPU Max Thread16
DateTue Jan 2 16:53:03 2024
\n" ], "text/plain": [ "" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from mindquantum.utils.show_info import InfoTable\n", "InfoTable('mindquantum', 'scipy', 'numpy')" ] } ], "metadata": { "kernelspec": { "display_name": "MindSpore", "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.17" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }