{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "4cb32582",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Arbeiten mit DAGs in Transpiler-Durchläufen\"\n",
        "description: \"Verwendung gerichteter azyklischer Graphen (DAGs) zur Analyse und Transformation von Quantenschaltungen in Qiskit-Transpiler-Durchläufen\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore subdag DAGOpNode qargs cargs dag_drawer couplinglist */}\n",
        "\n",
        "<span id=\"work-with-dags-in-transpiler-passes\" />\n",
        "\n",
        "# Arbeiten mit DAGs in Transpiler-Durchläufen\n",
        "\n",
        "In Qiskit werden die Schaltkreise in den Umsetzungsphasen durch ein DAG dargestellt. Im Allgemeinen besteht ein DAG aus Knoten (auch \"Nodes\" genannt) und gerichteten Kanten, die Paare von Knoten in einer bestimmten Ausrichtung verbinden. Diese Darstellung wird über `qiskit.dagcircuit.DAGCircuit` Objekte gespeichert, die aus einzelnen `DagNode` Objekten bestehen. 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 es einfacher macht, Transformationsentscheidungen zu treffen.\n",
        "\n",
        "Dieser Leitfaden zeigt, wie man mit DAGs arbeitet und sie zum Schreiben von benutzerdefinierten Transpilerübergängen verwendet. Er beginnt mit dem Aufbau einer einfachen Schaltung und der Untersuchung ihrer DAG-Darstellung, erforscht dann grundlegende DAG-Operationen und implementiert einen benutzerdefinierten `BasicMapper` -Durchlauf.\n",
        "\n",
        "<span id=\"build-a-circuit-and-examine-its-dag\" />\n",
        "\n",
        "## Eine Schaltung aufbauen und ihren DAG untersuchen\n",
        "\n",
        "Der folgende Codeschnipsel veranschaulicht die DAG, indem er eine einfache Schaltung erstellt, die einen Bell-Zustand vorbereitet und je nach Messergebnis eine $R_Z$ Drehung anwendet.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "version-info-cell",
      "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": "code",
      "execution_count": 1,
      "id": "1d16892a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/DAG-representation/extracted-outputs/1d16892a-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit\n",
        "from qiskit.converters import circuit_to_dag\n",
        "from qiskit.visualization import circuit_drawer\n",
        "from qiskit.visualization.dag_visualization import dag_drawer\n",
        "\n",
        "# Create circuit\n",
        "q = QuantumRegister(3, \"q\")\n",
        "c = ClassicalRegister(3, \"c\")\n",
        "circ = QuantumCircuit(q, c)\n",
        "circ.h(q[0])\n",
        "circ.cx(q[0], q[1])\n",
        "circ.measure(q[0], c[0])\n",
        "\n",
        "# Qiskit 2.0 uses if_test instead of c_if\n",
        "with circ.if_test((c, 2)):\n",
        "    circ.rz(0.5, q[1])\n",
        "\n",
        "circuit_drawer(circ, output=\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5971b6ed",
      "metadata": {},
      "source": [
        "In der DAG gibt es drei Arten von Graphknoten: Qubit/Clbit-Eingangsknoten (grün), Operationsknoten (blau) und Ausgangsknoten (rot). Jede Kante zeigt den Datenfluss (oder die Abhängigkeit) zwischen zwei Knoten an. Verwenden Sie die Funktion qiskit.tools.visualization.dag\\_drawer (), um die DAG dieser Schaltung anzuzeigen. (Installieren Sie die [Graphviz-Bibliothek](https://graphviz.org/download/), um dies auszuführen.)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "e498faa3",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/DAG-representation/extracted-outputs/e498faa3-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Convert to DAG\n",
        "dag = circuit_to_dag(circ)\n",
        "dag_drawer(dag)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3b728136",
      "metadata": {},
      "source": [
        "<span id=\"basic-dag-operations\" />\n",
        "\n",
        "## Grundlegende DAG-Operationen\n",
        "\n",
        "Die folgenden Code-Beispiele demonstrieren gängige Operationen mit DAGs, einschließlich des Zugriffs auf Knoten, Hinzufügen von Operationen und Ersetzen von Teilschaltungen. Diese Operationen bilden die Grundlage für die Erstellung von Transpilerpässen.\n",
        "\n",
        "<span id=\"get-all-operation-nodes-in-the-dag\" />\n",
        "\n",
        "## Alle Betriebsknoten im DAG abrufen\n",
        "\n",
        "Die Methode `op_nodes()` gibt eine iterierbare Liste der `DAGOpNode` Objekte im Stromkreis zurück:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "4f848695",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[DAGOpNode(op=Instruction(name='h', num_qubits=1, num_clbits=0, params=[]), qargs=(<Qubit register=(3, \"q\"), index=0>,), cargs=()),\n",
              " DAGOpNode(op=Instruction(name='cx', num_qubits=2, num_clbits=0, params=[]), qargs=(<Qubit register=(3, \"q\"), index=0>, <Qubit register=(3, \"q\"), index=1>), cargs=()),\n",
              " DAGOpNode(op=Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), qargs=(<Qubit register=(3, \"q\"), index=0>,), cargs=(<Clbit register=(3, \"c\"), index=0>,)),\n",
              " DAGOpNode(op=Instruction(name='if_else', num_qubits=1, num_clbits=3, params=[<qiskit.circuit.quantumcircuit.QuantumCircuit object at 0x12559c410>, None]), qargs=(<Qubit register=(3, \"q\"), index=1>,), cargs=(<Clbit register=(3, \"c\"), index=0>, <Clbit register=(3, \"c\"), index=1>, <Clbit register=(3, \"c\"), index=2>))]"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "dag.op_nodes()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8f2676b9",
      "metadata": {},
      "source": [
        "Jeder Knoten ist eine Instanz der Klasse `DAGOpNode` :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "5866159f",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "node name: if_else\n",
            "op: Instruction(name='if_else', num_qubits=1, num_clbits=3, params=[<qiskit.circuit.quantumcircuit.QuantumCircuit object at 0x12559f490>, None])\n",
            "qargs: (<Qubit register=(3, \"q\"), index=1>,)\n",
            "cargs: (<Clbit register=(3, \"c\"), index=0>, <Clbit register=(3, \"c\"), index=1>, <Clbit register=(3, \"c\"), index=2>)\n",
            "condition: (ClassicalRegister(3, 'c'), 2)\n"
          ]
        }
      ],
      "source": [
        "node = dag.op_nodes()[3]\n",
        "print(\"node name:\", node.name)\n",
        "print(\"op:\", node.op)\n",
        "print(\"qargs:\", node.qargs)\n",
        "print(\"cargs:\", node.cargs)\n",
        "print(\"condition:\", node.op.condition)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f2560cc1",
      "metadata": {},
      "source": [
        "<span id=\"add-an-operation-to-the-back\" />\n",
        "\n",
        "## Eine Operation hinzufügen\n",
        "\n",
        "Am Ende des DAGCircuit wird mit der Methode `apply_operation_back()` ein Vorgang hinzugefügt. Damit wird das angegebene Gatter an die angegebenen Qubits angehängt, um nach allen bestehenden Operationen in der Schaltung zu wirken.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "3c144b49",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/DAG-representation/extracted-outputs/3c144b49-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.circuit.library import HGate\n",
        "\n",
        "dag.apply_operation_back(HGate(), qargs=[q[0]])\n",
        "dag_drawer(dag)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "80af1d3d",
      "metadata": {},
      "source": [
        "<span id=\"add-an-operation-to-the-front\" />\n",
        "\n",
        "## Eine Operation an den Anfang hinzufügen\n",
        "\n",
        "Am Anfang des DAGCircuit wird mit der Methode `apply_operation_front()` eine Operation hinzugefügt. Dadurch wird das angegebene Gatter vor allen bestehenden Operationen in der Schaltung eingefügt, so dass es effektiv die erste ausgeführte Operation ist.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "ed80a69f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/DAG-representation/extracted-outputs/ed80a69f-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.circuit.library import CCXGate\n",
        "\n",
        "dag.apply_operation_front(CCXGate(), qargs=[q[0], q[1], q[2]])\n",
        "dag_drawer(dag)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4bcdf5fe",
      "metadata": {},
      "source": [
        "<span id=\"substitute-a-node-with-a-subcircuit\" />\n",
        "\n",
        "## Ersetzen Sie einen Knoten durch eine Teilschaltung\n",
        "\n",
        "Ein Knoten, der eine bestimmte Operation im DAGCircuit repräsentiert, wird durch einen Subcircuit ersetzt. Zunächst wird eine neue Unter-DAG mit der gewünschten Folge von Gattern konstruiert, dann wird der Zielknoten mit Hilfe von `substitute_node_with_dag()` durch diese Unter-DAG ersetzt, wobei die Verbindungen zum Rest der Schaltung erhalten bleiben.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "fdb3dd70",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/DAG-representation/extracted-outputs/fdb3dd70-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.dagcircuit import DAGCircuit\n",
        "from qiskit.circuit.library import CHGate, U2Gate, CXGate\n",
        "\n",
        "# Build sub-DAG\n",
        "mini_dag = DAGCircuit()\n",
        "p = QuantumRegister(2, \"p\")\n",
        "mini_dag.add_qreg(p)\n",
        "mini_dag.apply_operation_back(CHGate(), qargs=[p[1], p[0]])\n",
        "mini_dag.apply_operation_back(U2Gate(0.1, 0.2), qargs=[p[1]])\n",
        "\n",
        "# Replace CX with mini_dag\n",
        "cx_node = dag.op_nodes(op=CXGate).pop()\n",
        "dag.substitute_node_with_dag(cx_node, mini_dag, wires=[p[0], p[1]])\n",
        "dag_drawer(dag)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "028566f7",
      "metadata": {},
      "source": [
        "Nachdem alle Transformationen abgeschlossen sind, kann die DAG wieder in ein reguläres `QuantumCircuit` Objekt umgewandelt werden. So funktioniert die Transpiler-Pipeline. Ein Schaltkreis wird genommen, in DAG-Form verarbeitet und ein transformierter Schaltkreis wird als Ausgabe erzeugt.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "786571f7",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/DAG-representation/extracted-outputs/786571f7-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.converters import dag_to_circuit\n",
        "\n",
        "new_circ = dag_to_circuit(dag)\n",
        "circuit_drawer(new_circ, output=\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f743bb3b",
      "metadata": {},
      "source": [
        "<span id=\"implement-a-basicmapper-pass\" />\n",
        "\n",
        "## BasicMapper -Pass implementieren\n",
        "\n",
        "Die DAG-Struktur kann für das Schreiben von Transpilerübergängen genutzt werden. Im folgenden Beispiel wird ein `BasicMapper` Durchgang implementiert, um eine beliebige Schaltung auf ein Gerät mit eingeschränkter Qubit-Konnektivität abzubilden. Weitere Anleitungen finden Sie im Leitfaden zum [Schreiben benutzerdefinierter Transpilerübergänge](/docs/guides/custom-transpiler-pass).\n",
        "\n",
        "Der Pass ist als `TransformationPass` definiert, was bedeutet, dass er den Stromkreis verändert. Dazu wird die DAG Schicht für Schicht durchlaufen und geprüft, ob jede Anweisung die von der Kopplungskarte des Geräts auferlegten Beschränkungen erfüllt. Wird ein Verstoß festgestellt, wird ein Swap-Pfad ermittelt und die erforderlichen SWAP-Gates werden entsprechend eingefügt.\n",
        "\n",
        "Bei der Erstellung eines Transpiler-Passes muss zunächst entschieden werden, ob der Pass von `TransformationPass` oder `AnalysisPass` erben soll. Transformationsdurchgänge dienen dazu, die Schaltung zu verändern, während Analysedurchgänge nur dazu dienen, Informationen zu extrahieren, die von nachfolgenden Durchgängen verwendet werden können. Die Hauptfunktionalität wird dann in der Methode `run(dag)` implementiert. Schließlich sollte der Pass im Modul `qiskit.transpiler.passes` registriert werden.\n",
        "\n",
        "In diesem speziellen Durchgang wird die DAG Schicht für Schicht durchlaufen (wobei jede Schicht Operationen enthält, die auf disjunkte Mengen von Qubits wirken und daher unabhängig voneinander ausgeführt werden können). Wenn die Bedingungen der Kopplungskarte nicht erfüllt sind, wird für jede Operation ein geeigneter Tauschpfad ermittelt, und die erforderlichen Tauschvorgänge werden eingefügt, um die beteiligten Qubits in Nachbarschaft zu bringen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "8c0d7e5a",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.transpiler.basepasses import TransformationPass\n",
        "from qiskit.transpiler import Layout\n",
        "from qiskit.circuit.library import SwapGate\n",
        "\n",
        "\n",
        "class BasicSwap(TransformationPass):\n",
        "    def __init__(self, coupling_map, initial_layout=None):\n",
        "        super().__init__()\n",
        "        self.coupling_map = coupling_map\n",
        "        self.initial_layout = initial_layout\n",
        "\n",
        "    def run(self, dag):\n",
        "        new_dag = DAGCircuit()\n",
        "        for qreg in dag.qregs.values():\n",
        "            new_dag.add_qreg(qreg)\n",
        "        for creg in dag.cregs.values():\n",
        "            new_dag.add_creg(creg)\n",
        "\n",
        "        if self.initial_layout is None:\n",
        "            self.initial_layout = Layout.generate_trivial_layout(\n",
        "                *dag.qregs.values()\n",
        "            )\n",
        "\n",
        "        current_layout = self.initial_layout.copy()\n",
        "\n",
        "        for layer in dag.serial_layers():\n",
        "            subdag = layer[\"graph\"]\n",
        "            for gate in subdag.two_qubit_ops():\n",
        "                q0, q1 = gate.qargs\n",
        "                p0 = current_layout[q0]\n",
        "                p1 = current_layout[q1]\n",
        "\n",
        "                if self.coupling_map.distance(p0, p1) != 1:\n",
        "                    path = self.coupling_map.shortest_undirected_path(p0, p1)\n",
        "                    for i in range(len(path) - 2):\n",
        "                        wire1, wire2 = path[i], path[i + 1]\n",
        "                        qubit1 = current_layout[wire1]\n",
        "                        qubit2 = current_layout[wire2]\n",
        "                        new_dag.apply_operation_back(\n",
        "                            SwapGate(), qargs=[qubit1, qubit2]\n",
        "                        )\n",
        "                        current_layout.swap(wire1, wire2)\n",
        "\n",
        "            new_dag.compose(\n",
        "                subdag, qubits=current_layout.reorder_bits(new_dag.qubits)\n",
        "            )\n",
        "\n",
        "        return new_dag"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4a95eaab",
      "metadata": {},
      "source": [
        "Der Durchgang kann nun an einer kleinen Beispielschaltung getestet werden. Es wird ein Passmanager erstellt, der den neu definierten Pass enthält. Die Beispielschaltung wird dann an diesen Passmanager weitergegeben, und als Ergebnis erhält man eine neue, transformierte Schaltung.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "2f35375f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/DAG-representation/extracted-outputs/2f35375f-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 10,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.transpiler import CouplingMap, PassManager\n",
        "from qiskit import QuantumRegister, QuantumCircuit\n",
        "\n",
        "q = QuantumRegister(7, \"q\")\n",
        "in_circ = QuantumCircuit(q)\n",
        "in_circ.h(q[0])\n",
        "in_circ.cx(q[0], q[4])\n",
        "in_circ.cx(q[2], q[3])\n",
        "in_circ.cx(q[6], q[1])\n",
        "in_circ.cx(q[5], q[0])\n",
        "in_circ.rz(0.1, q[2])\n",
        "in_circ.cx(q[5], q[0])\n",
        "\n",
        "coupling = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6]]\n",
        "coupling_map = CouplingMap(couplinglist=coupling)\n",
        "\n",
        "pm = PassManager()\n",
        "pm.append(BasicSwap(coupling_map))\n",
        "\n",
        "out_circ = pm.run(in_circ)\n",
        "\n",
        "in_circ.draw(output=\"mpl\")\n",
        "out_circ.draw(output=\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "56b80ce3",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Nächste Schritte\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Empfehlungen\">\n",
        "  * Lesen Sie die Anleitung zum Erstellen eines [benutzerdefinierten Transpiler-Durchlaufs](/docs/guides/custom-transpiler-pass)\n",
        "  * Erfahren Sie, wie Sie [Projekte erstellen und für benutzerdefinierte Backends transpilieren](/docs/guides/custom-backend)\n",
        "  * Probieren Sie die Anleitung [zum Vergleichen der Transpiler-Einstellungen](/docs/guides/circuit-transpilation-settings) aus.\n",
        "  * Lesen Sie die [Dokumentation zur DAG Circuit API](/docs/api/qiskit/dagcircuit).\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": 5
}