{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "fad91a68",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Atténuation des erreurs\"\n",
        "description: \"Tout au long de cette leçon, nous examinerons le bruit et comment il peut être atténué sur les ordinateurs quantiques.\"\n",
        "---\n",
        "\n",
        "<span id=\"quantum-noise-and-error-mitigation\" />\n",
        "\n",
        "# Bruit quantique et atténuation des erreurs\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  Toshinari Itoko (28 juin 2024)\n",
        "\n",
        "  [Télécharger le pdf](https://ibm.ent.box.com/public/static/a0zgies7bh91hm2lwev9o0bfeybxc6n6.zip) de la conférence originale. Notez que certains extraits de code peuvent devenir obsolètes car il s'agit d'images statiques.\n",
        "\n",
        "  *Le temps approximatif d'exécution de cette expérience par la QPU est de 1 m 40 s.*\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e936adb0-bc31-41a8-b988-02ce7e68b902",
      "metadata": {},
      "source": [
        "<span id=\"1-introduction\" />\n",
        "\n",
        "## 1. Introduction\n",
        "\n",
        "Tout au long de cette leçon, nous examinerons le bruit et la manière dont il peut être atténué sur les ordinateurs quantiques. Nous commencerons par examiner les effets du bruit à l'aide d'un simulateur qui peut simuler le bruit de plusieurs façons, notamment en utilisant des profils de bruit provenant de véritables ordinateurs quantiques. Nous passerons ensuite à de véritables ordinateurs quantiques, dans lesquels le bruit est inhérent. Nous examinerons les effets de l'atténuation des erreurs, y compris les combinaisons d'éléments tels que l'extrapolation à bruit nul (ZNE) et le tourbillonnement de portes.\n",
        "\n",
        "Nous commencerons par charger quelques paquets.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "38cf024b",
      "metadata": {},
      "outputs": [],
      "source": [
        "# !pip install qiskit qiskit_aer qiskit_ibm_runtime\n",
        "# !pip install jupyter\n",
        "# !pip install matplotlib pylatexenc"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "897008ea",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'2.0.2'"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit\n",
        "\n",
        "qiskit.__version__"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "486b4d35",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'0.17.1'"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit_aer\n",
        "\n",
        "qiskit_aer.__version__"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "994c44e5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'0.40.1'"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit_ibm_runtime\n",
        "\n",
        "qiskit_ibm_runtime.__version__"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ee48a826-fda3-4fb4-b50b-d69c38eb887f",
      "metadata": {
        "editable": true,
        "slideshow": {
          "slide_type": "slide"
        },
        "tags": []
      },
      "source": [
        "<span id=\"2-noisy-simulation-without-error-mitigation\" />\n",
        "\n",
        "## 2. Simulation bruyante sans atténuation des erreurs\n",
        "\n",
        "Qiskit Aer est un simulateur classique pour l'informatique quantique. Il peut simuler non seulement l'exécution idéale mais aussi l'exécution bruyante de circuits quantiques. Ce carnet montre comment exécuter une simulation bruyante à l'aide de Qiskit Aer :\n",
        "\n",
        "1. Construire un modèle de bruit\n",
        "2. Construire un échantillonneur bruyant (simulateur) avec le modèle de bruit\n",
        "3. Exécuter un circuit quantique sur l'échantillonneur bruyant\n",
        "\n",
        "```\n",
        "noise_model = NoiseModel()\n",
        "...\n",
        "noisy_sampler = Sampler(options={\"backend_options\": {\"noise_model\": noise_model}})\n",
        "job = noisy_sampler.run([circuit])\n",
        "```\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d1490ab8",
      "metadata": {},
      "source": [
        "<span id=\"21-build-a-test-circuit\" />\n",
        "\n",
        "### 2.1 Construire un circuit de test\n",
        "\n",
        "Nous considérons des circuits jouets à 1 qubit qui répètent simplement X portes `d` fois (`d`=0... 100) et mesurer l'observable `Z` .\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "b4863c66",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/b4863c66-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "from qiskit.circuit import QuantumCircuit\n",
        "\n",
        "MAX_DEPTH = 100\n",
        "circuits = []\n",
        "for d in range(MAX_DEPTH + 1):\n",
        "    circ = QuantumCircuit(1)\n",
        "    for _ in range(d):\n",
        "        circ.x(0)\n",
        "        circ.barrier(0)\n",
        "    circ.measure_all()\n",
        "    circuits.append(circ)\n",
        "\n",
        "display(circuits[3].draw(output=\"mpl\"))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "a366502c",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "SparsePauliOp(['Z'],\n",
              "              coeffs=[1.+0.j])"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.quantum_info import SparsePauliOp\n",
        "\n",
        "obs = SparsePauliOp.from_list([(\"Z\", 1.0)])\n",
        "obs"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6200c2ed",
      "metadata": {},
      "source": [
        "<span id=\"22-build-a-noise-model\" />\n",
        "\n",
        "### 2.2 Construire un modèle de bruit\n",
        "\n",
        "Pour effectuer une simulation bruyante, nous devons spécifier `NoiseModel`. Nous montrons comment construire `NoiseModel` dans cette section.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dae0c070",
      "metadata": {},
      "source": [
        "Nous devons d'abord définir les erreurs quantiques (ou de lecture) à ajouter à un modèle de bruit.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "1e0f1c12",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_aer.noise.errors import (\n",
        "    coherent_unitary_error,\n",
        "    amplitude_damping_error,\n",
        "    ReadoutError,\n",
        ")\n",
        "from qiskit.circuit.library import RXGate\n",
        "\n",
        "# Coherent (unitary) error: Over X-rotation error\n",
        "# https://qiskit.github.io/qiskit-aer/stubs/qiskit_aer.noise.coherent_unitary_error.html#qiskit_aer.noise.coherent_unitary_error\n",
        "OVER_ROTATION_ANGLE = 0.05\n",
        "coherent_error = coherent_unitary_error(RXGate(OVER_ROTATION_ANGLE).to_matrix())\n",
        "\n",
        "# Incoherent error: Amplitude dumping error\n",
        "# https://qiskit.github.io/qiskit-aer/stubs/qiskit_aer.noise.amplitude_damping_error.html#qiskit_aer.noise.amplitude_damping_error\n",
        "AMPLITUDE_DAMPING_PARAM = 0.02  # in [0, 1] (0: no error)\n",
        "incoherent_error = amplitude_damping_error(AMPLITUDE_DAMPING_PARAM)\n",
        "\n",
        "# Readout (measurement) error: Readout error\n",
        "# https://qiskit.github.io/qiskit-aer/stubs/qiskit_aer.noise.ReadoutError.html#qiskit_aer.noise.ReadoutError\n",
        "PREP0_MEAS1 = 0.03  # P(1|0): Probability of preparing 0 and measuring 1\n",
        "PREP1_MEAS0 = 0.08  # P(0|1): Probability of preparing 1 and measuring 0\n",
        "readout_error = ReadoutError(\n",
        "    [[1 - PREP0_MEAS1, PREP0_MEAS1], [PREP1_MEAS0, 1 - PREP1_MEAS0]]\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "e23c26ba",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_aer.noise import NoiseModel\n",
        "\n",
        "noise_model = NoiseModel()\n",
        "noise_model.add_quantum_error(coherent_error.compose(incoherent_error), \"x\", (0,))\n",
        "noise_model.add_readout_error(readout_error, (0,))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5a786224",
      "metadata": {},
      "source": [
        "<span id=\"23-build-a-noisy-sampler-with-the-noise-model\" />\n",
        "\n",
        "### 2.3 Construisez un échantillonneur bruyant avec le modèle de bruit\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "f8aded6f",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_aer.primitives import SamplerV2 as Sampler\n",
        "\n",
        "noisy_sampler = Sampler(options={\"backend_options\": {\"noise_model\": noise_model}})"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "922ba1ac",
      "metadata": {},
      "source": [
        "<span id=\"24-run-quantum-circuits-on-the-noisy-sampler\" />\n",
        "\n",
        "### 2.4 Exécutez des circuits quantiques sur l'échantillonneur bruyant\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "4ae504e7",
      "metadata": {},
      "outputs": [],
      "source": [
        "job = noisy_sampler.run(circuits, shots=400)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "3b2fff25",
      "metadata": {},
      "outputs": [],
      "source": [
        "result = job.result()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "4dc12337",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'0': 389, '1': 11}"
            ]
          },
          "execution_count": 12,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "result[0].data.meas.get_counts()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7e654c5e",
      "metadata": {},
      "source": [
        "<span id=\"25-plot-results\" />\n",
        "\n",
        "### 2.5 Résultats du tracé\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "1a25e394",
      "metadata": {},
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "\n",
        "plt.title(\"Noisy simulation\")\n",
        "ds = list(range(MAX_DEPTH + 1))\n",
        "plt.plot(\n",
        "    ds,\n",
        "    [result[d].data.meas.expectation_values([\"Z\"]) for d in ds],\n",
        "    color=\"gray\",\n",
        "    linestyle=\"-\",\n",
        ")\n",
        "plt.scatter(ds, [result[d].data.meas.expectation_values([\"Z\"]) for d in ds], marker=\"o\")\n",
        "plt.hlines(0, xmin=0, xmax=MAX_DEPTH, colors=\"black\")\n",
        "plt.ylim(-1, 1)\n",
        "plt.xlabel(\"Circuit depth\")\n",
        "plt.ylabel(\"Measured <Z>\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "09ef68bb",
      "metadata": {},
      "source": [
        "<span id=\"26-ideal-simulation\" />\n",
        "\n",
        "### 2.6 Simulation idéale\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "041abc81",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/041abc81-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "ideal_sampler = Sampler()\n",
        "job_ideal = ideal_sampler.run(circuits)\n",
        "result_ideal = job_ideal.result()\n",
        "plt.title(\"Ideal simulation\")\n",
        "ds = list(range(MAX_DEPTH + 1))\n",
        "plt.plot(\n",
        "    ds,\n",
        "    [result_ideal[d].data.meas.expectation_values([\"Z\"]) for d in ds],\n",
        "    color=\"gray\",\n",
        "    linestyle=\"-\",\n",
        ")\n",
        "plt.scatter(\n",
        "    ds, [result_ideal[d].data.meas.expectation_values([\"Z\"]) for d in ds], marker=\"o\"\n",
        ")\n",
        "plt.hlines(0, xmin=0, xmax=MAX_DEPTH, colors=\"black\")\n",
        "plt.xlabel(\"Circuit depth\")\n",
        "plt.ylabel(\"Measured <Z>\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a1e1b6e6",
      "metadata": {},
      "source": [
        "<span id=\"27-exercise\" />\n",
        "\n",
        "### 2.7 Exercice\n",
        "\n",
        "En modifiant le code ci-dessous,\n",
        "\n",
        "* [ ] Essayer 25x le nombre de prises de vue (= 10 000 prises de vue) et s'assurer qu'un tracé plus lisse est obtenu\n",
        "* [ ] Modifiez les paramètres de bruit (OVER\\_ROTATION\\_ANGLE, AMPLITUDE\\_DAMPING\\_PARAM, PREP0\\_MEAS1, ou PREP1\\_MEAS0 ) et observez les changements sur le graphique\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "502b9cfe",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/502b9cfe-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "OVER_ROTATION_ANGLE = 0.05\n",
        "coherent_error = coherent_unitary_error(RXGate(OVER_ROTATION_ANGLE).to_matrix())\n",
        "AMPLITUDE_DAMPING_PARAM = 0.02  # in [0, 1] (0: no error)\n",
        "incoherent_error = amplitude_damping_error(AMPLITUDE_DAMPING_PARAM)\n",
        "PREP0_MEAS1 = 0.1  # P(1|0): Probability of preparing 0 and measuring 1\n",
        "PREP1_MEAS0 = 0.05  # P(0|1): Probability of preparing 1 and measuring 0\n",
        "readout_error = ReadoutError(\n",
        "    [[1 - PREP0_MEAS1, PREP0_MEAS1], [PREP1_MEAS0, 1 - PREP1_MEAS0]]\n",
        ")\n",
        "noise_model = NoiseModel()\n",
        "noise_model.add_quantum_error(coherent_error.compose(incoherent_error), \"x\", (0,))\n",
        "noise_model.add_readout_error(readout_error, (0,))\n",
        "options = {\n",
        "    \"backend_options\": {\"noise_model\": noise_model},\n",
        "}\n",
        "noisy_sampler = Sampler(options=options)\n",
        "job = noisy_sampler.run(circuits, shots=400)\n",
        "result = job.result()\n",
        "plt.title(\"Noisy simulation\")\n",
        "ds = list(range(MAX_DEPTH + 1))\n",
        "plt.plot(\n",
        "    ds,\n",
        "    [result[d].data.meas.expectation_values([\"Z\"]) for d in ds],\n",
        "    marker=\"o\",\n",
        "    linestyle=\"-\",\n",
        ")\n",
        "plt.hlines(0, xmin=0, xmax=MAX_DEPTH, colors=\"black\")\n",
        "plt.ylim(-1, 1)\n",
        "plt.xlabel(\"Depth\")\n",
        "plt.ylabel(\"Measured <Z>\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3cfe1a93",
      "metadata": {},
      "source": [
        "<span id=\"28-more-realistic-noisy-simulation\" />\n",
        "\n",
        "### 2.8 Simulation bruyante plus réaliste\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "8d607bb5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<IBMBackend('ibm_strasbourg')>"
            ]
          },
          "execution_count": 17,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit_aer import AerSimulator\n",
        "from qiskit_ibm_runtime import SamplerV2 as Sampler, QiskitRuntimeService\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "real_backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=127\n",
        ")  # Eagle"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "id": "81a67f2f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/81a67f2f-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "aer = AerSimulator.from_backend(real_backend)\n",
        "noisy_sampler = Sampler(mode=aer)\n",
        "job = noisy_sampler.run(circuits)\n",
        "result = job.result()\n",
        "plt.title(\"Noisy simulation with noise model from real backend\")\n",
        "ds = list(range(MAX_DEPTH + 1))\n",
        "plt.plot(\n",
        "    ds,\n",
        "    [result[d].data.meas.expectation_values([\"Z\"]) for d in ds],\n",
        "    marker=\"o\",\n",
        "    linestyle=\"-\",\n",
        ")\n",
        "plt.hlines(0, xmin=0, xmax=MAX_DEPTH, colors=\"black\")\n",
        "plt.ylim(-1, 1)\n",
        "plt.xlabel(\"Depth\")\n",
        "plt.ylabel(\"Measured <Z>\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "567d30e9",
      "metadata": {},
      "source": [
        "<span id=\"3-real-quantum-computation-with-error-mitigation\" />\n",
        "\n",
        "## 3. Calcul quantique réel avec atténuation des erreurs\n",
        "\n",
        "Dans cette partie, nous montrons comment obtenir des résultats à erreur atténuée (valeurs d'espérance) à l'aide de l'estimateur Qiskit.\n",
        "Nous considérons des circuits trotterisés à 6 qubits pour simuler l'évolution temporelle d'un modèle d'Ising unidimensionnel et nous voyons comment l'erreur évolue en fonction du nombre de pas de temps.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "2d301499",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<IBMBackend('ibm_strasbourg')>"
            ]
          },
          "execution_count": 20,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=127\n",
        ")  # Eagle\n",
        "backend"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "id": "6c90b89c",
      "metadata": {},
      "outputs": [],
      "source": [
        "NUM_QUBITS = 6\n",
        "NUM_TIME_STEPS = list(range(8))\n",
        "RX_ANGLE = 0.1\n",
        "RZZ_ANGLE = 0.1"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b1489739",
      "metadata": {},
      "source": [
        "<span id=\"31-build-circuits\" />\n",
        "\n",
        "### 3.1 Construire des circuits\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "id": "1a77956e",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Build circuits with different number of time steps\n",
        "circuits = []\n",
        "for n_steps in NUM_TIME_STEPS:\n",
        "    circ = QuantumCircuit(NUM_QUBITS)\n",
        "    for i in range(n_steps):\n",
        "        # rx layer\n",
        "        for q in range(NUM_QUBITS):\n",
        "            circ.rx(RX_ANGLE, q)\n",
        "        # 1st rzz layer\n",
        "        for q in range(1, NUM_QUBITS - 1, 2):\n",
        "            circ.rzz(RZZ_ANGLE, q, q + 1)\n",
        "        # 2nd rzz layer\n",
        "        for q in range(0, NUM_QUBITS - 1, 2):\n",
        "            circ.rzz(RZZ_ANGLE, q, q + 1)\n",
        "    circ.barrier()  # need not to optimize the circuit\n",
        "    # Uncompute stage\n",
        "    for i in range(n_steps):\n",
        "        for q in range(0, NUM_QUBITS - 1, 2):\n",
        "            circ.rzz(-RZZ_ANGLE, q, q + 1)\n",
        "        for q in range(1, NUM_QUBITS - 1, 2):\n",
        "            circ.rzz(-RZZ_ANGLE, q, q + 1)\n",
        "        for q in range(NUM_QUBITS):\n",
        "            circ.rx(-RX_ANGLE, q)\n",
        "    circuits.append(circ)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "94eb9062",
      "metadata": {},
      "source": [
        "Pour connaître la sortie idéale à l'avance, nous utilisons des circuits de calcul-décompilation qui consistent en un premier étage où le circuit original $U$ est appliqué, et un deuxième étage où il est inversé $U^\\dagger$. Notez que le résultat idéal de ces circuits sera trivialement l'état d'entrée $|000000\\rangle$, qui a les valeurs triviales de l'espérance pour toutes les observables de Pauli, par exemple, $\\langle IIIIIZ \\rangle = 1$.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "id": "20296b5a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/20296b5a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 23,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Print the circuit with 2 time steps\n",
        "circuits[2].draw(output=\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cde8d3ea",
      "metadata": {},
      "source": [
        "Remarque : comme indiqué ci-dessus, le circuit avec des pas de temps de $k$ aura $4k$ couches de portes à deux qubits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "id": "af0d03e9",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "SparsePauliOp(['IIIIIZ'],\n",
              "              coeffs=[1.+0.j])"
            ]
          },
          "execution_count": 24,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "obs = SparsePauliOp.from_sparse_list([(\"Z\", [0], 1.0)], num_qubits=NUM_QUBITS)\n",
        "obs"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ebd6ea9b",
      "metadata": {},
      "source": [
        "<span id=\"32-transpile-the-circuits\" />\n",
        "\n",
        "### 3.2 Transpiler les circuits\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8eaa552e",
      "metadata": {},
      "source": [
        "Nous transposons les circuits pour le backend avec optimisation (`optimization_level=1`).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "87b861e2",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/87b861e2-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "pm = generate_preset_pass_manager(optimization_level=1, backend=backend)\n",
        "isa_circuits = pm.run(circuits)\n",
        "display(isa_circuits[2].draw(\"mpl\", idle_wires=False, fold=-1))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "743ad427",
      "metadata": {},
      "source": [
        "<span id=\"33-execute-using-estimator-with-different-resilience-levels\" />\n",
        "\n",
        "### 3.3 Exécuter à l'aide de l'estimateur (avec différents niveaux de résilience)\n",
        "\n",
        "Définir le niveau de résilience (`estimator.options.resilience_level`) est le moyen le plus simple d'appliquer une atténuation des erreurs lors de l'utilisation de Qiskit Estimator. Estimator prend en charge les niveaux de résilience suivants (au 28 juin 2024). Pour plus de détails, consultez le guide [de configuration de l'atténuation des erreurs](/docs/guides/error-mitigation-and-suppression-techniques).\n",
        "\n",
        "![image.png](https://quantum.cloud.ibm.com/learning/images/courses/utility-scale-quantum-computing/error-mitigation/res_level.avif)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "id": "328f71f2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID (rl=0): d146vcnmya70008emprg\n",
            "Job ID (rl=1): d146vdnqf56g0081sva0\n",
            "Job ID (rl=2): d146ven5z6q00087c61g\n"
          ]
        }
      ],
      "source": [
        "from qiskit_ibm_runtime import Batch\n",
        "from qiskit_ibm_runtime import EstimatorV2 as Estimator\n",
        "\n",
        "jobs = []\n",
        "job_ids = []\n",
        "with Batch(backend=backend):\n",
        "    for resilience_level in [0, 1, 2]:\n",
        "        estimator = Estimator()\n",
        "        estimator.options.resilience_level = resilience_level\n",
        "        job = estimator.run(\n",
        "            [(circ, obs.apply_layout(circ.layout)) for circ in isa_circuits]\n",
        "        )\n",
        "        job_ids.append(job.job_id())\n",
        "        print(f\"Job ID (rl={resilience_level}): {job.job_id()}\")\n",
        "        jobs.append(job)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "id": "1dd804e4-0d7d-4782-9559-7b3796cab121",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "DONE\n",
            "DONE\n",
            "DONE\n"
          ]
        }
      ],
      "source": [
        "# check job status\n",
        "for job in jobs:\n",
        "    print(job.status())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 32,
      "id": "d138e1e9",
      "metadata": {},
      "outputs": [],
      "source": [
        "# REPLACE WITH YOUR OWN JOB IDS\n",
        "jobs = [service.job(job_id) for job_id in job_ids]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "id": "ea820e98",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Get results\n",
        "results = [job.result() for job in jobs]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e3691462",
      "metadata": {},
      "source": [
        "<span id=\"34-plot-results\" />\n",
        "\n",
        "### 3.4 Résultats du tracé\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "id": "7527976e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/7527976e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.title(\"Error mitigation with different resilience levels\")\n",
        "labels = [\"0 (No mitigation)\", \"1 (TREX)\", \"2 (ZNE + Gate twirling)\"]\n",
        "steps = NUM_TIME_STEPS\n",
        "for result, label in zip(results, labels):\n",
        "    plt.errorbar(\n",
        "        x=steps,\n",
        "        y=[result[s].data.evs for s in steps],\n",
        "        yerr=[result[s].data.stds for s in steps],\n",
        "        marker=\"o\",\n",
        "        linestyle=\"-\",\n",
        "        capsize=4,\n",
        "        label=label,\n",
        "    )\n",
        "plt.hlines(\n",
        "    1.0, min(steps), max(steps), linestyle=\"dashed\", label=\"Ideal\", colors=\"black\"\n",
        ")\n",
        "plt.xlabel(\"Time steps\")\n",
        "plt.ylabel(\"Mitigated <IIIIIZ>\")\n",
        "plt.legend()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e4def30b",
      "metadata": {},
      "source": [
        "<span id=\"4-optional-customize-error-mitigation-options\" />\n",
        "\n",
        "## 4. (Facultatif) Personnaliser les options d'atténuation des erreurs\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f099e16c",
      "metadata": {},
      "source": [
        "Nous pouvons personnaliser l'application des techniques d'atténuation des erreurs grâce aux options présentées ci-dessous.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 35,
      "id": "a22e6b8c",
      "metadata": {},
      "outputs": [],
      "source": [
        "# TREX\n",
        "estimator.options.twirling.enable_measure = True\n",
        "estimator.options.twirling.num_randomizations = \"auto\"\n",
        "estimator.options.twirling.shots_per_randomization = \"auto\"\n",
        "\n",
        "# Gate twirling\n",
        "estimator.options.twirling.enable_gates = True\n",
        "# ZNE\n",
        "estimator.options.resilience.zne_mitigation = True\n",
        "estimator.options.resilience.zne.noise_factors = [1, 3, 5]\n",
        "estimator.options.resilience.zne.extrapolator = (\"exponential\", \"linear\")\n",
        "\n",
        "# Dynamical decoupling\n",
        "estimator.options.dynamical_decoupling.enable = True  # Default: False\n",
        "estimator.options.dynamical_decoupling.sequence_type = \"XX\"\n",
        "\n",
        "# Other options\n",
        "estimator.options.default_shots = 10_000"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "79dd06fb",
      "metadata": {},
      "source": [
        "Voir les guides suivants et la référence API pour les détails des options d'atténuation des erreurs.\n",
        "\n",
        "* [Configurer la réduction des erreurs](/docs/guides/error-mitigation-and-suppression-techniques)\n",
        "* [Introduction aux options](/docs/guides/runtime-options-overview)\n",
        "* [EstimatorOptions](/docs/api/qiskit-ibm-runtime/options-estimator-options)\n",
        "* [SamplerOptions](/docs/api/qiskit-ibm-runtime/options-sampler-options)\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"
    },
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "state": {},
        "version_major": 2,
        "version_minor": 0
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}