{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "828c3465-62a7-4c42-b376-e3ec32f67595",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Assistant d'apprentissage du bruit\"\n",
        "description: \"Commencez à utiliser l'outil d'aide à l'apprentissage du bruit pour enregistrer les modèles de bruit créés lors de l'exécution de charges de travail dans qiskit-ibm-runtime\"\n",
        "---\n",
        "\n",
        "<span id=\"noise-learning-helper\" />\n",
        "\n",
        "# Assistant d'apprentissage du bruit\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "40a246f5-4efd-4fb0-861b-c4e013c1572a",
      "metadata": {
        "tags": [
          "version-info"
        ]
      },
      "source": [
        "{/*\n",
        "  DO NOT EDIT THIS CELL!!!\n",
        "  This cell's content is generated automatically by a script. Anything you add\n",
        "  here will be removed next time the notebook is run. To add new content, create\n",
        "  a new cell before or after this one.\n",
        "  */}\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Versions de package\">\n",
        "    Le code de cette page a été développé en tenant compte des exigences suivantes.\n",
        "    Nous recommandons d'utiliser ces versions ou des versions plus récentes.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.4.1\n",
        "    qiskit-ibm-runtime~=0.47.0\n",
        "    samplomatic~=0.18.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cce93074-df51-4760-9fce-5a520c3bc59a",
      "metadata": {},
      "source": [
        "Les techniques d'atténuation des erreurs [PEA](/docs/guides/error-mitigation-and-suppression-techniques#pea) et [PEC](/docs/guides/error-mitigation-and-suppression-techniques#pec) utilisent toutes deux un composant d'apprentissage du bruit basé sur un [modèle de bruit de Pauli-Lindblad](https://arxiv.org/abs/2201.09866), qui est généralement géré pendant l'exécution après la soumission d'une ou plusieurs tâches via `qiskit-ibm-runtime` \\[...], sans aucun accès local au modèle de bruit ajusté. Toutefois, à partir de la version `qiskit-ibm-runtime`v0.27.1, une classe [`NoiseLearner`](/docs/api/qiskit-ibm-runtime/noise-learner) ainsi qu'une [`NoiseLearnerOptions`](/docs/api/qiskit-ibm-runtime/options-noise-learner-options) classe associée ont été créées pour récupérer les résultats de ces expériences d'apprentissage du bruit. Ces résultats peuvent ensuite être enregistrés localement sous forme de `NoiseLearnerResult` et servir de données d'entrée pour des expériences ultérieures. Cette page présente une vue d'ensemble de son utilisation et des options associées disponibles.\n",
        "\n",
        "De plus, à partir de la version `qiskit-ibm-runtime`v0.47.0, une nouvelle `NoiseLearnerV3` classe compatible avec la primitive Executor a été ajoutée. Cette nouvelle version, qui s'inscrit également dans le [modèle d'exécution dirigée](/docs/guides/directed-execution-model), vous permet de spécifier explicitement les couches que vous souhaitez apprendre.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  `NoiseLearner` fonctionne uniquement avec EstimatorV2 et `NoiseLearnerV3` fonctionne uniquement avec Executor.\n",
        "</Admonition>\n",
        "\n",
        "<span id=\"noiselearner\" />\n",
        "\n",
        "## `NoiseLearner`\n",
        "\n",
        "<span id=\"overview\" />\n",
        "\n",
        "### Aperçu\n",
        "\n",
        "Ce `NoiseLearner` cours propose des expériences visant à caractériser les processus de bruit à partir d'un modèle de bruit de Pauli-Lindblad appliqué à un (ou plusieurs) circuit(s). Elle dispose d'une `run()` méthode qui exécute les expériences d'apprentissage et prend en entrée soit une liste de circuits, soit un objet [PUB](/docs/guides/primitive-input-output), et renvoie un objet `NoiseLearnerResult` contenant les canaux de bruit appris ainsi que des métadonnées sur la ou les tâches soumises. Vous trouverez ci-dessous un extrait de code illustrant l'utilisation du programme d'aide.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "d9a5320d-8ec6-483a-9ecf-931b0f5f5d13",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit import QuantumCircuit\n",
        "from qiskit.transpiler import CouplingMap\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, EstimatorV2\n",
        "from qiskit_ibm_runtime.noise_learner import NoiseLearner\n",
        "from qiskit_ibm_runtime.options import (\n",
        "    NoiseLearnerOptions,\n",
        "    ResilienceOptionsV2,\n",
        "    EstimatorOptions,\n",
        ")\n",
        "\n",
        "# Build a circuit with two entangling layers\n",
        "num_qubits = 27\n",
        "edges = list(CouplingMap.from_line(num_qubits, bidirectional=False))\n",
        "even_edges = edges[::2]\n",
        "odd_edges = edges[1::2]\n",
        "\n",
        "circuit = QuantumCircuit(num_qubits)\n",
        "for pair in even_edges:\n",
        "    circuit.cx(pair[0], pair[1])\n",
        "for pair in odd_edges:\n",
        "    circuit.cx(pair[0], pair[1])\n",
        "\n",
        "# Choose a backend to run on\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy()\n",
        "\n",
        "# Transpile the circuit for execution\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=3)\n",
        "circuit_to_learn = pm.run(circuit)\n",
        "\n",
        "# Instantiate a NoiseLearner object and execute the noise learning program\n",
        "learner = NoiseLearner(mode=backend)\n",
        "job = learner.run([circuit_to_learn])\n",
        "noise_model = job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ef141d65-d14d-4e2b-9813-b8766e29fdb9",
      "metadata": {},
      "source": [
        "Le résultat `NoiseLearnerResult.data` est une liste d'objets [`LayerError`](/docs/api/qiskit-ibm-runtime/results-layer-error) contenant le [modèle de bruit](https://arxiv.org/abs/2201.09866) pour chaque couche d'intrication appartenant aux circuits cibles. Chacune d'entre elles stocke `LayerError` les informations relatives à la couche, sous la forme d'un circuit et d'un ensemble d'étiquettes de qubits, ainsi que le modèle de [`PauliLindbladError`](/docs/api/qiskit-ibm-runtime/results-pauli-lindblad-error) bruit qui a été appris pour la couche en question.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a9be8ff1-7494-407c-853c-50d471a2f55f",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Noise learner result contains 2 entries and has the following type:\n",
            " <class 'qiskit_ibm_runtime.utils.noise_learner_result.NoiseLearnerResult'>\n",
            "\n",
            "Each element of `NoiseLearnerResult` then contains an object of type:\n",
            " <class 'qiskit_ibm_runtime.utils.noise_learner_result.LayerError'>\n",
            "\n",
            "And each of these `LayerError` objects possess data on the generators for the error channel: \n",
            "['IIIIIIIIIIIIIIIIIIIIIIIIIIX', 'IIIIIIIIIIIIIIIIIIIIIIIIIIY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIIZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIXI',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIXX', 'IIIIIIIIIIIIIIIIIIIIIIIIIXY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIXZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIYI',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIYX', 'IIIIIIIIIIIIIIIIIIIIIIIIIYY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIYZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIZI',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIZX', 'IIIIIIIIIIIIIIIIIIIIIIIIIZY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIZZ', 'IIIIIIIIIIIIIIIIIIIIIIIIXII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIXIX', 'IIIIIIIIIIIIIIIIIIIIIIIIXIY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIXIZ', 'IIIIIIIIIIIIIIIIIIIIIIIIYII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIYIX', 'IIIIIIIIIIIIIIIIIIIIIIIIYIY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIYIZ', 'IIIIIIIIIIIIIIIIIIIIIIIIZII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIZIX', 'IIIIIIIIIIIIIIIIIIIIIIIIZIY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIZIZ', 'IIIIIIIIIIIIIIIIIIIIIIIXIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIYIII', 'IIIIIIIIIIIIIIIIIIIIIIIZIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIXIIII', 'IIIIIIIIIIIIIIIIIIIIIIXXIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIXYIII', 'IIIIIIIIIIIIIIIIIIIIIIXZIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIYIIII', 'IIIIIIIIIIIIIIIIIIIIIIYXIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIYYIII', 'IIIIIIIIIIIIIIIIIIIIIIYZIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIZIIII', 'IIIIIIIIIIIIIIIIIIIIIIZXIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIZYIII', 'IIIIIIIIIIIIIIIIIIIIIIZZIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIXIIIII', 'IIIIIIIIIIIIIIIIIIIIIXXIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIXYIIII', 'IIIIIIIIIIIIIIIIIIIIIXZIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIYIIIII', 'IIIIIIIIIIIIIIIIIIIIIYXIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIYYIIII', 'IIIIIIIIIIIIIIIIIIIIIYZIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIZIIIII', 'IIIIIIIIIIIIIIIIIIIIIZXIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIZYIIII', 'IIIIIIIIIIIIIIIIIIIIIZZIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIXIIIIII', 'IIIIIIIIIIIIIIIIIIIIXXIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIXYIIIII', 'IIIIIIIIIIIIIIIIIIIIXZIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIYIIIIII', 'IIIIIIIIIIIIIIIIIIIIYXIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIYYIIIII', 'IIIIIIIIIIIIIIIIIIIIYZIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIZIIIIII', 'IIIIIIIIIIIIIIIIIIIIZXIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIZYIIIII', 'IIIIIIIIIIIIIIIIIIIIZZIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIXIIIIIII', 'IIIIIIIIIIIIIIIIIIIXXIIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIXYIIIIII', 'IIIIIIIIIIIIIIIIIIIXZIIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIYIIIIIII', 'IIIIIIIIIIIIIIIIIIIYXIIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIYYIIIIII', 'IIIIIIIIIIIIIIIIIIIYZIIIIII', ...]\n",
            "\n",
            "Along with the error rates: \n",
            "[5.9e-04 5.3e-04 5.7e-04 ... 0.0e+00 1.0e-05 0.0e+00]\n",
            "\n"
          ]
        }
      ],
      "source": [
        "import numpy\n",
        "\n",
        "print(\n",
        "    f\"Noise learner result contains {len(noise_model.data)} entries\"\n",
        "    f\" and has the following type:\\n {type(noise_model)}\\n\"\n",
        ")\n",
        "print(\n",
        "    f\"Each element of `NoiseLearnerResult` then contains\"\n",
        "    f\" an object of type:\\n {type(noise_model.data[0])}\\n\"\n",
        ")\n",
        "# Results are truncated\n",
        "with numpy.printoptions(threshold=200):\n",
        "    print(\n",
        "        f\"And each of these `LayerError` objects possess\"\n",
        "        f\" data on the generators for the error channel: \\n\"\n",
        "        f\"{noise_model.data[0].error.generators}\\n\"\n",
        "    )\n",
        "# Results are truncated\n",
        "with numpy.printoptions(threshold=200):\n",
        "    print(\n",
        "        f\"Along with the error rates: \\n{noise_model.data[0].error.rates}\\n\"\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "faa3892e-30a5-48f7-87dd-39ab1b0846d9",
      "metadata": {},
      "source": [
        "L'attribut `LayerError.error` du résultat de l'apprentissage du bruit contient les générateurs et les taux d'erreur du modèle de Pauli Lindblad ajusté, qui se présente sous la forme suivante\n",
        "\n",
        "$\\Lambda(\\rho) = \\exp{\\sum_j r_j \\left(P_j \\rho P_j^\\dagger - \\rho\\right)},$\n",
        "\n",
        "où les $r_j$ sont les `LayerError.rates` et $P_j$ sont les opérateurs de Pauli spécifiés dans `LayerError.generators`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fc0000e6-e77a-4b87-a9ee-262f904953fc",
      "metadata": {},
      "source": [
        "<span id=\"noise-learning-options\" />\n",
        "\n",
        "### Options d'apprentissage du bruit\n",
        "\n",
        "Vous pouvez choisir parmi plusieurs options à fournir lors de la création d'un `NoiseLearner` objet. Ces options sont regroupées dans la `qiskit_ibm_runtime.options.NoiseLearnerOptions` classe et permettent notamment de définir le nombre maximal de couches à apprendre, le nombre de randomisations et la stratégie de rotation. Pour plus d'informations, consultez la [`NoiseLearnerOptions`](/docs/api/qiskit-ibm-runtime/options-noise-learner-options) documentation de l'API.\n",
        "\n",
        "Voici un exemple simple qui montre comment utiliser le `NoiseLearnerOptions` dans une `NoiseLearner` expérience :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "fcd1bd93-405d-4cfb-a5d1-bb646404aa58",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Build a GHZ circuit\n",
        "circuit = QuantumCircuit(10)\n",
        "circuit.h(0)\n",
        "circuit.cx(range(0, 9), range(1, 10))\n",
        "# Choose a backend to run on\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy()\n",
        "\n",
        "# Transpile the circuit for execution\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=3)\n",
        "circuit_to_run = pm.run(circuit_to_learn)\n",
        "\n",
        "# Instantiate a NoiseLearnerOptions object\n",
        "learner_options = NoiseLearnerOptions(\n",
        "    max_layers_to_learn=3, num_randomizations=32, twirling_strategy=\"all\"\n",
        ")\n",
        "\n",
        "# Instantiate a NoiseLearner object and execute the noise learning program\n",
        "learner = NoiseLearner(mode=backend, options=learner_options)\n",
        "job = learner.run([circuit_to_run])\n",
        "noise_model = job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d952d0cc-497b-45ae-a55e-2b611ebbe4a3",
      "metadata": {},
      "source": [
        "<span id=\"input-noise-model-to-a-primitive\" />\n",
        "\n",
        "### Modèle de bruit d'entrée vers une primitive\n",
        "\n",
        "Le modèle de bruit appris sur le circuit peut également servir d'entrée à la primitive `EstimatorV2` « IBM Quantum ». Cette valeur peut être transmise à la primitive de plusieurs façons différentes. Les trois exemples suivants montrent comment vous pouvez transmettre directement le modèle de bruit à l'attribut `estimator.options` , en utilisant un `ResilienceOptionsV2` objet avant d'instancier une primitive Estimator, et en lui transmettant un dictionnaire correctement formaté.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "9826013a-f9fd-4d72-baa7-dc5395b81007",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Pass the noise model to the `estimator.options` attribute directly\n",
        "estimator = EstimatorV2(mode=backend)\n",
        "estimator.options.resilience.layer_noise_model = noise_model"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "7ab10595-5c20-4954-9001-70b8879926b4",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Specify options through a ResilienceOptionsV2 object\n",
        "resilience_options = ResilienceOptionsV2(layer_noise_model=noise_model)\n",
        "estimator_options = EstimatorOptions(resilience=resilience_options)\n",
        "estimator = EstimatorV2(mode=backend, options=estimator_options)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "17b1f8de-fe14-4998-898b-ecd409a5efd3",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Specify options by using a dictionary\n",
        "options_dict = {\n",
        "    \"resilience_level\": 2,\n",
        "    \"resilience\": {\"layer_noise_model\": noise_model},\n",
        "}\n",
        "\n",
        "estimator = EstimatorV2(mode=backend, options=options_dict)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8c167b65-2e9a-41b9-b593-edfe80a2fde4",
      "metadata": {},
      "source": [
        "Une fois que le modèle de bruit a été transmis à l'objet `EstimatorV2` , celui-ci peut être utilisé pour exécuter des charges de travail et mettre en œuvre des mesures d'atténuation des erreurs comme d'habitude.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dad71939-7fe2-42f0-90fe-6974fe0854e7",
      "metadata": {},
      "source": [
        "<span id=\"NoiseLearnerV3\" />\n",
        "\n",
        "<span id=\"noiselearnerv3\" />\n",
        "\n",
        "## NoiseLearnerV3\n",
        "\n",
        "<span id=\"overview\" />\n",
        "\n",
        "### Aperçu\n",
        "\n",
        "À l'instar de `NoiseLearner`, la `NoiseLearnerV3` classe réalise des expériences visant à caractériser les processus de bruit à partir d'un modèle de bruit de Pauli-Lindblad pour un ou plusieurs circuits. Sa `run()` méthode prend en paramètre une liste d'instructions, dont chacune doit être une structure annotée de type « twirled » [`BoxOp`](/docs/api/qiskit/qiskit.circuit.BoxOp) contenant des opérations [ISA](/docs/guides/transpile#instruction-set-architecture).\n",
        "\n",
        "Le résultat d'une `NoiseLearnerV3` tâche contient une liste [`NoiseLearnerV3Result`](/docs/api/qiskit-ibm-runtime/results-noise-learner-v3-result) d'objets, à raison d'un pour chaque instruction d'entrée.\n",
        "Le code suivant montre comment utiliser le programme d'aide.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "0bbd2c21-6045-4954-aee9-339e6b060805",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Found 3 unique layers\n",
            "Each instruction is of type <class 'qiskit.circuit.controlflow.box.BoxOp'>\n",
            "And has annotations: [Twirl(group='pauli', dressing='left', decomposition='rzsx'), InjectNoise(ref='r789B', modifier_ref='', site='before')]\n"
          ]
        }
      ],
      "source": [
        "from qiskit import QuantumCircuit\n",
        "from qiskit.transpiler import CouplingMap\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, Executor\n",
        "from qiskit_ibm_runtime.noise_learner_v3 import NoiseLearnerV3\n",
        "from samplomatic.transpiler import generate_boxing_pass_manager\n",
        "from samplomatic.utils import find_unique_box_instructions\n",
        "\n",
        "\n",
        "# Build a circuit with two entangling layers\n",
        "num_qubits = 27\n",
        "edges = list(CouplingMap.from_line(num_qubits, bidirectional=False))\n",
        "even_edges = edges[::2]\n",
        "odd_edges = edges[1::2]\n",
        "\n",
        "circuit = QuantumCircuit(num_qubits)\n",
        "for pair in even_edges:\n",
        "    circuit.cx(pair[0], pair[1])\n",
        "for pair in odd_edges:\n",
        "    circuit.cx(pair[0], pair[1])\n",
        "\n",
        "# Choose a backend to run on\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy()\n",
        "\n",
        "# Transpile the circuit for execution\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=3)\n",
        "isa_circuit = pm.run(circuit)\n",
        "\n",
        "# Run the boxing pass manager to group instructions into annotated boxes\n",
        "boxing_pm = generate_boxing_pass_manager(\n",
        "    enable_gates=True,\n",
        "    enable_measures=False,\n",
        "    inject_noise_targets=\"gates\",  # no measurement mitigation\n",
        "    inject_noise_strategy=\"uniform_modification\",\n",
        ")\n",
        "boxed_circuit = boxing_pm.run(isa_circuit)\n",
        "\n",
        "# Find unique boxed instructions\n",
        "unique_box_instructions = find_unique_box_instructions(boxed_circuit.data)\n",
        "print(f\"Found {len(unique_box_instructions)} unique layers\")\n",
        "print(\n",
        "    f\"Each instruction is of type {type(unique_box_instructions[0].operation)}\"\n",
        ")\n",
        "print(\n",
        "    f\"And has annotations: {unique_box_instructions[0].operation.annotations}\"\n",
        ")\n",
        "\n",
        "# Instantiate a NoiseLearnerV3 object and execute the noise learning program\n",
        "learner = NoiseLearnerV3(backend)\n",
        "learner.options.shots_per_randomization = 128\n",
        "learner.options.num_randomizations = 32\n",
        "learner_job = learner.run(unique_box_instructions)\n",
        "learner_result = learner_job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "937986c1-b08d-4218-ae5d-c9dbfbf4a0cf",
      "metadata": {},
      "source": [
        "Le résultat de la fonction est une liste `NoiseLearnerV3Result` d'objets, à raison d'un pour chaque ensemble d'instructions entre crochets. `NoiseLearnerV3Result` dispose d'une `to_pauli_lindblad_map()` méthode qui renvoie un [`PauliLindbladMap`](/docs/api/qiskit/qiskit.quantum_info.PauliLindbladMap) objet, lequel comporte des méthodes permettant d'extraire les générateurs, les taux d'erreur et bien plus encore.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "4a9b686b-cf8d-4986-8fff-83eedda1f2c1",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The Noise learner V3 result contains 3 entries and each has the following type:\n",
            " <class 'qiskit_ibm_runtime.results.noise_learner_v3.NoiseLearnerV3Result'>\n",
            "\n",
            "After converting to PauliLindbladMap, you can extract data  on the generators for the error channel (truncated to 3): \n",
            "<QubitSparsePauliList with 3 elements on 27 qubits: [X_0, Y_0, Z_0]>\n",
            "\n",
            "Along with the error rates (truncated to 3): \n",
            "[0.00026 0.00032 0.00023]\n",
            "\n"
          ]
        }
      ],
      "source": [
        "print(\n",
        "    f\"The Noise learner V3 result contains {len(learner_result)} entries\"\n",
        "    f\" and each has the following type:\\n {type(learner_result[0])}\\n\"\n",
        ")\n",
        "noise_map = learner_result[0].to_pauli_lindblad_map()\n",
        "print(\n",
        "    f\"After converting to PauliLindbladMap, you can extract data \"\n",
        "    f\" on the generators for the error channel \"\n",
        "    f\"(truncated to 3): \\n{noise_map.generators()[:3]}\\n\"\n",
        ")\n",
        "with numpy.printoptions(threshold=20):\n",
        "    print(\n",
        "        f\"Along with the error rates \"\n",
        "        f\"(truncated to 3): \\n{noise_map.rates[:3]}\\n\"\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "baa61d6a-7efc-498b-bccd-260871e174df",
      "metadata": {},
      "source": [
        "<span id=\"noise-learning-options\" />\n",
        "\n",
        "### Options d'apprentissage du bruit\n",
        "\n",
        "`NoiseLearnerV3` prend en charge plusieurs options, notamment le nombre de randomisations et la profondeur des paires de couches, entre autres. Tout comme pour les types primitifs, vous pouvez définir les options pendant ou après l'instanciation de `NoiseLearnerV3` l'objet. L'exemple de code précédent montrait comment définir les `shots_per_randomization` options et `num_randomizations` . Pour plus d'informations, consultez la [`NoiseLearnerV3Options`](/docs/api/qiskit-ibm-runtime/options-models-noise-learner-v3-options) documentation de l'API.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e76e997d-506f-4607-a89a-e4723c640a44",
      "metadata": {},
      "source": [
        "<span id=\"input-a-noise-model-to-executor\" />\n",
        "\n",
        "### Importer un modèle de bruit dans Executor\n",
        "\n",
        "Executor suit les intentions de conception spécifiées dans les annotations du circuit (sous la forme d'un samplex) et dans les options. `InjectNoise` est l'annotation permettant de préciser où injecter du bruit, et l'argument `pauli_lindblad_maps` `samplex` indique quelle carte de bruit utiliser.\n",
        "\n",
        "Le circuit de l'exemple précédent passe par le gestionnaire de passes de boxing, qui regroupe les instructions dans des cases annotées. Le code correspondant est ajouté ici pour faciliter la compréhension.\n",
        "\n",
        "* `inject_noise_targets=”gates”` indique d'ajouter les `InjectNoise` annotations aux encadrés contenant des éléments d'entrelacement.\n",
        "* `inject_noise_strategy=\"uniform_modification\"` indique d'attribuer les mêmes `ref` et `modifier_ref` à toutes les cases équivalentes comportant `InjectNoise` des annotations.\n",
        "  * `InjectNoise.ref` est un identifiant unique utilisé pour attribuer un modèle de bruit à cette case.\n",
        "  * `InjectNoise.modifier_ref` permet de modifier l'échelle du modèle de bruit attribué à une boîte à l'aide de facteurs multiplicatifs.\n",
        "\n",
        "```python\n",
        "boxing_pm = generate_boxing_pass_manager(\n",
        "    enable_gates=True,\n",
        "    enable_measures=False,\n",
        "    inject_noise_targets=\"gates\",  # no measurement mitigation\n",
        "    inject_noise_strategy=\"uniform_modification\",\n",
        ")\n",
        "```\n",
        "\n",
        "Le circuit de l'exemple précédent comporte trois cases, dont deux contiennent `InjectNoise` des annotations dotées d'attributs différents `ref` (puisqu'elles ne sont pas équivalentes).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "3b86853b-6766-4cf6-9a6b-2ea1008aea42",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Annotations of box #0: [Twirl(group='pauli', dressing='left', decomposition='rzsx'), InjectNoise(ref='r789B', modifier_ref='r789B', site='before')]\n",
            "\n",
            "Annotations of box #1: [Twirl(group='pauli', dressing='left', decomposition='rzsx'), InjectNoise(ref='r054B', modifier_ref='r054B', site='before')]\n",
            "\n",
            "Annotations of box #2: [Twirl(group='pauli', dressing='right', decomposition='rzsx')]\n",
            "\n"
          ]
        }
      ],
      "source": [
        "# box_circuit comes from the example above\n",
        "for idx, instruction in enumerate(boxed_circuit):\n",
        "    # The `InjectNoise` annotation defines which boxes to inject noise.\n",
        "    print(f\"Annotations of box #{idx}: {instruction.operation.annotations}\\n\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3ab1e503-b36a-46bd-b5d1-2735c3d0a82d",
      "metadata": {},
      "source": [
        "Le résultat de la `NoiseLearnerV3` tâche doit être converti en dictionnaire avant d'être transmis à Executor. Les clés de ce dictionnaire sont les `InjectNoise.ref` attributs, et les valeurs sont les cartes de bruit correspondantes. Ce mappage indique à Executor quels modèles de bruit injecter et à quel endroit.\n",
        "\n",
        "Le code suivant montre comment récupérer le circuit et le `NoiseLearnerV3` résultat de l'exemple précédent et les transmettre à Executor, qui générera les variantes du circuit avec les modèles de bruit injectés et les exécutera sur le matériel.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "96d59082-7adc-482a-b57f-0f7a5c3eb217",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_ibm_runtime.quantum_program import QuantumProgram\n",
        "from samplomatic import build\n",
        "\n",
        "# Generate a quantum program\n",
        "program = QuantumProgram(shots=1000)\n",
        "\n",
        "# Build the template circuit and samplex pair\n",
        "template_circuit, samplex = build(boxed_circuit)\n",
        "\n",
        "# Convert the NoiseLearnerV3 result to a dictionary\n",
        "noise_maps = learner_result.to_dict(\n",
        "    instructions=unique_box_instructions, require_refs=False\n",
        ")\n",
        "\n",
        "# Append the samplex item and execute\n",
        "program.append_samplex_item(\n",
        "    template_circuit,\n",
        "    samplex=samplex,\n",
        "    samplex_arguments={\n",
        "        \"pauli_lindblad_maps\": noise_maps,\n",
        "    },\n",
        ")\n",
        "\n",
        "executor = Executor(backend)\n",
        "executor_job = executor.run(program)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "936c08fb-7838-4d61-9060-092b479e7909",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Etapes suivantes\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recommandations\">\n",
        "  * Consultez la [référence de l'API EstimatorOptions](/docs/api/qiskit-ibm-runtime/options-estimator-options) et la [référence de l'API ResilienceOptionsV2](/docs/api/qiskit-ibm-runtime/options-resilience-options-v2).\n",
        "  * Découvrez-en davantage sur [les techniques](error-mitigation-and-suppression-techniques) disponibles de limitation et de suppression des erreurs.\n",
        "  * Découvrez comment mettre en œuvre [la gestion du bruit dans Estimator](/docs/guides/estimator-noise-management).\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": 4
}