{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "ce3d197d-7b14-4c60-8d39-a202146d0663",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Entradas y salidas del ejecutor\"\n",
        "description: \"Comprender las entradas y salidas de la primitiva «Executor».\"\n",
        "---\n",
        "\n",
        "<span id=\"executor-inputs-and-outputs\" />\n",
        "\n",
        "# Entradas y salidas del ejecutor\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "44219323-9419-471a-86c4-488ef0162420",
      "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 posteriores.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.4.0\n",
        "    qiskit-ibm-runtime~=0.46.1\n",
        "    samplomatic~=0.18.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "43c044dc-259d-4759-b6a7-a05bd9d3667f",
      "metadata": {},
      "source": [
        "La primitiva «Executor» forma parte del [modelo de ejecución dirigida](/docs/guides/directed-execution-model), que ofrece mayor flexibilidad a la hora de personalizar un flujo de trabajo de mitigación de errores.\n",
        "\n",
        "Las entradas y salidas de la primitiva «Executor» son muy diferentes de las de las primitivas [«Sampler»](/docs/guides/sampler-input-output) y «[Estimator](/docs/guides/estimator-input-output) ». Por ejemplo, en lugar de tomar como entrada una lista de PUB, Executor toma un `QuantumProgram`, que contiene una lista de `QuantumProgramItem` objetos. Estas clases de contenedores te ofrecen más flexibilidad que un « PUB », que es una estructura de datos de tipo tupla simple.\n",
        "\n",
        "El resultado de «executor» es un `QuantumProgramResult`, que es un objeto iterable y contiene un elemento por cada entrada `QuantumProgramItem`.\n",
        "\n",
        "<span id=\"programs\" />\n",
        "\n",
        "<span id=\"inputs-quantum-programs\" />\n",
        "\n",
        "## Entradas: Programas de Quantum\n",
        "\n",
        "Como se ha indicado anteriormente, la entrada de una primitiva «Executor» es un [`QuantumProgram`](/docs/api/qiskit-ibm-runtime/quantum-program-quantum-program), que es una secuencia iterable de\n",
        "[`QuantumProgramItem`](/docs/api/qiskit-ibm-runtime/quantum-program-quantum-program-item) objetos.  Estos objetos pueden ser de dos tipos:\n",
        "\n",
        "* `CircuitItem`, que suele contener un circuito y los valores de sus parámetros (si los hay).\n",
        "* `SamplexItem`, que suele contener lo siguiente:\n",
        "  * Un circuito modelo\n",
        "  * Un objeto «samplex», que se utiliza para generar conjuntos aleatorios de parámetros en tiempo de ejecución (por ejemplo, para realizar twirling o introducir ruido)\n",
        "  * Argumentos para el samplex, que pueden incluir valores de parámetros del circuito original\n",
        "\n",
        "Cada uno de estos elementos representa una tarea diferente que debe realizar Executor.\n",
        "\n",
        "<span id=\"before-you-begin\" />\n",
        "\n",
        "### Antes de empezar\n",
        "\n",
        "Algunos de los ejemplos de código de esta página utilizan `samplex`, que forma parte del paquete Samplomatic.  Por lo tanto, antes de ejecutar esos bloques de código, debes instalar Samplomatic, tal y como se muestra en el siguiente bloque de código.  Para obtener más información, consulta la [documentación de Samplomatic](https://qiskit.github.io/samplomatic).\n",
        "\n",
        "```python\n",
        "pip install samplomatic\n",
        "\n",
        "# For visualization support, include the visualization dependencies.\n",
        "# pip install samplomatic[vis]\n",
        "```\n",
        "\n",
        "<span id=\"example-create-a-quantumprogram-with-two-different-tasks\" />\n",
        "\n",
        "### Ejemplo: Crea una lista `QuantumProgram` con dos tareas diferentes\n",
        "\n",
        "En primer lugar, inicializa tu programa cuántico y, a continuación, añádele elementos utilizando o `append_samplex_item``append_circuit_item` (si hay un samplex), tal y como se muestra en los siguientes ejemplos.\n",
        "\n",
        "La siguiente celda inicializa un `QuantumProgram` y especifica que debe ejecutar 1024 simulaciones para cada configuración de cada elemento del programa.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  A diferencia de Sampler, un `QuantumProgram` solo admite un valor de disparo. `QuantumProgram`Si quieres un valor de exposición diferente, necesitarás una toma aparte, lo que supondría un trabajo adicional.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "81fc7c9e-2cc9-416a-b3d5-74f45eab48fc",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit_ibm_runtime.quantum_program import QuantumProgram\n",
        "from qiskit_ibm_runtime import Executor, QiskitRuntimeService\n",
        "from qiskit.circuit import Parameter, QuantumCircuit\n",
        "import numpy as np\n",
        "from samplomatic import build\n",
        "from samplomatic.transpiler import generate_boxing_pass_manager\n",
        "\n",
        "# Initialize an empty program\n",
        "program = QuantumProgram(shots=1024)\n",
        "\n",
        "# Initialize and transpile a 3-qubit quantum circuit with 2 parameters.\n",
        "circuit = QuantumCircuit(3)\n",
        "circuit.h(0)\n",
        "circuit.cx(0, 1)\n",
        "circuit.cx(1, 2)\n",
        "circuit.rz(Parameter(\"theta\"), 0)\n",
        "circuit.rz(Parameter(\"phi\"), 1)\n",
        "\n",
        "# `measure_all` adds a 3-bit classical register named \"meas\"\n",
        "circuit.measure_all()\n",
        "\n",
        "# Choose the least busy backend\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(operational=True, simulator=False)\n",
        "\n",
        "# Generate a preset pass manager\n",
        "# This will be used to convert the abstract circuit to an\n",
        "# equivalent Instruction Set Architecture (ISA) circuit.\n",
        "preset_pass_manager = generate_preset_pass_manager(\n",
        "    backend=backend, optimization_level=0\n",
        ")\n",
        "\n",
        "# Transpile the circuit\n",
        "isa_circuit = preset_pass_manager.run(circuit)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a1cc6580-3f31-4322-b0ea-f6bcf032a872",
      "metadata": {},
      "source": [
        "<span id=\"append-a-circuititem\" />\n",
        "\n",
        "### Añadir un `CircuitItem`\n",
        "\n",
        "A continuación, añade el circuito de destino, que se ha transpuesto de acuerdo con la arquitectura del conjunto de instrucciones (ISA) del backend, al archivo `QuantumProgram`. Dado que este circuito tiene dos parámetros, también debemos indicar los valores de los parámetros (10 conjuntos en este ejemplo). La ejecución de esto `CircuitItem` es la primera tarea que llevará a cabo el programa.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "e6f6762f-1627-450a-b74b-96ad4a3b1c9c",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Append the transpiled circuit and an array\n",
        "# containing 10 sets of parameter values to the program\n",
        "program.append_circuit_item(\n",
        "    isa_circuit,\n",
        "    circuit_arguments=np.random.rand(\n",
        "        10, 2\n",
        "    ),  # 10 sets of parameter values and 2 parameters\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "96f9ac43-8ce4-4389-bff4-5bd68b799974",
      "metadata": {},
      "source": [
        "<span id=\"append-a-samplexitem\" />\n",
        "\n",
        "### Añadir un `SamplexItem`\n",
        "\n",
        "Las instrucciones del circuito se ejecutan sin ningún tipo de aleatoriedad. Por el contrario, los elementos de Samplex te permiten especificar cómo aleatorizar su contenido. La siguiente celda utiliza la `generate_boxing_pass_manager()` función para agrupar las puertas y las mediciones del circuito en recuadros y añadir una anotación giratoria a cada recuadro. A continuación, genera un circuito de plantilla y un par de samplex utilizando la `build()` función.\n",
        "\n",
        "La ejecución de esto `SamplexItem` es la segunda tarea que llevará a cabo el programa.\n",
        "\n",
        "Consulte la documentación [de la API](https://github.com/Qiskit/samplomatic/) de Samplomatic para obtener información detallada sobre `samplex` y sus argumentos. Consulte la [guía](https://qiskit.github.io/samplomatic/guides/transpiler.html) de Samplomatic Transpiler para obtener información sobre cómo utilizar la `generate_boxing_pass_manager()` función.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "4ac19f46-226b-4b13-b278-1e39e719484b",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "TensorInterface(<\n",
            "  - 'parameter_values' <float64[2]>: Input parameter values to use during sampling.\n",
            ">)\n"
          ]
        }
      ],
      "source": [
        "# Transpile the circuit, additionally grouping gates and measurements into annotated boxes\n",
        "preset_pass_manager = generate_preset_pass_manager(\n",
        "    backend=backend, optimization_level=0\n",
        ")\n",
        "\n",
        "# Use the boxing pass manager to group gates\n",
        "# and measurements into boxes and add\n",
        "# a`Twirl` annotation.\n",
        "preset_pass_manager.post_scheduling = generate_boxing_pass_manager(\n",
        "    # Add gate twirling\n",
        "    enable_gates=True,\n",
        "    # Add measurement twirling\n",
        "    enable_measures=True,\n",
        ")\n",
        "boxed_circuit = preset_pass_manager.run(circuit)\n",
        "\n",
        "# Build the template circuit and the samplex.  The template circuit has parametric gates\n",
        "# without fixed values and the samplex randomly generates the parameter\n",
        "# values on the server side at runtime to perform twirling.\n",
        "template_circuit, samplex = build(boxed_circuit)\n",
        "\n",
        "# Determine what arguments are required by the samplex.\n",
        "# Input the arguments in samplex_arguments.\n",
        "print(samplex.inputs())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "0e3b4d3d-12ea-47f2-a605-b64eed03cf95",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Append the template circuit and samplex as a samplex item\n",
        "program.append_samplex_item(\n",
        "    template_circuit,\n",
        "    samplex=samplex,\n",
        "    samplex_arguments={\n",
        "        # the arguments required by the samplex.sample method\n",
        "        \"parameter_values\": np.random.rand(10, 2),\n",
        "    },\n",
        "    shape=(28, 10),  # 28 randomizations and 10 sets of parameter values\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "eb850401-3d4f-4fac-8965-fb9ac4827ebd",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Initialize an Executor with the default options\n",
        "executor = Executor(mode=backend)\n",
        "\n",
        "# Submit the job\n",
        "job = executor.run(program)\n",
        "\n",
        "# Retrieve the result\n",
        "result = job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "541f5d2d-b974-4ae5-81e0-ef2b6e1dbe82",
      "metadata": {},
      "source": [
        "<span id=\"outputs\" />\n",
        "\n",
        "## Resultados\n",
        "\n",
        "El resultado de «executor» es un [`QuantumProgramResult`](/docs/api/qiskit-ibm-runtime/results-quantum-program-result), que es un iterable. Contiene una entrada por cada entrada `QuantumProgramItem` , en el mismo orden que los elementos de la entrada. Cada uno de estos elementos de salida es un diccionario cuyas claves son cadenas que se corresponden con los nombres de los registros clásicos de los circuitos de entrada (entre otros), por lo que ya no es necesario memorizar estos nombres como ocurría con la salida del Sampler. Los valores del diccionario son de tipo `np.ndarray`.\n",
        "\n",
        "El resultado del ejemplo anterior contiene los siguientes elementos:\n",
        "\n",
        "<span id=\"circuititem-result\" />\n",
        "\n",
        "### `CircuitItem` resultado\n",
        "\n",
        "`CircuitItem`El primer elemento contiene los resultados de la ejecución de la primera tarea (a) del programa. Contiene una sola clave, `meas`, que es el nombre del registro clásico en el circuito de entrada. El valor de esta clave se corresponde con un `np.ndarray` de forma `(parameter sets, shots, register bits)`, que en el ejemplo anterior es (10, 1024, 3).\n",
        "\n",
        "El siguiente código muestra cómo acceder a esta información:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "d652d69a-7a4e-4e5c-8469-97cb9ec92010",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Result shape: (10, 1024, 3)\n"
          ]
        }
      ],
      "source": [
        "# Access the results of the classical register of task #0, a CircuitItem\n",
        "result_0 = result[0][\"meas\"]\n",
        "print(f\"Result shape: {result_0.shape}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7185353a-e7a0-4bb2-b605-664184e684ed",
      "metadata": {},
      "source": [
        "<span id=\"samplexitem-result\" />\n",
        "\n",
        "### `SamplexItem` resultado\n",
        "\n",
        "El segundo elemento contiene los resultados de la ejecución de la segunda tarea (a `SamplexItem`) del programa. Este artículo contiene varias llaves. La `meas` clave, que es el nombre del registro clásico del circuito de entrada, se asigna a la matriz de resultados de dicho registro. Esta matriz tiene la forma `(randomizations, parameter sets, shots, classical bits)`, o (28, 10, 1024, 3) en este ejemplo. Además, la salida contiene una `measurement_flips.meas` clave, que corresponde a las correcciones de inversión de bits necesarias para contrarrestar la distorsión de la medición en el `meas` registro.  En nuestro ejemplo, esta matriz de salida será (28, 10, 1, 3), ya que solo se necesita una operación para realizar la inversión de bits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "884af6e2-614a-4b18-83dc-04505ddbc488",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Result shape: (28, 10, 1024, 3)\n",
            "Bit-flip corrections shape: (28, 10, 1, 3)\n"
          ]
        }
      ],
      "source": [
        "# Access the results of the classical register of task #1\n",
        "result_1 = result[1][\"meas\"]\n",
        "print(f\"Result shape: {result_1.shape}\")\n",
        "\n",
        "# Access the bit-flip corrections\n",
        "flips_1 = result[1][\"measurement_flips.meas\"]\n",
        "print(f\"Bit-flip corrections shape: {flips_1.shape}\")\n",
        "\n",
        "# Undo the bit flips via classical XOR\n",
        "unflipped_result_1 = result_1 ^ flips_1"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bb0c9225-9a52-4d94-b75d-6ae408f4e029",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Próximos pasos\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recomendaciones\">\n",
        "  * Explora [ejemplos](/docs/guides/executor-examples) en los que se utiliza Executor.\n",
        "  * Descubre el [modelo](/docs/guides/directed-execution-model) de ejecución dirigida.\n",
        "  * Comprender [la difusión de Executor](/docs/guides/executor-broadcasting).\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}