{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "fad91a68",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Fehlerbehebung\"\n",
        "description: \"In dieser Lektion werden wir uns mit Rauschen befassen und untersuchen, wie es auf Quantencomputern gemindert werden kann.\"\n",
        "---\n",
        "\n",
        "<span id=\"quantum-noise-and-error-mitigation\" />\n",
        "\n",
        "# Quantenrauschen und Fehlerminderung\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  Toshinari Itoko (28. Juni 2024)\n",
        "\n",
        "  [Laden Sie die PDF-Datei](https://ibm.ent.box.com/public/static/a0zgies7bh91hm2lwev9o0bfeybxc6n6.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 1 m 40 s.*\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e936adb0-bc31-41a8-b988-02ce7e68b902",
      "metadata": {},
      "source": [
        "<span id=\"1-introduction\" />\n",
        "\n",
        "## 1. Einführung\n",
        "\n",
        "In dieser Lektion werden wir uns mit dem Rauschen befassen und damit, wie es auf Quantencomputern gemildert werden kann. Zunächst werden wir die Auswirkungen des Rauschens mit Hilfe eines Simulators untersuchen, der das Rauschen auf verschiedene Weise simulieren kann, u. a. mit Rauschprofilen von echten Quantencomputern. Dann werden wir zu echten Quantencomputern übergehen, bei denen das Rauschen inhärent ist. Wir werden uns mit den Auswirkungen der Fehlerminderung befassen, einschließlich Kombinationen von Dingen wie Null-Rausch-Extrapolation (ZNE) und Gate-Twirling.\n",
        "\n",
        "Wir beginnen mit dem Laden einiger Pakete.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "38cf024b",
      "metadata": {},
      "outputs": [],
      "source": [
        "# !pip install qiskit qiskit_aer qiskit_ibm_runtime\n",
        "# !pip install jupyter\n",
        "# !pip install matplotlib pylatexenc"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "897008ea",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'2.0.2'"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit\n",
        "\n",
        "qiskit.__version__"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "486b4d35",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'0.17.1'"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit_aer\n",
        "\n",
        "qiskit_aer.__version__"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "994c44e5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'0.40.1'"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit_ibm_runtime\n",
        "\n",
        "qiskit_ibm_runtime.__version__"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ee48a826-fda3-4fb4-b50b-d69c38eb887f",
      "metadata": {
        "editable": true,
        "slideshow": {
          "slide_type": "slide"
        },
        "tags": []
      },
      "source": [
        "<span id=\"2-noisy-simulation-without-error-mitigation\" />\n",
        "\n",
        "## 2. Laute Simulation ohne Fehlerminderung\n",
        "\n",
        "Qiskit Aer ist ein klassischer Simulator für Quantencomputer. Es kann nicht nur die ideale Ausführung, sondern auch die verrauschte Ausführung von Quantenschaltungen simulieren. Dieses Notizbuch zeigt, wie man mit Qiskit Aer eine Rauschsimulation durchführt:\n",
        "\n",
        "1. Erstellen eines Lärmmodells\n",
        "2. Erstellen eines verrauschten Samplers (Simulators) mit dem Rauschmodell\n",
        "3. Führen Sie eine Quantenschaltung auf dem verrauschten Probenehmer aus\n",
        "\n",
        "```\n",
        "noise_model = NoiseModel()\n",
        "...\n",
        "noisy_sampler = Sampler(options={\"backend_options\": {\"noise_model\": noise_model}})\n",
        "job = noisy_sampler.run([circuit])\n",
        "```\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d1490ab8",
      "metadata": {},
      "source": [
        "<span id=\"21-build-a-test-circuit\" />\n",
        "\n",
        "### 2.1 Eine Testschaltung aufbauen\n",
        "\n",
        "Wir betrachten Spielzeug-1-Qubit-Schaltungen, die einfach X Gatter `d` mal wiederholen (`d`=0... 100) und messen Sie die `Z` beobachtbar.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "b4863c66",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/b4863c66-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "from qiskit.circuit import QuantumCircuit\n",
        "\n",
        "MAX_DEPTH = 100\n",
        "circuits = []\n",
        "for d in range(MAX_DEPTH + 1):\n",
        "    circ = QuantumCircuit(1)\n",
        "    for _ in range(d):\n",
        "        circ.x(0)\n",
        "        circ.barrier(0)\n",
        "    circ.measure_all()\n",
        "    circuits.append(circ)\n",
        "\n",
        "display(circuits[3].draw(output=\"mpl\"))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "a366502c",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "SparsePauliOp(['Z'],\n",
              "              coeffs=[1.+0.j])"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.quantum_info import SparsePauliOp\n",
        "\n",
        "obs = SparsePauliOp.from_list([(\"Z\", 1.0)])\n",
        "obs"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6200c2ed",
      "metadata": {},
      "source": [
        "<span id=\"22-build-a-noise-model\" />\n",
        "\n",
        "### 2.2 Ein Geräuschmodell erstellen\n",
        "\n",
        "Um eine Rauschsimulation durchzuführen, müssen wir `NoiseModel` angeben. In diesem Abschnitt zeigen wir, wie man `NoiseModel` erstellt.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dae0c070",
      "metadata": {},
      "source": [
        "Zunächst müssen wir Quantenfehler (oder Auslesefehler) definieren, die einem Rauschmodell hinzugefügt werden.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "1e0f1c12",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_aer.noise.errors import (\n",
        "    coherent_unitary_error,\n",
        "    amplitude_damping_error,\n",
        "    ReadoutError,\n",
        ")\n",
        "from qiskit.circuit.library import RXGate\n",
        "\n",
        "# Coherent (unitary) error: Over X-rotation error\n",
        "# https://qiskit.github.io/qiskit-aer/stubs/qiskit_aer.noise.coherent_unitary_error.html#qiskit_aer.noise.coherent_unitary_error\n",
        "OVER_ROTATION_ANGLE = 0.05\n",
        "coherent_error = coherent_unitary_error(RXGate(OVER_ROTATION_ANGLE).to_matrix())\n",
        "\n",
        "# Incoherent error: Amplitude dumping error\n",
        "# https://qiskit.github.io/qiskit-aer/stubs/qiskit_aer.noise.amplitude_damping_error.html#qiskit_aer.noise.amplitude_damping_error\n",
        "AMPLITUDE_DAMPING_PARAM = 0.02  # in [0, 1] (0: no error)\n",
        "incoherent_error = amplitude_damping_error(AMPLITUDE_DAMPING_PARAM)\n",
        "\n",
        "# Readout (measurement) error: Readout error\n",
        "# https://qiskit.github.io/qiskit-aer/stubs/qiskit_aer.noise.ReadoutError.html#qiskit_aer.noise.ReadoutError\n",
        "PREP0_MEAS1 = 0.03  # P(1|0): Probability of preparing 0 and measuring 1\n",
        "PREP1_MEAS0 = 0.08  # P(0|1): Probability of preparing 1 and measuring 0\n",
        "readout_error = ReadoutError(\n",
        "    [[1 - PREP0_MEAS1, PREP0_MEAS1], [PREP1_MEAS0, 1 - PREP1_MEAS0]]\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "e23c26ba",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_aer.noise import NoiseModel\n",
        "\n",
        "noise_model = NoiseModel()\n",
        "noise_model.add_quantum_error(coherent_error.compose(incoherent_error), \"x\", (0,))\n",
        "noise_model.add_readout_error(readout_error, (0,))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5a786224",
      "metadata": {},
      "source": [
        "<span id=\"23-build-a-noisy-sampler-with-the-noise-model\" />\n",
        "\n",
        "### 2.3 Erstellen Sie einen lauten Sampler mit dem Geräuschmodell\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "f8aded6f",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_aer.primitives import SamplerV2 as Sampler\n",
        "\n",
        "noisy_sampler = Sampler(options={\"backend_options\": {\"noise_model\": noise_model}})"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "922ba1ac",
      "metadata": {},
      "source": [
        "<span id=\"24-run-quantum-circuits-on-the-noisy-sampler\" />\n",
        "\n",
        "### 2.4 Quantenschaltungen auf dem verrauschten Sampler ausführen\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "4ae504e7",
      "metadata": {},
      "outputs": [],
      "source": [
        "job = noisy_sampler.run(circuits, shots=400)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "3b2fff25",
      "metadata": {},
      "outputs": [],
      "source": [
        "result = job.result()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "4dc12337",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'0': 389, '1': 11}"
            ]
          },
          "execution_count": 12,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "result[0].data.meas.get_counts()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7e654c5e",
      "metadata": {},
      "source": [
        "<span id=\"25-plot-results\" />\n",
        "\n",
        "### 2.5 Plot-Ergebnisse\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "1a25e394",
      "metadata": {},
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "\n",
        "plt.title(\"Noisy simulation\")\n",
        "ds = list(range(MAX_DEPTH + 1))\n",
        "plt.plot(\n",
        "    ds,\n",
        "    [result[d].data.meas.expectation_values([\"Z\"]) for d in ds],\n",
        "    color=\"gray\",\n",
        "    linestyle=\"-\",\n",
        ")\n",
        "plt.scatter(ds, [result[d].data.meas.expectation_values([\"Z\"]) for d in ds], marker=\"o\")\n",
        "plt.hlines(0, xmin=0, xmax=MAX_DEPTH, colors=\"black\")\n",
        "plt.ylim(-1, 1)\n",
        "plt.xlabel(\"Circuit depth\")\n",
        "plt.ylabel(\"Measured <Z>\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "09ef68bb",
      "metadata": {},
      "source": [
        "<span id=\"26-ideal-simulation\" />\n",
        "\n",
        "### 2.6 Ideale Simulation\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "041abc81",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/041abc81-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "ideal_sampler = Sampler()\n",
        "job_ideal = ideal_sampler.run(circuits)\n",
        "result_ideal = job_ideal.result()\n",
        "plt.title(\"Ideal simulation\")\n",
        "ds = list(range(MAX_DEPTH + 1))\n",
        "plt.plot(\n",
        "    ds,\n",
        "    [result_ideal[d].data.meas.expectation_values([\"Z\"]) for d in ds],\n",
        "    color=\"gray\",\n",
        "    linestyle=\"-\",\n",
        ")\n",
        "plt.scatter(\n",
        "    ds, [result_ideal[d].data.meas.expectation_values([\"Z\"]) for d in ds], marker=\"o\"\n",
        ")\n",
        "plt.hlines(0, xmin=0, xmax=MAX_DEPTH, colors=\"black\")\n",
        "plt.xlabel(\"Circuit depth\")\n",
        "plt.ylabel(\"Measured <Z>\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a1e1b6e6",
      "metadata": {},
      "source": [
        "<span id=\"27-exercise\" />\n",
        "\n",
        "### 2.7 Übung\n",
        "\n",
        "Indem Sie den nachstehenden Code ändern,\n",
        "\n",
        "* [ ] Versuchen Sie 25x Anzahl der Schüsse (= 10\\_000 Schüsse) und stellen Sie sicher, dass eine glattere Darstellung erhalten wird\n",
        "* [ ] Ändern Sie die Rauschparameter (OVER\\_ROTATION\\_ANGLE, AMPLITUDE\\_DAMPING\\_PARAM, PREP0\\_MEAS1 oder PREP1\\_MEAS0 ) und beobachten Sie, wie sich die Darstellung ändert\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "502b9cfe",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/502b9cfe-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "OVER_ROTATION_ANGLE = 0.05\n",
        "coherent_error = coherent_unitary_error(RXGate(OVER_ROTATION_ANGLE).to_matrix())\n",
        "AMPLITUDE_DAMPING_PARAM = 0.02  # in [0, 1] (0: no error)\n",
        "incoherent_error = amplitude_damping_error(AMPLITUDE_DAMPING_PARAM)\n",
        "PREP0_MEAS1 = 0.1  # P(1|0): Probability of preparing 0 and measuring 1\n",
        "PREP1_MEAS0 = 0.05  # P(0|1): Probability of preparing 1 and measuring 0\n",
        "readout_error = ReadoutError(\n",
        "    [[1 - PREP0_MEAS1, PREP0_MEAS1], [PREP1_MEAS0, 1 - PREP1_MEAS0]]\n",
        ")\n",
        "noise_model = NoiseModel()\n",
        "noise_model.add_quantum_error(coherent_error.compose(incoherent_error), \"x\", (0,))\n",
        "noise_model.add_readout_error(readout_error, (0,))\n",
        "options = {\n",
        "    \"backend_options\": {\"noise_model\": noise_model},\n",
        "}\n",
        "noisy_sampler = Sampler(options=options)\n",
        "job = noisy_sampler.run(circuits, shots=400)\n",
        "result = job.result()\n",
        "plt.title(\"Noisy simulation\")\n",
        "ds = list(range(MAX_DEPTH + 1))\n",
        "plt.plot(\n",
        "    ds,\n",
        "    [result[d].data.meas.expectation_values([\"Z\"]) for d in ds],\n",
        "    marker=\"o\",\n",
        "    linestyle=\"-\",\n",
        ")\n",
        "plt.hlines(0, xmin=0, xmax=MAX_DEPTH, colors=\"black\")\n",
        "plt.ylim(-1, 1)\n",
        "plt.xlabel(\"Depth\")\n",
        "plt.ylabel(\"Measured <Z>\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3cfe1a93",
      "metadata": {},
      "source": [
        "<span id=\"28-more-realistic-noisy-simulation\" />\n",
        "\n",
        "### 2.8 Realistischere Simulation von Störgeräuschen\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "8d607bb5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<IBMBackend('ibm_strasbourg')>"
            ]
          },
          "execution_count": 17,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit_aer import AerSimulator\n",
        "from qiskit_ibm_runtime import SamplerV2 as Sampler, QiskitRuntimeService\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "real_backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=127\n",
        ")  # Eagle"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "id": "81a67f2f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/81a67f2f-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "aer = AerSimulator.from_backend(real_backend)\n",
        "noisy_sampler = Sampler(mode=aer)\n",
        "job = noisy_sampler.run(circuits)\n",
        "result = job.result()\n",
        "plt.title(\"Noisy simulation with noise model from real backend\")\n",
        "ds = list(range(MAX_DEPTH + 1))\n",
        "plt.plot(\n",
        "    ds,\n",
        "    [result[d].data.meas.expectation_values([\"Z\"]) for d in ds],\n",
        "    marker=\"o\",\n",
        "    linestyle=\"-\",\n",
        ")\n",
        "plt.hlines(0, xmin=0, xmax=MAX_DEPTH, colors=\"black\")\n",
        "plt.ylim(-1, 1)\n",
        "plt.xlabel(\"Depth\")\n",
        "plt.ylabel(\"Measured <Z>\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "567d30e9",
      "metadata": {},
      "source": [
        "<span id=\"3-real-quantum-computation-with-error-mitigation\" />\n",
        "\n",
        "## 3. Echte Quantenberechnung mit Fehlerminderung\n",
        "\n",
        "In diesem Teil zeigen wir, wie man mit Qiskit Estimator fehlerbereinigte Ergebnisse (Erwartungswerte) erhält.\n",
        "Wir betrachten trotterisierte 6-Qubit-Schaltungen zur Simulation der zeitlichen Entwicklung des eindimensionalen Ising-Modells und sehen, wie der Fehler mit der Anzahl der Zeitschritte skaliert.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "2d301499",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<IBMBackend('ibm_strasbourg')>"
            ]
          },
          "execution_count": 20,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=127\n",
        ")  # Eagle\n",
        "backend"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "id": "6c90b89c",
      "metadata": {},
      "outputs": [],
      "source": [
        "NUM_QUBITS = 6\n",
        "NUM_TIME_STEPS = list(range(8))\n",
        "RX_ANGLE = 0.1\n",
        "RZZ_ANGLE = 0.1"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b1489739",
      "metadata": {},
      "source": [
        "<span id=\"31-build-circuits\" />\n",
        "\n",
        "### 3.1 Schaltungen bauen\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "id": "1a77956e",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Build circuits with different number of time steps\n",
        "circuits = []\n",
        "for n_steps in NUM_TIME_STEPS:\n",
        "    circ = QuantumCircuit(NUM_QUBITS)\n",
        "    for i in range(n_steps):\n",
        "        # rx layer\n",
        "        for q in range(NUM_QUBITS):\n",
        "            circ.rx(RX_ANGLE, q)\n",
        "        # 1st rzz layer\n",
        "        for q in range(1, NUM_QUBITS - 1, 2):\n",
        "            circ.rzz(RZZ_ANGLE, q, q + 1)\n",
        "        # 2nd rzz layer\n",
        "        for q in range(0, NUM_QUBITS - 1, 2):\n",
        "            circ.rzz(RZZ_ANGLE, q, q + 1)\n",
        "    circ.barrier()  # need not to optimize the circuit\n",
        "    # Uncompute stage\n",
        "    for i in range(n_steps):\n",
        "        for q in range(0, NUM_QUBITS - 1, 2):\n",
        "            circ.rzz(-RZZ_ANGLE, q, q + 1)\n",
        "        for q in range(1, NUM_QUBITS - 1, 2):\n",
        "            circ.rzz(-RZZ_ANGLE, q, q + 1)\n",
        "        for q in range(NUM_QUBITS):\n",
        "            circ.rx(-RX_ANGLE, q)\n",
        "    circuits.append(circ)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "94eb9062",
      "metadata": {},
      "source": [
        "Um den idealen Ausgang im Voraus zu kennen, verwenden wir Compute-Uncompute-Schaltungen, die aus einer ersten Stufe bestehen, in der die ursprüngliche Schaltung $U$ angewendet wird, und einer zweiten Stufe, in der sie umgekehrt wird $U^\\dagger$. Man beachte, dass das ideale Ergebnis solcher Schaltungen trivialerweise der Eingangszustand $|000000\\rangle$ ist, der die trivialen Erwartungswerte für alle Pauli-Beobachtungsgrößen hat, zum Beispiel $\\langle IIIIIZ \\rangle = 1$.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "id": "20296b5a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/20296b5a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 23,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Print the circuit with 2 time steps\n",
        "circuits[2].draw(output=\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cde8d3ea",
      "metadata": {},
      "source": [
        "Hinweis: Wie oben gezeigt, hat die Schaltung mit $k$ Zeitschritten $4k$ Zwei-Qubit-Gatterschichten.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "id": "af0d03e9",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "SparsePauliOp(['IIIIIZ'],\n",
              "              coeffs=[1.+0.j])"
            ]
          },
          "execution_count": 24,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "obs = SparsePauliOp.from_sparse_list([(\"Z\", [0], 1.0)], num_qubits=NUM_QUBITS)\n",
        "obs"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ebd6ea9b",
      "metadata": {},
      "source": [
        "<span id=\"32-transpile-the-circuits\" />\n",
        "\n",
        "### 3.2 Die Schaltkreise transpilieren\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8eaa552e",
      "metadata": {},
      "source": [
        "Wir transponieren die Schaltungen für das Backend mit Optimierung (`optimization_level=1`).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "87b861e2",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/87b861e2-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "pm = generate_preset_pass_manager(optimization_level=1, backend=backend)\n",
        "isa_circuits = pm.run(circuits)\n",
        "display(isa_circuits[2].draw(\"mpl\", idle_wires=False, fold=-1))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "743ad427",
      "metadata": {},
      "source": [
        "<span id=\"33-execute-using-estimator-with-different-resilience-levels\" />\n",
        "\n",
        "### 3.3 Ausführung mit Estimator (mit unterschiedlichen Resilienzstufen)\n",
        "\n",
        "Die Einstellung der Resilienzstufe (`estimator.options.resilience_level`) ist der einfachste Weg, um bei der Verwendung von Qiskit Estimator Fehlerminderung anzuwenden. Estimator unterstützt die folgenden Resilienzstufen (Stand: 28.06.2024). Weitere Informationen finden Sie im Leitfaden [zur Konfiguration der Fehlerbehebung](/docs/guides/error-mitigation-and-suppression-techniques).\n",
        "\n",
        "![image.png](https://quantum.cloud.ibm.com/learning/images/courses/utility-scale-quantum-computing/error-mitigation/res_level.avif)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "id": "328f71f2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID (rl=0): d146vcnmya70008emprg\n",
            "Job ID (rl=1): d146vdnqf56g0081sva0\n",
            "Job ID (rl=2): d146ven5z6q00087c61g\n"
          ]
        }
      ],
      "source": [
        "from qiskit_ibm_runtime import Batch\n",
        "from qiskit_ibm_runtime import EstimatorV2 as Estimator\n",
        "\n",
        "jobs = []\n",
        "job_ids = []\n",
        "with Batch(backend=backend):\n",
        "    for resilience_level in [0, 1, 2]:\n",
        "        estimator = Estimator()\n",
        "        estimator.options.resilience_level = resilience_level\n",
        "        job = estimator.run(\n",
        "            [(circ, obs.apply_layout(circ.layout)) for circ in isa_circuits]\n",
        "        )\n",
        "        job_ids.append(job.job_id())\n",
        "        print(f\"Job ID (rl={resilience_level}): {job.job_id()}\")\n",
        "        jobs.append(job)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "id": "1dd804e4-0d7d-4782-9559-7b3796cab121",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "DONE\n",
            "DONE\n",
            "DONE\n"
          ]
        }
      ],
      "source": [
        "# check job status\n",
        "for job in jobs:\n",
        "    print(job.status())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 32,
      "id": "d138e1e9",
      "metadata": {},
      "outputs": [],
      "source": [
        "# REPLACE WITH YOUR OWN JOB IDS\n",
        "jobs = [service.job(job_id) for job_id in job_ids]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "id": "ea820e98",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Get results\n",
        "results = [job.result() for job in jobs]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e3691462",
      "metadata": {},
      "source": [
        "<span id=\"34-plot-results\" />\n",
        "\n",
        "### 3.4 Plot-Ergebnisse\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "id": "7527976e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/7527976e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.title(\"Error mitigation with different resilience levels\")\n",
        "labels = [\"0 (No mitigation)\", \"1 (TREX)\", \"2 (ZNE + Gate twirling)\"]\n",
        "steps = NUM_TIME_STEPS\n",
        "for result, label in zip(results, labels):\n",
        "    plt.errorbar(\n",
        "        x=steps,\n",
        "        y=[result[s].data.evs for s in steps],\n",
        "        yerr=[result[s].data.stds for s in steps],\n",
        "        marker=\"o\",\n",
        "        linestyle=\"-\",\n",
        "        capsize=4,\n",
        "        label=label,\n",
        "    )\n",
        "plt.hlines(\n",
        "    1.0, min(steps), max(steps), linestyle=\"dashed\", label=\"Ideal\", colors=\"black\"\n",
        ")\n",
        "plt.xlabel(\"Time steps\")\n",
        "plt.ylabel(\"Mitigated <IIIIIZ>\")\n",
        "plt.legend()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e4def30b",
      "metadata": {},
      "source": [
        "<span id=\"4-optional-customize-error-mitigation-options\" />\n",
        "\n",
        "## 4. (Optional) Optionen zur Fehlerbehebung anpassen\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f099e16c",
      "metadata": {},
      "source": [
        "Wir können die Anwendung der Fehlerbegrenzungstechniken über die unten aufgeführten Optionen individuell anpassen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 35,
      "id": "a22e6b8c",
      "metadata": {},
      "outputs": [],
      "source": [
        "# TREX\n",
        "estimator.options.twirling.enable_measure = True\n",
        "estimator.options.twirling.num_randomizations = \"auto\"\n",
        "estimator.options.twirling.shots_per_randomization = \"auto\"\n",
        "\n",
        "# Gate twirling\n",
        "estimator.options.twirling.enable_gates = True\n",
        "# ZNE\n",
        "estimator.options.resilience.zne_mitigation = True\n",
        "estimator.options.resilience.zne.noise_factors = [1, 3, 5]\n",
        "estimator.options.resilience.zne.extrapolator = (\"exponential\", \"linear\")\n",
        "\n",
        "# Dynamical decoupling\n",
        "estimator.options.dynamical_decoupling.enable = True  # Default: False\n",
        "estimator.options.dynamical_decoupling.sequence_type = \"XX\"\n",
        "\n",
        "# Other options\n",
        "estimator.options.default_shots = 10_000"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "79dd06fb",
      "metadata": {},
      "source": [
        "In den folgenden Leitfäden und der API-Referenz finden Sie Einzelheiten zu den Optionen zur Fehlerbehebung.\n",
        "\n",
        "* [Fehlerbehebung konfigurieren](/docs/guides/error-mitigation-and-suppression-techniques)\n",
        "* [Einführung in die Optionen](/docs/guides/runtime-options-overview)\n",
        "* [EstimatorOptions](/docs/api/qiskit-ibm-runtime/options-models-estimator-options)\n",
        "* [SamplerOptions](/docs/api/qiskit-ibm-runtime/options-models-sampler-options)\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
}