{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "1fd07edc-2356-49d3-bf35-6e4e1256b61b",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Ein- und Ausgänge des Samplers\"\n",
        "description: \"Die Eingabe- und Ausgabeformate der Sampler-Primitive verstehen\"\n",
        "---\n",
        "\n",
        "<span id=\"sampler-inputs-and-outputs\" />\n",
        "\n",
        "# Ein- und Ausgänge des Samplers\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fcd633c9-366b-440f-8997-7c60692e5a4d",
      "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, diese Versionen oder neuere zu verwenden.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.5.2\n",
        "    qiskit-ibm-runtime~=0.47.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "672f7038-64e7-42cc-9936-c30a03596791",
      "metadata": {},
      "source": [
        "Diese Seite bietet einen Überblick über die Ein- und Ausgänge der `qiskit-ibm-runtime` „Sampler“-Primitive, die Workloads auf dem IBM Quantum® Compute -Dienst ausführt. Mit Sampler können Sie vektorisierte Workloads mithilfe einer Datenstruktur namens [**„Primitive Unified Bloc“ ( PUB )**](/docs/guides/primitive-input-output#pubs) effizient definieren. Sie dienen als Eingaben für die Methode [`run()`](/docs/api/qiskit-ibm-runtime/executor-sampler-sampler#run) der Sampler-Primitive, die die definierte Arbeitslast als Job ausführt. Nachdem der Auftrag abgeschlossen ist, werden die Ergebnisse in einem Format zurückgegeben, das sowohl von den verwendeten PUBs als auch von den in der Primitive angegebenen Laufzeitoptionen abhängt.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0115445a-d695-4806-8a9a-6bcd2451e418",
      "metadata": {},
      "source": [
        "<span id=\"inputs\" />\n",
        "\n",
        "## Eingaben\n",
        "\n",
        "Jede „ PUB “-Datei hat das folgende Format:\n",
        "\n",
        "(`<single circuit>`, `<one or more optional parameter value>`, `<optional shots>`),\n",
        "\n",
        "Es können mehrere `parameter values` Elemente vorhanden sein, und jedes Element kann je nach gewähltem Schaltkreis entweder ein Array oder ein einzelner Parameter sein. Außerdem muss die Eingabe Messwerte enthalten.\n",
        "\n",
        "Bei der Sampler-Primitive kann ein „ PUB “ höchstens drei Werte enthalten:\n",
        "\n",
        "* Ein Einzelobjekt `QuantumCircuit`, das ein oder mehrere [`Parameter`](/docs/api/qiskit/qiskit.circuit.Parameter) Objekte enthalten kann\n",
        "  *Hinweis: Diese Schaltkreise sollten auch Messanweisungen für jedes der zu messenden Qubits enthalten.*\n",
        "* Eine Sammlung von Parameterwerten zur Anbindung der Schaltung an $\\theta_k$ (nur erforderlich, wenn Objekte `Parameter` verwendet werden, die zur Laufzeit gebunden werden müssen)\n",
        "* (optional) eine bestimmte Anzahl von Messungen zur Überprüfung der Schaltung\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f2314472-55e7-4f31-824e-31b18179e18d",
      "metadata": {},
      "source": [
        "***\n",
        "\n",
        "Der folgende Code zeigt ein Beispiel für eine Reihe vektorisierter Eingaben für die `Sampler` Primitive und führt diese auf einem „ IBM® “-Backend als ein einziges `RuntimeJobV2 ` Objekt aus.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "21687f88-51fc-4139-91b0-3fb4542716ca",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.circuit import (\n",
        "    Parameter,\n",
        "    QuantumCircuit,\n",
        "    ClassicalRegister,\n",
        "    QuantumRegister,\n",
        ")\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit.primitives.containers import BitArray\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "\n",
        "# Legacy server-side primitive before qiskit-ibm-runtime 0.50.0\n",
        "# from qiskit_ibm_runtime import Sampler\n",
        "\n",
        "# Client-side primitive introduced in qiskit-ibm-runtime 0.50.0\n",
        "from qiskit_ibm_runtime.executor_sampler import Sampler\n",
        "\n",
        "import numpy as np\n",
        "\n",
        "# Instantiate runtime service and get\n",
        "# the least busy backend\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(operational=True, simulator=False)\n",
        "\n",
        "# Define a circuit with two parameters.\n",
        "circuit = QuantumCircuit(2)\n",
        "circuit.h(0)\n",
        "circuit.cx(0, 1)\n",
        "circuit.ry(Parameter(\"a\"), 0)\n",
        "circuit.rz(Parameter(\"b\"), 0)\n",
        "circuit.cx(0, 1)\n",
        "circuit.h(0)\n",
        "circuit.measure_all()\n",
        "\n",
        "# Transpile the circuit\n",
        "pm = generate_preset_pass_manager(optimization_level=1, backend=backend)\n",
        "transpiled_circuit = pm.run(circuit)\n",
        "layout = transpiled_circuit.layout\n",
        "\n",
        "# Now define a sweep over parameter values, the last axis of dimension 2 is\n",
        "# for the two parameters \"a\" and \"b\"\n",
        "params = np.vstack(\n",
        "    [\n",
        "        np.linspace(-np.pi, np.pi, 100),\n",
        "        np.linspace(-4 * np.pi, 4 * np.pi, 100),\n",
        "    ]\n",
        ").T\n",
        "\n",
        "sampler_pub = (transpiled_circuit, params)\n",
        "\n",
        "# Instantiate the new Sampler object, then run the transpiled circuit\n",
        "# using the set of parameters and observables.\n",
        "sampler = Sampler(mode=backend)\n",
        "job = sampler.run([sampler_pub])\n",
        "result = job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9f1a6c43-a00c-421f-b11d-62d3237f1ccb",
      "metadata": {},
      "source": [
        "<span id=\"outputs\" />\n",
        "\n",
        "## Ausgaben\n",
        "\n",
        "Nachdem ein oder mehrere PUBs zur Ausführung an eine QPU gesendet wurden und ein Job erfolgreich abgeschlossen wurde, werden die Daten als [`PrimitiveResult`](/docs/api/qiskit/qiskit.primitives.PrimitiveResult) Containerobjekt zurückgegeben, auf das durch Aufruf der `RuntimeJobV2.result()` Methode zugegriffen wird. Das `PrimitiveResult` enthält eine iterierbare Liste von [`SamplerPubResult`](/docs/api/qiskit/qiskit.primitives.SamplerPubResult) Objekten, die die Ausführungsergebnisse für jeden PUB enthalten. Diese Daten sind Abtastwerte des Schaltungsausgangs.\n",
        "\n",
        "Jedes Element dieser Liste entspricht einem „ PUB “, das an die Methode `run()` der Primitive übergeben wurde (ein Job, der beispielsweise mit 20 PUBs übergeben wurde, gibt ein `PrimitiveResult` Objekt zurück, das eine Liste mit 20 `SamplerPubResult` Objekten enthält, wobei jedes Objekt einem „ PUB “ entspricht).\n",
        "\n",
        "Jedes `SamplerPubResult` Objekt verfügt sowohl über ein `data` als auch über ein `metadata` Attribut.\n",
        "\n",
        "* Das `data` Attribut ist ein benutzerdefiniertes [`DataBin`](/docs/api/qiskit/qiskit.primitives.DataBin) Feld, das die tatsächlichen Messwerte, Standardabweichungen usw. enthält. Die Datenbehälter sind dict-ähnliche Objekte, die jeweils einen Wert `BitArray` pro `ClassicalRegister` Schaltkreis enthalten.\n",
        "* Die `BitArray` Klasse dient als Container für geordnete Aufnahmedaten. Es speichert die abgetasteten Bitfolgen als Bytes in einem zweidimensionalen Array. Die Achse ganz links in diesem Array erstreckt sich über geordnete Aufnahmen, während sich die Achse ganz rechts über Bytes erstreckt.\n",
        "* Das `metadata` Attribut enthält Informationen zu den verwendeten Laufzeitoptionen (die später im Abschnitt [„Ergebnis-Metadaten“](#result-metadata) dieser Seite erläutert werden).\n",
        "\n",
        "Im Folgenden finden Sie eine grafische Darstellung der `PrimitiveResult` Datenstruktur:\n",
        "\n",
        "```\n",
        "    └── PrimitiveResult\n",
        "        ├── SamplerPubResult[0]\n",
        "        │   ├── metadata\n",
        "        │   └── data  ## In the form of a DataBin object\n",
        "        │       ├── NAME_OF_CLASSICAL_REGISTER\n",
        "        │       │   └── BitArray of count data (default is 'meas')\n",
        "        |       |\n",
        "        │       └── NAME_OF_ANOTHER_CLASSICAL_REGISTER\n",
        "        │           └── BitArray of count data (exists only if more than one\n",
        "        |                 ClassicalRegister was specified in the circuit)\n",
        "        ├── SamplerPubResult[1]\n",
        "        |   ├── metadata\n",
        "        |   └── data  ## In the form of a DataBin object\n",
        "        |       └── NAME_OF_CLASSICAL_REGISTER\n",
        "        |           └── BitArray of count data for second pub\n",
        "        ├── ...\n",
        "        ├── ...\n",
        "        └── ...\n",
        "```\n",
        "\n",
        "Einfach ausgedrückt: Eine einzelne Funktion gibt ein [`PrimitiveResult`](/docs/api/qiskit/qiskit.primitives.PrimitiveResult) Objekt zurück und enthält eine Liste mit einem oder mehreren [`SamplerPubResult`](/docs/api/qiskit/qiskit.primitives.SamplerPubResult) Objekten. Diese `SamplerPubResult` Objekte speichern dann die Messdaten für jeden „ PUB “, der an den Job übermittelt wurde.\n",
        "\n",
        "Betrachten wir als erstes Beispiel die folgende Schaltung mit zehn Qubits:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "e42b2fd8-0790-4a38-9082-f2334440e411",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Databin: DataBin(meas=BitArray(<shape=(), num_shots=4096, num_bits=10>))\n",
            "\n",
            "BitArray: BitArray(<shape=(), num_shots=4096, num_bits=10>)\n",
            "\n",
            "The shape of register `meas` is (4096, 2).\n",
            "\n",
            "The bytes in register `alpha`, shot by shot:\n",
            "[[  3 247]\n",
            " [  0   0]\n",
            " [  3 223]\n",
            " ...\n",
            " [  0 255]\n",
            " [  0   0]\n",
            " [  0   0]]\n",
            "\n"
          ]
        }
      ],
      "source": [
        "# generate a ten-qubit GHZ circuit\n",
        "circuit = QuantumCircuit(10)\n",
        "circuit.h(0)\n",
        "circuit.cx(range(0, 9), range(1, 10))\n",
        "\n",
        "# append measurements with the `measure_all` method\n",
        "circuit.measure_all()\n",
        "\n",
        "# transpile the circuit\n",
        "transpiled_circuit = pm.run(circuit)\n",
        "\n",
        "# run the Sampler job and retrieve the results\n",
        "sampler = Sampler(mode=backend)\n",
        "job = sampler.run([transpiled_circuit])\n",
        "result = job.result()\n",
        "\n",
        "# the data bin contains one BitArray\n",
        "data = result[0].data\n",
        "print(f\"Databin: {data}\\n\")\n",
        "\n",
        "# to access the BitArray, use the key \"meas\", which is the default name of\n",
        "# the classical register when this is added by the `measure_all` method\n",
        "array = data.meas\n",
        "print(f\"BitArray: {array}\\n\")\n",
        "print(f\"The shape of register `meas` is {data.meas.array.shape}.\\n\")\n",
        "print(f\"The bytes in register `alpha`, shot by shot:\\n{data.meas.array}\\n\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5926adf1-c7db-425a-a5cf-cb97eb5fa389",
      "metadata": {},
      "source": [
        "Manchmal kann es praktisch sein, Daten aus dem `BitArray` Byte-Format in Bitstrings umzuwandeln. Die `get_count` Methode gibt ein Wörterbuch zurück, in dem Bitstrings der Häufigkeit ihres Auftretens zugeordnet sind.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "b4eb01c9-d438-46ca-9057-4e91b7656748",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Counts: {'1111110111': 28, '0000000000': 1680, '1111011111': 35, '1111111111': 1467, '1110000000': 28, '0000000010': 15, '1111111011': 15, '1110111111': 7, '1000000000': 52, '1111101111': 16, '1111110000': 22, '0000000101': 3, '0001111101': 1, '0000000111': 17, '0000000001': 66, '1111111110': 119, '0000001000': 15, '0011111111': 24, '1111111101': 38, '0000001111': 32, '1100000000': 39, '1101111111': 51, '0000011111': 34, '1110000010': 2, '0010000000': 25, '0111111111': 21, '0001111111': 34, '1011111111': 16, '1000011111': 3, '0000001101': 1, '1111100000': 22, '1111111100': 22, '1111111000': 8, '0010001011': 1, '0011000000': 1, '0000000011': 16, '0011111100': 2, '1011110001': 1, '1101111100': 1, '1101111101': 1, '0000000110': 2, '0000000100': 2, '0001111110': 6, '0000001110': 4, '0011110111': 2, '1101111110': 3, '0111111011': 1, '0110000000': 1, '0000001011': 2, '1111110110': 3, '0111111000': 1, '1010000000': 2, '0001110111': 1, '1111101000': 1, '0010011110': 1, '1111100111': 1, '0111110111': 1, '0100000000': 5, '1101110111': 1, '0000001001': 1, '0010000001': 1, '1111000001': 1, '0000010000': 3, '1111101110': 1, '1111000000': 8, '0001011111': 3, '1000000001': 1, '1111010111': 2, '0010011111': 1, '1011111110': 1, '1101101111': 1, '1111011110': 2, '1111111010': 1, '1111010000': 1, '1101000000': 1, '1100001111': 1, '1100011111': 1, '0000111111': 4, '0010111111': 1, '1000000110': 1, '1110111110': 1, '1101011111': 2, '0000011000': 1, '1101110000': 2, '1011111011': 1, '1000111111': 1, '1011000000': 1, '1110000001': 2, '0101111111': 2, '1111110101': 1, '0010000011': 1, '0000011110': 1, '0000011101': 1, '0111000000': 1, '0001110000': 1, '0001000000': 4, '1101111000': 1, '1011111000': 1, '0111110000': 1, '1101110110': 1, '0011011111': 1, '0000100000': 2, '1111101100': 1, '1100001000': 1, '1010000011': 1, '0011111110': 1, '1010001110': 1, '1000001000': 1, '1000000011': 1, '1111101011': 1}\n"
          ]
        }
      ],
      "source": [
        "# optionally, convert away from the native BitArray format to a dictionary format\n",
        "counts = data.meas.get_counts()\n",
        "print(f\"Counts: {counts}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e186d055-09e7-421c-8d70-0d27e7d0edaa",
      "metadata": {},
      "source": [
        "Wenn eine Schaltung mehr als ein klassisches Register enthält, werden die Ergebnisse in verschiedenen `BitArray` Objekten gespeichert. Das folgende Beispiel erweitert den vorherigen Codeausschnitt, indem es das klassische Register in zwei separate Register aufteilt:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "e81d87ce-2fd6-4498-a9a5-f3432209fccd",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "BitArray for register 'alpha': BitArray(<shape=(), num_shots=4096, num_bits=1>)\n",
            "BitArray for register 'beta': BitArray(<shape=(), num_shots=4096, num_bits=9>)\n"
          ]
        }
      ],
      "source": [
        "# generate a ten-qubit GHZ circuit with two classical registers\n",
        "circuit = QuantumCircuit(\n",
        "    qreg := QuantumRegister(10),\n",
        "    alpha := ClassicalRegister(1, \"alpha\"),\n",
        "    beta := ClassicalRegister(9, \"beta\"),\n",
        ")\n",
        "circuit.h(0)\n",
        "circuit.cx(range(0, 9), range(1, 10))\n",
        "\n",
        "# append measurements with the `measure_all` method\n",
        "circuit.measure([0], alpha)\n",
        "circuit.measure(range(1, 10), beta)\n",
        "\n",
        "# transpile the circuit\n",
        "transpiled_circuit = pm.run(circuit)\n",
        "\n",
        "# run the Sampler job and retrieve the results\n",
        "sampler = Sampler(mode=backend)\n",
        "job = sampler.run([transpiled_circuit])\n",
        "result = job.result()\n",
        "\n",
        "# the data bin contains two BitArrays, one per register, and can be accessed\n",
        "# as attributes using the registers' names\n",
        "data = result[0].data\n",
        "print(f\"BitArray for register 'alpha': {data.alpha}\")\n",
        "print(f\"BitArray for register 'beta': {data.beta}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d93dd9f5-cc43-41b0-b350-f545a14d1f38",
      "metadata": {},
      "source": [
        "<span id=\"use-bitarray-objects-for-performant-post-processing\" />\n",
        "\n",
        "### Verwenden Sie `BitArray` Objekte für eine leistungsstarke Nachbearbeitung\n",
        "\n",
        "Da Arrays im Vergleich zu Dictionaries in der Regel eine bessere Leistung bieten, ist es ratsam, jegliche Nachbearbeitung direkt an den `BitArray` Objekten durchzuführen und nicht an Dictionaries mit Zählwerten. Die `BitArray` Klasse bietet eine Reihe von Methoden zur Durchführung einiger gängiger Nachbearbeitungsvorgänge:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "6465d11b-9e5b-4078-a1be-75229297093a",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The shape of register `alpha` is (4096, 1).\n",
            "The bytes in register `alpha`, shot by shot:\n",
            "[[1]\n",
            " [0]\n",
            " [1]\n",
            " ...\n",
            " [0]\n",
            " [1]\n",
            " [0]]\n",
            "\n",
            "The shape of register `beta` is (4096, 2).\n",
            "The bytes in register `beta`, shot by shot:\n",
            "[[  1 255]\n",
            " [  0   0]\n",
            " [  1 255]\n",
            " ...\n",
            " [  0   0]\n",
            " [  1 255]\n",
            " [  0   0]]\n",
            "\n",
            "The shape of `beta` after post-selection is (0, 2).\n",
            "The bytes in `beta` after post-selection:\n",
            "[]\n",
            "The shape of `beta` after bit-wise slicing is (4096, 1).\n",
            "The bytes in `beta` after bit-wise slicing:\n",
            "[[7]\n",
            " [0]\n",
            " [7]\n",
            " ...\n",
            " [0]\n",
            " [7]\n",
            " [0]]\n",
            "\n",
            "The shape of `beta` after shot-wise slicing is (5, 2).\n",
            "The bytes in `beta` after shot-wise slicing:\n",
            "[[  1 255]\n",
            " [  0   0]\n",
            " [  1 255]\n",
            " [  1 255]\n",
            " [  1 255]]\n",
            "\n",
            "Exp. val. for observable `SparsePauliOp(['ZZZZZZZZZ'],\n",
            "              coeffs=[1.+0.j])` is: 0.0595703125\n",
            "Exp. val. for observable `SparsePauliOp(['IIIIIIIIZ'],\n",
            "              coeffs=[1.+0.j])` is: 0.02783203125\n",
            "\n",
            "The shape of the merged results is (4096, 2).\n",
            "The bytes of the merged results:\n",
            "[[  3 255]\n",
            " [  0   0]\n",
            " [  3 255]\n",
            " ...\n",
            " [  0   0]\n",
            " [  3 255]\n",
            " [  0   0]]\n",
            "\n"
          ]
        }
      ],
      "source": [
        "print(f\"The shape of register `alpha` is {data.alpha.array.shape}.\")\n",
        "print(f\"The bytes in register `alpha`, shot by shot:\\n{data.alpha.array}\\n\")\n",
        "\n",
        "print(f\"The shape of register `beta` is {data.beta.array.shape}.\")\n",
        "print(f\"The bytes in register `beta`, shot by shot:\\n{data.beta.array}\\n\")\n",
        "\n",
        "# post-select the bitstrings of `beta` based on having sampled \"1\" in `alpha`\n",
        "mask = data.alpha.array == \"0b1\"\n",
        "ps_beta = data.beta[mask[:, 0]]\n",
        "print(f\"The shape of `beta` after post-selection is {ps_beta.array.shape}.\")\n",
        "print(f\"The bytes in `beta` after post-selection:\\n{ps_beta.array}\")\n",
        "\n",
        "# get a slice of `beta` to retrieve the first three bits\n",
        "beta_sl_bits = data.beta.slice_bits([0, 1, 2])\n",
        "print(\n",
        "    f\"The shape of `beta` after bit-wise slicing is {beta_sl_bits.array.shape}.\"\n",
        ")\n",
        "print(f\"The bytes in `beta` after bit-wise slicing:\\n{beta_sl_bits.array}\\n\")\n",
        "\n",
        "# get a slice of `beta` to retrieve the bytes of the first five shots\n",
        "beta_sl_shots = data.beta.slice_shots([0, 1, 2, 3, 4])\n",
        "print(\n",
        "    f\"The shape of `beta` after shot-wise slicing is {beta_sl_shots.array.shape}.\"\n",
        ")\n",
        "print(\n",
        "    f\"The bytes in `beta` after shot-wise slicing:\\n{beta_sl_shots.array}\\n\"\n",
        ")\n",
        "\n",
        "# calculate the expectation value of diagonal operators on `beta`\n",
        "ops = [SparsePauliOp(\"ZZZZZZZZZ\"), SparsePauliOp(\"IIIIIIIIZ\")]\n",
        "exp_vals = data.beta.expectation_values(ops)\n",
        "for o, e in zip(ops, exp_vals):\n",
        "    print(f\"Exp. val. for observable `{o}` is: {e}\")\n",
        "\n",
        "# concatenate the bitstrings in `alpha` and `beta` to \"merge\" the results of the two\n",
        "# registers\n",
        "merged_results = BitArray.concatenate_bits([data.alpha, data.beta])\n",
        "print(f\"\\nThe shape of the merged results is {merged_results.array.shape}.\")\n",
        "print(f\"The bytes of the merged results:\\n{merged_results.array}\\n\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b3765ba4-ffaa-4f51-a657-1fdfb588b849",
      "metadata": {},
      "source": [
        "<span id=\"result-metadata\" />\n",
        "\n",
        "## Metadaten zum Ergebnis\n",
        "\n",
        "Zusätzlich zu den Ausführungsergebnissen enthalten sowohl das `PrimitiveResult` als auch `SamplerPubResult` das Objekt ein Metadatenattribut zu dem übermittelten Auftrag. Die Metadaten, die Informationen zu allen eingereichten PUBs enthalten (wie beispielsweise die verschiedenen verfügbaren [Laufzeitoptionen](/docs/api/qiskit-ibm-runtime/options) ), finden Sie in der `PrimitiveResult.metatada`, während die für jede einzelne „ PUB “ spezifischen Metadaten in der zu finden `SamplerPubResult.metadata` sind.\n",
        "\n",
        "Die Metadaten des Sampler-Ergebnisses enthalten auch Informationen zum Ausführungszeitpunkt, die als [*„*](#execution-spans) Ausführungsdauer“ bezeichnet werden.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  Im Metadatenfeld können Primitivimplementierungen beliebige für sie relevante Informationen zur Ausführung zurückgeben, und es gibt keine Schlüssel-Wert-Paare, die von der Basisprimitive garantiert werden. Daher können sich die zurückgegebenen Metadaten bei verschiedenen Implementierungen der Primitive unterscheiden.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "9a40d177-917b-484a-a809-44554efcee28",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The metadata of the PrimitiveResult is:\n",
            "'execution' : {'execution_spans': ExecutionSpans([DoubleSliceSpan(<start='2026-09-01 07:46:47', stop='2026-09-01 07:46:49', size=4096>)])},\n",
            "'version' : 2,\n",
            "\n",
            "The metadata of the PubResult result is:\n",
            "'circuit_metadata' : {},\n"
          ]
        }
      ],
      "source": [
        "# Print out the results metadata\n",
        "print(\"The metadata of the PrimitiveResult is:\")\n",
        "for key, val in result.metadata.items():\n",
        "    print(f\"'{key}' : {val},\")\n",
        "\n",
        "print(\"\\nThe metadata of the PubResult result is:\")\n",
        "for key, val in result[0].metadata.items():\n",
        "    print(f\"'{key}' : {val},\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "403dd006-33ec-4bd6-ad45-857535857077",
      "metadata": {},
      "source": [
        "<span id=\"execution-spans\" />\n",
        "\n",
        "<span id=\"view-execution-spans\" />\n",
        "\n",
        "### Ausführungsspannen anzeigen\n",
        "\n",
        "Die Ergebnisse der im „ IBM Quantum Compute “-Dienst ausgeführten Jobs [`SamplerV2`](/docs/api/qiskit-ibm-runtime/executor-sampler-sampler) enthalten in ihren Metadaten Angaben zum Ausführungszeitpunkt.\n",
        "Anhand dieser Zeitangaben lassen sich obere und untere Zeitgrenzen dafür festlegen, wann bestimmte Befehle auf der QPU ausgeführt wurden.\n",
        "Die Aufnahmen sind in [`ExecutionSpan`](/docs/api/qiskit-ibm-runtime/execution-span-execution-span) Objekte gruppiert, von denen jedes eine Startzeit, eine Endzeit und eine Angabe darüber enthält, welche Aufnahmen in diesem Zeitraum erfasst wurden.\n",
        "\n",
        "Ein Ausführungsfenster gibt durch die Angabe einer [`ExecutionSpan.mask`](/docs/api/qiskit-ibm-runtime/execution-span-execution-span#mask) Methode an, welche Daten während dieses Zeitraums ausgeführt wurden. Diese Methode gibt bei Angabe eines beliebigen Indexes [eines „Primitive Unified Block“ ( PUB )](/docs/guides/primitive-input-output#pubs) eine boolesche Maske zurück, die für alle während ihres `True` Zeitfensters ausgeführten Shots gilt. PUBs werden in der Reihenfolge indiziert, in der sie dem Aufruf des Sampler-Laufs übergeben wurden. Wenn beispielsweise ein „ PUB “ die Form hat `(2, 3)` und mit vier Schüssen ausgeführt wurde, dann hat die Maske `(2, 3, 4)`die Form. Ausführliche Informationen finden Sie auf der Seite [zur](/docs/api/qiskit-ibm-runtime/execution-span) execution\\_span-API.\n",
        "\n",
        "Um Informationen zur Ausführungsdauer anzuzeigen, überprüfen Sie die Metadaten des von `SamplerV2`zurückgegebenen Ergebnisses, das in Form eines `ExecutionSpans` Objekts vorliegt. Dieses Objekt ist ein listenähnlicher Container, der Instanzen von Unterklassen von enthält `ExecutionSpan`, wie `SliceSpan`beispielsweise.\n",
        "\n",
        "Beispiel:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "480e553c-2e53-40ca-bafd-e350f173cbcc",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "ExecutionSpans([DoubleSliceSpan(<start='2026-09-01 08:11:01', stop='2026-09-01 08:11:02', size=24>)])\n"
          ]
        }
      ],
      "source": [
        "# Define two circuits, each with one parameter with two parameters.\n",
        "circuit = QuantumCircuit(2)\n",
        "circuit.h(0)\n",
        "circuit.cx(0, 1)\n",
        "circuit.ry(Parameter(\"a\"), 0)\n",
        "circuit.cx(0, 1)\n",
        "circuit.h(0)\n",
        "circuit.measure_all()\n",
        "\n",
        "\n",
        "pm = generate_preset_pass_manager(optimization_level=1, backend=backend)\n",
        "transpiled_circuit = pm.run(circuit)\n",
        "\n",
        "params = np.random.uniform(size=(2, 3)).T\n",
        "\n",
        "sampler_pub = (transpiled_circuit, params)\n",
        "\n",
        "# Instantiate the new Estimator object, then run the transpiled circuit\n",
        "# using the set of parameters and observables.\n",
        "\n",
        "job = sampler.run([sampler_pub], shots=4)\n",
        "\n",
        "result = job.result()\n",
        "spans = job.result().metadata[\"execution\"][\"execution_spans\"]\n",
        "print(spans)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "092fedcc-c4ac-4841-9846-f77b9ec90d2e",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.primitives import BitArray\n",
        "\n",
        "# Get the mask of the 1st PUB for the 0th span.\n",
        "mask = spans[0].mask(0)\n",
        "\n",
        "# Decide whether the 0th shot of parameter set (1, 2) occurred in this span.\n",
        "in_this_span = mask[2, 1, 0]\n",
        "\n",
        "# Create a new bit array containing only the PUB-1 data collected during this span.\n",
        "bits = result[0].data.meas\n",
        "filtered_data = BitArray(bits.array[mask], bits.num_bits)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2ba13f59-c804-4e3b-85c9-90f26cb68e92",
      "metadata": {},
      "source": [
        "Ausführungsspannen können gefiltert werden, um Informationen zu bestimmten PUBs einzubeziehen, die anhand ihrer Indizes ausgewählt werden:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "53dec6a3-57b9-41b0-8ebd-28c6257dd10e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "ExecutionSpans([DoubleSliceSpan(<start='2026-09-01 08:11:01', stop='2026-09-01 08:11:02', size=24>)])"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# take the subset of spans that reference data in PUBs 0 or 2\n",
        "spans.filter_by_pub([0, 2])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4f635472-60a9-4729-9880-5581fb3806f2",
      "metadata": {},
      "source": [
        "Globale Informationen zur Erfassung von Ausführungsspannen anzeigen:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "ba4aa14d-4182-47bf-93a6-df607fd82594",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Number of execution spans: 1\n",
            "  Start of the first span: 2026-09-01 08:11:01.798871\n",
            "     End of the last span: 2026-09-01 08:11:02.894134\n",
            "       Total duration (s): 1.095263\n"
          ]
        }
      ],
      "source": [
        "print(\"Number of execution spans:\", len(spans))\n",
        "print(\"  Start of the first span:\", spans.start)\n",
        "print(\"     End of the last span:\", spans.stop)\n",
        "print(\"       Total duration (s):\", spans.duration)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1392fbc0-0792-402c-9568-160313ab76c4",
      "metadata": {},
      "source": [
        "Einen bestimmten Abschnitt extrahieren und überprüfen:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "077a74ad-2780-4c61-8310-a4821efbfa68",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            " Start of first span: 2026-09-01 08:11:01.798871\n",
            "   End of first span: 2026-09-01 08:11:02.894134\n",
            "#shots in first span: 24\n"
          ]
        }
      ],
      "source": [
        "spans.sort()\n",
        "print(\" Start of first span:\", spans[0].start)\n",
        "print(\"   End of first span:\", spans[0].stop)\n",
        "print(\"#shots in first span:\", spans[0].size)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "924e26ed-ece0-42ef-a985-ae1aaea86622",
      "metadata": {},
      "source": [
        "<Admonition type=\"note\">\n",
        "  Es ist möglich, dass sich Zeitfenster, die durch unterschiedliche Ausführungszeiträume festgelegt sind, überschneiden. Dies liegt nicht daran, dass eine QPU mehrere Befehle gleichzeitig ausgeführt hat, sondern ist vielmehr ein Nebeneffekt bestimmter klassischer Verarbeitungsprozesse, die möglicherweise parallel zur Quantenausführung ablaufen. Es wird garantiert, dass die betreffenden Daten definitiv innerhalb des angegebenen Ausführungszeitraums aufgetreten sind, jedoch nicht unbedingt, dass die Grenzen des Zeitfensters so eng wie möglich sind.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "celltoolbar": "Raw Cell Format",
    "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
}