{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "0ff6f833-f5fb-4e9e-a572-445f2ff9ad64",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Entrées et sorties primitives\"\n",
        "description: \"Comprendre les formats d'entrée et de sortie (y compris les « Primitive Unified Blocs » ou PUB) des primitives de l' Qiskit SDK\"\n",
        "---\n",
        "\n",
        "<span id=\"primitive-inputs-and-outputs\" />\n",
        "\n",
        "# Entrées et sorties primitives\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "36a00905-1855-4fce-9686-20eb01ba72b6",
      "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.5.1\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "203951dd-4da7-4e0d-93f7-3ed7e2cd624b",
      "metadata": {},
      "source": [
        "Cette page présente une vue d'ensemble des entrées et des sorties des primitives de l' Qiskit SDK. Grâce à ces primitives, vous pouvez utiliser une structure de données appelée « **PUB » (bloc unifié de** primitives) pour définir efficacement des charges de travail vectorisées. Ces PUB constituent l'unité de travail fondamentale pour l'exécution des charges de travail. Ils servent d'entrées à la méthode `run()` des primitives « Sampler » et « Estimator », qui exécutent 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 des PUB utilisés et des options éventuellement spécifiées.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c7bc7444-eada-42ec-8f9a-6ec848c40014",
      "metadata": {},
      "source": [
        "<span id=\"pubs\" />\n",
        "\n",
        "<span id=\"overview-of-pubs\" />\n",
        "\n",
        "## Aperçu des PUB\n",
        "\n",
        "Lorsqu'on appelle la `run()` méthode d'une primitive, l'argument principal requis est un tableau `list` contenant un ou plusieurs tuples — un pour chaque circuit exécuté par la primitive. Chacun de ces tuples est considéré comme une « PUB », et les éléments requis de chaque tuple de la liste dépendent de la primitive utilisée. Les données fournies à ces tuples peuvent également être organisées sous diverses formes afin d'offrir une certaine souplesse dans le traitement d'une charge de travail grâce à la diffusion — dont les règles sont décrites dans la [section suivante](#broadcasting-rules).\n",
        "\n",
        "<span id=\"estimator-pub\" />\n",
        "\n",
        "### PUB de l'estimateur\n",
        "\n",
        "Pour la primitive Estimator, le format de PUB doit contenir au maximum quatre valeurs :\n",
        "\n",
        "* Un seul `QuantumCircuit`, qui peut contenir un ou plusieurs [`Parameter`](/docs/api/qiskit/qiskit.circuit.Parameter) objets\n",
        "* Une liste d'un ou plusieurs observables, qui spécifient les valeurs d'espérance à estimer, disposées dans un tableau (par exemple, un seul observable représenté comme un tableau de 0-d, une liste d'observables comme un tableau de 1-d, et ainsi de suite). Les données peuvent être dans l'un des formats `ObservablesArrayLike` tels que `Pauli`, `SparsePauliOp`, `PauliList` ou `str`.\n",
        "  <Admonition type=\"note\">\n",
        "    Si vous avez deux observables de trajet dans des PUB différents mais avec le même circuit, ils ne seront pas estimés à l'aide de la même mesure. Chaque PUB représente une base de mesure différente, et par conséquent, des mesures distinctes sont nécessaires pour chaque PUB. Pour garantir que les observables liés aux déplacements domicile-travail sont estimés à l'aide de la même mesure, ils doivent être regroupés au sein de la même unité d' PUB.\n",
        "  </Admonition>\n",
        "* Une collection de valeurs de paramètres pour lier le circuit. Il peut être spécifié sous la forme d'un objet unique de type tableau dont le dernier index est sur les objets `Parameter` du circuit, ou être omis (ou, de manière équivalente, prendre la valeur `None`) si le circuit n'a pas d'objets `Parameter` .\n",
        "* (Optionnellement) une précision cible pour les valeurs d'espérance à estimer\n",
        "\n",
        "<span id=\"sampler-pub\" />\n",
        "\n",
        "### PUB de l'échantillonneur\n",
        "\n",
        "Pour la primitive Sampler, le format du tuple PUB contient 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",
        "* Une collection de valeurs de paramètres pour lier le circuit à $\\theta_k$ (nécessaire uniquement si des objets `Parameter` sont utilisés et doivent être liés au moment de l'exécution)\n",
        "* (Optionnellement) un nombre de prises de vue pour mesurer le circuit avec\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2bdb4618-e59f-4627-81b6-6828b40258f7",
      "metadata": {},
      "source": [
        "***\n",
        "\n",
        "Le code suivant présente un exemple d'ensemble d'entrées vectorisées pour la `Estimator` primitive.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "e84f14f0-7190-4ab6-ba49-2746c515238c",
      "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",
        "from qiskit.primitives import StatevectorEstimator\n",
        "\n",
        "\n",
        "import numpy as np\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",
        "\n",
        "# Transpile the circuit without providing a backend\n",
        "pm = generate_preset_pass_manager(optimization_level=1)\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, 10),\n",
        "        np.linspace(-4 * np.pi, 4 * np.pi, 10),\n",
        "    ]\n",
        ").T\n",
        "\n",
        "# Define three observables. The inner length-1 lists cause this array of\n",
        "# observables to have shape (3, 1), rather than shape (3,) if they were\n",
        "# omitted.\n",
        "observables = [\n",
        "    [SparsePauliOp([\"XX\", \"IY\"], [0.5, 0.5])],\n",
        "    [SparsePauliOp(\"XX\")],\n",
        "    [SparsePauliOp(\"IY\")],\n",
        "]\n",
        "# Apply the same layout as the transpiled circuit.\n",
        "observables = [\n",
        "    [observable.apply_layout(layout) for observable in observable_set]\n",
        "    for observable_set in observables\n",
        "]\n",
        "\n",
        "# Estimate the expectation value for all 300 combinations of observables\n",
        "# and parameter values, where the pub result will have shape (3, 100).\n",
        "#\n",
        "# This shape is due to our array of parameter bindings having shape\n",
        "# (100, 2), combined with our array of observables having shape (3, 1).\n",
        "estimator = StatevectorEstimator()\n",
        "estimator_pub = (transpiled_circuit, observables, params)\n",
        "\n",
        "# Run the transpiled circuit\n",
        "# using the set of parameters and observables.\n",
        "\n",
        "job = estimator.run([estimator_pub])\n",
        "result = job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3acc54a9-ab50-4155-9c2d-c6a75dba816d",
      "metadata": {},
      "source": [
        "<span id=\"broadcasting\" />\n",
        "\n",
        "<span id=\"broadcasting-rules\" />\n",
        "\n",
        "### Règles de diffusion\n",
        "\n",
        "Les PUB regroupent des éléments provenant de plusieurs tableaux (observables et valeurs de paramètres) en suivant les mêmes règles de diffusion que NumPy. Cette section résume brièvement ces règles.  Pour une explication détaillée, voir la [documentation sur les règles de diffusion à l'adresse NumPy](https://numpy.org/doc/stable/user/basics.broadcasting.html).\n",
        "\n",
        "Règles :\n",
        "\n",
        "* Les tableaux d'entrée ne doivent pas nécessairement avoir le même nombre de dimensions.\n",
        "  * Le tableau résultant aura le même nombre de dimensions que le tableau d'entrée ayant la plus grande dimension.\n",
        "  * La taille de chaque dimension est la plus grande taille de la dimension correspondante.\n",
        "  * Les dimensions manquantes sont supposées avoir la taille 1.\n",
        "* Les comparaisons de formes commencent par la dimension la plus à droite et se poursuivent vers la gauche.\n",
        "* Deux dimensions sont compatibles si leurs tailles sont égales ou si l'une d'entre elles vaut 1.\n",
        "\n",
        "Exemples de paires de tableaux qui diffusent :\n",
        "\n",
        "```text\n",
        "A1     (1d array):      1\n",
        "A2     (2d array):  3 x 5\n",
        "Result (2d array):  3 x 5\n",
        "\n",
        "\n",
        "A1     (3d array):  11 x 2 x 7\n",
        "A2     (3d array):  11 x 1 x 7\n",
        "Result (3d array):  11 x 2 x 7\n",
        "```\n",
        "\n",
        "Exemples de paires de tableaux qui ne diffusent pas :\n",
        "\n",
        "```text\n",
        "A1     (1d array):  5\n",
        "A2     (1d array):  3\n",
        "\n",
        "A1     (2d array):      2 x 1\n",
        "# The following would work if the middle dimension were 2,\n",
        "# instead of 5.\n",
        "A2     (3d array):  6 x 5 x 4\n",
        "```\n",
        "\n",
        "`Estimator` renvoie une estimation de la valeur attendue pour chaque élément de la matrice diffusée.\n",
        "\n",
        "Voici quelques exemples de modèles courants exprimés en termes de diffusion de tableaux.  Leur représentation visuelle est illustrée dans la figure suivante :\n",
        "\n",
        "Les ensembles de valeurs de paramètres sont représentés par des tableaux n x m et les tableaux d'observables sont représentés par un ou plusieurs tableaux à colonne unique. Pour chaque exemple du code précédent, les ensembles de valeurs des paramètres sont combinés avec leur tableau d'observables pour créer les estimations des valeurs attendues qui en résultent.\n",
        "\n",
        "* *Exemple 1* : (broadcast single observable) a un ensemble de valeurs de paramètres qui est un tableau 5x1 et un tableau 1x1 observables.  L'élément du tableau des observables est combiné avec chaque élément de l'ensemble des valeurs des paramètres pour créer un seul tableau 5x1 où chaque élément est une combinaison de l'élément original de l'ensemble des valeurs des paramètres avec l'élément du tableau des observables.\n",
        "\n",
        "* *Exemple 2* : (zip) a un ensemble de valeurs de paramètres 5x1 et un tableau d'observables 5x1.  Le résultat est un tableau 5x1 où chaque élément est une combinaison du nième élément de l'ensemble des valeurs des paramètres avec le nième élément du tableau des observables.\n",
        "\n",
        "* *Exemple 3* : (outer/product) possède un jeu de valeurs de paramètres 1x6 et un tableau d'observables 4x1.  Leur combinaison aboutit à un tableau 4x6 qui est créé en combinant chaque élément de l'ensemble des valeurs des paramètres avec *chaque* élément du tableau des observables, de sorte que chaque valeur de paramètre devient une colonne entière dans le résultat.\n",
        "\n",
        "* *Exemple 4* : (Standard nd generalization) a un tableau de valeurs de paramètres 3x6 et deux tableaux d'observables 3x1.  Ils se combinent pour créer deux tableaux de sortie 3x6 de la même manière que dans l'exemple précédent.\n",
        "\n",
        "![Cette image illustre plusieurs représentations visuelles de la diffusion de tableaux.](https://quantum.cloud.ibm.com/docs/images/guides/primitive-input-output/broadcasting.avif \" Représentation visuelle de la diffusion\")\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "37aa226f-d550-42fd-9ab0-60e27757722a",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Broadcast single observable\n",
        "parameter_values = np.random.uniform(size=(5,))  # shape (5,)\n",
        "observables = SparsePauliOp(\"ZZZ\")  # shape ()\n",
        "# >> pub result has shape (5,)\n",
        "\n",
        "# Zip\n",
        "parameter_values = np.random.uniform(size=(5,))  # shape (5,)\n",
        "observables = [\n",
        "    SparsePauliOp(pauli) for pauli in [\"III\", \"XXX\", \"YYY\", \"ZZZ\", \"XYZ\"]\n",
        "]  # shape (5,)\n",
        "# >> pub result has shape (5,)\n",
        "\n",
        "# Outer/Product\n",
        "parameter_values = np.random.uniform(size=(1, 6))  # shape (1, 6)\n",
        "observables = [\n",
        "    [SparsePauliOp(pauli)] for pauli in [\"III\", \"XXX\", \"YYY\", \"ZZZ\"]\n",
        "]  # shape (4, 1)\n",
        "# >> pub result has shape (4, 6)\n",
        "\n",
        "# Standard nd generalization\n",
        "parameter_values = np.random.uniform(size=(3, 6))  # shape (3, 6)\n",
        "observables = [\n",
        "    [\n",
        "        [SparsePauliOp([\"XII\"])],\n",
        "        [SparsePauliOp([\"IXI\"])],\n",
        "        [SparsePauliOp([\"IIX\"])],\n",
        "    ],\n",
        "    [\n",
        "        [SparsePauliOp([\"ZII\"])],\n",
        "        [SparsePauliOp([\"IZI\"])],\n",
        "        [SparsePauliOp([\"IIZ\"])],\n",
        "    ],\n",
        "]  # shape (2, 3, 1)\n",
        "# >> pub result has shape (2, 3, 6)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "408e47b0-24ca-45b5-b71b-080d8ccf30a6",
      "metadata": {},
      "source": [
        "<Admonition type=\"tip\" title=\"SparsePauliOp\">\n",
        "  Chaque `SparsePauliOp` compte comme un seul élément dans ce contexte, quel que soit le nombre de Paulis contenus dans le `SparsePauliOp`. Ainsi, aux fins des présentes règles de radiodiffusion, tous les éléments suivants ont la même forme :\n",
        "\n",
        "  ```text\n",
        "  a = SparsePauliOp(\"Z\") # shape ()\n",
        "  b = SparsePauliOp(\"IIIIZXYIZ\") # shape ()\n",
        "  c = SparsePauliOp.from_list([\"XX\", \"XY\", \"IZ\"]) # shape ()\n",
        "  ```\n",
        "\n",
        "  Les listes d'opérateurs suivantes, bien qu'équivalentes en termes d'informations contenues, ont des formes différentes :\n",
        "\n",
        "  ```text\n",
        "  list1 = SparsePauliOp.from_list([\"XX\", \"XY\", \"IZ\"])\n",
        "      # list1 has shape ()\n",
        "  list2 = [SparsePauliOp(\"XX\"), SparsePauliOp(\"XY\"), SparsePauliOp(\"IZ\")]\n",
        "      # list2 has shape (3, )\n",
        "  ```\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f548b270-afa7-480c-a457-c5260791d55b",
      "metadata": {},
      "source": [
        "<span id=\"overview-of-primitive-outputs\" />\n",
        "\n",
        "## Aperçu des sorties primitives\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. L'objet `PrimitiveResult` contient une liste itérable [`PubResult`](/docs/api/qiskit/qiskit.primitives.PubResult) d'objets qui renferment les résultats d'exécution pour chaque PUB. Par exemple, une tâche soumise avec 20 PUB renverra un `PrimitiveResult` objet contenant une liste de 20 éléments `PubResults`, chacun correspondant à un PUB.\n",
        "\n",
        "Chacun de ces `PubResult` objets possède à la fois un attribut `data` et un `metadata` attribut facultatif. L'attribut `data` est un objet personnalisé [`DataBin`](/docs/api/qiskit/qiskit.primitives.DataBin) qui contient les estimations de la valeur attendue dans le cas de l'Estimator, ou des échantillons de la sortie du circuit dans le cas du Sampler.\n",
        "\n",
        "Cet `data` attribut peut également contenir d'autres informations propres à la mise en œuvre, telles que les écarts-types. L'attribut `metadata` peut contenir des informations supplémentaires propres à l'implémentation concernant l'exécution de l' PUB associé.\n",
        "\n",
        "Voici un aperçu visuel de la structure des données de `PrimitiveResult` :\n",
        "\n",
        "<Tabs>\n",
        "  <TabItem value=\"estimator\" label=\"Estimator output\">\n",
        "    ```\n",
        "    └── PrimitiveResult\n",
        "        ├── PubResult[0]\n",
        "        │   ├── metadata\n",
        "        │   └── data  ## In the form of a DataBin object,\n",
        "        |       |     ## which includes data such as the following:\n",
        "        │       ├── evs\n",
        "        │       │   └── List of estimated expectation values in the shape\n",
        "        |       |         specified by the first pub\n",
        "        │       └── stds\n",
        "        │           └── List of calculated standard deviations in the\n",
        "        |                 same shape as above\n",
        "        ├── PubResult[1]\n",
        "        |   ├── metadata\n",
        "        |   └── data  ## In the form of a DataBin object,\n",
        "        |       |     ## which includes data such as the following:\n",
        "        |       ├── evs\n",
        "        |       │   └── List of estimated expectation values in the shape\n",
        "        |       |        specified by the second pub\n",
        "        |       └── stds\n",
        "        |           └── List of calculated standard deviations in the\n",
        "        |                same shape as above\n",
        "        ├── ...\n",
        "        ├── ...\n",
        "        └── ...\n",
        "    ```\n",
        "\n",
        "    <Admonition type=\"note\">\n",
        "      Ce qui précède est un exemple de données pouvant être renvoyées.  Les données effectivement renvoyées dépendent de la mise en œuvre.\n",
        "    </Admonition>\n",
        "  </TabItem>\n",
        "\n",
        "  <TabItem value=\"sampler\" label=\"Sampler output\">\n",
        "    ```\n",
        "    └── PrimitiveResult\n",
        "        ├── PubResult[0]\n",
        "        │   ├── metadata\n",
        "        │   └── data  ## In the form of a DataBin object\n",
        "        │       ├── NAME_OF_CLASSICAL_REGISTER\n",
        "        │       │   └── BitArray of count data for first PUB (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",
        "        ├── PubResult[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",
        "  </TabItem>\n",
        "</Tabs>\n",
        "\n",
        "<span id=\"estimator-output\" />\n",
        "\n",
        "### Sortie de l'estimateur\n",
        "\n",
        "Comme indiqué précédemment, les données renvoyées par `PubResult` la primitive Estimator dépendent de l'implémentation. Par exemple, il peut contenir un tableau de valeurs attendues (`PubResult.data.evs`) et d'écarts-types associés (`PubResult.data.stds`).\n",
        "\n",
        "L'extrait de code ci-dessous décrit le format `PrimitiveResult` (et le format associé `PubResult`) pour le travail créé ci-dessus.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "7b3ac687-8197-4c50-831c-a349fd8e90a2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The result of the submitted job had 1 PUB and has a value:\n",
            " PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(3, 10), dtype=float64>), stds=np.ndarray(<shape=(3, 10), dtype=float64>), shape=(3, 10)), metadata={'target_precision': 0.0, 'circuit_metadata': {}})], metadata={'version': 2})\n",
            "\n",
            "The associated PubResult of this job has the following data bins:\n",
            " DataBin(evs=np.ndarray(<shape=(3, 10), dtype=float64>), stds=np.ndarray(<shape=(3, 10), dtype=float64>), shape=(3, 10))\n",
            "\n",
            "And this DataBin has attributes: dict_keys(['evs', 'stds'])\n",
            "Recall that this shape is due to our array of parameter binding sets having shape (100, 2) -- where 2 is the number of parameters in the circuit -- combined with our array of observables having shape (3, 1).\n",
            "The expectation values measured from this PUB are: \n",
            "[[ 3.06161700e-16  4.52395120e-01  4.36594428e-01  2.16506351e-01\n",
            "   6.33718361e-01 -6.33718361e-01 -2.16506351e-01 -4.36594428e-01\n",
            "  -4.52395120e-01 -3.06161700e-16]\n",
            " [ 1.22464680e-16  6.42787610e-01  9.84807753e-01  8.66025404e-01\n",
            "   3.42020143e-01 -3.42020143e-01 -8.66025404e-01 -9.84807753e-01\n",
            "  -6.42787610e-01 -1.22464680e-16]\n",
            " [ 4.89858720e-16  2.62002630e-01 -1.11618897e-01 -4.33012702e-01\n",
            "   9.25416578e-01 -9.25416578e-01  4.33012702e-01  1.11618897e-01\n",
            "  -2.62002630e-01 -4.89858720e-16]]\n"
          ]
        }
      ],
      "source": [
        "print(\n",
        "    f\"The result of the submitted job had {len(result)} PUB and \"\n",
        "    f\"has a value:\\n {result}\\n\"\n",
        ")\n",
        "print(\n",
        "    f\"The associated PubResult of this job has the following data bins:\"\n",
        "    f\"\\n {result[0].data}\\n\"\n",
        ")\n",
        "print(f\"And this DataBin has attributes: {result[0].data.keys()}\")\n",
        "print(\n",
        "    \"Recall that this shape is due to our array of parameter binding sets \"\n",
        "    \"having shape (100, 2) -- where 2 is the number of parameters in the circuit -- \"\n",
        "    \"combined with our array of observables having shape (3, 1).\"\n",
        ")\n",
        "\n",
        "print(\n",
        "    f\"The expectation values measured from this PUB are: \\n{result[0].data.evs}\"\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "af092cd2-4388-4cb4-ba2a-a95b0d6b6c1e",
      "metadata": {},
      "source": [
        "<span id=\"sampler-output\" />\n",
        "\n",
        "### Sortie de l'échantillonneur\n",
        "\n",
        "Lorsqu'une tâche Sampler est terminée avec succès, l'objet [`PrimitiveResult`](/docs/api/qiskit/qiskit.primitives.PrimitiveResult) renvoyé contient une liste de [`SamplerPubResult`](/docs/api/qiskit/qiskit.primitives.SamplerPubResult)s, un par PUB Les compartiments de données de ces `SamplerPubResult` objets sont des objets de type dict qui contiennent un `BitArray` par `ClassicalRegister` dans le circuit.\n",
        "\n",
        "La classe `BitArray` est un conteneur pour les données de tir ordonnées. Plus précisément, il stocke les chaînes de bits échantillonnées sous forme d'octets dans un tableau à deux dimensions. L'axe le plus à gauche de ce tableau correspond aux plans ordonnés, tandis que l'axe le plus à droite correspond aux octets.\n",
        "\n",
        "En guise de premier exemple, examinons le circuit à dix qubits suivant :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "f2902d44-e97e-450f-9290-e9a8e1a5b287",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Databin: DataBin(meas=BitArray(<shape=(), num_shots=1024, num_bits=10>))\n",
            "\n",
            "BitArray: BitArray(<shape=(), num_shots=1024, num_bits=10>)\n",
            "\n",
            "The shape of register `meas` is (1024, 2).\n",
            "\n",
            "The bytes in register `alpha`, shot by shot:\n",
            "[[  3 255]\n",
            " [  0   0]\n",
            " [  0   0]\n",
            " ...\n",
            " [  0   0]\n",
            " [  0   0]\n",
            " [  0   0]]\n",
            "\n"
          ]
        }
      ],
      "source": [
        "from qiskit.primitives import StatevectorSampler\n",
        "\n",
        "# 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",
        "sampler = StatevectorSampler()\n",
        "\n",
        "# run the Sampler job and retrieve the results\n",
        "\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": "8d7e1188-d7a9-4e1a-a783-25e49a5fa1a2",
      "metadata": {},
      "source": [
        "Il peut parfois être pratique de convertir les données au 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": 5,
      "id": "0eb3a383-30cd-4a32-8d8d-740264587079",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Counts: {'1111111111': 517, '0000000000': 507}\n"
          ]
        }
      ],
      "source": [
        "# optionally convert the native BitArray format to a dictionary format\n",
        "counts = data.meas.get_counts()\n",
        "print(f\"Counts: {counts}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f02341ca-4d0f-421b-9817-47f7b339d057",
      "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": 6,
      "id": "5b294da8-b6b2-4313-aa98-efa4a1903ba4",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "BitArray for register 'alpha': BitArray(<shape=(), num_shots=1024, num_bits=1>)\n",
            "BitArray for register 'beta': BitArray(<shape=(), num_shots=1024, 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",
        "\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": "e384e005-24fe-4d7a-922a-39ae0d9089ab",
      "metadata": {},
      "source": [
        "<span id=\"leveraging-bitarray-objects-for-performant-post-processing\" />\n",
        "\n",
        "#### Exploitation `BitArray` d'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 post-traitement directement sur les `BitArray` objets plutôt que sur les dictionnaires de comptages. La `BitArray` classe propose toute une gamme de méthodes permettant d'effectuer certaines opérations courantes de post-traitement :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "44c7ee14-2b22-488e-bc58-164099855210",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The shape of register `alpha` is (1024, 1).\n",
            "The bytes in register `alpha`, shot by shot:\n",
            "[[1]\n",
            " [0]\n",
            " [1]\n",
            " ...\n",
            " [0]\n",
            " [1]\n",
            " [1]]\n",
            "\n",
            "The shape of register `beta` is (1024, 2).\n",
            "The bytes in register `beta`, shot by shot:\n",
            "[[  1 255]\n",
            " [  0   0]\n",
            " [  1 255]\n",
            " ...\n",
            " [  0   0]\n",
            " [  1 255]\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 (1024, 1).\n",
            "The bytes in `beta` after bit-wise slicing:\n",
            "[[7]\n",
            " [0]\n",
            " [7]\n",
            " ...\n",
            " [0]\n",
            " [7]\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",
            "[[  1 255]\n",
            " [  0   0]\n",
            " [  1 255]\n",
            " [  0   0]\n",
            " [  0   0]]\n",
            "\n",
            "Exp. val. for observable `SparsePauliOp(['ZZZZZZZZZ'],\n",
            "              coeffs=[1.+0.j])` is: 0.01171875\n",
            "Exp. val. for observable `SparsePauliOp(['IIIIIIIIZ'],\n",
            "              coeffs=[1.+0.j])` is: 0.01171875\n",
            "\n",
            "The shape of the merged results is (1024, 2).\n",
            "The bytes of the merged results:\n",
            "[[  3 255]\n",
            " [  0   0]\n",
            " [  3 255]\n",
            " ...\n",
            " [  0   0]\n",
            " [  3 255]\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\n",
        "# of the two 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": "6863da3a-77bd-4b7c-ac95-e5b4dd116180",
      "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` `PubResult` et contiennent un attribut de métadonnées facultatif concernant le travail qui a été soumis. Les métadonnées renvoyées (le cas échéant) dépendent de l'implémentation.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "5c08eeaa-8857-4fb6-aa8d-c4916f7354e8",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The metadata of the PrimitiveResult is:\n",
            "'version' : 2,\n",
            "\n",
            "The metadata of the PubResult result is:\n",
            "'shots' : 1024,\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": "75c67c45-102e-41dd-aebc-9e139b71a02f",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Etapes suivantes\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recommandations\">\n",
        "  * Consultez l'API [des primitives d' Qiskit SDK.](/docs/api/qiskit/primitives)\n",
        "  * Consultez l'API [des primitives de Qiskit Aer](https://qiskit.github.io/qiskit-aer/apidocs/aer_primitives.html).\n",
        "  * En savoir plus sur les [primitives de l' IBM Quantum.](/docs/guides/qiskit-runtime-primitives)\n",
        "  * Consultez l'API [Estimator `qiskit-ibm-runtime`](/docs/api/qiskit-ibm-runtime/estimator-v2) .\n",
        "  * Consultez l'API [Sampler `qiskit-ibm-runtime`](/docs/api/qiskit-ibm-runtime/sampler-v2) .\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
}