{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "0d58aa59",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"QESEM - Une fonction Qiskit par Qedma\"\n",
        "description: \"Exécutez des circuits quantiques sur des QPU bruyants pour obtenir des résultats très précis et sans erreur, avec des surcoûts de temps QPU très efficaces, proches des limites fondamentales.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore DESY Multibase, Quasicrystal, Downfolding, Aharonov, Goldack, wavefunctions, Sakuma */}\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dde95705",
      "metadata": {},
      "source": [
        "<span id=\"qesem-a-qiskit-function-by-qedma\" />\n",
        "\n",
        "# QESEM : une fonction Qiskit par Qedma\n",
        "\n",
        "*Consultez la [documentation de l'API](/docs/api/functions/qedma-qesem)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6256578e",
      "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 présenté sur cette page a été développé conformément aux exigences suivantes.\n",
        "    Nous vous recommandons d'utiliser ces versions ou des versions plus récentes.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.5.0\n",
        "    qiskit-ibm-runtime~=0.47.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "13528739",
      "metadata": {},
      "source": [
        "<Admonition type=\"note\" title=\"Remarque\">\n",
        "  Les fonctions Qiskit sont une fonctionnalité expérimentale disponible uniquement pour IBM Quantum® Premium Plan, Flex Plan, et On-Prem (via IBM Quantum Platform API). Elles sont en cours de publication et peuvent être modifiées.\n",
        "</Admonition>\n",
        "\n",
        "<span id=\"overview\" />\n",
        "\n",
        "## Aperçu\n",
        "\n",
        "Bien que les unités de traitement quantique se soient considérablement améliorées ces dernières années, les erreurs dues au bruit et aux imperfections du matériel existant restent un défi majeur pour les développeurs d'algorithmes quantiques. À mesure que le domaine se rapproche des calculs quantiques à l'échelle industrielle qui ne peuvent être vérifiés de manière classique, les solutions permettant d'annuler le bruit avec une précision garantie deviennent de plus en plus importantes. Pour relever ce défi, Qedma a développé Quantum Error Mitigation (QESEM), intégré de manière transparente sur IBM Quantum Platform en tant que [fonction](/docs/guides/functions) Qiskit.\n",
        "\n",
        "Grâce à QESEM, les utilisateurs peuvent exécuter leurs circuits quantiques sur des QPU sujets au bruit afin d'obtenir des résultats d'une grande précision et exempts d'erreurs, avec des surcoûts en temps de calcul sur QPU très efficaces, proches des limites fondamentales. Pour y parvenir, QESEM s'appuie sur un ensemble de méthodes exclusives mises au point par Qedma, destinées à la caractérisation et à la réduction des erreurs. Les techniques de réduction des erreurs comprennent l'optimisation des portes logiques, la transpilation tenant compte du bruit, la suppression des erreurs (ES) et l'atténuation non biaisée des erreurs (EM). Grâce à cette combinaison de méthodes fondées sur la caractérisation, les utilisateurs peuvent obtenir des résultats fiables et sans erreur pour des circuits quantiques génériques de grand volume, ouvrant ainsi la voie à des applications qui ne pourraient être réalisées autrement.\n",
        "\n",
        "Pour une description complète des composants sous-jacents, ainsi qu'une démonstration à l'échelle industrielle, consultez l'article «[ Reliable high-accuracy error mitigation for utility-scale quantum circuits](https://arxiv.org/abs/2508.10997) » (Atténuation fiable et hautement précise des erreurs pour les circuits quantiques à l'échelle industrielle).\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5f761442",
      "metadata": {},
      "source": [
        "<span id=\"description\" />\n",
        "\n",
        "## Description\n",
        "\n",
        "Vous pouvez utiliser la fonction QESEM de Qedma pour estimer et exécuter facilement vos circuits en supprimant et en atténuant les erreurs, ce qui permet d'obtenir des volumes de circuits plus importants et des précisions plus élevées. Pour utiliser QESEM, vous devez fournir un circuit quantique, un ensemble d'observables à mesurer, une précision statistique cible pour chaque observable et une QPU choisie. Avant d'exécuter le circuit avec la précision souhaitée, vous pouvez estimer le temps nécessaire à la QPU sur la base d'un calcul analytique qui ne nécessite pas l'exécution du circuit. Une fois que vous êtes satisfait de l'estimation du temps de QPU, vous pouvez exécuter le circuit avec QESEM.\n",
        "\n",
        "Lorsque vous exécutez un circuit, QESEM exécute un protocole de caractérisation des dispositifs adapté à votre circuit, ce qui permet d'obtenir un modèle de bruit fiable pour les erreurs qui se produisent dans le circuit. Sur la base de cette caractérisation, QESEM met d'abord en œuvre une transpilation sensible au bruit afin de mapper le circuit d'entrée sur un ensemble de qubits et de portes physiques, ce qui minimise le bruit affectant l'observable cible. Il s'agit notamment des portes disponibles en natif (CX/CZ sur les dispositifs d' IBM® ), ainsi que des portes supplémentaires optimisées par QESEM, formant l'ensemble de portes étendu de QESEM. QESEM exécute ensuite un ensemble de circuits ES et EM basés sur la caractérisation sur le QPU et recueille les résultats des mesures. Ces données sont ensuite traitées de manière classique afin d'obtenir une valeur attendue non biaisée et une barre d'erreur pour chaque observable, correspondant à la précision requise.\n",
        "\n",
        "![Qedma QESEM vue d'ensemble](https://quantum.cloud.ibm.com/docs/images/guides/qedma-qesem/overview.svg)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "74823696",
      "metadata": {},
      "source": [
        "Il a été démontré que le QESEM fournit des résultats de haute précision pour une variété d'applications quantiques et sur les plus grands volumes de circuits réalisables aujourd'hui. QESEM offre les fonctionnalités suivantes, démontrées dans la section \"benchmarks\" ci-dessous :\n",
        "\n",
        "* **Précision garantie :** QESEM fournit des estimations non biaisées pour les valeurs attendues des observables. Sa méthode EM est dotée de garanties théoriques qui, associées à la caractérisation de pointe de Qedma, garantissent que l'atténuation converge vers la sortie du circuit sans bruit jusqu'à la précision spécifiée par l'utilisateur. Contrairement à de nombreuses méthodes EM heuristiques sujettes à des erreurs systématiques ou à des biais, la précision garantie de QESEM est essentielle pour assurer des résultats fiables dans les circuits quantiques génériques et les observables.\n",
        "* **Évolutivité vers des QPU de grande taille :** le temps de QPU de QESEM dépend du volume des circuits, mais est par ailleurs indépendant du nombre de qubits. Qedma a fait la démonstration de QESEM sur les plus grands dispositifs quantiques disponibles à ce jour, notamment les dispositifs Eagle à 127 qubits et Heron à 133 qubits de l' IBM Quantum.\n",
        "* **Indépendant de l'application :** Le QESEM a fait ses preuves dans diverses applications, notamment la simulation hamiltonienne, le VQE, le QAOA et l'estimation d'amplitude. Les utilisateurs peuvent saisir n'importe quel circuit quantique et observable à mesurer, et obtenir des résultats précis et sans erreur. Les seules limitations sont dictées par les spécifications du matériel et le temps alloué à la QPU, qui déterminent les volumes de circuits accessibles et les précisions de sortie. En revanche, de nombreuses solutions de réduction des erreurs sont spécifiques à une application ou impliquent des heuristiques non contrôlées, ce qui les rend inapplicables aux circuits et applications quantiques génériques.\n",
        "* **Ensemble de portes étendu :** QESEM prend en charge les portes à angle fractionnaire et fournit des portes d' $Rzz(\\theta)$ s à angle fractionnaire optimisées pour Qedma sur les dispositifs IBM Quantum Heron et Eagle. Cet ensemble de portes étendu permet une compilation plus efficace et débloque des volumes de circuits jusqu'à deux fois plus importants par rapport à la compilation CX/CZ par défaut.\n",
        "* **Observables multibases :** QESEM prend en charge les observables d'entrée composées de nombreuses chaînes de Pauli non commutatives, telles que les hamiltoniens génériques. Le choix des bases de mesure et l'optimisation de l'allocation des ressources QPU (plans et circuits) sont alors effectués automatiquement par QESEM afin de minimiser le temps requis par QPU pour la précision demandée. Cette optimisation, qui prend en compte la fidélité du matériel et les taux d'exécution, vous permet d'exécuter des circuits plus profonds et d'obtenir des précisions plus élevées.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "57b41ab0",
      "metadata": {},
      "source": [
        "<span id=\"benchmarks\" />\n",
        "\n",
        "## Tests de performances\n",
        "\n",
        "QESEM a été testé sur une grande variété de cas d'utilisation et d'applications. Les exemples suivants peuvent vous aider à évaluer les types de charges de travail que vous pouvez exécuter avec QESEM.\n",
        "\n",
        "Un chiffre clé pour quantifier la difficulté de l'atténuation des erreurs et de la simulation classique pour un circuit et un observable donnés est le **volume actif** : le nombre de portes CNOT affectant l'observable dans le circuit. Le volume actif dépend de la profondeur et de la largeur du circuit, du poids de l'observable et de la structure du circuit, qui détermine le cône lumineux de l'observable. Pour plus de détails, voir l'exposé du [2024 IBM Quantum Summit.](https://www.youtube.com/watch?v=Hd-IGvuARfE\\&t=1730s) QESEM fournit une valeur particulièrement importante dans le régime des grands volumes, donnant des résultats fiables pour des circuits et des observables génériques.\n",
        "\n",
        "![Volume actif](https://quantum.cloud.ibm.com/docs/images/guides/qedma-qesem/active_volume.svg)\n",
        "\n",
        "| Application                          | Nombre de qubits | Dispositif   | Description du circuit                                         | Exactitude | Temps total | Utilisation de l'environnement d'exécution |\n",
        "| ------------------------------------ | ---------------- | ------------ | -------------------------------------------------------------- | ---------- | ----------- | ------------------------------------------ |\n",
        "| Circuit VQE                          | 8                | Aigle ( r3 ) | 21 couches au total, 9 bases de mesure, 1D chaîne              | 98 %       | 35 min      | 14 min                                     |\n",
        "| Kicked Ising                         | 28               | Aigle ( r3 ) | 3 couches uniques x 3 étapes, 2D heavy-hex topology            | 97 %       | 22 min      | 4 min                                      |\n",
        "| Kicked Ising                         | 28               | Aigle ( r3 ) | 3 couches uniques x 8 étapes, 2D heavy-hex topology            | 97 %       | 116 min     | 23 min                                     |\n",
        "| Simulation d'un hamiltonien trotteur | 40               | Aigle ( r3 ) | 2 couches uniques x 10 marches de Trotter, 1D chaîne           | 97 %       | 3 heures    | 25 min                                     |\n",
        "| Simulation d'un hamiltonien trotteur | 119              | Aigle ( r3 ) | 3 couches uniques x 9 étapes de Trotter, 2D heavy-hex topology | 95 %       | 6.5 heures  | 45 minutes                                 |\n",
        "| Kicked Ising                         | 136              | Héron ( r2 ) | 3 couches uniques x 15 étapes, 2D heavy-hex topology           | Dans 99 %  | 52 min      | 9 minutes                                  |\n",
        "\n",
        "La précision est mesurée ici par rapport à la valeur idéale de l'observable : $\\frac{\\langle O \\rangle_{ideal} - \\epsilon}{\\langle O \\rangle_{ideal}}$ où \" $\\epsilon$ \" est la précision absolue de l'atténuation (fixée par l'entrée de l'utilisateur), et $\\langle O \\rangle_{ideal}$ est l'observable dans le circuit sans bruit.\n",
        "l'utilisation du temps d'exécution mesure l'utilisation du benchmark en mode batch (somme de l'utilisation des tâches individuelles), tandis que le temps total mesure l'utilisation en mode session (temps de l'expérience), qui comprend des temps classiques et de communication supplémentaires. QESEM peut être exécuté dans les deux modes, afin que les utilisateurs puissent utiliser au mieux les ressources dont ils disposent.\n",
        "\n",
        "Les circuits Kicked Ising à 28 qubits simulent le Quasicrystal à temps discret étudié par Shinjo et al. (voir [arXiv 2403.16718](https://arxiv.org/abs/2403.16718) et [Q2B24 Tokyo](https://www.youtube.com/watch?v=tQW6FdLc6zo) ) sur trois boucles connectées de ibm\\_kawasaki. Les paramètres du circuit pris ici sont $(\\theta_x, \\theta_z) = (0.9 \\pi, 0)$, avec un état initial ferromagnétique $| \\psi_0 \\rangle = | 0 \\rangle ^{\\otimes n}$. L'observable mesuré est la valeur absolue de l'aimantation $M = |\\frac{1}{28} \\sum_{i=0}^{27} \\langle Z_i \\rangle|$. L'expérience Kicked Ising à l'échelle de l'utilitaire a été réalisée sur les 136 meilleurs qubits de ibm\\_fez; ce benchmark particulier a été réalisé à l'angle de Clifford $(\\theta_x, \\theta_z) = (\\pi, 0)$, auquel le volume actif croît lentement avec la profondeur du circuit, ce qui - avec les fidélités élevées du dispositif - permet une grande précision avec un temps d'exécution court.\n",
        "\n",
        "Les circuits de simulation du hamiltonien trottérisé concernent un modèle d'Ising à champ transversal à des angles fractionnaires : $(\\theta_{zz}, \\theta_x) = (\\pi / 4, \\pi /8)$ et $(\\theta_{zz}, \\theta_x) = (\\pi / 6, \\pi / 8)$ respectivement (voir [Q2B24 Tokyo](https://www.youtube.com/watch?v=tQW6FdLc6zo) ). Le circuit à grande échelle a été exécuté sur les 119 meilleurs qubits de ibm\\_brisbane, tandis que l'expérience à 40 qubits a été exécutée sur la meilleure chaîne disponible. La précision est indiquée pour l'aimantation; des résultats très précis ont également été obtenus pour des observables de poids plus élevé.\n",
        "\n",
        "Le circuit VQE a été développé en collaboration avec des chercheurs du Center for Quantum Technology and Applications du Deutsches Elektronen-Synchrotron (DESY). L'observable cible ici était un hamiltonien composé d'un grand nombre de cordes de Pauli non commutatives, ce qui met en évidence les performances optimisées de QESEM pour les observables à bases multiples. L'atténuation a été appliquée à un ansatz optimisé de manière classique; bien que ces résultats ne soient pas encore publiés, des résultats de même qualité seront obtenus pour différents circuits ayant des propriétés structurelles similaires.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d6fb65de",
      "metadata": {},
      "source": [
        "<span id=\"get-started\" />\n",
        "\n",
        "## Premiers pas\n",
        "\n",
        "Authentifiez-vous à l'aide de votre [clé API IBM Quantum Platform](http://quantum.cloud.ibm.com/) et sélectionnez la fonction QESEM Qiskit comme suit. (Cet extrait de code part du principe que vous avez déjà [enregistré votre compte](/docs/guides/functions-get-started#install-qiskit-functions-catalog-client) dans votre environnement local.)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "95a715d2",
      "metadata": {},
      "outputs": [],
      "source": [
        "import qiskit\n",
        "from qiskit_ibm_catalog import QiskitFunctionsCatalog\n",
        "\n",
        "catalog = QiskitFunctionsCatalog(channel=\"ibm_quantum_platform\")\n",
        "\n",
        "# verify that you have access to the function\n",
        "catalog.list()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "2d78b033",
      "metadata": {},
      "outputs": [],
      "source": [
        "# load the function\n",
        "qesem_function = catalog.load(\"qedma/qesem\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5f0120d8",
      "metadata": {},
      "source": [
        "<span id=\"examples\" />\n",
        "\n",
        "## Exemples\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7d102971",
      "metadata": {},
      "source": [
        "<span id=\"time-estimation-job-example\" />\n",
        "\n",
        "### Exemple de mission d'estimation du temps nécessaire\n",
        "\n",
        "`backend_name`La tâche d'estimation du temps est utile pour estimer le temps de calcul requis par le QPU pour un et un donnés `pub` . `backend_name` peut également être configuré pour n'importe quel moteur de simulation; par exemple, `fake_fez`.\n",
        "\n",
        "QESEM utilise une méthode EM quasi-probabiliste fondée sur la caractérisation. Cette méthode entraîne un surcoût en temps de traitement par le QPU qui évolue approximativement selon la formule suivante :\n",
        "\n",
        "$T_{QPU} = a \\frac{e^{\\alpha IF\\cdot V_a}}{\\epsilon^2} + b$\n",
        "\n",
        "Où $V_a$ représente le volume actif du circuit, $\\epsilon$ la précision visée, et $IF$ l'infidélité des portes natives.\n",
        "\n",
        "Notez que `\"estimate_time_only\": \"empirical\"` cette opération utilise quelques minutes de temps de QPU pour estimer la durée nécessaire à l'exécution de la tâche (si le backend est un périphérique réel; s'il s'agit d'un simulateur, aucun temps de QPU n'est utilisé). Cela prendra généralement environ 5 minutes, mais pas plus de 10 minutes. Si l'infidélité varie considérablement entre la tâche d'estimation empirique du temps et la tâche d'atténuation, le temps de traitement par QPU variera également considérablement.\n",
        "\n",
        "Pour commencer, essayez cet exemple de base qui consiste à estimer le temps nécessaire à la QPU pour exécuter QESEM pour une adresse `pub`:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "d56e1440",
      "metadata": {},
      "outputs": [],
      "source": [
        "backend_name = \"fake_fez\"\n",
        "\n",
        "circ = qiskit.QuantumCircuit(5)\n",
        "circ.cx(0, 1)\n",
        "circ.cx(2, 3)\n",
        "circ.cx(1, 2)\n",
        "circ.cx(3, 4)\n",
        "\n",
        "avg_magnetization = qiskit.quantum_info.SparsePauliOp.from_sparse_list(\n",
        "    [(\"Z\", [q], 1 / 5) for q in range(5)], num_qubits=5\n",
        ")\n",
        "other_observable = qiskit.quantum_info.SparsePauliOp.from_sparse_list(\n",
        "    [(\"ZZ\", [0, 1], 1.0), (\"XZ\", [1, 4], 0.5)], num_qubits=5\n",
        ")\n",
        "\n",
        "time_estimation_job = qesem_function.run(\n",
        "    pubs=[(circ, [avg_magnetization, other_observable])],\n",
        "    options={\n",
        "        \"estimate_time_only\": \"empirical\",\n",
        "    },\n",
        "    backend_name=backend_name,  # example: \"fake_fez\", \"ibm_fez\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "a6eb4bda04796ac5",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2026-05-03T12:04:42.901739Z",
          "start_time": "2026-05-03T12:02:20.288020Z"
        }
      },
      "outputs": [],
      "source": [
        "time_estimate_result = (\n",
        "    time_estimation_job.result()\n",
        ")  # a list of results per pub (circuit)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5ec8053b",
      "metadata": {},
      "source": [
        "L'extrait de code suivant explique comment récupérer différentes métriques d'exécution à partir de la tâche d'estimation de la durée (`estimate_time_only` lorsque est activée) :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 106,
      "id": "77a9dca8efb1a37b",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2026-05-12T11:22:06.848571Z",
          "start_time": "2026-05-12T11:22:06.838844Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The estimated QPU time for mitigation for this PUB is: 300\n",
            "The QPU time that this time estimation job took is (here it is 0 because we used fake_fez): 0\n",
            "Gates fidelity measured during the experiment: {'CZ': 0.9951354916722668, 'ID1Q': 0.9991246627329172}\n",
            "Total shots: 220000\n",
            "Resource usage breakdown: {'RUNNING: MAPPING': {'CPU_TIME': 33.6066133165732, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: OPTIMIZING_FOR_HARDWARE': {'CPU_TIME': 184.53575124032795, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: WAITING_FOR_QPU': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: EXECUTING_QPU': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: POST_PROCESSING': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}}\n"
          ]
        }
      ],
      "source": [
        "pub_result = time_estimate_result[0]\n",
        "\n",
        "print(\n",
        "    f\"The estimated QPU time for mitigation for this PUB is: {pub_result.metadata['time_estimation_sec']}\"\n",
        ")\n",
        "print(\n",
        "    f\"The QPU time that this time estimation job took is (here it is 0 because we used fake_fez): {pub_result.metadata['total_qpu_time']}\"\n",
        ")\n",
        "print(\n",
        "    f\"Gates fidelity measured during the experiment: {pub_result.metadata['gate_fidelities']}\"\n",
        ")\n",
        "print(f\"Total shots: {pub_result.metadata['total_shots']}\")\n",
        "print(f\"Resource usage breakdown: {pub_result.metadata['resource_usage']}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5f68f983189f00a1",
      "metadata": {},
      "source": [
        "Lorsque l'estimation empirique du temps est activée, QESEM exécute un petit nombre de circuits afin de fournir une estimation plus précise du temps de calcul du QPU. Les résultats des mesures d'atténuation relatives à ces circuits sont disponibles dans la `empirical_estimation_mitigation_results` section « sur site » de la mission.\n",
        "\n",
        "Ces résultats étant issus d'un échantillon limité de circuits, leur précision est nettement inférieure à celle des résultats finaux obtenus à l'issue de l'ensemble du processus d'atténuation par QESEM. Toutefois, lorsque le circuit est de petite taille ou que la précision visée est faible, les mesures d'atténuation mises en œuvre lors de l'estimation empirique du temps peuvent s'avérer suffisantes pour atteindre la précision souhaitée, et il n'est alors pas forcément nécessaire de procéder à l'ensemble des mesures d'atténuation.\n",
        "\n",
        "Le `empirical_estimation_mitigation_results` champ est une liste `PrimitiveResult` d'objets par paramètre d'entrée. Si le circuit n'est pas paramétré, la liste comportera un élément.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "7acca648911dacd5",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2026-05-05T13:41:38.131003Z",
          "start_time": "2026-05-05T13:41:38.127666Z"
        }
      },
      "outputs": [],
      "source": [
        "empirical_estimation_mitigation_results = time_estimate_result[0].metadata[\n",
        "    \"empirical_estimation_mitigation_results\"\n",
        "][0]  # a list per parameter"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "60b482803339ce27",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2026-05-05T15:23:58.817671Z",
          "start_time": "2026-05-05T15:23:58.811680Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Partial results for the observables:\n",
            "    Mitigated expectation values: [1.00347302 1.00693905]\n",
            "    Mitigated error bars: [0.00304061 0.00714276]\n",
            "    Number of shots used for mitigation: 180000\n",
            "    Qubit mapping: [[[0, 136], [1, 143], [2, 142], [3, 141], [4, 140]]]\n",
            "    Number of measurement bases: 2\n",
            "\n",
            "Results for each observable:\n",
            "Observable 1: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())\n",
            "    QESEM mitigated value: 1.003473015776871 ± 0.0030406128032204015\n",
            "Observable 2: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())\n",
            "    QESEM mitigated value: 1.0069390542613554 ± 0.0071427606736885925\n"
          ]
        }
      ],
      "source": [
        "print(\"Partial results for the observables:\")\n",
        "\n",
        "print(\n",
        "    f\"    Mitigated expectation values: {empirical_estimation_mitigation_results.data.evs}\"\n",
        ")\n",
        "print(\n",
        "    f\"    Mitigated error bars: {empirical_estimation_mitigation_results.data.stds}\"\n",
        ")\n",
        "print(\n",
        "    f\"    Number of shots used for mitigation: {empirical_estimation_mitigation_results.metadata['mitigation_shots']}\"\n",
        ")\n",
        "transpiled_circ = empirical_estimation_mitigation_results.metadata[\n",
        "    \"transpiled_circ\"\n",
        "]\n",
        "print(f\"    Qubit mapping: {transpiled_circ['qubit_maps']}\")\n",
        "print(\n",
        "    f\"    Number of measurement bases: {transpiled_circ['num_measurement_bases']}\\n\"\n",
        ")\n",
        "\n",
        "# results per obs\n",
        "emp_obs_results = empirical_estimation_mitigation_results.metadata[\"results\"][\n",
        "    0\n",
        "]\n",
        "# print(f\"Results for each observable: {results}\")\n",
        "print(\"Results for each observable:\")\n",
        "\n",
        "for i, (obs_array, result_dict) in enumerate(emp_obs_results):\n",
        "    # obs_array, result_dict = results\n",
        "    print(f\"Observable {i+1}: {obs_array}\")\n",
        "    print(\n",
        "        f\"    QESEM mitigated value: {result_dict['qesem']['value']} \\u00b1 {result_dict['qesem']['error_bar']}\"\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ae10a4c8",
      "metadata": {},
      "source": [
        "<span id=\"qesem-mitigation-job-example\" />\n",
        "\n",
        "### Exemple de tâche d'atténuation dans QESEM\n",
        "\n",
        "L'exemple suivant exécute un travail QESEM :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "e7351d6b",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2026-05-05T13:42:11.391952Z",
          "start_time": "2026-05-05T13:42:01.266109Z"
        }
      },
      "outputs": [],
      "source": [
        "sample_job = qesem_function.run(\n",
        "    pubs=[(circ, [avg_magnetization, other_observable])],\n",
        "    backend_name=backend_name,  # example: \"ibm_fez\"\n",
        "    # options = {\n",
        "    #     \"estimate_time_only\": \"empirical\",\n",
        "    #     \"default_precision\": 0.2,  # Default precision is applied to all pubs that don't have a precision specified, see API reference for more details\n",
        "    #     \"max_execution_time\": 3600,  # You can specify a maximum QPU time in seconds, see API reference for more details\n",
        "    #     \"transpilation_level\": \"standard\",  # \"minimal_with_layout_opt\" for minimal transpilation, see API reference for more details\n",
        "    #     \"parallel_execution\": True,  # True for parallel execution, see API reference for more details\n",
        "    # },\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f7f7fe68",
      "metadata": {},
      "source": [
        "Pour une description détaillée de chaque champ de saisie et de chaque option, consultez la documentation [de référence de l'API QESEM](/docs/api/functions/qedma-qesem).\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dfe99043",
      "metadata": {},
      "source": [
        "Vous pouvez utiliser les API Qiskit Serverless familières pour vérifier l'état de votre charge de travail Qiskit Function ou renvoyer des résultats :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "856fe992",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "3ac6b2df-15b0-4dc0-8f48-cf14bd20a1c8\n",
            "DONE\n"
          ]
        }
      ],
      "source": [
        "# Print the ID so you can use it later, if necessary\n",
        "print(sample_job.job_id)\n",
        "print(sample_job.status())\n",
        "sample_result = sample_job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a9e51542",
      "metadata": {},
      "source": [
        "L'extrait de code suivant montre comment récupérer les résultats des mesures d'atténuation et les indicateurs d'exécution. Ces données contiennent des informations essentielles qui permettent de mieux comprendre l'influence des différents paramètres sur le déroulement de l'analyse QESEM. Cela peut également s'avérer utile lorsque vous rédigez un article à partir de vos travaux de recherche.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 50,
      "id": "117c2e4aa624ed51",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2026-05-12T11:23:45.739919Z",
          "start_time": "2026-05-12T11:23:45.737884Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "PUB 0:\n",
            "  The QPU time that this job took is (here it is 0 because we used fake_fez): 0.0\n",
            "  Gates fidelity measured during the experiment: {'CZ': 0.9953704216147041, 'ID1Q': 0.9991834123567518}\n",
            "  Total shots: 446000\n",
            "  Number of shots used for mitigation: 194000\n",
            "  Resource usage breakdown: {'RUNNING: MAPPING': {'CPU_TIME': 32.52745003718883, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: OPTIMIZING_FOR_HARDWARE': {'CPU_TIME': 257.850521848537, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: WAITING_FOR_QPU': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: EXECUTING_QPU': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: POST_PROCESSING': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}}\n"
          ]
        }
      ],
      "source": [
        "for pub_idx, pub_result in enumerate(\n",
        "    sample_result\n",
        "):  # each element in the list is a result for a different pub, here we sent only one pub\n",
        "    print(f\"\\nPUB {pub_idx}:\")\n",
        "    print(\n",
        "        f\"  The QPU time that this job took is (here it is 0 because we used fake_fez): {pub_result.metadata['total_qpu_time']}\"\n",
        "    )\n",
        "    print(\n",
        "        f\"  Gates fidelity measured during the experiment: {pub_result.metadata['gate_fidelities']}\"\n",
        "    )\n",
        "    print(f\"  Total shots: {pub_result.metadata['total_shots']}\")\n",
        "    print(\n",
        "        f\"  Number of shots used for mitigation: {pub_result.metadata['mitigation_shots']}\"\n",
        "    )\n",
        "    print(\n",
        "        f\"  Resource usage breakdown: {pub_result.metadata['resource_usage']}\"\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3f71cc3a",
      "metadata": {},
      "source": [
        "Dans `metadata[\"results\"]`, les résultats sont d'abord regroupés par instance de circuit, puis par grandeur observable.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 99,
      "id": "a5899795",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Full QESEM mitigation results:\n",
            "\n",
            "PUB 0:\n",
            "  Mitigated expectation values: [1.00648343 1.00636289]\n",
            "  Mitigated error bars: [0.00253812 0.00693586]\n",
            "  Unmitigated expectation values: [0.98031429 0.96357143]\n",
            "  Unmitigated error bars: [0.00124128 0.00578812]\n",
            "  Transpiled circuits:\n",
            "    Circuit 0:\n",
            "      Qubit mapping: [[[0, 140], [1, 141], [2, 142], [3, 143], [4, 136]]]\n",
            "      Measurement bases: 2\n",
            "  Results for each observable:\n",
            "    Circuit 0:\n",
            "      Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())\n",
            "        QESEM mitigated value: 1.0064834305181962 ± 0.002538119914534849\n",
            "        Unmitigated value: 0.9803142857142859 ± 0.0012412835813609938\n",
            "      Observable 1: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())\n",
            "        QESEM mitigated value: 1.0063628870614818 ± 0.006935859820870656\n",
            "        Unmitigated value: 0.9635714285714285 ± 0.005788121870526659\n"
          ]
        }
      ],
      "source": [
        "print(\"Full QESEM mitigation results:\")\n",
        "\n",
        "for pub_idx, pub_result in enumerate(sample_result):\n",
        "    print(f\"\\nPUB {pub_idx}:\")\n",
        "\n",
        "    print(f\"  Mitigated expectation values: {pub_result.data.evs}\")\n",
        "    print(f\"  Mitigated error bars: {pub_result.data.stds}\")\n",
        "    noisy_results = pub_result.metadata.get(\"noisy_results\")\n",
        "    print(f\"  Unmitigated expectation values: {noisy_results.evs}\")\n",
        "    print(f\"  Unmitigated error bars: {noisy_results.stds}\")\n",
        "\n",
        "    print(\"  Transpiled circuits:\")\n",
        "    for circ_idx, transpiled_circ in enumerate(\n",
        "        pub_result.metadata[\"transpiled_circs\"]\n",
        "    ):\n",
        "        print(f\"    Circuit {circ_idx}:\")\n",
        "        # print(f\"      Circuit: \\n {transpiled_circ['circuit']}\") # not printing it because it's long but you can see the transpiled circuit itself\n",
        "        print(f\"      Qubit mapping: {transpiled_circ['qubit_maps']}\")\n",
        "        print(\n",
        "            f\"      Measurement bases: {transpiled_circ['num_measurement_bases']}\"\n",
        "        )\n",
        "\n",
        "    print(\"  Results for each observable:\")\n",
        "    for circ_idx, circ_results in enumerate(pub_result.metadata[\"results\"]):\n",
        "        print(f\"    Circuit {circ_idx}:\")\n",
        "        for obs_idx, (obs_array, result_dict) in enumerate(circ_results):\n",
        "            print(f\"      Observable {obs_idx}: {obs_array}\")\n",
        "            print(\n",
        "                f\"        QESEM mitigated value: {result_dict['qesem']['value']} ± {result_dict['qesem']['error_bar']}\"\n",
        "            )\n",
        "            print(\n",
        "                f\"        Unmitigated value: {result_dict['unmitigated']['value']} ± {result_dict['unmitigated']['error_bar']}\"\n",
        "            )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "345524a3",
      "metadata": {},
      "source": [
        "**Répartition des principaux résultats :**\n",
        "\n",
        "* `mitigated`: la valeur attendue du QESEM après atténuation complète.\n",
        "* `unmitigated`: le résultat brut du bruit physique, sans correction des erreurs.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "65a2e503",
      "metadata": {},
      "source": [
        "<span id=\"qesem-heuristic-extrapolation-results\" />\n",
        "\n",
        "#### Résultats de l'extrapolation heuristique QESEM\n",
        "\n",
        "Dans une session QESEM standard avec un seul `precision` flotteur, les résultats comprennent également des points de mise à l'échelle du bruit disponibles automatiquement, qui sont utilisés pour l'heuristique QESEM. Ces points sont calculés sans recourir à des ressources QPU supplémentaires.\n",
        "\n",
        "L'échelle `1.0` représente le niveau de bruit physique de l'appareil avec atténuation de la lecture (REM), tandis que l'échelle `2.0` correspond au point complémentaire amplifié par le bruit, également avec REM. Ces points servent à obtenir le `qesem_heuristic` résultat.\n",
        "\n",
        "* `qesem_heuristic`: une estimation de type ZNE calculée à partir des données disponibles, pondérées en fonction du bruit. Actuellement, cette méthode utilise une extrapolation exponentielle.\n",
        "* `noise_scaling.results_with_REM`: valeurs attendues à différentes échelles de bruit, toutes avec atténuation de la lecture (REM).\n",
        "\n",
        "Un détail subtil mais important réside dans le fait que le résultat de la mise à l'échelle `1.0` n'est pas le même que le `unmitigated` résultat. Ces deux valeurs correspondent au niveau de bruit physique de l'appareil, mais la valeur de l'échelle `1.0` tient compte de l'atténuation liée à la lecture, contrairement `unmitigated` à.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 101,
      "id": "21afd3d2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "QESEM heuristic results:\n",
            "\n",
            "PUB 0:\n",
            "  Circuit 0:\n",
            "    Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())\n",
            "      QESEM heuristic:\n",
            "        Value: 1.0008161638888535 ± 0.0038859458884403964\n",
            "        Extrapolation: exponential\n",
            "        Scale factors: [1.0, 2.0]\n",
            "      Noise scaling results:\n",
            "        Scaling method: QESEM\n",
            "        Results with Readout mitigation (REM):\n",
            "          Scale factor 1.0: 0.9918395459270772 ± 0.0012565417579355634\n",
            "          Scale factor 2.0: 0.982943441922748 ± 0.0028919278067695018\n",
            "    Observable 1: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())\n",
            "      QESEM heuristic:\n",
            "        Value: 0.9960853148925298 ± 0.013811635038961175\n",
            "        Extrapolation: exponential\n",
            "        Scale factors: [1.0, 2.0]\n",
            "      Noise scaling results:\n",
            "        Scaling method: QESEM\n",
            "        Results with Readout mitigation (REM):\n",
            "          Scale factor 1.0: 0.9902860583785115 ± 0.005921236914723409\n",
            "          Scale factor 2.0: 0.984520565414274 ± 0.006909522262347639\n"
          ]
        }
      ],
      "source": [
        "print(\"QESEM heuristic results:\")\n",
        "\n",
        "for pub_idx, pub_result in enumerate(sample_result):\n",
        "    print(f\"\\nPUB {pub_idx}:\")\n",
        "    for circ_idx, circ_results in enumerate(pub_result.metadata[\"results\"]):\n",
        "        print(f\"  Circuit {circ_idx}:\")\n",
        "        for obs_idx, (obs_array, result_dict) in enumerate(circ_results):\n",
        "            print(f\"    Observable {obs_idx}: {obs_array}\")\n",
        "            qesem_heuristic = result_dict[\"qesem_heuristic\"][0]\n",
        "            print(\"      QESEM heuristic:\")\n",
        "            print(\n",
        "                f\"        Value: {qesem_heuristic['value']} ± {qesem_heuristic['error_bar']}\"\n",
        "            )\n",
        "            print(\n",
        "                f\"        Extrapolation: {qesem_heuristic['extrapolation']}\"\n",
        "            )\n",
        "            print(\n",
        "                f\"        Scale factors: {qesem_heuristic['scale_factors']}\"\n",
        "            )\n",
        "            noise_scaling = result_dict[\"noise_scaling\"]\n",
        "            print(\"      Noise scaling results:\")\n",
        "            print(\n",
        "                f\"        Scaling method: {noise_scaling['scaling_method']}\"\n",
        "            )\n",
        "            print(\"        Results with Readout mitigation (REM):\")\n",
        "            for rem_result in sorted(\n",
        "                (\n",
        "                    item\n",
        "                    for item in noise_scaling[\"results_with_REM\"]\n",
        "                    if item[\"scale\"] != 0.0\n",
        "                ),\n",
        "                key=lambda item: item[\"scale\"],\n",
        "            ):\n",
        "                print(\n",
        "                    f\"          Scale factor {rem_result['scale']}: {rem_result['value']} ± {rem_result['error_bar']}\"\n",
        "                )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "899d229a",
      "metadata": {},
      "source": [
        "<Admonition type=\"note\">\n",
        "  Les exemples suivants se concentrent sur les données d'entrée et les résultats spécifiques à certaines fonctionnalités; ils n'affichent donc pas à chaque fois l'intégralité des métriques d'exécution. Les métadonnées de premier niveau présentées précédemment, telles que <code>temps\\_total\\_qpu</code>, <code>gate\\_fidelities</code>, <code>nombre\\_de\\_tirs</code>, <code>mesures\\_d'atténuation</code> et <code>utilisation\\_des\\_ressources</code>, sont également disponibles pour ces missions.\n",
        "\n",
        "  Par souci de concision, certaines variables des exemples précédents, notamment le backend, les observables et les paramètres du circuit de base, sont réutilisées ci-dessous.\n",
        "</Admonition>\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  Tous les exemples suivants peuvent également être exécutés avec une estimation empirique du temps. Pour l'activer, passez « <code>\"estimate\\_time\\_only\" : \"empirique\"</code> » dans les options de la fonction.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "079cb5be",
      "metadata": {},
      "source": [
        "<span id=\"parameterized-circuit-example\" />\n",
        "\n",
        "### Exemple de circuit paramétré\n",
        "\n",
        "De nombreux algorithmes évaluent le même circuit pour plusieurs valeurs de paramètres. L'envoi du circuit paramétré sous la forme d'une seule tâche QESEM permet à QESEM de réutiliser les résultats de caractérisation et d'étalonnage pour toutes les instances du circuit, ce qui peut réduire la charge en temps de calcul par rapport à l'exécution de tâches distinctes.\n",
        "\n",
        "Pour soumettre un circuit paramétré, il faut utiliser le `\"minimal_with_layout_opt\"` niveau de transpilation.\n",
        "Les circuits soumis à ce niveau doivent déjà être exprimés à l'aide des portes de base du backend, en fonction de ce dernier. À ce niveau, QESEM conserve la structure soumise aussi proche que possible du circuit d'entrée, respecte les barrières lors de la stratification (regroupement des opérations en couches de portes parallèles à deux qubits) et gère toujours automatiquement le mappage matériel vers des qubits haute fidélité ainsi que la connectivité des dispositifs.\n",
        "\n",
        "Concrètement, cela signifie que vous devez transcompiler les circuits en portes de base du backend cible avant de les soumettre. Vous trouverez ci-dessous un exemple simple de transpilation « basis-gate ».\n",
        "\n",
        "Actuellement, QESEM ne prend en charge qu'une seule grandeur observable par jeu de paramètres. Les deux lignes de paramètres ci-dessous sont associées aux deux observables : la première ligne est mesurée avec `avg_magnetization`, et la deuxième ligne est mesurée avec `other_observable`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "704f8aa5",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Transpile to the backend basis gates only. With minimal_with_layout_opt, QESEM handles hardware mapping/connectivity and observable layout internally.\n",
        "from qiskit_ibm_runtime.fake_provider import FakeFez\n",
        "\n",
        "backend = FakeFez()\n",
        "basis = backend.operation_names\n",
        "print(basis)\n",
        "\n",
        "param0 = qiskit.circuit.Parameter(\"param0\")\n",
        "param1 = qiskit.circuit.Parameter(\"param1\")\n",
        "parametrized_circ = qiskit.QuantumCircuit(5)\n",
        "parametrized_circ.rx(param0, 0)\n",
        "parametrized_circ.rx(param1, 1)\n",
        "parametrized_circ.cx(0, 1)\n",
        "parametrized_circ.cx(2, 3)\n",
        "parametrized_circ.cx(1, 2)\n",
        "parametrized_circ.cx(3, 4)\n",
        "\n",
        "parametrized_circ = qiskit.transpile(\n",
        "    parametrized_circ, basis_gates=basis, optimization_level=1\n",
        ")\n",
        "parametrized_parameter_values = [[0.5, 0.1], [0.0, 0.6]]\n",
        "parametrized_observables = [avg_magnetization, other_observable]\n",
        "\n",
        "parametrized_job = qesem_function.run(\n",
        "    pubs=[\n",
        "        (\n",
        "            parametrized_circ,\n",
        "            parametrized_observables,\n",
        "            parametrized_parameter_values,\n",
        "            0.1,\n",
        "        )\n",
        "    ],\n",
        "    backend_name=backend_name,\n",
        "    options={\n",
        "        \"max_execution_time\": 300,\n",
        "        \"transpilation_level\": \"minimal_with_layout_opt\",\n",
        "    },\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 72,
      "id": "85a452fc",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "d1b0e29b-196c-4896-aec6-44a268ebd874\n",
            "DONE\n"
          ]
        }
      ],
      "source": [
        "print(parametrized_job.job_id)\n",
        "print(parametrized_job.status())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 73,
      "id": "244cd3b2",
      "metadata": {},
      "outputs": [],
      "source": [
        "parametrized_result = parametrized_job.result()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 77,
      "id": "03399db5",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Parameterized circuit QESEM results:\n",
            "\n",
            "PUB 0:\n",
            "  Mitigated expectation values: [0.92392021 0.82517653]\n",
            "  Mitigated error bars: [0.00565281 0.00616016]\n",
            "  Unmitigated expectation values: [0.9028     0.78771429]\n",
            "  Unmitigated error bars: [0.00335142 0.00925413]\n",
            "  Results for each parameter value:\n",
            "    Parameter set 0: [0.5, 0.1]\n",
            "      Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())\n",
            "        QESEM mitigated value: 0.923920210615709 ± 0.005652811570890183\n",
            "        Unmitigated value: 0.9028 ± 0.0033514176105045447\n",
            "    Parameter set 1: [0.0, 0.6]\n",
            "      Observable 0: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())\n",
            "        QESEM mitigated value: 0.8251765289285893 ± 0.006160161743353999\n",
            "        Unmitigated value: 0.7877142857142858 ± 0.009254130564027902\n"
          ]
        }
      ],
      "source": [
        "print(\"Parameterized circuit QESEM results:\")\n",
        "\n",
        "for pub_idx, pub_result in enumerate(parametrized_result):\n",
        "    print(f\"\\nPUB {pub_idx}:\")\n",
        "    print(f\"  Mitigated expectation values: {pub_result.data.evs}\")\n",
        "    print(f\"  Mitigated error bars: {pub_result.data.stds}\")\n",
        "    noisy_results = pub_result.metadata[\"noisy_results\"]\n",
        "    print(f\"  Unmitigated expectation values: {noisy_results.evs}\")\n",
        "    print(f\"  Unmitigated error bars: {noisy_results.stds}\")\n",
        "    print(\"  Results for each parameter value:\")\n",
        "    for param_idx, param_results in enumerate(pub_result.metadata[\"results\"]):\n",
        "        print(\n",
        "            f\"    Parameter set {param_idx}: {parametrized_parameter_values[param_idx]}\"\n",
        "        )\n",
        "        for obs_idx, (obs_array, result_dict) in enumerate(param_results):\n",
        "            print(f\"      Observable {obs_idx}: {obs_array}\")\n",
        "            print(\n",
        "                f\"        QESEM mitigated value: {result_dict['qesem']['value']} ± {result_dict['qesem']['error_bar']}\"\n",
        "            )\n",
        "            print(\n",
        "                f\"        Unmitigated value: {result_dict['unmitigated']['value']} ± {result_dict['unmitigated']['error_bar']}\"\n",
        "            )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d6d1b6c2",
      "metadata": {},
      "source": [
        "<span id=\"multi-pub-example\" />\n",
        "\n",
        "### Exemple « Multi-pub »\n",
        "\n",
        "L'exécution multi-pub est utile lorsque vous souhaitez exécuter plusieurs circuits liés les uns aux autres au sein d'un même travail QESEM. Tout comme l'exécution paramétrée, cela permet de réduire la charge de travail, car QESEM peut réutiliser les résultats de caractérisation et d'étalonnage d'une instance de circuit à l'autre, au lieu de les répéter dans des tâches distinctes.\n",
        "\n",
        "Cela s'avère particulièrement utile pour les circuits dotés d'une structure à couches partagées, comme les charges de travail **de type Trotter**, dans lesquelles différents circuits réutilisent les mêmes couches uniques. Dans ce cas, les exécuter simultanément peut permettre de réduire les coûts de caractérisation par rapport à des sessions QESEM menées séparément.\n",
        "\n",
        "Les missions impliquant plusieurs établissements nécessitent `\"transpilation_level\": \"minimal_with_layout_opt\"`. Comme dans l'exemple paramétré, les circuits doivent être transpilés en portes de base du backend cible avant d'être soumis. QESEM gère ensuite en interne la connectivité des dispositifs, leur disposition et leur mise en correspondance avec des qubits haute fidélité.\n",
        "\n",
        "Chaque `PUB` ci-dessous contient un circuit et les deux mêmes grandeurs observables utilisées précédemment dans le notebook; ainsi, la valeur renvoyée `PrimitiveResult` contient une `PubResult` \\`\\` par circuit d'entrée.\n",
        "\n",
        "L'exemple ci-dessous utilise deux circuits de Trotter simples présentant le même motif de couche : `circ_a` comporte une couche de Trotter, tandis que `circ_b` répète deux fois le même motif de couche. Cela permet de rendre explicite la structure partagée.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "8cc663fc",
      "metadata": {},
      "outputs": [],
      "source": [
        "def make_trotter_circuit(num_qubits, num_layers, zz_angle=0.2, x_angle=0.1):\n",
        "    trotter_circ = qiskit.QuantumCircuit(num_qubits)\n",
        "    for _ in range(num_layers):\n",
        "        for q in range(num_qubits):\n",
        "            trotter_circ.rx(x_angle, q)\n",
        "        trotter_circ.barrier()\n",
        "        for q in range(0, num_qubits - 1, 2):\n",
        "            trotter_circ.rzz(zz_angle, q, q + 1)\n",
        "        trotter_circ.barrier()\n",
        "        for q in range(1, num_qubits - 1, 2):\n",
        "            trotter_circ.rzz(zz_angle, q, q + 1)\n",
        "        trotter_circ.barrier()\n",
        "    return trotter_circ\n",
        "\n",
        "\n",
        "circ_a = make_trotter_circuit(num_qubits=5, num_layers=1)\n",
        "circ_b = make_trotter_circuit(num_qubits=5, num_layers=2)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "371c4893",
      "metadata": {},
      "outputs": [],
      "source": [
        "multi_pubs = [\n",
        "    (\n",
        "        qiskit.transpile(qci, basis_gates=basis, optimization_level=1),\n",
        "        [avg_magnetization, other_observable],\n",
        "    )\n",
        "    for qci in [circ_a, circ_b]\n",
        "]\n",
        "\n",
        "multi_circ_job = qesem_function.run(\n",
        "    pubs=multi_pubs,\n",
        "    backend_name=backend_name,\n",
        "    options={\n",
        "        \"max_execution_time\": 300,\n",
        "        \"transpilation_level\": \"minimal_with_layout_opt\",\n",
        "        \"default_precision\": 0.1,\n",
        "    },\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 91,
      "id": "92e45737",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "e34565b8-7262-4133-a120-de42ce624a99\n",
            "DONE\n"
          ]
        }
      ],
      "source": [
        "print(multi_circ_job.job_id)\n",
        "print(multi_circ_job.status())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 92,
      "id": "23c61008",
      "metadata": {},
      "outputs": [],
      "source": [
        "multi_circ_result = multi_circ_job.result()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 105,
      "id": "1ae6f8c3",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Multi-pub QESEM results:\n",
            "\n",
            "PUB 0:\n",
            "  Mitigated expectation values: [0.99502406 1.02209332]\n",
            "  Mitigated error bars: [0.00483819 0.00707488]\n",
            "  Unmitigated expectation values: [0.96934286 0.97271429]\n",
            "  Unmitigated error bars: [0.00124855 0.00617294]\n",
            "  Results for each observable:\n",
            "    Circuit 0:\n",
            "      Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())\n",
            "        QESEM mitigated value: 0.9950240647925642 ± 0.004838188086259301\n",
            "        Unmitigated value: 0.9693428571428573 ± 0.0012485470362492692\n",
            "      Observable 1: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())\n",
            "        QESEM mitigated value: 1.0220933230604674 ± 0.007074884384355636\n",
            "        Unmitigated value: 0.9727142857142859 ± 0.006172939375512439\n",
            "\n",
            "PUB 1:\n",
            "  Mitigated expectation values: [0.98850017 1.02555188]\n",
            "  Mitigated error bars: [0.0077912  0.01672652]\n",
            "  Unmitigated expectation values: [0.93682857 0.95371429]\n",
            "  Unmitigated error bars: [0.00156245 0.00665735]\n",
            "  Results for each observable:\n",
            "    Circuit 0:\n",
            "      Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())\n",
            "        QESEM mitigated value: 0.988500171577252 ± 0.007791203181151346\n",
            "        Unmitigated value: 0.9368285714285716 ± 0.001562451883089579\n",
            "      Observable 1: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())\n",
            "        QESEM mitigated value: 1.02555188098689 ± 0.016726524388086233\n",
            "        Unmitigated value: 0.9537142857142858 ± 0.006657345655544263\n"
          ]
        }
      ],
      "source": [
        "print(\"Multi-pub QESEM results:\")\n",
        "\n",
        "for pub_idx, pub_result in enumerate(multi_circ_result):\n",
        "    print(f\"\\nPUB {pub_idx}:\")\n",
        "    print(f\"  Mitigated expectation values: {pub_result.data.evs}\")\n",
        "    print(f\"  Mitigated error bars: {pub_result.data.stds}\")\n",
        "    noisy_results = pub_result.metadata[\"noisy_results\"]\n",
        "    print(f\"  Unmitigated expectation values: {noisy_results.evs}\")\n",
        "    print(f\"  Unmitigated error bars: {noisy_results.stds}\")\n",
        "    print(\"  Results for each observable:\")\n",
        "    for circ_idx, circ_results in enumerate(pub_result.metadata[\"results\"]):\n",
        "        print(f\"    Circuit {circ_idx}:\")\n",
        "        for obs_idx, (obs_array, result_dict) in enumerate(circ_results):\n",
        "            print(f\"      Observable {obs_idx}: {obs_array}\")\n",
        "            print(\n",
        "                f\"        QESEM mitigated value: {result_dict['qesem']['value']} ± {result_dict['qesem']['error_bar']}\"\n",
        "            )\n",
        "            print(\n",
        "                f\"        Unmitigated value: {result_dict['unmitigated']['value']} ± {result_dict['unmitigated']['error_bar']}\"\n",
        "            )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8f28d826",
      "metadata": {},
      "source": [
        "<span id=\"quasi-probabilistic-error-tuning-qet-example\" />\n",
        "\n",
        "### Exemple d'ajustement quasi-probabiliste des erreurs (QET)\n",
        "\n",
        "Le réglage quasi-probabiliste des erreurs (QET) nécessite des valeurs d'espérance pour certains facteurs d'échelle de bruit. Cela s'avère utile pour les études de mise à l'échelle personnalisée du bruit et les processus d'extrapolation sans bruit. Le paramètre « Scale » `1.0` correspond au niveau de bruit physique; les valeurs comprises entre `0.0` et `1.0` réduisent partiellement le bruit, tandis que les valeurs supérieures à `1.0` l'amplifient.\n",
        "\n",
        "Pour utiliser QET avec la fonction Qiskit, transmettez un dictionnaire en tant que paramètre « precision » de la fonction « PUB ». Le dictionnaire associe chaque échelle de bruit demandée à sa précision cible. Les résultats du facteur d'échelle renvoyés sont stockés dans `noise_scaling.results_with_REM` et intègrent une correction de la lecture. La valeur à `1.0` l'échelle n'est donc pas identique à la valeur non atténuée, car `1.0` la première tient compte de l'atténuation lors de la lecture, `unmitigated` contrairement à la seconde.\n",
        "\n",
        "Lorsqu'une échelle est demandée, QESEM renvoie également l'échelle complémentaire autour de `1.0` sans consommation supplémentaire de QPU. Par exemple, la requête `0.5` peut également renvoyer `1.5`, et la requête `1.3` peut également renvoyer `0.7`. La précision de l'échelle complémentaire n'est pas garantie.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 88,
      "id": "723cdf95",
      "metadata": {},
      "outputs": [],
      "source": [
        "noise_scale_precision = {0.5: 0.15, 1.3: 0.2}\n",
        "\n",
        "qet_job = qesem_function.run(\n",
        "    pubs=[\n",
        "        (\n",
        "            circ,\n",
        "            [avg_magnetization, other_observable],\n",
        "            None,\n",
        "            noise_scale_precision,\n",
        "        )\n",
        "    ],\n",
        "    backend_name=backend_name,\n",
        "    options={\"max_execution_time\": 300},\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 95,
      "id": "d68a015c",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "8195fa58-f037-4651-8715-36ce1cdc5521\n",
            "DONE\n"
          ]
        }
      ],
      "source": [
        "print(qet_job.job_id)\n",
        "print(qet_job.status())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 96,
      "id": "927d8543",
      "metadata": {},
      "outputs": [],
      "source": [
        "qet_result = qet_job.result()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 104,
      "id": "1c9ba079",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "QET noise-scaling results:\n",
            "\n",
            "PUB 0:\n",
            "  Unmitigated expectation values: [0.97822857 0.96171429]\n",
            "  Unmitigated error bars: [0.00123812 0.00672958]\n",
            "  Results for each observable:\n",
            "    Circuit 0:\n",
            "      Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())\n",
            "        Scaling method: QESEM\n",
            "        Results with Readout mitigation (REM):\n",
            "          Scale factor 0.5: 0.9938730340199383 ± 0.0032116907357568275\n",
            "          Scale factor 0.7: 0.9963976191853445 ± 0.00036300258869586616\n",
            "          Scale factor 1.0: 0.9898115079506586 ± 0.0012525947426560995\n",
            "          Scale factor 1.3: 0.9864667065580341 ± 0.002633221613518526\n",
            "          Scale factor 1.5: 0.9838755527197551 ± 0.002948417797996015\n",
            "      Observable 1: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())\n",
            "        Scaling method: QESEM\n",
            "        Results with Readout mitigation (REM):\n",
            "          Scale factor 0.5: 1.0006538544450332 ± 0.002121742014777343\n",
            "          Scale factor 0.7: 1.0004159801523036 ± 0.0021671375357823794\n",
            "          Scale factor 1.0: 0.9898058846339917 ± 0.00690183710903159\n",
            "          Scale factor 1.3: 0.9948946719997267 ± 0.002146532859610311\n",
            "          Scale factor 1.5: 0.9927220368192772 ± 0.0020875057190323882\n"
          ]
        }
      ],
      "source": [
        "print(\"QET noise-scaling results:\")\n",
        "\n",
        "for pub_idx, pub_result in enumerate(qet_result):\n",
        "    print(f\"\\nPUB {pub_idx}:\")\n",
        "    noisy_results = pub_result.metadata[\"noisy_results\"]\n",
        "    print(f\"  Unmitigated expectation values: {noisy_results.evs}\")\n",
        "    print(f\"  Unmitigated error bars: {noisy_results.stds}\")\n",
        "    print(\"  Results for each observable:\")\n",
        "    for circ_idx, circ_results in enumerate(pub_result.metadata[\"results\"]):\n",
        "        print(f\"    Circuit {circ_idx}:\")\n",
        "        for obs_idx, (obs_array, result_dict) in enumerate(circ_results):\n",
        "            print(f\"      Observable {obs_idx}: {obs_array}\")\n",
        "            noise_scaling = result_dict[\"noise_scaling\"]\n",
        "            print(\n",
        "                f\"        Scaling method: {noise_scaling['scaling_method']}\"\n",
        "            )\n",
        "            print(\"        Results with Readout mitigation (REM):\")\n",
        "            for rem_result in sorted(\n",
        "                (\n",
        "                    item\n",
        "                    for item in noise_scaling[\"results_with_REM\"]\n",
        "                    if item[\"scale\"] != 0.0\n",
        "                ),\n",
        "                key=lambda item: item[\"scale\"],\n",
        "            ):\n",
        "                print(\n",
        "                    f\"          Scale factor {rem_result['scale']}: {rem_result['value']} ± {rem_result['error_bar']}\"\n",
        "                )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "35aed54a",
      "metadata": {},
      "source": [
        "<span id=\"fetch-error-messages\" />\n",
        "\n",
        "## Récupérer les messages d'erreur\n",
        "\n",
        "Si l'état de votre charge de travail est « ERROR », utilisez `job.result()` pour récupérer le message d'erreur comme suit :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "d95a3f30",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(2,), dtype=float64>), stds=np.ndarray(<shape=(2,), dtype=float64>), shape=(2,)), metadata={'gate_fidelities': {'CZ': 0.9979444718552628, 'ID1Q': 0.9991994239814883}, 'total_shots': 498600, 'mitigation_shots': 223400, 'transpiled_circs': [{'circuit': 'OPENQASM 3.0;\\ninclude \"stdgates.inc\";\\nbit[76] c0;\\nqubit[76] q0;\\nrx(0) q0[54];\\nrx(0) q0[59];\\nrx(0) q0[75];\\nrz(pi/2) q0[54];\\nrz(pi/2) q0[59];\\nrz(pi/2) q0[75];\\nrx(pi/2) q0[54];\\nr... (truncated 3771 characters)\n"
          ]
        }
      ],
      "source": [
        "# Get the result and truncate for readability\n",
        "result = sample_job.result()\n",
        "result_str = str(result)\n",
        "max_length = 500  # Adjust this value as necessary\n",
        "\n",
        "if len(result_str) > max_length:\n",
        "    truncated = (\n",
        "        result_str[:max_length]\n",
        "        + f\"... (truncated {len(result_str) - max_length} characters)\"\n",
        "    )\n",
        "else:\n",
        "    truncated = result_str\n",
        "\n",
        "print(truncated)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e9ec2e67",
      "metadata": {},
      "source": [
        "<span id=\"get-support\" />\n",
        "\n",
        "## Obtenir de l'aide\n",
        "\n",
        "L'équipe d'assistance de Qedma est là pour vous aider! Si vous rencontrez des problèmes ou si vous avez des questions sur l'utilisation de la fonction Qiskit de QESEM, n'hésitez pas à nous contacter. Notre personnel d'assistance, compétent et amical, est prêt à vous aider en cas de problèmes techniques ou de questions.\n",
        "\n",
        "Vous pouvez nous envoyer un courriel à [support@qedma.com](mailto:support@qedma.com) pour obtenir de l'aide. Veuillez fournir le plus de détails possible sur le problème que vous rencontrez afin de nous aider à fournir une réponse rapide et précise. Vous pouvez également contacter votre représentant Qedma POC par e-mail ou par téléphone.\n",
        "\n",
        "Pour nous permettre de vous aider plus efficacement, veuillez fournir les informations suivantes lorsque vous nous contactez :\n",
        "\n",
        "* Une description détaillée du problème\n",
        "* ID du travail\n",
        "* Tout message ou code d'erreur pertinent\n",
        "\n",
        "Nous nous engageons à vous fournir une assistance rapide et efficace afin de vous garantir la meilleure expérience possible avec notre fonction Qiskit.\n",
        "\n",
        "Nous cherchons constamment à améliorer notre produit et nous apprécions vos suggestions! Si vous avez des idées pour améliorer nos services ou des fonctionnalités que vous aimeriez voir apparaître, n'hésitez pas à nous envoyer vos suggestions à l'adresse [support@qedma.com](mailto:support@qedma.com).\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5a6a25c8",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Etapes suivantes\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recommandations\">\n",
        "  * [Demander l'accès à Qedma QESEM](/functions?id=qedma-qesem).\n",
        "  * Consultez [la documentation de l'API](/docs/api/functions/qedma-qesem) relative à cette fonction Qiskit.\n",
        "  * Essayez le tutoriel «[ Simuler un modèle d' 2D -Ising à champ incliné avec la fonction QESEM](/docs/tutorials/qedma-2d-ising-with-qesem) ».\n",
        "  * Critique [Aharonov, D., et al. (2025). Atténuation fiable et très précise des erreurs pour les circuits quantiques à l'échelle industrielle. arXiv prépublication arXiv:2508.10997](https://arxiv.org/pdf/2508.10997).\n",
        "  * Critique [Aharonov, D., et al. (2025). Atténuation des erreurs logiques tenant compte des syndromes. arXiv prépublication arXiv:2508.10997](https://arxiv.org/pdf/2508.10997).\n",
        "  * Critique [Aharonov, D., et al. (2025). De l'importance de l'atténuation des erreurs dans le calcul quantique. arXiv prépublication arXiv:2512.23810](https://arxiv.org/abs/2512.23810).\n",
        "  * Critique [Bauman, N. P., et al. (2025). Théorie du repliement des clusters couplés dans les simulations de systèmes chimiques sur du matériel quantique. arXiv prépublication arXiv:2507.01199](https://arxiv.org/pdf/2507.01199).\n",
        "  * Critique de [Goldack, M., et al. (2026). Calcul des propriétés statistiques des champs de vitesse sur le matériel quantique actuel. arXiv prépublication arXiv:2601.10166](https://arxiv.org/pdf/2601.10166).\n",
        "  * Critique de [Sakuma, R., et al. (2026). Analyse de la symétrie des groupes ponctuels des fonctions d'onde à plusieurs électrons sur un ordinateur quantique arXiv prépublication arXiv:2605.24824](https://arxiv.org/abs/2605.24824).\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
}