{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "710d86a8-3243-4133-b7bc-093306598512",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Einen benutzerdefinierten Transpiler-Pass schreiben\"\n",
        "description: \"Erfahren Sie, wie Sie mit Qiskit Ihren eigenen Transpiler-Pass schreiben, einschließlich der Darstellung von DAG-Schaltungen\"\n",
        "---\n",
        "\n",
        "<span id=\"write-a-custom-transpiler-pass\" />\n",
        "\n",
        "# Einen benutzerdefinierten Transpiler-Pass schreiben\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5a66bd4b-56b1-4f33-b1bf-b43dbc7c03a7",
      "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": "32806873-3c88-48fc-94ad-9d20e0f378f8",
      "metadata": {},
      "source": [
        "Mit dem Qiskit SDK können Sie benutzerdefinierte Transpilationspässe erstellen und sie im `PassManager` Objekt ausführen oder einem `StagedPassManager` hinzufügen. Hier wird demonstriert, wie man einen Transpiler-Pass schreibt, wobei der Schwerpunkt auf der Erstellung eines Passes liegt, der [Pauli-Twirling](https://arxiv.org/abs/quant-ph/0606161) an den verrauschten Quantengattern in einer Quantenschaltung durchführt. In diesem Beispiel wird die DAG verwendet, das Objekt, das durch den Durchgangstyp `TransformationPass` bearbeitet wird.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c49a2046-39b0-4e63-aa63-911845ffd315",
      "metadata": {},
      "source": [
        "<Accordion>\n",
        "  <AccordionItem title=\"Hintergrund: DAG-Darstellung\">\n",
        "    Bevor Sie einen Durchlauf bauen, ist es wichtig, die interne Darstellung von Quantenschaltungen in Qiskit, den [gerichteten azyklischen Graphen (DAG)](../api/qiskit/qiskit.dagcircuit.DAGCircuit), vorzustellen (siehe [dieses Tutorial](https://qiskit.org/ecosystem/rustworkx/tutorial/dags.html) für einen Überblick).  Um diese Schritte auszuführen, installieren Sie die [Bibliothek `graphviz` ](https://graphviz.org/download/) für die DAG-Darstellungsfunktionen.\n",
        "\n",
        "    In Qiskit werden Schaltungen innerhalb der Transpilierungsphasen mithilfe eines DAG dargestellt.  Im Allgemeinen besteht ein DAG aus *Knoten* (auch als „Nodes“ bezeichnet) und gerichteten *Kanten*, die Paare von Knoten in einer bestimmten Ausrichtung verbinden.  Diese Darstellung wird mithilfe von `qiskit.dagcircuit.DAGCircuit` Objekten gespeichert, die sich aus einzelnen `DagNode` Objekten zusammensetzen.  Der Vorteil dieser Darstellung gegenüber einer reinen Liste von Gattern (d. h. einer *Netzliste* ) besteht darin, dass der Informationsfluss zwischen den Operationen explizit ist, was die Entscheidungsfindung bei der Transformation erleichtert.\n",
        "\n",
        "    In diesem Beispiel wird die DAG durch eine einfache Schaltung veranschaulicht, die einen Bell-Zustand vorbereitet und je nach Messergebnis eine $R_Z$ Drehung vornimmt.\n",
        "\n",
        "    ```python\n",
        "    from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit\n",
        "    import numpy as np\n",
        "\n",
        "    qr = QuantumRegister(3, 'qr')\n",
        "    cr = ClassicalRegister(3, 'cr')\n",
        "    qc = QuantumCircuit(qr, cr)\n",
        "\n",
        "    qc.h(qr[0])\n",
        "    qc.cx(qr[0], qr[1])\n",
        "    qc.measure(qr[0], cr[0])\n",
        "    with qc.if_test((cr, 2)):\n",
        "        qc.rz(np.pi/2, qr[1])\n",
        "    qc.draw(output='mpl')\n",
        "\n",
        "    ```\n",
        "\n",
        "    ![Schaltung zur Vorbereitung eines Bell-Zustands und zur Anwendung einer R\\_Z-Drehung in Abhängigkeit vom Messergebnis.](https://quantum.cloud.ibm.com/docs/images/guides/custom-transpiler-pass/DAG_circ.avif \"Schaltung\")\n",
        "\n",
        "    Verwenden Sie die Funktion `qiskit.tools.visualization.dag_drawer()` , um die DAG dieser Schaltung anzuzeigen.  Es gibt drei Arten von Graphknoten: Qubit/Clbit-Knoten (grün), Operationsknoten (blau) und Ausgabeknoten (rot).  Jede Kante zeigt den Datenfluss (oder die Abhängigkeit) zwischen zwei Knoten an.\n",
        "\n",
        "    ```python\n",
        "    from qiskit.converters import circuit_to_dag\n",
        "    from qiskit.visualization import dag_drawer\n",
        "\n",
        "    dag = circuit_to_dag(qc)\n",
        "    dag_drawer(dag)\n",
        "    ```\n",
        "\n",
        "    ![Die DAG der Schaltung besteht aus Knoten, die durch gerichtete Kanten verbunden sind. Es handelt sich um eine visuelle Darstellung von Qubits oder klassischen Bits, den Operationen und der Art und Weise, wie Daten fließen.](https://quantum.cloud.ibm.com/docs/images/guides/custom-transpiler-pass/DAG.avif \"DAG\")\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7e2e2bc6-c900-4d3b-a948-3f5d154cdea2",
      "metadata": {},
      "source": [
        "<span id=\"transpiler-passes\" />\n",
        "\n",
        "## Transpiler-Durchläufe\n",
        "\n",
        "Transpiler-Durchläufe werden entweder als oder [`AnalysisPass`](../api/qiskit/qiskit.transpiler.AnalysisPass) als klassifiziert [`TransformationPass`](../api/qiskit/qiskit.transpiler.TransformationPass). Pässe arbeiten im Allgemeinen mit dem [DAG](../api/qiskit/qiskit.dagcircuit.DAGCircuit) und dem zusammen `property_set`, einem Wörterbuch-ähnlichen Objekt zum Speichern von Eigenschaften, die durch Analyse-Pässe bestimmt werden. Analyse-Passes funktionieren sowohl mit dem DAG als auch mit dessen `property_set`.  Sie können die DAG nicht ändern, aber sie können die `property_set`.  Im Gegensatz dazu verändern Transformationsdurchläufe den DAG und können darauf zugreifen (jedoch keine Änderungen vornehmen) `property_set`.  Beispielsweise wandeln Transformationsdurchläufe eine Schaltung in ihre [ISA](/docs/guides/transpile#instruction-set-architecture) um oder führen Routing-Durchläufe durch, um an den erforderlichen Stellen SWAP-Gatter einzufügen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f8ead728-b2b7-47b9-b3b1-f3578b594ffe",
      "metadata": {},
      "source": [
        "<span id=\"create-a-paulitwirl-transpiler-pass\" />\n",
        "\n",
        "## Erstellen Sie einen `PauliTwirl` Transpiler-Durchlauf\n",
        "\n",
        "Das folgende Beispiel konstruiert einen Transpiler-Durchgang, der Pauli-Wirbel hinzufügt. [Pauli-Twirling](https://arxiv.org/abs/quant-ph/0606161) ist eine Strategie zur Fehlerunterdrückung, die zufällig bestimmt, wie die Qubits verrauschte Kanäle wahrnehmen. In diesem Beispiel nehmen wir an, dass es sich dabei um Zwei-Qubit-Gatter handelt (weil diese viel fehleranfälliger sind als Ein-Qubit-Gatter). Die Pauli-Wirbel haben keinen Einfluss auf die Funktion der Zwei-Qubit-Tore. Sie sind so gewählt, dass diejenigen, die *vor dem* Zwei-Qubit-Gatter (links) angewendet werden, durch diejenigen, die *nach dem* Zwei-Qubit-Gatter (rechts) angewendet werden, ausgeglichen werden. In diesem Sinne sind die Zwei-Qubit-Operationen identisch, aber die Art und Weise, wie sie durchgeführt werden, ist unterschiedlich. Ein Vorteil des Pauli-Twirlings ist, dass es kohärente Fehler in stochastische Fehler umwandelt, die durch eine stärkere Mittelwertbildung verbessert werden können.\n",
        "\n",
        "Die Transpiler-Passagen wirken auf die [DAG](../api/qiskit/qiskit.dagcircuit.DAGCircuit), so dass die wichtigste Methode, die überschrieben werden muss, `.run()` ist, die die DAG als Eingabe erhält. Bei der Initialisierung von Paulis-Paaren bleibt die Funktion jedes Zwei-Qubit-Gatters erhalten. Dies geschieht mit der Hilfsmethode `build_twirl_set`, die jedes Zwei-Qubit-Pauli (wie von `pauli_basis(2)` erhalten) durchgeht und das andere Pauli findet, das die Operation bewahrt.\n",
        "\n",
        "Verwenden Sie in der DAG die Methode `op_nodes()` , um alle ihre Knoten zurückzugeben. Die DAG kann auch verwendet werden, um Läufe zu sammeln, d. h. Sequenzen von Knoten, die ohne Unterbrechung auf einem Qubit ablaufen. Diese können als Ein-Qubit-Läufe mit `collect_1q_runs`, Zwei-Qubit-Läufe mit `collect_2q_runs` und Läufe von Knoten, bei denen die Befehlsnamen in einer Namensliste stehen, mit `collect_runs` gesammelt werden.  `DAGCircuit` verfügt über zahlreiche Methoden zum Suchen und Durchlaufen eines Graphen.  Eine häufig verwendete Methode ist `topological_op_nodes`, die die Knoten in einer Abhängigkeitsordnung bereitstellt. Andere Methoden wie `bfs_successors` werden in erster Linie verwendet, um zu bestimmen, wie Knoten mit nachfolgenden Operationen auf einer DAG interagieren.\n",
        "\n",
        "In unserem Beispiel wollen wir jeden Knoten, der eine Anweisung darstellt, durch einen Teilschaltkreis ersetzen, der als Mini-DAG aufgebaut ist. Der Mini-DAG wurde um ein Zwei-Qubit-Quantenregister erweitert.  Die Operationen werden dem Mini-DAG durch die Verwendung von `apply_operation_back` hinzugefügt, wodurch `Instruction` auf dem Ausgang des Mini-DAG platziert wird (während `apply_operation_front` auf dem Eingang des Mini-DAG platziert würde). Der Knoten wird dann durch die Mini-DAG ersetzt, indem `substitute_node_with_dag` verwendet wird, und der Prozess wird über jede Instanz von `CXGate` und `ECRGate` in der DAG fortgesetzt (entsprechend den Zwei-Qubit-Basisgattern auf IBM® Backends).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "80546e59-dcd8-4b61-88b5-00b220409f6d",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.dagcircuit import DAGCircuit\n",
        "from qiskit.circuit import QuantumCircuit, QuantumRegister, Gate\n",
        "from qiskit.circuit.library import CXGate, ECRGate\n",
        "from qiskit.transpiler import PassManager\n",
        "from qiskit.transpiler.basepasses import TransformationPass\n",
        "from qiskit.quantum_info import Operator, pauli_basis\n",
        "\n",
        "import numpy as np\n",
        "\n",
        "from typing import Iterable, Optional"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "6bb6ff72-43dd-4f8c-a67c-b43af2548b2a",
      "metadata": {},
      "outputs": [],
      "source": [
        "class PauliTwirl(TransformationPass):\n",
        "    \"\"\"Add Pauli twirls to two-qubit gates.\"\"\"\n",
        "\n",
        "    def __init__(\n",
        "        self,\n",
        "        gates_to_twirl: Optional[Iterable[Gate]] = None,\n",
        "    ):\n",
        "        \"\"\"\n",
        "        Args:\n",
        "            gates_to_twirl: Names of gates to twirl. The default behavior is to twirl all\n",
        "                two-qubit basis gates, `cx` and `ecr` for IBM backends.\n",
        "        \"\"\"\n",
        "        if gates_to_twirl is None:\n",
        "            gates_to_twirl = [CXGate(), ECRGate()]\n",
        "        self.gates_to_twirl = gates_to_twirl\n",
        "        self.build_twirl_set()\n",
        "        super().__init__()\n",
        "\n",
        "    def build_twirl_set(self):\n",
        "        \"\"\"\n",
        "        Build a set of Paulis to twirl for each gate and store internally as .twirl_set.\n",
        "        \"\"\"\n",
        "        self.twirl_set = {}\n",
        "\n",
        "        # iterate through gates to be twirled\n",
        "        for twirl_gate in self.gates_to_twirl:\n",
        "            twirl_list = []\n",
        "\n",
        "            # iterate through Paulis on left of gate to twirl\n",
        "            for pauli_left in pauli_basis(2):\n",
        "                # iterate through Paulis on right of gate to twirl\n",
        "                for pauli_right in pauli_basis(2):\n",
        "                    # save pairs that produce identical operation as gate to twirl\n",
        "                    if (Operator(pauli_left) @ Operator(twirl_gate)).equiv(\n",
        "                        Operator(twirl_gate) @ pauli_right\n",
        "                    ):\n",
        "                        twirl_list.append((pauli_left, pauli_right))\n",
        "\n",
        "            self.twirl_set[twirl_gate.name] = twirl_list\n",
        "\n",
        "    def run(\n",
        "        self,\n",
        "        dag: DAGCircuit,\n",
        "    ) -> DAGCircuit:\n",
        "        # collect all nodes in DAG and proceed if it is to be twirled\n",
        "        twirling_gate_classes = tuple(\n",
        "            gate.base_class for gate in self.gates_to_twirl\n",
        "        )\n",
        "        for node in dag.op_nodes():\n",
        "            if not isinstance(node.op, twirling_gate_classes):\n",
        "                continue\n",
        "\n",
        "            # random integer to select Pauli twirl pair\n",
        "            pauli_index = np.random.randint(\n",
        "                0, len(self.twirl_set[node.op.name])\n",
        "            )\n",
        "            twirl_pair = self.twirl_set[node.op.name][pauli_index]\n",
        "\n",
        "            # instantiate mini_dag and attach quantum register\n",
        "            mini_dag = DAGCircuit()\n",
        "            register = QuantumRegister(2)\n",
        "            mini_dag.add_qreg(register)\n",
        "\n",
        "            # apply left Pauli, gate to twirl, and right Pauli to empty mini-DAG\n",
        "            mini_dag.apply_operation_back(\n",
        "                twirl_pair[0].to_instruction(), [register[0], register[1]]\n",
        "            )\n",
        "            mini_dag.apply_operation_back(node.op, [register[0], register[1]])\n",
        "            mini_dag.apply_operation_back(\n",
        "                twirl_pair[1].to_instruction(), [register[0], register[1]]\n",
        "            )\n",
        "\n",
        "            # substitute gate to twirl node with twirling mini-DAG\n",
        "            dag.substitute_node_with_dag(node, mini_dag)\n",
        "\n",
        "        return dag"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "da136beb-d1b2-4f68-8274-386e80a49860",
      "metadata": {},
      "source": [
        "<span id=\"use-the-paulitwirl-transpiler-pass\" />\n",
        "\n",
        "## Verwenden Sie den `PauliTwirl` Transpiler-Durchlauf\n",
        "\n",
        "Der folgende Code verwendet den oben erstellten Pass, um eine Schaltung zu transpilieren. Betrachten Sie eine einfache Schaltung mit `cx` und `ecr` Gattern.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "9123905d-b4cb-4ae9-9695-4ad77e70bdab",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/custom-transpiler-pass/extracted-outputs/9123905d-b4cb-4ae9-9695-4ad77e70bdab-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(3)\n",
        "qc.cx(0, 1)\n",
        "qc.ecr(1, 2)\n",
        "qc.ecr(1, 0)\n",
        "qc.cx(2, 1)\n",
        "qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f112c2af-c99a-4733-8118-4786e2dfdfd3",
      "metadata": {},
      "source": [
        "Um den benutzerdefinierten Durchgang anzuwenden, erstellen Sie einen Durchgangsmanager mit dem Durchgang `PauliTwirl` und lassen Sie ihn auf 50 Stromkreisen laufen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "ea884cd2-2446-4b2d-a0f7-82ef574b11ee",
      "metadata": {},
      "outputs": [],
      "source": [
        "pm = PassManager([PauliTwirl()])\n",
        "twirled_qcs = [pm.run(qc) for _ in range(50)]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3d4d921e-1a43-4f9a-bc30-6c64092d8f6b",
      "metadata": {},
      "source": [
        "Jedes Zwei-Qubit-Gate ist nun zwischen zwei Paulis eingebettet.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "e2515cf3-f8d9-4281-9673-d5a955d7aab9",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/custom-transpiler-pass/extracted-outputs/e2515cf3-f8d9-4281-9673-d5a955d7aab9-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "twirled_qcs[-1].draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "41cccfba-8b65-401c-9d30-66396a3fe3a1",
      "metadata": {},
      "source": [
        "Die Operatoren sind dieselben, wenn `Operator` von `qiskit.quantum_info` verwendet wird:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "0f8b4ca1-4205-4b71-941d-0852eebbe917",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "np.True_"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "np.all([Operator(twirled_qc).equiv(qc) for twirled_qc in twirled_qcs])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0d680854-13f8-4ccd-9be1-595edb4f942c",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Nächste Schritte\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Empfehlungen\">\n",
        "  * Wenn Sie wissen möchten, wie Sie die Funktion `generate_preset_passmanager` verwenden können, anstatt Ihre eigenen Pässe zu schreiben, beginnen Sie mit dem Thema [Transpilationsstandardeinstellungen und Konfigurationsoptionen](defaults-and-configuration-options).\n",
        "  * Probieren Sie die Anleitung [zum Vergleichen der Transpiler-Einstellungen](/docs/guides/circuit-transpilation-settings) aus.\n",
        "  * Lesen Sie [die Dokumentation zur Transpiler-API.](/docs/api/qiskit/transpiler)\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "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
}