{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "d0e7f54f-e951-44d4-8cd8-5b539cf5c91c",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Exemples d'exécuteurs testamentaires\"\n",
        "description: \"Exemples pratiques d'utilisation de la primitive « Executor » dans qiskit-ibm-runtime.\"\n",
        "---\n",
        "\n",
        "<span id=\"executor-examples\" />\n",
        "\n",
        "# Exemples d'exécuteurs testamentaires\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a53ccd93-5bca-4dfb-a8a0-fcf4ed046fa7",
      "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é en respectant les exigences suivantes.\n",
        "    Nous vous recommandons d'utiliser ces versions ou des versions plus récentes.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.4.0\n",
        "    qiskit-ibm-runtime~=0.46.1\n",
        "    samplomatic~=0.18.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fed832ee-87a7-4261-874d-84002f3863b5",
      "metadata": {},
      "source": [
        "Les exemples présentés dans cette section illustrent certaines façons courantes d'utiliser la primitive Executor. Avant d'exécuter ces exemples, suivez les instructions fournies dans [le guide de démarrage rapide](/docs/guides/directed-execution-model) «[ Installer Qiskit](/docs/guides/install-qiskit) et Executor ».\n",
        "\n",
        "<span id=\"before-you-begin\" />\n",
        "\n",
        "## Avant de commencer\n",
        "\n",
        "Certains des exemples de code présentés sur cette page utilisent `samplex`, qui fait partie du package Samplomatic.  Par conséquent, avant d'exécuter ces blocs de code, vous devez installer Samplomatic, comme indiqué dans le bloc de code suivant.  Pour plus d'informations, consultez la [documentation de Samplomatic](https://qiskit.github.io/samplomatic).\n",
        "\n",
        "```python\n",
        "pip install samplomatic\n",
        "\n",
        "# For visualization support, include the visualization dependencies.\n",
        "# pip install samplomatic[vis]\n",
        "```\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "19549d62-4095-458d-a691-00b9bc456ed5",
      "metadata": {},
      "source": [
        "<span id=\"example-parameterized-circuit\" />\n",
        "\n",
        "## Exemple : circuit paramétré\n",
        "\n",
        "Cet exemple montre comment ajouter des éléments de circuit avec des paramètres, ainsi que des éléments Samplex. Elle comprend les étapes suivantes :\n",
        "\n",
        "1. Configurer le circuit : générer et transcompiler le circuit cible.\n",
        "2. Préparez un samplex : regroupez les portes et les mesures dans des zones annotées, puis générez le modèle de circuit et la paire de samplex.\n",
        "3. Exécuter : ajouter un élément de circuit et un élément Samplex à un `QuantumProgram` et exécuter les deux dans une seule tâche.\n",
        "\n",
        "<span id=\"set-up-the-circuit\" />\n",
        "\n",
        "### Mettre en place le circuit\n",
        "\n",
        "Préparez un état GHZ à trois qubits, faites pivoter les qubits autour de l'axe de Pauli-Z, puis mesurez les qubits dans la base de calcul.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "caf43d3e-ed55-4805-8d19-6c0980eeb1dc",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.circuit import Parameter, QuantumCircuit\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, Executor\n",
        "from qiskit_ibm_runtime.quantum_program import QuantumProgram\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "import numpy as np\n",
        "from samplomatic import build\n",
        "from samplomatic.transpiler import generate_boxing_pass_manager\n",
        "\n",
        "# Generate the circuit\n",
        "circuit = QuantumCircuit(3)\n",
        "circuit.h(0)\n",
        "circuit.h(1)\n",
        "circuit.cz(0, 1)\n",
        "circuit.h(1)\n",
        "circuit.h(2)\n",
        "circuit.cz(1, 2)\n",
        "circuit.h(2)\n",
        "circuit.rz(Parameter(\"theta\"), 0)\n",
        "circuit.rz(Parameter(\"phi\"), 1)\n",
        "circuit.rz(Parameter(\"lam\"), 2)\n",
        "circuit.measure_all()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f95bc53d-ed01-4b94-988b-1e497916d0fa",
      "metadata": {},
      "source": [
        "Spécifiez le backend et transcompilez le circuit afin qu'il n'utilise que les instructions prises en charge par le QPU (ce que l'on appelle un circuit à architecture de jeu d'instructions (ISA)).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "bf633f01-372f-4519-b89d-ab4075255bd9",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Initialize the service and choose a backend\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(operational=True, simulator=False)\n",
        "\n",
        "# Transpile the circuit to ISA\n",
        "preset_pass_manager = generate_preset_pass_manager(\n",
        "    backend=backend, optimization_level=3\n",
        ")\n",
        "isa_circuit = preset_pass_manager.run(circuit)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fbecf32d-d1b9-4e12-ab56-0a1ede7ebf04",
      "metadata": {},
      "source": [
        "<span id=\"prepare-the-samplex\" />\n",
        "\n",
        "### Préparez le samplex\n",
        "\n",
        "Utilisez la `generate_boxing_pass_manager` fonction pratique et ses paramètres de rotation pour regrouper les portes à deux qubits et les mesures dans des encadrés, puis appliquez des annotations de rotation.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "8d6d64ad-12ee-4c0c-a683-d1178600d3c7",
      "metadata": {},
      "outputs": [],
      "source": [
        "boxing_pm = generate_boxing_pass_manager(\n",
        "    # Add gate twirling\n",
        "    enable_gates=True,\n",
        "    # Add measurement twirling\n",
        "    enable_measures=True,\n",
        ")\n",
        "\n",
        "boxed_circuit = boxing_pm.run(isa_circuit)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2e8fb1f9-4b15-4161-9f8f-1c24d64b0045",
      "metadata": {},
      "source": [
        "Utilisez la `build` méthode pour générer le circuit type et le samplex.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "90e21ca1-7f39-4636-b65e-28685b610a3c",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Build the template circuit and the samplex\n",
        "template_circuit, samplex = build(boxed_circuit)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "521a7263-8d2f-46fd-a261-c23ae56aa5b5",
      "metadata": {},
      "source": [
        "<span id=\"execute-the-circuits\" />\n",
        "\n",
        "### Effectuez les circuits\n",
        "\n",
        "Executor exécute `QuantumProgram` des objets. Chacun `QuantumProgram` peut contenir plusieurs éléments. Cet exemple ajoute un élément de circuit et un élément Samplex à exécuter. Pour plus de détails, consultez [la section « Entrées et sorties de l'exécuteur](/docs/guides/executor-input-output) ».\n",
        "\n",
        "La première étape consiste à initialiser un programme vide, en demandant `1024` des images pour chaque configuration de chaque élément.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "85d7d9ef-a74c-42e4-a758-0f490e29275d",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Generate a quantum program\n",
        "program = QuantumProgram(shots=1024)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8869d18d-cc0e-4556-a195-cd6b590bcef7",
      "metadata": {},
      "source": [
        "`QuantumProgram`Ajouter l'élément de circuit à la liste. Cet élément de circuit se compose de deux parties : le circuit ISA et 10 jeux de valeurs de paramètres.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "19963674-3e72-473c-b24a-228316946dc5",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Append the circuit and the parameter values to the program\n",
        "program.append_circuit_item(\n",
        "    isa_circuit,\n",
        "    circuit_arguments=np.random.rand(10, 3),  # 10 sets of parameter values\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "41505f83-a7a6-4ea8-a7fc-a3fb45a2992a",
      "metadata": {},
      "source": [
        "`QuantumProgram` Ajoutez l'élément samplex à avec ces arguments :\n",
        "\n",
        "* Le circuit modèle et le samplex générés par la `build` fonction\n",
        "* Dix jeux de valeurs de paramètres pour le circuit d'origine\n",
        "* Le nombre de randomisations à effectuer\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "d6b07700-5834-4baa-a08a-434516f5bc07",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Append the template circuit and samplex as a samplex item\n",
        "program.append_samplex_item(\n",
        "    template_circuit,\n",
        "    samplex=samplex,\n",
        "    samplex_arguments={\n",
        "        \"parameter_values\": np.random.rand(\n",
        "            10, 3\n",
        "        ),  # 10 sets of parameter values\n",
        "    },\n",
        "    shape=(2, 14, 10),\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f39e3e78-5953-4801-b521-dd48ae487acf",
      "metadata": {},
      "source": [
        "<span id=\"run-the-executor-job\" />\n",
        "\n",
        "### Exécuter la tâche Executor\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "149addb2-e76f-427c-bac4-54b6a83ddb0a",
      "metadata": {},
      "outputs": [],
      "source": [
        "# initialize an Executor with default options\n",
        "executor = Executor(mode=backend)\n",
        "\n",
        "# Submit the job\n",
        "job = executor.run(program)\n",
        "\n",
        "# Retrieve the result\n",
        "result = job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "93698fec-cff7-4153-8cbb-f7e39c972d9a",
      "metadata": {},
      "source": [
        "Récupérer le résultat pour chaque tâche.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "77235bf8-bcac-43fb-89b0-9ba74b976053",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Access the results of the classical register of task #0, the CircuitItem\n",
        "result_0 = result[0][\"meas\"]\n",
        "\n",
        "# Access the results of the classical register of task #1, the SamplexItem\n",
        "result_1 = result[1][\"meas\"]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "64063941-87b5-4c5d-bbf9-8920c24a216f",
      "metadata": {},
      "source": [
        "<span id=\"example-perform-pec\" />\n",
        "\n",
        "## Exemple : Exécuter PEC\n",
        "\n",
        "Cet exemple montre comment utiliser un élément Samplex pour effectuer une annulation probabiliste des erreurs ( [PEC](/docs/guides/error-mitigation-and-suppression-techniques#pec) ) afin d'atténuer les erreurs.\n",
        "\n",
        "Considérons une version symétrique d'un circuit comportant dix qubits et deux couches distinctes de portes CX. Voici les principales tâches :\n",
        "\n",
        "* Effectuez le circuit en tournoyant.\n",
        "* Réalisez le circuit en utilisant l'atténuation PEC, comme décrit dans l'article [« Probabilistic error cancellation with sparse Pauli-Lindblad models on noisy quantum processors](https://arxiv.org/abs/2201.09866) ».\n",
        "\n",
        "Le processus comprend les étapes suivantes :\n",
        "\n",
        "1. Configuration : générez le circuit cible et regroupez ses opérations dans des encadrés.\n",
        "2. Apprendre : Identifier le bruit des instructions que nous souhaitons atténuer à l'aide du PEC.\n",
        "3. Exécuter : lancer le circuit sur un serveur.\n",
        "4. Analyser : Traiter et analyser les résultats.\n",
        "\n",
        "À titre de comparaison, nous allons exécuter ce circuit en miroir deux fois. Une fois avec uniquement l'effet de Pauli appliqué, et une fois avec l'atténuation PEC appliquée.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  L'exécution de cet exemple prend environ 10 minutes sur un processeur Heron r2.\n",
        "</Admonition>\n",
        "\n",
        "<span id=\"set-up-the-circuit\" />\n",
        "\n",
        "### Mettre en place le circuit\n",
        "\n",
        "Choisissez un backend et préparez un circuit de 10 qubits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "f9e93b2c-154a-4d09-872d-f770bcc669c4",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/executor-examples/extracted-outputs/f9e93b2c-154a-4d09-872d-f770bcc669c4-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 10,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit_ibm_runtime import QiskitRuntimeService, Executor\n",
        "from qiskit_ibm_runtime.quantum_program import QuantumProgram\n",
        "from qiskit.circuit import QuantumCircuit, Parameter\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from samplomatic.transpiler import generate_boxing_pass_manager\n",
        "from samplomatic import build\n",
        "\n",
        "# Initialize the service and choose a backend\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(operational=True, simulator=False)\n",
        "\n",
        "# Prepare a circuit\n",
        "\n",
        "num_qubits = 10\n",
        "num_layers = 10\n",
        "\n",
        "qubits = list(range(num_qubits))\n",
        "circuit = QuantumCircuit(num_qubits)\n",
        "\n",
        "for layer_idx in range(num_layers):\n",
        "    circuit.rx(Parameter(f\"theta_{layer_idx}\"), qubits)\n",
        "    for i in range(num_qubits // 2):\n",
        "        circuit.cz(qubits[2 * i], qubits[2 * i + 1])\n",
        "\n",
        "    circuit.rx(Parameter(f\"phi_{layer_idx}\"), qubits)\n",
        "    for i in range(num_qubits // 2 - 1):\n",
        "        circuit.cz(qubits[2 * i] + 1, qubits[2 * i + 1] + 1)\n",
        "\n",
        "circuit.draw(\"mpl\", scale=0.35, fold=100)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2d76f4f5-48b7-4123-8b6b-32eeaa06527d",
      "metadata": {},
      "source": [
        "Combinez le circuit avec son inverse pour créer un circuit miroir.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "f8ac3f75-88ca-40f9-8382-6a427303bb8e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/executor-examples/extracted-outputs/f8ac3f75-88ca-40f9-8382-6a427303bb8e-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 11,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "mirror_circuit = circuit.compose(circuit.inverse())\n",
        "mirror_circuit.measure_all()\n",
        "\n",
        "mirror_circuit.draw(\"mpl\", scale=0.35, fold=100)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2bb0692c-3d4f-4a74-807e-6b93ef4ea8d2",
      "metadata": {},
      "source": [
        "Définissez certaines valeurs de paramètres :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "c1974bff-c738-43a8-8e27-b85059e2428a",
      "metadata": {},
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "\n",
        "parameter_values = np.random.rand(mirror_circuit.num_parameters)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0ca9f203-008b-4190-9e86-affefb303938",
      "metadata": {},
      "source": [
        "Utilisez le gestionnaire de passes pour transcompiler le circuit afin d'en faire un circuit ISA.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "224e0d6d-9238-4fae-aad8-f051c7e34938",
      "metadata": {},
      "outputs": [],
      "source": [
        "preset_pass_manager = generate_preset_pass_manager(\n",
        "    backend=backend,\n",
        "    optimization_level=3,\n",
        ")\n",
        "\n",
        "isa_circuit = preset_pass_manager.run(mirror_circuit)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9dd71644-df3d-4cf3-9e4b-9c7624b54961",
      "metadata": {},
      "source": [
        "Ensuite, regroupez les portes et les mesures dans des encadrés annotés. Vous pouvez le faire manuellement ou, pour plus de commodité, utiliser la `generate_boxing_pass_manager` fonction de Samplomatic. Le premier circuit ne comportera qu'une rotation et ne nécessite donc que l'annotation `Twirl` . Le deuxième circuit sera exécuté avec une atténuation PEC complète et nécessite les `Twirl` annotations et `InjectNoise` .\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "4afb22f1-b41f-40ed-87f7-c2d0b0f6730c",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Pass manager used to create twirled-annotated boxes.\n",
        "boxing_pm = generate_boxing_pass_manager(\n",
        "    enable_gates=True,\n",
        "    enable_measures=True,\n",
        ")\n",
        "\n",
        "mirror_circuit_twirl = boxing_pm.run(isa_circuit)\n",
        "\n",
        "# Pass manager used to create a new boxed circuit with\n",
        "# both Twirl and InjectNoise annotations.\n",
        "boxing_pm = generate_boxing_pass_manager(\n",
        "    enable_gates=True,\n",
        "    enable_measures=True,\n",
        "    inject_noise_targets=\"gates\",  # no measurement mitigation\n",
        "    inject_noise_strategy=\"uniform_modification\",\n",
        ")\n",
        "\n",
        "mirror_circuit_pec = boxing_pm.run(isa_circuit)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bd0c7cc5-48ba-47ab-84bc-41f832af3d8d",
      "metadata": {},
      "source": [
        "<span id=\"learn-the-noise\" />\n",
        "\n",
        "### Apprenez à reconnaître ce bruit\n",
        "\n",
        "Afin de réduire au minimum le nombre d'expériences d'apprentissage du bruit, identifiez les instructions uniques présentes dans le deuxième circuit (celui dont les cases sont annotées d'un `InjectNoise`). Pour définir l'unicité, deux instructions de boîte sont considérées comme égales si les deux conditions suivantes sont remplies :\n",
        "\n",
        "* Leur contenu est identique, jusqu'aux portes à un seul qubit.\n",
        "* Leur `Twirl` annotation est identique (toutes les autres annotations sont ignorées).\n",
        "\n",
        "Cela donne lieu à trois instructions distinctes, à savoir les cases « porte paire » et « porte impaire », ainsi que la case de mesure finale.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "2f8b325a-ffa4-447a-bf32-8b26b7404b0a",
      "metadata": {},
      "outputs": [],
      "source": [
        "from samplomatic.utils import find_unique_box_instructions\n",
        "\n",
        "unique_box_instructions = find_unique_box_instructions(\n",
        "    mirror_circuit_pec.data\n",
        ")\n",
        "assert len(unique_box_instructions) == 3"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7d496c90-fb07-49e6-a233-451ad4306102",
      "metadata": {},
      "source": [
        "`NoiseLearnerV3`Lancez une session, sélectionnez les paramètres d'apprentissage en configurant les options correspondantes, puis exécutez une tâche d'apprentissage du bruit.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "d69204bb-4beb-4b31-b9dd-e8923889685e",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_ibm_runtime.noise_learner_v3 import NoiseLearnerV3\n",
        "\n",
        "learner = NoiseLearnerV3(backend)\n",
        "\n",
        "learner.options.shots_per_randomization = 128\n",
        "learner.options.num_randomizations = 32\n",
        "learner.options.layer_pair_depths = [0, 1, 2, 4, 16, 32]\n",
        "\n",
        "learner_job = learner.run(unique_box_instructions)\n",
        "\n",
        "learner_job.job_id()\n",
        "learner_result = learner_job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "efe80acb-f12d-4051-84ed-d61a5a93ca23",
      "metadata": {},
      "source": [
        "Convertissez `result` l'objet en celui requis par le samplex à l'aide de la `result.to_dict` méthode.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "fd63ad99-01ad-492b-9232-91f2377f97f6",
      "metadata": {},
      "outputs": [],
      "source": [
        "noise_maps = learner_result.to_dict(\n",
        "    instructions=unique_box_instructions, require_refs=False\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "89dd2022-db07-46f6-8737-644aa070dcdb",
      "metadata": {},
      "source": [
        "<span id=\"execute-the-circuits\" />\n",
        "\n",
        "### Effectuez les circuits\n",
        "\n",
        "`Executor` exécute `QuantumProgram` des objets. Chacune `QuantumProgram` peut contenir plusieurs *éléments*, qui sont ajoutés au programme. Chaque élément correspond à une tâche que le programme doit effectuer.\n",
        "\n",
        "Lancez un programme vide qui demande `1000` des captures d'écran pour chaque configuration de chaque élément.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "id": "b48b038e-6e7d-4a6a-8f9a-df1389b644fa",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_ibm_runtime.quantum_program import QuantumProgram\n",
        "\n",
        "# Initialize an empty QuantumProgram\n",
        "program = QuantumProgram(shots=1000)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "845a9fdb-6837-4bda-925c-8795613bb708",
      "metadata": {},
      "source": [
        "Ensuite, créez le circuit modèle et le samplex pour `mirror_circuit_twirl` et ajoutez-les au programme. Demandez `900` également des échantillons aléatoires à partir du samplex. Cela signifie que le samplex générera `900` des ensembles de paramètres, et que chaque ensemble sera exécuté `1000` un certain nombre de fois (le nombre de passes) dans le QPU.\n",
        "\n",
        "Il s'agit de la première tâche du programme (résultat 0).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "id": "38942fab-f68d-44ed-b613-362b38a1ca02",
      "metadata": {},
      "outputs": [],
      "source": [
        "template_twirl, samplex_twirl = build(mirror_circuit_twirl)\n",
        "\n",
        "program.append_samplex_item(\n",
        "    template_twirl,\n",
        "    samplex=samplex_twirl,\n",
        "    samplex_arguments={\"parameter_values\": parameter_values},\n",
        "    shape=(900,),\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a30d1536-5339-4f19-b351-1c26891a4817",
      "metadata": {},
      "source": [
        "De même, ajoutez le circuit modèle et le samplex créés pour `mirror_circuit_pec`, en demandant `900` des randomisations.  Il s'agit de la deuxième tâche du programme (résultat 1).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "16bbb410-b0b7-4011-b4d0-62ffbad30f41",
      "metadata": {},
      "outputs": [],
      "source": [
        "template_pec, samplex_pec = build(mirror_circuit_pec)\n",
        "\n",
        "program.append_samplex_item(\n",
        "    template_pec,\n",
        "    samplex=samplex_pec,\n",
        "    samplex_arguments={\n",
        "        \"parameter_values\": parameter_values,\n",
        "        \"pauli_lindblad_maps\": noise_maps,\n",
        "        \"noise_scales\": {\n",
        "            ref: -1.0 for ref in noise_maps\n",
        "        },  # Set the scales to -1 for PEC\n",
        "    },\n",
        "    shape=(900,),\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "abf9d679-0262-4447-b889-9b06ad3cd77d",
      "metadata": {},
      "source": [
        "Importer `Executor` et envoyer un travail.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "id": "6231e441-87f4-480a-886a-5fdd83631e60",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Twirl result keys:\n",
            " ['meas', 'measurement_flips.meas']\n",
            "\n",
            "Shape of results: (900, 1000, 10)\n",
            "PEC result keys:\n",
            " ['meas', 'measurement_flips.meas', 'pauli_signs']\n",
            "\n",
            "Shape of results: (900, 1000, 10)\n"
          ]
        }
      ],
      "source": [
        "from qiskit_ibm_runtime.executor import Executor\n",
        "\n",
        "executor = Executor(backend)\n",
        "executor_job = executor.run(program)\n",
        "\n",
        "executor_job.job_id()\n",
        "\n",
        "executor_results = executor_job.result()\n",
        "executor_results\n",
        "\n",
        "twirl_result = executor_results[0]\n",
        "\n",
        "print(f\"Twirl result keys:\\n {list(twirl_result.keys())}\\n\")\n",
        "print(f\"Shape of results: {twirl_result['meas'].shape}\")\n",
        "\n",
        "pec_result = executor_results[1]\n",
        "\n",
        "print(f\"PEC result keys:\\n {list(pec_result.keys())}\\n\")\n",
        "print(f\"Shape of results: {pec_result['meas'].shape}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "021b944c-5119-4554-b4e9-2af1cfc906d8",
      "metadata": {},
      "source": [
        "<span id=\"analyze-results\" />\n",
        "\n",
        "### Analyser les résultats\n",
        "\n",
        "Enfin, on effectue un post-traitement des résultats afin d'estimer les valeurs attendues des opérateurs de Pauli-Z à un qubit agissant sur chacun des dix qubits actifs (valeur attendue : `1.0`).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "id": "a24c1dd9-7f29-40b0-87ad-25c2a03e0431",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Qubit 0 -> 0.77\n",
            "Qubit 1 -> 0.76\n",
            "Qubit 2 -> 0.66\n",
            "Qubit 3 -> 0.71\n",
            "Qubit 4 -> 0.69\n",
            "Qubit 5 -> 0.67\n",
            "Qubit 6 -> 0.62\n",
            "Qubit 7 -> 0.59\n",
            "Qubit 8 -> 0.62\n",
            "Qubit 9 -> 0.68\n"
          ]
        }
      ],
      "source": [
        "# Undo measurement twirling\n",
        "twirl_result_unflipped = (\n",
        "    twirl_result[\"meas\"] ^ twirl_result[\"measurement_flips.meas\"]\n",
        ")\n",
        "\n",
        "# Calculate the expectation values of single-qubit Z operators\n",
        "exp_vals = 1 - 2 * twirl_result_unflipped.mean(axis=1).mean(axis=0)\n",
        "\n",
        "for qubit, val in enumerate(exp_vals):\n",
        "    print(f\"Qubit {qubit} -> {np.round(val, 2)}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "id": "8aa25d47-c4fd-4b20-a36f-fa69d7bd0971",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Qubit 0 -> 0.98\n",
            "Qubit 1 -> 0.99\n",
            "Qubit 2 -> 0.96\n",
            "Qubit 3 -> 0.98\n",
            "Qubit 4 -> 0.98\n",
            "Qubit 5 -> 0.98\n",
            "Qubit 6 -> 0.98\n",
            "Qubit 7 -> 0.95\n",
            "Qubit 8 -> 0.95\n",
            "Qubit 9 -> 0.94\n"
          ]
        }
      ],
      "source": [
        "# Undo measurement twirling\n",
        "pec_result_unflipped = (\n",
        "    pec_result[\"meas\"] ^ pec_result[\"measurement_flips.meas\"]\n",
        ")\n",
        "\n",
        "# Calculate the signs for PEC mitigation\n",
        "signs = np.prod((-1) ** pec_result[\"pauli_signs\"], axis=-1)\n",
        "signs = signs.reshape((signs.shape[0], 1))\n",
        "\n",
        "# Calculate the expectation values of single-qubit Z operators as required by\n",
        "# PEC mitigation\n",
        "exp_vals = 1 - (2 * pec_result_unflipped.mean(axis=1) * signs).mean(axis=0)\n",
        "\n",
        "for qubit, val in enumerate(exp_vals):\n",
        "    print(f\"Qubit {qubit} -> {np.round(val, 2)}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cf25d17a-5e90-4e24-a3bf-c86f5bc3444b",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Etapes suivantes\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recommandations\">\n",
        "  * Consultez la présentation générale [de la diffusion](/docs/guides/primitive-input-output#broadcasting).\n",
        "  * Découvrez comment utiliser [les options d'Executor](/docs/guides/executor-options).\n",
        "  * Comprendre le [modèle d'exécution dirigée](/docs/guides/directed-execution-model).\n",
        "  * Consultez la [documentation de Samplomatic](https://qiskit.github.io/samplomatic/).\n",
        "  * Découvrez comment combiner différentes techniques d'atténuation des erreurs lors de l'utilisation du modèle d'exécution dirigée dans le tutoriel «[ Annulation probabiliste des erreurs avec cônes de lumière ombrés](https://qiskit.github.io/qiskit-addon-slc/tutorials/01_getting_started.html) ».\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
}