{ "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
}