{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "39a1fd9b-a17f-486e-aa7a-38d46b867984",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Dienstprogramm I\"\n",
        "description: \"In dieser Lektion führen wir einen Schaltkreis im Versorgungsmaßstab aus, der in dem von uns informell als „Utility Paper“ bezeichneten Artikel erscheint, der am 15. Juni 2023 in Nature, Band 618, veröffentlicht wurde.\"\n",
        "---\n",
        "\n",
        "<span id=\"utility-scale-experiment-i\" />\n",
        "\n",
        "# Experiment im Versorgungsmaßstab I\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  Tamiya Onodera (5. Juli 2024)\n",
        "\n",
        "  [Laden Sie die PDF-Datei](https://ibm.ent.box.com/public/static/k38xhk5yaqy9b3gjdmu0ynhnd9i4c3e1.zip) der Originalvorlesung herunter. Beachten Sie, dass einige Codeschnipsel veraltet sein könnten, da es sich um statische Bilder handelt.\n",
        "\n",
        "  *Die ungefähre QPU-Zeit für die Durchführung dieses Experiments beträgt 45 Sekunden.*\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "f0d73c71-11ba-4dcb-b230-ecea500e8732",
      "metadata": {},
      "source": [
        "<span id=\"1-introduction-to-the-utility-paper\" />\n",
        "\n",
        "## 1. Einführung in das Utility Paper\n",
        "\n",
        "In dieser Lektion führen wir eine Schaltung im Versorgungsbereich durch, die in der [Zeitschrift](https://www.nature.com/articles/s41586-023-06096-3) Nature Vol. 618 vom 15. Juni 2023 veröffentlicht wurde. Der Beitrag befasst sich mit der zeitlichen Entwicklung des 2D Transversalfeld-Ising-Modells. Sie berücksichtigen insbesondere die zeitliche Dynamik des Hamiltonianers,\n",
        "\n",
        "$$\n",
        "H = H_{ZZ} + H_X = - J \\sum_{(i,j)} Z_i Z_j + h \\sum_{i} X_i\n",
        "$$\n",
        "\n",
        "wobei $J > 0$ die Kopplung der nächstgelegenen Spins mit $i < j$ und $h$ das globale Transversalfeld ist.\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "c92cf6bb-df3e-4020-b980-edf17188e096",
      "metadata": {
        "jp-MarkdownHeadingCollapsed": true
      },
      "source": [
        "Sie simulieren die Spindynamik ausgehend von einem Anfangszustand mit Hilfe der Trotter-Zerlegung erster Ordnung des Zeitentwicklungsoperators,\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        " \\exp(-i H_{ZZ} \\delta t) &= \\prod_{(i,j)} \\exp (i J \\delta t Z_i Z_j)  = \\prod_{(i,j)} \\mathrm{R}_{Z_i Z_j} ( - 2 J \\delta t) \\\\\n",
        " \\exp(-i H_X \\delta t) &= \\prod_{i} \\exp (-i h \\delta t X_i )  = \\prod_{i} \\mathrm{R}_{X_i} ( 2 h \\delta t)\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n",
        "wobei die Entwicklungszeit $T$ in $T / \\delta t$ Trotter-Schritte diskretisiert ist und $\\mathrm{R}_{Z_i Z_j}(\\theta_J)$ und $\\mathrm{R}_{X_i}(\\theta_h)$ $ZZ$ bzw. $X$ Rotationstore sind.\n",
        "\n",
        "Sie führten Experimente auf einem IBM Quantum® Eagle-Prozessor durch, einem 127-Qubit-Gerät mit Heavy-Hex-Konnektivität, und wendeten $X$ Wechselwirkungen auf alle Qubits und $ZZ$ Wechselwirkungen auf alle Kanten der Kopplungskarte an.  Beachten Sie, dass aufgrund der \"Datenabhängigkeit\" nicht alle $ZZ$ Interaktionen gleichzeitig angewendet werden können.  Daher **färben sie die Kopplungskarte ein**, um sie in Schichten zu gruppieren. Die Elemente einer Ebene erhalten die gleiche Farbe und können parallel angewendet werden.\n",
        "\n",
        "Außerdem konzentrierten sie sich der Einfachheit halber auf den Fall $\\theta_J=-\\pi /2$.\n",
        "\n",
        "Der neuartige Beitrag der Arbeit besteht darin, dass sie Quantenschaltungen in einem Maßstab gebaut haben, der über die Zustandsvektorsimulation hinausgeht, sie auf verrauschten Quantencomputern betrieben haben und es ihnen gelungen ist, zuverlässige Ergebnisse zu erzielen. Das heißt, sie haben den Nutzen von verrauschten Quantencomputern demonstriert. Dabei wendeten sie die Null-Rausch-Extrapolation (ZNE) mit probabilistischer Fehlerverstärkung (PEA) an, um Fehler durch verrauschte Geräte abzuschwächen.\n",
        "\n",
        "Von da an nannten wir solche Experimente und Schaltungen \"utility-scale\".\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fcb359b4-469a-4e37-b260-8bf5044d1f60",
      "metadata": {},
      "source": [
        "<span id=\"11-your-goal\" />\n",
        "\n",
        "### 1.1 Ihr Ziel\n",
        "\n",
        "Das Ziel dieser Lektion ist es, einen Stromkreis zu bauen und ihn mit einem Eagle-Prozessor zu betreiben.  Es würde den Rahmen dieses Notizbuchs sprengen, verlässliche Ergebnisse zu liefern, zum einen, weil PEA zum Zeitpunkt der Erstellung dieses Dokuments eine experimentelle Funktion von Qiskit ist, und zum anderen, weil die Anwendung von ZNE mit PEA ziemlich viel Zeit in Anspruch nehmen wird.\n",
        "\n",
        "Konkret werden Sie gebeten, die Schaltung, die der Abbildung 4b des Papiers entspricht, zu bauen und zu betreiben und die \"unmitigated\" Punkte selbst zu zeichnen.  Wie Sie sehen, handelt es sich um eine 127-Qubit-Schaltung $\\times$ mit 60 Schichten (20 Trotter-Schritte) und der $\\langle Z_{62} \\rangle$ als Beobachtungsgröße.\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "a4aecf28-fc89-42db-ad8f-67e8afacff87",
      "metadata": {},
      "source": [
        "![image.png](https://quantum.cloud.ibm.com/learning/images/courses/utility-scale-quantum-computing/utility-i/utility1.avif)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b8c5a5ae-fc75-4fa9-9c70-2de36652f49a",
      "metadata": {},
      "source": [
        "Klingt das nach einer großen Sache? Keine Sorge. Die letzten drei Lektionen dieses Kurses sind Sprungbretter. Zu Beginn werden wir ein kleineres Experiment vorführen, bei dem ein 27-Qubit-Schaltkreis $\\times$ mit 6 Schichten (2 Trotter-Schritte) und der $\\langle Z_{13} \\rangle$ als Beobachtungsgröße auf einem gefälschten Gerät aufgebaut und betrieben wird.\n",
        "\n",
        "Das war's mit der Einführung. Begeben wir uns auf ein Abenteuer im Versorgungsbereich!\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "ad57179f-240e-441d-b2e4-e531cd192b45",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'2.0.2'"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit\n",
        "\n",
        "qiskit.__version__"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "35fff60f-7c73-4492-ace9-ecdc8fd33b0c",
      "metadata": {},
      "outputs": [],
      "source": [
        "#!pip install qiskit_ibm_runtime\n",
        "#!pip install qiskit_aer"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "2f7464cc-4190-400f-b947-4f38100b43d2",
      "metadata": {},
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "import rustworkx as rx\n",
        "\n",
        "from qiskit import QuantumCircuit, transpile\n",
        "from qiskit.circuit import Parameter\n",
        "from qiskit.circuit.library import YGate\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit_ibm_runtime import (\n",
        "    QiskitRuntimeService,\n",
        "    fake_provider,\n",
        "    EstimatorV2 as Estimator,\n",
        ")\n",
        "from qiskit_aer import AerSimulator"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "acd628f1-e010-44b7-ba77-cceb3b4198c6",
      "metadata": {},
      "outputs": [],
      "source": [
        "service = QiskitRuntimeService()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "06556d62-08bc-4c43-a7d0-382b73ec239a",
      "metadata": {},
      "source": [
        "<span id=\"2-preparation\" />\n",
        "\n",
        "## 2. Vorbereitung\n",
        "\n",
        "<span id=\"21-construct-rzz-$pi$-/-2\" />\n",
        "\n",
        "### 2.1 Konstruiere RZZ(- $\\pi$ /2)\n",
        "\n",
        "Zunächst ist zu beachten, dass das RZZ-Gatter im Allgemeinen zwei $CX$ -Gatter benötigt.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "d0b96520-3a4b-43c4-ade8-85cec68e3e09",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-i/extracted-outputs/d0b96520-3a4b-43c4-ade8-85cec68e3e09-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.circuit.library import RZZGate\n",
        "\n",
        "θ_h = Parameter(\"$\\\\theta_h$\")\n",
        "qc1 = QuantumCircuit(2)\n",
        "qc1.append(RZZGate(θ_h), [0, 1])\n",
        "qc1.decompose(reps=1).draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2770e3d2-d9d1-4bd5-8f00-8d8401f10438",
      "metadata": {},
      "source": [
        "Wie bereits erwähnt, konzentrieren wir uns in diesem Experiment auf das RZZ-Gate mit einem bestimmten Winkel, - $\\pi$ / 2.  Wie in der Arbeit gezeigt wird, kann dies mit nur einem $CX$ Gate realisiert werden.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "14b0ecb2-a8da-484a-bf49-606450bb074a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-i/extracted-outputs/14b0ecb2-a8da-484a-bf49-606450bb074a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc2 = QuantumCircuit(2)\n",
        "\n",
        "qc2.sdg([0, 1])\n",
        "qc2.append(YGate().power(1 / 2), [1])\n",
        "qc2.cx(0, 1)\n",
        "qc2.append(YGate().power(1 / 2).adjoint(), [1])\n",
        "\n",
        "qc2.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "269a5094-b4e6-4249-b9d5-ea25ded1767e",
      "metadata": {},
      "source": [
        "Wir definieren ein Gatter in Bezug auf diese Schaltung für zukünftige Referenzen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "2b5fbb1a",
      "metadata": {},
      "outputs": [],
      "source": [
        "rzz = qc2.to_gate(label=\"RZZ\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d89cccac-13a8-49b5-9dab-c1e98f9735c8",
      "metadata": {},
      "source": [
        "Lassen Sie uns eine zufällige Verwendung der neu definierten `rzz` vornehmen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "6753b9a4-90b1-4981-82b2-8177ac258af2",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-i/extracted-outputs/6753b9a4-90b1-4981-82b2-8177ac258af2-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "qc3 = QuantumCircuit(3)\n",
        "qc3.append(rzz, [0, 1])\n",
        "qc3.append(rzz, [0, 2])\n",
        "display(qc3.draw(\"mpl\"))\n",
        "# display(qc.decompose(reps=1).draw(\"mpl\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ed9c4589-c996-4199-8dd7-19e8d144a384",
      "metadata": {},
      "source": [
        "Bevor wir dies weiter verwenden, wollen wir die logische Äquivalenz von `qc1` (das RZZ-Gatter) für -pi/2 und unser neu definiertes `rzz` oder `qc2` Gatter überprüfen:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "b84c6f00-d50a-4874-9fa4-0c81742654e8",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "True"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.quantum_info import Operator\n",
        "\n",
        "op1 = Operator(qc1.assign_parameters([-np.pi / 2]))\n",
        "op2 = Operator(qc2)\n",
        "\n",
        "op1.equiv(op2)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ace1a98d-2ef7-4fe8-b67d-7799e7566f5a",
      "metadata": {},
      "source": [
        "<span id=\"22-color-the-coupling-map\" />\n",
        "\n",
        "### 2.2 Färben Sie die Kopplungskarte ein\n",
        "\n",
        "Lassen Sie uns untersuchen, wie wir die Kopplungskarte eines Backends einfärben.  Dies ist erforderlich, um die Interaktionen von $ZZ$ in Schichten zu gruppieren.\n",
        "\n",
        "Lassen Sie uns zunächst die Kopplungskarte eines Backends visualisieren.  Beachten Sie, dass die Kopplungskarten für alle aktuellen IBM Quantum-Geräte schwer-hexagonal sind.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "84e11b8e-bc74-4f3a-8538-d4d34d069e0f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-i/extracted-outputs/84e11b8e-bc74-4f3a-8538-d4d34d069e0f-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 10,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "backend = service.least_busy(operational=True, simulator=False)\n",
        "\n",
        "backend.coupling_map.draw()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a5fbfce4-c8cc-49fe-831d-31ad59f84c08",
      "metadata": {},
      "source": [
        "Zum Einfärben einer Kopplungskarte verwenden wir [rustworkx](https://www.rustworkx.org/), ein Python -Paket für die Arbeit mit Graphen und komplexen Netzwerken.  Es bietet mehrere Färbungsalgorithmen, die alle heuristisch sind und daher nicht garantieren, dass sie eine minimale Färbung finden.\n",
        "\n",
        "Da Heavy-Hex-Graphen bipartit sind, greifen wir auf [graph\\_bipartite\\_edge\\_color](https://www.rustworkx.org/apiref/rustworkx.graph_bipartite_edge_color.html) zurück, der eine minimale Färbung für diese Graphen finden sollte.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "79d3af17-efa0-4e48-89c5-ad9a962cf83b",
      "metadata": {
        "scrolled": true
      },
      "outputs": [],
      "source": [
        "def color_coupling_map(backend):\n",
        "    graph = backend.coupling_map.graph\n",
        "    undirected_graph = graph.to_undirected(multigraph=False)\n",
        "    edge_color_map = rx.graph_bipartite_edge_color(undirected_graph)\n",
        "    if edge_color_map is None:\n",
        "        edge_color_map = rx.graph_greedy_edge_color(undirected_graph)\n",
        "    # build a map from color to a list of edges\n",
        "    edge_index_map = undirected_graph.edge_index_map()\n",
        "    color_edges_map = {color: [] for color in edge_color_map.values()}\n",
        "    for edge_index, color in edge_color_map.items():\n",
        "        color_edges_map[color].append(\n",
        "            (edge_index_map[edge_index][0], edge_index_map[edge_index][1])\n",
        "        )\n",
        "    return edge_color_map, color_edges_map"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1a409faf-cb52-4c1c-95bd-beeca2cfd379",
      "metadata": {},
      "source": [
        "Schwere sechseckige Diagramme sollten in drei Farben gestrichen werden.  Überprüfen wir dies für die obige Kopplungskarte.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "5cf7f215-2155-498e-a8e8-acc51ccba363",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "ibm_strasbourg, 127-qubit device, 3 colors assigned.\n"
          ]
        }
      ],
      "source": [
        "edge_color_map, color_edges_map = color_coupling_map(backend)\n",
        "print(\n",
        "    f\"{backend.name}, {backend.num_qubits}-qubit device, {len(color_edges_map.keys())} colors assigned.\"\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "574bb71f-436e-499c-bb23-1adbab9445db",
      "metadata": {},
      "source": [
        "Ja, das ist sie!\n",
        "\n",
        "Lassen Sie uns zum Spaß die Kopplungskarte mit der erhaltenen Färbung malen, indem wir die Funktion der Rustworks-Visualisierung verwenden.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "fb9b6915-5ace-4104-b81d-91666e689f0d",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-i/extracted-outputs/fb9b6915-5ace-4104-b81d-91666e689f0d-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 13,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "color_str_map = {0: \"green\", 1: \"red\", 2: \"blue\"}\n",
        "\n",
        "undirected_graph = backend.coupling_map.graph.to_undirected(multigraph=False)\n",
        "for i in undirected_graph.edge_indices():\n",
        "    undirected_graph.get_edge_data_by_index(i)[\"color\"] = color_str_map[\n",
        "        edge_color_map[i]\n",
        "    ]\n",
        "\n",
        "rx.visualization.graphviz_draw(\n",
        "    undirected_graph, method=\"neato\", edge_attr_fn=lambda edge: {\"color\": edge[\"color\"]}\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4ae34f8d-6a46-4d81-bd0d-66a0d6fca588",
      "metadata": {},
      "source": [
        "<span id=\"3-solve-the-trotterized-time-evolution-of-a-2d-ising-model\" />\n",
        "\n",
        "## 3. Lösen Sie die Trotterisierte Zeitentwicklung eines Ising-Modells mit der Methode „ 2D “.\n",
        "\n",
        "Definieren wir eine Routine zur Konstruktion eines Schaltkreises des Gebrauchspapiers für die zeitliche Entwicklung eines 2D Ising-Modells.  Die Routine benötigt drei Parameter, ein Backend, eine ganze Zahl, die die Anzahl der Trotter-Schritte angibt, und einen booleschen Wert, der das Einfügen der Barriere steuert.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "b9d5dfd9-997f-4d8c-af1f-7927df31bffb",
      "metadata": {},
      "outputs": [],
      "source": [
        "def get_utility_circuit(backend, num_steps: int, barrier: bool = False):\n",
        "    num_qubits = backend.num_qubits\n",
        "    _, color_edges_map = color_coupling_map(backend)\n",
        "    θ_h = Parameter(\"$\\\\theta_h$\")\n",
        "    qc = QuantumCircuit(num_qubits)\n",
        "\n",
        "    for i in range(num_steps):\n",
        "        qc.rx(θ_h, range(num_qubits))\n",
        "\n",
        "        for _, edge_list in color_edges_map.items():\n",
        "            for edge in edge_list:\n",
        "                qc.append(rzz, edge)\n",
        "\n",
        "        if barrier:\n",
        "            qc.barrier()\n",
        "    return qc"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e6689c89-8321-44e8-8983-82d6b0735751",
      "metadata": {},
      "source": [
        "Bitte beachten Sie, dass wir die Zuordnung und das Routing der Qubits für die konstruierte Schaltung bereits manuell vorgenommen haben.  Wenn wir also die Schaltung später transpilieren, müssen (**sollten** ) wir den Transpiler nicht bitten, das Qubit-Mapping und Routing zu übernehmen. Wie Sie gleich sehen werden, rufen wir es mit der Optimierungsstufe 1 und der Layoutmethode \"trivial\" auf.\n",
        "\n",
        "Als Nächstes definieren wir eine einfache Routine, um die Informationen über die konstruierte Schaltung für eine schnelle Überprüfung zu erhalten.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "5c002120",
      "metadata": {},
      "outputs": [],
      "source": [
        "def get_circuit_info(qc: QuantumCircuit, reps: int = 0):\n",
        "    qc0 = qc.decompose(reps=reps)\n",
        "    return (\n",
        "        f\"{qc0.num_qubits} qubits × {qc0.depth(lambda x: x.operation.num_qubits == 2)} layers ({qc0.depth()}-depth)\"\n",
        "        + \",  \"\n",
        "        + f\"\"\"Gate breakdown: {\", \".join([f\"{k.upper()} {v}\" for k, v in qc0.count_ops().items()])}\"\"\"\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "30b69c52-09f0-4d5a-855c-e8f90acd0984",
      "metadata": {},
      "source": [
        "Lassen Sie uns diese Routinen üben.  Sie sollten einen Schaltkreis mit 27 Qubits sehen $\\times$ 15 Schichten (5 Trotter-Schritte). Da das gefälschte Gerät 28 Kanten hat, sollte es 28\\*5 Verschränkungslehren geben.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "af7bdb29-3bdb-4f6e-a53c-76ce935dff03",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-i/extracted-outputs/af7bdb29-3bdb-4f6e-a53c-76ce935dff03-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "27 qubits × 15 layers (20-depth),  Gate breakdown: CIRCUIT-165 140, RX 135, BARRIER 5\n",
            "27 qubits × 15 layers (60-depth),  Gate breakdown: SDG 280, UNITARY 280, CX 140, R 135, BARRIER 5\n"
          ]
        }
      ],
      "source": [
        "backend = fake_provider.FakeTorontoV2()\n",
        "num_steps = 5\n",
        "qc = get_utility_circuit(backend, num_steps, True)\n",
        "\n",
        "display(qc.draw(output=\"mpl\", fold=-1))\n",
        "print(get_circuit_info(qc, reps=0))\n",
        "print(get_circuit_info(qc, reps=1))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bf038a4d-4482-4368-8171-8cb4cd828c51",
      "metadata": {},
      "source": [
        "<span id=\"4-solve-the-27-qubit-version-of-the-problem\" />\n",
        "\n",
        "## 4. Lösen Sie die 27-Qubit-Version des Problems.\n",
        "\n",
        "Wir demonstrieren nun eine kleinere Version des Nutzenexperiments. Wir bauen einen 27-Qubit $\\times$ 6-Schicht-Schaltkreis (2 Trotter-Schritte) mit $\\langle Z_{13} \\rangle$ als Observable und lassen ihn sowohl auf AerSimulator als auch auf einem gefälschten Gerät laufen.\n",
        "\n",
        "Natürlich folgen wir unserem vierstufigen Workflow, dem \"Qiskit-Muster\", das aus Map, Optimize, Execute und Post-Process besteht. Konkreter,\n",
        "\n",
        "* Zuordnung klassischer Eingaben zu einer Quantenberechnung.\n",
        "* Optimierung von Schaltungen für Quantenberechnungen.\n",
        "* Ausführen von Schaltungen mit Hilfe von Primitiven.\n",
        "* Nachbearbeitung und Rückgabe der Ergebnisse im klassischen Format.\n",
        "\n",
        "Im Folgenden wird der Map-Schritt zur Erstellung einer Schaltung für ein kleineres Experiment beschrieben. Wir haben dann einen Satz von Optimize and Execute für AerSimulator und einen anderen für ein falsches Gerät.  Schließlich folgt der Post-Process-Schritt zur Darstellung der Ergebnisse.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ad5f3abd-0f25-47ec-9541-16fe83b7e710",
      "metadata": {},
      "source": [
        "<span id=\"41-step-1-map\" />\n",
        "\n",
        "### 4.1 Schritt 1: Karte\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "cd9c6774",
      "metadata": {},
      "outputs": [],
      "source": [
        "backend = fake_provider.FakeTorontoV2()  # a 27 qubit fake device.\n",
        "num_steps = 2\n",
        "qc = get_utility_circuit(backend, num_steps)\n",
        "obs = SparsePauliOp.from_sparse_list(\n",
        "    [(\"Z\", [13], 1)], num_qubits=backend.num_qubits\n",
        ")  # Falcon\n",
        "angles = [\n",
        "    0,\n",
        "    0.1,\n",
        "    0.2,\n",
        "    0.3,\n",
        "    0.4,\n",
        "    0.5,\n",
        "    0.6,\n",
        "    0.7,\n",
        "    0.8,\n",
        "    1.0,\n",
        "    np.pi / 2,\n",
        "]  # We try 11 angles for theta_h."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "81b39024-a7f4-4a7a-a543-59185def648b",
      "metadata": {},
      "source": [
        "<span id=\"42-steps-2-and-3-optimize-and-execute-simulator\" />\n",
        "\n",
        "### 4.2 Schritte 2 und 3: Optimieren und Ausführen (Simulator)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "id": "fa307165-fc74-4b6c-88c5-a2ac36341a3c",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "27 qubits × 6 layers (23-depth),  Gate breakdown: SDG 112, UNITARY 112, CX 56, R 54\n",
            "27 qubits × 6 layers (16-depth),  Gate breakdown: U3 80, CX 56, R 54, U1 32, U 28\n"
          ]
        }
      ],
      "source": [
        "backend_sim = AerSimulator()\n",
        "transpiled_qc_sim = transpile(\n",
        "    qc, backend_sim, optimization_level=1, layout_method=\"trivial\"\n",
        ")\n",
        "transpiled_obs_sim = obs.apply_layout(layout=transpiled_qc_sim.layout)\n",
        "\n",
        "print(get_circuit_info(qc, reps=1))\n",
        "print(get_circuit_info(transpiled_qc_sim, reps=1))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0a101b40-5555-41d9-96b2-a8c986ea9903",
      "metadata": {},
      "source": [
        "Ein Nutzer führte die nächste Zelle mit einem MacBook Pro mit 2.3 GHz Quad-Core Intel Core i7 Prozessor aus, der mit 32GB 3LPDDR4X RAM ausgestattet ist, auf dem macOS 14.5 läuft.  Es dauerte 161ms in Wandzeit. Jeder Laptop ist etwas anders.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "id": "178dd8c4-439b-4324-ba1f-687acc57a678",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "CPU times: user 231 ms, sys: 186 ms, total: 417 ms\n",
            "Wall time: 111 ms\n"
          ]
        }
      ],
      "source": [
        "%%time\n",
        "params = [[p] for p in angles]\n",
        "estimator = Estimator(mode=backend_sim)\n",
        "pub = (transpiled_qc_sim, transpiled_obs_sim, params)\n",
        "result_sim = estimator.run([pub]).result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "48b684f9-061a-49fd-acb1-3ed7b4bab1f2",
      "metadata": {},
      "source": [
        "<span id=\"43-steps-2-and-3-optimize-and-execute-fake-device\" />\n",
        "\n",
        "### 4.3 Schritte 2 und 3: Optimieren und ausführen (gefälschtes Gerät)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "f944eeae-8dc5-4ad6-97ad-92f95159956b",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "27 qubits × 6 layers (23-depth),  Gate breakdown: SDG 112, UNITARY 112, CX 56, R 54\n",
            "27 qubits × 6 layers (49-depth),  Gate breakdown: SDG 324, U1 274, H 162, CX 56, U3 14\n"
          ]
        }
      ],
      "source": [
        "backend_fake = fake_provider.FakeTorontoV2()\n",
        "transpiled_qc_fake = transpile(\n",
        "    qc, backend_fake, optimization_level=1, layout_method=\"trivial\"\n",
        ")\n",
        "transpiled_obs_fake = obs.apply_layout(layout=transpiled_qc_fake.layout)\n",
        "\n",
        "print(get_circuit_info(qc, reps=1))\n",
        "print(get_circuit_info(transpiled_qc_fake, reps=1))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "59adfdfb-0954-42f7-9dd2-c819d04264b6",
      "metadata": {},
      "source": [
        "Als derselbe Benutzer die nächste Zelle mit der gleichen Umgebung wie oben ausführte, benötigte er 2min 19s in Wall Time.  Die Ausführung einer Schaltung auf einem gefälschten Gerät führt zu einer verrauschten Simulation, die viel mehr Zeit in Anspruch nimmt als eine exakte Simulation.   Wir empfehlen, keine größeren Schaltungen (z. B. eine 27-Qubit-Schaltung $\\times$ 9 Schichten mit 3 Trotter-Schritten) auf einem gefälschten Gerät auszuführen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "id": "62d0e0bb-9acb-474a-8d19-b132013131a0",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "CPU times: user 4min 42s, sys: 9.35 s, total: 4min 51s\n",
            "Wall time: 38.3 s\n"
          ]
        }
      ],
      "source": [
        "%%time\n",
        "params = [[p] for p in angles]\n",
        "estimator = Estimator(mode=backend_fake)\n",
        "pub = (transpiled_qc_fake, transpiled_obs_fake, params)\n",
        "result_fake = estimator.run([pub]).result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "181e5f61-2830-485c-bd22-a1d70b443ed9",
      "metadata": {},
      "source": [
        "<span id=\"44-step-4-post-process\" />\n",
        "\n",
        "### 4.4 Schritt 4: Nachbearbeitung\n",
        "\n",
        "Wir stellen die Ergebnisse von exakten und verrauschten Simulationen dar. Sie sehen die gravierenden Auswirkungen von Lärm auf FakeToronto.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "id": "4cf3cad0-e720-469c-a9ed-e397dae0f2f6",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-i/extracted-outputs/4cf3cad0-e720-469c-a9ed-e397dae0f2f6-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(angles, result_fake[0].data.evs, \"o\", label=\"Fake Device\")\n",
        "plt.plot(angles, result_sim[0].data.evs, \"o\", label=\"AerSimulator\")\n",
        "plt.xlabel(\"$\\\\mathrm{R_x}$ angle $\\\\theta_h$\")\n",
        "plt.title(\"$\\\\langle Z_{13} \\\\rangle$\")\n",
        "plt.legend()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1b05966c-efe2-4eb4-b63c-43c07cf81f41",
      "metadata": {},
      "source": [
        "<span id=\"5-solve-the-127-qubit-version-of-the-problem\" />\n",
        "\n",
        "## 5. Lösen Sie die 127-Qubit-Version des Problems\n",
        "\n",
        "Ihr Ziel ist es, das eingangs erwähnte Experiment im Versorgungsmaßstab durchzuführen. Sie werden eine 127-Qubit- und 60-Schichten-Schaltung (20 Trotter-Schritte) mit $\\langle Z_{62} \\rangle$ als Observable erstellen und ausführen. Wir empfehlen Ihnen, dies selbst zu versuchen und dabei gegebenenfalls den Code für die 27-Qubit-Version zu verwenden. Aber die Lösung ist hier zu finden.\n",
        "\n",
        "**Lösung:**\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a18a42dd-5891-4b5f-8c3b-1bc7e1ae4a5e",
      "metadata": {},
      "source": [
        "<span id=\"51-step-1-map\" />\n",
        "\n",
        "### 5.1 Schritt 1: Karte\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "8b900d9a-0351-426a-b25b-19e631fd257e",
      "metadata": {},
      "outputs": [],
      "source": [
        "# backend_map = service.backend(\"ibm_brisbane\")\n",
        "backend_map = service.least_busy(operational=True, simulator=False)\n",
        "\n",
        "num_steps = 20\n",
        "qc = get_utility_circuit(backend_map, num_steps)\n",
        "obs = SparsePauliOp.from_sparse_list(\n",
        "    [(\"Z\", [62], 1)], num_qubits=backend_map.num_qubits\n",
        ")  # Eagle\n",
        "angles = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 1.0, np.pi / 2]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "51ea0288-d8e9-4ee1-bbe8-dc24826a5026",
      "metadata": {},
      "source": [
        "<span id=\"52-steps-2-and-3-optimize-and-execute\" />\n",
        "\n",
        "### 5.2 Schritte 2 und 3: Optimieren und ausführen\n",
        "\n",
        "Wir stellen fest, dass die Kopplungskarte des Eagle-Prozessors 144 Kanten hat.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "f9fadf76-48e3-43a3-b773-8fa3b5fd5f3d",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "156 qubits × 60 layers (221-depth),  Gate breakdown: SDG 7040, UNITARY 7040, CX 3520, R 3120\n",
            "156 qubits × 60 layers (201-depth),  Gate breakdown: RZ 11933, SX 6240, CZ 3520\n"
          ]
        }
      ],
      "source": [
        "# backend = service.backend(\"ibm_brisbane\")\n",
        "backend = backend_map\n",
        "\n",
        "transpiled_qc = transpile(qc, backend, optimization_level=1, layout_method=\"trivial\")\n",
        "transpiled_obs = obs.apply_layout(layout=transpiled_qc.layout)\n",
        "\n",
        "print(get_circuit_info(qc, reps=1))\n",
        "print(get_circuit_info(transpiled_qc))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "id": "2ddff1e1-c868-4300-bdbb-cdd3b6932302",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "job id=d1479n6qf56g0081sxa0\n"
          ]
        }
      ],
      "source": [
        "params = [[p] for p in angles]\n",
        "estimator = Estimator(mode=backend)\n",
        "pub = (transpiled_qc, transpiled_obs, params)\n",
        "job = estimator.run([pub])\n",
        "\n",
        "job_id = job.job_id()\n",
        "print(f\"job id={job_id}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c497fc9d-aa58-4eb2-851e-369c7209da97",
      "metadata": {},
      "source": [
        "<span id=\"53-post-process\" />\n",
        "\n",
        "### 5.3 Nachbearbeitung\n",
        "\n",
        "Die Werte für die \"entschärften\" Punkte finden Sie in Abbildung 4b im Utility Paper.   Stellen Sie diese zusammen mit Ihren Ergebnissen dar.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 28,
      "id": "1c4ede0c-e865-41fe-9b38-8ecf39afa64f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-i/extracted-outputs/1c4ede0c-e865-41fe-9b38-8ecf39afa64f-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "result_paper = [\n",
        "    1.0171,\n",
        "    1.0044,\n",
        "    0.9563,\n",
        "    0.9602,\n",
        "    0.8394,\n",
        "    0.8120,\n",
        "    0.5466,\n",
        "    0.4556,\n",
        "    0.1953,\n",
        "    0.0141,\n",
        "    0.0117,\n",
        "]\n",
        "\n",
        "# REPLACE WITH YOUR OWN JOB ID\n",
        "job = service.job(job_id)\n",
        "\n",
        "plt.plot(angles, job.result()[0].data.evs, \"o\", label=f\"{job.backend().name}\")\n",
        "plt.plot(angles, result_paper, \"o\", label=\"Utility Paper\")\n",
        "plt.xlabel(\"$\\\\mathrm{R_x}$ angle $\\\\theta_h$\")\n",
        "plt.title(\"$\\\\langle Z_{62} \\\\rangle$\")\n",
        "plt.legend()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7fb3e103-af1d-4a9f-8016-1a270c5706be",
      "metadata": {},
      "source": [
        "Sind Ihre Ergebnisse ähnlich wie die \"ungemilderten\" in Abbildung 4b? Je nach Gerät und dessen Zustand zum Zeitpunkt des Experiments können sie sehr unterschiedlich sein.  Machen Sie sich keine Gedanken über die Ergebnisse selbst. Wir prüfen, ob Sie die Kodierung korrekt vorgenommen haben.  Wenn Sie das getan haben, herzlichen Glückwunsch, dann haben Sie die Startlinie der Ära der Versorgungsunternehmen erreicht.\n",
        "\n",
        "Wie in der Studie \"Utility\" haben Wissenschaftler aus aller Welt einen enormen Einfallsreichtum an den Tag gelegt, um selbst bei Rauschen aussagekräftige Ergebnisse zu erhalten. Das Endziel dieser kollektiven Bemühungen ist der Quantenvorteil: ein Zustand, in dem Quantencomputer einige Probleme, die in der Industrie gebraucht werden, schneller, mit höherer Genauigkeit oder billiger lösen können als klassische Computer. Dabei handelt es sich wahrscheinlich nicht um ein einmaliges Ereignis, sondern eher um eine Ära, in der die klassische Reproduktion von Quantenergebnissen immer länger dauert, bis irgendwann die Quantenvorlaufzeit von entscheidender Bedeutung wird. In Bezug auf den Quantenvorteil ist eines klar: Wir erreichen ihn nur durch Experimente im praktischen Maßstab.  Wenn dieser Kurs dazu führt, dass Sie sich an der Suche beteiligen, die voller Herausforderungen und Spaß ist, würden wir uns sehr freuen.\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "a346d104-299e-4152-a8ea-5e297d05b6a1",
      "metadata": {},
      "source": [
        "<span id=\"reference\" />\n",
        "\n",
        "## Referenz\n",
        "\n",
        "* Kim, Y., Eddins, A., Anand, S. et al. Beweis für den Nutzen von Quantencomputing vor Fehlertoleranz. Nature 618, 500-505 (2023). [https://doi.org/10.1038/s41586-023-06096-3](https://doi.org/10.1038/s41586-023-06096-3)\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"
    },
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "state": {},
        "version_major": 2,
        "version_minor": 0
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}