Commit bed9adfe authored by Nicolas Ollinger's avatar Nicolas Ollinger

TP3

parent fb0fd7cb
{
"cells": [
{
"cell_type": "markdown",
"id": "9930deb1",
"metadata": {},
"source": [
"# Programmation quantique\n",
"# Notebook #3. Algorithme de Grover\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 __4 décembre__."
]
},
{
"cell_type": "markdown",
"id": "cf788cc0",
"metadata": {},
"source": [
"L'objectif est de proposer une implémentation de l'algorithme de Grover, et d'étudier son comportement. Ne pas hésiter à vous appuyer sur les notes de cours."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2a0466e2",
"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",
"import math\n",
"import random\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": "9d98df4e",
"metadata": {},
"source": [
"## 1. Fonction mistère. Le cas “simple”\n",
"\n",
"Rappelons que l'algorithme de Grover prend en entrée une fonction $f:\\{0,1\\}^n \\mapsto \\{0,1\\}$ et produit en sortie un vecteur booléen $x_1 \\in \\{0,1\\}^n$ tel que $f(x_1)=1$, si un tel vecteur existe.\n",
"\n",
"Commençons par le cas “simple”, où ce vecteur $x_1$ est unique. "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "94b3f95b",
"metadata": {},
"outputs": [],
"source": [
"### Construire le circuit de la fonction f telle que décrite ci-dessus.\n",
"### Votre fonction prend en entrée un vecteur booléen x1 de taille n et retourne \n",
"### le circuit U_f correspondant. Rappelons que f(x1)=1, et f(x)=0 pour tout x != x1.\n",
"\n",
"def fGrov(x1):\n",
" \"Construit un circuit à n+1 qubits qui simule une fonction f vallant 0 partout sauf en x1\"\n",
" pass"
]
},
{
"cell_type": "markdown",
"id": "26914209",
"metadata": {},
"source": [
"Pensez à tester votre fonction !"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1e90d267",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"id": "ab6c61a1",
"metadata": {},
"source": [
"## 2. Opérateur de diffusion de Grover\n",
"\n",
"Rappelons que l'opérateur de diffusion de Grover, sur $n$ qubits, correspond à $H^{\\oplus n} Z_{\\operatorname{OR}} H^{\\oplus n}$, où $\\operatorname{OR}$ est la fonction booléenne OU sur $n$ bits.\n",
"\n",
"Néanmoins, lors de l'implémentation, on utilisera un circuit sur $n+1$ qubits, et le dernier qubit sera laissé en permanence dans l'état $|-\\rangle = \\frac{|0\\rangle - |1\\rangle}{\\sqrt{2}}$."
]
},
{
"cell_type": "markdown",
"id": "a8b28beb",
"metadata": {},
"source": [
"Commençons donc par le circuit de la fonction $\\operatorname{OR}$ sur $n$ bits. Il a été déjà vu lors du premier TP !"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "69230b37",
"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": "d531c542",
"metadata": {},
"source": [
"Construire l'opérateur de diffusion de Grover. "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "203c34d1",
"metadata": {},
"outputs": [],
"source": [
"### Construire l'opérateur de diffusion de Grover sur n qubits,\n",
"### en utilisant un qubit auxiliaire qui sera maintenu en l'état |-).\n",
"\n",
"def GrovDiffOp(n):\n",
" # \"Construit l'opérateur de diffusion de Grover, H^{x n} Z_OR H^{x n} sur n qubits\n",
" # on garde néanmoins le n+1ème qubit qui restera à \\ket{-} tout le long du circuit\n",
" # On utilise donc directement le circuit U_OR et pas Z_OR\n",
"\n",
" pass"
]
},
{
"cell_type": "markdown",
"id": "00d44f7d",
"metadata": {},
"source": [
"Tester “visuellement” votre opérateur de Grover."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ff91b6ea",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"id": "b80b9ff6",
"metadata": {},
"source": [
"## 3. Le circuit de Grover complet (toujours dans le cas “simple”)\n",
"\n",
"Construire ici le circuit de Grover complet. Votre fonction prendra en entrée la taille $n$ des vecteurs considérés en entrée, et le circuit de la fonction “mistère” $f$. \n",
"\n",
"Nous somes toujours sous l'hypothèse où $f$ a une seule entrée $x_1$ telle que $f(x_1)=1$.\n",
"\n",
"Pour mémoire, le circuit de Grover \n",
"- Sera formé de $n+1$ qubits, le dernier étant gardé en permanence à $|-\\rangle$, et de $n$ bits\n",
"- Sur les $n$ premiers qubits, on applique d'abord un mur de portes $H$,\n",
"- Ensuite on répète $t = \\lfloor \\frac{\\pi \\sqrt{2^n}}{4}\\rfloor$ fois l'enchaînement du circuit de $f$ et de l'opérateur de diffusion de Grover,\n",
"- ... et à la fin on mesure les $n$ premiers qubits."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9c3d39f5",
"metadata": {},
"outputs": [],
"source": [
"### Construire le circuit de Grover prenant en entrée n et le circuit cf de la fonction f\n",
"### Vous pouvez mettre en paramètre le nombre t d'itérations\n",
"\n",
"def GrovAlgo(n, cf, t=None):\n",
" # Le circuit de Grover\n",
" if t is None:\n",
" pass "
]
},
{
"cell_type": "markdown",
"id": "c9e1128b",
"metadata": {},
"source": [
"Afficher le circuit de Grover pour plusieurs dimensions $n$ possibles et plusieurs fonctions $f$ possibles."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "10f9b11f",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"id": "1f6514fb",
"metadata": {},
"source": [
"## 4. Test du circuit de Grover et compilation source à source\n",
"\n",
"Vous pouvez déjà tester le circuit de Grover... si l'entrée est de dimension $n \\leq 2$. En revanche, pour $n \\geq 3$, le “simulateur basique” (sim, obtenu avec la fonction BasicProvider) ne fonctionnera pas sur des portes mcx ayant 3 qubits de contrôle ou plus. \n",
"\n",
"Vous devrez “transpiler” votre circuit, ce qui revient à le transformer en un circuit équivalent avec des portes plus simples, et c'est ce dernier qui pourra être simulé."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d9ad24fc",
"metadata": {},
"outputs": [],
"source": [
"# Warning : le simulateur \"basique\" n'accepte pas les portes \"complexes\" \n",
"# telles que les portes mcx avec trois qubits de contrôle\n",
"# du coup, on procède à une \"compilation source à source\" (en anglais : transpile)\n",
"# qui va transformer le circuit en un circuit similaire, mais avec des portes plus basiques,\n",
"# à l'instar du travail du 1er TP\n",
"\n",
"\n",
"# Exemple de \"transpile\" d'un circuit cGrov en circuit simplifié cGrov_t\n",
"#### cGrov_t = transpile(cGrov, backend = sim)\n",
"\n",
"# c'est donc sur ce dernier circuit \"simplifié\" que l'on fait la simulation\n",
"#### res = sim.run(cGrov_t, shots=1000).result()\n",
"\n",
"# pour analyser les réponses les réponses et récupérer la sortie la plus fréquents\n",
"#### counts = res.get_counts(cGrov_t)\n",
"#### most_frequent_result = max(counts, key=counts.get)"
]
},
{
"cell_type": "markdown",
"id": "64c2719a",
"metadata": {},
"source": [
"Vérifier empiriquement l'affirmation faite en cours : l'algorithme de Grover pour les fonctions “simples” (c-à-d avec une seule entrée qui donne 1, toutes les autres donnant 0) trouve la bonne réponse avec une probabilité d'au moins $1-\\frac{1}{2^n}$. "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "94d20081",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"id": "c538e074",
"metadata": {},
"source": [
"## 5. Algorithme de Grover : cas général\n",
"\n",
"Jusqu'à présent, nous avons vu l'algorithme de Grover dans le cas particulier où la fonction $f$ en entrée avait exactement une solution. Cependant, l'algorithme de Grover peut être généralisé pour fonctionner avec une fonction quelconque $f : \\{0,1\\}^n \\to \\{0,1\\}$. \n",
"\n",
"Le nouvel objectif est de traiter maintenant ce cas général. Cette fois, nous allons faire un vrai mélange de code “classique” et ”quantique”, assez représentatif de ce qui se passe dans la pratique : des algorithmes classiques font un certain nombre d'appels à du calcul quantique. "
]
},
{
"cell_type": "markdown",
"id": "1a3f3f86",
"metadata": {},
"source": [
"Rappelons brièvement l'algorithme de Grover dans le cas général.\n",
"\n",
"**A. Description d'une étape**\n",
"\n",
"- choisir le nombre $t$ d'itérations uniformément au hasard parmi $\\{1,2,\\dots, \\lfloor \\pi \\sqrt{2^n} /4 \\rfloor\\}$.\n",
"- construire le circuit de Grover à partir du circuit de la fonction $f$, en faisant $t$ répétitions de l'opérateur $Z_f H^{\\otimes n} Z_{\\operatorname{OR}} H^{\\otimes n}$.\n",
"\n",
"**B. L'algorithme, avec les mains**\n",
"\n",
"Rappelons que, si la fonction $f$ a au moins une entrée $x_1$ telle que $f(x_1) = 1$, le circuit du point A trouvera un tel $x_1$ avec une probabilité d'au moins 40%. En faisant le nombre suffisant d'étapes et le traitement adéquat, adaptez l'algorithme afin d'obtenir le bon résultat avec probabilité au moins $1 - \\frac{1}{2^n}$.\n",
"\n",
"Ce procédé s'appelle **amplification**, il est très utilisé pour les algorithmes probabilistes. \n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "10fc7527",
"metadata": {},
"outputs": [],
"source": [
"### Proposer une fonction qui prend en entrée un circuit circ se terminant par une mesure \n",
"### et qui rend la mesure la plus fréquente, après simulation, sous la forme d'un tableau de 0/1.\n",
"### En plus du circuit, on ajoute deux paramètres optionnels, nb_shots avec le nombre de runs et le booléen \n",
"### transp indiquant si l'on procède à un \"transpile\" du circuit d'origine\n",
"\n",
"def mesure_majoritaire(circ,nb_shots=1,transp=True):\n",
" pass\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fa008b2e",
"metadata": {},
"outputs": [],
"source": [
"### Algorithme de Grover prenant en entrée la dimension n le circuit cf d'une fonction f quelconque à n bits \n",
"### en entrée et 1 bit en sortie\n",
"### C'est un algorithme \"mixte\", faisant appel à un circuit quantique, mais également un post-traitement\n",
"\n",
"def Grov(n,cf): \n",
" # répéter suffisament de fois ; bien choisir le nombre de répétitions\n",
" \n",
" pass"
]
},
{
"cell_type": "markdown",
"id": "466793cd",
"metadata": {},
"source": [
"Testez votre algorithme sur différentes fonctions $f$. Ne pas oublier d'inclure la fonction $f_0:\\{0,1\\}^n \\to \\{0,1\\}$, définie par $f_0(x)=0$, pour toute entrée $x$."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f24941ee",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"id": "bf0b9249",
"metadata": {},
"source": [
"## 6. BONUS : boucler la boucle\n",
"\n",
"Au fait, pourquoi utiliser la fonction *transpile* de *qiskit*, alors que vous avez déjà travaillé sur les portes *mcx* lors du premier TP ?\n",
"\n",
"Adapter la construction du circuit de Grover de sorte à **ne pas utiliser** de porte *mcx* avec plus de 2 qubits de contrôle. Pour ce faire, utilisez les exercices du premier notebook. Vérifiez que tous vos tests antérieurs continuent à fonctionner avec le nouveau circuit, sans utiliser la fonction *transpile*. "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "10e86247",
"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.10.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment