{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "1fd07edc-2356-49d3-bf35-6e4e1256b61b",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Entrées et sorties de l'échantillonneur\"\n",
        "description: \"Comprendre les formats d'entrée et de sortie des primitives Sampler\"\n",
        "---\n",
        "\n",
        "<span id=\"sampler-inputs-and-outputs\" />\n",
        "\n",
        "# Entrées et sorties de l'échantillonneur\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fcd633c9-366b-440f-8997-7c60692e5a4d",
      "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 tenant compte des exigences suivantes.\n",
        "    Nous vous recommandons d'utiliser ces versions ou des versions plus récentes.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.5.1\n",
        "    qiskit-ibm-runtime~=0.47.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "672f7038-64e7-42cc-9936-c30a03596791",
      "metadata": {},
      "source": [
        "Cette page présente une vue d'ensemble des entrées et sorties de la primitive « Sampler `qiskit-ibm-runtime` », qui exécute des charges de travail sur le service de calcul IBM Quantum®. Sampler vous permet de définir efficacement des charges de travail vectorisées à l'aide d'une structure de données appelée « [**PUB » (bloc unifié primitif)**](/docs/guides/primitive-input-output#pubs). Ils servent d'entrées à la méthode [`run()`](/docs/api/qiskit-ibm-runtime/sampler-v2#run) de la primitive « Sampler », qui exécute la charge de travail définie sous forme de tâche. Ensuite, une fois la tâche terminée, les résultats sont renvoyés dans un format qui dépend à la fois des PUB utilisés et des options d'exécution spécifiées au niveau de la primitive.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0115445a-d695-4806-8a9a-6bcd2451e418",
      "metadata": {},
      "source": [
        "<span id=\"inputs\" />\n",
        "\n",
        "## Entrées\n",
        "\n",
        "Chaque « PUB » se présente sous la forme suivante :\n",
        "\n",
        "(`<single circuit>`, `<one or more optional parameter value>`, `<optional shots>`),\n",
        "\n",
        "Il peut y avoir plusieurs `parameter values` éléments, et chaque élément peut être soit un tableau, soit un paramètre unique, selon le circuit choisi. De plus, les données saisies doivent comporter des mesures.\n",
        "\n",
        "Pour la primitive Sampler, une instance de type « PUB » peut contenir au maximum trois valeurs :\n",
        "\n",
        "* Un circuit unique `QuantumCircuit`, pouvant contenir un ou plusieurs [`Parameter`](/docs/api/qiskit/qiskit.circuit.Parameter) objets\n",
        "  *Remarque : ces circuits doivent également inclure des instructions de mesure pour chacun des qubits à échantillonner.*\n",
        "* Ensemble de valeurs de paramètres permettant de lier le circuit à $\\theta_k$ (nécessaire uniquement si des `Parameter` objets doivent être liés lors de l'exécution)\n",
        "* (Facultatif) un nombre de mesures pour analyser le circuit\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f2314472-55e7-4f31-824e-31b18179e18d",
      "metadata": {},
      "source": [
        "***\n",
        "\n",
        "Le code suivant présente un exemple d'ensemble d'entrées vectorisées pour la `Sampler` primitive et les exécute sur un backend IBM® en tant qu'objet `RuntimeJobV2 ` unique.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "21687f88-51fc-4139-91b0-3fb4542716ca",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.circuit import (\n",
        "    Parameter,\n",
        "    QuantumCircuit,\n",
        "    ClassicalRegister,\n",
        "    QuantumRegister,\n",
        ")\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit.primitives.containers import BitArray\n",
        "\n",
        "from qiskit_ibm_runtime import (\n",
        "    QiskitRuntimeService,\n",
        "    SamplerV2 as Sampler,\n",
        ")\n",
        "\n",
        "import numpy as np\n",
        "\n",
        "# Instantiate runtime service and get\n",
        "# the least busy backend\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(operational=True, simulator=False)\n",
        "\n",
        "# Define a circuit with two parameters.\n",
        "circuit = QuantumCircuit(2)\n",
        "circuit.h(0)\n",
        "circuit.cx(0, 1)\n",
        "circuit.ry(Parameter(\"a\"), 0)\n",
        "circuit.rz(Parameter(\"b\"), 0)\n",
        "circuit.cx(0, 1)\n",
        "circuit.h(0)\n",
        "circuit.measure_all()\n",
        "\n",
        "# Transpile the circuit\n",
        "pm = generate_preset_pass_manager(optimization_level=1, backend=backend)\n",
        "transpiled_circuit = pm.run(circuit)\n",
        "layout = transpiled_circuit.layout\n",
        "\n",
        "# Now define a sweep over parameter values, the last axis of dimension 2 is\n",
        "# for the two parameters \"a\" and \"b\"\n",
        "params = np.vstack(\n",
        "    [\n",
        "        np.linspace(-np.pi, np.pi, 100),\n",
        "        np.linspace(-4 * np.pi, 4 * np.pi, 100),\n",
        "    ]\n",
        ").T\n",
        "\n",
        "sampler_pub = (transpiled_circuit, params)\n",
        "\n",
        "# Instantiate the new Sampler object, then run the transpiled circuit\n",
        "# using the set of parameters and observables.\n",
        "sampler = Sampler(mode=backend)\n",
        "job = sampler.run([sampler_pub])\n",
        "result = job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9f1a6c43-a00c-421f-b11d-62d3237f1ccb",
      "metadata": {},
      "source": [
        "<span id=\"outputs\" />\n",
        "\n",
        "## Sorties\n",
        "\n",
        "Une fois qu'un ou plusieurs PUB ont été envoyés à une QPU pour exécution et qu'une tâche s'est achevée avec succès, les données sont renvoyées sous la forme d'un objet [`PrimitiveResult`](/docs/api/qiskit/qiskit.primitives.PrimitiveResult) conteneur accessible en appelant la `RuntimeJobV2.result()` méthode. L'objet `PrimitiveResult` contient une liste itérable [`SamplerPubResult`](/docs/api/qiskit/qiskit.primitives.SamplerPubResult) d'objets qui renferment les résultats d'exécution pour chaque PUB. Ces données constituent des échantillons de la sortie du circuit.\n",
        "\n",
        "Chaque élément de cette liste correspond à une PUB soumise à la méthode `run()` de la primitive (par exemple, une tâche soumise avec 20 PUB renverra un `PrimitiveResult` objet contenant une liste de 20 `SamplerPubResult` objets, chacun correspondant à une PUB ).\n",
        "\n",
        "Chaque `SamplerPubResult` objet possède à la fois un attribut `data` et un `metadata` attribut.\n",
        "\n",
        "* L'attribut `data` est un champ personnalisé [`DataBin`](/docs/api/qiskit/qiskit.primitives.DataBin) qui contient les valeurs de mesure réelles, les écarts-types, etc. Les conteneurs de données sont des objets de type dictionnaire qui contiennent un élément `BitArray` par `ClassicalRegister` dans le circuit.\n",
        "* Cette `BitArray` classe sert de conteneur pour les données de prise de vue classées par ordre. Il stocke les chaînes de bits échantillonnées sous forme d'octets dans un tableau bidimensionnel. L'axe le plus à gauche de ce tableau couvre les images classées par ordre, tandis que l'axe le plus à droite couvre les octets.\n",
        "* L'attribut `metadata` contient des informations sur les options d'exécution utilisées (expliquées plus loin dans la section «[ Métadonnées du résultat](#result-metadata) » de cette page).\n",
        "\n",
        "Voici une représentation schématique de la structure `PrimitiveResult` de données :\n",
        "\n",
        "```\n",
        "    └── PrimitiveResult\n",
        "        ├── SamplerPubResult[0]\n",
        "        │   ├── metadata\n",
        "        │   └── data  ## In the form of a DataBin object\n",
        "        │       ├── NAME_OF_CLASSICAL_REGISTER\n",
        "        │       │   └── BitArray of count data (default is 'meas')\n",
        "        |       |\n",
        "        │       └── NAME_OF_ANOTHER_CLASSICAL_REGISTER\n",
        "        │           └── BitArray of count data (exists only if more than one\n",
        "        |                 ClassicalRegister was specified in the circuit)\n",
        "        ├── SamplerPubResult[1]\n",
        "        |   ├── metadata\n",
        "        |   └── data  ## In the form of a DataBin object\n",
        "        |       └── NAME_OF_CLASSICAL_REGISTER\n",
        "        |           └── BitArray of count data for second pub\n",
        "        ├── ...\n",
        "        ├── ...\n",
        "        └── ...\n",
        "```\n",
        "\n",
        "En termes simples, une tâche renvoie un [`PrimitiveResult`](/docs/api/qiskit/qiskit.primitives.PrimitiveResult) objet et contient une liste d'un ou plusieurs [`SamplerPubResult`](/docs/api/qiskit/qiskit.primitives.SamplerPubResult) objets. Ces `SamplerPubResult` objets stockent ensuite les données de mesure pour chaque PUB ion soumise au travail.\n",
        "\n",
        "À titre d'exemple, examinons le circuit à dix qubits suivant :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "e42b2fd8-0790-4a38-9082-f2334440e411",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Databin: DataBin(meas=BitArray(<shape=(), num_shots=4096, num_bits=10>))\n",
            "\n",
            "BitArray: BitArray(<shape=(), num_shots=4096, num_bits=10>)\n",
            "\n",
            "The shape of register `meas` is (4096, 2).\n",
            "\n",
            "The bytes in register `alpha`, shot by shot:\n",
            "[[  3 255]\n",
            " [  0   0]\n",
            " [  0   1]\n",
            " ...\n",
            " [  3   0]\n",
            " [  0   0]\n",
            " [  3 254]]\n",
            "\n"
          ]
        }
      ],
      "source": [
        "# generate a ten-qubit GHZ circuit\n",
        "circuit = QuantumCircuit(10)\n",
        "circuit.h(0)\n",
        "circuit.cx(range(0, 9), range(1, 10))\n",
        "\n",
        "# append measurements with the `measure_all` method\n",
        "circuit.measure_all()\n",
        "\n",
        "# transpile the circuit\n",
        "transpiled_circuit = pm.run(circuit)\n",
        "\n",
        "# run the Sampler job and retrieve the results\n",
        "sampler = Sampler(mode=backend)\n",
        "job = sampler.run([transpiled_circuit])\n",
        "result = job.result()\n",
        "\n",
        "# the data bin contains one BitArray\n",
        "data = result[0].data\n",
        "print(f\"Databin: {data}\\n\")\n",
        "\n",
        "# to access the BitArray, use the key \"meas\", which is the default name of\n",
        "# the classical register when this is added by the `measure_all` method\n",
        "array = data.meas\n",
        "print(f\"BitArray: {array}\\n\")\n",
        "print(f\"The shape of register `meas` is {data.meas.array.shape}.\\n\")\n",
        "print(f\"The bytes in register `alpha`, shot by shot:\\n{data.meas.array}\\n\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5926adf1-c7db-425a-a5cf-cb97eb5fa389",
      "metadata": {},
      "source": [
        "Il peut parfois être pratique de convertir les données du format octet en chaînes `BitArray` de bits. Cette `get_count` méthode renvoie un dictionnaire qui associe des chaînes de bits au nombre de fois où elles sont apparues.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "b4eb01c9-d438-46ca-9057-4e91b7656748",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Counts: {'1111111111': 1346, '0000000000': 1754, '0000000001': 55, '1000000000': 56, '1111111110': 92, '0111111111': 23, '1011111111': 15, '0001111111': 23, '1111011011': 1, '1111111101': 45, '1111111011': 108, '1111110111': 32, '0100000000': 10, '0000000111': 21, '0011111111': 21, '1111110000': 26, '1101111111': 47, '1111011111': 23, '1111111010': 6, '1100000000': 45, '1111100000': 32, '1110000000': 21, '1111101111': 13, '0010000000': 14, '0000000011': 19, '0000000101': 2, '0000001110': 2, '0000100000': 4, '0000001111': 20, '1111111100': 22, '0000010000': 5, '1101110111': 4, '1011111101': 1, '0000000010': 15, '0000001000': 12, '1111110110': 7, '1111000000': 3, '0010000001': 1, '0111011111': 3, '1001111111': 3, '1101111011': 3, '0000011111': 16, '0000011110': 3, '0001111011': 1, '1011111011': 3, '1111110011': 4, '1111101011': 2, '0000000100': 6, '1110111111': 12, '1111111000': 17, '0000111111': 5, '0001111101': 2, '1101100000': 2, '1101110001': 1, '1000001111': 2, '1111101110': 1, '1110111101': 1, '1101111101': 2, '1110000100': 1, '0100011111': 1, '1110000010': 1, '0011111110': 2, '0111111110': 1, '1111110010': 1, '0111110111': 1, '0000000110': 1, '0101111111': 1, '1101011111': 1, '1111001111': 1, '1110011111': 1, '0011111000': 2, '1101111110': 3, '1110111110': 1, '0110000000': 2, '1110000111': 1, '0000010111': 3, '0001000000': 3, '0111101111': 1, '0000011100': 1, '1000000001': 1, '1111011010': 1, '0000001010': 1, '1111100111': 2, '1111100011': 2, '0000001101': 1, '0111001111': 1, '1111111001': 1, '1101111000': 1, '0111110000': 1, '1111000111': 1, '1010000000': 1, '0011110000': 1, '1100000001': 1, '1011001101': 1, '0000001100': 1, '1100111111': 1, '1110111011': 1, '1111011101': 1, '1000011111': 1, '1101111001': 1, '0101101111': 1, '0000011011': 1, '0000111011': 1, '0111111100': 1, '1011100000': 1, '0011111011': 1, '0000010010': 1, '1001111011': 1}\n"
          ]
        }
      ],
      "source": [
        "# optionally, convert away from the native BitArray format to a dictionary format\n",
        "counts = data.meas.get_counts()\n",
        "print(f\"Counts: {counts}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e186d055-09e7-421c-8d70-0d27e7d0edaa",
      "metadata": {},
      "source": [
        "Lorsqu'un circuit contient plusieurs registres classiques, les résultats sont stockés dans différents `BitArray` objets. L'exemple suivant modifie l'extrait précédent en divisant le registre classique en deux registres distincts :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "e81d87ce-2fd6-4498-a9a5-f3432209fccd",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "BitArray for register 'alpha': BitArray(<shape=(), num_shots=4096, num_bits=1>)\n",
            "BitArray for register 'beta': BitArray(<shape=(), num_shots=4096, num_bits=9>)\n"
          ]
        }
      ],
      "source": [
        "# generate a ten-qubit GHZ circuit with two classical registers\n",
        "circuit = QuantumCircuit(\n",
        "    qreg := QuantumRegister(10),\n",
        "    alpha := ClassicalRegister(1, \"alpha\"),\n",
        "    beta := ClassicalRegister(9, \"beta\"),\n",
        ")\n",
        "circuit.h(0)\n",
        "circuit.cx(range(0, 9), range(1, 10))\n",
        "\n",
        "# append measurements with the `measure_all` method\n",
        "circuit.measure([0], alpha)\n",
        "circuit.measure(range(1, 10), beta)\n",
        "\n",
        "# transpile the circuit\n",
        "transpiled_circuit = pm.run(circuit)\n",
        "\n",
        "# run the Sampler job and retrieve the results\n",
        "sampler = Sampler(mode=backend)\n",
        "job = sampler.run([transpiled_circuit])\n",
        "result = job.result()\n",
        "\n",
        "# the data bin contains two BitArrays, one per register, and can be accessed\n",
        "# as attributes using the registers' names\n",
        "data = result[0].data\n",
        "print(f\"BitArray for register 'alpha': {data.alpha}\")\n",
        "print(f\"BitArray for register 'beta': {data.beta}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d93dd9f5-cc43-41b0-b350-f545a14d1f38",
      "metadata": {},
      "source": [
        "<span id=\"use-bitarray-objects-for-performant-post-processing\" />\n",
        "\n",
        "### Utilisez `BitArray` des objets pour un post-traitement performant\n",
        "\n",
        "Étant donné que les tableaux offrent généralement de meilleures performances que les dictionnaires, il est conseillé d'effectuer tout traitement ultérieur directement sur les `BitArray` objets plutôt que sur des dictionnaires de comptes. Cette `BitArray` classe propose toute une série de méthodes permettant d'effectuer certaines opérations courantes de post-traitement :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "6465d11b-9e5b-4078-a1be-75229297093a",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The shape of register `alpha` is (4096, 1).\n",
            "The bytes in register `alpha`, shot by shot:\n",
            "[[0]\n",
            " [0]\n",
            " [0]\n",
            " ...\n",
            " [1]\n",
            " [0]\n",
            " [1]]\n",
            "\n",
            "The shape of register `beta` is (4096, 2).\n",
            "The bytes in register `beta`, shot by shot:\n",
            "[[  0   0]\n",
            " [  0   0]\n",
            " [  1 255]\n",
            " ...\n",
            " [  1 255]\n",
            " [  0   0]\n",
            " [  1 255]]\n",
            "\n",
            "The shape of `beta` after post-selection is (0, 2).\n",
            "The bytes in `beta` after post-selection:\n",
            "[]\n",
            "The shape of `beta` after bit-wise slicing is (4096, 1).\n",
            "The bytes in `beta` after bit-wise slicing:\n",
            "[[0]\n",
            " [0]\n",
            " [7]\n",
            " ...\n",
            " [7]\n",
            " [0]\n",
            " [7]]\n",
            "\n",
            "The shape of `beta` after shot-wise slicing is (5, 2).\n",
            "The bytes in `beta` after shot-wise slicing:\n",
            "[[  0   0]\n",
            " [  0   0]\n",
            " [  1 255]\n",
            " [  0   0]\n",
            " [  1 255]]\n",
            "\n",
            "Exp. val. for observable `SparsePauliOp(['ZZZZZZZZZ'],\n",
            "              coeffs=[1.+0.j])` is: 0.115234375\n",
            "Exp. val. for observable `SparsePauliOp(['IIIIIIIIZ'],\n",
            "              coeffs=[1.+0.j])` is: 0.02392578125\n",
            "\n",
            "The shape of the merged results is (4096, 2).\n",
            "The bytes of the merged results:\n",
            "[[  0   0]\n",
            " [  0   0]\n",
            " [  3 254]\n",
            " ...\n",
            " [  3 255]\n",
            " [  0   0]\n",
            " [  3 255]]\n",
            "\n"
          ]
        }
      ],
      "source": [
        "print(f\"The shape of register `alpha` is {data.alpha.array.shape}.\")\n",
        "print(f\"The bytes in register `alpha`, shot by shot:\\n{data.alpha.array}\\n\")\n",
        "\n",
        "print(f\"The shape of register `beta` is {data.beta.array.shape}.\")\n",
        "print(f\"The bytes in register `beta`, shot by shot:\\n{data.beta.array}\\n\")\n",
        "\n",
        "# post-select the bitstrings of `beta` based on having sampled \"1\" in `alpha`\n",
        "mask = data.alpha.array == \"0b1\"\n",
        "ps_beta = data.beta[mask[:, 0]]\n",
        "print(f\"The shape of `beta` after post-selection is {ps_beta.array.shape}.\")\n",
        "print(f\"The bytes in `beta` after post-selection:\\n{ps_beta.array}\")\n",
        "\n",
        "# get a slice of `beta` to retrieve the first three bits\n",
        "beta_sl_bits = data.beta.slice_bits([0, 1, 2])\n",
        "print(\n",
        "    f\"The shape of `beta` after bit-wise slicing is {beta_sl_bits.array.shape}.\"\n",
        ")\n",
        "print(f\"The bytes in `beta` after bit-wise slicing:\\n{beta_sl_bits.array}\\n\")\n",
        "\n",
        "# get a slice of `beta` to retrieve the bytes of the first five shots\n",
        "beta_sl_shots = data.beta.slice_shots([0, 1, 2, 3, 4])\n",
        "print(\n",
        "    f\"The shape of `beta` after shot-wise slicing is {beta_sl_shots.array.shape}.\"\n",
        ")\n",
        "print(\n",
        "    f\"The bytes in `beta` after shot-wise slicing:\\n{beta_sl_shots.array}\\n\"\n",
        ")\n",
        "\n",
        "# calculate the expectation value of diagonal operators on `beta`\n",
        "ops = [SparsePauliOp(\"ZZZZZZZZZ\"), SparsePauliOp(\"IIIIIIIIZ\")]\n",
        "exp_vals = data.beta.expectation_values(ops)\n",
        "for o, e in zip(ops, exp_vals):\n",
        "    print(f\"Exp. val. for observable `{o}` is: {e}\")\n",
        "\n",
        "# concatenate the bitstrings in `alpha` and `beta` to \"merge\" the results of the two\n",
        "# registers\n",
        "merged_results = BitArray.concatenate_bits([data.alpha, data.beta])\n",
        "print(f\"\\nThe shape of the merged results is {merged_results.array.shape}.\")\n",
        "print(f\"The bytes of the merged results:\\n{merged_results.array}\\n\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b3765ba4-ffaa-4f51-a657-1fdfb588b849",
      "metadata": {},
      "source": [
        "<span id=\"result-metadata\" />\n",
        "\n",
        "## Métadonnées des résultats\n",
        "\n",
        "Outre les résultats d'exécution, les objets `PrimitiveResult` `SamplerPubResult` et contiennent tous deux un attribut de métadonnées concernant le travail qui a été soumis. Les métadonnées contenant des informations sur toutes les publications soumises (telles que les différentes [options d'exécution](/docs/api/qiskit-ibm-runtime/options) disponibles) se trouvent dans le `PrimitiveResult.metatada`, tandis que les métadonnées spécifiques à chaque publication PUB se trouvent dans `SamplerPubResult.metadata`le.\n",
        "\n",
        "Les métadonnées des résultats du Sampler comprennent également des informations sur la durée d'exécution, appelées [*« durée*](#execution-spans) d'exécution ».\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  Dans le champ des métadonnées, les implémentations de primitives peuvent renvoyer toute information relative à l'exécution qui leur est pertinente, et aucune paire clé-valeur n'est garantie par la primitive de base. Ainsi, les métadonnées renvoyées peuvent varier selon les implémentations des primitives.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "9a40d177-917b-484a-a809-44554efcee28",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The metadata of the PrimitiveResult is:\n",
            "'execution' : {'execution_spans': ExecutionSpans([DoubleSliceSpan(<start='2026-08-01 08:21:10', stop='2026-08-01 08:21:13', size=4096>)])},\n",
            "'version' : 2,\n",
            "\n",
            "The metadata of the PubResult result is:\n",
            "'circuit_metadata' : {},\n"
          ]
        }
      ],
      "source": [
        "# Print out the results metadata\n",
        "print(\"The metadata of the PrimitiveResult is:\")\n",
        "for key, val in result.metadata.items():\n",
        "    print(f\"'{key}' : {val},\")\n",
        "\n",
        "print(\"\\nThe metadata of the PubResult result is:\")\n",
        "for key, val in result[0].metadata.items():\n",
        "    print(f\"'{key}' : {val},\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "403dd006-33ec-4bd6-ad45-857535857077",
      "metadata": {},
      "source": [
        "<span id=\"execution-spans\" />\n",
        "\n",
        "<span id=\"view-execution-spans\" />\n",
        "\n",
        "### Afficher les intervalles d'exécution\n",
        "\n",
        "Les résultats des tâches [`SamplerV2`](/docs/api/qiskit-ibm-runtime/sampler-v2) exécutées dans le service de calcul « IBM Quantum » contiennent, dans leurs métadonnées, des informations relatives à la durée d'exécution.\n",
        "Ces informations temporelles peuvent être utilisées pour définir des limites supérieure et inférieure quant à la date et l'heure auxquelles des plans spécifiques ont été exécutés sur le QPU.\n",
        "Les plans sont regroupés en « objets [`ExecutionSpan`](/docs/api/qiskit-ibm-runtime/execution-span-execution-span) », dont chacun indique une heure de début, une heure de fin et précise quels plans ont été enregistrés pendant cette période.\n",
        "\n",
        "Une fenêtre d'exécution précise quelles données ont été exécutées pendant sa durée en fournissant une [`ExecutionSpan.mask`](/docs/api/qiskit-ibm-runtime/execution-span-execution-span#mask) méthode. Cette méthode, à partir d'un index [de bloc unifié primitif ( PUB )](/docs/guides/primitive-input-output#pubs), renvoie un masque booléen qui est `True` vrai pour tous les plans exécutés pendant sa fenêtre. Les PUB sont indexés selon l'ordre dans lequel ils ont été transmis à l'appel d'exécution du Sampler. Si, par exemple, une image de fond ( PUB ) a la forme `(2, 3)` et a été traitée avec quatre passes, alors la forme du masque est `(2, 3, 4)`. Consultez la page de l'API [execution\\_span](/docs/api/qiskit-ibm-runtime/execution-span) pour plus de détails.\n",
        "\n",
        "Pour consulter les informations relatives à la durée d'exécution, examinez les métadonnées du résultat renvoyé par `SamplerV2`, qui se présente sous la forme d'un `ExecutionSpans` objet. Cet objet est un conteneur de type liste contenant des instances de sous-classes de `ExecutionSpan`, telles que `SliceSpan`.\n",
        "\n",
        "Exemple :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "480e553c-2e53-40ca-bafd-e350f173cbcc",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "ExecutionSpans([DoubleSliceSpan(<start='2026-08-01 08:21:37', stop='2026-08-01 08:21:38', size=24>)])\n"
          ]
        }
      ],
      "source": [
        "# Define two circuits, each with one parameter with two parameters.\n",
        "circuit = QuantumCircuit(2)\n",
        "circuit.h(0)\n",
        "circuit.cx(0, 1)\n",
        "circuit.ry(Parameter(\"a\"), 0)\n",
        "circuit.cx(0, 1)\n",
        "circuit.h(0)\n",
        "circuit.measure_all()\n",
        "\n",
        "\n",
        "pm = generate_preset_pass_manager(optimization_level=1, backend=backend)\n",
        "transpiled_circuit = pm.run(circuit)\n",
        "\n",
        "params = np.random.uniform(size=(2, 3)).T\n",
        "\n",
        "sampler_pub = (transpiled_circuit, params)\n",
        "\n",
        "# Instantiate the new Estimator object, then run the transpiled circuit\n",
        "# using the set of parameters and observables.\n",
        "\n",
        "job = sampler.run([sampler_pub], shots=4)\n",
        "\n",
        "result = job.result()\n",
        "spans = job.result().metadata[\"execution\"][\"execution_spans\"]\n",
        "print(spans)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "092fedcc-c4ac-4841-9846-f77b9ec90d2e",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.primitives import BitArray\n",
        "\n",
        "# Get the mask of the 1st PUB for the 0th span.\n",
        "mask = spans[0].mask(0)\n",
        "\n",
        "# Decide whether the 0th shot of parameter set (1, 2) occurred in this span.\n",
        "in_this_span = mask[2, 1, 0]\n",
        "\n",
        "# Create a new bit array containing only the PUB-1 data collected during this span.\n",
        "bits = result[0].data.meas\n",
        "filtered_data = BitArray(bits.array[mask], bits.num_bits)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2ba13f59-c804-4e3b-85c9-90f26cb68e92",
      "metadata": {},
      "source": [
        "Les intervalles d'exécution peuvent être filtrés pour inclure les informations relatives à des PUB spécifiques, sélectionnés en fonction de leurs indices :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "53dec6a3-57b9-41b0-8ebd-28c6257dd10e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "ExecutionSpans([DoubleSliceSpan(<start='2026-08-01 08:21:37', stop='2026-08-01 08:21:38', size=24>)])"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# take the subset of spans that reference data in PUBs 0 or 2\n",
        "spans.filter_by_pub([0, 2])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4f635472-60a9-4729-9880-5581fb3806f2",
      "metadata": {},
      "source": [
        "Afficher les informations générales sur l'ensemble des intervalles d'exécution :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "ba4aa14d-4182-47bf-93a6-df607fd82594",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Number of execution spans: 1\n",
            "  Start of the first span: 2026-08-01 08:21:37.606114\n",
            "     End of the last span: 2026-08-01 08:21:38.960352\n",
            "       Total duration (s): 1.354238\n"
          ]
        }
      ],
      "source": [
        "print(\"Number of execution spans:\", len(spans))\n",
        "print(\"  Start of the first span:\", spans.start)\n",
        "print(\"     End of the last span:\", spans.stop)\n",
        "print(\"       Total duration (s):\", spans.duration)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1392fbc0-0792-402c-9568-160313ab76c4",
      "metadata": {},
      "source": [
        "Extraire et inspecter une portée spécifique :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "077a74ad-2780-4c61-8310-a4821efbfa68",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            " Start of first span: 2026-08-01 08:21:37.606114\n",
            "   End of first span: 2026-08-01 08:21:38.960352\n",
            "#shots in first span: 24\n"
          ]
        }
      ],
      "source": [
        "spans.sort()\n",
        "print(\" Start of first span:\", spans[0].start)\n",
        "print(\"   End of first span:\", spans[0].stop)\n",
        "print(\"#shots in first span:\", spans[0].size)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "924e26ed-ece0-42ef-a985-ae1aaea86622",
      "metadata": {},
      "source": [
        "<Admonition type=\"note\">\n",
        "  Il est possible que des plages horaires définies par des durées d'exécution distinctes se chevauchent. Cela ne tient pas au fait qu'un QPU effectuait plusieurs exécutions simultanément, mais résulte plutôt d'un artefact lié à certains traitements classiques pouvant se produire en parallèle de l'exécution quantique. La garantie donnée est que les données concernées se sont bel et bien produites au cours de la période d'exécution indiquée, mais pas nécessairement que les limites de cette fenêtre temporelle sont aussi précises que possible.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "celltoolbar": "Raw Cell Format",
    "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
}