{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "b793601b-95bc-4d36-adfc-c9fc34ce45cd",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Etapas del transpilador\"\n",
        "description: \"Las etapas predeterminadas del proceso de transpilación del circuito cuántico en Qiskit.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore fontsize */}\n",
        "\n",
        "<span id=\"transpiler-stages\" />\n",
        "\n",
        "# Etapas del transpilador\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4a38c84a-eed2-4fa4-9823-3d544e572398",
      "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": "9f2ecc4b-e6a3-418c-8a65-a9f3ac98c3dc",
      "metadata": {},
      "source": [
        "Esta página describe las etapas del pipeline de transpilación preconstruido en el SDK de Qiskit. Hay seis etapas:\n",
        "\n",
        "1. `init`\n",
        "2. `layout`\n",
        "3. `routing`\n",
        "4. `translation`\n",
        "5. `optimization`\n",
        "6. `scheduling`\n",
        "\n",
        "La función [`generate_preset_pass_manager`](/docs/api/qiskit/qiskit.transpiler.generate_preset_pass_manager#qiskit.transpiler.generate_preset_pass_manager) crea un [gestor de pases por](/docs/api/qiskit/qiskit.transpiler.StagedPassManager) etapas preestablecido compuesto por estas etapas. Los pases específicos que componen cada etapa dependen de los argumentos pasados a `generate_preset_pass_manager`. `optimization_level` es un argumento posicional que debe especificarse; es un número entero que puede ser 0, 1, 2 ó 3. Los valores más altos indican una optimización más intensa pero más costosa (véase [Transpilación por defecto y opciones de configuración](defaults-and-configuration-options) ).\n",
        "\n",
        "La forma recomendada de transpilar un circuito es crear un administrador de pases por etapas preestablecido y luego ejecutar ese administrador de pases en el circuito, como se describe en [Transpilar con administradores de pases](transpile-with-pass-managers). Sin embargo, una alternativa más sencilla pero menos personalizable es utilizar la función [`transpile`](/docs/api/qiskit/compiler#qiskit.compiler.transpile) función Esta función acepta el circuito directamente como argumento. Al igual que con `generate_preset_pass_manager`, los pases de transpilador específicos utilizados dependen de los argumentos, como `optimization_level`, pasados a `transpile`. De hecho, internamente la función `transpile` llama a `generate_preset_pass_manager` para crear un gestor de pases por etapas preestablecido y lo ejecuta en el circuito.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "18140654-10ff-40c5-ab75-4d19b8a7f5dd",
      "metadata": {},
      "source": [
        "<span id=\"init-stage\" />\n",
        "\n",
        "## Etapa inicial\n",
        "\n",
        "Esta primera etapa hace muy poco por defecto y es principalmente útil si desea incluir sus propias optimizaciones iniciales.  Dado que la mayoría de los algoritmos de trazado y encaminamiento sólo están diseñados para trabajar con puertas de uno o dos qubits, esta etapa también se utiliza para traducir cualquier puerta que opere con más de dos qubits, en puertas que sólo operen con uno o dos qubits.\n",
        "\n",
        "Para más información sobre cómo implementar tus propias optimizaciones iniciales para esta etapa, consulta la sección sobre plugins y personalización de gestores de pases.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "506a831f-b317-4335-8124-20ed994292cd",
      "metadata": {},
      "source": [
        "<span id=\"layout-stage\" />\n",
        "\n",
        "## Etapa de diseño\n",
        "\n",
        "La siguiente etapa consiste en la configuración o la conectividad del backend al que se enviará el circuito.  En general, los circuitos cuánticos son entidades abstractas cuyos qubits son representaciones «virtuales» o «lógicas» de los qubits reales que se utilizan en los cálculos.  Para ejecutar una secuencia de puertas, es necesaria una correspondencia biunívoca entre los qubits «virtuales» y los qubits «físicos» de un dispositivo cuántico real.  Esta correspondencia se almacena como un `Layout` objeto y forma parte de las restricciones definidas en [la arquitectura del conjunto de instrucciones (ISA)](/docs/guides/transpile#instruction-set-architecture) de un backend.\n",
        "\n",
        "![Esta imagen muestra cómo se asignan los qubits desde la representación esquemática a un diagrama que representa cómo están conectados los qubits en la QPU. Asignación](https://quantum.cloud.ibm.com/docs/images/guides/transpiler-stages/layout-mapping.svg \" de qubits\")\n",
        "\n",
        "La elección del mapeado es extremadamente importante para minimizar el número de operaciones SWAP necesarias para mapear el circuito de entrada en la topología del dispositivo y garantizar que se utilizan los qubits mejor calibrados.  Dada la importancia de esta etapa, los gestores de pases prefijados prueban distintos métodos para encontrar la mejor disposición.  Normalmente, esto implica dos pasos: primero, intentar encontrar una disposición \"perfecta\" (una disposición que no requiera ninguna operación SWAP) y, después, una pasada heurística que intenta encontrar la mejor disposición a utilizar si no se puede encontrar una disposición perfecta.  Para este primer paso se suelen utilizar dos sitios web: `Passes` :\n",
        "\n",
        "* `TrivialLayout`:Asigna de forma ingenua cada qubit virtual al mismo qubit físico numerado en el dispositivo (es decir, \\[`0`,`1`,`1`,`3`] -> \\[`0`,`1`,`1`,`3`] ). Este es un comportamiento histórico que solo se utiliza en `optimzation_level=1` para intentar encontrar un diseño perfecto.  Si falla, se intenta a continuación `VF2Layout` .\n",
        "* `VF2Layout`: Se trata de un `AnalysisPass` que selecciona un trazado ideal tratando esta etapa como un problema de isomorfismo de subgrafos, resuelto por el algoritmo VF2++.  Si se encuentra más de un trazado, se ejecuta una heurística de puntuación para seleccionar el trazado con el error medio más bajo.\n",
        "\n",
        "A continuación, para la etapa heurística, se utilizan dos pasadas por defecto:\n",
        "\n",
        "* `DenseLayout`: Busca el subgrafo del dispositivo con mayor conectividad y que tenga el mismo número de qubits que el circuito (se utiliza para el nivel de optimización 1 si hay operaciones de flujo de control (como IfElseOp ) presentes en el circuito).\n",
        "* `SabreLayout`: Este paso selecciona un diseño partiendo de un diseño aleatorio inicial y ejecutando repetidamente el `SabreSwap` algoritmo.  Este paso solo se utiliza en los niveles de optimización 1, 2 y 3 si no se encuentra un diseño perfecto mediante el `VF2Layout` paso.  Para obtener más detalles sobre este algoritmo, consulte el artículo « [arXiv:1809.02573](https://arxiv.org/abs/1809.02573) » (El algoritmo de optimización de la red de control de la red de control de la red de control de la red de control de la red de control de la red de control de la red de control de la red de\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cf772b6c-2578-455d-8014-9a7de2f9db19",
      "metadata": {},
      "source": [
        "<span id=\"routing-stage\" />\n",
        "\n",
        "## Etapa de enrutamiento\n",
        "\n",
        "Para implementar una puerta de dos qubits entre qubits que no están conectados directamente en un dispositivo cuántico, se deben insertar una o más puertas SWAP en el circuito para mover los estados de los qubits hasta que sean adyacentes en el mapa de puertas del dispositivo.  Cada puerta SWAP representa una operación cara y ruidosa de realizar.  Por tanto, encontrar el número mínimo de puertas SWAP necesarias para mapear un circuito en un dispositivo dado es un paso importante en el proceso de transpilación.  En aras de la eficacia, esta etapa suele calcularse por defecto junto con la etapa de maquetación, pero son lógicamente distintas.  La etapa de *diseño* selecciona los qubits hardware que se van a utilizar, mientras que la etapa *de enrutamiento* inserta la cantidad adecuada de puertas SWAP para ejecutar los circuitos utilizando el diseño seleccionado.\n",
        "\n",
        "Sin embargo, encontrar el mapa SWAP óptimo es difícil.  De hecho, es un problema NP-difícil y, por tanto, prohibitivamente caro de calcular para todos los dispositivos cuánticos y circuitos de entrada, salvo los más pequeños.  Para evitarlo, Qiskit utiliza un algoritmo heurístico estocástico llamado `SabreSwap` para calcular una asignación SWAP buena, aunque no necesariamente óptima. El uso de un método estocástico significa que no se garantiza que los circuitos generados sean los mismos en repetidas ejecuciones.  De hecho, al ejecutar repetidamente el mismo circuito se produce una distribución de la profundidad del circuito y del número de compuertas a la salida.  Es por esta razón que muchos usuarios optan por ejecutar la función de enrutamiento (o la totalidad de `StagedPassManager`) muchas veces y seleccionar los circuitos de menor profundidad de la distribución de salidas.\n",
        "\n",
        "Por ejemplo, tomemos un circuito GHZ de 15 qubits ejecutado 100 veces, utilizando un \"mal\" (desconectado) `initial_layout`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "62479697-cef1-4a89-ac2a-20051dd294f4",
      "metadata": {
        "tags": []
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "Text(0, 0.5, 'Counts')"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/62479697-cef1-4a89-ac2a-20051dd294f4-1.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "from qiskit import QuantumCircuit\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit.providers.fake_provider import GenericBackendV2\n",
        "\n",
        "backend = GenericBackendV2(15)\n",
        "\n",
        "\n",
        "ghz = QuantumCircuit(15)\n",
        "ghz.h(0)\n",
        "ghz.cx(0, range(1, 15))\n",
        "\n",
        "depths = []\n",
        "for seed in range(100):\n",
        "    pass_manager = generate_preset_pass_manager(\n",
        "        optimization_level=1,\n",
        "        backend=backend,\n",
        "        layout_method=\"trivial\",  # Fixed layout mapped in circuit order\n",
        "        seed_transpiler=seed,  # For reproducible results\n",
        "    )\n",
        "    depths.append(pass_manager.run(ghz).depth())\n",
        "\n",
        "plt.figure(figsize=(8, 6))\n",
        "plt.hist(depths, align=\"left\", color=\"#AC557C\")\n",
        "plt.xlabel(\"Depth\", fontsize=14)\n",
        "plt.ylabel(\"Counts\", fontsize=14)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ff31f484-a816-4479-8827-d56641501319",
      "metadata": {},
      "source": [
        "Esta amplia distribución demuestra lo difícil que es para el mapeador SWAP calcular la mejor asignación.  Para entenderlo mejor, veamos tanto el circuito que se ejecuta como los qubits elegidos en el hardware.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "ab89c4ea-06c4-4320-b493-feb691b3570d",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/ab89c4ea-06c4-4320-b493-feb691b3570d-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz.draw(\"mpl\", idle_wires=False)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "f6a3a92a-8656-4518-ba2c-c3b0b038f507",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/f6a3a92a-8656-4518-ba2c-c3b0b038f507-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.visualization import plot_circuit_layout\n",
        "\n",
        "# Plot the hardware graph and indicate which hardware qubits were chosen to run the circuit\n",
        "transpiled_circ = pass_manager.run(ghz)\n",
        "plot_circuit_layout(transpiled_circ, backend)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0ec2818a-8087-42ba-990d-b3c1258dbf35",
      "metadata": {},
      "source": [
        "Como puedes ver, este circuito tiene que ejecutar una puerta de dos qubits entre los qubits 0 y 14, que están muy separados en el gráfico de conectividad.  Por lo tanto, para ejecutar este circuito es necesario insertar puertas SWAP para ejecutar todas las puertas de dos qubits utilizando el paso `SabreSwap` .\n",
        "\n",
        "Obsérvese también que el algoritmo `SabreSwap` es diferente del método `SabreLayout` más amplio de la etapa anterior.  Por defecto, `SabreLayout` ejecuta tanto el trazado como el enrutado, y devuelve el circuito transformado.  Esto se hace por algunas razones técnicas concretas que se especifican en la [página de referencia de la API](../api/qiskit/qiskit.transpiler.passes.SabreLayout) del pase.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "650f978b-d992-4d67-a356-5bf73902f212",
      "metadata": {},
      "source": [
        "<span id=\"translation-stage\" />\n",
        "\n",
        "## Etapa de traducción\n",
        "\n",
        "Al escribir un circuito cuántico, puedes utilizar cualquier puerta cuántica (operación unitaria) que desees, junto con un conjunto de operaciones que no sean puertas, como la medición de qubits o las instrucciones de reinicio.  Sin embargo, la mayoría de los dispositivos cuánticos solo admiten de forma nativa unas pocas operaciones de puertas cuánticas y operaciones que no son de puertas.  Estas puertas nativas forman parte de la definición de [la ISA](/docs/guides/transpile#instruction-set-architecture) de un destino, y esta etapa del preajuste `PassManagers` traduce (o *despliega* ) las puertas especificadas en un circuito a las puertas de base nativa de un backend determinado.  Este es un paso importante, ya que permite que el circuito sea ejecutado por el backend, pero suele provocar un aumento de la profundidad y del número de puertas lógicas.\n",
        "\n",
        "Cabe destacar dos casos especiales que ayudan a ilustrar lo que hace esta etapa.\n",
        "\n",
        "1. Si una puerta SWAP no es una puerta nativa del backend de destino, se necesitan tres puertas CNOT:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "d4d1f65a-3336-4d70-9189-65ba010f2366",
      "metadata": {
        "tags": []
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "native gates:['cx', 'delay', 'id', 'measure', 'reset', 'rz', 'sx', 'x']\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/d4d1f65a-3336-4d70-9189-65ba010f2366-1.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "print(\"native gates:\" + str(sorted(backend.operation_names)))\n",
        "qc = QuantumCircuit(2)\n",
        "qc.swap(0, 1)\n",
        "qc.decompose().draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "56347603-8766-4165-af18-1f6fe4c61d4f",
      "metadata": {},
      "source": [
        "Como producto de tres puertas CNOT, un SWAP es una operación cara de realizar en dispositivos cuánticos ruidosos.  Sin embargo, estas operaciones suelen ser necesarias para incrustar un circuito en las limitadas conectividades de puerta de muchos dispositivos.  Por tanto, minimizar el número de puertas SWAP en un circuito es un objetivo primordial en el proceso de transpilación.\n",
        "\n",
        "2. Una puerta Toffoli, o puerta controlada-controlada-no (`ccx`), es una puerta de tres qubits.  Dado que nuestro conjunto de puertas base sólo incluye puertas de uno y dos qubits, esta operación debe descomponerse.  Sin embargo, es bastante costoso:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "4552b367-75e9-4faa-a59d-8317e25ac145",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/4552b367-75e9-4faa-a59d-8317e25ac145-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(3)\n",
        "qc.ccx(0, 1, 2)\n",
        "qc.decompose().draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "70af8d85-84c2-43cf-96fa-37bcf68f89c9",
      "metadata": {},
      "source": [
        "Por cada puerta Toffoli de un circuito cuántico, el hardware puede ejecutar hasta seis puertas CNOT y un puñado de puertas de un solo qubit.  Este ejemplo demuestra que cualquier algoritmo que haga uso de múltiples puertas Toffoli acabará siendo un circuito con una gran profundidad y, por tanto, se verá sensiblemente afectado por el ruido.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8b396526-b14b-48a3-93ed-37e590b06caf",
      "metadata": {},
      "source": [
        "<span id=\"optimization-stage\" />\n",
        "\n",
        "## Etapa de optimización\n",
        "\n",
        "Esta etapa se centra en la descomposición de los circuitos cuánticos en el conjunto de puertas base del dispositivo de destino, y debe luchar contra el aumento de profundidad de las etapas de diseño y enrutamiento.  Afortunadamente, existen muchas rutinas para optimizar los circuitos combinando o eliminando puertas.  En algunos casos, estos métodos son tan eficaces que los circuitos de salida tienen menor profundidad que los de entrada, incluso después de la disposición y el encaminamiento a la topología de hardware.  En otros casos, no se puede hacer mucho, y el cálculo puede ser difícil de realizar en dispositivos ruidosos.  En esta fase empiezan a diferenciarse los distintos niveles de optimización.\n",
        "\n",
        "* Para `optimization_level=1`, esta etapa prepara [`Optimize1qGatesDecomposition`](../api/qiskit/qiskit.transpiler.passes.Optimize1qGatesDecomposition) y [`CXCancellation`](/docs/api/qiskit/1.4/qiskit.transpiler.passes.CXCancellation)que combinan cadenas de compuertas de un solo qubit y cancelan cualquier compuerta CNOT consecutiva.\n",
        "* Para `optimization_level=2`, esta etapa utiliza el [`CommutativeCancellation`](../api/qiskit/qiskit.transpiler.passes.CommutativeCancellation) en lugar de `CXCancellation`, que elimina las puertas redundantes explotando las relaciones de conmutación.\n",
        "* Para `optimization_level=3`, esta etapa prepara los siguientes pases:\n",
        "  * [`Collect2qBlocks`](../api/qiskit/qiskit.transpiler.passes.Collect2qBlocks)\n",
        "  * [`ConsolidateBlocks`](../api/qiskit/qiskit.transpiler.passes.ConsolidateBlocks)\n",
        "  * [`UnitarySynthesis`](../api/qiskit/qiskit.transpiler.passes.UnitarySynthesis)\n",
        "  * [`Optimize1qGateDecomposition`](../api/qiskit/qiskit.transpiler.passes.Optimize1qGatesDecomposition)\n",
        "  * [`CommutativeCancellation`](../api/qiskit/qiskit.transpiler.passes.CommutativeCancellation)\n",
        "\n",
        "Además, esta etapa también ejecuta algunas comprobaciones finales para asegurarse de que todas las instrucciones del circuito están compuestas por las puertas base disponibles en el backend de destino.\n",
        "\n",
        "El siguiente ejemplo, que utiliza un estado GHZ, muestra los efectos de diferentes niveles de optimización en la profundidad del circuito y el número de puertas.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  El resultado de la transpilación varía debido al mapeador estocástico SWAP. Por lo tanto, es probable que los números que aparecen a continuación cambien cada vez que ejecute el código.\n",
        "</Admonition>\n",
        "\n",
        "![15-qubit GHZ state](https://quantum.cloud.ibm.com/docs/images/guides/transpiler-stages/transpiler-11.avif \"15-qubit GHZ state before transpilation\")\n",
        "\n",
        "El siguiente código construye un estado GHZ de 15 qubits y compara la `optimization_levels` de transpilación en términos de profundidad de circuito resultante, recuento de puertas y recuento de puertas multi-qubit.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "2700405a-f559-45d3-99a9-5b4447621743",
      "metadata": {
        "tags": []
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/2700405a-f559-45d3-99a9-5b4447621743-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "ghz = QuantumCircuit(15)\n",
        "ghz.h(0)\n",
        "ghz.cx(0, range(1, 15))\n",
        "\n",
        "depths = []\n",
        "gate_counts = []\n",
        "multiqubit_gate_counts = []\n",
        "levels = [str(x) for x in range(4)]\n",
        "for level in range(4):\n",
        "    pass_manager = generate_preset_pass_manager(\n",
        "        optimization_level=level,\n",
        "        backend=backend,\n",
        "        seed_transpiler=1234,\n",
        "    )\n",
        "    circ = pass_manager.run(ghz)\n",
        "    depths.append(circ.depth())\n",
        "    gate_counts.append(sum(circ.count_ops().values()))\n",
        "    multiqubit_gate_counts.append(circ.count_ops()[\"cx\"])\n",
        "\n",
        "fig, (ax1, ax2) = plt.subplots(2, 1)\n",
        "ax1.bar(levels, depths, label=\"Depth\")\n",
        "ax1.set_xlabel(\"Optimization Level\")\n",
        "ax1.set_ylabel(\"Depth\")\n",
        "ax1.set_title(\"Output Circuit Depth\")\n",
        "ax2.bar(levels, gate_counts, label=\"Number of Circuit Operations\")\n",
        "ax2.bar(levels, multiqubit_gate_counts, label=\"Number of CX gates\")\n",
        "ax2.set_xlabel(\"Optimization Level\")\n",
        "ax2.set_ylabel(\"Number of gates\")\n",
        "ax2.legend()\n",
        "ax2.set_title(\"Number of output circuit gates\")\n",
        "fig.tight_layout()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c870a48f-2bc4-4150-83ff-857a06e42ffb",
      "metadata": {},
      "source": [
        "<span id=\"scheduling\" />\n",
        "\n",
        "## Planificación\n",
        "\n",
        "Esta última etapa sólo se ejecuta si se solicita explícitamente (de forma similar a la etapa Init) y no se ejecuta por defecto (aunque se puede especificar un método estableciendo el argumento `scheduling_method` al llamar a `generate_preset_pass_manager`).  La etapa de programación se suele utilizar una vez que el circuito se ha traducido a la base de destino, se ha asignado al dispositivo y se ha optimizado.  Estos pases se centran en contabilizar todos los tiempos muertos de un circuito.  A un alto nivel, el paso de programación se puede considerar como la inserción explícita de instrucciones de retardo para tener en cuenta el tiempo de inactividad entre las ejecuciones de las puertas y para inspeccionar cuánto tiempo se ejecutará el circuito en el backend.\n",
        "\n",
        "A continuación se muestra un ejemplo:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "ae2d9390-5c26-46f3-9418-a684ba8a406a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/ae2d9390-5c26-46f3-9418-a684ba8a406a-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz = QuantumCircuit(5)\n",
        "ghz.h(0)\n",
        "ghz.cx(0, range(1, 5))\n",
        "\n",
        "\n",
        "# Use fake backend\n",
        "backend = GenericBackendV2(5)\n",
        "\n",
        "# Run with optimization level 3 and 'asap' scheduling pass\n",
        "pass_manager = generate_preset_pass_manager(\n",
        "    optimization_level=3,\n",
        "    backend=backend,\n",
        "    scheduling_method=\"asap\",\n",
        "    seed_transpiler=1234,\n",
        ")\n",
        "\n",
        "\n",
        "circ = pass_manager.run(ghz)\n",
        "circ.draw(output=\"mpl\", idle_wires=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "442cb546-3463-4044-8406-1c68d371a2c9",
      "metadata": {},
      "source": [
        "![Circuito con instrucciones de retardo](https://quantum.cloud.ibm.com/docs/images/guides/transpiler-stages/transpiler-16.avif)\n",
        "\n",
        "El transpilador insertó instrucciones `Delay` para tener en cuenta el tiempo de inactividad de cada qubit. Para hacernos una mejor idea de la temporización del circuito también podemos mirarlo con la función `timeline.draw()` :\n",
        "\n",
        "![timeline.draw (): vista del mismo circuito](https://quantum.cloud.ibm.com/docs/images/guides/transpiler-stages/transpiler-17.svg)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0b214bba-1f0e-49fc-be7e-29ccb57fff8a",
      "metadata": {},
      "source": [
        "La programación de un circuito consta de dos partes: el análisis y la asignación de restricciones, seguidos de una pasada de relleno.  La primera parte requiere ejecutar un pase de análisis de programación (por defecto es [`ALAPSchedulingAnalysis`](../api/qiskit/qiskit.transpiler.passes.ALAPScheduleAnalysis)), que analiza el circuito y registra la hora de inicio de cada instrucción del circuito en una programación.  Una vez que el circuito tiene una programación inicial, se pueden ejecutar pasadas adicionales para tener en cuenta cualquier restricción de tiempo en el backend de destino.  Por último, un pase de relleno como [`PadDelay`](../api/qiskit/qiskit.transpiler.passes.PadDelay) o [`PadDynamicalDecoupling`](../api/qiskit/qiskit.transpiler.passes.PadDynamicalDecoupling) puede ejecutarse.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "62c19c54-6dcc-4025-b800-7a74be69808d",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Próximos pasos\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recomendaciones\">\n",
        "  * Para aprender a utilizar la función `generate_preset_passmanager` , empiece por el tema [Ajustes por defecto y opciones de configuración de la transpilación](defaults-and-configuration-options).\n",
        "  * Continúe aprendiendo sobre la transpilación con el tema [Transpilador con administradores de pases](transpile-with-pass-managers).\n",
        "  * Prueba la guía [de configuración del transpilador Compare](/docs/guides/circuit-transpilation-settings).\n",
        "  * Consulte la [documentación de la API de Transpile](https://docs.quantum-computing.ibm.com/api/qiskit/transpiler).\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"
    },
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "state": {},
        "version_major": 2,
        "version_minor": 0
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}