{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "b793601b-95bc-4d36-adfc-c9fc34ce45cd",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Étapes du transpilateur\"\n",
        "description: \"Les étapes par défaut du pipeline de transpilation de circuits quantiques dans Qiskit.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore fontsize */}\n",
        "\n",
        "<span id=\"transpiler-stages\" />\n",
        "\n",
        "# Étapes du transpilateur\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=\"Versions de package\">\n",
        "    Le code de cette page a été développé en tenant compte des exigences suivantes.\n",
        "    Nous recommandons d'utiliser ces versions ou des versions plus récentes.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.5.1\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9f2ecc4b-e6a3-418c-8a65-a9f3ac98c3dc",
      "metadata": {},
      "source": [
        "Cette page décrit les étapes du pipeline de transpilation préconstruit dans le SDK Qiskit. Il y a six étapes :\n",
        "\n",
        "1. `init`\n",
        "2. `layout`\n",
        "3. `routing`\n",
        "4. `translation`\n",
        "5. `optimization`\n",
        "6. `scheduling`\n",
        "\n",
        "La fonction [`generate_preset_pass_manager`](/docs/api/qiskit/qiskit.transpiler.generate_preset_pass_manager#qiskit.transpiler.generate_preset_pass_manager) crée un [gestionnaire de passage par étapes](/docs/api/qiskit/qiskit.transpiler.StagedPassManager) prédéfini composé de ces étapes. Les passes spécifiques qui composent chaque étape dépendent des arguments transmis à `generate_preset_pass_manager`. `optimization_level` est un argument de position qui doit être spécifié; c'est un nombre entier qui peut être 0, 1, 2 ou 3. Des valeurs plus élevées indiquent une optimisation plus importante mais plus coûteuse (voir les [options de configuration et les valeurs par défaut de la transpilation](defaults-and-configuration-options) ).\n",
        "\n",
        "La méthode recommandée pour transpiler un circuit consiste à créer un gestionnaire de passes prédéfini et à le faire fonctionner sur le circuit, comme décrit dans [Transpiler avec des gestionnaires de passes.](transpile-with-pass-managers) Cependant, une alternative plus simple mais moins personnalisable consiste à utiliser la fonction [`transpile`](/docs/api/qiskit/compiler#qiskit.compiler.transpile) fonction. Cette fonction accepte le circuit directement comme argument. Comme pour `generate_preset_pass_manager`, les passes de transposition spécifiques utilisées dépendent des arguments, tels que `optimization_level`, transmis à `transpile`. En fait, en interne, la fonction `transpile` appelle `generate_preset_pass_manager` pour créer un gestionnaire de passage prédéfini et l'exécuter sur le circuit.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "18140654-10ff-40c5-ab75-4d19b8a7f5dd",
      "metadata": {},
      "source": [
        "<span id=\"init-stage\" />\n",
        "\n",
        "## Phase initiale\n",
        "\n",
        "Cette première étape ne fait pas grand-chose par défaut et est surtout utile si vous souhaitez inclure vos propres optimisations initiales.  Comme la plupart des algorithmes de disposition et de routage ne sont conçus que pour fonctionner avec des portes à un ou deux qubits, cette étape est également utilisée pour convertir toutes les portes qui fonctionnent sur plus de deux qubits en portes qui ne fonctionnent que sur un ou deux qubits.\n",
        "\n",
        "Pour plus d'informations sur la mise en œuvre de vos propres optimisations initiales pour cette étape, voir la section sur les plugins et la personnalisation des gestionnaires de passe.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "506a831f-b317-4335-8124-20ed994292cd",
      "metadata": {},
      "source": [
        "<span id=\"layout-stage\" />\n",
        "\n",
        "## Phase de mise en page\n",
        "\n",
        "L'étape suivante concerne la configuration ou la connectivité du backend vers lequel le circuit sera acheminé.  En général, les circuits quantiques sont des entités abstraites dont les qubits sont des représentations « virtuelles » ou « logiques » des qubits réels utilisés dans les calculs.  Pour exécuter une séquence de portes, il est nécessaire d'établir une correspondance biunivoque entre les qubits « virtuels » et les qubits « physiques » d'un dispositif quantique réel.  Ce mappage est stocké sous la forme d'un `Layout` objet et fait partie des contraintes définies dans [l'architecture de jeu d'instructions (ISA)](/docs/guides/transpile#instruction-set-architecture) d'un backend.\n",
        "\n",
        "![Cette image montre la conversion des qubits de la représentation schématique à un diagramme illustrant la manière dont les qubits sont connectés sur le processeur quantique (QPU). Conversion](https://quantum.cloud.ibm.com/docs/images/guides/transpiler-stages/layout-mapping.svg \" des qubits\")\n",
        "\n",
        "Le choix du mappage est extrêmement important pour minimiser le nombre d'opérations SWAP nécessaires pour mapper le circuit d'entrée sur la topologie du dispositif et garantir l'utilisation des qubits les mieux calibrés.  En raison de l'importance de cette étape, les gestionnaires de la présélection essaient plusieurs méthodes différentes pour trouver la meilleure disposition.  En règle générale, cela implique deux étapes : d'abord, essayer de trouver une disposition \"parfaite\" (une disposition qui ne nécessite aucune opération SWAP), et ensuite, une passe heuristique qui tente de trouver la meilleure disposition à utiliser si une disposition parfaite ne peut être trouvée.  Deux sites `Passes` sont généralement utilisés pour cette première étape :\n",
        "\n",
        "* `TrivialLayout`:Mappe naïvement chaque qubit virtuel au même qubit physique numéroté sur l'appareil (c'est-à-dire, \\[`0`,`1`,`1`,`3`] -> \\[`0`,`1`,`1`,`3`] ). Il s'agit d'un comportement historique utilisé uniquement dans `optimzation_level=1` pour essayer de trouver une disposition parfaite.  En cas d'échec, l'essai suivant est celui de `VF2Layout` .\n",
        "* `VF2Layout`: Il s'agit d'un site `AnalysisPass` qui sélectionne une disposition idéale en traitant cette étape comme un problème d'isomorphisme de sous-graphes, résolu par l'algorithme VF2++.  Si plus d'une disposition est trouvée, une heuristique de notation est exécutée pour sélectionner la cartographie présentant l'erreur moyenne la plus faible.\n",
        "\n",
        "Ensuite, pour l'étape heuristique, deux passages sont utilisés par défaut :\n",
        "\n",
        "* `DenseLayout`: Trouve le sous-graphe du dispositif avec la plus grande connectivité et qui a le même nombre de qubits que le circuit (utilisé pour le niveau d'optimisation 1 s'il y a des opérations de flux de contrôle (telles que IfElseOp ) présentes dans le circuit).\n",
        "* `SabreLayout`: Ce passage sélectionne une disposition en partant d'une disposition aléatoire initiale et en exécutant de manière répétée `SabreSwap` l'algorithme.  Ce passage n'est utilisé que dans les niveaux d'optimisation 1, 2 et 3 si aucune disposition parfaite n'est trouvée via le `VF2Layout` passage.  Pour plus de détails sur cet algorithme, consultez l'article « [arXiv:1809.02573](https://arxiv.org/abs/1809.02573) » (Algorithmes de calcul de la valeur de la confiance).\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cf772b6c-2578-455d-8014-9a7de2f9db19",
      "metadata": {},
      "source": [
        "<span id=\"routing-stage\" />\n",
        "\n",
        "## Étape de routage\n",
        "\n",
        "Pour mettre en œuvre une porte à deux qubits entre des qubits qui ne sont pas directement connectés sur un dispositif quantique, une ou plusieurs portes SWAP doivent être insérées dans le circuit pour déplacer les états des qubits jusqu'à ce qu'ils soient adjacents sur la carte des portes du dispositif.  Chaque porte SWAP représente une opération coûteuse et bruyante.  Ainsi, la recherche du nombre minimum de portes SWAP nécessaires pour transposer un circuit sur un dispositif donné est une étape importante du processus de transpilation.  Par souci d'efficacité, cette étape est généralement calculée par défaut en même temps que l'étape de mise en page, mais elles sont logiquement distinctes l'une de l'autre.  L'étape de *mise en page* sélectionne les qubits matériels à utiliser, tandis que l'étape de *routage* insère la quantité appropriée de portes SWAP afin d'exécuter les circuits à l'aide de la mise en page sélectionnée.\n",
        "\n",
        "Cependant, il est difficile de trouver la cartographie SWAP optimale.  En fait, il s'agit d'un problème NP-hard, dont le coût de calcul est prohibitif pour tous les dispositifs quantiques et circuits d'entrée, à l'exception des plus petits.  Pour contourner ce problème, Qiskit utilise un algorithme heuristique stochastique appelé `SabreSwap` pour calculer une bonne correspondance SWAP, mais pas nécessairement optimale. L'utilisation d'une méthode stochastique signifie que les circuits générés ne sont pas garantis d'être les mêmes lors d'exécutions répétées.  En effet, l'exécution répétée d'un même circuit se traduit par une distribution des profondeurs de circuit et des nombres de portes à la sortie.  C'est pour cette raison que de nombreux utilisateurs choisissent d'exécuter plusieurs fois la fonction de routage (ou l'ensemble du site `StagedPassManager`) et de sélectionner les circuits les moins profonds dans la distribution des sorties.\n",
        "\n",
        "Prenons par exemple un circuit GHZ de 15 qubits exécuté 100 fois, en utilisant un \"mauvais\" circuit (déconnecté) `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": [
        "Cette large distribution démontre à quel point il est difficile pour le SWAP mapper de calculer la meilleure cartographie.  Pour mieux comprendre, examinons à la fois le circuit exécuté et les qubits choisis sur le matériel.\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": [
        "Comme vous pouvez le voir, ce circuit doit exécuter une porte à deux qubits entre les qubits 0 et 14, qui sont très éloignés l'un de l'autre sur le graphe de connectivité.  L'exécution de ce circuit nécessite donc l'insertion de portes SWAP pour exécuter toutes les portes à deux qubits à l'aide de la passe `SabreSwap` .\n",
        "\n",
        "Notez également que l'algorithme `SabreSwap` est différent de la méthode `SabreLayout` plus large de l'étape précédente.  Par défaut, `SabreLayout` exécute à la fois la mise en page et le routage, et renvoie le circuit transformé.  Ceci est fait pour quelques raisons techniques particulières spécifiées dans la [page de référence de l'API](../api/qiskit/qiskit.transpiler.passes.SabreLayout) de la passe.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "650f978b-d992-4d67-a356-5bf73902f212",
      "metadata": {},
      "source": [
        "<span id=\"translation-stage\" />\n",
        "\n",
        "## Étape de traduction\n",
        "\n",
        "Lorsque vous écrivez un circuit quantique, vous êtes libre d'utiliser n'importe quelle porte quantique (opération unitaire) de votre choix, ainsi qu'un ensemble d'opérations autres que les portes, telles que la mesure de qubits ou les instructions de réinitialisation.  Cependant, la plupart des dispositifs quantiques ne prennent en charge nativement qu'une poignée d'opérations quantiques, qu'il s'agisse de portes quantiques ou d'autres opérations.  Ces portes natives font partie de la définition de [l'ISA](/docs/guides/transpile#instruction-set-architecture) d'une cible, et cette étape du préréglage `PassManagers` convertit (ou «\\* déroule\\* ») les portes spécifiées dans un circuit en portes de base natives d'un backend donné.  Il s'agit d'une étape importante, car elle permet au circuit d'être exécuté par le backend, mais elle entraîne généralement une augmentation de la profondeur et du nombre de portes logiques.\n",
        "\n",
        "Deux cas particuliers sont particulièrement importants et permettent d'illustrer le rôle de cette étape.\n",
        "\n",
        "1. Si une porte SWAP n'est pas une porte native du backend cible, trois portes CNOT sont nécessaires :\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": [
        "En tant que produit de trois portes CNOT, un SWAP est une opération coûteuse à réaliser sur des dispositifs quantiques bruyants.  Toutefois, ces opérations sont généralement nécessaires pour intégrer un circuit dans les connectivités de porte limitées de nombreux dispositifs.  La minimisation du nombre de portes SWAP dans un circuit est donc un objectif primordial dans le processus de transpilation.\n",
        "\n",
        "2. Une porte de Toffoli, ou porte contrôlée-contrôlée-non (`ccx`), est une porte à trois qubits.  Étant donné que notre ensemble de portes de base ne comprend que des portes à un ou deux qubits, cette opération doit être décomposée.  Cependant, il est assez coûteux :\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": [
        "Pour chaque porte de Toffoli dans un circuit quantique, le matériel peut exécuter jusqu'à six portes CNOT et une poignée de portes à qubit unique.  Cet exemple démontre que tout algorithme utilisant plusieurs portes de Toffoli aboutira à un circuit de grande profondeur et sera donc sensiblement affecté par le bruit.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8b396526-b14b-48a3-93ed-37e590b06caf",
      "metadata": {},
      "source": [
        "<span id=\"optimization-stage\" />\n",
        "\n",
        "## Phase d'optimisation\n",
        "\n",
        "Cette étape est centrée sur la décomposition des circuits quantiques dans l'ensemble de portes de base du dispositif cible, et doit lutter contre l'augmentation de la profondeur résultant des étapes de mise en page et de routage.  Heureusement, il existe de nombreuses routines permettant d'optimiser les circuits en combinant ou en éliminant des portes.  Dans certains cas, ces méthodes sont si efficaces que les circuits de sortie ont une profondeur inférieure à celle des circuits d'entrée, même après la mise en page et l'acheminement vers la topologie matérielle.  Dans d'autres cas, il n'y a pas grand-chose à faire et le calcul peut être difficile à effectuer sur des appareils bruyants.  C'est à ce stade que les différents niveaux d'optimisation commencent à se différencier.\n",
        "\n",
        "* Pour `optimization_level=1`, cette étape prépare [`Optimize1qGatesDecomposition`](../api/qiskit/qiskit.transpiler.passes.Optimize1qGatesDecomposition) et [`CXCancellation`](/docs/api/qiskit/1.4/qiskit.transpiler.passes.CXCancellation)qui combinent des chaînes de portes à un qubit et annulent toute porte CNOT placée dos à dos.\n",
        "* Pour `optimization_level=2`, cette étape utilise la passe [`CommutativeCancellation`](../api/qiskit/qiskit.transpiler.passes.CommutativeCancellation) au lieu de `CXCancellation`, qui supprime les portes redondantes en exploitant les relations de commutation.\n",
        "* Pour `optimization_level=3`, cette étape prépare les passes suivantes :\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",
        "En outre, cette étape exécute également quelques vérifications finales pour s'assurer que toutes les instructions du circuit sont composées des portes de base disponibles sur le backend cible.\n",
        "\n",
        "L'exemple ci-dessous, qui utilise un état GHZ, montre les effets des différents niveaux d'optimisation sur la profondeur du circuit et le nombre de portes.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  Le résultat de la transpilation varie en raison du mappeur SWAP stochastique. Par conséquent, les chiffres ci-dessous changeront probablement à chaque fois que vous exécuterez le code.\n",
        "</Admonition>\n",
        "\n",
        "![état GHZ à 15 qubits](https://quantum.cloud.ibm.com/docs/images/guides/transpiler-stages/transpiler-11.avif \"État GHZ à 15 qubits avant transpilation\")\n",
        "\n",
        "Le code suivant construit un état GHZ à 15 qubits et compare la transpilation à l'adresse `optimization_levels` en termes de profondeur de circuit, de nombre de portes et de nombre de portes à plusieurs qubits.\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",
        "## Planification\n",
        "\n",
        "Cette dernière étape n'est exécutée que si elle est explicitement demandée (comme l'étape Init) et n'est pas exécutée par défaut (bien qu'une méthode puisse être spécifiée en définissant l'argument `scheduling_method` lors de l'appel à `generate_preset_pass_manager`).  L'étape de programmation est généralement utilisée une fois que le circuit a été traduit dans la base cible, mappé sur le dispositif et optimisé.  Ces passes visent à tenir compte de toutes les périodes d'inactivité dans un circuit.  À un niveau élevé, la passe d'ordonnancement peut être considérée comme l'insertion explicite d'instructions de retard pour tenir compte du temps d'inactivité entre les exécutions de portes et pour contrôler la durée d'exécution du circuit sur le backend.\n",
        "\n",
        "Par exemple :\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": [
        "![Circuit avec instructions de retardement](https://quantum.cloud.ibm.com/docs/images/guides/transpiler-stages/transpiler-16.avif)\n",
        "\n",
        "Le transpileur a inséré des instructions `Delay` pour tenir compte du temps d'inactivité de chaque qubit. Pour avoir une meilleure idée de la synchronisation du circuit, nous pouvons également l'examiner à l'aide de la fonction `timeline.draw()` :\n",
        "\n",
        "![Vue timeline.draw () du même circuit](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": [
        "L'ordonnancement d'un circuit comporte deux parties : l'analyse et la cartographie des contraintes, suivies d'une passe de remplissage.  La première partie nécessite l'exécution d'une passe d'analyse d'ordonnancement (par défaut, il s'agit de [`ALAPSchedulingAnalysis`](../api/qiskit/qiskit.transpiler.passes.ALAPScheduleAnalysis)), qui analyse le circuit et enregistre l'heure de début de chaque instruction du circuit dans un calendrier.  Une fois que le circuit dispose d'une programmation initiale, des passes supplémentaires peuvent être exécutées pour tenir compte de toute contrainte de temps sur le backend cible.  Enfin, une passe de rembourrage telle que [`PadDelay`](../api/qiskit/qiskit.transpiler.passes.PadDelay) ou [`PadDynamicalDecoupling`](../api/qiskit/qiskit.transpiler.passes.PadDynamicalDecoupling) peut être exécutée.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "62c19c54-6dcc-4025-b800-7a74be69808d",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Etapes suivantes\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recommandations\">\n",
        "  * Pour apprendre à utiliser la fonction `generate_preset_passmanager` , commencez par la rubrique [Paramètres par défaut et options de configuration de la transpilation](defaults-and-configuration-options).\n",
        "  * Poursuivre l'apprentissage de la transpilation avec le thème [Transpiler with pass managers.](transpile-with-pass-managers)\n",
        "  * Consultez le guide [Comparer les paramètres du transpiler](/docs/guides/circuit-transpilation-settings).\n",
        "  * Consultez la [documentation de l'API 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
}