{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "0ff6f833-f5fb-4e9e-a572-445f2ff9ad64",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Primitive Eingaben und Ausgaben\"\n",
        "description: \"Die Eingabe- und Ausgabeformate (einschließlich „Primitive Unified Blocs“ oder PUBs) der „ Qiskit SDK “-Primitive verstehen\"\n",
        "---\n",
        "\n",
        "<span id=\"primitive-inputs-and-outputs\" />\n",
        "\n",
        "# Primitive Eingaben und Ausgaben\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "36a00905-1855-4fce-9686-20eb01ba72b6",
      "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",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "203951dd-4da7-4e0d-93f7-3ed7e2cd624b",
      "metadata": {},
      "source": [
        "Diese Seite bietet einen Überblick über die Ein- und Ausgänge der Primitive „ Qiskit SDK “. Mit diesen Primitiven können Sie eine als **„Primitive Unified Bloc“ ( PUB )** bezeichnete Datenstruktur nutzen, um vektorisierte Workloads effizient zu definieren. Diese PUBs sind die grundlegende Arbeitseinheit für die Ausführung von Workloads. Sie dienen als Eingaben für die Methode `run()` der Primitive „Sampler“ und „Estimator“, die die definierte Arbeitslast als Job ausführen. Nach Abschluss des Auftrags werden die Ergebnisse in einem Format zurückgegeben, das von den verwendeten PUBs und den gegebenenfalls angegebenen Optionen abhängt.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c7bc7444-eada-42ec-8f9a-6ec848c40014",
      "metadata": {},
      "source": [
        "<span id=\"pubs\" />\n",
        "\n",
        "<span id=\"overview-of-pubs\" />\n",
        "\n",
        "## Übersicht über PUBs\n",
        "\n",
        "Beim Aufruf einer Methode `run()` einer Primitive ist das wichtigste erforderliche Argument ein Array `list` aus einem oder mehreren Tupeln – eines für jeden Schaltkreis, der von der Primitive ausgeführt wird. Jedes dieser Tupel wird als „ PUB “ betrachtet, und die erforderlichen Elemente jedes Tupels in der Liste hängen von der verwendeten Primitivtyp ab. Die diesen Tupeln zugeführten Daten können zudem in verschiedenen Formen angeordnet werden, um durch Broadcasting Flexibilität bei der Arbeitslast zu gewährleisten – die Regeln hierfür werden in einem [späteren Abschnitt](#broadcasting-rules) beschrieben.\n",
        "\n",
        "<span id=\"estimator-pub\" />\n",
        "\n",
        "### Schätzer PUB\n",
        "\n",
        "Für das Primitiv Estimator sollte das Format von PUB höchstens vier Werte enthalten:\n",
        "\n",
        "* Eine einzelne `QuantumCircuit`, die ein oder mehrere Objekte enthalten kann [`Parameter`](/docs/api/qiskit/qiskit.circuit.Parameter) objekte enthalten kann\n",
        "* Eine Liste von einer oder mehreren Beobachtungswerten, die die zu schätzenden Erwartungswerte angeben und in einem Array angeordnet sind (z. B. eine einzelne Beobachtungsgröße, die als 0-d-Array dargestellt wird, eine Liste von Beobachtungsgrößen als 1-d-Array und so weiter). Die Daten können in einem der Formate `ObservablesArrayLike` wie `Pauli`, `SparsePauliOp`, `PauliList` oder `str` vorliegen.\n",
        "  <Admonition type=\"note\">\n",
        "    Wenn Sie zwei Pendelbeobachtungen in verschiedenen PUBs, aber mit demselben Schaltkreis haben, werden diese nicht anhand derselben Messung geschätzt. Jede PUB stellt eine andere Messgrundlage dar, weshalb für jede PUB separate Messungen erforderlich sind. Um sicherzustellen, dass die Pendler-Beobachtungsgrößen anhand derselben Messung geschätzt werden, müssen sie innerhalb derselben „ PUB ” gruppiert werden.\n",
        "  </Admonition>\n",
        "* Eine Sammlung von Parameterwerten, an die der Stromkreis gebunden werden soll. Dies kann als einzelnes Array-ähnliches Objekt angegeben werden, wobei der letzte Index über die `Parameter` Objekte des Stromkreises ist, oder weggelassen (oder gleichwertig auf `None` gesetzt) werden, wenn der Stromkreis keine `Parameter` Objekte hat.\n",
        "* (Optional) eine Zielgenauigkeit für die zu schätzenden Erwartungswerte\n",
        "\n",
        "<span id=\"sampler-pub\" />\n",
        "\n",
        "### Sampler- PUB\n",
        "\n",
        "Für das Sampler-Primitiv enthält das Format des Tupels PUB höchstens drei Werte:\n",
        "\n",
        "* Ein Einzelobjekt `QuantumCircuit`, das ein oder mehrere [`Parameter`](/docs/api/qiskit/qiskit.circuit.Parameter) Objekte enthalten kann\n",
        "  *Hinweis: Diese Schaltungen müssen außerdem Messanweisungen für jedes der zu messenden Qubits enthalten.*\n",
        "* Eine Sammlung von Parameterwerten zur Bindung der Schaltung an $\\theta_k$ (nur erforderlich, wenn `Parameter` Objekte verwendet werden, die zur Laufzeit gebunden werden müssen)\n",
        "* (Optional) eine Anzahl von Schüssen zur Messung des Stromkreises mit\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2bdb4618-e59f-4627-81b6-6828b40258f7",
      "metadata": {},
      "source": [
        "***\n",
        "\n",
        "Der folgende Code zeigt ein Beispiel für vektorisierte Eingaben für die `Estimator` Primitive.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "e84f14f0-7190-4ab6-ba49-2746c515238c",
      "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",
        "from qiskit.primitives import StatevectorEstimator\n",
        "\n",
        "\n",
        "import numpy as np\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",
        "\n",
        "# Transpile the circuit without providing a backend\n",
        "pm = generate_preset_pass_manager(optimization_level=1)\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, 10),\n",
        "        np.linspace(-4 * np.pi, 4 * np.pi, 10),\n",
        "    ]\n",
        ").T\n",
        "\n",
        "# Define three observables. The inner length-1 lists cause this array of\n",
        "# observables to have shape (3, 1), rather than shape (3,) if they were\n",
        "# omitted.\n",
        "observables = [\n",
        "    [SparsePauliOp([\"XX\", \"IY\"], [0.5, 0.5])],\n",
        "    [SparsePauliOp(\"XX\")],\n",
        "    [SparsePauliOp(\"IY\")],\n",
        "]\n",
        "# Apply the same layout as the transpiled circuit.\n",
        "observables = [\n",
        "    [observable.apply_layout(layout) for observable in observable_set]\n",
        "    for observable_set in observables\n",
        "]\n",
        "\n",
        "# Estimate the expectation value for all 300 combinations of observables\n",
        "# and parameter values, where the pub result will have shape (3, 100).\n",
        "#\n",
        "# This shape is due to our array of parameter bindings having shape\n",
        "# (100, 2), combined with our array of observables having shape (3, 1).\n",
        "estimator = StatevectorEstimator()\n",
        "estimator_pub = (transpiled_circuit, observables, params)\n",
        "\n",
        "# Run the transpiled circuit\n",
        "# using the set of parameters and observables.\n",
        "\n",
        "job = estimator.run([estimator_pub])\n",
        "result = job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3acc54a9-ab50-4155-9c2d-c6a75dba816d",
      "metadata": {},
      "source": [
        "<span id=\"broadcasting\" />\n",
        "\n",
        "<span id=\"broadcasting-rules\" />\n",
        "\n",
        "### Rundfunkvorschriften\n",
        "\n",
        "Die PUBs aggregieren Elemente aus mehreren Arrays (Observablen und Parameterwerte), indem sie denselben Übertragungsregeln folgen wie NumPy. In diesem Abschnitt werden diese Regeln kurz zusammengefasst.  Eine ausführliche Erklärung finden Sie in der [Dokumentation NumPy broadcasting rules](https://numpy.org/doc/stable/user/basics.broadcasting.html).\n",
        "\n",
        "Regeln:\n",
        "\n",
        "* Die Eingabefelder müssen nicht die gleiche Anzahl von Dimensionen haben.\n",
        "  * Das resultierende Array hat die gleiche Anzahl von Dimensionen wie das Eingabe-Array mit der größten Dimension.\n",
        "  * Die Größe der einzelnen Dimensionen ist die größte Größe der entsprechenden Dimension.\n",
        "  * Bei fehlenden Abmessungen wird angenommen, dass sie die Größe eins haben.\n",
        "* Formvergleiche beginnen mit der ganz rechten Dimension und setzen sich nach links fort.\n",
        "* Zwei Dimensionen sind kompatibel, wenn ihre Größen gleich sind oder wenn eine der beiden Dimensionen 1 ist.\n",
        "\n",
        "Beispiele für Array-Paare, die senden:\n",
        "\n",
        "```text\n",
        "A1     (1d array):      1\n",
        "A2     (2d array):  3 x 5\n",
        "Result (2d array):  3 x 5\n",
        "\n",
        "\n",
        "A1     (3d array):  11 x 2 x 7\n",
        "A2     (3d array):  11 x 1 x 7\n",
        "Result (3d array):  11 x 2 x 7\n",
        "```\n",
        "\n",
        "Beispiele für Array-Paare, die nicht übertragen werden:\n",
        "\n",
        "```text\n",
        "A1     (1d array):  5\n",
        "A2     (1d array):  3\n",
        "\n",
        "A1     (2d array):      2 x 1\n",
        "# The following would work if the middle dimension were 2,\n",
        "# instead of 5.\n",
        "A2     (3d array):  6 x 5 x 4\n",
        "```\n",
        "\n",
        "`Estimator` gibt für jedes Element der übertragenen Form eine Schätzung des Erwartungswerts zurück.\n",
        "\n",
        "Hier sind einige Beispiele für gängige Muster, die in Form von Array-Übertragungen ausgedrückt werden.  Die dazugehörige visuelle Darstellung ist in der folgenden Abbildung zu sehen:\n",
        "\n",
        "Parameterwertsätze werden durch n x m Arrays dargestellt, und beobachtbare Arrays werden durch eine oder mehrere einspaltige Arrays dargestellt. Für jedes Beispiel im vorangegangenen Code werden die Parameterwertsätze mit dem jeweiligen Beobachtungsfeld kombiniert, um die resultierenden Erwartungswertschätzungen zu erstellen.\n",
        "\n",
        "* *Beispiel 1* : (broadcast single observable) hat einen Parameterwertsatz, der ein Array 5x1 und ein Array 1x1 observables ist.  Das eine Element im Beobachtungswerte-Array wird mit jedem Element im Parameterwertsatz kombiniert, um ein einziges 5x1 -Array zu erstellen, in dem jedes Element eine Kombination aus dem ursprünglichen Element im Parameterwertsatz und dem Element im Beobachtungswerte-Array ist.\n",
        "\n",
        "* *Beispiel 2* : (zip) hat einen 5x1 Parameterwertsatz und ein 5x1 Observables-Array.  Die Ausgabe ist ein Array 5x1, in dem jedes Element eine Kombination aus dem n-ten Element im Parameterwertsatz und dem n-ten Element im Array Observables ist.\n",
        "\n",
        "* *Beispiel 3* : (outer/product) hat einen 1x6 Parameterwertsatz und ein 4x1 Observables-Array.  Ihre Kombination führt zu einem Array 4x6, das durch Kombination jedes Elements im Parameterwertsatz mit *jedem* Element im Array Observables erstellt wird, so dass jeder Parameterwert zu einer ganzen Spalte in der Ausgabe wird.\n",
        "\n",
        "* *Beispiel 4* : (Standard- und Verallgemeinerung) hat ein Array mit 3x6 Parameterwerten und zwei Arrays mit 3x1 Beobachtungswerten.  Diese werden kombiniert, um zwei 3x6 Ausgabefelder in ähnlicher Weise wie im vorherigen Beispiel zu erstellen.\n",
        "\n",
        "![Dieses Bild veranschaulicht verschiedene visuelle Darstellungen des Array-Broadcastings.](https://quantum.cloud.ibm.com/docs/images/guides/primitive-input-output/broadcasting.avif \" Visuelle Darstellung des Broadcastings\")\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "37aa226f-d550-42fd-9ab0-60e27757722a",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Broadcast single observable\n",
        "parameter_values = np.random.uniform(size=(5,))  # shape (5,)\n",
        "observables = SparsePauliOp(\"ZZZ\")  # shape ()\n",
        "# >> pub result has shape (5,)\n",
        "\n",
        "# Zip\n",
        "parameter_values = np.random.uniform(size=(5,))  # shape (5,)\n",
        "observables = [\n",
        "    SparsePauliOp(pauli) for pauli in [\"III\", \"XXX\", \"YYY\", \"ZZZ\", \"XYZ\"]\n",
        "]  # shape (5,)\n",
        "# >> pub result has shape (5,)\n",
        "\n",
        "# Outer/Product\n",
        "parameter_values = np.random.uniform(size=(1, 6))  # shape (1, 6)\n",
        "observables = [\n",
        "    [SparsePauliOp(pauli)] for pauli in [\"III\", \"XXX\", \"YYY\", \"ZZZ\"]\n",
        "]  # shape (4, 1)\n",
        "# >> pub result has shape (4, 6)\n",
        "\n",
        "# Standard nd generalization\n",
        "parameter_values = np.random.uniform(size=(3, 6))  # shape (3, 6)\n",
        "observables = [\n",
        "    [\n",
        "        [SparsePauliOp([\"XII\"])],\n",
        "        [SparsePauliOp([\"IXI\"])],\n",
        "        [SparsePauliOp([\"IIX\"])],\n",
        "    ],\n",
        "    [\n",
        "        [SparsePauliOp([\"ZII\"])],\n",
        "        [SparsePauliOp([\"IZI\"])],\n",
        "        [SparsePauliOp([\"IIZ\"])],\n",
        "    ],\n",
        "]  # shape (2, 3, 1)\n",
        "# >> pub result has shape (2, 3, 6)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "408e47b0-24ca-45b5-b71b-080d8ccf30a6",
      "metadata": {},
      "source": [
        "<Admonition type=\"tip\" title=\"SparsePauliOp\">\n",
        "  Jedes `SparsePauliOp` zählt in diesem Zusammenhang als ein einziges Element, unabhängig von der Anzahl der in `SparsePauliOp` enthaltenen Paulis. Für die Zwecke dieser Übertragungsregeln haben also alle folgenden Elemente die gleiche Form:\n",
        "\n",
        "  ```text\n",
        "  a = SparsePauliOp(\"Z\") # shape ()\n",
        "  b = SparsePauliOp(\"IIIIZXYIZ\") # shape ()\n",
        "  c = SparsePauliOp.from_list([\"XX\", \"XY\", \"IZ\"]) # shape ()\n",
        "  ```\n",
        "\n",
        "  Die folgenden Listen von Operatoren sind zwar in Bezug auf die enthaltenen Informationen gleichwertig, haben aber unterschiedliche Formen:\n",
        "\n",
        "  ```text\n",
        "  list1 = SparsePauliOp.from_list([\"XX\", \"XY\", \"IZ\"])\n",
        "      # list1 has shape ()\n",
        "  list2 = [SparsePauliOp(\"XX\"), SparsePauliOp(\"XY\"), SparsePauliOp(\"IZ\")]\n",
        "      # list2 has shape (3, )\n",
        "  ```\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f548b270-afa7-480c-a457-c5260791d55b",
      "metadata": {},
      "source": [
        "<span id=\"overview-of-primitive-outputs\" />\n",
        "\n",
        "## Übersicht über primitive Ausgaben\n",
        "\n",
        "Sobald eine 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) Container-Objekt zurückgegeben. Das `PrimitiveResult` enthält eine iterierbare Liste von [`PubResult`](/docs/api/qiskit/qiskit.primitives.PubResult) Objekten, die die Ausführungsergebnisse für jeden PUB enthalten. Wenn beispielsweise ein Job mit 20 PUBs übermittelt wird, wird ein `PrimitiveResult` Objekt zurückgegeben, das eine Liste mit 20 `PubResults`Elementen enthält, wobei jedes Element einem „ PUB “ entspricht.\n",
        "\n",
        "Jedes dieser `PubResult` Objekte verfügt sowohl über ein `data` als auch über ein optionales `metadata` Attribut. Das `data` Attribut ist ein benutzerdefiniertes [`DataBin`](/docs/api/qiskit/qiskit.primitives.DataBin) Feld, das im Fall des Schätzers die Schätzungen der Erwartungswerte und im Fall des Abtasters Stichproben des Schaltungsausgangs enthält.\n",
        "\n",
        "Das `data` Attribut kann auch andere implementierungsspezifische Informationen enthalten, wie beispielsweise Standardabweichungen. Das `metadata` Attribut kann zusätzliche implementierungsspezifische Informationen über die Ausführung des zugehörigen „ PUB “ enthalten.\n",
        "\n",
        "Nachfolgend finden Sie eine Übersicht über die Datenstruktur von `PrimitiveResult` :\n",
        "\n",
        "<Tabs>\n",
        "  <TabItem value=\"estimator\" label=\"Estimator output\">\n",
        "    ```\n",
        "    └── PrimitiveResult\n",
        "        ├── PubResult[0]\n",
        "        │   ├── metadata\n",
        "        │   └── data  ## In the form of a DataBin object,\n",
        "        |       |     ## which includes data such as the following:\n",
        "        │       ├── evs\n",
        "        │       │   └── List of estimated expectation values in the shape\n",
        "        |       |         specified by the first pub\n",
        "        │       └── stds\n",
        "        │           └── List of calculated standard deviations in the\n",
        "        |                 same shape as above\n",
        "        ├── PubResult[1]\n",
        "        |   ├── metadata\n",
        "        |   └── data  ## In the form of a DataBin object,\n",
        "        |       |     ## which includes data such as the following:\n",
        "        |       ├── evs\n",
        "        |       │   └── List of estimated expectation values in the shape\n",
        "        |       |        specified by the second pub\n",
        "        |       └── stds\n",
        "        |           └── List of calculated standard deviations in the\n",
        "        |                same shape as above\n",
        "        ├── ...\n",
        "        ├── ...\n",
        "        └── ...\n",
        "    ```\n",
        "\n",
        "    <Admonition type=\"note\">\n",
        "      Das Obige ist ein Beispiel für Daten, die zurückgegeben werden könnten.  Welche Daten tatsächlich zurückgegeben werden, hängt von der jeweiligen Implementierung ab.\n",
        "    </Admonition>\n",
        "  </TabItem>\n",
        "\n",
        "  <TabItem value=\"sampler\" label=\"Sampler output\">\n",
        "    ```\n",
        "    └── PrimitiveResult\n",
        "        ├── PubResult[0]\n",
        "        │   ├── metadata\n",
        "        │   └── data  ## In the form of a DataBin object\n",
        "        │       ├── NAME_OF_CLASSICAL_REGISTER\n",
        "        │       │   └── BitArray of count data for first PUB (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",
        "        ├── PubResult[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",
        "  </TabItem>\n",
        "</Tabs>\n",
        "\n",
        "<span id=\"estimator-output\" />\n",
        "\n",
        "### Ausgabe des Schätzers\n",
        "\n",
        "Wie bereits erwähnt, hängen die von `PubResult` der Estimator-Primitive zurückgegebenen Daten von der jeweiligen Implementierung ab. Beispielsweise könnte es ein Array aus Erwartungswerten (`PubResult.data.evs`) und den dazugehörigen Standardabweichungen (`PubResult.data.stds`) enthalten.\n",
        "\n",
        "Der folgende Codeschnipsel beschreibt das Format `PrimitiveResult` (und das zugehörige `PubResult`) für den oben erstellten Auftrag.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "7b3ac687-8197-4c50-831c-a349fd8e90a2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The result of the submitted job had 1 PUB and has a value:\n",
            " PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(3, 10), dtype=float64>), stds=np.ndarray(<shape=(3, 10), dtype=float64>), shape=(3, 10)), metadata={'target_precision': 0.0, 'circuit_metadata': {}})], metadata={'version': 2})\n",
            "\n",
            "The associated PubResult of this job has the following data bins:\n",
            " DataBin(evs=np.ndarray(<shape=(3, 10), dtype=float64>), stds=np.ndarray(<shape=(3, 10), dtype=float64>), shape=(3, 10))\n",
            "\n",
            "And this DataBin has attributes: dict_keys(['evs', 'stds'])\n",
            "Recall that this shape is due to our array of parameter binding sets having shape (100, 2) -- where 2 is the number of parameters in the circuit -- combined with our array of observables having shape (3, 1).\n",
            "The expectation values measured from this PUB are: \n",
            "[[ 3.06161700e-16  4.52395120e-01  4.36594428e-01  2.16506351e-01\n",
            "   6.33718361e-01 -6.33718361e-01 -2.16506351e-01 -4.36594428e-01\n",
            "  -4.52395120e-01 -3.06161700e-16]\n",
            " [ 1.22464680e-16  6.42787610e-01  9.84807753e-01  8.66025404e-01\n",
            "   3.42020143e-01 -3.42020143e-01 -8.66025404e-01 -9.84807753e-01\n",
            "  -6.42787610e-01 -1.22464680e-16]\n",
            " [ 4.89858720e-16  2.62002630e-01 -1.11618897e-01 -4.33012702e-01\n",
            "   9.25416578e-01 -9.25416578e-01  4.33012702e-01  1.11618897e-01\n",
            "  -2.62002630e-01 -4.89858720e-16]]\n"
          ]
        }
      ],
      "source": [
        "print(\n",
        "    f\"The result of the submitted job had {len(result)} PUB and \"\n",
        "    f\"has a value:\\n {result}\\n\"\n",
        ")\n",
        "print(\n",
        "    f\"The associated PubResult of this job has the following data bins:\"\n",
        "    f\"\\n {result[0].data}\\n\"\n",
        ")\n",
        "print(f\"And this DataBin has attributes: {result[0].data.keys()}\")\n",
        "print(\n",
        "    \"Recall that this shape is due to our array of parameter binding sets \"\n",
        "    \"having shape (100, 2) -- where 2 is the number of parameters in the circuit -- \"\n",
        "    \"combined with our array of observables having shape (3, 1).\"\n",
        ")\n",
        "\n",
        "print(\n",
        "    f\"The expectation values measured from this PUB are: \\n{result[0].data.evs}\"\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "af092cd2-4388-4cb4-ba2a-a95b0d6b6c1e",
      "metadata": {},
      "source": [
        "<span id=\"sampler-output\" />\n",
        "\n",
        "### Sampler-Ausgabe\n",
        "\n",
        "Wenn ein Sampler-Job erfolgreich abgeschlossen wurde, enthält das zurückgegebene [`PrimitiveResult`](/docs/api/qiskit/qiskit.primitives.PrimitiveResult) Objekt eine Liste von [`SamplerPubResult`](/docs/api/qiskit/qiskit.primitives.SamplerPubResult)s, eine pro PUB. Die Datenbehälter dieser `SamplerPubResult` Objekte sind diktatähnliche Objekte, die jeweils `BitArray` einen `ClassicalRegister` im Schaltkreis enthalten.\n",
        "\n",
        "Die Klasse `BitArray` ist ein Container für geordnete Schussdaten. Genauer gesagt, speichert es die abgetasteten Bitstrings als Bytes in einem zweidimensionalen Array. Die linke Achse dieses Feldes verläuft über geordnete Schüsse, die rechte Achse über Bytes.\n",
        "\n",
        "Betrachten wir als erstes Beispiel die folgende Zehn-Qubit-Schaltung:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "f2902d44-e97e-450f-9290-e9a8e1a5b287",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Databin: DataBin(meas=BitArray(<shape=(), num_shots=1024, num_bits=10>))\n",
            "\n",
            "BitArray: BitArray(<shape=(), num_shots=1024, num_bits=10>)\n",
            "\n",
            "The shape of register `meas` is (1024, 2).\n",
            "\n",
            "The bytes in register `alpha`, shot by shot:\n",
            "[[  3 255]\n",
            " [  0   0]\n",
            " [  3 255]\n",
            " ...\n",
            " [  0   0]\n",
            " [  3 255]\n",
            " [  0   0]]\n",
            "\n"
          ]
        }
      ],
      "source": [
        "from qiskit.primitives import StatevectorSampler\n",
        "\n",
        "# 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",
        "sampler = StatevectorSampler()\n",
        "\n",
        "# run the Sampler job and retrieve the results\n",
        "\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": "8d7e1188-d7a9-4e1a-a783-25e49a5fa1a2",
      "metadata": {},
      "source": [
        "Manchmal kann es praktisch sein, Daten aus dem Byte-Format in Bitstrings `BitArray` 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": 5,
      "id": "0eb3a383-30cd-4a32-8d8d-740264587079",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Counts: {'1111111111': 484, '0000000000': 540}\n"
          ]
        }
      ],
      "source": [
        "# optionally convert the native BitArray format to a dictionary format\n",
        "counts = data.meas.get_counts()\n",
        "print(f\"Counts: {counts}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f02341ca-4d0f-421b-9817-47f7b339d057",
      "metadata": {},
      "source": [
        "Wenn eine Schaltung mehr als ein klassisches Register enthält, werden die Ergebnisse in verschiedenen `BitArray` Objekten gespeichert. Das folgende Beispiel modifiziert den vorherigen Ausschnitt, indem es das klassische Register in zwei separate Register aufteilt:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "5b294da8-b6b2-4313-aa98-efa4a1903ba4",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "BitArray for register 'alpha': BitArray(<shape=(), num_shots=1024, num_bits=1>)\n",
            "BitArray for register 'beta': BitArray(<shape=(), num_shots=1024, 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",
        "\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": "e384e005-24fe-4d7a-922a-39ae0d9089ab",
      "metadata": {},
      "source": [
        "<span id=\"leveraging-bitarray-objects-for-performant-post-processing\" />\n",
        "\n",
        "#### Nutzung von `BitArray` Objekten für eine performante Nachbearbeitung\n",
        "\n",
        "Da Arrays im Vergleich zu Wörterbüchern in der Regel eine bessere Leistung bieten, ist es ratsam, die Nachbearbeitung direkt an den `BitArray` Objekten vorzunehmen und nicht an Wörterbüchern mit Zählungen. Die `BitArray` Klasse bietet eine Reihe von Methoden zur Durchführung einiger gängiger Nachbearbeitungsvorgänge:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "44c7ee14-2b22-488e-bc58-164099855210",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The shape of register `alpha` is (1024, 1).\n",
            "The bytes in register `alpha`, shot by shot:\n",
            "[[1]\n",
            " [1]\n",
            " [0]\n",
            " ...\n",
            " [1]\n",
            " [0]\n",
            " [1]]\n",
            "\n",
            "The shape of register `beta` is (1024, 2).\n",
            "The bytes in register `beta`, shot by shot:\n",
            "[[  1 255]\n",
            " [  1 255]\n",
            " [  0   0]\n",
            " ...\n",
            " [  1 255]\n",
            " [  0   0]\n",
            " [  1 255]]\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 (1024, 1).\n",
            "The bytes in `beta` after bit-wise slicing:\n",
            "[[7]\n",
            " [7]\n",
            " [0]\n",
            " ...\n",
            " [7]\n",
            " [0]\n",
            " [7]]\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",
            " [  1 255]\n",
            " [  0   0]\n",
            " [  0   0]\n",
            " [  1 255]]\n",
            "\n",
            "Exp. val. for observable `SparsePauliOp(['ZZZZZZZZZ'],\n",
            "              coeffs=[1.+0.j])` is: -0.02734375\n",
            "Exp. val. for observable `SparsePauliOp(['IIIIIIIIZ'],\n",
            "              coeffs=[1.+0.j])` is: -0.02734375\n",
            "\n",
            "The shape of the merged results is (1024, 2).\n",
            "The bytes of the merged results:\n",
            "[[  3 255]\n",
            " [  3 255]\n",
            " [  0   0]\n",
            " ...\n",
            " [  3 255]\n",
            " [  0   0]\n",
            " [  3 255]]\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\n",
        "# of the two 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": "6863da3a-77bd-4b7c-ac95-e5b4dd116180",
      "metadata": {},
      "source": [
        "<span id=\"result-metadata\" />\n",
        "\n",
        "## Ergebnis-Metadaten\n",
        "\n",
        "Zusätzlich zu den Ausführungsergebnissen enthalten die `PrimitiveResult` Objekte `PubResult` und ein optionales Metadatenattribut zu dem übermittelten Auftrag. Die zurückgegebenen Metadaten (sofern vorhanden) sind implementierungsspezifisch.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "5c08eeaa-8857-4fb6-aa8d-c4916f7354e8",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The metadata of the PrimitiveResult is:\n",
            "'version' : 2,\n",
            "\n",
            "The metadata of the PubResult result is:\n",
            "'shots' : 1024,\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": "75c67c45-102e-41dd-aebc-9e139b71a02f",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Nächste Schritte\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Empfehlungen\">\n",
        "  * Machen Sie sich mit der API für die „ [Qiskit SDK “-Primitive](/docs/api/qiskit/primitives) vertraut.\n",
        "  * Machen Sie sich mit der API der [Qiskit Aer-Primitive](https://qiskit.github.io/qiskit-aer/apidocs/aer_primitives.html) vertraut.\n",
        "  * Erfahren Sie mehr über die „ [IBM Quantum “-Primitive](/docs/guides/qiskit-runtime-primitives).\n",
        "  * Sehen Sie sich die [`qiskit-ibm-runtime` Estimator](/docs/api/qiskit-ibm-runtime/executor-estimator-estimator) -API an.\n",
        "  * Sehen Sie sich die [`qiskit-ibm-runtime` Sampler](/docs/api/qiskit-ibm-runtime/executor-sampler-sampler) -API an.\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
}