{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "3c9b9ca5",
   "metadata": {},
   "source": [
    "NAME:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6d71a1d5-6589-4320-900f-b07f08df01f4",
   "metadata": {},
   "source": [
    "# INF TC1 - TD6 (2h) - Automates"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "54c3bdf8-4ded-45da-a79a-6530af149f51",
   "metadata": {},
   "source": [
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "33320365-404e-4424-96d1-6e6b742c8f44",
   "metadata": {},
   "source": [
    "## Objectif du TD\n",
    "\n",
    "Dans ce TD nous allons introduire les automates (en informatique), un modèle de calcul permettant de déterminer si une séquence d'information est valide ou non, selon une règle déterminée. Dans un premier temps nous allons définir des automates simples, et ensuite les implémenter en Python et résoudre des problèmes de complexité croissante."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02ba4e95-34be-41b9-b36c-255b5af6b3de",
   "metadata": {},
   "source": [
    "## Qu'est-ce qu'un automate ?\n",
    "\n",
    "Un automate est un outil de calcul permettant la validation de séquences d'instructions, à base d'états et de transitions. Un exemple d'automate est un feu tricolore, où les états sont la couleur du feu (rouge, vert ou orange) et les transitions les changements possibles de couleurs (du rouge au vert, du vert au orange, et du orange au rouge). Les automates permettent donc de formaliser le fonctionnement d'un système et de détecter des erreurs éventuelles qui ne respectent pas les changements pré-définis (en reprenant l'exemple du feu tricolore, passer du vert au rouge directement est une erreur). Les applications des automates sont nombreuses et offrent souvent un code plus facile à écire et lire."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "07c95f05-1782-4f25-80fe-9dcf93bdedc6",
   "metadata": {},
   "source": [
    "## Définitions\n",
    "\n",
    "Un automate possède une structure de données similaire à un graphe orienté, où **chaque nœud représente un état** et un **arc représente une transition possible d'un état à un autre**. Ce graphe est ensuite parcouru à partir de `mots` (par exemple : `aba`), qui sont une suite de symboles (comme les lettres `a` et `b`) permettant de passer d'un état à un autre. L'état initial (unique) est représenté visuellement par un cercle en gras, et le dernier état (il peut y en avoir plusieurs) par un double cercle. Les symboles `a` et `b` constituent l'alphabet de l'automate (il est possible d'utiliser tout type d'alphabet, comme les transitions d'un feu tricolore).\n",
    "\n",
    "Dans l'exemple ci-dessus, si le mot à lire est `ab`, l'automate commence à lire le mot depuis l'état `0` et réalise ensuite une transition vers un autre état à partir du premier symbole du mot, la lettre `a`. La transition vers l'état `1` est effectuée. L'automate se retrouve alors dans l'état `1` et lit le symbole suivant, la lettre `b`. L'automate reste sur l'état `1` (il s'agit d'une boucle).\n",
    "\n",
    "Les automates servent à valider un comportement appelé un *motif* (ou langage). Dans l'exemple ci-dessus, l'automate valide tous les mots contenant au moins un symbole **a** (souvent noté *a*, l'astérisque indiquant que tout symbole peut être utilisé).\n",
    "\n",
    "De manière générale, un automate est défini comme $A = (\\Sigma, S, s_{0}, \\delta, F)$, avec :\n",
    "\n",
    "- $\\Sigma$, un ensemble fini, non vide de symboles qui est l'alphabet d'entrée\n",
    "- $S$, un ensemble fini, non vide d'états\n",
    "- $s_{0}$, l'état initial, élément de $S$\n",
    "- $\\delta$, la fonction de transition d'états: $\\delta : S \\times \\Sigma \\rightarrow S$\n",
    "- $F$ est l'ensemble des états terminaux, un sous-ensemble (éventuellement vide) de $S$"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15b6ca9c-be1c-4757-b02c-1511fed5df68",
   "metadata": {},
   "source": [
    "## Dessin d'automates\n",
    "\n",
    "Pour dessiner des automates, nous utiliserons [Graphviz](https://graphviz.org/), un outil en ligne de commande qui permet de dessiner des graphes basé sur le langage [DOT](https://graphviz.org/doc/info/lang.html). Un exemple d'automate est donné ci-dessous :\n",
    "\n",
    "```python\n",
    "from graphviz import Digraph\n",
    "\n",
    "dot = Digraph()\n",
    "dot.graph_attr['rankdir'] = 'LR'\n",
    "\n",
    "dot.node('A', shape='circle', style='bold', label='0')\n",
    "dot.node('B', shape='doublecircle', label='1')\n",
    "\n",
    "dot.edge('A', 'B', label='a')\n",
    "dot.edge('B', 'A', label='a')\n",
    "\n",
    "dot\n",
    "``````"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "07d1cd6d-1845-4707-b126-fbe219408a92",
   "metadata": {},
   "source": [
    "**IMPORTANT :** vérifier que le code ci-dessus s'exécute bien (dans la cellule ci-dessous). Si cela n'est pas le cas alors suivez ces [instructions d'installation de la bibliothèque Graphviz](graphviz.ipynb)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bff8d514-4ab5-4a24-81c2-ecd7ef39aa9e",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from graphviz import Digraph\n",
    "\n",
    "dot = Digraph()\n",
    "dot.graph_attr['rankdir'] = 'LR'\n",
    "\n",
    "dot.node('0', shape='circle', style='bold', label='0')\n",
    "dot.node('1', shape='doublecircle', label='1')\n",
    "\n",
    "dot.edge('0', '1', label='a')\n",
    "\n",
    "dot"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ad7810cc-eefc-4733-993e-50c131c3e514",
   "metadata": {},
   "source": [
    "## Exercice 1 : Automates simples\n",
    "\n",
    "Dans cette section, nous vous demandons de proposer un automate qui valide un motif donné. Pour les questions 1.1, 1.2 et 1.3, nous considérons un alphabet contenant les lettres `a` et `b` seulement. Vous pouvez répondre aux questions sur papier de préférence, ou utiliser le code ci-dessus du mondule `graphviz` pour dessiner l'automate.\n",
    "\n",
    "**Question 1.1 -** Proposer un automate qui contient un nombre paire de fois la lettre `a`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d33a29aa-5e07-476d-bfa9-4ef7454bc6f4",
   "metadata": {
    "deletable": false,
    "nbgrader": {
     "cell_type": "code",
     "checksum": "4168e502dae02b09a9f1571e6849bb89",
     "grade": false,
     "grade_id": "cell-a0ee7afc3671a91f",
     "locked": false,
     "schema_version": 3,
     "solution": true,
     "task": false
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# YOUR CODE HERE\n",
    "raise NotImplementedError()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "87566002-5968-4b5f-aa05-c108bfe1cf33",
   "metadata": {
    "tags": []
   },
   "source": [
    "**Question 1.2 -** Proposer un automate qui valide le motif `a*a` (les mots qui commencent et finissent par `a`, de taille > 2). "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a8a32710-840f-4385-a85f-670c992ddca7",
   "metadata": {
    "deletable": false,
    "nbgrader": {
     "cell_type": "code",
     "checksum": "f23f682d6b6d2307e5dfde60dd09bf63",
     "grade": false,
     "grade_id": "cell-ae01cb69694c88b2",
     "locked": false,
     "schema_version": 3,
     "solution": true,
     "task": false
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# YOUR CODE HERE\n",
    "raise NotImplementedError()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "70c4a996-c123-49c9-b771-b58046b6bb97",
   "metadata": {},
   "source": [
    "penser à proposer une liste de mots à valider et à ne pas valider afin de guider les étudiants."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "14d7d169-fa9b-4c90-87d9-b07cfb1cc323",
   "metadata": {
    "tags": []
   },
   "source": [
    "**Question 1.3 -** Quel langage valide l'automate ci-dessous ? Donnez un exemple de mots validés et le langage."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b83f2bad-2864-4eeb-9851-510c7d5dd273",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from IPython.core.display import HTML\n",
    "HTML('<svg width=\"368pt\" height=\"118pt\" viewBox=\"0.00 0.00 368.00 118.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"><g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 114)\"><polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-114 364,-114 364,4 -4,4\"/><g id=\"node1\" class=\"node\"><title>0</title><ellipse fill=\"none\" stroke=\"black\" stroke-width=\"2\" cx=\"18\" cy=\"-39\" rx=\"18\" ry=\"18\"/><text text-anchor=\"middle\" x=\"18\" y=\"-35.3\" font-family=\"Times,serif\" font-size=\"14.00\">0</text></g><g id=\"node2\" class=\"node\"><title>1</title><ellipse fill=\"none\" stroke=\"black\" cx=\"97\" cy=\"-52\" rx=\"18\" ry=\"18\"/><text text-anchor=\"middle\" x=\"97\" y=\"-48.3\" font-family=\"Times,serif\" font-size=\"14.00\">1</text></g><g id=\"edge1\" class=\"edge\"><title>0→1</title><path fill=\"none\" stroke=\"black\" d=\"M34.18,-47.66C40.16,-50.6 47.21,-53.52 54,-55 58.45,-55.97 63.23,-56.29 67.9,-56.22\"/><polygon fill=\"black\" stroke=\"black\" points=\"67.86,-59.73 77.58,-55.49 67.34,-52.75 67.86,-59.73\"/><text text-anchor=\"middle\" x=\"57.5\" y=\"-58.8\" font-family=\"Times,serif\" font-size=\"14.00\">a</text></g><g id=\"edge2\" class=\"edge\"><title>1→0</title><path fill=\"none\" stroke=\"black\" d=\"M80.82,-43.34C74.84,-40.4 67.79,-37.48 61,-36 56.55,-35.03 51.77,-34.71 47.1,-34.78\"/><polygon fill=\"black\" stroke=\"black\" points=\"47.14,-31.27 37.42,-35.51 47.66,-38.25 47.14,-31.27\"/><text text-anchor=\"middle\" x=\"57.5\" y=\"-39.8\" font-family=\"Times,serif\" font-size=\"14.00\">b</text></g><g id=\"node3\" class=\"node\"><title>2</title><ellipse fill=\"none\" stroke=\"black\" cx=\"176\" cy=\"-52\" rx=\"18\" ry=\"18\"/><text text-anchor=\"middle\" x=\"176\" y=\"-48.3\" font-family=\"Times,serif\" font-size=\"14.00\">2</text></g><g id=\"edge3\" class=\"edge\"><title>1→2</title><path fill=\"none\" stroke=\"black\" d=\"M115.47,-52C124.53,-52 135.83,-52 146.14,-52\"/><polygon fill=\"black\" stroke=\"black\" points=\"146.08,-55.5 156.08,-52 146.08,-48.5 146.08,-55.5\"/><text text-anchor=\"middle\" x=\"136.5\" y=\"-55.8\" font-family=\"Times,serif\" font-size=\"14.00\">a</text></g><g id=\"edge4\" class=\"edge\"><title>2→2</title><path fill=\"none\" stroke=\"black\" d=\"M169,-69.04C167.57,-78.86 169.91,-88 176,-88 179.52,-88 181.79,-84.94 182.8,-80.47\"/><polygon fill=\"black\" stroke=\"black\" points=\"186.3,-80.61 182.97,-70.55 179.3,-80.49 186.3,-80.61\"/><text text-anchor=\"middle\" x=\"176\" y=\"-91.8\" font-family=\"Times,serif\" font-size=\"14.00\">a</text></g><g id=\"node4\" class=\"node\"><title>3</title><ellipse fill=\"none\" stroke=\"black\" cx=\"255\" cy=\"-22\" rx=\"18\" ry=\"18\"/><text text-anchor=\"middle\" x=\"255\" y=\"-18.3\" font-family=\"Times,serif\" font-size=\"14.00\">3</text></g><g id=\"edge5\" class=\"edge\"><title>2→3</title><path fill=\"none\" stroke=\"black\" d=\"M193.33,-45.64C203.13,-41.82 215.84,-36.87 227.09,-32.48\"/><polygon fill=\"black\" stroke=\"black\" points=\"228.24,-35.79 236.28,-28.9 225.7,-29.27 228.24,-35.79\"/><text text-anchor=\"middle\" x=\"215.5\" y=\"-40.8\" font-family=\"Times,serif\" font-size=\"14.00\">b</text></g><g id=\"edge6\" class=\"edge\"><title>3→0</title><path fill=\"none\" stroke=\"black\" d=\"M236.53,-21.08C204.94,-19.69 136.3,-17.91 79,-25 68.32,-26.32 56.76,-28.77 46.67,-31.25\"/><polygon fill=\"black\" stroke=\"black\" points=\"45.9,-27.83 37.1,-33.73 47.66,-34.61 45.9,-27.83\"/><text text-anchor=\"middle\" x=\"136.5\" y=\"-23.8\" font-family=\"Times,serif\" font-size=\"14.00\">a</text></g><g id=\"node5\" class=\"node\"><title>4</title><ellipse fill=\"none\" stroke=\"black\" cx=\"338\" cy=\"-22\" rx=\"18\" ry=\"18\"/><ellipse fill=\"none\" stroke=\"black\" cx=\"338\" cy=\"-22\" rx=\"22\" ry=\"22\"/><text text-anchor=\"middle\" x=\"338\" y=\"-18.3\" font-family=\"Times,serif\" font-size=\"14.00\">4</text></g><g id=\"edge7\" class=\"edge\"><title>3→4</title><path fill=\"none\" stroke=\"black\" d=\"M273.18,-22C282.15,-22 293.45,-22 304.03,-22\"/><polygon fill=\"black\" stroke=\"black\" points=\"304,-25.5 314,-22 304,-18.5 304,-25.5\"/><text text-anchor=\"middle\" x=\"294.5\" y=\"-25.8\" font-family=\"Times,serif\" font-size=\"14.00\">a</text></g><g id=\"edge8\" class=\"edge\"><title>4→4</title><path fill=\"none\" stroke=\"black\" d=\"M333.99,-43.81C333.6,-53.56 334.94,-62 338,-62 339.72,-62 340.9,-59.33 341.53,-55.26\"/><polygon fill=\"black\" stroke=\"black\" points=\"345.02,-55.46 341.95,-45.32 338.03,-55.16 345.02,-55.46\"/><text text-anchor=\"middle\" x=\"338\" y=\"-65.8\" font-family=\"Times,serif\" font-size=\"14.00\">a</text></g><g id=\"edge9\" class=\"edge\"><title>4→4</title><path fill=\"none\" stroke=\"black\" d=\"M331.14,-43.11C328.11,-61.1 330.4,-80 338,-80 344,-80 346.69,-68.23 346.07,-54.43\"/><polygon fill=\"black\" stroke=\"black\" points=\"349.56,-54.19 345.02,-44.62 342.6,-54.93 349.56,-54.19\"/><text text-anchor=\"middle\" x=\"338\" y=\"-83.8\" font-family=\"Times,serif\" font-size=\"14.00\">b</text></g></g></g></svg>')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7aae22c9",
   "metadata": {
    "deletable": false,
    "nbgrader": {
     "cell_type": "code",
     "checksum": "4c1d218cdb71fdfce3e681ffc99f4f0e",
     "grade": false,
     "grade_id": "cell-e67623920e712c80",
     "locked": false,
     "schema_version": 3,
     "solution": true,
     "task": false
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# YOUR CODE HERE\n",
    "raise NotImplementedError()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b1c8a625-b2e5-4958-b49f-009c7bcdb038",
   "metadata": {},
   "source": [
    "**Question 1.4 -** Proposer un automate qui valide le fait qu'une chaîne de caractères est une adresse email. Les adresses email peuvent être définies comme suit :\n",
    "\n",
    "- tout d'abord le premier caractère ne peut pas être un chiffre\n",
    "- ensuite tous les caractères de `a` à `z` (majuscules et minuscules) et chiffres sont acceptés\n",
    "- un `@` doit être présent\n",
    "- ensuite un nom de domaine qui lui aussi ne peut commencer par un chiffre (et doit faire + de 1 caractère)\n",
    "- un \".\"\n",
    "- une extension parmis une liste autorisée (`fr`, `com`, etc)\n",
    "\n",
    "Un exemple de chaîne qui n'est pas validée est `3toto@a.fr2` car la première partie commence par un chiffre, le nom de domaine est trop court et enfin l'extension n'est pas valide. Pour la partie de validation de l'extension (`.fr`, etc.), vous pouvez simplifier en proposant une reconnaissance de motifs pré-définis (`.fr`, `.com`, etc.). Vous pouvez vous référer à la page Wikipedia [ici](https://fr.wikipedia.org/wiki/Adresse_\\%C3\\%A9lectronique) ou à la RFC 8222 [ici](https://www.w3.org/Protocols/rfc822/) pour une définition plus précise.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2ee41daa-5611-433d-862a-f098127cad73",
   "metadata": {
    "deletable": false,
    "nbgrader": {
     "cell_type": "code",
     "checksum": "0f25fc1405b403c0ee1ce1ca76cb31d5",
     "grade": false,
     "grade_id": "cell-364a7a05c761af46",
     "locked": false,
     "schema_version": 3,
     "solution": true,
     "task": false
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# YOUR CODE HERE\n",
    "raise NotImplementedError()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6655a83e",
   "metadata": {},
   "source": [
    "## Exercice 2 : Structure de données d'automate en Python"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd6c2f5f-a14a-4a72-bbbe-ad7ec0406dad",
   "metadata": {},
   "source": [
    "**Question 2.1 -** Nous allons désormais implémenter en Python une structure de données d'automate. Celle-ci doit être en mesure de stocker toutes les informations relatives à la définition d'un automate (symboles reconnu, états, états initiaux/finaux) et valider un mot donné. Votre structure de données peut être composée comme suit :\n",
    "\n",
    "1. Un constructeur `__init__` qui initialise l'automate avec les symboles du motif (ici `a` et `b`) et les variables d'état interne. En particulier l'état initial.\n",
    "\n",
    "2. Une méthode `ajout_etat` qui rajoute un nouvel état et s'assure que l'état n'existe pas déjà; un paramètre additionnel `final` indiquera si il s'agit d'un état finaal\n",
    "\n",
    "3. Une méthode `ajout_transition` qui rajoute un nouvel état et s'assure que l'état n'existe pas déjà.\n",
    "  \n",
    "4. Une méthode `recherche_etat` qui étant donné un état source et un symbole, renvoie l'état correspondant (via la transition correspondant au symbole donné).\n",
    "\n",
    "5. Une fonction `run` qui valide un mot donné, et renvoie `True` si l'état final est atteint et `False`.\n",
    "\n",
    "Voici l'initialisation et le test de l'automate qui implémente le motif `*a*` :\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "445d2964",
   "metadata": {
    "deletable": false,
    "nbgrader": {
     "cell_type": "code",
     "checksum": "fd9267cdf1e9360727e498c4a8cbd6d9",
     "grade": false,
     "grade_id": "cell-2a3af123dd05d32f",
     "locked": false,
     "schema_version": 3,
     "solution": true,
     "task": false
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "class automate:\n",
    "# YOUR CODE HERE\n",
    "raise NotImplementedError()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dd5fe66b-8232-4ab6-94d7-0e49ca591f26",
   "metadata": {},
   "source": [
    "Voici un exemple attendu d'utilisation de votre structure de données :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "51a7c400",
   "metadata": {},
   "outputs": [],
   "source": [
    "a = automate(\"ab\")\n",
    "\n",
    "a.ajout_etat(\"0\")\n",
    "a.ajout_etat(\"1\", True)\n",
    "\n",
    "a.ajout_transition(\"0\", \"b\", \"0\")\n",
    "a.ajout_transition(\"0\", \"a\", \"1\")\n",
    "a.ajout_transition(\"1\", \"a\", \"1\")\n",
    "a.ajout_transition(\"1\", \"b\", \"1\")\n",
    "\n",
    "assert a.run(\"abaaaaa\") == True\n",
    "assert a.run(\"bbb\") == False"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d16f624a-7810-489c-9b6a-f0bba5eb25f2",
   "metadata": {},
   "source": [
    "**Question 2.2 -** Utilisez votre structure de données pour implémenter les automates de la partie précédente."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "244afe6c-a606-4e1f-b09b-f9dd59882135",
   "metadata": {},
   "source": [
    "Question 1.1 (solution) :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "428cf819-3d60-4776-ba94-3e8733eeadea",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# automate qui valide un nombre pair de fois la lettre \"a\" avec langage a, b\n",
    "a = automate(\"ab\")\n",
    "\n",
    "a.ajout_etat(\"0\", True)\n",
    "a.ajout_etat(\"1\", False)\n",
    "\n",
    "a.ajout_transition(\"0\", \"a\", \"1\")\n",
    "a.ajout_transition(\"1\", \"a\", \"0\")\n",
    "a.ajout_transition(\"0\", \"b\", \"0\")\n",
    "a.ajout_transition(\"1\", \"b\", \"1\")\n",
    "\n",
    "# tests valides\n",
    "assert a.run(\"\") == True\n",
    "assert a.run(\"aa\") == True\n",
    "assert a.run(\"aaaa\") == True\n",
    "assert a.run(''.join(\"a\" for i in range(100))) == True\n",
    "\n",
    "# tests non-valides\n",
    "assert a.run(\"a\") == False\n",
    "assert a.run(''.join(\"a\" for i in range(100 + 1))) == False"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "64e021b0-4613-444d-87d8-b0abeed5aef2",
   "metadata": {},
   "source": [
    "Question 1.2 (solution) :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f51ce343-fcdb-49c0-a126-4ffeaf4e1920",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# automate qui valide a*a\n",
    "a = automate(\"ab\")\n",
    "\n",
    "a.ajout_etat(\"0\", False)\n",
    "a.ajout_etat(\"1\", False)\n",
    "a.ajout_etat(\"2\", True)\n",
    "\n",
    "a.ajout_transition(\"0\", \"a\", \"1\")\n",
    "a.ajout_transition(\"1\", \"a\", \"2\")\n",
    "a.ajout_transition(\"2\", \"a\", \"2\")\n",
    "\n",
    "a.ajout_transition(\"1\", \"b\", \"1\")\n",
    "a.ajout_transition(\"2\", \"b\", \"1\")\n",
    "\n",
    "# tests valides\n",
    "assert a.run(\"aa\") == True\n",
    "assert a.run(\"aaaa\") == True\n",
    "assert a.run(''.join(\"a\" for i in range(100))) == True\n",
    "\n",
    "# tests non-valides\n",
    "assert a.run(\"\") == False\n",
    "assert a.run(\"a\") == False\n",
    "assert a.run(\"aabb\") == False\n",
    "assert a.run(\"b\") == False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6c1a0049-03c3-47b1-adf7-35a59d8c78f7",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# automate qui valide *aaba*\n",
    "a = automate(\"ab\")\n",
    "\n",
    "a.ajout_etat(\"0\", False)\n",
    "a.ajout_etat(\"1\", False)\n",
    "a.ajout_etat(\"2\", False)\n",
    "a.ajout_etat(\"3\", False)\n",
    "a.ajout_etat(\"4\", True)\n",
    "\n",
    "a.ajout_transition(\"0\", \"a\", \"1\")\n",
    "a.ajout_transition(\"1\", \"a\", \"2\")\n",
    "a.ajout_transition(\"2\", \"b\", \"3\")\n",
    "a.ajout_transition(\"3\", \"a\", \"4\")\n",
    "\n",
    "a.ajout_transition(\"0\", \"b\", \"0\")\n",
    "a.ajout_transition(\"1\", \"b\", \"0\")\n",
    "a.ajout_transition(\"2\", \"a\", \"2\")\n",
    "a.ajout_transition(\"3\", \"b\", \"0\")\n",
    "\n",
    "a.ajout_transition(\"4\", \"a\", \"4\")\n",
    "a.ajout_transition(\"4\", \"b\", \"4\")\n",
    "\n",
    "# tests valides\n",
    "assert a.run(\"aaba\") == True\n",
    "assert a.run(\"aaaaaabaaaaa\") == True\n",
    "\n",
    "# tests non-valides\n",
    "assert a.run(\"\") == False\n",
    "assert a.run(\"a\") == False\n",
    "assert a.run(\"aabb\") == False\n",
    "assert a.run(\"b\") == False\n",
    "assert a.run(''.join(\"a\" for i in range(100))) == False"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "954a7d30-9e8a-4269-aee4-e36924da2e86",
   "metadata": {},
   "source": [
    "**Question 2.3 (bonus) -** Implémentez une méthode `__str__` afin que la commande `print(a)` affiche les états internes à l'automate comme ci-dessous :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "43b69f12",
   "metadata": {},
   "outputs": [],
   "source": [
    "automate :\n",
    "   - alphabet   : 'ab'\n",
    "   - init       : 0\n",
    "   - final     : ['1']\n",
    "   - etats (2) :\n",
    "       - (0)automate :\n",
    "   - alphabet   : 'ab'\n",
    "   - init       : 0\n",
    "   - final     : ['1']\n",
    "   - etats (2) :\n",
    "       - (0):\n",
    "          --(b)--> (0)\n",
    "          --(a)--> (1)\n",
    "       - (1):\n",
    "          --(a)--> (1)\n",
    "          --(b)--> (1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "677eed03-4571-4751-bb71-07640eb54927",
   "metadata": {},
   "source": [
    "**Question 2.4 (bonus) -** Implémentez une méthode `visualize(self)` afin d'afficher votre automate en utilisant le code `graphviz` fourni dans les questions précédentes."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6764667b-ab2b-46c1-a5bb-2a12bb670afd",
   "metadata": {},
   "source": [
    "## Exercice 3 : Analyse de texte avec un automate"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b13e013c-8c73-4008-ac92-cf981b2a5cb0",
   "metadata": {},
   "source": [
    "Nous allons maintenant développer un programme qui utilise votre structure de données d'automate implémentée en Python dans la section précédente. L'objectif de ce programme sera le suivant : proposer de compléter un mot, à partir d'une séquence de lettres partielle donnée. Par exemple si votre programme prend en entrée la séquence `bon`, en retour vous devez proposer une séquence de lettres pertinentes afin de compléter ce mot comme `bonjour` ou `bonsoir`. \n",
    "\n",
    "Vous êtes libres de proposer la stratégie de recommandation de lettres que vous souhaitez. Nous vous proposons de vous baser sur es listes de mots les plus fréquents en Français [ce lien](http://www.pallier.org/extra/liste.de.mots.francais.frgut.txt) (fourni dans le fichier `code/mots.txt`). Ces mots permettent de réaliser des statistiques de co-occurences. Par exemple, étant donné les mots suivants :\n",
    "\n",
    "```\n",
    "  abaissa\n",
    "  abaissable\n",
    "  abaissables\n",
    "  abaissai\n",
    "  abaissaient\n",
    "  abaissais\n",
    "  abaissait\n",
    "  abaissâmes\n",
    "```\n",
    "\n",
    "\n",
    "Si le mot d'entrée est `abaissa` alors votre programme suggère les lettres suivantes ordonnées par ordre de probabilité de transition pour compléter le mot (basé sur l'analyse du fichier `code/mots-10.txt` qui contient les mots ci-dessus):\n",
    "\n",
    "\n",
    "\n",
    "```\n",
    "  i (4)\n",
    "  b (2)\n",
    "  m (1)\n",
    "```\n",
    "\n",
    "\n",
    "Conseils :\n",
    "\n",
    "1. Utiliser les fichiers de listes de mots (`mots.txt`, ..) en analysant la fréquence de co-occurrences de lettres (autrement dit calculer probabilité d'être l'une après l'autre)\n",
    "\n",
    "2. Construire un automate dont les transitions sont les probabilités de co-occurence entre les lettres\n",
    "\n",
    "3. Proposer une méthode de recommandation de transition à partir de quelques lettres fournies en entrée\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b5309ac0",
   "metadata": {
    "deletable": false,
    "nbgrader": {
     "cell_type": "code",
     "checksum": "871c056907d157a30a5173a7ab560b23",
     "grade": false,
     "grade_id": "cell-d468616ce83d8d50",
     "locked": false,
     "schema_version": 3,
     "solution": true,
     "task": false
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# YOUR CODE HERE\n",
    "raise NotImplementedError()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "77408003",
   "metadata": {},
   "source": [
    "##  Pour aller plus loin\n",
    "\n",
    "- Vérifier si les automates sont [déterministes](https://fr.wikipedia.org/wiki/Automate_fini_d%C3%A9terministe)\n",
    "\n",
    "- Comparer vos résultats avec une implémentation [Python d'Automate](https://pypi.org/project/python-automaton/) :\n"
   ]
  }
 ],
 "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.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}