{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "a0f5b3c9-754e-47d4-8dc7-5af247070187",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Erstellen und transpilieren Sie gegen benutzerdefinierte Backends\"\n",
        "description: \"Erfahren Sie, wie Sie Ihre eigenen benutzerdefinierten Backends erstellen und Schaltkreise dafür transpilieren können\"\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",
        "# Erstellen und transpilieren Sie gegen benutzerdefinierte 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=\"Paketversionen\">\n",
        "    Der Code auf dieser Seite wurde unter Berücksichtigung der folgenden Anforderungen entwickelt.\n",
        "    Wir empfehlen die Verwendung dieser oder neuerer Versionen.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.5.2\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "678c28a1-d1ee-4179-8c7a-be5698e045bb",
      "metadata": {},
      "source": [
        "{/* cspell:ignore LOCC */}\n",
        "\n",
        "Eine der leistungsstärksten Funktionen von Qiskit ist die Fähigkeit, einzigartige Gerätekonfigurationen zu unterstützen.  Qiskit ist unabhängig vom Anbieter der von Ihnen verwendeten Quantenhardware, und Anbieter können das Objekt `BackendV2` mit ihren eigenen Geräteeigenschaften konfigurieren.  In diesem Thema wird gezeigt, wie Sie Ihr eigenes Backend konfigurieren und Quantenschaltungen gegen dieses umsetzen können.\n",
        "\n",
        "Sie können einzigartige `BackendV2` Objekte mit verschiedenen Geometrien oder Basisgattern erstellen und Ihre Schaltungen mit diesen Konfigurationen im Hinterkopf umsetzen.  Das nachstehende Beispiel bezieht sich auf ein Backend mit einem disjunkten Qubit-Gitter, dessen Basistore sich entlang der Kanten von denen des Bulk unterscheiden.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "77d43aaf-5f92-412d-b49a-30be82268d21",
      "metadata": {},
      "source": [
        "<span id=\"understand-the-provider-backendv2-and-target-interfaces\" />\n",
        "\n",
        "## Verstehen Sie die Schnittstellen „Provider“, „ BackendV2 “ und „Target“\n",
        "\n",
        "Bevor Sie beginnen, ist es hilfreich, die Verwendung und den Zweck der [`Provider`](../api/qiskit/providers), [`BackendV2`](../api/qiskit/qiskit.providers.BackendV2), und [`Target`](../api/qiskit/qiskit.transpiler.Target) objekte zu verstehen.\n",
        "\n",
        "* Wenn Sie ein Quantengerät oder einen Quantensimulator haben, den Sie in das Qiskit SDK integrieren möchten, müssen Sie Ihre eigene `Provider` Klasse schreiben. Diese Klasse dient einem einzigen Zweck: dem Abrufen von Backend-Objekten, die Sie bereitstellen. Hier werden alle erforderlichen Anmeldeinformationen und/oder Authentifizierungsaufgaben bearbeitet. Nach der Instanziierung bietet das Anbieterobjekt eine Liste von Backends sowie die Möglichkeit, Backends zu erwerben/einzuführen.\n",
        "\n",
        "* Die Backend-Klassen bilden die Schnittstelle zwischen dem Qiskit SDK und der Hardware oder dem Simulator, der die Schaltungen ausführt. Sie enthalten alle notwendigen Informationen, um ein Backend für den Transpiler zu beschreiben, so dass dieser jede Schaltung entsprechend ihrer Einschränkungen optimieren kann. Eine `BackendV2` besteht aus vier Hauptbestandteilen:\n",
        "  * A [`Target`](../api/qiskit/qiskit.transpiler.Target) eigenschaft, die eine Beschreibung der Beschränkungen des Backends enthält und ein Modell des Backends für den Transpiler bereitstellt\n",
        "  * Eine Eigenschaft von `max_circuits` , die die Anzahl der Schaltungen begrenzt, die ein Backend in einem einzigen Auftrag ausführen kann\n",
        "  * Eine `run()` -Methode, die Auftragseingaben akzeptiert\n",
        "  * Ein Satz von `_default_options` , um die vom Benutzer konfigurierbaren Optionen und ihre Standardwerte zu definieren\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0ad9dc45-97e9-4e47-b7c0-2fa536d4e624",
      "metadata": {},
      "source": [
        "<span id=\"create-a-custom-backendv2\" />\n",
        "\n",
        "## Erstellen Sie eine benutzerdefinierte Datei „ BackendV2 “\n",
        "\n",
        "Das `BackendV2` Objekt ist eine abstrakte Klasse, die für alle Backend-Objekte verwendet wird, die von einem Anbieter (entweder innerhalb von `qiskit.providers` oder einer anderen Bibliothek wie [`qiskit_ibm_runtime.IBMBackend`](../api/qiskit-ibm-runtime/ibm-backend)).  Wie bereits erwähnt, enthalten diese Objekte mehrere Attribute, darunter ein [`Target`](/docs/api/qiskit/qiskit.transpiler.Target). Die `Target` enthält Informationen, die die Attribute des Backends spezifizieren - wie z. B. die [`Coupling Map`](/docs/api/qiskit/qiskit.transpiler.CouplingMap), Liste der [`Instructions`](/docs/api/qiskit/qiskit.circuit.Instruction), und andere - an den Transpiler weitergeben.  Zusätzlich zur `Target` kann man auch Details auf Impulsebene definieren, wie z. B. die [`DriveChannel`](/docs/api/qiskit/1.4/qiskit.pulse.channels.DriveChannel) oder [`ControlChannel`](/docs/api/qiskit/1.4/qiskit.pulse.channels.ControlChannel).\n",
        "\n",
        "Das folgende Beispiel veranschaulicht diese Anpassung, indem es ein simuliertes Multi-Chip-Backend erstellt, bei dem jeder Chip über eine Heavy-Hex-Konnektivität verfügt.  Das Beispiel legt fest, dass das Zwei-Qubit-Gate des Backends [`CZGates`](../api/qiskit/qiskit.circuit.library.CZGate) innerhalb jedes Chips und [`CXGates`](../api/qiskit/qiskit.circuit.library.ECRGate) zwischen den Chips.  Erstellen Sie zunächst Ihr eigenes `BackendV2` und passen Sie dessen `Target` mit Ein- und Zwei-Qubit-Gattern gemäß den zuvor beschriebenen Einschränkungen an.\n",
        "\n",
        "<Admonition type=\"tip\" title=\"graphviz-Bibliothek\">\n",
        "  Für die Darstellung einer Kopplungskarte muss die [`graphviz`](https://graphviz.org/) bibliothek installiert sein.\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",
        "### Backends visualisieren\n",
        "\n",
        "Sie können den Konnektivitätsgraphen dieser neuen Klasse mit der [`plot_gate_map()`](../api/qiskit/qiskit.visualization.plot_gate_map) methode aus dem Modul `qiskit.visualization` anzeigen lassen.  Diese Methode, zusammen mit [`plot_coupling_map()`](../api/qiskit/qiskit.visualization.plot_coupling_map) und [`plot_circuit_layout()`](../api/qiskit/qiskit.visualization.plot_circuit_layout)sind hilfreiche Werkzeuge, um die Qubit-Anordnung eines Backends zu visualisieren und um zu sehen, wie ein Schaltkreis über die Qubits eines Backends verteilt ist.  In diesem Beispiel wird ein Backend mit drei kleinen Heavy-Hex-Chips erstellt. Sie gibt eine Reihe von Koordinaten für die Anordnung der Qubits sowie eine Reihe von benutzerdefinierten Farben für die verschiedenen Zwei-Qubit-Tore an.\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": [
        "Jedes Qubit ist beschriftet, und farbige Pfeile stellen die Zwei-Qubit-Tore dar.  Graue Pfeile sind die CZ-Gatter und die schwarzen Pfeile sind die Inter-Chip-CX-Gatter (diese verbinden die Qubits $6 \\rightarrow 21$ und $25 \\rightarrow 40$ ). Die Richtung des Pfeils gibt die Standardrichtung an, in der diese Gatter ausgeführt werden; sie legen fest, welche Qubits standardmäßig für jeden Zwei-Qubit-Kanal Kontroll-/Zielgrößen sind.\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",
        "## Transpile gegen benutzerdefinierte Backends\n",
        "\n",
        "Nachdem nun ein benutzerdefiniertes Backend mit seinem eigenen eindeutigen [`Target`](../api/qiskit/qiskit.transpiler.Target) definiert wurde, ist es ein Leichtes, Quantenschaltungen gegen dieses Backend zu transpilieren, da alle relevanten Einschränkungen (Basisgatter, Qubit-Konnektivität usw.), die für Transpiler-Durchläufe benötigt werden, in diesem Attribut enthalten sind. Im nächsten Beispiel wird eine Schaltung aufgebaut, die einen großen GHZ-Zustand erzeugt und diesen mit dem oben konstruierten Backend abgleicht.\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: 204\n",
            "ECR gates: 8\n",
            "SX gates: 373\n",
            "RZ gates: 216\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": [
        "Der transpilierte Schaltkreis enthält nun eine Mischung aus `CZ` und `ECR` Gattern, die wir als Basisgatter im Backend-Modul spezifiziert `Target` haben.  Es gibt auch deutlich mehr Gates als zu Beginn, da nach der Auswahl eines Layouts SWAP-Befehle eingefügt werden müssen.  Im Folgenden wird das [`plot_circuit_layout()`](/docs/api/qiskit/qiskit.visualization.plot_circuit_layout) Visualisierungstool verwendet, um anzugeben, welche Qubits und Zwei-Qubit-Kanäle in dieser Schaltung verwendet wurden.\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",
        "## Erstellen Sie einzigartige Backends\n",
        "\n",
        "Das [rustworkx-Paket](https://www.rustworkx.org/) enthält eine große Bibliothek mit verschiedenen Graphen und ermöglicht die Erstellung von benutzerdefinierten Graphen.  Der folgende visuell interessante Code erstellt ein Backend, das vom torischen Code inspiriert ist. Anschließend können Sie das Backend mit den Funktionen aus dem Abschnitt [Visualisierung von Backends](#visualize-backends) visualisieren.\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: 548\n",
            "X gates: 139\n",
            "SX gates: 871\n",
            "RZ gates: 797\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
}