{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "0ff6f833-f5fb-4e9e-a572-445f2ff9ad64",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Entradas y salidas primitivas\"\n",
        "description: \"Comprender el formato de entrada y salida (incluidos los bloques primitivos unificados o PUB) del servidor de datos de la red de datos de la Tierra ( Qiskit primitives )\"\n",
        "---\n",
        "\n",
        "<span id=\"primitive-inputs-and-outputs\" />\n",
        "\n",
        "# Entradas y salidas primitivas\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=\"Versiones del paquete\">\n",
        "    El código de esta página se ha desarrollado teniendo en cuenta los siguientes requisitos.\n",
        "    Recomendamos utilizar estas versiones o versiones más recientes.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.5.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "203951dd-4da7-4e0d-93f7-3ed7e2cd624b",
      "metadata": {},
      "source": [
        "Esta página ofrece una visión general de las entradas y salidas del sistema de gestión de datos de la Universidad de California ( Qiskit primitives ). Con estas primitivas, puedes utilizar una estructura de datos conocida como **« PUB » (bloque unificado de** primitivas) para definir de forma eficiente cargas de trabajo vectorizadas. Estos PUB son la unidad básica de trabajo para la ejecución de cargas de trabajo. Se utilizan como entradas para el `run()` método de las primitivas «Sampler» y «Estimator», que ejecutan la carga de trabajo definida como un trabajo. A continuación, una vez finalizado el proceso, los resultados se devuelven en un formato que depende de los PUB utilizados y de las opciones especificadas.\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",
        "## Descripción general de los PUB\n",
        "\n",
        "Al invocar el método `run()` de una primitiva, el argumento principal que se requiere es una lista `list` de una o más tuplas: una por cada circuito que ejecute la primitiva. Cada una de estas tuplas se considera un « PUB », y los elementos necesarios de cada tupla de la lista dependen del tipo primitivo utilizado. Los datos proporcionados a estas tuplas también pueden organizarse de diversas formas para ofrecer flexibilidad en una carga de trabajo mediante la difusión, cuyas reglas se describen en una [sección posterior](#broadcasting-rules).\n",
        "\n",
        "<span id=\"estimator-pub\" />\n",
        "\n",
        "### Estimador PUB\n",
        "\n",
        "Para la primitiva Estimator, el formato de PUB debe contener como máximo cuatro valores:\n",
        "\n",
        "* Un único `QuantumCircuit`, que puede contener uno o varios [`Parameter`](/docs/api/qiskit/qiskit.circuit.Parameter) objetos\n",
        "* Una lista de uno o más observables, que especifican los valores de expectativa a estimar, ordenados en una matriz (por ejemplo, un único observable representado como una matriz 0-d, una lista de observables como una matriz 1-d, etc.). Los datos pueden estar en cualquiera de los formatos de `ObservablesArrayLike` como `Pauli`, `SparsePauliOp`, `PauliList`, o `str`.\n",
        "  <Admonition type=\"note\">\n",
        "    Si tienes dos observables de conmutación en diferentes PUB, pero con el mismo circuito, no se estimarán utilizando la misma medición. Cada PUB representa una base de medición diferente y, por lo tanto, se requieren mediciones separadas para cada PUB. Para garantizar que los observables de desplazamiento se estimen utilizando la misma medida, deben agruparse dentro del mismo PUB.\n",
        "  </Admonition>\n",
        "* Una colección de valores de parámetros para enlazar el circuito. Puede especificarse como un único objeto de tipo matriz en el que el último índice se encuentra sobre los objetos `Parameter` del circuito, u omitirse (o, de forma equivalente, establecerse en `None`) si el circuito no tiene objetos `Parameter` .\n",
        "* (Opcionalmente) un objetivo de precisión para los valores de expectativa a estimar\n",
        "\n",
        "<span id=\"sampler-pub\" />\n",
        "\n",
        "### Muestreador PUB\n",
        "\n",
        "Para la primitiva Sampler, el formato de la tupla PUB contiene como máximo tres valores:\n",
        "\n",
        "* Un único \\*circuito \\*`QuantumCircuit`, que puede contener uno o más [`Parameter`](/docs/api/qiskit/qiskit.circuit.Parameter) objetos\n",
        "  Nota: Estos circuitos también deben incluir instrucciones de medición para cada uno de los qubits que se vayan a muestrear.\n",
        "* Una colección de valores de parámetros para enlazar el circuito con $\\theta_k$ (sólo se necesita si se utiliza algún objeto `Parameter` que deba enlazarse en tiempo de ejecución)\n",
        "* (Opcionalmente) un número de disparos para medir el circuito con\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2bdb4618-e59f-4627-81b6-6828b40258f7",
      "metadata": {},
      "source": [
        "***\n",
        "\n",
        "El siguiente código muestra un ejemplo de conjunto de entradas vectorizadas para la `Estimator` primitiva.\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",
        "### Normas de radiodifusión\n",
        "\n",
        "Los PUB agregan elementos de múltiples matrices (observables y valores de parámetros) siguiendo las mismas reglas de difusión que NumPy. Esta sección resume brevemente esas normas.  Para una explicación detallada, consulte la [documentación sobre las reglas de difusión en NumPy](https://numpy.org/doc/stable/user/basics.broadcasting.html).\n",
        "\n",
        "Reglas:\n",
        "\n",
        "* No es necesario que las matrices de entrada tengan el mismo número de dimensiones.\n",
        "  * La matriz resultante tendrá el mismo número de dimensiones que la matriz de entrada con la dimensión mayor.\n",
        "  * El tamaño de cada dimensión es el mayor tamaño de la dimensión correspondiente.\n",
        "  * Se supone que las dimensiones que faltan tienen tamaño uno.\n",
        "* Las comparaciones de formas empiezan por la dimensión situada más a la derecha y continúan hacia la izquierda.\n",
        "* Dos dimensiones son compatibles si sus tamaños son iguales o si uno de ellos es 1.\n",
        "\n",
        "Ejemplos de pares de matrices que emiten:\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",
        "Ejemplos de pares de matrices que no emiten:\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` devuelve una estimación del valor esperado para cada elemento de la forma difundida.\n",
        "\n",
        "He aquí algunos ejemplos de patrones comunes expresados en términos de emisión de matrices.  En la figura siguiente se muestra su representación visual:\n",
        "\n",
        "Los conjuntos de valores de parámetros se representan mediante matrices n x m, y las matrices observables se representan mediante una o más matrices de una sola columna. Para cada ejemplo del código anterior, los conjuntos de valores de los parámetros se combinan con su matriz observable para crear las estimaciones de valores de expectativas resultantes.\n",
        "\n",
        "* *Ejemplo 1* : (broadcast single observable) tiene un conjunto de valores de parámetro que es un array 5x1 y un array 1x1 observables.  El elemento de la matriz de observables se combina con cada elemento del conjunto de valores de los parámetros para crear una única matriz 5x1 en la que cada elemento es una combinación del elemento original del conjunto de valores de los parámetros con el elemento de la matriz de observables.\n",
        "\n",
        "* *Ejemplo 2* : (zip) tiene un conjunto de valores de parámetros 5x1 y una matriz de observables 5x1.  La salida es una matriz 5x1 en la que cada elemento es una combinación del enésimo elemento del conjunto de valores de parámetros con el enésimo elemento de la matriz de observables.\n",
        "\n",
        "* *Ejemplo 3* : (outer/product) tiene un conjunto de valores de parámetros 1x6 y una matriz de observables 4x1.  Su combinación da como resultado una matriz 4x6 que se crea combinando cada elemento del conjunto de valores de parámetros con *cada* elemento de la matriz de observables, y así cada valor de parámetro se convierte en una columna entera en la salida.\n",
        "\n",
        "* *Ejemplo 4* : (Generalización estándar nd) tiene una matriz de conjuntos de valores de parámetros 3x6 y dos matrices de observables 3x1.  Estos se combinan para crear dos matrices de salida 3x6 de forma similar al ejemplo anterior.\n",
        "\n",
        "![Esta imagen muestra varias representaciones visuales de la difusión de matrices. ](https://quantum.cloud.ibm.com/docs/images/guides/primitive-input-output/broadcasting.svg \"Representación visual de la difusión\")\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",
        "  Cada `SparsePauliOp` cuenta como un único elemento en este contexto, independientemente del número de Paulis que contenga `SparsePauliOp`. Así pues, a efectos de estas normas de radiodifusión, todos los elementos siguientes tienen la misma forma:\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",
        "  Las siguientes listas de operadores, aunque equivalentes en cuanto a la información contenida, tienen formas diferentes:\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",
        "## Resumen de las salidas primitivas\n",
        "\n",
        "Una vez que se envían uno o varios PUB a una QPU para su ejecución y un trabajo se completa con éxito, los datos se devuelven como un objeto [`PrimitiveResult`](/docs/api/qiskit/qiskit.primitives.PrimitiveResult) contenedor. El objeto `PrimitiveResult` contiene una lista iterable de [`PubResult`](/docs/api/qiskit/qiskit.primitives.PubResult) objetos que recogen los resultados de la ejecución de cada `PUB`. Por ejemplo, un trabajo enviado con 20 PUB devolverá un `PrimitiveResult` objeto que contiene una lista de 20 elementos `PubResults`, uno correspondiente a cada PUB.\n",
        "\n",
        "Cada uno de estos `PubResult` objetos tiene un atributo `data` y un `metadata` atributo opcional. El `data` atributo es un objeto personalizado [`DataBin`](/docs/api/qiskit/qiskit.primitives.DataBin) que contiene las estimaciones del valor esperado en el caso del Estimador, o muestras de la salida del circuito en el caso del Muestreador.\n",
        "\n",
        "El `data` atributo también podría incluir otra información específica de la implementación, como las desviaciones estándar. El `metadata` atributo puede contener información adicional específica de la implementación sobre la ejecución del `PUB` asociado.\n",
        "\n",
        "A continuación se muestra un esquema visual de la estructura de datos de `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",
        "      Lo anterior es un ejemplo de los datos que podrían devolverse.  Los datos que se devuelven dependen de la implementación.\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",
        "### Salida del estimador\n",
        "\n",
        "Como se ha indicado anteriormente, los datos devueltos en la `PubResult` primitiva Estimator dependen de la implementación. Por ejemplo, podría contener una matriz de valores esperados (`PubResult.data.evs`) y las desviaciones estándar asociadas (`PubResult.data.stds`).\n",
        "\n",
        "El siguiente fragmento de código describe el formato `PrimitiveResult` (y el asociado `PubResult`) para el trabajo creado anteriormente.\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",
        "### Salida del muestreador\n",
        "\n",
        "Cuando un trabajo de Sampler se completa con éxito, el objeto [`PrimitiveResult`](/docs/api/qiskit/qiskit.primitives.PrimitiveResult) devuelto contiene una lista de [`SamplerPubResult`](/docs/api/qiskit/qiskit.primitives.SamplerPubResult)s, uno por cada PUB Los contenedores de datos de estos `SamplerPubResult` objetos son objetos similares a diccionarios que contienen uno `BitArray` por `ClassicalRegister` cada elemento del circuito.\n",
        "\n",
        "La clase `BitArray` es un contenedor de datos de tomas ordenadas. Más detalladamente, almacena las cadenas de bits muestreadas como bytes dentro de una matriz bidimensional. El eje de la izquierda de esta matriz recorre las tomas ordenadas, mientras que el eje de la derecha recorre los bytes.\n",
        "\n",
        "Como primer ejemplo, veamos el siguiente circuito de diez qubits:\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": [
        "A veces puede resultar útil convertir los datos del formato de bytes en cadenas `BitArray` de bits. El `get_count` método devuelve un diccionario que asocia cadenas de bits con el número de veces que han aparecido.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "0eb3a383-30cd-4a32-8d8d-740264587079",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Counts: {'1111111111': 507, '0000000000': 517}\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": [
        "Cuando un circuito contiene más de un registro clásico, los resultados se almacenan en diferentes `BitArray` objetos. El siguiente ejemplo modifica el fragmento anterior dividiendo el registro clásico en dos registros distintos:\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",
        "#### Aprovechamiento de `BitArray` objetos para un posprocesamiento eficaz\n",
        "\n",
        "Dado que las matrices suelen ofrecer un mejor rendimiento en comparación con los diccionarios, es recomendable realizar cualquier posprocesamiento directamente sobre los `BitArray` objetos en lugar de sobre los diccionarios de recuentos. La `BitArray` clase ofrece una serie de métodos para realizar algunas operaciones comunes de posprocesamiento:\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",
            "[[0]\n",
            " [1]\n",
            " [1]\n",
            " ...\n",
            " [0]\n",
            " [0]\n",
            " [0]]\n",
            "\n",
            "The shape of register `beta` is (1024, 2).\n",
            "The bytes in register `beta`, shot by shot:\n",
            "[[  0   0]\n",
            " [  1 255]\n",
            " [  1 255]\n",
            " ...\n",
            " [  0   0]\n",
            " [  0   0]\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 (1024, 1).\n",
            "The bytes in `beta` after bit-wise slicing:\n",
            "[[0]\n",
            " [7]\n",
            " [7]\n",
            " ...\n",
            " [0]\n",
            " [0]\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",
            "[[  0   0]\n",
            " [  1 255]\n",
            " [  1 255]\n",
            " [  1 255]\n",
            " [  0   0]]\n",
            "\n",
            "Exp. val. for observable `SparsePauliOp(['ZZZZZZZZZ'],\n",
            "              coeffs=[1.+0.j])` is: -0.03515625\n",
            "Exp. val. for observable `SparsePauliOp(['IIIIIIIIZ'],\n",
            "              coeffs=[1.+0.j])` is: -0.03515625\n",
            "\n",
            "The shape of the merged results is (1024, 2).\n",
            "The bytes of the merged results:\n",
            "[[  0   0]\n",
            " [  3 255]\n",
            " [  3 255]\n",
            " ...\n",
            " [  0   0]\n",
            " [  0   0]\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\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",
        "## Metadatos del resultado\n",
        "\n",
        "Además de los resultados de la ejecución, los `PrimitiveResult` objetos `PubResult` y contienen un atributo de metadatos opcional sobre el trabajo que se envió. Los metadatos devueltos (si los hay) dependen de la implementación.\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",
        "## Próximos pasos\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recomendaciones\">\n",
        "  * Consulte la API de « [Qiskit primitives](/docs/api/qiskit/primitives) ».\n",
        "  * Consulte la API [de primitivas de Qiskit Aer](https://qiskit.github.io/qiskit-aer/apidocs/aer_primitives.html).\n",
        "  * Más información sobre las [primitivas de « Qiskit Runtime](/docs/guides/qiskit-runtime-primitives) ».\n",
        "  * Consulte la API [de Estimator](/docs/api/qiskit-ibm-runtime/estimator-v2) de Qiskit Runtime.\n",
        "  * Consulte la API [de Sampler](/docs/api/qiskit-ibm-runtime/sampler-v2) de Qiskit Runtime.\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
}