{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "828c3465-62a7-4c42-b376-e3ec32f67595",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Lärmlernhilfe\"\n",
        "description: \"Machen Sie sich mit dem „Noise Learning Helper“-Programm vertraut, um die bei der Ausführung von Workloads in qiskit-ibm-runtime erstellten Rauschmodelle zu speichern\"\n",
        "---\n",
        "\n",
        "<span id=\"noise-learning-helper\" />\n",
        "\n",
        "# Lärmlernhilfe\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "40a246f5-4efd-4fb0-861b-c4e013c1572a",
      "metadata": {
        "tags": [
          "version-info"
        ]
      },
      "source": [
        "{/*\n",
        "  DO NOT EDIT THIS CELL!!!\n",
        "  This cell's content is generated automatically by a script. Anything you add\n",
        "  here will be removed next time the notebook is run. To add new content, create\n",
        "  a new cell before or after this one.\n",
        "  */}\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Paketversionen\">\n",
        "    Der Code auf dieser Seite wurde unter Berücksichtigung der folgenden Anforderungen entwickelt.\n",
        "    Wir empfehlen die Verwendung dieser oder neuerer Versionen.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.5.2\n",
        "    qiskit-ibm-runtime~=0.47.0\n",
        "    samplomatic~=0.21.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cce93074-df51-4760-9fce-5a520c3bc59a",
      "metadata": {},
      "source": [
        "Die Fehlerminderungstechniken [PEA](/docs/guides/error-mitigation-and-suppression-techniques#pea) und [PEC](/docs/guides/error-mitigation-and-suppression-techniques#pec) nutzen beide eine Komponente zum Rauschlernen, die auf einem [Pauli-Lindblad-Rauschmodell](https://arxiv.org/abs/2201.09866) basiert. Diese wird in der Regel während der Ausführung verwaltet, nachdem ein oder mehrere Jobs über `qiskit-ibm-runtime` übermittelt wurden, ohne dass ein lokaler Zugriff auf das angepasste Rauschmodell besteht. Seit der Version `qiskit-ibm-runtime`v0.27.1 wurden jedoch eine Klasse [`NoiseLearner`](/docs/api/qiskit-ibm-runtime/noise-learner) und [`NoiseLearnerOptions`](/docs/api/qiskit-ibm-runtime/options-noise-learner-options) eine zugehörige Klasse erstellt, um die Ergebnisse dieser Experimente zum Lernen mit Rauschen abzurufen. `NoiseLearnerResult` Diese Ergebnisse können dann lokal als gespeichert und in späteren Experimenten als Eingabe verwendet werden. Diese Seite bietet einen Überblick über die Verwendung und die verfügbaren Optionen.\n",
        "\n",
        "Außerdem gibt es ab der Version `qiskit-ibm-runtime`v0.47.0 eine neue `NoiseLearnerV3` Klasse, die mit der Executor-Primitive kompatibel ist. Diese neue Version, die ebenfalls Teil des [Modells](/docs/guides/directed-execution-model) der gerichteten Ausführung ist, bietet Ihnen die Möglichkeit, die Ebenen, die Sie trainieren möchten, explizit anzugeben.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  `NoiseLearner` funktioniert nur mit dem serverseitigen „ EstimatorV2 “ und `NoiseLearnerV3` nur mit „Executor“ sowie dem neuen clientseitigen „Estimator“ (eingeführt in qiskit-ibm-runtime v0.50.0 ).\n",
        "</Admonition>\n",
        "\n",
        "<span id=\"noiselearner\" />\n",
        "\n",
        "## `NoiseLearner`\n",
        "\n",
        "<span id=\"overview\" />\n",
        "\n",
        "### Übersicht\n",
        "\n",
        "In dieser `NoiseLearner` Vorlesung werden Experimente durchgeführt, die Rauschprozesse auf der Grundlage eines Pauli-Lindblad-Rauschmodells für eine (oder mehrere) Schaltungen charakterisieren. Es verfügt über eine `run()` Methode, die die Lernversuche ausführt und entweder eine Liste von Schaltkreisen oder ein [PUB](/docs/guides/primitive-input-output) als Eingabe entgegennimmt und ein Objekt `NoiseLearnerResult` zurückgibt, das die erlernten Rauschkanäle sowie Metadaten zu den übermittelten Aufträgen enthält. Nachfolgend finden Sie einen Codeausschnitt, der die Verwendung des Hilfsprogramms veranschaulicht.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "d9a5320d-8ec6-483a-9ecf-931b0f5f5d13",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit import QuantumCircuit\n",
        "from qiskit.transpiler import CouplingMap\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, EstimatorV2\n",
        "from qiskit_ibm_runtime.noise_learner import NoiseLearner\n",
        "from qiskit_ibm_runtime.options import (\n",
        "    NoiseLearnerOptions,\n",
        "    ResilienceOptionsV2,\n",
        "    EstimatorOptions,\n",
        ")\n",
        "\n",
        "# Build a circuit with two entangling layers\n",
        "num_qubits = 27\n",
        "edges = list(CouplingMap.from_line(num_qubits, bidirectional=False))\n",
        "even_edges = edges[::2]\n",
        "odd_edges = edges[1::2]\n",
        "\n",
        "circuit = QuantumCircuit(num_qubits)\n",
        "for pair in even_edges:\n",
        "    circuit.cx(pair[0], pair[1])\n",
        "for pair in odd_edges:\n",
        "    circuit.cx(pair[0], pair[1])\n",
        "\n",
        "# Choose a backend to run on\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy()\n",
        "\n",
        "# Transpile the circuit for execution\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=3)\n",
        "circuit_to_learn = pm.run(circuit)\n",
        "\n",
        "# Instantiate a NoiseLearner object and execute the noise learning program\n",
        "learner = NoiseLearner(mode=backend)\n",
        "job = learner.run([circuit_to_learn])\n",
        "noise_model = job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ef141d65-d14d-4e2b-9813-b8766e29fdb9",
      "metadata": {},
      "source": [
        "Das Ergebnis ist `NoiseLearnerResult.data` eine Liste von Objekten [`LayerError`](/docs/api/qiskit-ibm-runtime/results-layer-error) , die das [Rauschmodell](https://arxiv.org/abs/2201.09866) für jede einzelne Verschränkungsschicht enthalten, die zu den Zielschaltungen gehört. Jedes speichert `LayerError` die Schichteninformationen in Form einer Schaltung und einer Reihe von Qubit-Bezeichnungen sowie die [`PauliLindbladError`](/docs/api/qiskit-ibm-runtime/results-pauli-lindblad-error) für die jeweilige Schicht gelernten Parameter des Rauschmodells.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "a9be8ff1-7494-407c-853c-50d471a2f55f",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Noise learner result contains 2 entries and has the following type:\n",
            " <class 'qiskit_ibm_runtime.utils.noise_learner_result.NoiseLearnerResult'>\n",
            "\n",
            "Each element of `NoiseLearnerResult` then contains an object of type:\n",
            " <class 'qiskit_ibm_runtime.utils.noise_learner_result.LayerError'>\n",
            "\n",
            "And each of these `LayerError` objects possess data on the generators for the error channel: \n",
            "['IIIIIIIIIIIIIIIIIIIIIIIIIIX', 'IIIIIIIIIIIIIIIIIIIIIIIIIIY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIIZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIXI',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIXX', 'IIIIIIIIIIIIIIIIIIIIIIIIIXY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIXZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIYI',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIYX', 'IIIIIIIIIIIIIIIIIIIIIIIIIYY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIYZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIZI',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIZX', 'IIIIIIIIIIIIIIIIIIIIIIIIIZY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIZZ', 'IIIIIIIIIIIIIIIIIIIIIIIIXII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIXXI', 'IIIIIIIIIIIIIIIIIIIIIIIIXYI',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIXZI', 'IIIIIIIIIIIIIIIIIIIIIIIIYII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIYXI', 'IIIIIIIIIIIIIIIIIIIIIIIIYYI',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIYZI', 'IIIIIIIIIIIIIIIIIIIIIIIIZII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIZXI', 'IIIIIIIIIIIIIIIIIIIIIIIIZYI',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIZZI', 'IIIIIIIIIIIIIIIIIIIIIIIXIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIXXII', 'IIIIIIIIIIIIIIIIIIIIIIIXYII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIXZII', 'IIIIIIIIIIIIIIIIIIIIIIIYIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIYXII', 'IIIIIIIIIIIIIIIIIIIIIIIYYII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIYZII', 'IIIIIIIIIIIIIIIIIIIIIIIZIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIZXII', 'IIIIIIIIIIIIIIIIIIIIIIIZYII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIZZII', 'IIIIIIIIIIIIIIIIIIIIIIXIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIXXIII', 'IIIIIIIIIIIIIIIIIIIIIIXYIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIXZIII', 'IIIIIIIIIIIIIIIIIIIIIIYIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIYXIII', 'IIIIIIIIIIIIIIIIIIIIIIYYIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIYZIII', 'IIIIIIIIIIIIIIIIIIIIIIZIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIZXIII', 'IIIIIIIIIIIIIIIIIIIIIIZYIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIZZIII', 'IIIIIIIIIIIIIIIIIIIIIXIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIXIIIIX', 'IIIIIIIIIIIIIIIIIIIIIXIIIIY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIXIIIIZ', 'IIIIIIIIIIIIIIIIIIIIIYIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIYIIIIX', 'IIIIIIIIIIIIIIIIIIIIIYIIIIY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIYIIIIZ', 'IIIIIIIIIIIIIIIIIIIIIZIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIZIIIIX', 'IIIIIIIIIIIIIIIIIIIIIZIIIIY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIZIIIIZ', 'IIIIIIIIIIIIIIIIIIIIXIIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIXIXIIII', 'IIIIIIIIIIIIIIIIIIIIXIYIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIXIZIIII', 'IIIIIIIIIIIIIIIIIIIIYIIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIYIXIIII', 'IIIIIIIIIIIIIIIIIIIIYIYIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIYIZIIII', 'IIIIIIIIIIIIIIIIIIIIZIIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIZIXIIII', 'IIIIIIIIIIIIIIIIIIIIZIYIIII', ...]\n",
            "\n",
            "Along with the error rates: \n",
            "[0.00037 0.00043 0.00032 ... 0.00031 0.00035 0.00017]\n",
            "\n"
          ]
        }
      ],
      "source": [
        "import numpy\n",
        "\n",
        "print(\n",
        "    f\"Noise learner result contains {len(noise_model.data)} entries\"\n",
        "    f\" and has the following type:\\n {type(noise_model)}\\n\"\n",
        ")\n",
        "print(\n",
        "    f\"Each element of `NoiseLearnerResult` then contains\"\n",
        "    f\" an object of type:\\n {type(noise_model.data[0])}\\n\"\n",
        ")\n",
        "# Results are truncated\n",
        "with numpy.printoptions(threshold=200):\n",
        "    print(\n",
        "        f\"And each of these `LayerError` objects possess\"\n",
        "        f\" data on the generators for the error channel: \\n\"\n",
        "        f\"{noise_model.data[0].error.generators}\\n\"\n",
        "    )\n",
        "# Results are truncated\n",
        "with numpy.printoptions(threshold=200):\n",
        "    print(\n",
        "        f\"Along with the error rates: \\n{noise_model.data[0].error.rates}\\n\"\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "faa3892e-30a5-48f7-87dd-39ab1b0846d9",
      "metadata": {},
      "source": [
        "Das Attribut `LayerError.error` des Rausch-Lernergebnisses enthält die Generatoren und Fehlerraten des angepassten Pauli-Lindblad-Modells, das folgende Form hat\n",
        "\n",
        "$\\Lambda(\\rho) = \\exp{\\sum_j r_j \\left(P_j \\rho P_j^\\dagger - \\rho\\right)},$\n",
        "\n",
        "wobei $r_j$ die `LayerError.rates` und $P_j$ die in `LayerError.generators` angegebenen Pauli-Operatoren sind.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fc0000e6-e77a-4b87-a9ee-262f904953fc",
      "metadata": {},
      "source": [
        "<span id=\"noise-learning-options\" />\n",
        "\n",
        "### Optionen zum Erlernen von Geräuschen\n",
        "\n",
        "Bei der Instanziierung eines `NoiseLearner` Objekts können Sie zwischen mehreren Eingabeoptionen wählen. Diese Optionen sind in der Klasse `qiskit_ibm_runtime.options.NoiseLearnerOptions` „“ zusammengefasst und umfassen unter anderem die Möglichkeit, die maximale Anzahl der zu lernenden Schichten, die Anzahl der Randomisierungen sowie die Twirling-Strategie festzulegen. Ausführliche Informationen finden Sie in der [`NoiseLearnerOptions`](/docs/api/qiskit-ibm-runtime/options-models-noise-learner-v3-options) API-Dokumentation.\n",
        "\n",
        "Im Folgenden finden Sie ein einfaches Beispiel, das zeigt, wie man das `NoiseLearnerOptions` in einem `NoiseLearner` Experiment verwendet:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "fcd1bd93-405d-4cfb-a5d1-bb646404aa58",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Build a GHZ circuit\n",
        "circuit = QuantumCircuit(10)\n",
        "circuit.h(0)\n",
        "circuit.cx(range(0, 9), range(1, 10))\n",
        "# Choose a backend to run on\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy()\n",
        "\n",
        "# Transpile the circuit for execution\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=3)\n",
        "circuit_to_run = pm.run(circuit_to_learn)\n",
        "\n",
        "# Instantiate a NoiseLearnerOptions object\n",
        "learner_options = NoiseLearnerOptions(\n",
        "    max_layers_to_learn=3, num_randomizations=32, twirling_strategy=\"all\"\n",
        ")\n",
        "\n",
        "# Instantiate a NoiseLearner object and execute the noise learning program\n",
        "learner = NoiseLearner(mode=backend, options=learner_options)\n",
        "job = learner.run([circuit_to_run])\n",
        "noise_model = job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d952d0cc-497b-45ae-a55e-2b611ebbe4a3",
      "metadata": {},
      "source": [
        "<span id=\"input-noise-model-to-a-primitive\" />\n",
        "\n",
        "### Eingangsrauschmodell zu einer Primitive\n",
        "\n",
        "Das auf der Schaltung trainierte Rauschmodell kann auch als Eingabe für die Primitive `EstimatorV2` „ IBM Quantum “ verwendet werden. Dies kann auf verschiedene Arten an die Primitive übergeben werden. Die folgenden drei Beispiele zeigen, wie Sie das Rauschmodell direkt an das `estimator.options` Attribut übergeben können, indem Sie vor der Instanziierung einer Estimator-Primitive ein `ResilienceOptionsV2` Objekt verwenden und ein entsprechend formatiertes Dictionary übergeben.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "9826013a-f9fd-4d72-baa7-dc5395b81007",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Pass the noise model to the `estimator.options` attribute directly\n",
        "estimator = EstimatorV2(mode=backend)\n",
        "estimator.options.resilience.layer_noise_model = noise_model"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "7ab10595-5c20-4954-9001-70b8879926b4",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Specify options through a ResilienceOptionsV2 object\n",
        "resilience_options = ResilienceOptionsV2(layer_noise_model=noise_model)\n",
        "estimator_options = EstimatorOptions(resilience=resilience_options)\n",
        "estimator = EstimatorV2(mode=backend, options=estimator_options)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "17b1f8de-fe14-4998-898b-ecd409a5efd3",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Specify options by using a dictionary\n",
        "options_dict = {\n",
        "    \"resilience_level\": 2,\n",
        "    \"resilience\": {\"layer_noise_model\": noise_model},\n",
        "}\n",
        "\n",
        "estimator = EstimatorV2(mode=backend, options=options_dict)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8c167b65-2e9a-41b9-b593-edfe80a2fde4",
      "metadata": {},
      "source": [
        "Nachdem das Rauschmodell an das `EstimatorV2` Objekt übergeben wurde, kann es wie gewohnt zum Ausführen von Workloads und zur Fehlerbehebung verwendet werden.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dad71939-7fe2-42f0-90fe-6974fe0854e7",
      "metadata": {},
      "source": [
        "<span id=\"NoiseLearnerV3\" />\n",
        "\n",
        "<span id=\"noiselearnerv3\" />\n",
        "\n",
        "## NoiseLearnerV3\n",
        "\n",
        "<span id=\"overview\" />\n",
        "\n",
        "### Übersicht\n",
        "\n",
        "`NoiseLearner`Ähnlich wie führt die `NoiseLearnerV3` Klasse Experimente durch, die Rauschprozesse auf der Grundlage eines Pauli-Lindblad-Rauschmodells für eine oder mehrere Schaltungen charakterisieren. Die `run()` Methode nimmt eine Liste von Anweisungen entgegen, von denen jede eine mit Twirls annotierte [`BoxOp`](/docs/api/qiskit/qiskit.circuit.BoxOp) Struktur sein muss, die [ISA](/docs/guides/transpile#instruction-set-architecture) -Operationen enthält.\n",
        "\n",
        "Das Ergebnis eines Auftrags `NoiseLearnerV3` enthält eine Liste von [`NoiseLearnerV3Result`](/docs/api/qiskit-ibm-runtime/results-noise-learner-v3-result) Objekten, eines für jede Eingabeanweisung. Der folgende Code zeigt, wie das Hilfsprogramm verwendet wird.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "0bbd2c21-6045-4954-aee9-339e6b060805",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Found 3 unique layers\n",
            "Each instruction is of type <class 'qiskit.circuit.controlflow.box.BoxOp'>\n",
            "And has annotations: [Twirl(group='pauli', dressing='left', decomposition='rzsx'), InjectNoise(ref='r223A', modifier_ref='', site='after')]\n"
          ]
        }
      ],
      "source": [
        "from qiskit import QuantumCircuit\n",
        "from qiskit.transpiler import CouplingMap\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, Executor\n",
        "from qiskit_ibm_runtime.noise_learner_v3 import NoiseLearnerV3\n",
        "from samplomatic.transpiler import generate_boxing_pass_manager\n",
        "from samplomatic.utils import find_unique_box_instructions\n",
        "\n",
        "\n",
        "# Build a circuit with two entangling layers\n",
        "num_qubits = 27\n",
        "edges = list(CouplingMap.from_line(num_qubits, bidirectional=False))\n",
        "even_edges = edges[::2]\n",
        "odd_edges = edges[1::2]\n",
        "\n",
        "circuit = QuantumCircuit(num_qubits)\n",
        "for pair in even_edges:\n",
        "    circuit.cx(pair[0], pair[1])\n",
        "for pair in odd_edges:\n",
        "    circuit.cx(pair[0], pair[1])\n",
        "\n",
        "# Choose a backend to run on\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy()\n",
        "\n",
        "# Transpile the circuit for execution\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=3)\n",
        "isa_circuit = pm.run(circuit)\n",
        "\n",
        "# Run the boxing pass manager to group instructions into annotated boxes\n",
        "boxing_pm = generate_boxing_pass_manager(\n",
        "    enable_gates=True,\n",
        "    enable_measures=False,\n",
        "    inject_noise_targets=\"gates\",  # no measurement mitigation\n",
        "    inject_noise_strategy=\"uniform_modification\",\n",
        ")\n",
        "boxed_circuit = boxing_pm.run(isa_circuit)\n",
        "\n",
        "# Find unique boxed instructions\n",
        "unique_box_instructions = find_unique_box_instructions(boxed_circuit.data)\n",
        "print(f\"Found {len(unique_box_instructions)} unique layers\")\n",
        "print(\n",
        "    f\"Each instruction is of type {type(unique_box_instructions[0].operation)}\"\n",
        ")\n",
        "print(\n",
        "    f\"And has annotations: {unique_box_instructions[0].operation.annotations}\"\n",
        ")\n",
        "\n",
        "# Instantiate a NoiseLearnerV3 object and execute the noise learning program\n",
        "learner = NoiseLearnerV3(backend)\n",
        "learner.options.shots_per_randomization = 128\n",
        "learner.options.num_randomizations = 32\n",
        "learner_job = learner.run(unique_box_instructions)\n",
        "learner_result = learner_job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "937986c1-b08d-4218-ae5d-c9dbfbf4a0cf",
      "metadata": {},
      "source": [
        "Das Ergebnis der Funktion ist eine Liste von `NoiseLearnerV3Result` Objekten, wobei jedes Objekt einem in ein Eingabefeld eingegebenen Befehlssatz entspricht. `NoiseLearnerV3Result` verfügt über eine `to_pauli_lindblad_map()` Methode, die ein [`PauliLindbladMap`](/docs/api/qiskit/qiskit.quantum_info.PauliLindbladMap) Objekt zurückgibt, das Methoden zum Abrufen der Generatoren, Fehlerraten und weiterer Informationen enthält.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "4a9b686b-cf8d-4986-8fff-83eedda1f2c1",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The Noise learner V3 result contains 3 entries and each has the following type:\n",
            " <class 'qiskit_ibm_runtime.results.noise_learner_v3.NoiseLearnerV3Result'>\n",
            "\n",
            "After converting to PauliLindbladMap, you can extract data  on the generators for the error channel (truncated to 3): \n",
            "<QubitSparsePauliList with 3 elements on 27 qubits: [X_5, Y_5, Z_5]>\n",
            "\n",
            "Along with the error rates (truncated to 3): \n",
            "[2.3e-04 9.0e-05 1.1e-04]\n",
            "\n"
          ]
        }
      ],
      "source": [
        "print(\n",
        "    f\"The Noise learner V3 result contains {len(learner_result)} entries\"\n",
        "    f\" and each has the following type:\\n {type(learner_result[0])}\\n\"\n",
        ")\n",
        "noise_map = learner_result[0].to_pauli_lindblad_map()\n",
        "print(\n",
        "    f\"After converting to PauliLindbladMap, you can extract data \"\n",
        "    f\" on the generators for the error channel \"\n",
        "    f\"(truncated to 3): \\n{noise_map.generators()[:3]}\\n\"\n",
        ")\n",
        "with numpy.printoptions(threshold=20):\n",
        "    print(\n",
        "        f\"Along with the error rates \"\n",
        "        f\"(truncated to 3): \\n{noise_map.rates[:3]}\\n\"\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "baa61d6a-7efc-498b-bccd-260871e174df",
      "metadata": {},
      "source": [
        "<span id=\"noise-learning-options\" />\n",
        "\n",
        "### Optionen zum Erlernen von Geräuschen\n",
        "\n",
        "`NoiseLearnerV3` bietet verschiedene Optionen, darunter unter anderem die Anzahl der Randomisierungen und die Tiefe der Ebenenpaare. Ähnlich wie bei den Primitiven können Sie die Optionen während oder nach der Instanziierung des `NoiseLearnerV3` Objekts festlegen. Das vorangegangene Codebeispiel hat gezeigt, wie man die Optionen `shots_per_randomization` und `num_randomizations` einstellt. Ausführliche Informationen finden Sie in der [`NoiseLearnerV3Options`](/docs/api/qiskit-ibm-runtime/options-models-noise-learner-v3-options) API-Dokumentation.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e76e997d-506f-4607-a89a-e4723c640a44",
      "metadata": {},
      "source": [
        "<span id=\"input-a-noise-model-to-executor\" />\n",
        "\n",
        "### Ein Rauschmodell in den Executor eingeben\n",
        "\n",
        "Executor folgt den in den Schaltungsanmerkungen (in Form eines Samplex) und den Optionen festgelegten Designvorgaben. `InjectNoise` ist die Anmerkung, mit der festgelegt wird, wo Rauschen eingefügt werden soll, und das `pauli_lindblad_maps` Argument `samplex` gibt an, welche Rauschkarte verwendet werden soll.\n",
        "\n",
        "Der Ablauf im vorigen Beispiel läuft über den Boxing-Pass-Manager, der Anweisungen in kommentierte Blöcke gruppiert. Der entsprechende Code wird hier zum besseren Verständnis eingefügt.\n",
        "\n",
        "* `inject_noise_targets=”gates”` legt fest, dass die `InjectNoise` Anmerkungen zu Feldern hinzugefügt werden sollen, die Verflechtungen enthalten.\n",
        "* `inject_noise_strategy=\"uniform_modification\"` legt fest, dass allen gleichwertigen Feldern mit `InjectNoise` Anmerkungen dieselben `ref` Werte und `modifier_ref` zugewiesen werden.\n",
        "  * `InjectNoise.ref` ist eine eindeutige Kennung, die dazu dient, diesem Feld ein Lärmmodell zuzuweisen.\n",
        "  * `InjectNoise.modifier_ref` ermöglicht die Skalierung des einer Box zugewiesenen Rauschmodells durch Multiplikationsfaktoren.\n",
        "\n",
        "```python\n",
        "boxing_pm = generate_boxing_pass_manager(\n",
        "    enable_gates=True,\n",
        "    enable_measures=False,\n",
        "    inject_noise_targets=\"gates\",  # no measurement mitigation\n",
        "    inject_noise_strategy=\"uniform_modification\",\n",
        ")\n",
        "```\n",
        "\n",
        "Der Schaltkreis aus dem vorherigen Beispiel enthält drei Kästchen, von denen zwei Anmerkungen mit unterschiedlichen `ref` Attributen enthalten `InjectNoise` (da sie nicht gleichwertig sind).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "3b86853b-6766-4cf6-9a6b-2ea1008aea42",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Annotations of box #0: [Twirl(group='pauli', dressing='left', decomposition='rzsx'), InjectNoise(ref='r223A', modifier_ref='r223A', site='after')]\n",
            "\n",
            "Annotations of box #1: [Twirl(group='pauli', dressing='left', decomposition='rzsx'), InjectNoise(ref='r621A', modifier_ref='r621A', site='after')]\n",
            "\n",
            "Annotations of box #2: [Twirl(group='pauli', dressing='right', decomposition='rzsx')]\n",
            "\n"
          ]
        }
      ],
      "source": [
        "# box_circuit comes from the example above\n",
        "for idx, instruction in enumerate(boxed_circuit):\n",
        "    # The `InjectNoise` annotation defines which boxes to inject noise.\n",
        "    print(f\"Annotations of box #{idx}: {instruction.operation.annotations}\\n\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3ab1e503-b36a-46bd-b5d1-2735c3d0a82d",
      "metadata": {},
      "source": [
        "Das Ergebnis des `NoiseLearnerV3` Auftrags muss in ein Dictionary konvertiert werden, bevor es an den Executor übergeben wird. Die Schlüssel dieses Wörterbuchs sind die `InjectNoise.ref` Attribute, und die Werte sind die entsprechenden Rauschkarten. Diese Zuordnung teilt Executor mit, welche Rauschmodelle an welcher Stelle eingefügt werden sollen.\n",
        "\n",
        "Der folgende Code zeigt, wie man den Schaltkreis und das `NoiseLearnerV3` Ergebnis aus dem vorherigen Beispiel an den Executor übergibt, der die Schaltkreisvarianten mit den eingefügten Rauschmodellen generiert und diese auf der Hardware ausführt.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "96d59082-7adc-482a-b57f-0f7a5c3eb217",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_ibm_runtime.quantum_program import QuantumProgram\n",
        "from samplomatic import build\n",
        "\n",
        "# Generate a quantum program\n",
        "program = QuantumProgram(shots=1000)\n",
        "\n",
        "# Build the template circuit and samplex pair\n",
        "template_circuit, samplex = build(boxed_circuit)\n",
        "\n",
        "# Convert the NoiseLearnerV3 result to a dictionary\n",
        "noise_maps = learner_result.to_dict(\n",
        "    instructions=unique_box_instructions, require_refs=False\n",
        ")\n",
        "\n",
        "# Append the samplex item and execute\n",
        "program.append_samplex_item(\n",
        "    template_circuit,\n",
        "    samplex=samplex,\n",
        "    samplex_arguments={\n",
        "        \"pauli_lindblad_maps\": noise_maps,\n",
        "    },\n",
        ")\n",
        "\n",
        "executor = Executor(backend)\n",
        "executor_job = executor.run(program)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5759bcd1-afb9-4660-889e-485dff65d102",
      "metadata": {},
      "source": [
        "<span id=\"using-noiselearnerv3-with-client-side-estimator\" />\n",
        "\n",
        "### Verwendung von „ NoiseLearnerV3 “ mit dem clientseitigen Estimator\n",
        "\n",
        "Der folgende Code zeigt, wie das Hilfsprogramm mit dem neuen clientseitigen Estimator verwendet wird\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "85c85e3d-bedf-4c2f-950e-1c44cd997f2a",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit import QuantumCircuit\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, NoiseLearnerV3\n",
        "from qiskit_ibm_runtime.executor_estimator import Estimator\n",
        "\n",
        "\n",
        "# 1. Account + backend\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(operational=True, simulator=False)\n",
        "\n",
        "# 2. Circuit + observable\n",
        "circuit = QuantumCircuit(2)\n",
        "circuit.h(0)\n",
        "circuit.cx(0, 1)\n",
        "\n",
        "observable = SparsePauliOp(\"ZZ\")\n",
        "\n",
        "# 3. Transpile to ISA\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=1)\n",
        "isa_circuit = pm.run(circuit)\n",
        "isa_observable = observable.apply_layout(isa_circuit.layout)\n",
        "pubs = [(isa_circuit, isa_observable)]\n",
        "\n",
        "# 4. Initialize Estimator with options\n",
        "estimator = Estimator(backend)\n",
        "estimator.options.resilience.pec_mitigation = True\n",
        "\n",
        "# 5. Extract the unique boxed layers from PUBs\n",
        "layers = estimator.find_unique_layers(pubs)\n",
        "\n",
        "# 6. Learn the noise model for those layers.\n",
        "learner = NoiseLearnerV3(backend)\n",
        "learner_job = learner.run(layers)\n",
        "learner_result = learner_job.result()\n",
        "\n",
        "# 7. Convert the result to Pauli-Lindblad maps and pass them to Estimator.\n",
        "pauli_lindblad_maps = learner_result.to_pauli_lindblad_maps()\n",
        "estimator.options.resilience.layer_noise_model = zip(\n",
        "    layers, pauli_lindblad_maps\n",
        ")\n",
        "\n",
        "# 8. Execute the target PUBs.\n",
        "job = estimator.run(pubs)\n",
        "result = job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "936c08fb-7838-4d61-9060-092b479e7909",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Nächste Schritte\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Empfehlungen\">\n",
        "  * Lesen Sie die [API-Referenz zu „ EstimatorOptions “ und](/docs/api/qiskit-ibm-runtime/options-models-estimator-options) [die API-Referenz zu „ ResilienceOptionsV2 “.](/docs/api/qiskit-ibm-runtime/options-models-resilience-options)\n",
        "  * Erfahren Sie mehr über [die](error-mitigation-and-suppression-techniques) verfügbaren Techniken zur Fehlerminderung und -unterdrückung.\n",
        "  * Erfahren Sie, wie Sie [das Rauschmanagement für Schätzer](/docs/guides/estimator-noise-management) implementieren.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}