{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "cell-00",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Actualiser les propriétés du backend grâce à des tests de performance en temps réel\"\n",
        "description: \"Effectuez rapidement des expériences de caractérisation pour mesurer en temps réel les propriétés du QPU et actualiser un backend avec les dernières données concernant les erreurs d' T1 ( T2 ), de lecture et de porte.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore CPMG dephase ylim */}\n",
        "\n",
        "<span id=\"refresh-backend-properties-with-real-time-benchmarking\" />\n",
        "\n",
        "# Actualiser les propriétés du backend grâce à des tests de performance en temps réel\n",
        "\n",
        "Estimation de la durée *d'utilisation : 3 minutes sur ibm\\_kingston (REMARQUE : il ne s'agit que d'une estimation. (Votre temps d'exécution peut varier.)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-01",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## Acquis d'apprentissage\n",
        "\n",
        "* Pourquoi les propriétés renvoyées par une QPU peuvent ne pas refléter le comportement actuel du périphérique, et dans quels cas il est utile de les mesurer à nouveau soi-même\n",
        "* Ce que mesure chacune des cinq expériences de caractérisation standard (lecture, benchmark aléatoire à un qubit, benchmark aléatoire à deux qubits en couches, $T_1$ et $T_2$ )\n",
        "* Comment exécuter l'ensemble complet de la suite de caractérisation en une seule fois ou étape par étape, et obtenir en retour un objet backend dont les propriétés ont été mises à jour\n",
        "* Comment comparer les propriétés mesurées à celles indiquées, et pourquoi certaines différences sont davantage liées à la méthode de mesure qu'à une dérive de l'appareil\n",
        "\n",
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## Prérequis\n",
        "\n",
        "* Le flux de travail « [Patterns ](/docs/guides/intro-to-patterns)» de Qiskit\n",
        "* [Qiskit Runtime modes d'exécution](/docs/guides/execution-modes), notamment le mode batch\n",
        "* Comment consulter [les informations relatives au QPU](/docs/guides/qpu-information), telles que les propriétés du backend et les données d'étalonnage\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-02",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## Arrière-plan\n",
        "\n",
        "Chaque QPU « IBM Quantum® » communique un ensemble de propriétés décrivant les performances actuelles de chacun de ses qubits : temps de relaxation ( $T_1$ ), temps de cohérence ( $T_2$ ), erreurs de lecture, ainsi que les erreurs liées aux portes à un et deux qubits. Ces chiffres ont une importance concrète. Le transpileur s'en sert pour déterminer sur quels qubits physiques votre circuit doit s'exécuter; les techniques d'atténuation des erreurs s'appuient sur ces informations, et vous pouvez vous en servir pour évaluer si un dispositif fonctionne suffisamment bien pour une expérience.\n",
        "\n",
        "Les caractéristiques indiquées proviennent de procédures d'étalonnage qui sont généralement effectuées environ une fois par jour. Les qubits supraconducteurs peuvent toutefois subir une dérive à des échelles de temps plus courtes, et des défauts transitoires (ce qu’on appelle des « systèmes à deux niveaux ») peuvent temporairement dégrader un qubit qui semblait parfait au moment de l’étalonnage. De plus, une tâche est souvent transcompilée bien avant son exécution effective; les décisions fondées sur les propriétés signalées peuvent donc reposer sur des informations obsolètes. Le tutoriel « [Benchmarking en temps réel pour la sélection des qubits](/docs/tutorials/real-time-benchmarking-for-qubit-selection) » montre à quel point ces propriétés peuvent varier d’un jour à l’autre et présente la mise en place manuelle d’un workflow complet de caractérisation à partir [d’expériences Qiskit](https://qiskit-community.github.io/qiskit-experiments/) individuelles.\n",
        "\n",
        "Ce tutoriel présente une version simplifiée de ce workflow, grâce à l'utilisation de l'utilitaire `BackendCharacterization` de [Qiskit Device Benchmarking](https://github.com/qiskit-community/qiskit-device-benchmarking), qui regroupe la création de l'expérience, la soumission de la tâche et l'ajustement des courbes en quelques appels seulement. Cela vous prend environ 70 secondes de temps de traitement sur le QPU et vous obtenez en retour un objet backend dont les propriétés reflètent *l'état actuel* de l'appareil, prêt à être comparé aux valeurs communiquées ou transmis aux outils en aval.\n",
        "\n",
        "<span id=\"the-characterization-experiments\" />\n",
        "\n",
        "### Les expériences de caractérisation\n",
        "\n",
        "La suite comprend cinq propriétés, chacune associée à une expérience standard :\n",
        "\n",
        "* **Erreur de lecture** (`readout`): Chaque qubit est préparé dans l'état « $|0\\rangle$ » ou « $|1\\rangle$ » et immédiatement mesuré. La probabilité de lire un état erroné correspond à l'erreur de préparation et de mesure de l'état (SPAM).\n",
        "* **Erreur de porte à un qubit** (`rb_1q`): L'évaluation aléatoire (RB) consiste à exécuter des séquences de portes de Clifford aléatoires à un qubit qui, dans l'idéal, se combinent pour former la porte d'identité. La façon dont la probabilité de survie diminue avec la longueur de la séquence permet de déterminer l'erreur moyenne par porte, indépendamment des erreurs SPAM.\n",
        "* **Erreur de porte à deux qubits** (`rb_2q`): Le même principe RB appliqué à des couches entières de portes à deux qubits non superposées exécutées simultanément, comme dans une expérience [de fidélité de couche](https://arxiv.org/abs/2311.05933). Comme de nombreuses portes fonctionnent simultanément, les taux d'erreur qui en résultent tiennent compte des effets de diaphonie et se rapprochent davantage de ceux observés dans un circuit profond.\n",
        "* **$T_1$** (`t1`): Chaque qubit est excité puis mesuré après des délais croissants. La décroissance de la population à l'état excité détermine le temps de relaxation.\n",
        "* **$T_2$** (`t2`): Une expérience d'écho de Hahn place chaque qubit dans un état de superposition, applique une impulsion d'écho à mi-parcours d'un délai, puis mesure la vitesse à laquelle la cohérence de phase se perd. Par défaut, un seul écho est utilisé; une variante à échos multiples (de type CPMG) est présentée à la fin de ce tutoriel.\n",
        "\n",
        "<span id=\"what-refreshing-does-and-does-not-do\" />\n",
        "\n",
        "### Ce que la réinitialisation fait et ne fait pas\n",
        "\n",
        "Gardez trois points à l'esprit lorsque vous utilisez ce processus :\n",
        "\n",
        "* Les propriétés mises à jour ne figurent que dans l'objet backend qui vous est renvoyé. Rien ne change sur l'appareil lui-même ni dans les données d'étalonnage qu' IBM Quantum transmet aux autres utilisateurs.\n",
        "* Les valeurs mesurées constituent un instantané obtenu selon une méthodologie particulière. Certaines d'entre elles, notamment les erreurs superposées à deux qubits et les valeurs d' $T_2$ s à écho unique en parallèle, sont mesurées différemment des données d'étalonnage publiées; ainsi, une partie de l'écart que vous observez est d'ordre méthodologique plutôt que due à une dérive. Ce tutoriel explique où cela se produit.\n",
        "* La caractérisation elle-même nécessite du temps de calcul sur le QPU (environ 70 secondes pour la suite complète sur un processeur Heron r2 ), ce qui est le prix à payer pour disposer d'informations à jour.\n",
        "\n",
        "Le flux de travail suit les quatre étapes d'un modèle Qiskit :\n",
        "\n",
        "* **Étape 1 : Mettre en correspondance les entrées classiques avec un problème quantique.** Sélectionnez l'appareil et l'ensemble des propriétés à mesurer.\n",
        "* **Étape 2 : Optimiser le problème pour son exécution sur un matériel quantique.** Cet utilitaire construit les circuits d'expérimentation directement dans les portes natives du dispositif et les parallélise à l'échelle de la puce.\n",
        "* **Étape 3 : Exécutez la commande à l'aide d' Qiskit primitives.** Les expériences sont exécutées sous forme de tâches Sampler au sein d'un lot.\n",
        "* **Étape 4 : Effectuer le post-traitement et restituer le résultat dans le format classique souhaité.** Intégrer les données de mesure dans des cartes d'erreurs par qubit, actualiser le backend, puis comparer les propriétés mesurées à celles indiquées.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-03",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## Exigences\n",
        "\n",
        "Avant de commencer ce tutoriel, assurez-vous d'avoir installé les éléments suivants :\n",
        "\n",
        "* Qiskit SDK v2.0 ou version ultérieure, avec prise en charge de [la visualisation](/docs/api/qiskit/visualization)\n",
        "* Qiskit Runtime v0.40 ou version ultérieure (`pip install qiskit-ibm-runtime`)\n",
        "* Qiskit Device Benchmarking, qui installe également [Qiskit Experiments](https://qiskit-community.github.io/qiskit-experiments/) (`pip install git+https://github.com/qiskit-community/qiskit-device-benchmarking.git`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-04",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## Configuration\n",
        "\n",
        "Importez les bibliothèques nécessaires.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "cell-05",
      "metadata": {},
      "outputs": [],
      "source": [
        "import logging\n",
        "import sys\n",
        "\n",
        "import numpy as np\n",
        "from qiskit_ibm_runtime import Batch, QiskitRuntimeService\n",
        "\n",
        "from qiskit_device_benchmarking.utilities.characterization_utils import (\n",
        "    BackendCharacterization,\n",
        "    plot_characterization_comparison,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-06",
      "metadata": {},
      "source": [
        "La suite de caractérisation met en place plusieurs expériences, envoie plusieurs tâches et effectue l'ajustement des résultats, ce qui peut prendre quelques minutes au total. Activez la journalisation de niveau INFO afin que chaque étape affiche sa progression au fur et à mesure.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "cell-07",
      "metadata": {},
      "outputs": [],
      "source": [
        "logger = logging.getLogger(\"qiskit_device_benchmarking\")\n",
        "logger.setLevel(logging.INFO)\n",
        "logger.addHandler(logging.StreamHandler(stream=sys.stdout))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-08",
      "metadata": {},
      "source": [
        "<span id=\"small-scale-simulator-example\" />\n",
        "\n",
        "## Exemple de simulateur à petite échelle\n",
        "\n",
        "Ce tutoriel ne comprend pas d'exemple de simulation. Ce processus permet de mesurer les imperfections physiques d'un dispositif donné : la vitesse à laquelle ses qubits se relâchent et se déphasent, ainsi que la fréquence à laquelle ses portes logiques et ses lectures échouent. Un simulateur idéal ne présente aucune de ces imperfections; il n'y a donc rien à caractériser. Vous pourriez associer un modèle de bruit synthétique à un backend fictif, mais les expériences ne feraient alors que reproduire les chiffres que vous auriez vous-même saisis. C'est pourquoi nous passons directement au matériel, en suivant les quatre étapes d'un modèle Qiskit.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-09",
      "metadata": {},
      "source": [
        "<span id=\"large-scale-hardware-example\" />\n",
        "\n",
        "## Exemple de matériel à grande échelle\n",
        "\n",
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "### Étape 1 : Mettre en correspondance les entrées classiques avec un problème quantique\n",
        "\n",
        "Dans ce flux de travail, le « problème » est le dispositif lui-même : les entrées classiques sont le QPU que l'on souhaite caractériser et la liste des propriétés à mesurer, tandis que les expériences quantiques correspondent aux circuits de caractérisation générés à partir de ces données.\n",
        "\n",
        "Commencez par choisir un backend. Ce tutoriel utilise un processeur Heron r2 de 156 qubits `ibm_kingston`; vous pouvez le remplacer par n'importe quel appareil IBM Quantum auquel vous avez accès (ou en choisir un avec `service.least_busy()`).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "cell-10",
      "metadata": {},
      "outputs": [],
      "source": [
        "service = QiskitRuntimeService()\n",
        "device = \"ibm_kingston\"\n",
        "backend = service.backend(device)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-11",
      "metadata": {},
      "source": [
        "Choisissez ensuite les propriétés que vous souhaitez mesurer. Vous pouvez réussir n'importe quel sous-ensemble des épreuves suivantes :\n",
        "\n",
        "* `readout`: Expérience SPAM (préparation et mesure des états)\n",
        "* `rb_1q`: tests de performance aléatoires sur un qubit isolé\n",
        "* `rb_2q`: Évaluation comparative aléatoire simultanée de deux qubits à partir d'une expérience de fidélité par couches\n",
        "* `t2`: $T_2$ Expérience d'écho de Hahn (un seul écho par défaut)\n",
        "* `t1`: Expérience de relaxation « $T_1$ »\n",
        "\n",
        "Lancez la suite complète pour obtenir une vue d'ensemble de l'appareil; supprimez les entrées de la liste si seules certaines propriétés vous intéressent et que vous souhaitez économiser du temps de calcul sur la QPU.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "cell-12",
      "metadata": {},
      "outputs": [],
      "source": [
        "experiments = [\"readout\", \"rb_1q\", \"rb_2q\", \"t1\", \"t2\"]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-13",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "### Étape 2 : Optimisation du problème en vue de son exécution sur un matériel quantique\n",
        "\n",
        "Dans la plupart des tutoriels, c'est à ce stade que vous devriez transcompiler vos circuits. Ici, s'en `BackendCharacterization` charge en interne. Il construit les circuits d'expérimentation directement dans les portes natives du dispositif, exécute les expériences sur un seul qubit sur tous les qubits en parallèle, et planifie les tests de performance sur deux qubits sur des couches disjointes de la carte de couplage, de sorte que l'ensemble du dispositif soit couvert par une poignée de tâches. Grâce à cette parallélisation, l'ensemble de la suite ne nécessite qu'environ 70 secondes de temps de calcul sur le QPU.\n",
        "\n",
        "Initialisez la classe qui gère le flux de travail :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "cell-14",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Initialize the class used to run the experiments\n",
        "characterizer = BackendCharacterization(backend)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-15",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### Étape 3 : Exécutez la commande à l'aide d' Qiskit primitives\n",
        "\n",
        "Cette méthode `run_experiments` crée les circuits et les soumet sous forme de tâches [Sampler](/docs/guides/get-started-with-sampler). Exécutez-la dans un contexte [`Batch`](/docs/guides/run-jobs-batch) afin que les tâches soient planifiées ensemble sur le QPU et que la méthode renvoie un résultat une fois que toutes les tâches ont été soumises. (Vous pouvez également l'exécuter en dehors d'un fichier batch, ou à l'intérieur d'un `Session`.)\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  Il se peut qu'un message d'avertissement s'affiche, indiquant qu'un backend a été transmis alors qu'un gestionnaire de contexte de session est ouvert. Ce phénomène est normal et peut être ignoré sans risque.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "cell-16",
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "base_primitive.get_mode_service_backend:WARNING:2026-07-14 14:23:02,051: A backend was passed in as the mode but a session context manager is open so this job will run inside this session/batch instead of in job mode.\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Building readout experiments\n",
            "Building 1Q RB experiments\n",
            "Building 2Q RB experiments\n",
            "Building T1 experiments\n",
            "Building T2 experiments\n",
            "Layered two-qubit RB submitted: ['d9b7tfu6hjac73ffba2g', 'd9b7tjug26ic73dfju3g', 'd9b7u3u6hjac73ffban0', 'd9b7u7rv6alc73csmicg']\n",
            "Readout job submitted: d9b7u8bv6alc73csmidg\n",
            "T1 experiment submitted: ['d9b7u8ug26ic73dfjuqg']\n",
            "T2 (Hahn) experiment submitted: ['d9b7u9fu62qs738othg0']\n",
            "Single-qubit RB submitted: ['d9b7v8m6hjac73ffbc40', 'd9b7veeg26ic73dfk040']\n"
          ]
        }
      ],
      "source": [
        "# Run the characterization experiments inside a Batch\n",
        "with Batch(backend=backend):\n",
        "    jobs = characterizer.run_experiments(experiments=experiments)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-17",
      "metadata": {},
      "source": [
        "Cette méthode renvoie les tâches soumises sous la forme d'un dictionnaire dont les clés correspondent aux expériences, ce qui est utile pour les suivre sur le [tableau de bord de IBM Quantum Platform ou à des fins de débogage.](/docs/guides/monitor-job)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "cell-18",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'rb_2q': [<RuntimeJobV2('d9b7tfu6hjac73ffba2g', 'sampler')>,\n",
              "  <RuntimeJobV2('d9b7tjug26ic73dfju3g', 'sampler')>,\n",
              "  <RuntimeJobV2('d9b7u3u6hjac73ffban0', 'sampler')>,\n",
              "  <RuntimeJobV2('d9b7u7rv6alc73csmicg', 'sampler')>],\n",
              " 'readout': [<RuntimeJobV2('d9b7u8bv6alc73csmidg', 'sampler')>],\n",
              " 't1': [<RuntimeJobV2('d9b7u8ug26ic73dfjuqg', 'sampler')>],\n",
              " 't2': [<RuntimeJobV2('d9b7u9fu62qs738othg0', 'sampler')>],\n",
              " 'rb_1q': [<RuntimeJobV2('d9b7v8m6hjac73ffbc40', 'sampler')>,\n",
              "  <RuntimeJobV2('d9b7veeg26ic73dfk040', 'sampler')>]}"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Print all the job IDs for debugging purposes\n",
        "jobs"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-19",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-and-return-result-in-desired-classical-format\" />\n",
        "\n",
        "### Étape 4 : Traitement ultérieur et restitution du résultat dans le format classique souhaité\n",
        "\n",
        "<span id=\"analyze-the-results\" />\n",
        "\n",
        "#### Analyser les résultats\n",
        "\n",
        "La méthode `analyze_results` attend que les tâches soient terminées, puis effectue l'ajustement des données de mesure : des décroissances exponentielles pour $T_1$ et $T_2$, des décroissances de probabilité de survie pour les expériences RB, et des matrices d'affectation pour la lecture. Elle renvoie un dictionnaire de *tables d'erreurs*, avec une entrée par propriété mesurée, chacune associant un qubit (ou une paire de qubits) à sa valeur mesurée.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "cell-20",
      "metadata": {},
      "outputs": [],
      "source": [
        "error_maps = characterizer.analyze_results()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "cell-21",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The following error maps are available: ['readout_error', 'oneq_error_x', 'oneq_error_sx', 'lf_error_map', 't1_map', 't2_map']\n",
            "For example, readout error for qubit 0 is 0.007600000000000051\n"
          ]
        }
      ],
      "source": [
        "print(f\"The following error maps are available: {list(error_maps.keys())}\")\n",
        "readout_q0 = error_maps[\"readout_error\"][0]\n",
        "print(f\"For example, readout error for qubit 0 is {readout_q0}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-22",
      "metadata": {},
      "source": [
        "Les graphiques présentent les erreurs de lecture, les erreurs de porte `sx` sur un seul qubit et `x` les erreurs de porte, les erreurs de deux qubits par couches (`lf_error_map`issues de l'expérience sur la fidélité par couche), ainsi que les temps de « $T_1$ » et de « $T_2$ » exprimés en secondes.\n",
        "\n",
        "<span id=\"update-the-backend-properties\" />\n",
        "\n",
        "#### Mettre à jour les propriétés du backend\n",
        "\n",
        "Cette méthode `update_backend` enregistre les valeurs mesurées dans les propriétés d'une copie du backend, puis renvoie cette copie. L'objet `backend` d'origine conserve les données d'étalonnage enregistrées, ce qui nous permet de comparer les deux, comme illustré ci-dessous. N'oubliez pas que cette mise à jour ne concerne que votre session « Python »; elle n'entraîne aucun changement sur l'appareil ni pour les autres utilisateurs.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "cell-23",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Updating readout error\n",
            "Updating single-qubit X error\n",
            "Updating single-qubit SX error\n",
            "Updating two-qubit error\n",
            "Updating T1\n",
            "Updating T2\n"
          ]
        }
      ],
      "source": [
        "backend_updated = characterizer.update_backend()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-24",
      "metadata": {},
      "source": [
        "<span id=\"compare-the-measured-properties-against-the-reported-ones\" />\n",
        "\n",
        "#### Comparez les propriétés mesurées à celles indiquées\n",
        "\n",
        "Enfin, tracez un graphique comparant les propriétés mesurées en temps réel aux valeurs fournies par le backend. Dans chaque panneau, les qubits (ou paires de qubits) sont classés en fonction de la valeur mesurée; ainsi, la courbe de mesure est lisse par nature et la dispersion des valeurs indiquées autour de celle-ci met en évidence les points de divergence entre les deux. Un seul graphique est présenté pour le RB à un seul qubit, car la même erreur mesurée par porte est attribuée à la fois aux portes `sx` et `x` . Les limites des axes sont choisies à partir de l'ensemble des données afin d'éviter que quelques valeurs aberrantes extrêmes ne déforment les graphiques; les points situés en dehors de cette plage sont indiqués dans une annotation sur le graphique (ou utilisez la commande « pass » pour `ylim` remplacer ces limites).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "cell-25",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/refresh-backend-properties-with-real-time-benchmarking/extracted-outputs/cell-25-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/refresh-backend-properties-with-real-time-benchmarking/extracted-outputs/cell-25-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/refresh-backend-properties-with-real-time-benchmarking/extracted-outputs/cell-25-2.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/refresh-backend-properties-with-real-time-benchmarking/extracted-outputs/cell-25-3.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/refresh-backend-properties-with-real-time-benchmarking/extracted-outputs/cell-25-4.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plot_characterization_comparison(\n",
        "    old_props=backend.properties().to_dict(),\n",
        "    new_props=backend_updated.properties().to_dict(),\n",
        "    plots=[\"readout\", \"rb_1q\", \"rb_2q\", \"t1\", \"t2\"],\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-26",
      "metadata": {},
      "source": [
        "Ces graphiques doivent être interprétés avec précaution, car tous les écarts entre les deux courbes ne signifient pas nécessairement que l'appareil a dérivé :\n",
        "\n",
        "* **Lecture et erreurs sur un seul qubit** : les valeurs mesurées correspondent à celles rapportées pour la plupart des qubits, tandis que la valeur rapportée pour quelques-uns d'entre eux s'écarte considérablement de la courbe mesurée. Ce sont précisément ces divergences ponctuelles que ce processus de travail est censé détecter.\n",
        "* **$T_1$** : Les deux ensembles de données se répartissent de manière aléatoire l’un par rapport à l’autre, sans décalage systématique, ce qui corrobore l’hypothèse selon laquelle l’ $T_1$ e fluctue naturellement au fil du temps.\n",
        "* **Erreurs sur deux qubits** : les valeurs mesurées sont systématiquement *supérieures* à celles rapportées. Ce résultat est prévisible, car les valeurs rapportées sont mesurées sur des grilles isolées, tandis que l'expérience sur la fidélité de la couche porte sur de nombreuses grilles simultanément et inclut donc la diaphonie. Les chiffres par couches sont plus pertinents pour les circuits profonds, mais ils ne sont pas directement comparables aux données d'étalonnage publiées.\n",
        "* **$T_2$** : Les valeurs mesurées sont nettement *inférieures* à celles rapportées pour la plupart des qubits. Là encore, la méthodologie joue un rôle important, comme nous le verrons dans la section suivante.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-27",
      "metadata": {},
      "source": [
        "<span id=\"inspect-individual-experiment-results\" />\n",
        "\n",
        "#### Consulter les résultats de chaque expérience\n",
        "\n",
        "Vous pouvez également consulter les résultats bruts des différentes expériences de caractérisation grâce à la propriété `experiment_data` , qui renvoie les objets `ExperimentData` [Qiskit Experiments](https://qiskit-community.github.io/qiskit-experiments/) sous-jacents. Par exemple, le graphique suivant présente la courbe de décroissance mesurée de l' $T_1$ e d'un qubit unique, ce qui permet de vérifier la qualité d'un ajustement avant de se fier aux résultats obtenus.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "cell-28",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "156 figures available, e.g. T1_Q0_c78ef792.svg\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/refresh-backend-properties-with-real-time-benchmarking/extracted-outputs/cell-28-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 12,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "t1_data = characterizer.experiment_data[\"t1\"]\n",
        "\n",
        "# Each qubit has its own fit figure\n",
        "n_figs = len(t1_data.figure_names)\n",
        "print(f\"{n_figs} figures available, e.g. {t1_data.figure_names[0]}\")\n",
        "\n",
        "# Show the T1 decay curve of the first qubit\n",
        "t1_data.figure(0)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-29",
      "metadata": {},
      "source": [
        "<span id=\"measure-t2-with-a-dynamical-decoupling-train\" />\n",
        "\n",
        "#### Mesure de l' T2 e à l'aide d'un train de découplage dynamique\n",
        "\n",
        "Par défaut, l'expérience « $T_2$ » utilise un seul écho de Hahn et mesure tous les qubits en parallèle, ce qui, comme le montre le graphique comparatif ci-dessus, peut donner des valeurs d' $T_2$ ion nettement inférieures à celles indiquées par le backend. Une hypothèse concerne le nombre d'échos : les valeurs rapportées pourraient avoir été calibrées à l'aide d'un découplage dynamique, qui supprime le bruit à basse fréquence. Pour vérifier cela, lancez une caractérisation « $T_2$ » avec le paramètre réglé `t2_num_echoes` sur une valeur plus élevée, ce qui applique une séquence d’impulsions d’écho de type CPMG. Ces retards correspondent à la durée totale d'évolution libre dans les deux cas; les valeurs d' $T_2$ s obtenues par ajustement sont donc directement comparables aux résultats obtenus avec un seul écho.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "cell-30",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Building T2 experiments\n",
            "T2 (Hahn) experiment submitted: ['d9b96s6g26ic73dflcn0']\n",
            "Updating T2\n"
          ]
        }
      ],
      "source": [
        "# Run a T2-only characterization using a CPMG-style train of 8 echoes\n",
        "characterizer_dd = BackendCharacterization(backend)\n",
        "backend_updated_dd = characterizer_dd.run_and_update(\n",
        "    experiments=[\"t2\"], t2_num_echoes=8\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "cell-31",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/refresh-backend-properties-with-real-time-benchmarking/extracted-outputs/cell-31-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Median T2 — reported: 142 us | single echo: 53 us | 8-echo CPMG: 56 us\n"
          ]
        }
      ],
      "source": [
        "# Compare the multi-echo T2 against the backend-reported values\n",
        "plot_characterization_comparison(\n",
        "    old_props=backend.properties().to_dict(),\n",
        "    new_props=backend_updated_dd.properties().to_dict(),\n",
        "    plots=[\"t2\"],\n",
        "    title_prefix=\"8-echo CPMG\",\n",
        ")\n",
        "\n",
        "# Compare medians across the reported values, the single-echo run,\n",
        "# and the 8-echo run\n",
        "reported_t2s = [\n",
        "    prop[\"value\"]\n",
        "    for qubit in backend.properties().to_dict()[\"qubits\"]\n",
        "    for prop in qubit\n",
        "    if prop[\"name\"] == \"T2\"\n",
        "]\n",
        "t2_reported = np.median(reported_t2s)\n",
        "t2_single = np.median(list(error_maps[\"t2_map\"].values())) * 1e6\n",
        "t2_dd = (\n",
        "    np.median(list(characterizer_dd.analyze_results()[\"t2_map\"].values()))\n",
        "    * 1e6\n",
        ")\n",
        "print(\n",
        "    f\"Median T2 — reported: {t2_reported:.0f} us | \"\n",
        "    f\"single echo: {t2_single:.0f} us | 8-echo CPMG: {t2_dd:.0f} us\"\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-32",
      "metadata": {},
      "source": [
        "Dans cette série de mesures, les échos supplémentaires n'ont pratiquement pas modifié le résultat : la médiane obtenue avec 8 échos (56 µs) est proche de celle obtenue avec un seul écho (53 µs), et toutes deux restent bien en deçà de la médiane rapportée (142 µs). Le nombre d'échos à lui seul ne suffit pas à expliquer cet écart; d'autres différences méthodologiques entrent en ligne de compte, telles que les détails de la procédure d'étalonnage, la mesure de tous les qubits en parallèle plutôt qu'individuellement, etc.\n",
        "\n",
        "La leçon à en tirer est qu'il faut considérer avec prudence les comparaisons entre les méthodes concernant l'erreur de type « $T_2$ » (et l'erreur de type « layered two-qubit »). Les valeurs actualisées constituent un instantané cohérent, obtenu dans des conditions proches d'une charge de travail réelle, ce qui les rend particulièrement adaptées à la comparaison entre différents qubits ou au suivi d'un dispositif au fil du temps. Un écart par rapport aux données d'étalonnage communiquées ne constitue toutefois pas automatiquement une preuve de dérive.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-33",
      "metadata": {},
      "source": [
        "<span id=\"steps-1–4-compressed-into-a-single-call\" />\n",
        "\n",
        "### Étapes 1 à 4 regroupées en un seul appel\n",
        "\n",
        "Dans le cadre d'une utilisation quotidienne, on a rarement besoin des résultats intermédiaires. Cette méthode `run_and_update` regroupe toutes les opérations que vous avez effectuées ci-dessus (compilation, envoi, ajustement et mise à jour) en un seul appel qui renvoie le backend actualisé. Elle accepte la même `experiments` liste (et transmet des options telles que `t2_num_echoes`), et peut également être placée dans un `Session` contexte `Batch` ou.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  La cellule suivante ne renvoie pas de résultat tant que toutes les tâches et le post-traitement ne sont pas terminés.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "cell-34",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Building readout experiments\n",
            "Building 1Q RB experiments\n",
            "Building 2Q RB experiments\n",
            "Building T1 experiments\n",
            "Building T2 experiments\n",
            "Layered two-qubit RB submitted: ['d9b7oqnu62qs738otat0', 'd9b7p76g26ic73dfjolg', 'd9b7pnm6hjac73ffb57g', 'd9b7q4fu62qs738otce0']\n",
            "Readout job submitted: d9b7q4mg26ic73dfjprg\n",
            "T1 experiment submitted: ['d9b7q57u62qs738otcfg']\n",
            "T2 (Hahn) experiment submitted: ['d9b7q5m6hjac73ffb5pg']\n",
            "Single-qubit RB submitted: ['d9b7r4e6hjac73ffb71g', 'd9b7reu6hjac73ffb7d0']\n",
            "Updating readout error\n",
            "Updating single-qubit X error\n",
            "Updating single-qubit SX error\n",
            "Updating two-qubit error\n",
            "Updating T1\n",
            "Updating T2\n"
          ]
        }
      ],
      "source": [
        "# Initialize a fresh characterizer\n",
        "characterizer = BackendCharacterization(backend)\n",
        "\n",
        "# Run all of the experiments and update the backend in a single call\n",
        "backend_updated = characterizer.run_and_update(experiments=experiments)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-35",
      "metadata": {},
      "source": [
        "L'objet `backend_updated` mis à jour est désormais prêt à être utilisé partout où les propriétés du backend alimentent votre flux de travail. Essayez cette méthode en complément du tutoriel « [Benchmarking en temps réel pour la sélection des qubits ](/docs/tutorials/real-time-benchmarking-for-qubit-selection)» afin de choisir les qubits les plus performants lors de la transpilation d'un circuit. Comme l'appareil ne cesse de dériver, actualisez ses propriétés peu avant l'exécution effective de votre charge de travail.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cell-36",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Etapes suivantes\n",
        "\n",
        "Si ce travail vous a paru intéressant, les documents suivants pourraient vous intéresser :\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recommandations\">\n",
        "  * Utilisez les propriétés actualisées pour sélectionner de meilleurs qubits dans le tutoriel « [Évaluation en temps réel de la sélection des qubits ».](/docs/tutorials/real-time-benchmarking-for-qubit-selection)\n",
        "  * Découvrez comment les données d'étalonnage déclarées sont présentées dans le guide [d'information sur la QPU](/docs/guides/qpu-information)\n",
        "  * Découvrez les différentes expériences de caractérisation dans la [documentation « Qiskit Experiments »](https://qiskit-community.github.io/qiskit-experiments/)\n",
        "  * Découvrez d'autres tests de performance au niveau des appareils dans le [référentiel « Qiskit Device Benchmarking »](https://github.com/qiskit-community/qiskit-device-benchmarking)\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": 5
}