{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "-LuIQvRkv5DN" }, "source": [ "# Introduction to Rivet Transpiler" ] }, { "cell_type": "markdown", "metadata": { "id": "aC0BK8tYv6GG" }, "source": [ "**Quantum Transpilation** is the transformation of a given virtual quantum circuit:\n", "\n", "- to match the topology of a specific device\n", "- to optimize the circuit for execution\n", "\n", "Rivet gives the User a high level of insight into, and control over the transpilation process, including the – typically invisible to the user – use of quantum resources, such as auxiliary qubits used in various transpilation passes, which can be constrained via the Qubit-Constrained Transpilation function. Combined with a debugging interface it allows to optimize the classical and quantum compute involved in the execution and shorten the development loop, especially in research and prototyping.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. Basic Example" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Transpilation includes placement of *virtual qubits* of a circuit to *physical qubits* of the quantum device or simulator. Additionally, SWAP gates can be included to route qubits around the backend topology.\n", "\n", "Here we present a simple quantum circuit with 3 qubits before and after transpilation (using the function `transpile_chain` which transpiles a chain of virtual circuits keeping qubits consistent).\n", "\n", "### BEFORE transpilation\n", "\n", "```python\n", "from qiskit import QuantumCircuit\n", "\n", "from qiskit_ibm_runtime.fake_provider import FakeLimaV2\n", "\n", "from rivet_transpiler import transpile_chain\n", "\n", "backend = FakeLimaV2()\n", "\n", "circuit = QuantumCircuit(3)\n", "\n", "circuit.cx(0, 1)\n", "circuit.cx(1, 2)\n", "circuit.cx(0, 2)\n", "\n", "circuit.barrier()\n", "\n", "circuit.draw()\n", "```\n", "\n", "```bash\n", "q_0: ──■─────────■──\n", " ┌─┴─┐ │\n", "q_1: ┤ X ├──■────┼──\n", " └───┘┌─┴─┐┌─┴─┐\n", "q_2: ─────┤ X ├┤ X ├\n", " └───┘└───┘\n", "```\n", "\n", "### AFTER transpilation\n", "\n", "```python\n", "CHAIN = [circuit] * 3\n", "\n", "transpiled_circuit = transpile_chain(\n", " CHAIN,\n", " backend,\n", " seed_transpiler=1234\n", ")\n", "\n", "transpiled_circuit.draw(fold=-1)\n", "```\n", "\n", "```bash\n", " ┌───┐ ░ ┌───┐ ░ ┌───┐ ┌───┐ ┌───┐ ░\n", " q_1 -> 0 ──■─────────■──┤ X ├──■────────░─┤ X ├─────────────────■────────░───■──┤ X ├──■───────┤ X ├───────────────┤ X ├─░─\n", " ┌─┴─┐ ┌─┴─┐└─┬─┘┌─┴─┐ ░ └─┬─┘┌───┐ ┌───┐┌─┴─┐┌───┐ ░ ┌─┴─┐└─┬─┘┌─┴─┐┌───┐└─┬─┘┌───┐ ┌───┐└─┬─┘ ░\n", " q_2 -> 1 ┤ X ├──■──┤ X ├──■──┤ X ├──■───░───■──┤ X ├──■──┤ X ├┤ X ├┤ X ├─░─┤ X ├──■──┤ X ├┤ X ├──■──┤ X ├──■──┤ X ├──■───░─\n", " └───┘┌─┴─┐└───┘ └───┘┌─┴─┐ ░ └─┬─┘┌─┴─┐└─┬─┘└───┘└─┬─┘ ░ └───┘ └───┘└─┬─┘ └─┬─┘┌─┴─┐└─┬─┘ ░\n", " q_0 -> 2 ─────┤ X ├───────────────┤ X ├─░────────■──┤ X ├──■─────────■───░──────────────────■─────────■──┤ X ├──■────────░─\n", " └───┘ └───┘ ░ └───┘ ░ └───┘ ░\n", "ancilla_0 -> 3 ────────────────────────────────────────────────────────────────░───────────────────────────────────────────────░─\n", " ░ ░\n", "ancilla_1 -> 4 ────────────────────────────────────────────────────────────────░───────────────────────────────────────────────░─\n", " ░ ░\n", "```" ] }, { "cell_type": "markdown", "metadata": { "id": "Tf3CiM5nv-Rk" }, "source": [ "## 2. Transpilation Stages\n", "**Pass Manager** is an internal Qiskit object constructed by the `transpile` function \"under the hood\" during transpilation.\n", "Pass Manager consists of Passes which analyse or change the transpiled circuit.\n", "Calling `pass_manager.run` is equivalent to calling `transpile` and passing a circuit, backend and corresponding transpilation parameters." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "id": "5HAsOYSzwID4" }, "outputs": [], "source": [ "import qiskit\n", "\n", "pass_manager = qiskit.transpiler.preset_passmanagers.generate_preset_pass_manager(\n", " # backend=backend,\n", " # initial_layout=[1, 0, 2],\n", " optimization_level=3,\n", " seed_transpiler=1234\n", ")" ] }, { "cell_type": "markdown", "metadata": { "id": "7T1KiSEVv-UZ" }, "source": [ "Calling `pass_manager.stages` the main transpilation stages can be displayed: ('init', 'layout', 'routing', 'translation', 'optimization', 'scheduling')\n", "\n", "1) **Init** - Unrolling custom instructions and converting the circuit to all 1 and 2 qubit gates.\n", "\n", "2) **Layout** - Mapping circuit virtual qubits to backend physical qubits.\n", "\n", "3) **Routing** - Inject SWAP gates to comply with the backend’s coupling map.\n", "\n", "4) **Translation** - Translate to the target backend’s basis gate set.\n", "\n", "5) **Optimization** - Main optimization loop to increase circuit quality.\n", "\n", "6) **Scheduling** - Conversion to hardware-specific pulses." ] }, { "cell_type": "markdown", "metadata": { "id": "eFmE1DKZwLGJ" }, "source": [ "\n", " **The Rivet Transpiler package** provides a family of functions (transpile and service functions) for the efficient transpilation of quantum circuits. Check `API Reference` section for more details.\n", " " ] }, { "cell_type": "markdown", "metadata": { "id": "K463n8w1VpsY" }, "source": [ "## 3. Supported Stacks" ] }, { "cell_type": "markdown", "metadata": { "id": "s1yxZK8_WQ7U" }, "source": [ "Flexible Stack Selection: Users can transpile their entire circuit, or parts of a circuit, via one or a combination of transpilation passes from different stacks of their preference. This allows one to choose the optimal transpiling strategy for the given use case and circuit architecture. Supported stacks include:\n", "\n", "1. Qiskit transpilation\n", "2. Pytket transpilation\n", "3. BQSKit QSearch synthesis\n", "4. BQSKit QFactor instantiation\n", " \n", "Make sure you have followed and installed Rivet Transpiler. Check the installation steps from **Readme.md**. Then import Qiskit, other modules required for the example execution and Rivet Transpiler functions." ] }, { "cell_type": "markdown", "metadata": { "id": "JNy-siUqWX_E" }, "source": [ "### Stacks Usage" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
            ┌──────────────┐          ┌───┐ Litmus \n",
       "Litmus_0_0: ┤ Rz(Litmus_0) ├──■───────┤ X ├───░────\n",
       "            ├──────────────┤┌─┴─┐     └─┬─┘   ░    \n",
       "Litmus_0_1: ┤ Rz(Litmus_1) ├┤ X ├──■────┼─────░────\n",
       "            ├──────────────┤└───┘┌─┴─┐  │     ░    \n",
       "Litmus_0_2: ┤ Rz(Litmus_2) ├─────┤ X ├──■─────░────\n",
       "            └──────────────┘     └───┘        ░    
" ], "text/plain": [ " ┌──────────────┐ ┌───┐ Litmus \n", "Litmus_0_0: ┤ Rz(Litmus_0) ├──■───────┤ X ├───░────\n", " ├──────────────┤┌─┴─┐ └─┬─┘ ░ \n", "Litmus_0_1: ┤ Rz(Litmus_1) ├┤ X ├──■────┼─────░────\n", " ├──────────────┤└───┘┌─┴─┐ │ ░ \n", "Litmus_0_2: ┤ Rz(Litmus_2) ├─────┤ X ├──■─────░────\n", " └──────────────┘ └───┘ ░ " ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from rivet_transpiler import transpile\n", "from rivet_transpiler import get_litmus_circuit\n", "\n", "from qiskit_ibm_runtime.fake_provider import FakeLimaV2\n", "\n", "backend = FakeLimaV2()\n", "\n", "QUBITS_COUNT = 3\n", "\n", "litmus_circuit = get_litmus_circuit(QUBITS_COUNT, \"Litmus\")\n", "\n", "litmus_circuit.draw()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "id": "KdwJrqFrWTrU" }, "outputs": [], "source": [ "STACKS = [\"qiskit\",\n", " \"qiskit_qsearch\",\n", " \"qiskit_qfactor_qsearch\",\n", " \"qiskit_pytket\"]" ] }, { "cell_type": "markdown", "metadata": { "id": "RL-JtsJ5Wd6x" }, "source": [ "#### Qiskit" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "id": "QJeXNbuQWeE6" }, "outputs": [ { "data": { "text/html": [ "
                ┌──────────────┐          ┌───┐          ┌───┐ Litmus \n",
       "Litmus_0_2 -> 0 ┤ Rz(Litmus_2) ├───────■──┤ X ├──■───────┤ X ├───░────\n",
       "                ├──────────────┤     ┌─┴─┐└─┬─┘┌─┴─┐┌───┐└─┬─┘   ░    \n",
       "Litmus_0_0 -> 1 ┤ Rz(Litmus_0) ├──■──┤ X ├──■──┤ X ├┤ X ├──■─────░────\n",
       "                ├──────────────┤┌─┴─┐└───┘     └───┘└─┬─┘        ░    \n",
       "Litmus_0_1 -> 2 ┤ Rz(Litmus_1) ├┤ X ├─────────────────■──────────░────\n",
       "                └──────────────┘└───┘                            ░    \n",
       " ancilla_0 -> 3 ──────────────────────────────────────────────────────\n",
       "                                                                      \n",
       " ancilla_1 -> 4 ──────────────────────────────────────────────────────\n",
       "                                                                      
" ], "text/plain": [ " ┌──────────────┐ ┌───┐ ┌───┐ Litmus \n", "Litmus_0_2 -> 0 ┤ Rz(Litmus_2) ├───────■──┤ X ├──■───────┤ X ├───░────\n", " ├──────────────┤ ┌─┴─┐└─┬─┘┌─┴─┐┌───┐└─┬─┘ ░ \n", "Litmus_0_0 -> 1 ┤ Rz(Litmus_0) ├──■──┤ X ├──■──┤ X ├┤ X ├──■─────░────\n", " ├──────────────┤┌─┴─┐└───┘ └───┘└─┬─┘ ░ \n", "Litmus_0_1 -> 2 ┤ Rz(Litmus_1) ├┤ X ├─────────────────■──────────░────\n", " └──────────────┘└───┘ ░ \n", " ancilla_0 -> 3 ──────────────────────────────────────────────────────\n", " \n", " ancilla_1 -> 4 ──────────────────────────────────────────────────────\n", " " ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "transpiled_circuit = transpile(\n", " litmus_circuit,\n", " backend,\n", " stack=\"qiskit\",\n", " seed_transpiler=1234)\n", "\n", "transpiled_circuit.draw()" ] }, { "cell_type": "markdown", "metadata": { "id": "Ca6C762iWePl" }, "source": [ "#### Pytket" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "id": "yUjx0ZUTWeZN" }, "outputs": [ { "data": { "text/html": [ "
                ┌──────────────┐          ┌───┐          ┌───┐ ░ \n",
       "Litmus_0_2 -> 0 ┤ Rz(Litmus_2) ├───────■──┤ X ├──■───────┤ X ├─░─\n",
       "                ├──────────────┤     ┌─┴─┐└─┬─┘┌─┴─┐┌───┐└─┬─┘ ░ \n",
       "Litmus_0_0 -> 1 ┤ Rz(Litmus_0) ├──■──┤ X ├──■──┤ X ├┤ X ├──■───░─\n",
       "                ├──────────────┤┌─┴─┐└───┘     └───┘└─┬─┘      ░ \n",
       "Litmus_0_1 -> 2 ┤ Rz(Litmus_1) ├┤ X ├─────────────────■────────░─\n",
       "                └──────────────┘└───┘                          ░ \n",
       " ancilla_0 -> 3 ─────────────────────────────────────────────────\n",
       "                                                                 \n",
       " ancilla_1 -> 4 ─────────────────────────────────────────────────\n",
       "                                                                 
" ], "text/plain": [ " ┌──────────────┐ ┌───┐ ┌───┐ ░ \n", "Litmus_0_2 -> 0 ┤ Rz(Litmus_2) ├───────■──┤ X ├──■───────┤ X ├─░─\n", " ├──────────────┤ ┌─┴─┐└─┬─┘┌─┴─┐┌───┐└─┬─┘ ░ \n", "Litmus_0_0 -> 1 ┤ Rz(Litmus_0) ├──■──┤ X ├──■──┤ X ├┤ X ├──■───░─\n", " ├──────────────┤┌─┴─┐└───┘ └───┘└─┬─┘ ░ \n", "Litmus_0_1 -> 2 ┤ Rz(Litmus_1) ├┤ X ├─────────────────■────────░─\n", " └──────────────┘└───┘ ░ \n", " ancilla_0 -> 3 ─────────────────────────────────────────────────\n", " \n", " ancilla_1 -> 4 ─────────────────────────────────────────────────\n", " " ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "transpiled_circuit = transpile(\n", " litmus_circuit,\n", " backend,\n", " stack=\"qiskit_pytket\",\n", " seed_transpiler=1234)\n", "\n", "transpiled_circuit.draw()" ] } ], "metadata": { "colab": { "provenance": [] }, "kernelspec": { "display_name": "Rivet_Release", "language": "python", "name": "rivet_release" }, "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.10.13" } }, "nbformat": 4, "nbformat_minor": 4 }