{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "3445b0b5-7f26-4610-8e1b-5112df1fccb0",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Fehlerreduktionsoptionen mit dem Schätz-Basiselement kombinieren\"\n",
        "description: \"Kombinieren Sie Optionen zur Fehlerminderung für Experimente im industriellen Maßstab unter Verwendung von „ 100Q+ “ IBM Quantum -QPUs und der „ IBM Quantum “-Estimator-Primitive.\"\n",
        "---\n",
        "\n",
        "<span id=\"combine-error-mitigation-options-with-the-estimator-primitive\" />\n",
        "\n",
        "# Fehlerreduktionsoptionen mit dem Schätz-Basiselement kombinieren\n",
        "\n",
        "*Geschätzte Laufzeit: 7 Minuten auf einem Heron- r2 -Prozessor (HINWEIS: Dies ist nur eine Schätzung. (Die Laufzeit kann variieren.)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "39ba4396-9111-4421-9371-542f067bc816",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## Lernziele\n",
        "\n",
        "* Wie dynamische Entkopplung, Messfehlerminderung, Gate-Twirling und rauschfreie Extrapolation selektiv auf Hardware umgesetzt werden.\n",
        "* Wie sie sich hinsichtlich ihrer Fähigkeit zur Dämpfung von Hardwaregeräuschen vergleichen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b27cb482-b77a-4953-a0a4-39df33896d12",
      "metadata": {},
      "source": [
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## Voraussetzungen\n",
        "\n",
        "* Die Grundlagen der dynamischen Entkopplung, der Minderung von Messfehlern, des Gate-Twirling und der rauschfreien Extrapolation, wie in diesem [Leitfaden](/docs/guides/error-mitigation-and-suppression-techniques) beschrieben.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "018313d1-d959-4011-81df-59bf7c157470",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## Hintergrund\n",
        "\n",
        "In diesem Tutorial werden die Optionen zur Fehlerunterdrückung und Fehlerminderung behandelt, die mit der „ IBM Quantum “-Estimator-Primitive zur Verfügung stehen. In diesem Tutorial wird gezeigt, wie die folgenden Methoden jeweils einzeln implementiert werden:\n",
        "\n",
        "* Dynamische Entkopplung\n",
        "* Verringerung von Messfehlern\n",
        "* Torzwirbeln\n",
        "* Null-Rausch-Extrapolation (ZNE)\n",
        "\n",
        "Beachten Sie, dass eine Alternative zur individuellen Implementierung dieser Techniken darin besteht, sie mithilfe einer [Resilienzstufe](/docs/guides/estimator-noise-management) zu implementieren, wobei die Werte `resilience_level` 0, 1 und 2 annimmt:\n",
        "\n",
        "* 0: Es wurden keine Maßnahmen zur Risikominderung umgesetzt.\n",
        "* 1: Es wurde eine Maßnahme zur Minderung von Messfehlern implementiert.\n",
        "* 2: Gate-Twirling, Minderung von Messfehlern und ZNE sind implementiert.\n",
        "\n",
        "In diesem Tutorial erstellen Sie eine Schaltung und eine Beobachtungsgröße und reichen Jobs unter Verwendung der Estimator-Primitive mit verschiedenen Kombinationen von Einstellungen zur Fehlerminderung ein. Anschließend stellen Sie die Ergebnisse grafisch dar, um die Auswirkungen der verschiedenen Einstellungen zu beobachten. Der Großteil des Tutorials verwendet eine Schaltung mit 10 Qubits, um die Visualisierung zu vereinfachen; am Ende werden Sie den Arbeitsablauf auf 50 Qubits ausweiten.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0f3d3378-8dac-489e-bf6d-292e693ec145",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## Anforderungen\n",
        "\n",
        "Bevor Sie mit dieser Anleitung beginnen, stellen Sie sicher, dass Sie Folgendes installiert haben:\n",
        "\n",
        "* Qiskit SDK v2.1 oder später, mit [Visual](/docs/api/qiskit/visualization) isierungsunterstützung\n",
        "* Qiskit Runtime v0.40 oder später (`pip install qiskit-ibm-runtime`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "069658fa-fa45-48b8-ab69-2610228bf6e4",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## Einrichtung\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "95a72452-e067-4ee5-bcd9-e3bfcf0de208",
      "metadata": {},
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "\n",
        "from qiskit.circuit.library import efficient_su2, unitary_overlap\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_ibm_runtime import Batch, EstimatorV2 as Estimator"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d15c5fde-5046-4d86-86d8-72d1ed748c4e",
      "metadata": {},
      "source": [
        "<span id=\"small-scale-simulator-example\" />\n",
        "\n",
        "## Beispiel für einen Simulator im kleinen Maßstab\n",
        "\n",
        "Wir werden diesen Schritt überspringen, da die Behebung von Laufzeitfehlern auf Simulatoren nicht unterstützt wird.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b2be0539-4f60-46e8-be1f-8869dae30888",
      "metadata": {},
      "source": [
        "<span id=\"hardware-example\" />\n",
        "\n",
        "## Beispiel für Hardware\n",
        "\n",
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "### Schritt 1: Klassische Eingaben einem Quantenproblem zuordnen\n",
        "\n",
        "Diese Anleitung geht davon aus, dass das klassische Problem bereits auf Quanten abgebildet wurde. Beginnen Sie mit dem Aufbau einer Schaltung und eines Messgeräts. Die hier verwendeten Techniken lassen sich auf viele verschiedene Arten von Schaltungen anwenden, aber der Einfachheit halber wird in dieser Anleitung die [`efficient_su2`](/docs/api/qiskit/qiskit.circuit.library.efficient_su2) Schaltung aus der Qiskit-Schaltungsbibliothek verwendet.\n",
        "\n",
        "`efficient_su2` ist ein parametrisierter Quantenschaltkreis, der so konzipiert ist, dass er auf Quantenhardware mit begrenzter Qubit-Konnektivität effizient ausgeführt werden kann, dabei aber dennoch über genügend Ausdruckskraft verfügt, um Probleme in Anwendungsbereichen wie Optimierung und Chemie zu lösen. Es wird aufgebaut, indem Schichten aus parametrisierten Einzelqubit-Gattern mit einer Schicht, die ein festes Muster aus Zwei-Qubit-Gattern enthält, für eine bestimmte Anzahl von Wiederholungen abwechselnd angeordnet werden. Das Muster der Zwei-Qubit-Gatter kann vom Benutzer festgelegt werden. Hier können Sie das integrierte `pairwise` Muster verwenden, da es die Schaltungstiefe minimiert, indem es die Zwei-Qubit-Gatter so dicht wie möglich anordnet. Dieses Muster lässt sich ausschließlich mit linearen Qubit-Verbindungen realisieren.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "24abd7ba-bbb8-443b-9e81-866795d39a6c",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/combine-error-mitigation-techniques/extracted-outputs/24abd7ba-bbb8-443b-9e81-866795d39a6c-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "n_qubits = 10\n",
        "reps = 1\n",
        "\n",
        "circuit = efficient_su2(n_qubits, entanglement=\"pairwise\", reps=reps)\n",
        "\n",
        "circuit.decompose().draw(\"mpl\", scale=0.7)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "34fec53b-a8b2-461b-a20d-e8ad54b992fa",
      "metadata": {},
      "source": [
        "Nehmen wir als Observable den Pauli- $Z$ -Operator, der auf das letzte Qubit wirkt: $Z I \\cdots I$.\n",
        "Beachte, dass die Tatsache, dass das letzte Qubit dem ersten Element dieser Zeichenfolge entspricht, darauf zurückzuführen ist, dass Qiskit die Little-Endian-Notation verwendet.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "9500ba7b-4542-465f-a4e1-60165d6b6d1e",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Z on the last qubit (index -1) with coefficient 1.0\n",
        "observable = SparsePauliOp.from_sparse_list(\n",
        "    [(\"Z\", [-1], 1.0)], num_qubits=n_qubits\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "46eff743-de9f-4f55-9c47-02c6d6115b80",
      "metadata": {},
      "source": [
        "Nun könnten Sie Ihre Schaltung in Betrieb nehmen und die Messgröße erfassen. Sie möchten jedoch auch die Ausgabe des Quantenbauelements mit der richtigen Antwort vergleichen – also mit dem theoretischen Wert der Observable, wenn die Schaltung fehlerfrei ausgeführt worden wäre. Bei kleinen Quantenschaltungen lässt sich dieser Wert durch Simulation der Schaltung auf einem klassischen Computer berechnen, bei größeren Schaltungen im industriellen Maßstab ist dies jedoch nicht möglich. Sie können dieses Problem mit der „Mirror-Circuit“-Technik (auch als „Compute-Uncompute“ bekannt) umgehen, die sich gut zur Leistungsmessung von Quantenbauelementen eignet.\n",
        "\n",
        "<span id=\"mirror-circuit\" />\n",
        "\n",
        "#### Spiegelschaltung\n",
        "\n",
        "Bei der Spiegelschaltungstechnik wird die Schaltung mit ihrer Umkehrschaltung verknüpft, die durch Invertieren der einzelnen Gatter der Schaltung in umgekehrter Reihenfolge gebildet wird. Die resultierende Schaltung implementiert den Identitätsoperator, der trivialerweise simuliert werden kann. Da die Struktur der ursprünglichen Schaltung in der Spiegelschaltung erhalten bleibt, gibt die Ausführung der Spiegelschaltung immer noch einen Eindruck davon, wie das Quantengerät auf der ursprünglichen Schaltung funktionieren würde.\n",
        "\n",
        "Die folgende Codezelle weist Ihrer Schaltung zufällige Parameter zu und erstellt anschließend mithilfe der [`unitary_overlap`](/docs/api/qiskit/qiskit.circuit.library.unitary_overlap) Klasse die Spiegel-Schaltung. Fügen Sie vor dem Spiegeln der Schaltung eine [Bar](/docs/api/qiskit/circuit#qiskit.circuit.Barrier) riereanweisung ein, um zu verhindern, dass der Transpiler die beiden Teile der Schaltung auf beiden Seiten der Barriere zusammenführt und dadurch eine transpilierte Schaltung ohne Gatter entsteht.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "4dbde811-1ba9-47a8-85a0-dcaff054ed60",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/combine-error-mitigation-techniques/extracted-outputs/4dbde811-1ba9-47a8-85a0-dcaff054ed60-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 10,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Generate random parameters\n",
        "rng = np.random.default_rng(1234)\n",
        "params = rng.uniform(-np.pi, np.pi, size=circuit.num_parameters)\n",
        "\n",
        "# Assign the parameters to the circuit\n",
        "assigned_circuit = circuit.assign_parameters(params)\n",
        "\n",
        "# Add a barrier to prevent circuit optimization of mirrored operators\n",
        "assigned_circuit.barrier()\n",
        "\n",
        "# Construct mirror circuit\n",
        "mirror_circuit = unitary_overlap(assigned_circuit, assigned_circuit)\n",
        "\n",
        "mirror_circuit.decompose().draw(\"mpl\", scale=0.7)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a37c97de-c942-4419-9409-5bcaef9c6876",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "### Schritt 2: Optimierung des Problems für die Ausführung auf Quantenhardware\n",
        "\n",
        "Sie müssen Ihre Schaltung optimieren, bevor Sie sie auf der Hardware betreiben. Dieser Prozess umfasst mehrere Schritte:\n",
        "\n",
        "* Wählen Sie ein Qubit-Layout, das die virtuellen Qubits Ihrer Schaltung auf physische Qubits in der Hardware abbildet.\n",
        "* Fügen Sie nach Bedarf Swap-Gates ein, um Wechselwirkungen zwischen nicht verbundenen Qubits zu steuern.\n",
        "* Übersetzen Sie die Gatter in Ihrer Schaltung in [ISA-Befehle (Instruction Set Architecture)](/docs/guides/transpile#instruction-set-architecture), die direkt in der Hardware ausgeführt werden können.\n",
        "* Optimieren Sie die Schaltung, um die Schaltungstiefe und die Anzahl der Gatter zu minimieren.\n",
        "\n",
        "Der in Qiskit integrierte Transpiler kann alle diese Schritte für Sie ausführen. Da dieses Beispiel eine hardwareeffiziente Schaltung verwendet, sollte der Transpiler in der Lage sein, ein Qubit-Layout auszuwählen, bei dem keine Swap-Gates für Routing-Interaktionen eingefügt werden müssen.\n",
        "\n",
        "Bevor Sie Ihre Schaltung optimieren, müssen Sie das zu verwendende Hardwaregerät auswählen. Die folgende Codezelle fordert das am wenigsten ausgelastete Gerät mit mindestens 127 Qubits an.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "2c3ea768-0596-4db1-9b51-3ff78ec65818",
      "metadata": {},
      "outputs": [],
      "source": [
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=127\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "aeaf076c-1c0a-4ec4-af66-49eff621589d",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "<IBMBackend('ibm_fez')>\n"
          ]
        }
      ],
      "source": [
        "print(backend)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "46280e59-8c9f-4dd9-a365-6a230ceccf42",
      "metadata": {},
      "source": [
        "Sie können Ihren Schaltkreis auf das Backend Ihrer Wahl transpilieren, indem Sie einen Pass-Manager erstellen und diesen anschließend auf den Schaltkreis anwenden. Eine einfache Möglichkeit, einen Pass-Manager zu erstellen, ist die Verwendung der [`generate_preset_pass_manager`](/docs/api/qiskit/qiskit.transpiler.generate_preset_pass_manager) Funktion. Eine ausführlichere Erläuterung zum Transpiling [mit](/docs/guides/transpile-with-pass-managers) Pass-Managern finden Sie unter „Transpile with pass managers“.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "027e829a-44d3-455e-b2bf-8ce0d7e26b9b",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/combine-error-mitigation-techniques/extracted-outputs/027e829a-44d3-455e-b2bf-8ce0d7e26b9b-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 13,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pass_manager = generate_preset_pass_manager(\n",
        "    optimization_level=3, backend=backend, seed_transpiler=1234\n",
        ")\n",
        "isa_circuit = pass_manager.run(mirror_circuit)\n",
        "\n",
        "isa_circuit.draw(\"mpl\", idle_wires=False, scale=0.7, fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1865671e-2c7a-44dd-8938-fe4637bb5993",
      "metadata": {},
      "source": [
        "Die transpilierte Schaltung enthält nun ausschließlich ISA-Befehle. Alle Gatter wurden in „ $\\sqrt{X}$ “-Gatter, „ $R_z$ “-Rotationen und [CZ-Gatter](/docs/api/qiskit/qiskit.circuit.library.CZGate) zerlegt.\n",
        "\n",
        "Der Transpilierungsprozess hat die virtuellen Qubits des Schaltkreises auf physische Qubits in der Hardware abgebildet. Die Informationen über das Qubit-Layout sind im `layout` -Attribut der umgesetzten Schaltung gespeichert. Die Observable wurde auch in Bezug auf die virtuellen Qubits definiert, also müssen Sie dieses Layout auf die Observable anwenden, was Sie mit der [`apply_layout`](/docs/api/qiskit/qiskit.quantum_info.SparsePauliOp#apply_layout) methode von `SparsePauliOp`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "12338588-a2d0-4b9c-9e49-e25ec8617b93",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Original observable:\n",
            "SparsePauliOp(['ZIIIIIIIII'],\n",
            "              coeffs=[1.+0.j])\n",
            "\n",
            "Observable with layout applied:\n",
            "SparsePauliOp(['IIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'],\n",
            "              coeffs=[1.+0.j])\n"
          ]
        }
      ],
      "source": [
        "isa_observable = observable.apply_layout(isa_circuit.layout)\n",
        "\n",
        "print(\"Original observable:\")\n",
        "print(observable)\n",
        "print()\n",
        "print(\"Observable with layout applied:\")\n",
        "print(isa_observable)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "439d4edf-d1ad-49f3-b206-320958be4f82",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### Schritt 3: Mit „ Qiskit primitives “ ausführen\n",
        "\n",
        "Sie sind nun bereit, Ihre Schaltung mit dem Estimator-Primitiv zu betreiben.\n",
        "\n",
        "Hier führen Sie fünf separate Aufträge aus, wobei Sie zunächst keine Fehlerunterdrückung oder -minderung anwenden und nach und nach verschiedene Optionen zur Fehlerunterdrückung und -minderung aktivieren, die im „ IBM Quantum Compute Service“ verfügbar sind. Informationen zu den Optionen finden Sie auf den folgenden Seiten:\n",
        "\n",
        "* [Überblick über alle Optionen](/docs/api/qiskit-ibm-runtime/options)\n",
        "* [Dynamische Entkopplung](/docs/api/qiskit-ibm-runtime/options-models-dynamical-decoupling-options)\n",
        "* [Robustheit, einschließlich Minderung von Messfehlern und rauschfreier Extrapolation (ZNE)](/docs/api/qiskit-ibm-runtime/options-models-resilience-options)\n",
        "* [Wirbeln](/docs/api/qiskit-ibm-runtime/options-models-twirling-options)\n",
        "\n",
        "Da diese Jobs unabhängig voneinander ausgeführt werden können, können Sie [den Batch-Modus](/docs/guides/run-jobs-batch) nutzen, damit Quantum Compute den Zeitpunkt ihrer Ausführung optimieren kann.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "1114d15b-1408-4f4c-a20f-60f0da722325",
      "metadata": {},
      "outputs": [],
      "source": [
        "pub = (isa_circuit, isa_observable)\n",
        "\n",
        "jobs = []\n",
        "\n",
        "with Batch(backend=backend) as batch:\n",
        "    estimator = Estimator(mode=batch)\n",
        "    estimator.options.environment.job_tags = [\n",
        "        \"TUT_CEM_SS\"\n",
        "    ]  # add tag for this small scale job\n",
        "    # Set number of shots\n",
        "    estimator.options.default_shots = 100_000\n",
        "    # Disable runtime compilation and error mitigation\n",
        "    estimator.options.resilience_level = 0\n",
        "\n",
        "    # Run job with no error mitigation\n",
        "    job0 = estimator.run([pub])\n",
        "    jobs.append(job0)\n",
        "\n",
        "    # Add dynamical decoupling (DD)\n",
        "    estimator.options.dynamical_decoupling.enable = True\n",
        "    estimator.options.dynamical_decoupling.sequence_type = \"XpXm\"\n",
        "    job1 = estimator.run([pub])\n",
        "    jobs.append(job1)\n",
        "\n",
        "    # Add readout error mitigation (DD + TREX)\n",
        "    estimator.options.resilience.measure_mitigation = True\n",
        "    job2 = estimator.run([pub])\n",
        "    jobs.append(job2)\n",
        "\n",
        "    # Add gate twirling (DD + TREX + Gate Twirling)\n",
        "    estimator.options.twirling.enable_gates = True\n",
        "    estimator.options.twirling.num_randomizations = \"auto\"\n",
        "    job3 = estimator.run([pub])\n",
        "    jobs.append(job3)\n",
        "\n",
        "    # Add zero-noise extrapolation (DD + TREX + Gate Twirling + 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",
        "    job4 = estimator.run([pub])\n",
        "    jobs.append(job4)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "919517c8-6f42-48d9-a976-53c715c00a4b",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-and-return-result-in-desired-classical-format\" />\n",
        "\n",
        "### Schritt 4: Nachbearbeitung und Rückgabe des Ergebnisses im gewünschten klassischen Format\n",
        "\n",
        "Schließlich können Sie die Daten analysieren. Hier rufen Sie die Auftragsergebnisse ab, extrahieren daraus die gemessenen Erwartungswerte und stellen die Werte einschließlich Fehlerbalken mit einer Standardabweichung dar.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "eef38976-0ca2-429a-b2dc-41aac69605f7",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/combine-error-mitigation-techniques/extracted-outputs/eef38976-0ca2-429a-b2dc-41aac69605f7-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Retrieve the job results\n",
        "results = [job.result() for job in jobs]\n",
        "\n",
        "# Unpack the PUB results (there's only one PUB result in each job result)\n",
        "pub_results = [result[0] for result in results]\n",
        "\n",
        "# Unpack the expectation values and standard errors\n",
        "expectation_vals = np.array(\n",
        "    [float(pub_result.data.evs) for pub_result in pub_results]\n",
        ")\n",
        "standard_errors = np.array(\n",
        "    [float(pub_result.data.stds) for pub_result in pub_results]\n",
        ")\n",
        "\n",
        "# Plot the expectation values\n",
        "fig, ax = plt.subplots()\n",
        "labels = [\"No mitigation\", \"+ DD\", \"+ TREX\", \"+ Twirling\", \"+ ZNE\"]\n",
        "ax.bar(\n",
        "    range(len(labels)),\n",
        "    expectation_vals,\n",
        "    yerr=standard_errors,\n",
        "    label=\"experiment\",\n",
        ")\n",
        "ax.axhline(y=1.0, color=\"gray\", linestyle=\"--\", label=\"ideal\")\n",
        "ax.set_xticks(range(len(labels)))\n",
        "ax.set_xticklabels(labels)\n",
        "ax.set_ylabel(\"Expectation value\")\n",
        "ax.legend(loc=\"upper left\")\n",
        "\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b400eae8-f38c-4566-82fe-0ccc5ee3f05d",
      "metadata": {},
      "source": [
        "Auf dieser kleinen Skala ist es schwierig, die Wirkung der meisten Fehlerbegrenzungsverfahren zu erkennen, aber die Extrapolation ohne Rauschen führt zu einer spürbaren Verbesserung. Beachten Sie jedoch, dass diese Verbesserung nicht umsonst ist, da das ZNE-Ergebnis auch einen größeren Fehlerbalken aufweist.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "958a5d23-ea09-4750-827c-e3bf6c3fa3f4",
      "metadata": {},
      "source": [
        "<span id=\"large-scale-hardware-example\" />\n",
        "\n",
        "## Beispiel für groß angelegte Hardware\n",
        "\n",
        "Bei der Entwicklung eines Experiments ist es sinnvoll, mit einer kleinen Schaltung zu beginnen, um Visualisierungen und Simulationen zu vereinfachen. Nachdem Sie unseren Workflow nun auf einer 10-Qubit-Schaltung entwickelt und getestet haben, können Sie ihn auf bis zu 50 Qubits skalieren. Die folgende Codezelle wiederholt alle Schritte dieser Anleitung, wendet sie nun jedoch auf eine 50-Qubit-Schaltung an.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "d7d8408b-faf1-4eda-ab9c-bdeaab01ff53",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/combine-error-mitigation-techniques/extracted-outputs/d7d8408b-faf1-4eda-ab9c-bdeaab01ff53-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "n_qubits = 50\n",
        "reps = 1\n",
        "\n",
        "# Construct circuit and observable\n",
        "circuit = efficient_su2(n_qubits, entanglement=\"pairwise\", reps=reps)\n",
        "observable = SparsePauliOp.from_sparse_list(\n",
        "    [(\"Z\", [-1], 1.0)], num_qubits=n_qubits\n",
        ")\n",
        "\n",
        "# Assign parameters to circuit\n",
        "params = rng.uniform(-np.pi, np.pi, size=circuit.num_parameters)\n",
        "assigned_circuit = circuit.assign_parameters(params)\n",
        "assigned_circuit.barrier()\n",
        "\n",
        "# Construct mirror circuit\n",
        "mirror_circuit = unitary_overlap(assigned_circuit, assigned_circuit)\n",
        "\n",
        "# Transpile circuit and observable\n",
        "isa_circuit = pass_manager.run(mirror_circuit)\n",
        "isa_observable = observable.apply_layout(isa_circuit.layout)\n",
        "\n",
        "# Run jobs\n",
        "pub = (isa_circuit, isa_observable)\n",
        "\n",
        "jobs = []\n",
        "\n",
        "with Batch(backend=backend) as batch:\n",
        "    estimator = Estimator(mode=batch)\n",
        "    estimator.options.environment.job_tags = [\n",
        "        \"TUT_CEM_LS\"\n",
        "    ]  # add tag for this large scale job\n",
        "    # Set number of shots\n",
        "    estimator.options.default_shots = 100_000\n",
        "    # Disable runtime compilation and error mitigation\n",
        "    estimator.options.resilience_level = 0\n",
        "\n",
        "    # Run job with no error mitigation\n",
        "    job0 = estimator.run([pub])\n",
        "    jobs.append(job0)\n",
        "\n",
        "    # Add dynamical decoupling (DD)\n",
        "    estimator.options.dynamical_decoupling.enable = True\n",
        "    estimator.options.dynamical_decoupling.sequence_type = \"XpXm\"\n",
        "    job1 = estimator.run([pub])\n",
        "    jobs.append(job1)\n",
        "\n",
        "    # Add readout error mitigation (DD + TREX)\n",
        "    estimator.options.resilience.measure_mitigation = True\n",
        "    job2 = estimator.run([pub])\n",
        "    jobs.append(job2)\n",
        "\n",
        "    # Add gate twirling (DD + TREX + Gate Twirling)\n",
        "    estimator.options.twirling.enable_gates = True\n",
        "    estimator.options.twirling.num_randomizations = \"auto\"\n",
        "    job3 = estimator.run([pub])\n",
        "    jobs.append(job3)\n",
        "\n",
        "    # Add zero-noise extrapolation (DD + TREX + Gate Twirling + 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",
        "    job4 = estimator.run([pub])\n",
        "    jobs.append(job4)\n",
        "\n",
        "# Retrieve the job results\n",
        "results = [job.result() for job in jobs]\n",
        "\n",
        "# Unpack the PUB results (there's only one PUB result in each job result)\n",
        "pub_results = [result[0] for result in results]\n",
        "\n",
        "# Unpack the expectation values and standard errors\n",
        "expectation_vals = np.array(\n",
        "    [float(pub_result.data.evs) for pub_result in pub_results]\n",
        ")\n",
        "standard_errors = np.array(\n",
        "    [float(pub_result.data.stds) for pub_result in pub_results]\n",
        ")\n",
        "\n",
        "# Plot the expectation values\n",
        "fig, ax = plt.subplots()\n",
        "labels = [\"No mitigation\", \"+ DD\", \"+ TREX\", \"+ Twirling\", \"+ ZNE\"]\n",
        "ax.bar(\n",
        "    range(len(labels)),\n",
        "    expectation_vals,\n",
        "    yerr=standard_errors,\n",
        "    label=\"experiment\",\n",
        ")\n",
        "ax.axhline(y=1.0, color=\"gray\", linestyle=\"--\", label=\"ideal\")\n",
        "ax.set_xticks(range(len(labels)))\n",
        "ax.set_xticklabels(labels)\n",
        "ax.set_ylabel(\"Expectation value\")\n",
        "ax.legend(loc=\"upper left\")\n",
        "\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "32d9b036-ea0a-4484-b6ee-036ff732026b",
      "metadata": {},
      "source": [
        "Wenn Sie die 50-Qubit-Ergebnisse mit den 10-Qubit-Ergebnissen von vorhin vergleichen, können Sie Folgendes feststellen (Ihre Ergebnisse können von Lauf zu Lauf unterschiedlich sein):\n",
        "\n",
        "* Bei allen Experimenten liegen die Ergebnisse näher am Idealwert, und alle Fehlerbalken sind kleiner.\n",
        "* Die Einführung der dynamischen Entkopplung könnte die Leistung im Vergleich zum Fall ohne Abhilfemaßnahmen verschlechtert haben. Das ist nicht verwunderlich, da die Schaltung sehr dicht ist. Die dynamische Entkopplung ist vor allem dann sinnvoll, wenn es in der Schaltung große Lücken gibt, in denen die Qubits untätig sind, ohne dass Gatter an sie angelegt werden. Wenn diese Lücken nicht vorhanden sind, ist die dynamische Entkopplung nicht wirksam und kann aufgrund von Fehlern in den Entkopplungsimpulsen selbst die Leistung sogar verschlechtern. Der 10-Qubit-Schaltkreis war möglicherweise zu klein, als dass wir diesen Effekt hätten beobachten können.\n",
        "* Bei der rauschfreien Extrapolation liegt das Ergebnis sehr nahe am Idealwert. Dies verdeutlicht die Leistungsfähigkeit von ZNE.\n",
        "\n",
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Nächste Schritte\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Empfehlungen\">\n",
        "  Wenn Sie diese Arbeit interessant fanden, könnten Sie auch an den folgenden Materialien zu weiteren Techniken der Fehlerminderung und -unterdrückung interessiert sein, die in diesem Tutorial nicht erwähnt wurden:\n",
        "\n",
        "  * [Probabilistische Fehlerkompensation (PEC)](/docs/guides/error-mitigation-and-suppression-techniques#probabilistic-error-cancellation-pec)\n",
        "  * [Matrixfreie Messfehlerkompensation ( M3 )](https://qiskit.github.io/qiskit-addon-mthree/) (siehe auch das Tutorial „[Kompensation von Auslesefehlern für die Sampler-Primitive unter Verwendung von M3](/docs/tutorials/readout-error-mitigation-sampler/) “)\n",
        "  * [Schattierte Lichtkegel](https://qiskit.github.io/qiskit-addon-slc/)\n",
        "  * [Ausbreitungsgeräuschabsorption (PNA)](https://qiskit.github.io/qiskit-addon-pna/)\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"
    },
    "hours": 1,
    "qpuSeconds": 420
  },
  "nbformat": 4,
  "nbformat_minor": 4
}