{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "dd33e9e7-3e4c-48ea-81a9-70b74c34b130",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Transformée de Fourier quantique\"\n",
        "description: \"Découvrez la transformée de Fourier quantique et son utilisation en tant que sous-programme dans des algorithmes tels que l'estimation de phase quantique.\"\n",
        "---\n",
        "\n",
        "<span id=\"quantum-fourier-transform\" />\n",
        "\n",
        "# Transformée de Fourier quantique\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a920f884-f6b0-46fd-a4ef-126f9c281f17",
      "metadata": {},
      "source": [
        "Pour ce module Qiskit in Classrooms, les étudiants doivent disposer d'un environnement Python fonctionnel avec les paquets suivants installés :\n",
        "\n",
        "* `qiskit` v2.1.0 ou plus récent\n",
        "* `qiskit-ibm-runtime` v0.40.1 ou plus récent\n",
        "* `qiskit-aer` v0.17.0 ou plus récent\n",
        "* `qiskit.visualization`\n",
        "* `numpy`\n",
        "* `pylatexenc`\n",
        "\n",
        "Pour configurer et installer les paquets ci-dessus, voir le guide d' [installation de Qiskit](/docs/guides/install-qiskit).\n",
        "Afin d'exécuter des tâches sur de véritables ordinateurs quantiques, les étudiants devront créer un compte sur IBM Quantum® en suivant les étapes du guide [Configurer votre compte IBM Cloud](/docs/guides/cloud-setup).\n",
        "\n",
        "Ce module a été testé et a utilisé 13 secondes de temps QPU. Il s'agit d'une estimation de bonne foi; votre utilisation réelle peut varier.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "46231c35-a3f5-4b04-83c5-6f15d6a5785c",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Uncomment and modify this line as needed to install dependencies\n",
        "#!pip install 'qiskit>=2.1.0' 'qiskit-ibm-runtime>=0.40.1' 'qiskit-aer>=0.17.0' 'numpy' 'pylatexenc'"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d77edd39-2574-41bb-9338-13d139f1a6a9",
      "metadata": {},
      "source": [
        "<span id=\"introduction\" />\n",
        "\n",
        "## Présentation\n",
        "\n",
        "La transformée de Fourier est un outil omniprésent qui trouve des applications dans les mathématiques, la physique, le traitement des signaux, la compression des données et d'innombrables autres domaines. Une version *quantique* de la transformée de Fourier, appelée à juste titre transformée de Fourier quantique, constitue la base de certains des algorithmes quantiques les plus importants.\n",
        "\n",
        "Aujourd'hui, après un rappel de la transformée de Fourier classique, nous verrons comment mettre en œuvre la transformée de Fourier quantique sur un ordinateur quantique. Nous examinerons ensuite l'une des applications de la transformée de Fourier quantique à un algorithme appelé algorithme d'estimation de phase. L'estimation de la phase quantique est un sous-programme du célèbre algorithme de factorisation de Shor, qui est parfois considéré comme le \"joyau de la couronne\" de l'informatique quantique. Ce module s'inscrit dans le prolongement d'un autre module consacré à l'algorithme de Shor, mais il est également conçu pour être autonome. La transformée de Fourier quantique est un algorithme fascinant et utile en soi!\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "24e8de09-0876-46cd-9346-c0d46ffce8a9",
      "metadata": {},
      "source": [
        "<span id=\"the-classical-fourier-transform\" />\n",
        "\n",
        "## La transformée de Fourier classique\n",
        "\n",
        "Avant d'aborder la transformée de Fourier quantique, rappelons d'abord la version classique. La transformée de Fourier est une méthode de transformation d'une \"base\" en une autre. Vous pouvez considérer les deux bases comme des perspectives différentes du même problème - ce sont toutes deux des façons valables d'exprimer une fonction, mais l'une ou l'autre peut être plus éclairante, en fonction du problème en question. Quelques exemples de paires de bases reliées par la transformée de Fourier sont la position et la quantité de mouvement, ainsi que le temps et la fréquence.\n",
        "\n",
        "Voyons comment la transformée de Fourier peut nous aider à déterminer la note jouée par un instrument à partir de sa forme d'onde audio. En général, les formes d'onde sont représentées dans le temps, c'est-à-dire que l'amplitude de l'onde est exprimée en fonction du temps.\n",
        "\n",
        "![Signal sinusoïdal unique tracé en fonction du temps.](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/qft/Cnote.avif)\n",
        "\n",
        "Nous pouvons transformer cette forme d'onde en Fourier pour passer de la base temporelle à la base fréquentielle :\n",
        "\n",
        "![Spectre de fréquence de la forme d'onde audio. Un pic net et clair à 260 Hz.](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/qft/Cnotefreq.avif)\n",
        "\n",
        "Dans la base de fréquence, nous pouvons facilement voir un pic clair à environ 260 Hz. C'est un do du milieu!\n",
        "\n",
        "Vous auriez pu déterminer qu'un do du milieu était joué sans utiliser de transformée de Fourier, mais qu'en est-il si plusieurs notes sont jouées en même temps? La forme d'onde se complique ensuite lorsque nous la représentons dans le temps :\n",
        "\n",
        "![Graphique du déplacement en fonction du temps de plusieurs ondes sinusoïdales à la fois, créant un motif périodique plus complexe.](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/qft/Cchord.avif)\n",
        "\n",
        "Mais le spectre de fréquences identifie clairement trois pics :\n",
        "\n",
        "![Spectre de fréquence de la forme d'onde audio ci-dessus. Trois pics à environ 260 Hz, 330 Hz et 392 Hz. Le dernier pic est très faible, mais visible.](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/qft/Cchordfreq.avif)\n",
        "\n",
        "Il s'agissait d'un accord de do majeur, jouant les notes do, mi et sol.\n",
        "\n",
        "Ce type d'analyse de Fourier peut nous aider à extraire les composantes de fréquence de n'importe quel type de signal compliqué.\n",
        "\n",
        "<span id=\"discrete-fourier-transform\" />\n",
        "\n",
        "### Transformée de Fourier discrète\n",
        "\n",
        "La transformée de Fourier est utile pour un grand nombre d'applications de traitement des signaux. Mais dans la plupart de ces applications réelles (y compris l'exemple de la musique que nous avons utilisé ci-dessus), nous voulons transformer un ensemble discret de points de données $N$ - et non une fonction continue. Dans ce cas, nous utilisons la transformée de Fourier *discrète*. La transformée de Fourier discrète (DFT) agit sur un vecteur $(x_0, ..., x_{N-1})$ et le fait correspondre au vecteur $(y_0, ..., y_{N-1})$ selon la formule suivante :\n",
        "\n",
        "$y_k = \\frac{1}{\\sqrt{N}}\\sum_{j=0}^{N-1}x_j\\omega_N^{jk}$\n",
        "\n",
        "où nous prenons $\\omega_N^{jk} = e^{2\\pi i \\frac{jk}{N}}$. (Notez qu'il existe d'autres conventions qui utilisent le signe moins dans l'exponentielle, alors soyez prudent lorsque vous voyez la TFD dans la nature) Rappelons que $e^{2\\pi i \\frac{jk}{N}}$ est une fonction périodique, de période $\\frac{N}{k}$. Ainsi, en multipliant par cette fonction, la transformée de Fourier est essentiellement un moyen de décomposer la fonction (discrète) $\\{x_{j}\\}$ en une combinaison linéaire des fonctions périodiques qui la composent, chacune ayant une période $\\frac{N}{k}$.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e1271322-48e3-47e1-90e1-7cf7117ccd7c",
      "metadata": {},
      "source": [
        "<span id=\"the-quantum-fourier-transform\" />\n",
        "\n",
        "## La transformée de Fourier quantique\n",
        "\n",
        "Nous avons vu comment la transformée de Fourier est utilisée pour représenter une fonction comme une combinaison linéaire d'un nouvel ensemble de \"fonctions de base\" Les transformations de base sont également effectuées régulièrement sur les états des qubits. Par exemple, l'état d'un qubit unique $|\\psi\\rangle$ peut être exprimé dans la base de calcul $|\\psi\\rangle = c_0 |0\\rangle + c_1 |1\\rangle$, avec les états de base $|0\\rangle$ et $|1\\rangle$, ou dans la base $X$ $|\\psi\\rangle = c_+ |+\\rangle + c_- |-\\rangle$ avec les états de base $|+\\rangle = \\frac{1}{\\sqrt{2}} (|0\\rangle + |1\\rangle)$ et $|-\\rangle = \\frac{1}{\\sqrt{2}} (|0\\rangle - |1\\rangle)$. Les deux sont également valables, mais l'une peut être plus naturelle que l'autre, en fonction du type de problème que vous essayez de résoudre.\n",
        "\n",
        "Les états de Qubit peuvent également être exprimés dans la base de Fourier, où un état est exprimé en termes de combinaison linéaire des états de la base de Fourier $|\\phi_y\\rangle$, plutôt que des états de la base de calcul habituelle, $|x\\rangle$. Pour ce faire, vous devez appliquer une transformée de Fourier quantique (QFT) :\n",
        "\n",
        "$ | \\phi_y \\rangle =  \\frac{1}{\\sqrt{N}}\\sum_{x=0}^{N-1}\\omega_N^{y x} \\vert x \\rangle$\n",
        "\n",
        "avec $\\omega_N^{yx} = e^{\\frac{2\\pi i y x}{N}}$ comme ci-dessus, et $N$ est le nombre d'états de base dans votre système quantique. Notez que, puisque nous travaillons désormais avec des qubits, $m$ qubits vous donne $2^m$ états de base, donc $N=2^m$. Ici, les états de base sont écrits sous la forme d'un seul nombre $|x\\rangle$ où $x$ varie de $0$ à $N-1$, mais vous verrez plus souvent les états de base exprimés sous la forme $|00...00\\rangle$, $|00...01\\rangle$, $|00...11\\rangle$,..., $|11...11\\rangle$, où chaque chiffre binaire représente l'état du qubit 0 à $m-1$, de droite à gauche. Il existe un moyen simple de convertir ces états binaires en un seul nombre : il suffit de les traiter comme des nombres binaires! Ainsi, $|00...00\\rangle = |0\\rangle$, $|00...01\\rangle = |1\\rangle$, $|00...10\\rangle = |2\\rangle$, $|00...11\\rangle = |3\\rangle$, et ainsi de suite, jusqu'à $|11...11\\rangle = |2^m -1\\rangle = |N-1\\rangle$.\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "07d09c65-9ba8-41cb-983d-b5dd33d99458",
      "metadata": {},
      "source": [
        "<span id=\"build-intuition-for-the-fourier-basis-states\" />\n",
        "\n",
        "### Développer l'intuition pour les états de base de Fourier\n",
        "\n",
        "Nous venons de voir ce que sont les états de la base de calcul et comment ils sont ordonnés : il s'agit de l'ensemble des états où chaque qubit est soit dans $0$ soit dans $1$, et nous les ordonnons de l'état où tous les qubits sont $0$, $|00...00\\rangle$, à l'état où ils sont tous $1$, $|11...11\\rangle$.\n",
        "\n",
        "Mais comment donner un sens aux états de la base de *Fourier*? Tous les états de base de Fourier sont des superpositions égales de tous les états de base de calcul, mais chaque état diffère de l'autre par la périodicité de la *phase des* composants. Pour comprendre cela plus concrètement, examinons les quatre états de la base de Fourier d'un système à deux qubits. L'état de Fourier le plus bas est celui dont la phase ne varie pas du tout :\n",
        "\n",
        "$|\\phi_0\\rangle = \\frac{1}{2} (|00\\rangle + |01\\rangle + |10\\rangle + |11\\rangle)$\n",
        "\n",
        "Nous pouvons visualiser cet état en traçant l'amplitude complexe de chacun des termes. La ligne rouge guide l'œil pour montrer comment la phase de cette amplitude s'enroule autour du plan complexe en fonction de l'état de la base de calcul. Pour $|\\phi_0\\rangle$, la phase reste constante :\n",
        "\n",
        "![Diagramme à barres de l'amplitude complexe (plan x-y) pour chaque état de base de calcul (axe z) pour phi\\_0. Ils sont tous réels, et les barres pointent donc toutes vers +1 sur l'axe des x](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/qft/phi0.avif)\n",
        "\n",
        "L'état de base de Fourier suivant est celui dont les phases des composants passent une seule fois de $0$ à $2\\pi$ :\n",
        "\n",
        "$|\\phi_1\\rangle = \\frac{1}{2} (|00\\rangle + e^{i\\pi/2}|01\\rangle + e^{i\\pi}|10\\rangle + e^{3i\\pi/2}|11\\rangle) = \\frac{1}{2}(|00\\rangle + i|01\\rangle - |10\\rangle - i|11\\rangle)$\n",
        "\n",
        "Et nous pouvons voir cet enroulement dans le graphique de l'amplitude complexe en fonction de l'état de la base de calcul :\n",
        "\n",
        "![Diagramme à barres de l'amplitude complexe (plan x-y) pour chaque état de base de calcul (axe z) pour phi\\_1. La ligne rouge montre comment la phase complexe s'accumule de telle sorte qu'elle s'enroule une fois autour de 2\\pi lorsque l'on passe par tous les états de base de calcul.](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/qft/phi1.avif)\n",
        "\n",
        "Ainsi, chaque état a une phase qui est $2\\pi/4$ radians plus élevée que l'état qui le précède lorsqu'ils sont ordonnés de manière standard, puisque dans cet exemple nous avons quatre états de base ( $N=4$ ). L'état de base suivant s'enroule de 0 à 2 $\\pi$ deux fois :\n",
        "\n",
        "$|\\phi_2\\rangle = \\frac{1}{2} (|00\\rangle + e^{i\\pi}|01\\rangle + e^{2i\\pi}|10\\rangle + e^{3i\\pi}|11\\rangle) = \\frac{1}{2} (|00\\rangle - |01\\rangle + |10\\rangle - |11\\rangle)$\n",
        "\n",
        "![Diagramme à barres de l'amplitude complexe (plan x-y) pour chaque état de base de calcul (axe z) pour phi\\_2. La ligne rouge montre comment la phase complexe s'accumule de telle sorte qu'elle s'enroule deux fois autour de 2\\pi lorsque l'on passe par tous les états de base de calcul.](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/qft/phi2.avif)\n",
        "\n",
        "Enfin, la composante de Fourier la plus élevée est celle dont la phase varie le plus rapidement. Pour notre exemple avec deux qubits, c'est celui dont les phases s'enroulent de 0 à $2\\pi$ trois fois :\n",
        "\n",
        "$|\\phi_3\\rangle = \\frac{1}{2} (|00\\rangle + e^{3i\\pi/2}|01\\rangle + e^{6i\\pi/2}|10\\rangle + e^{9i\\pi/2}|11\\rangle) = \\frac{1}{2} (|00\\rangle - i|01\\rangle - |10\\rangle + i|11\\rangle)$\n",
        "\n",
        "![Diagramme à barres de l'amplitude complexe (plan x-y) pour chaque état de base de calcul (axe z) pour phi\\_3. La ligne rouge montre comment la phase complexe s'accumule de telle sorte qu'elle s'enroule autour de 2\\pi trois fois lorsque vous passez par tous les états de base de calcul.](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/qft/phi3.avif)\n",
        "\n",
        "En général, pour un état d' $m$ qubits, il y aura $2^m$ états de base de Fourier, dont la fréquence de variation de phase varie d'une valeur constante, pour $|\\phi_0\\rangle$, à une variation rapide pour $|\\phi_{2^m-1}\\rangle$, effectuant $2^m-1$ enroulements autour de $2\\pi$ sur la superposition des états. Ainsi, lorsque nous prenons une QFT d'un état quantique, nous effectuons essentiellement la même analyse de base que celle que nous avons effectuée pour la forme d'onde musicale dans l'introduction. Nous déterminons les composantes de fréquence de Fourier qui contribuent à créer l'état quantique qui nous intéresse.\n",
        "\n",
        "<span id=\"try-some-example-qfts\" />\n",
        "\n",
        "### Essayez quelques exemples de QFT\n",
        "\n",
        "Essayons de continuer à construire notre intuition de la transformée de Fourier quantique en créant un état dans la base de calcul, puis en voyant ce qui se passe lorsque nous lui appliquons la QFT. Pour l'instant, nous traiterons la QFT comme une boîte noire que nous appliquerons en utilisant le site `QFTGate` de la [bibliothèque de circuits Qiskit](/docs/guides/circuit-library) Plus tard, nous jetterons un coup d'œil sous le capot pour voir comment il est mis en œuvre.\n",
        "\n",
        "Nous commençons par charger les paquets nécessaires et par sélectionner un appareil sur lequel nous ferons fonctionner notre circuit :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "3b420ee9-fe1f-4f29-aa73-1306e7a86688",
      "metadata": {},
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "from qiskit import QuantumCircuit\n",
        "from qiskit.visualization import plot_histogram\n",
        "from qiskit.circuit.library import QFTGate"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "f93e8786-96e4-4adf-97b1-1d6c1222b3dc",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "ibm_pinguino2\n"
          ]
        }
      ],
      "source": [
        "# Load IBM Quantum Compute Service\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "\n",
        "# Load the Runtime primitive and session\n",
        "from qiskit_ibm_runtime import SamplerV2 as Sampler\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "\n",
        "# Use the least busy backend\n",
        "# backend = service.least_busy(operational=True, simulator=False, min_num_qubits = 127)\n",
        "backend = service.backend(\"ibm_pinguino2\")\n",
        "\n",
        "print(backend.name)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ea5beb2c-d7b2-4d7b-9015-02dad90d44b6",
      "metadata": {},
      "source": [
        "Si vous n'avez pas de temps disponible sur votre compte ou si vous souhaitez utiliser un simulateur pour une raison quelconque, vous pouvez exécuter la cellule ci-dessous pour configurer un simulateur qui imitera le dispositif quantique que nous avons sélectionné ci-dessus :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "7f33f044-a798-4b9c-baad-6676650cd322",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Load the backend sampler\n",
        "from qiskit.primitives import BackendSamplerV2\n",
        "\n",
        "# Load the Aer simulator and generate a noise model based on the currently-selected backend.\n",
        "from qiskit_aer import AerSimulator\n",
        "from qiskit_aer.noise import NoiseModel\n",
        "\n",
        "noise_model = NoiseModel.from_backend(backend)\n",
        "\n",
        "# Define a simulator using Aer, and use it in Sampler.\n",
        "backend_sim = AerSimulator(noise_model=noise_model)\n",
        "sampler_sim = BackendSamplerV2(backend=backend_sim)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "1d4d986a-6164-40cd-8bba-0289af2430f4",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Alternatively, load a fake backend with generic properties and define a simulator.\n",
        "from qiskit.providers.fake_provider import GenericBackendV2\n",
        "\n",
        "backend_gen = GenericBackendV2(num_qubits=18)\n",
        "sampler_gen = BackendSamplerV2(backend=backend_gen)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bce6f65e-1105-4abf-80ab-476385ff5b60",
      "metadata": {},
      "source": [
        "<span id=\"single-computational-basis-state\" />\n",
        "\n",
        "#### État de base computationnel unique\n",
        "\n",
        "Tout d'abord, essayons de transformer un seul état de base de calcul. Nous commencerons par créer un état de calcul aléatoire :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "79943d18-2d57-41f4-ba6e-9c40aca24d38",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/qft/extracted-outputs/79943d18-2d57-41f4-ba6e-9c40aca24d38-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Step 1: Map\n",
        "\n",
        "qubits = 4\n",
        "N = 2**qubits\n",
        "\n",
        "\n",
        "qc = QuantumCircuit(qubits)\n",
        "\n",
        "# flip state of random qubits to put in a random single computational basis state\n",
        "for i in range(1, qubits):\n",
        "    if np.random.randint(0, 2):\n",
        "        qc.x(i)\n",
        "\n",
        "\n",
        "# make a copy of the above circuit. (to be used when we apply the QFT in next part)\n",
        "qc_qft = qc.copy()\n",
        "\n",
        "\n",
        "qc.measure_all()\n",
        "qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "c16bbbb1-99fe-4824-b9a5-b74fa79eeedf",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/qft/extracted-outputs/c16bbbb1-99fe-4824-b9a5-b74fa79eeedf-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Step 2: Transpile\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "target = backend.target\n",
        "pm = generate_preset_pass_manager(target=target, optimization_level=3)\n",
        "\n",
        "qc_isa = pm.run(qc)\n",
        "\n",
        "# Step 3: Run the job on a real quantum computer OR try fake backend\n",
        "\n",
        "sampler = Sampler(mode=backend)\n",
        "pubs = [qc_isa]\n",
        "\n",
        "# Run the job on real quantum device\n",
        "\n",
        "job = sampler.run(pubs, shots=1000)\n",
        "res = job.result()\n",
        "counts = res[0].data.meas.get_counts()\n",
        "\n",
        "# OR Run the job on the Aer simulator with noise model from real backend\n",
        "\n",
        "# job = sampler_sim.run([qc_isa])\n",
        "# res = job.result()\n",
        "# counts = res[0].data.meas.get_counts()\n",
        "\n",
        "# Step 4: Post-Process\n",
        "plot_histogram(counts)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f3723281-56f2-42ac-afd9-44f6d0fe147b",
      "metadata": {},
      "source": [
        "Transformons maintenant cet état en transformée de Fourier avec `QFTGate`:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "51b45910-624c-40ee-ad56-d9af094490d2",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/qft/extracted-outputs/51b45910-624c-40ee-ad56-d9af094490d2-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Step 1: Map\n",
        "\n",
        "qc_qft.compose(QFTGate(qubits), inplace=True)\n",
        "qc_qft.measure_all()\n",
        "qc_qft.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "198a4223-96ab-475e-a83c-75596bf569cb",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/qft/extracted-outputs/198a4223-96ab-475e-a83c-75596bf569cb-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 10,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Step 2: Transpile\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "target = backend.target\n",
        "pm = generate_preset_pass_manager(target=target, optimization_level=3)\n",
        "\n",
        "qc_isa = pm.run(qc_qft)\n",
        "\n",
        "# Step 3: Run the job on a real quantum computer - try fake backend\n",
        "\n",
        "sampler = Sampler(mode=backend)\n",
        "pubs = [qc_isa]\n",
        "\n",
        "# Run the job on real quantum device\n",
        "\n",
        "job = sampler.run(pubs, shots=1000)\n",
        "res = job.result()\n",
        "counts = res[0].data.meas.get_counts()\n",
        "\n",
        "# OR Run the job on the Aer simulator with noise model from real backend\n",
        "\n",
        "# job = sampler_sim.run([qc_isa])\n",
        "# res = job.result()\n",
        "# counts = res[0].data.meas.get_counts()\n",
        "\n",
        "# Step 4: Post-Process\n",
        "plot_histogram(counts)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "89965746-e7d1-409f-a893-5766759a8ce3",
      "metadata": {},
      "source": [
        "Comme vous pouvez le constater, nous mesurons que les populations de chaque État sont plus ou moins égales, à quelques bruits expérimentaux et statistiques près. Ainsi, si vous prenez la QFT d'un seul état de base de calcul, le résultat est une superposition égale de tous les états. Si vous êtes familier avec les transformées de Fourier, cela ne vous surprendra probablement pas. Un principe de base qui peut nous aider à établir un lien intuitif entre une fonction et sa transformée de Fourier est que la largeur d'une fonction est inversement proportionnelle à la largeur de sa transformée de Fourier. Ainsi, quelque chose qui est très localisé dans le temps, par exemple une impulsion très courte, nécessitera une large gamme de fréquences pour générer cette impulsion. Ce signal sera très large dans l'espace de Fourier.\n",
        "\n",
        "Ce fait est en fait lié à l'incertitude quantique! Le principe d'incertitude d'Heisenberg est généralement énoncé comme suit : $\\Delta x \\Delta p \\ge \\hbar / 2 $. Ainsi, si l'incertitude sur $x$ ( $\\Delta x$ ) est petite, l'incertitude sur la quantité de mouvement ( $\\Delta p$ ) doit être grande, et vice versa. Il s'avère que la transformation de la base de position $x$ à la base de quantité de mouvement $p$ s'effectue au moyen d'une transformée de Fourier.\n",
        "\n",
        "Note : N'oubliez pas que nous mesurons les populations dans chacun des états de base, ce qui nous fait perdre des informations sur les phases relatives entre les différentes parties de la superposition. Ainsi, bien que la QFT d'un état de base de calcul unique produise la même répartition uniforme de la population sur tous les états de base, les *phases* ne seront pas nécessairement les mêmes.\n",
        "\n",
        "<span id=\"two-computational-basis-states\" />\n",
        "\n",
        "#### Deux états de base computationnels\n",
        "\n",
        "Voyons maintenant ce qui se passe lorsque nous préparons une superposition d'états de base de calcul. A quoi ressemble la transformée de Fourier dans ce cas?\n",
        "\n",
        "Choisissons la superposition :\n",
        "\n",
        "$|\\psi\\rangle = \\frac{1}{\\sqrt{2}} (|0\\rangle + |N/2\\rangle) = \\frac{1}{\\sqrt{2}} (|000...0\\rangle + |100...0\\rangle)$\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "cd0b237b-b139-451a-8170-69babdc29e56",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/qft/extracted-outputs/cd0b237b-b139-451a-8170-69babdc29e56-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 11,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Step 1: Map\n",
        "qubits = 4\n",
        "N = 2**qubits\n",
        "\n",
        "\n",
        "qc = QuantumCircuit(qubits)\n",
        "\n",
        "# To make this state, we just need to apply a Hadamard to the last qubit\n",
        "\n",
        "qc.h(qubits - 1)\n",
        "\n",
        "\n",
        "qc_qft = qc.copy()\n",
        "\n",
        "\n",
        "qc.measure_all()\n",
        "\n",
        "qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "0ad8006b-caaf-4e4c-b222-a9224d3f6af8",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/qft/extracted-outputs/0ad8006b-caaf-4e4c-b222-a9224d3f6af8-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 12,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# First, let's go through steps 2-4 for the first circuit, qc\n",
        "\n",
        "# Step 2: Transpile\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "target = backend.target\n",
        "pm = generate_preset_pass_manager(target=target, optimization_level=3)\n",
        "\n",
        "qc_isa = pm.run(qc)\n",
        "\n",
        "# Step 3: Run the job on a real quantum computer - try fake backend\n",
        "\n",
        "sampler = Sampler(mode=backend)\n",
        "pubs = [qc_isa]\n",
        "\n",
        "# Run the job on real quantum device\n",
        "\n",
        "job = sampler.run(pubs, shots=1000)\n",
        "res = job.result()\n",
        "counts = res[0].data.meas.get_counts()\n",
        "\n",
        "# OR run the job on the Aer simulator with noise model from real backend\n",
        "\n",
        "# job = sampler_sim.run([qc_isa])\n",
        "# res = job.result()\n",
        "# counts = res[0].data.meas.get_counts()\n",
        "\n",
        "# Step 4: Post-process\n",
        "plot_histogram(counts)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "93aaa06c-7de3-4c0f-950c-e48768ca50c5",
      "metadata": {},
      "source": [
        "Transformons maintenant cet état en transformée de Fourier avec `QFTGate`:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "11793bc2-53ea-4c34-aed7-06e1ce630557",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/qft/extracted-outputs/11793bc2-53ea-4c34-aed7-06e1ce630557-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 13,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Step 1: Map\n",
        "\n",
        "qc_qft.compose(QFTGate(qubits), inplace=True)\n",
        "qc_qft.measure_all()\n",
        "qc_qft.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "15b9688a-8c71-457d-87e7-8bfec6f4ee76",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/qft/extracted-outputs/15b9688a-8c71-457d-87e7-8bfec6f4ee76-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 14,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Step 2: Transpile\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "target = backend.target\n",
        "pm = generate_preset_pass_manager(target=target, optimization_level=3)\n",
        "\n",
        "qc_isa = pm.run(qc_qft)\n",
        "\n",
        "# Step 3: Run the job on a real quantum computer OR try fake backend\n",
        "\n",
        "sampler = Sampler(mode=backend)\n",
        "pubs = [qc_isa]\n",
        "\n",
        "# Run the job on real quantum device\n",
        "\n",
        "job = sampler.run(pubs, shots=1000)\n",
        "res = job.result()\n",
        "counts = res[0].data.meas.get_counts()\n",
        "\n",
        "# OR run the job on the Aer simulator with noise model from real backend\n",
        "\n",
        "# job = sampler_sim.run([qc_isa])\n",
        "# res = job.result()\n",
        "# counts = res[0].data.meas.get_counts()\n",
        "\n",
        "# Step 4: Post-process\n",
        "plot_histogram(counts)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "74008f89-5634-4e52-8061-87976888c39f",
      "metadata": {},
      "source": [
        "Celle-ci pourrait être un peu plus surprenante. Il semble que la QFT de l'état $|\\psi\\rangle = \\frac{1}{\\sqrt{2}} (|0\\rangle + |N/2\\rangle)$ soit une superposition de tous les états de base pairs. Mais si nous repensons à notre visualisation de chaque état de base $|\\phi_y\\rangle$, et à la manière dont la phase de chaque composant s'enroule autour de $2\\pi$ $y$ fois, la raison pour laquelle nous obtenons ce résultat peut devenir claire.\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Vérifiez votre compréhension\n",
        "\n",
        "En vous appuyant sur l'indice ci-dessus, expliquez pourquoi le résultat obtenu pour la théorie quantique de champ d' $|\\psi\\rangle = \\frac{1}{\\sqrt{2}} (|0\\rangle + |N/2\\rangle)$ e est conforme aux attentes.\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Réponse\">\n",
        "    L'état original a une phase relative de 0 (ou un multiple entier de $2\\pi$ ) entre les deux parties de la superposition. Nous savons donc que cet état possède des composantes de Fourier dont les phases correspondent également de cette manière : celles qui ont un déphasage nul entre le terme |0000> et le terme |1000>. Chaque état de la base de Fourier $|\\phi_y\\rangle$ est composé de termes dont la phase s'accumule à un taux de $2\\pi y/N$, ce qui signifie que, lorsqu'il est ordonné de la manière habituelle, chaque terme de la superposition a une phase de $2\\pi y/N$ supérieure à celle du terme qui le précède. Ainsi, au point médian $N/2$, nous voulons que la phase $2\\pi y/N * N/2$ soit un multiple entier de $2\\pi$, ce qui se produit lorsque $y$ est pair.\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "Quelle superposition d'états computationnelle correspondrait à une théorie quantique des champs présentant des pics pour chaque nombre binaire impair?\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Réponse\">\n",
        "    Si vous preniez la QFT de l'état $\\psi = |0\\rangle - |N/2\\rangle$, vous verriez des pics sur tous les états binaires impairs.\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "af84bf95-c211-4a58-a851-1e827a42fcdb",
      "metadata": {},
      "source": [
        "<span id=\"break-down-the-qft-algorithm\" />\n",
        "\n",
        "## Décomposer l'algorithme QFT\n",
        "\n",
        "Maintenant que nous avons mieux compris la relation entre les états des qubits dans la base de calcul et la base de Fourier, examinons l'algorithme QFT lui-même. En d'autres termes, quelles portes mettons-nous en œuvre sur l'ordinateur quantique pour réaliser cette transformation?\n",
        "\n",
        "Commençons par un qubit unique. Cela signifie que nous aurons deux états de base. QFT $_2$ transforme les états de base de calcul $|0\\rangle$ et $|1\\rangle$ en états de base de Fourier $\\phi_0$ et $\\phi_1$ :\n",
        "\n",
        "$|\\phi_0\\rangle = \\frac{1}{\\sqrt{2}}(|0\\rangle + |1\\rangle)$\n",
        "\n",
        "$|\\phi_1\\rangle = \\frac{1}{\\sqrt{2}}(|0\\rangle - |1\\rangle)$\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Vérifiez votre compréhension\n",
        "\n",
        "Utilisez l'équation de la théorie quantique des champs présentée dans la section précédente pour vérifier ces deux états de base de Fourier ci-dessus.\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Réponse\">\n",
        "    La formule générale de la QFT est la suivante :\n",
        "\n",
        "    $ | \\phi_y \\rangle =  \\frac{1}{\\sqrt{N}}\\sum_{x=0}^{N-1}\\omega_N^{y x} \\vert x \\rangle$\n",
        "\n",
        "    Pour un qubit unique ( $n=1$ ), $N=2^n=2$, et $\\omega_N^{xy} = e^{2\\pi i \\frac {y x}{2}}$. Nous avons donc\n",
        "\n",
        "    $ | \\phi_0 \\rangle = \\frac{1}{\\sqrt{2}}(e^{2\\pi i \\frac {0 \\times 0}{2}}|0\\rangle + e^{2\\pi i \\frac {0 \\times 1}{2}}|1\\rangle) = \\frac{1}{\\sqrt{2}}(|0\\rangle + |1\\rangle)$\n",
        "\n",
        "    $ | \\phi_1 \\rangle = \\frac{1}{\\sqrt{2}}(e^{2\\pi i \\frac {1 \\times 0}{2}}|0\\rangle + e^{2\\pi i \\frac {1 \\times 1}{2}}|1\\rangle) = \\frac{1}{\\sqrt{2}}(|0\\rangle - |1\\rangle)$\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "Examinez ces deux équations. Vous connaissez peut-être déjà une porte quantique qui peut être utilisée pour mettre en œuvre cette transformation. En d'autres termes, il existe une porte qui transforme les états de base de calcul $|0\\rangle$ et $|1\\rangle$ en états de base de Fourier $|\\phi_0\\rangle$ et $|\\phi_1\\rangle$. C'est une porte de Hadamard! Cela devient encore plus clair si nous introduisons une représentation matricielle de l'opération QFT $_N$ :\n",
        "\n",
        "$ \\text{QFT}_N = \\frac{1}{\\sqrt{N}} \\sum_{x=0}^{N-1} \\sum_{y=0}^{N-1} \\omega_N^{xy} \\vert x \\rangle \\langle y \\vert$\n",
        "\n",
        "Si vous n'êtes pas familier avec cette notation pour exprimer un opérateur quantique, ce n'est pas grave! Il s'agit d'une manière de représenter une matrice $N \\times N$, où $x$ et $y$ indexent les colonnes et les lignes de la matrice, de $0$ à $N-1$, et $\\omega_N^{xy}$ est la valeur de cette entrée particulière. Ainsi, l'entrée dans la 0e colonne et la 2e ligne, par exemple, serait simplement $\\omega_N^{0,2} = e^{2 \\pi i \\frac{0 \\times 2}{N}} = 1$.\n",
        "\n",
        "Dans cette représentation, chaque état de la base de calcul est associé à l'un des vecteurs de base :\n",
        "\n",
        "$$|0\\rangle =\n",
        "\\begin{pmatrix}\n",
        "1 \\\\ 0 \\\\ \\vdots \\\\ 0\n",
        "\\end{pmatrix},\n",
        "|1\\rangle =\n",
        "\\begin{pmatrix}\n",
        "0 \\\\ 1 \\\\ \\vdots \\\\ 0\n",
        "\\end{pmatrix},\n",
        "|N-1\\rangle =\n",
        "\\begin{pmatrix}\n",
        "0 \\\\ 0 \\\\ \\vdots \\\\ 1\n",
        "\\end{pmatrix}.\n",
        "$$\n",
        "\n",
        "Si vous souhaitez en savoir plus sur cette représentation, consultez la leçon de John Watrous sur les systèmes multiples dans le cours sur [les bases de l'information quantique](/learning/courses/basics-of-quantum-information/multiple-systems/introduction).\n",
        "\n",
        "Essayons de construire la matrice pour la QFT $_4$. En utilisant la formule ci-dessus, nous trouvons que\n",
        "\n",
        "$\\text{QFT}_4 = \\frac{1}{2} \\begin{pmatrix}     1 & 1 & 1 & 1 \\\\     1 & i & -1 & -i \\\\     1 & -1 & 1 & -1 \\\\     1 & -i & -1 & i \\\\ \\end{pmatrix} $\n",
        "\n",
        "Pour mettre en œuvre cette matrice sur un ordinateur quantique, nous devrons déterminer quelle combinaison de portes appliquées à quels qubits nous donnera une transformation unitaire correspondant à la matrice ci-dessus. Nous connaissons déjà l'une des portes qui seront nécessaires : la porte Hadamard. Une autre porte dont nous aurons besoin est la porte à phase contrôlée, qui applique une phase relative $\\alpha$ à l'état du qubit cible, tant que le qubit de contrôle est dans l'état $|1\\rangle$. Sous forme de matrice, cela se présente comme suit :\n",
        "\n",
        "$\\text{CP}_\\alpha = \\begin{pmatrix}     1 & 0 & 0 & 0 \\\\     0 & 1 & 0 & 0 \\\\     0 & 0 & 1 & 0 \\\\     0 & 0 & 0 & e^{i\\alpha} \\\\ \\end{pmatrix} $\n",
        "\n",
        "Étant donné que seul l'état $|11\\rangle$ est modifié, le qubit considéré comme le \"contrôle\" et celui considéré comme la \"cible\" n'ont pas d'importance Le résultat sera le même dans les deux cas.\n",
        "\n",
        "Enfin, nous aurons également besoin de portes SWAP. Une porte SWAP permute les états de deux qubits. On dirait que.. :\n",
        "\n",
        "$\\text{SWAP}_\\alpha = \\begin{pmatrix}     1 & 0 & 0 & 0 \\\\     0 & 0 & 1 & 0 \\\\     0 & 1 & 0 & 0 \\\\     0 & 0 & 0 & 1 \\\\ \\end{pmatrix} $\n",
        "\n",
        "La procédure de construction d'un circuit QFT $_{2^m}$ sur les qubits $m$ est itérative - vous appliquez d'abord la QFT $_{2^{m-1}}$ aux qubits $1$ à $m-1$, puis vous ajoutez des portes entre le qubit $0$ et les autres qubits $m-1$. Mais pour appliquer la QFT $_{2^{m-1}}$, il faut d'abord appliquer la QFT $_{2^{m-2}}$ aux qubits 2 à $m-1$, puis ajouter des portes entre le qubit 1 et les qubits restants $2$ à $m-1$. C'est comme une poupée russe gigogne : chaque poupée ajoute un facteur de deux à la dimension du circuit QFT, la plus petite poupée au centre étant QFT $_2$, ou la porte de Hadamard.\n",
        "\n",
        "Pour mettre une poupée à l'intérieur de la poupée de taille immédiatement supérieure, augmentant ainsi la dimension de la QFT d'un facteur de deux, vous suivez toujours la même procédure :\n",
        "\n",
        "1. Commencez par appliquer la QFT $_{2^{m-1}}$ aux qubits $m-1$ les plus bas. Il s'agit de la \"petite poupée\" du jeu de poupées russes gigognes que vous placerez bientôt à l'intérieur de la plus grande poupée suivante.\n",
        "2. Utilisez le qubit suivant comme contrôle et appliquez des portes de phase contrôlées à chacun des qubits inférieurs ( $m-1$ ), avec des phases aux états de base standard de chacun des qubits restants ( $m-1$ ).\n",
        "3. Effectuez un Hadamard sur le même qubit supérieur qui a été utilisé comme contrôle dans les portes de phase.\n",
        "4. Utilisez les portes SWAP pour permuter l'ordre des qubits de sorte que le bit le moins significatif (en haut) devienne le bit le plus significatif (en bas), et que tous les autres soient décalés d'une unité vers le haut.\n",
        "\n",
        "Nous avons déjà utilisé la fonction `QFTGate` de la bibliothèque de circuits Qiskit, mais jetons maintenant un coup d'œil à l'intérieur de certaines de ces portes QFT pour vérifier la procédure ci-dessus. Nous pouvons le faire avec `decompose()`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "6de41e8b-2900-4600-bd35-96df80b1b409",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/qft/extracted-outputs/6de41e8b-2900-4600-bd35-96df80b1b409-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 15,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(1)\n",
        "qc.compose(QFTGate(1), inplace=True)\n",
        "qc.decompose().draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "066a1c6b-864e-4cf3-b9f1-2751b9b00998",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/qft/extracted-outputs/066a1c6b-864e-4cf3-b9f1-2751b9b00998-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 16,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(2)\n",
        "qc.compose(QFTGate(2), inplace=True)\n",
        "qc.decompose().draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "dffb70da-0107-4aeb-b433-20f4b82f6abf",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/qft/extracted-outputs/dffb70da-0107-4aeb-b433-20f4b82f6abf-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 17,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(3)\n",
        "qc.compose(QFTGate(3), inplace=True)\n",
        "qc.decompose().draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "id": "b3375193-b230-4dda-a676-ae350c3a9b93",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/qft/extracted-outputs/b3375193-b230-4dda-a676-ae350c3a9b93-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 18,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(4)\n",
        "qc.compose(QFTGate(4), inplace=True)\n",
        "qc.decompose().draw(\"mpl\")"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "0f29ce85-e9a8-4445-b3ac-5625bdca9c8a",
      "metadata": {},
      "source": [
        "J'espère qu'à partir des quatre premières QFT, vous pourrez commencer à voir comment chacune d'entre elles est imbriquée dans la plus grande suivante. Vous avez peut-être remarqué, cependant, que certaines des portes de phase ne sont pas exactement comme prescrites dans la procédure que nous avons décrite ci-dessus, et que les SWAP n'apparaissent pas après chaque sous-programme, mais plutôt à la toute fin de la QFT complète. Cela nous évite d'utiliser des portes inutiles, qui rendraient le circuit plus long et plus sujet aux erreurs. Au lieu d'implémenter le SWAP après chaque poupée imbriquée, le circuit garde une trace de l'endroit où chaque état de qubit *doit* se trouver et ajuste les qubits auxquels il applique les portes de phase en conséquence. Ensuite, une dernière série de SWAPs à la fin remet tout à sa place.\n",
        "\n",
        "<span id=\"apply-the-qft-phase-estimation\" />\n",
        "\n",
        "## Appliquer la QFT : estimation de phase\n",
        "\n",
        "Voyons comment la QFT peut être utilisée pour résoudre un problème utile en informatique quantique. Le calcul de la transformée de Fourier quantique inverse est une étape nécessaire dans un algorithme connu sous le nom d'estimation de phase quantique (QPE), qui est lui-même une sous-routine dans de nombreux autres algorithmes, y compris le \"joyau de la couronne\" des algorithmes quantiques, l'algorithme de factorisation de Shor.\n",
        "\n",
        "L'objectif du QPE est d'estimer les valeurs propres d'un opérateur unitaire. Les opérateurs unitaires sont omniprésents dans l'informatique quantique et, souvent, la recherche des valeurs propres de leurs vecteurs propres associés est une étape nécessaire dans un algorithme plus large. Selon le problème, une valeur propre peut représenter l'énergie d'un hamiltonien dans un problème de type simulation, nous aider à trouver les facteurs premiers d'un nombre dans l'algorithme de Shor ou contenir d'autres informations essentielles. QPE est l'un des sous-programmes les plus importants et les plus largement utilisés en informatique quantique.\n",
        "\n",
        "Quel est donc le rapport avec la transformée de Fourier quantique? Comme vous vous en souvenez peut-être, toute valeur propre $\\lambda$ d'un opérateur unitaire a une magnitude $|\\lambda| = 1$. Nous pouvons donc écrire chaque valeur propre comme un nombre complexe de magnitude un :\n",
        "\n",
        "$\\lambda = e^{2\\pi i \\theta}$\n",
        "\n",
        "où $\\theta$ est un nombre réel compris entre 0 et 1. Si vous souhaitez plus d'informations sur les matrices unitaires, consultez [la leçon de John Watrous sur le sujet](/learning/courses/basics-of-quantum-information/multiple-systems/quantum-information) dans Principes de base de l'information quantique.\n",
        "\n",
        "Notez que $\\lambda$ est *périodique* dans $\\theta$. Cela pourrait déjà vous suggérer qu'une QFT pourrait être impliquée, puisque nous avons vu à quel point les QFT sont utiles pour analyser les fonctions périodiques. Ci-dessous, nous allons parcourir l'algorithme et voir précisément comment la QFT entre en jeu.\n",
        "\n",
        "<span id=\"how-qpe-works\" />\n",
        "\n",
        "### Comment fonctionne QPE?\n",
        "\n",
        "Nous commencerons par l'algorithme QPE le plus simple, qui estime grossièrement la phase avec une précision d'un seul chiffre binaire. En d'autres termes, cet algorithme peut faire la distinction entre $\\theta = 0 $ et $\\theta = 1/2$, mais ne peut pas faire mieux. Voici le schéma du circuit :\n",
        "\n",
        "![Schéma de l'algorithme QPE pour un qubit de données unique. Un Hadamard est appliqué au qubit de données. Ensuite, l'algorithme utilise un autre qubit auxiliaire, sur lequel une porte U contrôlée est appliquée, avec le qubit de données comme contrôle. Après un autre Hadamard sur le qubit 0, les qubits sont mesurés.](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/qft/QPE1qubit.avif)\n",
        "\n",
        "Les qubits sont préparés dans l'état $|\\pi_0\\rangle = |\\psi\\rangle|0\\rangle$, où le qubit $0$ est dans l'état $|0\\rangle$ et les qubits restants sont dans l'état $|\\psi\\rangle$, qui est un état propre de $U$. Après le premier Hadamard, l'état du qubit devient :\n",
        "\n",
        "$|\\pi_1\\rangle = \\frac{1}{\\sqrt{2}}|\\psi\\rangle (|0\\rangle + |1\\rangle)$\n",
        "\n",
        "La porte suivante est une porte \"contrôlée - $U$ \". Ceci applique l'opération unitaire $U$ aux qubits inférieurs qui sont dans l'état $|\\psi\\rangle$ si le qubit 0 est dans l'état $|1\\rangle$, mais ne fait rien à $|\\psi\\rangle$ si le qubit 0 est dans l'état $|0\\rangle$. Cela transforme les qubits en état :\n",
        "\n",
        "$|\\pi_2\\rangle = \\frac{1}{\\sqrt{2}}( |\\psi\\rangle|0\\rangle + e^{2\\pi i \\theta}|\\psi\\rangle|1\\rangle)$\n",
        "$=  \\frac{1}{\\sqrt{2}}|\\psi\\rangle (|0\\rangle + e^{2\\pi i \\theta}|1\\rangle)$\n",
        "\n",
        "Il vient de se passer quelque chose d'étrange : la porte contrôlée $U$ n'utilise que le qubit $0$ comme qubit de contrôle, de sorte que l'on pourrait penser que cette porte ne modifierait pas du tout l'état du qubit 0. Mais d'une manière ou d'une autre, c'est le cas! Même si l'opération a été appliquée aux qubits inférieurs, l'effet global de la porte est de changer la phase du qubit $0$. Ce mécanisme est connu sous le nom de \"phase kickback\" et est utilisé dans de nombreux algorithmes quantiques, y compris les algorithmes de Deutsch-Josza et de Grover. Si vous souhaitez en savoir plus sur le mécanisme de rétroaction en phase, consultez la leçon de John Watrous sur les [algorithmes de requête quantique](/learning/courses/fundamentals-of-quantum-algorithms/quantum-query-algorithms/deutsch-algorithm) dans Fundamentals of quantum algorithms (principes de base des algorithmes quantiques).\n",
        "\n",
        "Après le rebond de phase, nous appliquons une nouvelle fois la méthode de Hadamard au qubit $0$, ce qui donne l'état suivant :\n",
        "\n",
        "$|\\pi_3\\rangle = |\\psi\\rangle ( \\frac{1+e^{2\\pi i \\theta}}{2} |0\\rangle + \\frac{1 - e^{2\\pi i \\theta}}{2}|1\\rangle) = |\\psi\\rangle ( \\cos(\\pi\\theta) |0\\rangle - i \\sin(\\pi\\theta)|1\\rangle)$\n",
        "\n",
        "Ainsi, lorsque nous mesurons le qubit $0$ à la fin, nous mesurons $|0\\rangle$ avec une certitude de 100 % si $\\theta = 0$ et nous mesurons $|1\\rangle$ avec une certitude de 100 % si $\\theta = \\frac{1}{2}$ (et si notre ordinateur quantique est parfait, sans bruit). Si $\\theta$ est autre chose que cela, la mesure finale n'est que probabiliste et ne nous apprend que peu de choses.\n",
        "\n",
        "<span id=\"qpe-with-more-precision-more-qubits\" />\n",
        "\n",
        "### QPE avec plus de précision : plus de qubits\n",
        "\n",
        "Nous pouvons étendre ce concept simple à un algorithme plus compliqué avec une précision arbitraire. Si, au lieu d'utiliser uniquement le qubit $0$ pour mesurer la phase, nous utilisons les qubits $m$ $0$ à $m-1$, nous pourrons estimer la phase avec une précision de $m$ bits. Voyons comment cela fonctionne :\n",
        "\n",
        "![Schéma de l'algorithme QPE pour plusieurs qubits. Les Hadamards sont appliqués aux qubits de données 0 à m-1. Ensuite, une série de portes U contrôlées est appliquée aux m qubits auxiliaires. Enfin, une QFT inverse est appliquée aux qubits et ceux-ci sont mesurés.](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/qft/QPE_withpi.avif)\n",
        "\n",
        "Ce circuit QPE plus précis commence de la même manière que la version à un seul bit : Des hadamards sont appliqués aux premiers qubits $m$, et les qubits restants sont préparés dans l'état $|\\psi\\rangle$, créant ainsi l'état :\n",
        "\n",
        "$|\\pi_1\\rangle = \\frac{1}{2^{m/2}}|\\psi\\rangle(|0\\rangle+|1\\rangle)(|0\\rangle+|1\\rangle)...(|0\\rangle+|1\\rangle)$\n",
        "\n",
        "Les unités contrôlées sont maintenant appliquées. Qubit $0$ est le contrôle pour la même unité $U$ que précédemment. Mais maintenant, le qubit $1$ est le contrôle de l'unité $U^2$, qui est simplement $U$ appliqué deux fois. Ainsi, la valeur propre de $U^2$ est $e^{2*2\\pi i \\theta}$. En général, chaque qubit $k$ de 0 à $m-1$ sera le contrôle de l'unité $U^{2^k}$. Cela signifie que chacun de ces qubits subira un retour de phase de $e^{2^k*2\\pi i \\theta}$. Il en résulte l'état suivant :\n",
        "\n",
        "$|\\pi_2\\rangle = |\\psi\\rangle \\otimes \\frac{1}{2^{m/2}} (|0\\rangle+e^{2^{m-1}2\\pi i \\theta}|1\\rangle)(|0\\rangle+e^{2^{m-2}2\\pi i \\theta}|1\\rangle)...(|0\\rangle+e^{2\\pi i \\theta}|1\\rangle)$\n",
        "\n",
        "Ceci peut être réécrit comme une somme sur les états de la base de calcul :\n",
        "\n",
        "$|\\pi_2\\rangle = |\\psi\\rangle \\otimes \\frac{1}{2^{m/2}} \\sum_{k=0}^{2^{m}-1} e^{2\\pi i k \\theta} |k\\rangle $\n",
        "\n",
        "La somme vous semble-t-elle familière? C'est un QFT! Rappelons l'équation de la transformée de Fourier quantique :\n",
        "\n",
        "$ \\text{QFT}_{2^m}| y \\rangle =  \\frac{1}{\\sqrt{2^m}}\\sum_{x=0}^{2^m-1}\\omega_{2^m}^{y x} \\vert x \\rangle$\n",
        "\n",
        "Ainsi, si la phase $\\theta = y/2^m$ pour un certain entier $y$ entre $0$ et $2^m-1$, alors la QFT inverse de cet état donnera l'état :\n",
        "\n",
        "$|\\pi_3\\rangle = |\\psi\\rangle \\otimes |y\\rangle $\n",
        "\n",
        "et de $|y\\rangle$, nous pouvons déduire $\\theta$.\n",
        "\n",
        "Cependant, si $\\theta/2^m$ n'est *pas* un multiple entier, la méthode de la TQC inverse *n'approximera* que $\\theta$. Son approximation $\\theta$ sera probabiliste, ce qui signifie que nous n'obtiendrons pas toujours la meilleure approximation, mais qu'elle en sera assez proche. Plus vous utiliserez de qubits $m$, meilleure sera l'approximation. Pour savoir comment quantifier cette approximation de $\\theta$, consultez la leçon de John Watrous sur l' [estimation de phase et la factorisation](/learning/courses/fundamentals-of-quantum-algorithms/phase-estimation-and-factoring/phase-estimation-procedure) dans Fundamentals of quantum algorithms.\n",
        "\n",
        "<span id=\"conclusion\" />\n",
        "\n",
        "### Conclusion\n",
        "\n",
        "Ce module a donné un aperçu de ce qu'est une QFT, de la manière dont elle est mise en œuvre sur un ordinateur quantique et de son utilité pour résoudre des problèmes. Nous vous avons donné un aperçu de son utilité lorsque nous avons vu comment il peut être utilisé dans l'estimation de phase quantique pour connaître les valeurs propres d'une matrice unitaire.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "33b2c0e7-b48a-4426-8472-ad9a52bf48ea",
      "metadata": {},
      "source": [
        "<span id=\"critical-concepts\" />\n",
        "\n",
        "### Concepts essentiels\n",
        "\n",
        "* La transformée de Fourier quantique est l'analogue quantique de la transformée de Fourier discrète.\n",
        "* La QFT est un exemple de transformation de base.\n",
        "* La procédure d'estimation de la phase quantique repose sur le mécanisme de rétroaction de phase des opérations unitaires contrôlées, ainsi que sur une QFT inverse.\n",
        "* QFT et QPE sont tous deux des sous-programmes largement utilisés dans de nombreux algorithmes quantiques.\n",
        "\n",
        "<span id=\"questions\" />\n",
        "\n",
        "## Questions\n",
        "\n",
        "<span id=\"true/false\" />\n",
        "\n",
        "### True/False\n",
        "\n",
        "1. T/F La transformée de Fourier quantique est l'analogue quantique de la transformée de Fourier discrète (DFT) classique.\n",
        "2. La T/F QFT peut être mise en œuvre en utilisant uniquement des portes Hadamard et CNOT.\n",
        "3. T/F La QFT est un élément clé de l'algorithme de Shor.\n",
        "4. T/F La sortie de l'estimation quantique de phase est un état quantique représentant le vecteur propre de l'opérateur.\n",
        "5. T/F QPE nécessite l'utilisation de la transformée de Fourier quantique inverse (QFT $^\\dag$ ).\n",
        "6. T/F En QPE, si la phase $\\phi$ est exactement représentable avec $n$ bits, l'algorithme donne un résultat correct avec une probabilité de 1.\n",
        "\n",
        "<span id=\"short-answers\" />\n",
        "\n",
        "### Réponses courtes\n",
        "\n",
        "1. Combien de qubits sont nécessaires pour réaliser une QFT sur un système avec $2^n$ points de données?\n",
        "2. La QFT peut-elle être utilisée sur un état qui n'est pas un état de base de calcul? Dans l'affirmative, que se passe-t-il?\n",
        "3. Comment le nombre de qubits de contrôle utilisés dans le QPE affecte-t-il la résolution de l'estimation de la phase résultante?\n",
        "\n",
        "<span id=\"problems\" />\n",
        "\n",
        "### Incidents\n",
        "\n",
        "1. Utilisez la multiplication matricielle pour vérifier que les étapes de l'algorithme QFT aboutissent bien à la matrice $\\text{QFT}_4$ :\n",
        "\n",
        "$$\n",
        "\\text{QFT}_4 = \\frac{1}{2}\n",
        "\\begin{pmatrix}\n",
        "    1 & 1 & 1 & 1 \\\\\n",
        "    1 & i & -1 & -i \\\\\n",
        "    1 & -1 & 1 & -1 \\\\\n",
        "    1 & -i & -1 & i \\\\\n",
        "\\end{pmatrix}\n",
        "$$\n",
        "\n",
        "(Il n'est pas nécessaire de le faire à la main!)\n",
        "\n",
        "<span id=\"challenge-problems\" />\n",
        "\n",
        "### Problèmes difficiles\n",
        "\n",
        "1. Créez un état à quatre qubits qui est une superposition égale de toutes les bases de calcul impaires : $|\\psi\\rangle = |0001\\rangle + |0011\\rangle + |0101\\rangle + |0111\\rangle +|1001\\rangle +|1011\\rangle +|1101\\rangle +|1111\\rangle$. Effectuez ensuite une QFT sur cet état. Quel est l'état qui en résulte? Expliquez pourquoi votre résultat est logique, en utilisant vos connaissances sur les transformées de Fourier.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "in_page_toc_max_heading_level": 2,
    "in_page_toc_min_heading_level": 2,
    "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": 2
  },
  "nbformat": 4,
  "nbformat_minor": 5
}