{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "a0f5b3c9-754e-47d4-8dc7-5af247070187",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"カスタムバックエンドに対して作成およびトランスパイルする\"\n",
        "description: \"独自のカスタムバックエンドを作成し、それらに対して回路をトランスパイルする方法を学びましょう\"\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": [
        "<span id=\"create-and-transpile-against-custom-backends\" />\n",
        "\n",
        "# カスタムバックエンドに対して作成およびトランスパイルする\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=\"パッケージ・バージョン\">\n",
        "    このページのコードは、以下の要件に基づいて開発された。\n",
        "    これらのバージョンまたは新しいバージョンの使用をお勧めします。\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.5.1\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "678c28a1-d1ee-4179-8c7a-be5698e045bb",
      "metadata": {},
      "source": [
        "{/* cspell:ignore LOCC */}\n",
        "\n",
        "Qiskitのより強力な特徴の一つは、ユニークなデバイス構成をサポートする能力である。  Qiskitは、使用する量子ハードウェアのプロバイダに依存しないように構築されており、プロバイダは、 `BackendV2` オブジェクトを独自のデバイスプロパティに設定することができます。  このトピックでは、独自のバックエンドを設定し、それに対して量子回路をトランスパイルする方法を示す。\n",
        "\n",
        "異なるジオメトリや基底ゲートを持つユニークな `BackendV2` オブジェクトを作成し、それらの構成を念頭に置いて回路をトランスパイルすることができます。  以下の例は、基底ゲートがバルク内とエッジに沿って異なる、不連続な量子ビット格子を持つバックエンドをカバーしている。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "77d43aaf-5f92-412d-b49a-30be82268d21",
      "metadata": {},
      "source": [
        "<span id=\"understand-the-provider-backendv2-and-target-interfaces\" />\n",
        "\n",
        "## プロバイダー、 BackendV2、およびターゲットインターフェースを理解する\n",
        "\n",
        "の使い方と目的を理解しておくとよい。 [`Provider`](../api/qiskit/providers), [`BackendV2`](../api/qiskit/qiskit.providers.BackendV2)および [`Target`](../api/qiskit/qiskit.transpiler.Target) オブジェクトを理解するのに役立つ。\n",
        "\n",
        "* Qiskit SDKに統合したい量子デバイスやシミュレータがある場合は、独自の `Provider` クラスを書く必要があります。 このクラスの目的はただ一つ、あなたが提供するバックエンド・オブジェクトを取得することです。 ここでは、必要なクレデンシャルや認証タスクが処理される。 インスタンス化されると、プロバイダオブジェクトはバックエンドのリストを提供し、バックエンドを獲得/インスタンス化する機能も提供する。\n",
        "\n",
        "* 次に、バックエンドクラスは、Qiskit SDKと回路を実行するハードウェアやシミュレータとのインターフェースを提供します。 トランスパイラにバックエンドを記述するために必要な情報がすべて含まれているので、トランスパイラは制約に従って回路を最適化することができる。 `BackendV2` は4つの主要部分から構成されている：\n",
        "  * A [`Target`](../api/qiskit/qiskit.transpiler.Target) プロパティ。バックエンドの制約の説明を含み、トランスパイラにバックエンドのモデルを提供する\n",
        "  * `max_circuits` 、バックエンドが1つのジョブで実行できる回路数の上限を定義するプロパティ\n",
        "  * ジョブ投入を受け付ける `run()` メソッド\n",
        "  * `_default_options` ユーザーが設定可能なオプションとそのデフォルト値を定義するためのセット\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0ad9dc45-97e9-4e47-b7c0-2fa536d4e624",
      "metadata": {},
      "source": [
        "<span id=\"create-a-custom-backendv2\" />\n",
        "\n",
        "## カスタム BackendV2 を作成する\n",
        "\n",
        "`BackendV2` オブジェクトは、プロバイダ（ `qiskit.providers` 内または [`qiskit_ibm_runtime.IBMBackend`](../api/qiskit-ibm-runtime/ibm-backend)).  上述したように、これらのオブジェクトにはいくつかの属性があります。 [`Target`](/docs/api/qiskit/qiskit.transpiler.Target). `Target` には、バックエンドの属性を指定する情報が含まれている。 [`Coupling Map`](/docs/api/qiskit/qiskit.transpiler.CouplingMap)のリスト [`Instructions`](/docs/api/qiskit/qiskit.circuit.Instruction)などのバックエンドの属性を指定する情報が含まれています。  `Target`のようなパルスレベルの詳細も定義できる。 [`DriveChannel`](/docs/api/qiskit/1.4/qiskit.pulse.channels.DriveChannel) または [`ControlChannel`](/docs/api/qiskit/1.4/qiskit.pulse.channels.ControlChannel).\n",
        "\n",
        "以下の例では、各チップがヘビーヘックス接続を持つマルチチップ・バックエンドをシミュレートすることで、このカスタマイズを実証している。  この例では、バックエンドの2量子ビット・ゲート・セットを各チップ内で [`CZGates`](../api/qiskit/qiskit.circuit.library.CZGate) 各チップ内と [`CXGates`](../api/qiskit/qiskit.circuit.library.ECRGate) チップ間である。  まず、独自の `BackendV2` を作成し、その `Target` を、先に説明した制約に従ってシングルおよび2量子ビットゲートでカスタマイズする。\n",
        "\n",
        "<Admonition type=\"tip\" title=\"グラフビズ・ライブラリ\">\n",
        "  カップリング・マップの作図には [`graphviz`](https://graphviz.org/) ライブラリがインストールされている必要があります。\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\n",
        "        # 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": [
        "<span id=\"visualize-backends\" />\n",
        "\n",
        "### バックエンドを可視化する\n",
        "\n",
        "この新しいクラスの接続グラフは、 モジュールの [`plot_gate_map()`](../api/qiskit/qiskit.visualization.plot_gate_map)`qiskit.visualization` メソッドで見ることができます。  この方法は [`plot_coupling_map()`](../api/qiskit/qiskit.visualization.plot_coupling_map) と [`plot_circuit_layout()`](../api/qiskit/qiskit.visualization.plot_circuit_layout)とともに、バックエンドの量子ビットの配置や、バックエンドの量子ビットにまたがって回路がどのように配置されているかを視覚化するのに役立つツールです。  この例では、3つの小さなヘビーヘックス・チップを含むバックエンドを作成する。 これは、量子ビットを配置する座標のセットと、異なる2量子ビットゲートのカスタムカラーのセットを指定する。\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": [
        "それぞれの量子ビットにはラベルが付けられ、色の付いた矢印は2量子ビットのゲートを表している。  グレーの矢印はCZゲート、黒の矢印はチップ間CXゲート（これらは量子ビット $6 \\rightarrow 21$ と $25 \\rightarrow 40$ を接続している）。 矢印の方向は、これらのゲートが実行されるデフォルトの方向を示し、各2量子ビット・チャンネルのデフォルトでどの量子ビットが制御/ターゲットになるかを指定します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "59dc66df-5fb8-4844-922c-714fa86f08d5",
      "metadata": {},
      "source": [
        "<span id=\"ex-count-ops\" />\n",
        "\n",
        "<span id=\"transpile-against-custom-backends\" />\n",
        "\n",
        "## カスタムバックエンドに対してトランスパイルする\n",
        "\n",
        "を持つカスタムバックエンドが定義されました。 [`Target`](../api/qiskit/qiskit.transpiler.Target) が定義されたので、このバックエンドに対して量子回路をトランスパイルするのは簡単です。なぜなら、トランスパイラ・パスに必要なすべての関連制約（基底ゲート、量子ビットの接続性など）がこの属性に含まれているからです。 次の例では、大きなGHZステートを作成する回路を構築し、上で構築したバックエンドに対してそれをトランスパイルする。\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: 207\n",
            "ECR gates: 8\n",
            "SX gates: 379\n",
            "RZ gates: 211\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": [
        "トランスパイルされた回路には現在、 `ECR``CZ` とゲートが混在しています。これらはバックエンドので基本ゲート `Target`として指定したものです。  レイアウト選択後にSWAP命令を挿入する必要があるため、開始時よりもゲートがかなり多くなっています。  以下では、可視 [`plot_circuit_layout()`](/docs/api/qiskit/qiskit.visualization.plot_circuit_layout) 化ツールを用いて、この回路で使用された量子ビットと2量子ビットチャネルを特定します。\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": [
        "<span id=\"create-unique-backends\" />\n",
        "\n",
        "## 独自のバックエンドを作成する\n",
        "\n",
        "[rustworkx](https://www.rustworkx.org/) パッケージには、さまざまなグラフの大規模なライブラリーが含まれており、カスタムグラフの作成が可能です。  以下のビジュアル的に興味深いコードは、トーリックコードにインスパイアされたバックエンドを作成する。 そして、 [Visualize backends](#visualize-backends) セクションの関数を使ってバックエンドを可視化することができます。\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: 580\n",
            "X gates: 129\n",
            "SX gates: 936\n",
            "RZ gates: 840\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
}