{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "a0f5b3c9-754e-47d4-8dc7-5af247070187",
      "metadata": {},
      "source": [
        "---\n",
        "title: Create and transpile against custom backends\n",
        "description: Learn how to create your own custom backends and transpile circuits against them\n",
        "---\n",
        "\n",
        "{/* cspell:ignore multichip interchip Lasciate ogne speranza voi ch'intrate */}\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9429c31d-84b1-4547-9227-0b2fcf8a0193",
      "metadata": {},
      "source": [
        "# Create and transpile against custom backends\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "27349ef1-5e25-4762-8a6f-8b4c265763c9",
      "metadata": {
        "tags": [
          "version-info"
        ]
      },
      "source": [
        "{/*\n",
        "  DO NOT EDIT THIS CELL!!!\n",
        "  This cell's content is generated automatically by a script. Anything you add\n",
        "  here will be removed next time the notebook is run. To add new content, create\n",
        "  a new cell before or after this one.\n",
        "  */}\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Package versions\">\n",
        "    The code on this page was developed using the following requirements.\n",
        "    We recommend using these versions or newer.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.4.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "678c28a1-d1ee-4179-8c7a-be5698e045bb",
      "metadata": {},
      "source": [
        "{/* cspell:ignore LOCC */}\n",
        "\n",
        "One of the more powerful features of Qiskit is the ability to support unique device configurations.  Qiskit is built to be agnostic to the provider of the quantum hardware you use, and providers can configure the `BackendV2` object to their own unique device properties.  This topic demonstrates how to configure your own backend and transpile quantum circuits against them.\n",
        "\n",
        "You can create unique `BackendV2` objects with different geometries or basis gates and transpile your circuits with those configurations in mind.  The example below covers a backend with a disjoint qubit lattice, whose basis gates are different along the edges from within the bulk.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "77d43aaf-5f92-412d-b49a-30be82268d21",
      "metadata": {},
      "source": [
        "## Understand the Provider, BackendV2, and Target interfaces\n",
        "\n",
        "Before beginning, it is helpful to understand the usage and purpose of the [`Provider`](../api/qiskit/providers), [`BackendV2`](../api/qiskit/qiskit.providers.BackendV2), and [`Target`](../api/qiskit/qiskit.transpiler.Target) objects.\n",
        "\n",
        "* If you have a quantum device or simulator that you want to integrate into the Qiskit SDK, you need to write your own `Provider` class. This class serves a single purpose: to get backend objects that you provide. This is where any required credential and/or authentication tasks are handled. Once instantiated, the provider object will then provide a list of backends as well as the ability to acquire/instantiate backends.\n",
        "\n",
        "* Next, the backend classes provide the interface between the Qiskit SDK and the hardware or simulator that will execute circuits. They include all necessary information to describe a backend to the transpiler so that it can optimize any circuit according to its constraints. A `BackendV2` is built of four main parts:\n",
        "  * A [`Target`](../api/qiskit/qiskit.transpiler.Target) property, which contains a description of the constraints of the backend and provides a model of the backend for the transpiler\n",
        "  * A `max_circuits` property that defines a limit on the number of circuits a backend can execute in a single job\n",
        "  * A `run()` method that accept job submissions\n",
        "  * A set of `_default_options` to define the user configurable options and their default values\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0ad9dc45-97e9-4e47-b7c0-2fa536d4e624",
      "metadata": {},
      "source": [
        "## Create a custom BackendV2\n",
        "\n",
        "The `BackendV2` object is an abstract class used for all backend objects created by a provider (either within `qiskit.providers` or another library such as [`qiskit_ibm_runtime.IBMBackend`](../api/qiskit-ibm-runtime/ibm-backend)).  As mentioned above, these objects contain several attributes, including a [`Target`](/docs/api/qiskit/qiskit.transpiler.Target). The `Target` contains information that specifies the backend's attributes - such as the [`Coupling Map`](/docs/api/qiskit/qiskit.transpiler.CouplingMap), list of [`Instructions`](/docs/api/qiskit/qiskit.circuit.Instruction), and others - to the transpiler.  In addition to the `Target`, one can also define pulse-level details such as the [`DriveChannel`](/docs/api/qiskit/1.4/qiskit.pulse.channels.DriveChannel) or [`ControlChannel`](/docs/api/qiskit/1.4/qiskit.pulse.channels.ControlChannel).\n",
        "\n",
        "The following example demonstrates this customization by creating a simulated multi-chip backend, where each chip possesses a heavy-hex connectivity.  The example specifies the backend's two-qubit gate set to be [`CZGates`](../api/qiskit/qiskit.circuit.library.CZGate) within each chip and [`CXGates`](../api/qiskit/qiskit.circuit.library.ECRGate) between chips.  First, create your own `BackendV2` and customize its `Target` with single and two-qubit gates according to the previously described constraints.\n",
        "\n",
        "<Admonition type=\"tip\" title=\"graphviz library\">\n",
        "  Plotting a coupling map requires the [`graphviz`](https://graphviz.org/) library to be installed.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "b346f50b-b127-4074-99fc-7c53e3fbc022",
      "metadata": {},
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import rustworkx as rx\n",
        "\n",
        "from qiskit.providers import BackendV2, Options\n",
        "from qiskit.transpiler import Target, InstructionProperties\n",
        "from qiskit.circuit.library import XGate, SXGate, RZGate, CZGate, ECRGate\n",
        "from qiskit.circuit import Measure, Delay, Parameter, Reset\n",
        "from qiskit import QuantumCircuit, transpile\n",
        "from qiskit.visualization import plot_gate_map\n",
        "\n",
        "\n",
        "class FakeLOCCBackend(BackendV2):\n",
        "    \"\"\"Fake multi chip backend.\"\"\"\n",
        "\n",
        "    def __init__(self, distance=3, number_of_chips=3):\n",
        "        \"\"\"Instantiate a new fake multi chip backend.\n",
        "\n",
        "        Args:\n",
        "            distance (int): The heavy hex code distance to use for each chips'\n",
        "                coupling map. This number **must** be odd. The distance relates\n",
        "                to the number of qubits by:\n",
        "                :math:`n = \\\\frac{5d^2 - 2d - 1}{2}` where :math:`n` is the\n",
        "                number of qubits and :math:`d` is the ``distance``\n",
        "            number_of_chips (int): The number of chips to have in the multichip backend\n",
        "                each chip will be a heavy hex graph of ``distance`` code distance.\n",
        "        \"\"\"\n",
        "        super().__init__(name=\"Fake LOCC backend\")\n",
        "        # Create a heavy-hex graph using the rustworkx library, then instantiate a new target\n",
        "        self._graph = rx.generators.directed_heavy_hex_graph(\n",
        "            distance, bidirectional=False\n",
        "        )\n",
        "        num_qubits = len(self._graph) * number_of_chips\n",
        "        self._target = Target(\n",
        "            \"Fake multi-chip backend\", num_qubits=num_qubits\n",
        "        )\n",
        "\n",
        "        # Generate instruction properties for single qubit gates and a measurement, delay,\n",
        "        #  and reset operation to every qubit in the backend.\n",
        "        rng = np.random.default_rng(seed=12345678942)\n",
        "        rz_props = {}\n",
        "        x_props = {}\n",
        "        sx_props = {}\n",
        "        measure_props = {}\n",
        "        delay_props = {}\n",
        "\n",
        "        # Add 1q gates. Globally use virtual rz, x, sx, and measure\n",
        "        for i in range(num_qubits):\n",
        "            qarg = (i,)\n",
        "            rz_props[qarg] = InstructionProperties(error=0.0, duration=0.0)\n",
        "            x_props[qarg] = InstructionProperties(\n",
        "                error=rng.uniform(1e-6, 1e-4),\n",
        "                duration=rng.uniform(1e-8, 9e-7),\n",
        "            )\n",
        "            sx_props[qarg] = InstructionProperties(\n",
        "                error=rng.uniform(1e-6, 1e-4),\n",
        "                duration=rng.uniform(1e-8, 9e-7),\n",
        "            )\n",
        "            measure_props[qarg] = InstructionProperties(\n",
        "                error=rng.uniform(1e-3, 1e-1),\n",
        "                duration=rng.uniform(1e-8, 9e-7),\n",
        "            )\n",
        "            delay_props[qarg] = None\n",
        "        self._target.add_instruction(XGate(), x_props)\n",
        "        self._target.add_instruction(SXGate(), sx_props)\n",
        "        self._target.add_instruction(RZGate(Parameter(\"theta\")), rz_props)\n",
        "        self._target.add_instruction(Measure(), measure_props)\n",
        "        self._target.add_instruction(Reset(), measure_props)\n",
        "\n",
        "        self._target.add_instruction(Delay(Parameter(\"t\")), delay_props)\n",
        "        # Add chip local 2q gate which is CZ\n",
        "        cz_props = {}\n",
        "        for i in range(number_of_chips):\n",
        "            for root_edge in self._graph.edge_list():\n",
        "                offset = i * len(self._graph)\n",
        "                edge = (root_edge[0] + offset, root_edge[1] + offset)\n",
        "                cz_props[edge] = InstructionProperties(\n",
        "                    error=rng.uniform(7e-4, 5e-3),\n",
        "                    duration=rng.uniform(1e-8, 9e-7),\n",
        "                )\n",
        "        self._target.add_instruction(CZGate(), cz_props)\n",
        "\n",
        "        cx_props = {}\n",
        "        # Add interchip 2q gates which are ecr (effectively CX)\n",
        "        # First determine which nodes to connect\n",
        "        node_indices = self._graph.node_indices()\n",
        "        edge_list = self._graph.edge_list()\n",
        "        inter_chip_nodes = {}\n",
        "        for node in node_indices:\n",
        "            count = 0\n",
        "            for edge in edge_list:\n",
        "                if node == edge[0]:\n",
        "                    count += 1\n",
        "            if count == 1:\n",
        "                inter_chip_nodes[node] = count\n",
        "        # Create inter-chip ecr props\n",
        "        cx_props = {}\n",
        "        inter_chip_edges = list(inter_chip_nodes.keys())\n",
        "        for i in range(1, number_of_chips):\n",
        "            offset = i * len(self._graph)\n",
        "            edge = (\n",
        "                inter_chip_edges[1] + (len(self._graph) * (i - 1)),\n",
        "                inter_chip_edges[0] + offset,\n",
        "            )\n",
        "            cx_props[edge] = InstructionProperties(\n",
        "                error=rng.uniform(7e-4, 5e-3),\n",
        "                duration=rng.uniform(1e-8, 9e-7),\n",
        "            )\n",
        "\n",
        "        self._target.add_instruction(ECRGate(), cx_props)\n",
        "\n",
        "    @property\n",
        "    def target(self):\n",
        "        return self._target\n",
        "\n",
        "    @property\n",
        "    def max_circuits(self):\n",
        "        return None\n",
        "\n",
        "    @property\n",
        "    def graph(self):\n",
        "        return self._graph\n",
        "\n",
        "    @classmethod\n",
        "    def _default_options(cls):\n",
        "        return Options(shots=1024)\n",
        "\n",
        "    def run(self, circuit, **kwargs):\n",
        "        raise NotImplementedError(\n",
        "            \"This backend does not contain a run method\"\n",
        "        )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "64a418fa-7a7e-4a12-b9c9-ff7377bffed4",
      "metadata": {},
      "source": [
        "### Visualize backends\n",
        "\n",
        "You can view the connectivity graph of this new class with the [`plot_gate_map()`](../api/qiskit/qiskit.visualization.plot_gate_map) method from the `qiskit.visualization` module.  This method, along with [`plot_coupling_map()`](../api/qiskit/qiskit.visualization.plot_coupling_map) and [`plot_circuit_layout()`](../api/qiskit/qiskit.visualization.plot_circuit_layout), are helpful tools for visualizing the qubit arrangement of a backend, as well as how a circuit is laid out across the qubits of a backend.  This example creates a backend containing three small heavy-hex chips. It specifies a set of coordinates to arrange the qubits, as well as a set of custom colors for the differing two-qubit gates.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "fcc3056a-4e89-4b35-a0d5-e5c676459cc2",
      "metadata": {},
      "outputs": [],
      "source": [
        "backend = FakeLOCCBackend(3, 3)\n",
        "\n",
        "\n",
        "target = backend.target\n",
        "coupling_map_backend = target.build_coupling_map()\n",
        "\n",
        "\n",
        "coordinates = [\n",
        "    (3, 1),\n",
        "    (3, -1),\n",
        "    (2, -2),\n",
        "    (1, 1),\n",
        "    (0, 0),\n",
        "    (-1, -1),\n",
        "    (-2, 2),\n",
        "    (-3, 1),\n",
        "    (-3, -1),\n",
        "    (2, 1),\n",
        "    (1, -1),\n",
        "    (-1, 1),\n",
        "    (-2, -1),\n",
        "    (3, 0),\n",
        "    (2, -1),\n",
        "    (0, 1),\n",
        "    (0, -1),\n",
        "    (-2, 1),\n",
        "    (-3, 0),\n",
        "]\n",
        "\n",
        "single_qubit_coordinates = []\n",
        "total_qubit_coordinates = []\n",
        "\n",
        "\n",
        "for coordinate in coordinates:\n",
        "    total_qubit_coordinates.append(coordinate)\n",
        "\n",
        "for coordinate in coordinates:\n",
        "    total_qubit_coordinates.append(\n",
        "        (-1 * coordinate[0] + 1, coordinate[1] + 4)\n",
        "    )\n",
        "\n",
        "for coordinate in coordinates:\n",
        "    total_qubit_coordinates.append((coordinate[0], coordinate[1] + 8))\n",
        "\n",
        "\n",
        "line_colors = [\"#adaaab\" for edge in coupling_map_backend.get_edges()]\n",
        "ecr_edges = []\n",
        "\n",
        "# Get tuples for the edges which have an ecr instruction attached\n",
        "for instruction in target.instructions:\n",
        "    if instruction[0].name == \"ecr\":\n",
        "        ecr_edges.append(instruction[1])\n",
        "\n",
        "for i, edge in enumerate(coupling_map_backend.get_edges()):\n",
        "    if edge in ecr_edges:\n",
        "        line_colors[i] = \"#000000\""
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "6dc04d04-7afb-46f2-8ee6-ac961e4583f5",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Fake LOCC backend\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/custom-backend/extracted-outputs/6dc04d04-7afb-46f2-8ee6-ac961e4583f5-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "print(backend.name)\n",
        "plot_gate_map(\n",
        "    backend,\n",
        "    plot_directed=True,\n",
        "    qubit_coordinates=total_qubit_coordinates,\n",
        "    line_color=line_colors,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d61da191-caa0-4175-a5f4-741b60905cdc",
      "metadata": {},
      "source": [
        "Each qubit is labeled, and colored arrows represent the two-qubit gates.  Gray arrows are the CZ gates and the black arrows are the inter-chip CX gates (these connect qubits $6 \\rightarrow 21$ and $25 \\rightarrow 40$).  The direction of the arrow indicates the default direction in which these gates are executed; they specify which qubits are control/targets by default for each two-qubit channel.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "59dc66df-5fb8-4844-922c-714fa86f08d5",
      "metadata": {},
      "source": [
        "<span id=\"ex-count-ops\" />\n",
        "\n",
        "## Transpile against custom backends\n",
        "\n",
        "Now that a custom backend with its own unique [`Target`](../api/qiskit/qiskit.transpiler.Target) has been defined, it is straightforward to transpile quantum circuits against this backend, since all the relevant constraints (basis gates, qubit connectivity, and so forth) needed for transpiler passes are contained within this attribute. The next example builds a circuit that creates a large GHZ state and transpiles it against the backend constructed above.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "cf2b1e0f-e6a1-4274-af7b-e5d4d3df6add",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Pre-Transpilation: \n",
            "CX gates: 49\n",
            "H gates: 50\n",
            "\n",
            " ############################## \n",
            "\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Post-Transpilation: \n",
            "CZ gates: 146\n",
            "ECR gates: 6\n",
            "SX gates: 302\n",
            "RZ gates: 250\n"
          ]
        }
      ],
      "source": [
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "\n",
        "num_qubits = 50\n",
        "ghz = QuantumCircuit(num_qubits)\n",
        "ghz.h(range(num_qubits))\n",
        "ghz.cx(0, range(1, num_qubits))\n",
        "op_counts = ghz.count_ops()\n",
        "\n",
        "print(\"Pre-Transpilation: \")\n",
        "print(f\"CX gates: {op_counts['cx']}\")\n",
        "print(f\"H gates: {op_counts['h']}\")\n",
        "print(\"\\n\", 30 * \"#\", \"\\n\")\n",
        "\n",
        "pm = generate_preset_pass_manager(optimization_level=3, backend=backend)\n",
        "transpiled_ghz = pm.run(ghz)\n",
        "op_counts = transpiled_ghz.count_ops()\n",
        "\n",
        "print(\"Post-Transpilation: \")\n",
        "print(f\"CZ gates: {op_counts['cz']}\")\n",
        "print(f\"ECR gates: {op_counts['ecr']}\")\n",
        "print(f\"SX gates: {op_counts['sx']}\")\n",
        "print(f\"RZ gates: {op_counts['rz']}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "58625e26-e078-4ee6-8549-362762450a3b",
      "metadata": {},
      "source": [
        "The transpiled circuit now contains a mixture of `CZ` and `ECR` gates, which we specified as the basis gates in the backend's `Target`.  There are also quite a few more gates than you started with because of the need to insert SWAP instructions after choosing a layout.  Below, the [`plot_circuit_layout()`](/docs/api/qiskit/qiskit.visualization.plot_circuit_layout) visualization tool is used to specify which qubits and two-qubit channels were used in this circuit.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "b51657ed-bb37-4e1a-9dea-8189b4229d24",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/custom-backend/extracted-outputs/b51657ed-bb37-4e1a-9dea-8189b4229d24-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.visualization import plot_circuit_layout\n",
        "\n",
        "plot_circuit_layout(\n",
        "    transpiled_ghz, backend, qubit_coordinates=total_qubit_coordinates\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ec002958-7eda-4329-aabb-cdf1b4c61403",
      "metadata": {},
      "source": [
        "## Create unique backends\n",
        "\n",
        "The [rustworkx](https://www.rustworkx.org/) package contains a large library of different graphs and enables the creation of custom graphs.  The visually interesting code below creates a backend inspired by the toric code. You can then visualize the backend using the functions from the [Visualize backends](#visualize-backends) section.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "82b8fa47-b37f-4136-9e3a-ffa5bc72fdf5",
      "metadata": {},
      "outputs": [],
      "source": [
        "class FakeTorusBackend(BackendV2):\n",
        "    \"\"\"Fake multi chip backend.\"\"\"\n",
        "\n",
        "    def __init__(self):\n",
        "        \"\"\"Instantiate a new backend that is inspired by a toric code\"\"\"\n",
        "        super().__init__(name=\"Fake LOCC backend\")\n",
        "        graph = rx.generators.directed_grid_graph(20, 20)\n",
        "        for column in range(20):\n",
        "            graph.add_edge(column, 19 * 20 + column, None)\n",
        "        for row in range(20):\n",
        "            graph.add_edge(row * 20, row * 20 + 19, None)\n",
        "        num_qubits = len(graph)\n",
        "        rng = np.random.default_rng(seed=12345678942)\n",
        "        rz_props = {}\n",
        "        x_props = {}\n",
        "        sx_props = {}\n",
        "        measure_props = {}\n",
        "        delay_props = {}\n",
        "        self._target = Target(\"Fake Kookaburra\", num_qubits=num_qubits)\n",
        "        # Add 1q gates. Globally use virtual rz, x, sx, and measure\n",
        "        for i in range(num_qubits):\n",
        "            qarg = (i,)\n",
        "            rz_props[qarg] = InstructionProperties(error=0.0, duration=0.0)\n",
        "            x_props[qarg] = InstructionProperties(\n",
        "                error=rng.uniform(1e-6, 1e-4),\n",
        "                duration=rng.uniform(1e-8, 9e-7),\n",
        "            )\n",
        "            sx_props[qarg] = InstructionProperties(\n",
        "                error=rng.uniform(1e-6, 1e-4),\n",
        "                duration=rng.uniform(1e-8, 9e-7),\n",
        "            )\n",
        "            measure_props[qarg] = InstructionProperties(\n",
        "                error=rng.uniform(1e-3, 1e-1),\n",
        "                duration=rng.uniform(1e-8, 9e-7),\n",
        "            )\n",
        "            delay_props[qarg] = None\n",
        "        self._target.add_instruction(XGate(), x_props)\n",
        "        self._target.add_instruction(SXGate(), sx_props)\n",
        "        self._target.add_instruction(RZGate(Parameter(\"theta\")), rz_props)\n",
        "        self._target.add_instruction(Measure(), measure_props)\n",
        "        self._target.add_instruction(Reset(), measure_props)\n",
        "        self._target.add_instruction(Delay(Parameter(\"t\")), delay_props)\n",
        "        cz_props = {}\n",
        "        for edge in graph.edge_list():\n",
        "            cz_props[edge] = InstructionProperties(\n",
        "                error=rng.uniform(7e-4, 5e-3),\n",
        "                duration=rng.uniform(1e-8, 9e-7),\n",
        "            )\n",
        "        self._target.add_instruction(CZGate(), cz_props)\n",
        "\n",
        "    @property\n",
        "    def target(self):\n",
        "        return self._target\n",
        "\n",
        "    @property\n",
        "    def max_circuits(self):\n",
        "        return None\n",
        "\n",
        "    @classmethod\n",
        "    def _default_options(cls):\n",
        "        return Options(shots=1024)\n",
        "\n",
        "    def run(self, circuit, **kwargs):\n",
        "        raise NotImplementedError(\"Lasciate ogne speranza, voi ch'intrate\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "1d40864a-7695-438b-95bf-7724c34d92b4",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/custom-backend/extracted-outputs/1d40864a-7695-438b-95bf-7724c34d92b4-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "backend = FakeTorusBackend()\n",
        "# We set `figsize` to a smaller size to make the documentation website faster\n",
        "# to load. Normally, you do not need to set the argument.\n",
        "plot_gate_map(backend, figsize=(4, 4))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "341a0256-4a76-4d84-b598-5fc4d9fbef19",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "CZ gates: 834\n",
            "X gates: 18\n",
            "SX gates: 1534\n",
            "RZ gates: 1150\n"
          ]
        }
      ],
      "source": [
        "num_qubits = int(backend.num_qubits / 2)\n",
        "full_device_bv = QuantumCircuit(num_qubits, num_qubits - 1)\n",
        "full_device_bv.x(num_qubits - 1)\n",
        "full_device_bv.h(range(num_qubits))\n",
        "full_device_bv.cx(range(num_qubits - 1), num_qubits - 1)\n",
        "full_device_bv.h(range(num_qubits))\n",
        "full_device_bv.measure(range(num_qubits - 1), range(num_qubits - 1))\n",
        "tqc = transpile(full_device_bv, backend, optimization_level=3)\n",
        "op_counts = tqc.count_ops()\n",
        "print(f\"CZ gates: {op_counts['cz']}\")\n",
        "print(f\"X gates: {op_counts['x']}\")\n",
        "print(f\"SX gates: {op_counts['sx']}\")\n",
        "print(f\"RZ gates: {op_counts['rz']}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "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"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}