{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "24576595",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Noyaux quantiques avec des portes fractionnaires\"\n",
        "description: \"Utiliser des portes fractionnaires, c'est-à-dire des portes paramétrées qui exécutent directement des rotations d'angle arbitraire, afin de réduire la profondeur et la durée des circuits à noyau quantique.\"\n",
        "---\n",
        "\n",
        "<span id=\"quantum-kernels-with-fractional-gates\" />\n",
        "\n",
        "# Noyaux quantiques avec des portes fractionnaires\n",
        "\n",
        "*Estimation de l'utilisation : moins de 30 secondes sur un processeur Heron r2 (NOTE : Il s'agit uniquement d'une estimation. Votre durée d'exécution peut varier.)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "983da41e",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## Acquis d'apprentissage\n",
        "\n",
        "À l'issue de ce tutoriel, vous devriez avoir compris :\n",
        "\n",
        "* Qu'est-ce qu'une porte fractionnaire et comment permet-elle de réduire la profondeur et la durée des circuits sur les QPU d' IBM®?\n",
        "* Les contraintes liées à l'utilisation de portes fractionnaires (en particulier, la plage d'angles RZZ)\n",
        "* Comment mettre en place un workflow de noyau quantique utilisant des portes fractionnaires avec le service de calcul « IBM Quantum »\n",
        "* Comment comparer les indicateurs d'exécution matérielle (profondeur, durée, nombre de portes non locales, fidélité) avec et sans portes fractionnaires\n",
        "* Comment utiliser uniquement des portes RX fractionnaires tout en conservant le flux de travail standard de Qiskit Patterns\n",
        "\n",
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## Prérequis\n",
        "\n",
        "Nous vous recommandons de vous familiariser avec les sujets suivants avant de commencer ce tutoriel :\n",
        "\n",
        "* Le flux de travail [« Patterns »](/docs/guides/intro-to-patterns) de Qiskit\n",
        "* Guide [des portes fractionnaires](/docs/guides/fractional-gates)\n",
        "* Le tutoriel [sur l'entraînement des noyaux quantiques](/docs/tutorials/quantum-kernel-training) et la leçon consacrée [aux noyaux quantiques](/learning/courses/quantum-machine-learning/quantum-kernel-methods) du cours sur l'apprentissage automatique quantique\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "155eab76",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## Arrière-plan\n",
        "\n",
        "<span id=\"fractional-gates-on-ibm-qpus\" />\n",
        "\n",
        "### Portes fractionnaires sur les QPU d' IBM\n",
        "\n",
        "Les portes fractionnaires sont des portes quantiques paramétrées qui permettent l'exécution directe de rotations d'angle arbitraire (dans certaines limites),\n",
        "ce qui évite de devoir les décomposer en plusieurs portes de base.\n",
        "En tirant parti des interactions natives entre les qubits physiques, il est possible de mettre en œuvre certaines opérations unitaires de manière plus efficace sur le matériel.\n",
        "\n",
        "IBM Les QPU Quantum® Heron prennent en charge les portes fractionnaires suivantes :\n",
        "\n",
        "* $R_{ZZ}(\\theta)$ pour $0 < \\theta < \\pi / 2$\n",
        "* $R_X(\\theta)$ pour toute valeur réelle $\\theta$\n",
        "\n",
        "Ces portes peuvent réduire considérablement la profondeur et la durée des circuits quantiques.\n",
        "Elles sont particulièrement avantageuses dans les applications qui s'appuient fortement sur $R_{ZZ}$ et $R_X$, comme la simulation hamiltonienne, l'algorithme d'optimisation approximative quantique (QAOA) et les méthodes à noyau quantique.\n",
        "Dans ce tutoriel, nous nous concentrons sur le noyau quantique en tant qu'exemple pratique.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fe5675f3",
      "metadata": {},
      "source": [
        "<span id=\"limitations\" />\n",
        "\n",
        "### Limites\n",
        "\n",
        "Les portes fractionnaires sont actuellement une fonctionnalité expérimentale et s'accompagnent de quelques contraintes :\n",
        "\n",
        "* $R_{ZZ}$ est limitée aux angles dans l'intervalle $0 < \\theta < \\pi / 2$.\n",
        "* L'utilisation de portes fractionnaires n'est pas prise en charge pour les [circuits dynamiques](/docs/guides/classical-feedforward-and-control-flow), le [tournoiement de Pauli](/docs/guides/error-mitigation-and-suppression-techniques#pauli-twirling), l' [annulation probabiliste des erreurs](/docs/guides/error-mitigation-and-suppression-techniques#probabilistic-error-cancellation-pec) (PEC) et l' [extrapolation à bruit nul](/docs/guides/error-mitigation-and-suppression-techniques#zero-noise-extrapolation-zne) (ZNE) (à l'aide de l' [amplification probabiliste des erreurs](/docs/guides/error-mitigation-and-suppression-techniques#probabilistic-error-amplification-pea) (PEA)).\n",
        "\n",
        "Les portes fractionnées nécessitent un flux de travail différent par rapport à l'approche standard.\n",
        "Ce tutoriel explique comment travailler avec des portes fractionnaires à travers une application pratique.\n",
        "\n",
        "Pour plus de détails sur les portes fractionnaires, voir ce qui suit.\n",
        "\n",
        "* [Portes fractionnaires](/docs/guides/fractional-gates)\n",
        "* [Quand *ne* pas utiliser les portes fractionnaires](/docs/guides/fractional-gates#when-not-to-use)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a4bdab87",
      "metadata": {},
      "source": [
        "<span id=\"workflow-approaches-for-the-rzz-angle-constraint\" />\n",
        "\n",
        "### Approches de workflow pour la contrainte d'angle RZZ\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "db213506",
      "metadata": {},
      "source": [
        "Le processus d'utilisation des portes fractionnaires suit généralement celui défini par [les modèles Qiskit](/docs/guides/intro-to-patterns).\n",
        "La principale différence réside dans le fait que tous les angles RZZ doivent satisfaire la contrainte suivante : $0 < \\theta \\leq \\pi/2$.\n",
        "Il existe deux approches pour s'assurer que cette condition est respectée, comme nous le verrons ci-dessous. Nous recommandons la deuxième approche, et dans ce tutoriel, nous l'illustrons à l'aide d'un exemple inspiré de la méthode du noyau quantique.\n",
        "Pour mieux comprendre dans quels contextes les noyaux quantiques sont susceptibles d'être utiles, nous vous recommandons de consulter [l'article de Liu, Arunachalam et Temme (2021)](https://www.nature.com/articles/s41567-021-01287-z).\n",
        "\n",
        "Vous pouvez également suivre le tutoriel [de formation](/docs/tutorials/quantum-kernel-training) sur les noyaux quantiques ainsi que la leçon [consacrée aux noyaux quantiques](/learning/courses/quantum-machine-learning/quantum-kernel-methods) dans le cadre du cours sur l'apprentissage automatique quantique disponible sur IBM Quantum® Learning.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5797ed7e",
      "metadata": {},
      "source": [
        "<span id=\"1-generate-parameter-values-that-satisfy-the-rzz-angle-constraint\" />\n",
        "\n",
        "#### 1. Générer des valeurs de paramètres qui satisfont la contrainte d'angle RZZ\n",
        "\n",
        "Si vous êtes sûr que tous les angles RZZ se situent dans la plage valide, vous pouvez suivre le processus standard des modèles Qiskit.\n",
        "Dans ce cas, il suffit de soumettre les valeurs des paramètres dans le cadre d'une PUB. Le processus se déroule comme suit.\n",
        "\n",
        "```python\n",
        "pm = generate_preset_pass_manager(backend=backend, ...)\n",
        "t_circuit = pm.run(circuit)\n",
        "t_observable = observable.apply_layout(t_circuit.layout)\n",
        "sampler.run([(t_circuit, parameter_values)])\n",
        "estimator.run([(t_circuit, t_observable, parameter_values)])\n",
        "```\n",
        "\n",
        "Si vous tentez de soumettre un site PUB qui comprend une porte RZZ dont l'angle n'est pas valide, vous obtiendrez un message d'erreur tel que le suivant :\n",
        "\n",
        "```\n",
        "'The instruction rzz is supported only for angles in the range [0, pi/2], but an angle (20.0) outside of this range has been requested; via parameter value(s) γ[0]=10.0, substituted in parameter expression 2.0*γ[0].'\n",
        "```\n",
        "\n",
        "Pour éviter cette erreur, utilisez la deuxième méthode décrite ci-dessous.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d3e00f37",
      "metadata": {},
      "source": [
        "<span id=\"2-assign-parameter-values-to-circuits-before-transpilation\" />\n",
        "\n",
        "#### 2. Attribuer des valeurs de paramètres aux circuits avant la transpilation\n",
        "\n",
        "Ce `qiskit-ibm-runtime` package fournit une étape de transcompilation spécialisée appelée [`FoldRzzAngle`](/docs/api/qiskit-ibm-runtime/transpiler-passes-fold-rzz-angle).\n",
        "Cette étape transforme les circuits quantiques de manière à ce que tous les angles RZZ respectent la contrainte relative à ces angles.\n",
        "Si vous fournissez le backend à `generate_preset_pass_manager` ou `transpile`, Qiskit applique `FoldRzzAngle` automatiquement aux circuits quantiques.\n",
        "Cette approche nécessite d'attribuer des valeurs de paramètres aux circuits quantiques avant la transpilation.\n",
        "Le déroulement des opérations est le suivant.\n",
        "\n",
        "```python\n",
        "pm = generate_preset_pass_manager(backend=backend, ...)\n",
        "b_circuit = circuit.assign_parameters(parameter_values)\n",
        "t_circuit = pm.run(b_circuit)\n",
        "t_observable = observable.apply_layout(t_circuit.layout)\n",
        "sampler.run([(t_circuit,)])\n",
        "estimator.run([(t_circuit, t_observable)])\n",
        "```\n",
        "\n",
        "Il convient de noter que ce workflow entraîne un coût de calcul plus élevé que la première approche, car il implique d'attribuer des valeurs de paramètres aux circuits quantiques et de stocker localement les circuits associés à ces paramètres.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b7cb1bd2",
      "metadata": {},
      "source": [
        "<Admonition type=\"caution\">\n",
        "  **Veuillez noter un problème connu, décrit à l'adresse `qiskit-ibm-runtime`v0.47.0,** selon lequel, dans certains cas, des portes RZZ présentant des angles non valides peuvent subsister dans les circuits même après la transpilation.\n",
        "\n",
        "  Consultez la page [qiskit-ibm-runtime#2441](https://github.com/Qiskit/qiskit-ibm-runtime/issues/2441) pour suivre l'évolution de ce problème.\n",
        "  Nous vous recommandons d'appliquer la solution de contournement suivante jusqu'à ce que le problème soit résolu.\n",
        "\n",
        "  ```python\n",
        "  pm = generate_preset_pass_manager(backend=backend, ...)\n",
        "  pm.post_optimization = PassManager(\n",
        "      [\n",
        "          FoldRzzAngle(),\n",
        "          Optimize1qGatesDecomposition(target=backend.target),\n",
        "          RemoveIdentityEquivalent(target=backend.target),\n",
        "      ]\n",
        "  )\n",
        "  ... = pm.run(...)\n",
        "  ```\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "aaa153e7",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## Exigences\n",
        "\n",
        "Avant de commencer ce tutoriel, assurez-vous que les éléments suivants sont installés :\n",
        "\n",
        "* Qiskit SDK v2.0 ou plus tard, avec prise en charge de [la visualisation](/docs/api/qiskit/visualization)\n",
        "* Qiskit Runtime v0.41 ou version ultérieure (`pip install qiskit-ibm-runtime`)\n",
        "* Qiskit Aer v0.17 ou version ultérieure (`pip install qiskit-aer`)\n",
        "* Qiskit Basis Constructor (`pip install qiskit_basis_constructor`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5f43ce5d",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## Configuration\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "a6a15694",
      "metadata": {},
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "from qiskit import QuantumCircuit, generate_preset_pass_manager\n",
        "from qiskit.circuit import ParameterVector\n",
        "from qiskit.circuit.library import UGate, n_local, unitary_overlap\n",
        "from qiskit.transpiler import Target, PassManager\n",
        "from qiskit.transpiler.passes import (\n",
        "    Optimize1qGatesDecomposition,\n",
        "    RemoveIdentityEquivalent,\n",
        ")\n",
        "from qiskit_aer.primitives import SamplerV2 as AerSampler\n",
        "from qiskit_basis_constructor import DEFAULT_EQUIVALENCE_LIBRARY\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2\n",
        "from qiskit_ibm_runtime.transpiler.passes import FoldRzzAngle"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3e94382d",
      "metadata": {},
      "source": [
        "<span id=\"enable-fractional-gates-and-check-basis-gates\" />\n",
        "\n",
        "### Activer les portes fractionnaires et vérifier les portes de base\n",
        "\n",
        "Pour utiliser des portes fractionnaires, vous pouvez obtenir un backend qui les prend en charge en définissant l'option `use_fractional_gates=True` .\n",
        "Si le backend prend en charge les portes fractionnaires, vous verrez `rzz` et `rx` listés parmi ses portes de base.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "fd577102",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Backend: ibm_marrakesh\n",
            "No fractional gates: ['cz', 'id', 'rz', 'sx', 'x']\n",
            "With fractional gates: ['cz', 'id', 'rx', 'rz', 'rzz', 'sx', 'x']\n"
          ]
        }
      ],
      "source": [
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=133\n",
        ")  # backend should be a heron device or later\n",
        "backend_name = backend.name\n",
        "backend_c = service.backend(backend_name)  # w/o fractional gates\n",
        "backend_f = service.backend(\n",
        "    backend_name, use_fractional_gates=True\n",
        ")  # w/ fractional gates\n",
        "print(f\"Backend: {backend_name}\")\n",
        "print(f\"No fractional gates: {backend_c.basis_gates}\")\n",
        "print(f\"With fractional gates: {backend_f.basis_gates}\")\n",
        "if \"rzz\" not in backend_f.basis_gates:\n",
        "    print(f\"Backend {backend_name} does not support fractional gates\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3f11c5a3",
      "metadata": {},
      "source": [
        "<span id=\"small-scale-simulator-example\" />\n",
        "\n",
        "## Exemple de simulateur à petite échelle\n",
        "\n",
        "Dans cette section, nous allons passer en revue les quatre étapes du workflow [« Qiskit Patterns »](/docs/guides/intro-to-patterns) sur un simulateur, en prenant comme exemple concret le circuit « quantum kernel ».\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7bfd6a97",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "### Étape 1 : Mettre en correspondance les entrées classiques avec un problème quantique\n",
        "\n",
        "<span id=\"quantum-kernel-circuit\" />\n",
        "\n",
        "#### Circuit à noyau quantique\n",
        "\n",
        "Dans cette section, nous explorons le circuit du noyau quantique à l'aide de portes RZZ afin d'introduire le flux de travail pour les portes fractionnaires.\n",
        "\n",
        "Nous commençons par construire un circuit quantique pour calculer les entrées individuelles de la matrice du noyau.\n",
        "Pour ce faire, on combine des circuits de cartes de caractéristiques ZZ avec un chevauchement unitaire.\n",
        "La fonction noyau prend des vecteurs dans l'espace cartographié des caractéristiques et renvoie leur produit intérieur en tant qu'entrée de la matrice noyau : $K(x, y) = \\langle \\Phi(x) | \\Phi(y) \\rangle,$ où $|\\Phi(x)\\rangle$ représente l'état quantique représenté par les caractéristiques.\n",
        "\n",
        "Nous construisons manuellement un circuit de carte de caractéristiques ZZ à l'aide de portes RZZ.\n",
        "`zz_feature_map`Bien que Qiskit propose une fonctionnalité intégrée, il ne prend actuellement pas en charge les portes RZZ, selon la version de Qiskit disponible à l'adresse v2.4.1 ( [voir le ticket](https://github.com/Qiskit/qiskit/issues/14469) ).\n",
        "\n",
        "Ensuite, nous calculons la fonction noyau pour des entrées identiques - par exemple, $K(x, x) = 1$. Sur les ordinateurs quantiques bruyants, cette valeur peut être inférieure à 1 en raison du bruit.\n",
        "Un résultat plus proche de 1 indique un bruit plus faible dans l'exécution.\n",
        "Dans ce tutoriel, nous appelons cette valeur la *fidélité*, définie comme suit $\\text{fidelity} = K(x, x).$\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "e7d5b52a",
      "metadata": {},
      "outputs": [],
      "source": [
        "optimization_level = 2\n",
        "shots = 2000\n",
        "reps = 3\n",
        "rng = np.random.default_rng(seed=123)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "2e9ab33d",
      "metadata": {},
      "outputs": [],
      "source": [
        "def my_zz_feature_map(num_qubits: int, reps: int = 1) -> QuantumCircuit:\n",
        "    x = ParameterVector(\"x\", num_qubits * reps)\n",
        "    qc = QuantumCircuit(num_qubits)\n",
        "    qc.h(range(num_qubits))\n",
        "    for k in range(reps):\n",
        "        K = k * num_qubits\n",
        "        for i in range(num_qubits):\n",
        "            qc.rz(x[i + K], i)\n",
        "        pairs = [(i, i + 1) for i in range(num_qubits - 1)]\n",
        "        for i, j in pairs[0::2] + pairs[1::2]:\n",
        "            qc.rzz((np.pi - x[i + K]) * (np.pi - x[j + K]), i, j)\n",
        "    return qc\n",
        "\n",
        "\n",
        "def quantum_kernel(num_qubits: int, reps: int = 1) -> QuantumCircuit:\n",
        "    qc = my_zz_feature_map(num_qubits, reps=reps)\n",
        "    inner_product = unitary_overlap(qc, qc, \"x\", \"y\", insert_barrier=True)\n",
        "    inner_product.measure_all()\n",
        "    return inner_product\n",
        "\n",
        "\n",
        "def random_parameters(inner_product: QuantumCircuit) -> np.ndarray:\n",
        "    return np.tile(rng.random(inner_product.num_parameters // 2), 2)\n",
        "\n",
        "\n",
        "def fidelity(result) -> float:\n",
        "    ba = result.data.meas\n",
        "    return ba.get_int_counts().get(0, 0) / ba.num_shots"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f676ff81",
      "metadata": {},
      "source": [
        "Des circuits à noyau quantique et leurs valeurs de paramètres correspondantes sont générés pour des systèmes de 4 à 40 qubits, et leurs fidélités sont ensuite évaluées.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "24116973",
      "metadata": {},
      "outputs": [],
      "source": [
        "qubits = list(range(4, 12, 2))\n",
        "circuits = [quantum_kernel(i, reps=reps) for i in qubits]\n",
        "params = [random_parameters(circ) for circ in circuits]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "30a7c442",
      "metadata": {},
      "source": [
        "Le circuit à quatre qubits est représenté ci-dessous.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "b3d6341a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/b3d6341a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "circuits[0].draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "07f31cbe",
      "metadata": {},
      "source": [
        "Dans le flux de travail standard des modèles Qiskit, les valeurs des paramètres sont généralement transmises à l'échantillonneur ou à l'estimateur primitif dans le cadre d'une PUB.\n",
        "Toutefois, lorsqu'on utilise un backend qui prend en charge les portes fractionnaires, ces valeurs de paramètres doivent être explicitement attribuées au circuit quantique avant la transpilation.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "6c9c1977",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/6c9c1977-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "b_qc = [\n",
        "    circ.assign_parameters(param) for circ, param in zip(circuits, params)\n",
        "]\n",
        "b_qc[0].draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7513072b",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "### Étape 2 : Optimiser le problème pour l'exécution sur du matériel quantique\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "804ba317",
      "metadata": {},
      "source": [
        "Nous transpilons ensuite le circuit à l'aide du gestionnaire de passes en suivant le schéma standard de Qiskit.\n",
        "En fournissant un backend qui supporte les portes fractionnaires à `generate_preset_pass_manager`, une passe spécialisée appelée `FoldRzzAngle` est automatiquement incluse.\n",
        "Ce passage modifie le circuit pour qu'il soit conforme aux contraintes de l'angle RZZ.\n",
        "Par conséquent, les portes RZZ de la figure précédente qui avaient des valeurs négatives sont transformées en valeurs positives, et quelques portes X supplémentaires sont ajoutées.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "6054bdea",
      "metadata": {},
      "outputs": [],
      "source": [
        "backend_f = service.backend(name=backend_name, use_fractional_gates=True)\n",
        "# pm_f includes `FoldRzzAngle` pass\n",
        "pm_f = generate_preset_pass_manager(\n",
        "    optimization_level=optimization_level, backend=backend_f\n",
        ")\n",
        "pm_f.post_optimization = PassManager(\n",
        "    [\n",
        "        FoldRzzAngle(),\n",
        "        Optimize1qGatesDecomposition(target=backend_f.target),\n",
        "        RemoveIdentityEquivalent(target=backend_f.target),\n",
        "    ]\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "a18e5c70",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "OrderedDict({'rz': 35, 'rzz': 18, 'x': 13, 'rx': 9, 'measure': 4, 'barrier': 2})\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/a18e5c70-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "t_qc_f = pm_f.run(b_qc)\n",
        "print(t_qc_f[0].count_ops())\n",
        "t_qc_f[0].draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a4cd07d1",
      "metadata": {},
      "source": [
        "Pour évaluer l'impact des portes fractionnaires, nous évaluons le nombre de portes non locales (CZ et RZZ pour ce backend), ainsi que la profondeur et la durée des circuits, et nous comparons ces mesures à celles d'un flux de travail standard par la suite.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "b5bcf9ad",
      "metadata": {},
      "outputs": [],
      "source": [
        "nnl_f = [qc.num_nonlocal_gates() for qc in t_qc_f]\n",
        "depth_f = [qc.depth() for qc in t_qc_f]\n",
        "duration_f = [\n",
        "    qc.estimate_duration(backend_f.target, unit=\"u\") for qc in t_qc_f\n",
        "]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "629406cc",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### Étape 3 : Exécutez à l'aide d' Qiskit primitives\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "87926539",
      "metadata": {},
      "source": [
        "Nous exécutons le circuit transpilé avec le backend qui prend en charge les portes fractionnaires.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "a68acf11",
      "metadata": {},
      "outputs": [],
      "source": [
        "sampler_f = AerSampler.from_backend(backend_f)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "a703b939",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "085ce928-767e-4200-93bf-3905e5411cfe\n"
          ]
        }
      ],
      "source": [
        "job = sampler_f.run(t_qc_f, shots=shots)\n",
        "print(job.job_id())"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6c9fd10d",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-and-return-result-in-desired-classical-format\" />\n",
        "\n",
        "### Étape 4 : Post-traitement et restitution du résultat dans le format classique souhaité\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7a865036",
      "metadata": {},
      "source": [
        "Vous pouvez obtenir la valeur de la fonction noyau $K(x, x)$ en mesurant la probabilité de la chaîne de bits entièrement nulle `00...00` dans la sortie.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "1f0d9c51",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[0.929, 0.882, 0.8645, 0.817]\n"
          ]
        }
      ],
      "source": [
        "result = job.result()\n",
        "fidelity_f = [fidelity(result=res) for res in result]\n",
        "print(fidelity_f)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a5bcd1a8",
      "metadata": {},
      "source": [
        "<span id=\"comparison-of-workflow-and-circuit-without-fractional-gates\" />\n",
        "\n",
        "### Comparaison du flux de travail et du circuit sans portes fractionnaires\n",
        "\n",
        "Dans cette section, nous présentons le flux de travail standard de Qiskit Patterns à l'aide d'un backend qui ne prend pas en charge les portes fractionnaires.\n",
        "En comparant les circuits transpilés, vous remarquerez que la version utilisant des portes fractionnaires (présentée dans la section précédente) est plus compacte que celle qui n'en utilise pas.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "e97fd0d5",
      "metadata": {},
      "outputs": [],
      "source": [
        "# step 1: map classical inputs to quantum problem\n",
        "# `circuits` and `params` from the previous section are reused here"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "a10f2d95",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "OrderedDict({'rz': 130, 'sx': 80, 'cz': 36, 'measure': 4, 'barrier': 2})\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/a10f2d95-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 15,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# step 2: optimize circuits\n",
        "backend_c = service.backend(backend_name)  # w/o fractional gates\n",
        "pm_c = generate_preset_pass_manager(\n",
        "    optimization_level=optimization_level, backend=backend_c\n",
        ")\n",
        "t_qc_c = pm_c.run(circuits)\n",
        "print(t_qc_c[0].count_ops())\n",
        "t_qc_c[0].draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "bb3475df",
      "metadata": {},
      "outputs": [],
      "source": [
        "nnl_c = [qc.num_nonlocal_gates() for qc in t_qc_c]\n",
        "depth_c = [qc.depth() for qc in t_qc_c]\n",
        "duration_c = [\n",
        "    qc.estimate_duration(backend_c.target, unit=\"u\") for qc in t_qc_c\n",
        "]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "e8d307c0",
      "metadata": {},
      "outputs": [],
      "source": [
        "# step 3: execute\n",
        "sampler_c = AerSampler.from_backend(backend_c)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "id": "983dd26f",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "f2cca29d-7263-4976-9e51-13a91b75c3ae\n"
          ]
        }
      ],
      "source": [
        "job = sampler_c.run(pubs=zip(t_qc_c, params), shots=shots)\n",
        "print(job.job_id())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "id": "a6a6fa77",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[0.8625, 0.7605, 0.702, 0.671]\n"
          ]
        }
      ],
      "source": [
        "# step 4: post-processing\n",
        "result = job.result()\n",
        "fidelity_c = [fidelity(res) for res in result]\n",
        "print(fidelity_c)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "765a7980",
      "metadata": {},
      "source": [
        "<span id=\"comparison-of-depths-durations-and-fidelities\" />\n",
        "\n",
        "### Comparaison des niveaux de profondeur, des durées et des degrés de fidélité\n",
        "\n",
        "Dans cette section, nous comparons le nombre de portes non locales et les fidélités entre les circuits avec et sans portes fractionnaires.\n",
        "Cela met en évidence les avantages potentiels de l'utilisation de portes fractionnées en termes d'efficacité et de qualité d'exécution.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "ef343a53",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x116af3cb0>"
            ]
          },
          "execution_count": 20,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/ef343a53-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, depth_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, depth_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"depth\")\n",
        "plt.title(\"Comparison of depths\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "id": "98bb2cd0",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x11ea4f4d0>"
            ]
          },
          "execution_count": 21,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/98bb2cd0-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, duration_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, duration_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"duration (µs)\")\n",
        "plt.title(\"Comparison of durations\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "id": "1383b242",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x1247fc440>"
            ]
          },
          "execution_count": 22,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/1383b242-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, nnl_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, nnl_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"number of non-local gates\")\n",
        "plt.title(\"Comparison of numbers of non-local gates\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "id": "8b4594f5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x120b792b0>"
            ]
          },
          "execution_count": 23,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/8b4594f5-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, fidelity_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, fidelity_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"fidelity\")\n",
        "plt.title(\"Comparison of fidelities\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9f17acd5",
      "metadata": {},
      "source": [
        "<span id=\"large-scale-hardware-example\" />\n",
        "\n",
        "## Exemple de matériel à grande échelle\n",
        "\n",
        "Dans cette section, nous comparons les performances du workflow du noyau quantique, avec et sans portes fractionnaires, sur du matériel quantique comptant jusqu’à 40 qubits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fd68378c",
      "metadata": {},
      "source": [
        "<span id=\"step-1-4-combined\" />\n",
        "\n",
        "### Étapes 1 à 4 combinées\n",
        "\n",
        "Le flux de travail suit la même structure que l'exemple à petite échelle. Nous transpilons tous les circuits, qu'ils comportent ou non des portes fractionnaires, nous recueillons des métriques, puis nous soumettons ces circuits à du matériel quantique réel.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "id": "4431bf56",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "job id (w/ fractional gates): d8uasitbh0os73eqnpig\n"
          ]
        }
      ],
      "source": [
        "# -------------------------Step 1-------------------------\n",
        "qubits = list(range(4, 44, 4))\n",
        "circuits = [quantum_kernel(i, reps=reps) for i in qubits]\n",
        "params = [random_parameters(circ) for circ in circuits]\n",
        "b_qc = [\n",
        "    circ.assign_parameters(param) for circ, param in zip(circuits, params)\n",
        "]\n",
        "\n",
        "\n",
        "def benchmark(b_qc, backend):\n",
        "    # -------------------------Step 2-------------------------\n",
        "    pm = generate_preset_pass_manager(optimization_level, backend=backend)\n",
        "    if \"rzz\" in backend.target.operation_names:\n",
        "        # workaround until https://github.com/Qiskit/qiskit-ibm-runtime/issues/2441 is resolved\n",
        "        pm.post_optimization = PassManager(\n",
        "            [\n",
        "                FoldRzzAngle(),\n",
        "                Optimize1qGatesDecomposition(target=backend.target),\n",
        "                RemoveIdentityEquivalent(target=backend.target),\n",
        "            ]\n",
        "        )\n",
        "    t_qc = pm.run(b_qc)\n",
        "    nnl = [qc.num_nonlocal_gates() for qc in t_qc]\n",
        "    depth = [qc.depth() for qc in t_qc]\n",
        "    duration = [\n",
        "        qc.estimate_duration(backend_f.target, unit=\"u\") for qc in t_qc\n",
        "    ]\n",
        "\n",
        "    # -------------------------Step 3-------------------------\n",
        "    sampler = SamplerV2(mode=backend)\n",
        "    sampler.options.dynamical_decoupling.enable = True\n",
        "    sampler.options.dynamical_decoupling.sequence_type = \"XY4\"\n",
        "    sampler.options.dynamical_decoupling.skip_reset_qubits = True\n",
        "    sampler.options.environment.job_tags = [\"TUT_FG\"]\n",
        "    job = sampler.run(t_qc, shots=shots)\n",
        "    job_id = job.job_id()\n",
        "    return nnl, depth, duration, job_id\n",
        "\n",
        "\n",
        "def postprocessing(job_id: str):\n",
        "    # -------------------------Step 4-------------------------\n",
        "    job = service.job(job_id)\n",
        "    result = job.result()\n",
        "    fidelities = [fidelity(result=res) for res in result]\n",
        "    usage = job.usage()\n",
        "    return fidelities, usage\n",
        "\n",
        "\n",
        "backend_f = service.backend(backend_name, use_fractional_gates=True)\n",
        "nnl_f, depth_f, duration_f, job_id_f = benchmark(\n",
        "    b_qc, backend_f\n",
        ")  # step 2 & 3\n",
        "print(\"job id (w/ fractional gates):\", job_id_f)\n",
        "fidelity_f, usage_f = postprocessing(job_id_f)  # step 4"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "4a5d15a2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "job id (w/o fractional gates): d8uav3lposuc738pruug\n"
          ]
        }
      ],
      "source": [
        "backend_c = service.backend(backend_name, use_fractional_gates=False)\n",
        "nnl_c, depth_c, duration_c, job_id_c = benchmark(b_qc, backend_c)\n",
        "print(\"job id (w/o fractional gates):\", job_id_c)\n",
        "fidelity_c, usage_c = postprocessing(job_id_c)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9f78441e",
      "metadata": {},
      "source": [
        "Nous comparons ensuite les indicateurs.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 26,
      "id": "b409e8d3",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x12461e660>"
            ]
          },
          "execution_count": 26,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/b409e8d3-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, depth_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, depth_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"depth\")\n",
        "plt.title(\"Comparison of depths\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "id": "09f91f0f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x11f2ac980>"
            ]
          },
          "execution_count": 27,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/09f91f0f-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, duration_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, duration_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"duration (µs)\")\n",
        "plt.title(\"Comparison of durations\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 28,
      "id": "c9308517",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x125c91be0>"
            ]
          },
          "execution_count": 28,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/c9308517-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, nnl_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, nnl_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"number of non-local gates\")\n",
        "plt.title(\"Comparison of numbers of non-local gates\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 29,
      "id": "234731d4",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x11fcf6e40>"
            ]
          },
          "execution_count": 29,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/234731d4-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, fidelity_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, fidelity_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"fidelity\")\n",
        "plt.title(\"Comparison of fidelities\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d38b9fe1",
      "metadata": {},
      "source": [
        "Nous comparons le temps d'utilisation du QPU avec et sans portes fractionnaires. Les résultats de la cellule suivante montrent que les temps d'utilisation du QPU sont presque identiques.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 30,
      "id": "793326ca",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "no fractional gates: 8 seconds\n",
            "fractional gates: 8 seconds\n"
          ]
        }
      ],
      "source": [
        "print(f\"no fractional gates: {usage_c} seconds\")\n",
        "print(f\"fractional gates: {usage_f} seconds\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "efe18f80",
      "metadata": {},
      "source": [
        "<span id=\"advanced-topic-using-only-fractional-rx-gates\" />\n",
        "\n",
        "## Sujet avancé : Utilisation exclusive de portes RX fractionnaires\n",
        "\n",
        "La nécessité de modifier le flux de travail lors de l'utilisation de portes fractionnées découle principalement de la restriction des angles de porte RZZ.\n",
        "Toutefois, si vous n'utilisez que les portes RX fractionnaires et excluez les portes RZZ fractionnaires, vous pouvez continuer à suivre le flux de travail standard des motifs Qiskit.\n",
        "Cette approche peut encore offrir des avantages significatifs, en particulier dans les circuits qui comportent un grand nombre de portes RX et de portes U, en réduisant le nombre total de portes et en améliorant potentiellement les performances.\n",
        "Dans cette section, nous montrons comment optimiser vos circuits en utilisant uniquement des portes RX fractionnaires, tout en omettant les portes RZZ.\n",
        "\n",
        "Pour ce faire, nous fournissons une fonction utilitaire qui vous permet de désactiver une porte de base spécifique dans un objet Target.\n",
        "Ici, nous l'utilisons pour désactiver les portes RZZ.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "id": "ab43ba23",
      "metadata": {},
      "outputs": [],
      "source": [
        "def remove_instruction_from_target(target: Target, gate_name: str) -> Target:\n",
        "    new_target = Target(\n",
        "        description=target.description,\n",
        "        num_qubits=target.num_qubits,\n",
        "        dt=target.dt,\n",
        "        granularity=target.granularity,\n",
        "        min_length=target.min_length,\n",
        "        pulse_alignment=target.pulse_alignment,\n",
        "        acquire_alignment=target.acquire_alignment,\n",
        "        qubit_properties=target.qubit_properties,\n",
        "        concurrent_measurements=target.concurrent_measurements,\n",
        "    )\n",
        "\n",
        "    for name, qarg_map in target.items():\n",
        "        if name == gate_name:\n",
        "            continue\n",
        "        instruction = target.operation_from_name(name)\n",
        "        if qarg_map == {None: None}:\n",
        "            qarg_map = None\n",
        "        new_target.add_instruction(instruction, qarg_map, name=name)\n",
        "    return new_target"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7f689a02",
      "metadata": {},
      "source": [
        "Nous prenons comme exemple un circuit composé de portes U, CZ et RZZ.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 32,
      "id": "6b812497",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/6b812497-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 32,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = n_local(3, \"u\", \"cz\", \"linear\", reps=1)\n",
        "qc.rzz(1.1, 0, 1)\n",
        "qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fa9dc1c4",
      "metadata": {},
      "source": [
        "Nous transposons d'abord le circuit pour un backend qui ne prend pas en charge les portes fractionnaires.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "id": "9e8e0709",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "OrderedDict({'rz': 23, 'sx': 16, 'cz': 4})\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/9e8e0709-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 33,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm_c = generate_preset_pass_manager(\n",
        "    optimization_level=optimization_level, backend=backend_c\n",
        ")\n",
        "t_qc = pm_c.run(qc)\n",
        "print(t_qc.count_ops())\n",
        "t_qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bd0e24da",
      "metadata": {},
      "source": [
        "Ensuite, nous transposons le même circuit en utilisant des portes RX fractionnaires, tout en excluant les portes RZZ.\n",
        "Il en résulte une légère réduction du nombre total de portes, grâce à la mise en œuvre plus efficace des portes RX.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "id": "db45feb0",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "OrderedDict({'rz': 22, 'sx': 14, 'cz': 4, 'rx': 1})\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/db45feb0-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 34,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "backend_f = service.backend(backend_name, use_fractional_gates=True)\n",
        "target = remove_instruction_from_target(backend_f.target, \"rzz\")\n",
        "pm_f = generate_preset_pass_manager(\n",
        "    optimization_level=optimization_level,\n",
        "    target=target,\n",
        ")\n",
        "t_qc = pm_f.run(qc)\n",
        "print(t_qc.count_ops())\n",
        "t_qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "15140636",
      "metadata": {},
      "source": [
        "<span id=\"optimize-u-gates-with-fractional-rx-gates\" />\n",
        "\n",
        "### Optimiser les portes U avec des portes RX fractionnaires\n",
        "\n",
        "Dans cette section, nous démontrons comment optimiser les portes U en utilisant des portes RX fractionnaires, en nous basant sur le même circuit que celui présenté dans la section précédente.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3f73cbda",
      "metadata": {},
      "source": [
        "Nous transposons le circuit en utilisant uniquement des portes RX fractionnaires, à l'exclusion des portes RZZ.\n",
        "En introduisant une règle de décomposition personnalisée, comme indiqué ci-dessous, nous pouvons réduire le nombre de portes à un qubit nécessaires pour mettre en œuvre une porte U.\n",
        "\n",
        "Cette fonctionnalité fait actuellement l'objet de discussions dans ce [ticket](https://github.com/Qiskit/qiskit/issues/13455) sur GitHub.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 35,
      "id": "0f0c6d87",
      "metadata": {},
      "outputs": [],
      "source": [
        "# special decomposition rule for UGate\n",
        "x = ParameterVector(\"x\", 3)\n",
        "zxz = QuantumCircuit(1)\n",
        "zxz.rz(x[2] - np.pi / 2, 0)\n",
        "zxz.rx(x[0], 0)\n",
        "zxz.rz(x[1] + np.pi / 2, 0)\n",
        "DEFAULT_EQUIVALENCE_LIBRARY.add_equivalence(UGate(x[0], x[1], x[2]), zxz)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "91c824d8",
      "metadata": {},
      "source": [
        "Ensuite, nous utilisons le transpileur en nous appuyant sur `constructor-beta` la traduction fournie par le `qiskit-basis-constructor` paquet.\n",
        "Par conséquent, le nombre total de portes est réduit par rapport à la transpilation précédente.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 36,
      "id": "b19aae7c",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "OrderedDict({'rz': 16, 'rx': 9, 'cz': 4})\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/b19aae7c-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 36,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm_f = generate_preset_pass_manager(\n",
        "    optimization_level=optimization_level,\n",
        "    target=target,\n",
        "    translation_method=\"constructor-beta\",\n",
        ")\n",
        "t_qc = pm_f.run(qc)\n",
        "print(t_qc.count_ops())\n",
        "t_qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "23ad4615",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Etapes suivantes\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recommandations\">\n",
        "  Si ce travail vous a paru intéressant, les documents suivants pourraient vous intéresser :\n",
        "\n",
        "  * Guide [sur les portes fractionnaires](/docs/guides/fractional-gates)\n",
        "  * [Quand *ne* pas utiliser les portes fractionnaires](/docs/guides/fractional-gates#when-not-to-use)\n",
        "  * [`FoldRzzAngle`](/docs/api/qiskit-ibm-runtime/transpiler-passes-fold-rzz-angle) Référence de l'API du passage de transpilation\n",
        "  * Tutoriel sur [l'entraînement du noyau Quantum](/docs/tutorials/quantum-kernel-training)\n",
        "  * La leçon sur [les noyaux quantiques](/learning/courses/quantum-machine-learning/quantum-kernel-methods) dans le cours sur l'apprentissage automatique quantique\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"
    },
    "hours": 1,
    "qpuSeconds": 30
  },
  "nbformat": 4,
  "nbformat_minor": 5
}