{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "982215b2",
   "metadata": {},
   "source": [
    "# Programmation quantique\n",
    "## Notebook #1. Découverte de Qiskit et manipulation de circuits classiques\n",
    "\n",
    "Ce notebook est à compléter avec vos réponses puis à déposer sur la page Celene du cours __programmation quantique__ dans le dépôt aproprié avant le 5 novembre."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aeb913e6",
   "metadata": {},
   "source": [
    "## 0. Créer des circuits classiques avec un circuit quantique\n",
    "\n",
    "Les circuits quantiques sont suffisamment expressifs pour effectuer tout calcul réversible classique car ils disposent de portes comme la porte de Toffoli (aussi appelée CCX ou NON contrôlé contrôlé). C'est très pratique pour transformer des données et/ou faire subir une transformation à une superpositions de valeurs.\n",
    "\n",
    "Comme nous l'avons vu en cours, tout circuit booléen classique peut être reproduit efficacement sous forme de circuit réversible si on s'autorise à ajouter quelques bits de travail supplémentaires. Ces bits de travail sont initialisés à la valeur 0. En sortie du circuit, on récupère idéalement la sortie (si la fonction calculée est injective) ou l'entrée plus la sortie. Dans tous les cas, on peut remettre à 0 les bits de travail supplémentaires.\n",
    "\n",
    "Dans cette planche d'exercices, vous allez construire des circuits quantiques pour calculer des fonctions classiques avec Qiskit. Nous vous fournissons une fonction pour valider vos circuits. Ce validateur exécute une simulation quantique du circuit après avoir ajouté en entrée une superposition des bits d'entrée et en sortie des mesures sur les qubits vers de bits classiques.\n",
    "\n",
    "Dans vos circuits, vous vous contenterez d'utiliser les portes X (NON sur un seul qubit), CX (NON contrôlé) et CCX (NON contrôlé contrôlé)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "3166e1d2",
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit import QuantumCircuit, transpile\n",
    "from qiskit.providers.basic_provider import BasicProvider\n",
    "from qiskit.visualization import plot_histogram\n",
    "from qiskit.quantum_info import Operator\n",
    "\n",
    "# Un simulateur de circuit complet\n",
    "sim = BasicProvider().get_backend('basic_simulator')\n",
    "\n",
    "# Afficher un circuit\n",
    "def draw_circ(circ): display(circ.draw(output='mpl'))\n",
    "    \n",
    "def show(circ):\n",
    "    draw_circ(circ)\n",
    "    display(Operator(circ).draw('latex'))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d9c714b6",
   "metadata": {},
   "source": [
    "Un circuit se déclare en instanciant la classe `QuantumCircuit` avec en argument le nombre de qubits souhaités. On enfile ensuite les portes comme des perles sur les bits du circuit. À tout moment, il est possible de visualiser le circuit avec la méthode `draw`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "7f12c383",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 162.08x284.278 with 1 Axes>"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "moncircuit = QuantumCircuit(3)\n",
    "moncircuit.draw(output='mpl')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "54bc03b5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 4964 characters]",
      "text/plain": [
       "<Figure size 203.885x284.278 with 1 Axes>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "moncircuit.x(0) # ajoute une porte NON sur le qubit q0\n",
    "moncircuit.draw(output='mpl')  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "a58ce552",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 6912 characters]",
      "text/plain": [
       "<Figure size 287.496x284.278 with 1 Axes>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "moncircuit.cx(0,1) # ajoute une porte NON contrôlé sur les qubits q0 (contrôle) et q1 (NON)\n",
    "moncircuit.draw(output='mpl')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "034609c8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 11340 characters]",
      "text/plain": [
       "<Figure size 538.33x284.278 with 1 Axes>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "moncircuit.ccx(0,1,2)\n",
    "# et maintenant on remet les qubits 0 et 1 à leur valeur initiale\n",
    "moncircuit.cx(0,1)\n",
    "moncircuit.x(0)\n",
    "moncircuit.draw(output='mpl')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1ca7fef7",
   "metadata": {},
   "source": [
    "Voici le code de notre validateur. Il n'est pas nécessaire de comprendre comment il fonctionne pour l'utiliser dans les exercices de la planche."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "d01a1f70",
   "metadata": {},
   "outputs": [],
   "source": [
    "def validator(ninput, circuit, outset):\n",
    "    \"\"\"Teste la fonction classique calculée par le circuit [circuit]\n",
    "       en considérant que les [ninput] premiers qubits reçoivent une\n",
    "       entrée binaire et que les autres qubits reçoivent en entrée 0.\n",
    "       Vérifie que l'ensemble des mesures des qubits en sortie du\n",
    "       circuit produit l'ensemble de valeurs [outset].\"\"\"\n",
    "    assert circuit.num_clbits == 0\n",
    "    n = circuit.num_qubits\n",
    "    nanc = n-ninput\n",
    "    assert nanc >= 0\n",
    "    head = QuantumCircuit(n, n)\n",
    "    for i in range(ninput):\n",
    "        head.h(i)\n",
    "    head.barrier()\n",
    "    tail = QuantumCircuit(n, n)\n",
    "    tail.barrier()\n",
    "    for i in range(n):\n",
    "        tail.measure(i, n-1-i)\n",
    "    full = head.compose(circuit).compose(tail)\n",
    "    display(full.draw(output='mpl'))\n",
    "    res = sim.run(full, shots=65536).result()\n",
    "    counts = res.get_counts(full)\n",
    "    display(plot_histogram(counts))\n",
    "    expset = set(counts.keys())\n",
    "    return outset == expset\n",
    "\n",
    "def classicset(ninput, nanc, f):\n",
    "    rset = set()\n",
    "    fs = '{:0' + str(ninput) + 'b}'\n",
    "    ss = '0' * nanc\n",
    "    for i in range(pow(2,ninput)):\n",
    "        s = fs.format(i) + ss\n",
    "        res = f(*map(int,s))\n",
    "        rset.add(''.join(map(str,res)))\n",
    "    return rset"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0c76785f",
   "metadata": {},
   "source": [
    "Le validateur est appliqué à un circuit en lui indiquant le nombre de bits d'entrée et les sorties attendues lorsque l'entrée parcourt toutes les valeurs. Le validateur affiche le circuit qu'il exécute, le résultats de la simulation et retourne `True` ou `False` selon que le circuit proposé passe ou non le test.\n",
    "\n",
    "Pour notre circuit d'exemple,\n",
    "\n",
    "| q0 in | q1 in | q0 out | q1 out | q2 out |\n",
    "| :-: | :-: | :-: | :-: | :-: |\n",
    "|0|0|0|0|1|\n",
    "|0|1|0|1|0|\n",
    "|1|0|1|0|0|\n",
    "|1|1|1|1|0|"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "0a2c75f6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 23512 characters]",
      "text/plain": [
       "<Figure size 1040x367.889 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 22948 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "validator(2, moncircuit, classicset(2, 1, lambda x,y,z: (x,y,(1-x)*(1-y))))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d233d317",
   "metadata": {},
   "source": [
    "## 1. Portes logiques classiques\n",
    "\n",
    "Les circuits booléens classiques sont souvent composés avec les portes NON, ET et OU. À vous de proposer pour chacune des portes ci-dessous une version quantique qui accepte en entrée les bits d'entrée de la porte simulée et produit en sortie ces mêmes bits accompagnés de la valeur calculée par la porte. Nous fournissons le test de validation qui doit retourner `True` pour valider votre solution."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4679fde0",
   "metadata": {},
   "source": [
    "### Porte NON\n",
    "\n",
    "La porte `NON` inverse la valeur du bit reçu en entrée.\n",
    "\n",
    "|x|NON(x)|\n",
    "| :-: | :-: |\n",
    "|0|1|\n",
    "|1|0|"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "006d0138",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 13972 characters]",
      "text/plain": [
       "<Figure size 788.961x284.278 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 18612 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "circuitNON = QuantumCircuit(2) # un bit d'entrée, un bit de sortie\n",
    "\n",
    "### AJOUTER ICI CE QU'IL FAUT POUR MODIFIER LE CIRCUIT\n",
    "### ALLEZ, C'EST LE PREMIER, ON VOUS PROPOSE UNE SOLUTION ;-)\n",
    "### CE N'EST PAS LA MEILLEURE, VOUS POUVEZ LE FAIRE AVEC UNE PORTE DE MOINS\n",
    "\n",
    "circuitNON.x(0)\n",
    "circuitNON.cx(0,1)\n",
    "circuitNON.x(0)\n",
    "\n",
    "### ET VOICI LE TEST QUI DOIT RENVOYER TRUE\n",
    "validator(1, circuitNON, classicset(1,1, lambda x,y: (x,1-x)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "38301d59",
   "metadata": {},
   "source": [
    "### Porte ET\n",
    "\n",
    "La porte `ET` teste si les deux bits en entrée sont à 1.\n",
    "\n",
    "|x|y|ET(x,y)|\n",
    "| :-: | :-: | :-: |\n",
    "|0|0|0|\n",
    "|0|1|0|\n",
    "|1|0|0|\n",
    "|1|1|1|"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "9535d66f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 15872 characters]",
      "text/plain": [
       "<Figure size 621.941x367.889 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 23216 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "circuitET = QuantumCircuit(3) # deux bits d'entrée, un bit de sortie\n",
    "\n",
    "### AJOUTER ICI CE QU'IL FAUT POUR MODIFIER LE CIRCUIT\n",
    "\n",
    "\n",
    "### ET VOICI LE TEST QUI DOIT RENVOYER TRUE\n",
    "validator(2, circuitET, classicset(2,1, lambda x,y,z: (x,y,x*y)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4bec661f",
   "metadata": {},
   "source": [
    "### Porte OU\n",
    "\n",
    "La porte `OU` teste si l'un des deux bits en entrée est à 1.\n",
    "\n",
    "|x|y|OU(x,y)|\n",
    "| :-: | :-: | :-: |\n",
    "|0|0|0|\n",
    "|0|1|1|\n",
    "|1|0|1|\n",
    "|1|1|1|"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "3f1c0e22",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 15872 characters]",
      "text/plain": [
       "<Figure size 621.941x367.889 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 22600 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "circuitOU = QuantumCircuit(3) # deux bits d'entrée, un bit de sortie\n",
    "\n",
    "### AJOUTER ICI CE QU'IL FAUT POUR MODIFIER LE CIRCUIT\n",
    "\n",
    "\n",
    "\n",
    "### ET VOICI LE TEST QUI DOIT RENVOYER TRUE\n",
    "validator(2, circuitOU, classicset(2,1, lambda x,y,z: (x,y,max(x,y))))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e5affb66",
   "metadata": {},
   "source": [
    "### Porte XOR\n",
    "\n",
    "La porte `XOR` teste si exactement un deux bits en entrée est à 1.\n",
    "\n",
    "|x|y|XOR(x,y)|\n",
    "| :-: | :-: | :-: |\n",
    "|0|0|0|\n",
    "|0|1|1|\n",
    "|1|0|1|\n",
    "|1|1|0|"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "bcc7986f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 15872 characters]",
      "text/plain": [
       "<Figure size 621.941x367.889 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 22924 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "circuitXOR = QuantumCircuit(3) # deux bits d'entrée, un bit de sortie\n",
    "\n",
    "### AJOUTER ICI CE QU'IL FAUT POUR MODIFIER LE CIRCUIT\n",
    "\n",
    "\n",
    "### ET VOICI LE TEST QUI DOIT RENVOYER TRUE\n",
    "validator(2, circuitXOR, classicset(2,1, lambda x,y,z: (x,y,x^y)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c3ad8860",
   "metadata": {},
   "source": [
    "## 2. Produit scalaire booléen\n",
    "\n",
    "Pour l'algorithme de Bernstein-Vazirani étudié dans le cours, nous aurons besoin d'un circuit qui calcule le produit scalaire entre une suite de $k$ bits $x_1, x_2, \\ldots, x_k$ fournis en entrée et une chaîne constante $s_1, s_2, \\ldots, s_k$ choisie une fois pour toute. Plus précisemment, le circuit attendu prend en entrée les bits $x_1, x_2, \\ldots, x_k, y$ et retourne en sortie $x_1, x_2, \\ldots, x_k, z$ avec\n",
    "$$\n",
    "z = y\\oplus\\left( x_1\\cdot s_1 \\oplus x_2\\cdot s_2 \\oplus \\cdots \\oplus x_k\\cdot s_k\\right)\n",
    "$$\n",
    "\n",
    "Par exemple, sur 3 bits :\n",
    " - si $(s_1,s_2,s_3) = (1,0,1)$ alors $z = y \\oplus x_1 \\oplus x_3$ ;\n",
    " - si $(s_1,s_2,s_3) = (0,0,1)$ alors $z = y \\oplus x_3$ ;\n",
    " - si $(s_1,s_2,s_3) = (1,1,1)$ alors $z = y \\oplus x_1 \\oplus x_2 \\oplus x_3$.\n",
    " \n",
    " \n",
    " Vous devez écrire une fonction `circuitProduit(s)` qui reçoit en entrée la liste des valeurs $s_1, s_2, \\ldots, s_k$ et qui retourne un circuit à $k+1$ qubits qui calcule le produit scalaire entre son entrée et la suite $(s_i)$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "b83d840a",
   "metadata": {},
   "outputs": [],
   "source": [
    "### COMPLETER LA FONCTION circuitProduit POUR QU'ELLE PASSE LES TESTS DE VALIDATION !\n",
    "\n",
    "def circuitProduit(s):\n",
    "    k = len(s)\n",
    "    circuit = QuantumCircuit(k+1)\n",
    "    ### AJOUTER ICI CE QU'IL FAUT AU CIRCUIT !\n",
    "    return circuit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "cfcd8aa1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 20964 characters]",
      "text/plain": [
       "<Figure size 705.552x451.5 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 28832 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Circuit incorrect pour le vecteur [1, 0, 1]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def testscal(s):\n",
    "    k = len(s)\n",
    "    def aux(*xs):\n",
    "        y=xs[k]\n",
    "        for i in range(k):\n",
    "            if s[i] == 1:\n",
    "                y ^= xs[i]\n",
    "        return [*xs[:-1],y]\n",
    "    return aux\n",
    "\n",
    "check = True\n",
    "for ss in ['101', '00', '001', '111', '10111']:\n",
    "    s = list(map(int,ss))\n",
    "    k = len(s)\n",
    "    circ = circuitProduit(s)\n",
    "    outset = classicset(k,1,testscal(s))\n",
    "    check = validator(k, circ, outset)\n",
    "    if not check:\n",
    "        print('Circuit incorrect pour le vecteur', s)\n",
    "        break\n",
    "check"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d31dc16d",
   "metadata": {},
   "source": [
    "## 3. Plus ou moins de contrôle\n",
    "\n",
    "Maintenant que nous avons revu les constructions du cours, passons à quelque chose de plus original. Dans cette partie, nous allons revisiter les constructions de l'article [Elementary gates for quantum computation](https://arxiv.org/pdf/quant-ph/9503016v1) de A. Barenco *et al.* paru dans *Phys.Rev. A52 (1995) 3457*.\n",
    "\n",
    "La question que nous étudions est la suivante : comment faire pour simuler efficacement une porte NON avec $n$ bits de contrôle, $C^nX$, à l'aide de portes plus simples ? L'efficacité sera mesurée selon deux critères : la profondeur du circuit et le nombre de bits auxiliaires nécessaires au calcul."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2cd2ecd9",
   "metadata": {},
   "source": [
    "### 3.1 Simuler $C^nX$ avec $CCX$\n",
    "\n",
    "On s'intéresse d'abord au lemme 7.2 situé page 18 de l'article de référence. Il contient une figure que nous reproduisons ici avec qiskit :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "a9e14a25",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 16308 characters]",
      "text/plain": [
       "<Figure size 203.885x785.944 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "gauche = QuantumCircuit(9)\n",
    "gauche.mcx([0,1,2,3,4],8)\n",
    "draw_circ(gauche)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "c6ec1e9a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 42764 characters]",
      "text/plain": [
       "<Figure size 1123.61x785.944 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "droite = QuantumCircuit(9)\n",
    "droite.ccx(4,7,8)\n",
    "droite.ccx(3,6,7)\n",
    "droite.ccx(2,5,6)\n",
    "droite.ccx(0,1,5)\n",
    "droite.ccx(2,5,6)\n",
    "droite.ccx(3,6,7)\n",
    "droite.ccx(4,7,8)\n",
    "droite.ccx(3,6,7)\n",
    "droite.ccx(2,5,6)\n",
    "droite.ccx(0,1,5)\n",
    "droite.ccx(2,5,6)\n",
    "droite.ccx(3,6,7)\n",
    "draw_circ(droite)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "20e82d27",
   "metadata": {},
   "source": [
    "Demandons à Qiskit de tester si ces deux circuits sont équivalents."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "cd646149",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Operator(gauche) == Operator(droite)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1d97c61f",
   "metadata": {},
   "source": [
    "Dans le texte de l'article, la notation $\\Lambda_n(\\sigma_x)$ désigne une porte $C^nX$. Lire et comprendre les hypothèses du lemme 7.2. Écrire une fonction qui prend en entrée un nombre $n$ de qubits et un nombre $m$ de bits de contrôle. Cette fonction doit tester si les hypothèses sont satisfaites (si ce n'est pas le cas elle retourne `None`), construire les circuits `gauche` et `droite` correspondant, vérifier que `Operator(gauche) == Operator(droite)` et retourner `droite`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "8a482977",
   "metadata": {},
   "outputs": [],
   "source": [
    "def first_sim_cnx(n, m):\n",
    "    \"Simule une porte C^m(X) sur un circuit de n qubits\"\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8bb5bc80",
   "metadata": {},
   "source": [
    "### 3.2 Simuler $C^nX$ avec $CCX$ et 1 seul bit auxiliaire\n",
    "\n",
    "On va maintenant utiliser le lemme 7.3 et le corollaire 7.4 situés page 19 et 20 pour utiliser un unique qubit auxiliaire. Voici la figure de la page 20."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "f6f6d977",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 17120 characters]",
      "text/plain": [
       "<Figure size 203.885x785.944 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "gauche = QuantumCircuit(9)\n",
    "gauche.mcx([0,1,2,3,4,5,6],8)\n",
    "draw_circ(gauche)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "93faa1e0",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 26488 characters]",
      "text/plain": [
       "<Figure size 454.719x785.944 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "droite = QuantumCircuit(9)\n",
    "droite.mcx([0,1,2,3,4],7)\n",
    "droite.mcx([5,6,7],8)\n",
    "droite.mcx([0,1,2,3,4],7)\n",
    "droite.mcx([5,6,7],8)\n",
    "draw_circ(droite)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "17ec0236",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Operator(gauche) == Operator(droite)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e9a691e",
   "metadata": {},
   "source": [
    "Lire et comprendre les hypothèses du lemme 7.3 et du corollaire 7.4. Écrire une fonction qui prend en entrée un nombre $n$ de qubits et un nombre $m$ de bits de contrôle. Cette fonction doit tester si les hypothèses sont satisfaites (si ce n'est pas le cas elle retourne `None`), construire les circuits `gauche` et `droite` correspondant, vérifier que `Operator(gauche) == Operator(droite)` et retourner `droite`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "1aea6931",
   "metadata": {},
   "outputs": [],
   "source": [
    "def second_sim_cnx(n, m):\n",
    "    \"Simule une porte C^m(X) sur un circuit de n qubits en utilisant un unique qubit auxiliaire\"\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "327d3d3d",
   "metadata": {},
   "source": [
    "### 3.3 Ça vous a plu ? Vous en demandez encore ? (BONUS)\n",
    "\n",
    "Avec des portes quantiques, on peut se débarasser de ce dernier qubit auxiliaire et simuler la port $C^nX$ directement. C'est l'objet des lemmes 7.5 et 7.6 de l'article. Pour cela on a besoin de la porte $\\sqrt{X}$, qui vérifie $\\sqrt{X} \\cdot \\sqrt{X} = X$, de son inverse et de leurs versions contrôlées. Elle est notée $SX$ en Quiskit.\n",
    "\n",
    "Voici un exemple de circuit qui réalise $CX$ grâce à cette astuce :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "d17c053f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 4680 characters]",
      "text/plain": [
       "<Figure size 203.683x200.667 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "gauche = QuantumCircuit(2)\n",
    "gauche.cx(0,1)\n",
    "draw_circ(gauche)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "1a32295f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 6724 characters]",
      "text/plain": [
       "<Figure size 454.517x200.667 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "droite = QuantumCircuit(2)\n",
    "droite.csx(0,1)\n",
    "droite.x(0)\n",
    "droite.csx(0,1).inverse()\n",
    "droite.x(0)\n",
    "droite.sx(1)\n",
    "draw_circ(droite)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "f8546d2a",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Operator(gauche) == Operator(droite)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d6836641",
   "metadata": {},
   "source": [
    "Si vous avez besoin de porte contrôlées généralisées, vous pouvez les construire comme ceci (c'est l'exemple de la figure page 21) :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "a1829b38",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 29468 characters]",
      "text/plain": [
       "<Figure size 538.33x785.944 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from qiskit.circuit.library.standard_gates import SXGate\n",
    "\n",
    "droite = QuantumCircuit(9)\n",
    "droite.csx(7,8)\n",
    "droite.mcx([0,1,2,3,4,5,6],7)\n",
    "droite.csx(7,8).inverse()\n",
    "droite.mcx([0,1,2,3,4,5,6],7)\n",
    "droite.append(SXGate().control(7), (0,1,2,3,4,5,6,8))\n",
    "draw_circ(droite)\n",
    "\n",
    "gauche = QuantumCircuit(9)\n",
    "gauche.mcx([0,1,2,3,4,5,6,7],8)\n",
    "Operator(gauche) == Operator(droite)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "89b69035",
   "metadata": {},
   "source": [
    "Si vous avez besoin de construire des racines de racines de racines de $X$, vous pouvez les construire comme ceci :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "004e6f18",
   "metadata": {},
   "outputs": [],
   "source": [
    "def racine(circ, kieme, qubit):\n",
    "    \"simule une porte racine kieme sur le qubit du circuit circ\"\n",
    "    circ.h(0)\n",
    "    circ.p(-pi/k, 0)\n",
    "    circ.h(0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "f389563c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 1105.17x117.056 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/latex": [
       "$$\n",
       "\n",
       "\\begin{bmatrix}\n",
       "0 & 1  \\\\\n",
       " 1 & 0  \\\\\n",
       " \\end{bmatrix}\n",
       "$$"
      ],
      "text/plain": [
       "<IPython.core.display.Latex object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 185.453x117.056 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/latex": [
       "$$\n",
       "\n",
       "\\begin{bmatrix}\n",
       "0 & 1  \\\\\n",
       " 1 & 0  \\\\\n",
       " \\end{bmatrix}\n",
       "$$"
      ],
      "text/plain": [
       "<IPython.core.display.Latex object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from math import pi\n",
    "moncircuit = QuantumCircuit(1)\n",
    "k = 1<<2\n",
    "for _ in range(k):\n",
    "    racine(moncircuit, k, 0)\n",
    "show(moncircuit)\n",
    "moncircuitb = QuantumCircuit(1)\n",
    "moncircuitb.x(0)\n",
    "show(moncircuitb)\n",
    "Operator(moncircuit) == Operator(moncircuitb)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a25a91d",
   "metadata": {},
   "source": [
    "Lire et comprendre les hypothèses du lemme 7.5 et du corollaire 7.6. Écrire une fonction qui prend en entrée un nombre $n$ de qubits. Cette fonction doit construire les circuits `gauche` et `droite` correspondant à la simulation quadratique d'un $C^nX$, vérifier que `Operator(gauche) == Operator(droite)` et retourner `droite`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "2a8d0aa8",
   "metadata": {},
   "outputs": [],
   "source": [
    "def last_sim_cnx(n):\n",
    "    \"Simule une porte C^n(X) sur un circuit de n qubits en utilisant X, SX, CSX et leurs inverses\"\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d81882b6",
   "metadata": {},
   "source": [
    "### 3.4 C'est la fin de la fiche ! Vous êtes toujours là ? (BONUS du BONUS)\n",
    "\n",
    "En TD vous vous êtes intéressés à réaliser la porte $n$-OR qui est un porte OU à $n$ entrées. Montrer qu'on peut simuler cette porte avec $n+1$ qubits ($n$ d'entrée et $1$ de sortie), sans qubit auxiliaire, en utilisant des portes $C^nX$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "fa5951d0",
   "metadata": {},
   "outputs": [],
   "source": [
    "def nor_gate(n):\n",
    "    \"Construit un circuit à n+1 qubits qui simule n-OR avec des portes C^nX\"\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a07929d",
   "metadata": {},
   "source": [
    "### 3.5  Il faut sortir de la salle maintenant... On ferme... (BONUS du BONUS du BONUS)\n",
    "\n",
    "L'article de référence pour cette partie du TP date de 1995. Depuis, de l'eau a coulé sous les ponts. Si vous voulez comment simuler des $C^nX$ de manière plus efficace, nous vous recommandons deux lectures :\n",
    " - [Constructing Large Controlled Nots](https://algassert.com/circuits/2015/06/05/Constructing-Large-Controlled-Nots.html), un article de blog en 3 parties de C. Gidney, très pédagogique, sur la simulation avec un nombre linéaires de portes de Toffoli ;\n",
    " - [Polylogarithmic-depth controlled-NOT gates without ancilla qubits](https://arxiv.org/pdf/2312.13206) un article de 2024 paru dans *Nature Communications **15**, 5886 (2024)* de B. Claudon *et al.* qui propose une construction encore plus efficace."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d33d4ba7",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.9.20"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
