{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Programmation Quantique (suite)\n",
    "\n",
    "### Nicolas Ollinger et Ioan Todinca\n",
    "<img style=\"width:15%; height: auto;\" src=\"img/lifo.png\">\n",
    "\n",
    "#### M2 info, S9 2024/2025"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Circuits quantiques ?\n",
    "\n",
    "Les ordinateurs quantiques d'aujourd'hui (ou plutôt de demain ?) s'utilisent comme des _coprocesseurs_ : on y fait subir une <b class=\"cool\">transformation unitaire</b> à un <b class=\"cool\">registre de qubits</b> initialement tous à zéro avant d'effectuer des <b class=\"cool\">mesures</b> sur son état.\n",
    "\n",
    "Les <b class=\"cool\">transformations unitaires</b> sont codées sous forme de circuits et la programmation quantique ressemble à de la <b class=\"cool\">programmation assembleur</b>.\n",
    "\n",
    "La programmation quantique propose une <b class=\"cool\">nouvelle forme de parallélisme</b>."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "\n",
    "### Hello qiskit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit import QuantumCircuit, transpile\n",
    "from qiskit.providers.basic_provider import BasicProvider\n",
    "from qiskit_aer import UnitarySimulator\n",
    "from qiskit.visualization import plot_histogram\n",
    "import qiskit.quantum_info as qi\n",
    "from math import sqrt\n",
    "import numpy as np\n",
    "\n",
    "# Un simulateur de circuit complet\n",
    "sim = BasicProvider().get_backend('basic_simulator')\n",
    "\n",
    "# Un simulateur calculant la matrice de transformation\n",
    "usim = UnitarySimulator()\n",
    "\n",
    "# Afficher un circuit\n",
    "def draw_circ(circ): display(circ.draw(output='mpl'))\n",
    "    \n",
    "# Calculer la matrice d'un circuit\n",
    "def mat_circ(circ): return usim.run(circ).result().get_unitary()\n",
    "\n",
    "def show(circ):\n",
    "    draw_circ(circ)\n",
    "    display(mat_circ(circ).draw('latex'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Circuits quantiques"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Circuits quantiques\n",
    "\n",
    "Un circuit quantique est composé d'un nombre constant de **fils** qui représentent des états quantiques d'un système discret fini. Les **fils** sont les **qubits**.\n",
    "\n",
    "Des **portes quantiques** permettent d'effectuer des opérations sur ces états jusqu'à obtenir un état final.\n",
    "\n",
    "Seules des **mesures** de ces états permettent d'obtenir une information (partielle) en sortie.\n",
    "\n",
    "Les **qubits** sont tous initialisés à la valeur $\\left|0\\right>$."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Représentations et calculs\n",
    "\n",
    "Pour raisonner sur ces objets circuits et les **transformations unitaires** qu'ils réalisent, plusieurs outils sont à notre disposition :\n",
    " - la représentation matricielle des circuits (de dimension $2^n$ pour $n$ qubits !) ;\n",
    " - le calcul avec la notation de Dirac $\\left<\\phi\\middle|\\psi\\right>$ ;\n",
    " - les outils graphiques du ZX-calcul !"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "<div style=\"text-align:center; width: 100%; height: 70%\"><img style=\"margin: auto; width: auto; height: 100%;\" src=\"img/qpic.png\"></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Un qubit\n",
    "\n",
    "Un registre de <b class=\"cool\">mémoire quantique</b> est un <b class=\"cool\">système quantique discret fini</b> constitué de <b class=\"cool\">qubits</b>.\n",
    "\n",
    "Un <b class=\"cool\">bit quantique</b> est une superposition de $0$ et de $1$ :\n",
    "$$\n",
    "\\alpha \\left|0\\right> + \\beta \\left|1\\right> \\quad\\mbox{avec}\\quad \\alpha, \\beta \\in \\mathbb{C}\n",
    "\\quad\\mbox{tels que}\\quad |\\alpha|^2+|\\beta|^2 = 1\n",
    "$$\n",
    "\n",
    "Par exemple $\\left|0\\right>$ ou encore $\\frac{1}{\\sqrt{2}}\\left(\\left|0\\right>+\\left|1\\right>\\right)$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Des qubits\n",
    "\n",
    "Un registre de <b class=\"cool\">$n$ qubits</b> est une superposition de chacun des vecteurs de bits possibles, chacun muni d'une amplitude.\n",
    "\n",
    "$$\n",
    "\\left|\\varphi\\right> = \\sum_{x\\in\\{0,1\\}^n} \\alpha_x\\left|x\\right> \\quad\\mbox{tels que}\\quad \\sqrt{\\sum_{x\\in\\{0,1\\}^n}  |\\alpha_x|^2} = 1\n",
    "$$\n",
    "\n",
    "Par exemple $\\frac12\\left|1000\\right>+\\frac12\\left|0100\\right>+\\frac12\\left|0010\\right>+\\frac12\\left|0001\\right>$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Produit tensoriel\n",
    "\n",
    "La <b class=\"cool\">composition</b> de deux registres quantiques s'obtient par l'opérateur bilinéaire de produit tensoriel $\\otimes$ qui satisfait $\\left|x\\right> \\otimes \\left|y\\right> = \\left|xy\\right>$.\n",
    "\n",
    "$$\n",
    "\\left|1\\right> \\otimes \\frac{1}{\\sqrt{2}}\\left(\\left|0\\right>+\\left|1\\right>\\right) =\n",
    "\\frac{1}{\\sqrt{2}}\\left(\\left|10\\right>+\\left|11\\right>\\right)\n",
    "$$\n",
    "\n",
    "Contrairement au cas classique, tout registre n'est pas décomposable en sous-registres ! \n",
    "\n",
    "Exemple d'état <b class=\"cool\">intriqué</b> : $\\frac{1}{\\sqrt{2}}\\left(\\left|00\\right>+\\left|11\\right>\\right)$."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Mesure quantique (observation)\n",
    "\n",
    "<img style=\"width=100%; height=auto; margin: auto\" src=\"img/mesure.png\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Mesure quantique d'un qubit particulier\n",
    "\n",
    "Partant d'un état $\\left|\\varphi\\right> = \\sum_x \\alpha_x\\left|x\\right>$, si on mesure le qubit numéro $i$, on observe la valeur $r$ avec la probabilité $p_r$ et le système change d'état :\n",
    "\n",
    "$$\n",
    "\\sum_{x\\in\\left\\{0,1\\right\\}^n} \\alpha_x\\left|x\\right> \\underset{\\phantom{blop}p_r\\phantom{blop}}{\\longrightarrow}\n",
    "\\frac{1}{\\sqrt{p_r}} \\sum_{x\\in\\left\\{0,1\\right\\}^n | x_i = r} \\alpha_x\\left|x\\right>\n",
    "$$\n",
    " \n",
    "$$\n",
    "\\mbox{avec}\\quad p_r = \\sum_{x\\in\\left\\{0,1\\right\\}^n | x_i = r}|\\alpha_x|^2\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Évolution unitaire\n",
    "\n",
    "En l'absence de mesure, lorsqu'il est isolé, l'état d'un système quantique évolue de manière <b class=\"cool\">unitaire</b>.\n",
    "\n",
    "$$\n",
    "U : \\mathbb{C}^{\\{0,1\\}^n} \\rightarrow \\mathbb{C}^{\\{0,1\\}^n}\n",
    "$$\n",
    "\n",
    "1. $U$ est linéaire : $$\n",
    "U\\left(\\alpha\\left|\\varphi\\right>+\\beta\\left|\\psi\\right>\\right) = \\alpha U\\left|\\varphi\\right>+\\beta U\\left|\\psi\\right>\\quad;\n",
    "$$\n",
    "2. $U$ préserve la norme : $\\left\\| U\\left|\\varphi\\right> \\right\\| = \\left\\| \\left|\\varphi\\right> \\right\\|$."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Porte quantique\n",
    "\n",
    "Un circuit quantique code une <b class=\"cool\">transformation unitaire</b> obtenue par composition de <b class=\"cool\">portes quantiques</b> elles aussi unitaires, donc réversibles, avec autant de qubits en entrée qu'en sortie.\n",
    "- composition séquentielle : produit de matrices ;\n",
    "- composition parallèle : produit tensoriel."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Portes sur 1 qubit\n",
    "\n",
    "$$\n",
    "\\begin{array}{clclcl}\n",
    "X :& \\left|0\\right> \\mapsto \\left|1\\right> & H :& \\left|0\\right> \\mapsto \\frac{\\left|0\\right>+\\left|1\\right>}{\\sqrt2}  & R_\\theta :& \\left|0\\right> \\mapsto \\left|0\\right>\\\\\n",
    "   & \\left|1\\right> \\mapsto \\left|0\\right> &    & \\left|1\\right> \\mapsto \\frac{\\left|0\\right>-\\left|1\\right>}{\\sqrt2} &  & \\left|1\\right> \\mapsto e^{i\\theta}\\left|1\\right> \\\\\n",
    "\\end{array}\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAKIAAABuCAYAAACk2MjUAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAEgElEQVR4nO3dz0vbdxzH8VfSssYf8VBdl4mu1dmw2poIisPDGDo9uOJp0EspPbijWJiYP6CXLtBT6cXjTpKeBjNXWRHZIBIEcVJBiGj1y/iiF611RL87bbA27TRav+98eT6Ofj/x8z48+X4S9Yshz/M8AT4L+z0AIBEijCBEmECIMIEQYQIhwgRChAmECBMIESYQIkwgRJhAiDCBEGECIcIEQoQJhAgTCBEmECJMIESYQIgwgRBhAiHCBEKECYQIEwgRJhAiTCBEmECIMIEQYQIhwgRChAmECBMIESYQIkwgRJhAiDCBEGHCRb8HCDLP86SDA7/HOJlLlxQKhc59W0L8kA4OVLxz3+8pTuTis5+kSOTc9+VohgmECBMIESYQIkwgRJhAiDCBEGECIcIEQoQJhAgTCBEmECJMIESYELgQXddVKpVSW1ubIpGImpub9eDBA+3t7WlkZEShUEhPnz71e0y8IVB/BrawsKChoSE5jqOamhq1t7drc3NTT5480erqqra3tyVJnZ2d/g56Qs/dPzX426/6sT2hHz7/ouSaj355pm+vfKqfv/zqnKc7G4G5I7quq+HhYTmOo/HxcW1tbSmfz8txHKXTaWWzWeVyOYVCISUSCb/HxRsCE+LY2Jg2NjY0Ojqqx48fKxqN/nstlUopmUyqWCzq2rVrqqur83FSlBKIEJeXl5XJZNTQ0KBHjx6VXNPV1SVJSiaT5zkajikQ7xGnpqZ0dHSku3fvqra2tuSaqqoqSZUd4qvDQ7mV9gzMMQUixJmZGUlSX1/fO9dsbGxIquwQH75Y0sMXS36P8UEEIsS1tTVJ0tWrV0teLxaLmpubk3S6ELu7u+U4zrHXV4XD+qOzt+z93vT9Z636rrG55LWh35+fyR7xeFz7R0dlvTYWi2l+fr6s1wYixL29PUnS/v5+yeuZTEau6yoajaqlpaXsfRzH0cuXL4+9vvrCBamz7O3e0lZbq28+/uTsvmEJm5ubenV4+EH3KCUQIcZiMe3s7Cifz6u39793oK2tLU1MTEiSEonEqZ7ZjcViJ1pfFa68z4KNjY2nuiOWKxAhDgwMaHl5Wel0WoODg4rH45KkXC6ne/fuyXVdSaf/QfZJjx3v9euKe655ZWVFIZ5rLk8qlVJ9fb3W19d18+ZNdXR06Pr16+rp6VFra6v6+/slVfYHlaALRIhNTU2anZ3V7du3FYlEVCgUdPnyZU1OTiqbzWplZUUSIVoWiKNZkm7cuKHp6em3vr67u6tCoaBwOKxbt275MBmOIzAhvsvS0pI8z1M8Hld1dbXf45Tl64Yr+mv4znvX/N916wJxNL/P4uKiJI5l6wgRJhAiTAj8e8R/fg8N2wJ/R0RlIESYQIgwgRBhAiHCBEKECYQIEwgRJhAiTCBEmECIMCHkeZ7n9xBBxT+FPD5ChAkczTCBEGECIcIEQoQJhAgTCBEmECJMIESYQIgwgRBhAiHCBEKECYQIEwgRJhAiTCBEmECIMIEQYQIhwgRChAmECBMIESYQIkwgRJhAiDDhb1+BCUFmootuAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 185.453x117.056 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/latex": [
       "$$\n",
       "\n",
       "\\begin{bmatrix}\n",
       "\\frac{\\sqrt{2}}{2} & \\frac{\\sqrt{2}}{2}  \\\\\n",
       " \\frac{\\sqrt{2}}{2} & - \\frac{\\sqrt{2}}{2}  \\\\\n",
       " \\end{bmatrix}\n",
       "$$"
      ],
      "text/plain": [
       "<IPython.core.display.Latex object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from math import pi\n",
    "circuit = QuantumCircuit(1)\n",
    "# remplacer ici le x par h ou t (=r(pi/4)) ou sx (sqrt(x))\n",
    "circuit.h(0)\n",
    "show(circuit)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Portes contrôlées\n",
    "\n",
    "$$\n",
    "\\begin{array}{cl}\n",
    "CX :& \\left|00\\right> \\mapsto \\left|00\\right> \\\\\n",
    "   & \\left|01\\right> \\mapsto \\left|01\\right> \\\\\n",
    "   & \\left|10\\right> \\mapsto \\left|11\\right> \\\\\n",
    "   & \\left|11\\right> \\mapsto \\left|10\\right> \\\\\n",
    "\\end{array}\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 4680 characters]",
      "text/plain": [
       "<Figure size 203.683x200.667 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/latex": [
       "$$\n",
       "\n",
       "\\begin{bmatrix}\n",
       "1 & 0 & 0 & 0  \\\\\n",
       " 0 & 0 & 0 & 1  \\\\\n",
       " 0 & 0 & 1 & 0  \\\\\n",
       " 0 & 1 & 0 & 0  \\\\\n",
       " \\end{bmatrix}\n",
       "$$"
      ],
      "text/plain": [
       "<IPython.core.display.Latex object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "circuit = QuantumCircuit(2)\n",
    "circuit.cx(0,1)\n",
    "show(circuit)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Échauffement"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Que calcule ce circuit ?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "scrolled": true,
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 8100 characters]",
      "text/plain": [
       "<Figure size 370.906x200.667 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "circuit = QuantumCircuit(2)\n",
    "circuit.cx(0,1)\n",
    "circuit.cx(1,0)\n",
    "circuit.cx(0,1)\n",
    "draw_circ(circuit)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Routage\n",
    "\n",
    "Le processeur Quito peut effectuer des portes sur 1 qubit et des portes CX sur 2 qubits. Cette famille de portes est universelle.\n",
    "\n",
    "<div style=\"width:100%\">\n",
    "<img style=\"display:inline; width:45%; height: auto;\" src=\"img/quito2.png\">\n",
    "<img style=\"display:inline; width:45%; height: auto;\" src=\"img/quito3.png\">\n",
    "</div>\n",
    "\n",
    "Comment modifier un circuit complexe qui a besoin d'effectuer un CX entre les qubits 0 et 4 ? Quel en est le coût ?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "\n",
    "# Porte de Hadamard"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Porte de Hadamard\n",
    "\n",
    "La porte de Hadamard (H), sur 1 qubit, est une porte de changement de base.\n",
    "\n",
    "$$\n",
    "\\begin{array}{clllll}\n",
    "H :& \\left|0\\right> &\\mapsto &\\left|+\\right> & = &\\frac{\\left|0\\right>+\\left|1\\right>}{\\sqrt2} \\\\\n",
    "   & \\left|1\\right> &\\mapsto &\\left|-\\right> & = &\\frac{\\left|0\\right>-\\left|1\\right>}{\\sqrt2}  \\\\\n",
    "\\end{array}\n",
    "$$\n",
    "\n",
    "En théorie, il suffit d'ajouter cette porte à la porte de Toffoli pour simuler polynomialement toute transformation unitaire (donc tout circuit quantique).\n",
    "\n",
    "_En pratique ce n'est pas très efficace, on procède autrement._"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Exercice\n",
    "\n",
    "Étudier ce circuit sur l'entrée $\\left|00\\right>$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "scrolled": true,
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 5148 characters]",
      "text/plain": [
       "<Figure size 287.294x200.667 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "circuit = QuantumCircuit(2)\n",
    "circuit.h(0)\n",
    "circuit.cx(0,1)\n",
    "draw_circ(circuit)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Propriétés\n",
    "\n",
    "$$\n",
    "\\begin{array}{rl}\n",
    "H \\cdot H &= \\text{Id}\\\\\n",
    "H : \\quad\\left|x\\right> &\\mapsto \\frac1{\\sqrt 2}\\sum_{y\\in\\{0,1\\}} (-1)^{xy} \\left|y\\right>\\\\\n",
    "H^{\\otimes n} : \\quad\\left|x\\right> &\\mapsto \\frac1{\\sqrt {2^n}}\\sum_{y\\in\\{0,1\\}^n} (-1)^{x\\bullet y} \\left|y\\right> \\qquad\\text{avec}\\; x\\bullet y = \\bigoplus_i x_i y_i\n",
    "\\end{array}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Exercice\n",
    "\n",
    "1. Calculer $H^{\\otimes n} \\left( \\left|0\\right>^{\\otimes n}\\right)$\n",
    "\n",
    "2. Étudier ce circuit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "scrolled": false,
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 5740 characters]",
      "text/plain": [
       "<Figure size 370.906x200.667 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "circuit = QuantumCircuit(2)\n",
    "circuit.h(0)\n",
    "circuit.h(1)\n",
    "circuit.cx(0,1)\n",
    "circuit.h(0)\n",
    "circuit.h(1)\n",
    "draw_circ(circuit)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Vérification assistée par ordinateur"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "scrolled": true,
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 5740 characters]",
      "text/plain": [
       "<Figure size 370.906x200.667 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/latex": [
       "$$\n",
       "\n",
       "\\begin{bmatrix}\n",
       "1 & 0 & 0 & 0  \\\\\n",
       " 0 & 1 & 0 & 0  \\\\\n",
       " 0 & 0 & 0 & 1  \\\\\n",
       " 0 & 0 & 1 & 0  \\\\\n",
       " \\end{bmatrix}\n",
       "$$"
      ],
      "text/plain": [
       "<IPython.core.display.Latex object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "circuit = QuantumCircuit(2)\n",
    "circuit.h(0)\n",
    "circuit.h(1)\n",
    "circuit.cx(0,1)\n",
    "circuit.h(0)\n",
    "circuit.h(1)\n",
    "show(circuit)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "scrolled": true,
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 4696 characters]",
      "text/plain": [
       "<Figure size 203.683x200.667 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/latex": [
       "$$\n",
       "\n",
       "\\begin{bmatrix}\n",
       "1 & 0 & 0 & 0  \\\\\n",
       " 0 & 1 & 0 & 0  \\\\\n",
       " 0 & 0 & 0 & 1  \\\\\n",
       " 0 & 0 & 1 & 0  \\\\\n",
       " \\end{bmatrix}\n",
       "$$"
      ],
      "text/plain": [
       "<IPython.core.display.Latex object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "circuit = QuantumCircuit(2)\n",
    "circuit.cx(1,0)\n",
    "show(circuit)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Oracle\n",
    "\n",
    "Pour toute fonction $f : \\{0,1\\}^n\\rightarrow \\{0,1\\}$, nous avons vu qu'il existe un circuit quantique à $n+1$ qubits utiles (+ des qubits auxiliares) qui sur l'entrée $\\left|x\\right>\\otimes\\left|y\\right>$ calcule $\\left|x\\right>\\otimes\\left|y \\oplus f(x)\\right>$.\n",
    "\n",
    "Montrer qu'en ajoutant une porte $X$ et une porte $H$ de part et d'autre du circuit sur le fil de $\\left|y\\right>$, on obtient un circuit qui sur l'entrée $\\left|x\\right>$ calcule $(-1)^{f(x)} \\left|x\\right>$ à l'aide d'un qubit auxiliaire à $\\left|0\\right>$."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "\n",
    "# Algorithme de Bernstein-Vazirani "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Faire mieux en quantique ?\n",
    "\n",
    "Les <b class=\"cool\">algorithmes quantiques</b> dépassent les algorithmes classiques non pas sur ce qu'ils peuvent calculer mais par leur capacité à effectuer certains calculs asymptotiquement plus vite que les meilleurs algorithmes classiques connus :\n",
    "- factorisation d'entiers (Shor) ;\n",
    "- recherche d'un élément dans une liste non triée (Grover) ;\n",
    "- ...\n",
    "\n",
    "Regardons un exemple simple ensemble."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Bernstein-Vazirani\n",
    "\n",
    "Cet algorithme est de type <b class=\"cool\">boîte noire</b>.\n",
    "\n",
    "On suppose disposer d'un circuit classique qui, sur l'entrée $x \\in \\{0,1\\}^{n}$, calcule la valeur $f(x) = x\\odot s$ où $s$ est un vecteur caché de $n$ bits et $x\\odot s = x_1 s_1 \\oplus x_2 s_2 \\oplus \\cdots \\oplus x_n s_n$.\n",
    "\n",
    "L'objectif est de retrouver $s$ en le moins d'appels possible à $f$.\n",
    "\n",
    "Un rapide raisonnement de théorie de l'information montre qu'un algorithme classique a besoin d'appeler $f$ au moins $n$ fois pour retrouver $s$ (et y arrive toujours)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Bernstein-Vazirani (suite)\n",
    "\n",
    "L'algorithme quantique proposé par Bernstein et Vazirani retrouve $s$ en un unique appel à $f$ !\n",
    "\n",
    "On suppose disposer d'un circuit quantique qui, sur l'entrée $(x\\otimes y)\\in \\{\\left|0\\right>,\\left|1\\right>\\}^{n+1}$, calcule la valeur $x \\otimes (y \\oplus x\\odot s)$.\n",
    "\n",
    "Construisons un circuit qui illustre cet algorithme !"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 49440 characters]",
      "text/plain": [
       "<Figure size 1290.83x869.556 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'0110': 1}\n"
     ]
    }
   ],
   "source": [
    "s = '0110'\n",
    "k = len(s)\n",
    "\n",
    "circuit = QuantumCircuit(2*k+1,k)\n",
    " \n",
    "# superposition\n",
    "circuit.x(k)\n",
    "for i in range(k+1):\n",
    "    circuit.h(i)\n",
    "circuit.barrier()\n",
    "# calcul parallèle\n",
    "for i in range(k):\n",
    "    if s[i] == '1':\n",
    "        circuit.x(k+1+i)\n",
    "\n",
    "for i in range(k):\n",
    "    circuit.ccx(i,k+1+i,k)\n",
    "\n",
    "for i in range(k):\n",
    "    if s[i] == '1':\n",
    "        circuit.x(k+1+i)\n",
    "circuit.barrier()\n",
    "# transformation quantique\n",
    "for i in range(k):\n",
    "    circuit.h(i)\n",
    "# mesure\n",
    "circuit.measure(list(range(k)), list(range(k)))\n",
    "\n",
    "display(circuit.draw(output='mpl',scale=1))\n",
    "res = sim.run(circuit, shots=1).result()\n",
    "print(res.get_counts(circuit))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Exécuter à distance"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Exécuter le code sur un processeur quantique\n",
    "\n",
    "Quelle différence entre notre simulateur et la vraie vie ?\n",
    "\n",
    "Modifions l'exemple en un circuit équivalent pour le faire tenir sur moins de bits et le rendre un peu plus résistant au bruit.\n",
    "\n",
    "Observons le résultat obtenu et le circuit exécuté."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 29680 characters]",
      "text/plain": [
       "<Figure size 1040x535.111 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'0110': 1}\n"
     ]
    }
   ],
   "source": [
    "s = '0110'\n",
    "k = len(s)\n",
    "\n",
    "circuit = QuantumCircuit(k+1,k)\n",
    "\n",
    "circuit.x(k)\n",
    "for i in range(k+1):\n",
    "    circuit.h(i)\n",
    "circuit.barrier()\n",
    "\n",
    "for i in range(k):\n",
    "    if s[i] == '1':\n",
    "        circuit.cx(i,k)\n",
    "circuit.barrier()\n",
    "\n",
    "for i in range(k):\n",
    "    circuit.h(i)\n",
    "    \n",
    "circuit.measure(list(range(k)), list(range(k)))\n",
    "\n",
    "display(circuit.draw(output='mpl',scale=1))\n",
    "res = sim.run(circuit, shots=1).result()\n",
    "print(res.get_counts(circuit))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<IBMBackend('ibm_sherbrooke')> 20\n"
     ]
    }
   ],
   "source": [
    "from qiskit_ibm_runtime import QiskitRuntimeService\n",
    " \n",
    "service = QiskitRuntimeService()\n",
    "backend = service.least_busy(operational=True, simulator=False, min_num_qubits=5)\n",
    "\n",
    "# Get the least busy real quantum system\n",
    "print(backend, backend.status().pending_jobs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "<img style=\"width:100%; height: auto;\" src=\"img/sherbrooke1.png\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "<img style=\"width:100%; height: auto;\" src=\"img/sherbrooke2.png\">"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 59156 characters]",
      "text/plain": [
       "<Figure size 2299.7x535.111 with 1 Axes>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "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",
    "circuit_isa = pm.run(circuit)\n",
    "circuit_isa.draw(output=\"mpl\", idle_wires=False, style=\"iqp\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "from qiskit_ibm_runtime import SamplerV2 as Sampler\n",
    "\n",
    "sampler = Sampler(backend)\n",
    "sampler.options.default_shots = 10_000\n",
    "result = sampler.run([circuit_isa]).result()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "scrolled": false,
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 29584 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "plot_histogram(result[0].data.c.get_counts())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Démonstration\n",
    "\n",
    "## par le calcul et combinatoirement"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Slideshow",
  "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"
  },
  "rise": {
   "autolaunch": true,
   "chalkboard": {
    "readOnly": false
   },
   "enable_chalkboard": true,
   "reveal_shortcuts": {
    "chalkboard": {
     "colorNext": "s",
     "colorPrev": "q",
     "toggleChalkboard": "a",
     "toggleNotesCanvas": "z"
    }
   },
   "scroll": true,
   "theme": "white"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
