\n\n#### Vous devez travailler sur https://notebook.basthon.fr/\n \nVous devez charger ce module : `module_tree_2021.py` dans le document (icone ouvrir fichier puis choisir Installer le module)\n\n\n "},{"metadata":{"id":"0UE_Kb95NwfI"},"cell_type":"markdown","source":"Voici un labyrinthe que nous avons déjà étudié :\n"},{"metadata":{"id":"VfdVzH1_wiFp"},"cell_type":"markdown","source":""},{"metadata":{"id":"4_e9QUrWe-6T"},"cell_type":"markdown","source":"🖐 Nous vous redonnons la représentation de ce labyrinthe avec un arbre.\n\n"},{"metadata":{"id":"9BTmsVf00a9_"},"cell_type":"markdown","source":""},{"metadata":{"id":"lW4y9c6-_95s"},"cell_type":"markdown","source":"I. Implémentation d'arbres avec 2 classes\n\nLes arbres seront ici implémentés avec une classe `Node` et une classe `Arbre`. \nVous n'avez pas besoin de connaître cette implémentation. \n\n👉 Voici les fonctions de l'interface dont vous aurez besoin :\n\nNotre arbre sera modélisé avec un dictionnaire.\n\n```\n#################### Un arbre ###################\n\narbre = Arbre(etiquette) :\n Crée un objet arbre, dont la racine porte l'étiquette passée en paramètre\n Attributs :\n arbre.noeuds : dictionnaire dont les clés sont les etiquettes \n des sommets et les valeurs les objets noeuds associés\n arbre.etiquette_racine : etiquette de la racine de l'arbre\n\n############### Primitives d'accès ###############\n\narbre.empty():\n return True si Arbre est un arbre vide, False sinon\n\narbre.filsD(etiquette) :\n renvoie True si le noeud dont l'etiquette est donnée en paramètre a un fils droit, False sinon.\n \narbre.filsG(etiquette) :\n renvoie True si le noeud dont l'etiquette est donnée en paramètre a un fils gauche, False sinon.\n\narbre.racine() :\n renvoie l'objet noeud de la racine\n Les objets Noeuds disposent de 3 attributs :\n fg et fd : objets Noeud fils gauche et droit\n val : etiquette du noeud fils\n \narbre.est_feuille(etiquette) :\n Renvoie True si le noeud etiquette est une feuille\n \n############### Primitives d'ajouts ###############\n\narbre.addG(etiquette_parent, etiquette_fils) -> None :\n :param etiquette_parent: est une etiquette d'un noeud de l'arbre\n :param etiquette_fils: est l'etiquette du fils gauche à ajouter \n\n addG ajoute un fils gauche au noeud parent\n \n\n\narbre.addD(etiquette_parent, etiquette_fils) -> None :\n :param etiquette_parent: est une etiquette d'un noeud de l'arbre\n :param etiquette_fils: est l'etiquette du fils droit à ajouter \n\n addD ajoute un fils droit au noeud parent\n\n\n############### Primitives d'extraction de sous arbres ###############\n\narbre.sad(etiquette = None):\n si le paramètre cle est absent, la méthode renvoie le SAD de la racine\n si une etiquette et mentionnée, la méthode renvoie le SAD du noeud portant cette etiquette\n\narbre.sag(etiquette = None):\n si le paramètre cle est absent, la méthode renvoie le SAG de la racine\n si une etiquette et mentionnée, la méthode renvoie le SAG du noeud portant cette etiquette\n\n############### Primitive de représentation ###############\n\nprint(arbre) : permet d'afficher l'arbre en mode texte\n\narbre.show(etiquette = None, verts = None):\n Dessin de l'arbre.\n Si etiquette est None, la fonction dessinne l'arbre complet\n Sinon elle dessine le sous arbre dont la racine est etiquette\n Le paramètre verts peut être ajouté : c'est une liste d'étiquettes. \n Tous les noeuds de cette liste seront représentés en vert.\n```"},{"metadata":{"id":"YsLfbBBc_Gg5","trusted":true},"cell_type":"code","source":"from module_tree_2021 import Node, Arbre \nfrom module_tree_2021 import addNodes, make_it","execution_count":1,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Ce n'est pas nécessaire ici, mais vous pouvez exécuter la cellule suivante."},{"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"ll7IWFW7AmEg","outputId":"5f00433b-d53f-41a0-eae4-78b77b1cbe05","trusted":true},"cell_type":"code","source":"help(Node)\nhelp(Arbre)","execution_count":2,"outputs":[{"output_type":"stream","text":"Help on class Node in module module_tree_2021:\n\nclass Node(builtins.object)\n | Node(val: str) -> None\n | \n | Methods defined here:\n | \n | __init__(self, val: str) -> None\n | Crée un noeud, l'étiquette est donnée en argument, les attributs sont :\n | - val : l'etiquette\n | - fg et fd : initialisés à None tout les deux\n | \n | __str__(self) -> str\n | renvoie etiquette (etiquette_fg , etiquette_fils_droit)\n | \n | cree_fd(self, val) -> None\n | val est une étiquette de type str\n | Ajoute Node(val) en fils droit\n | \n | cree_fg(self, val) -> None\n | val est une étiquette de type str\n | Ajoute Node(val) en fils gauche\n | \n | est_feuille(self) -> bool\n | renvoie un booléen : True si self est une feuille, False sinon\n | \n | ----------------------------------------------------------------------\n | Data descriptors defined here:\n | \n | __dict__\n | dictionary for instance variables (if defined)\n | \n | __weakref__\n | list of weak references to the object (if defined)\n\nHelp on class Arbre in module module_tree_2021:\n\nclass Arbre(builtins.object)\n | Arbre(etiquette) -> None\n | \n | # Notre arbre sera modélisé avec un dictionnaire.\n | \n | Methods defined here:\n | \n | __init__(self, etiquette) -> None\n | Intialiste un objet Arbre\n | Attribut noeuds (dict):\n | Initialisé avec une seule clé : noeuds[etiquette] = Node[etiquette]\n | la prodondeur de cette feuille est 0\n | Attribut etiquette_racine :\n | Initialisée à etiquette_racine (jamais modifiée)\n | Si etiquette est égale à None on crée un arbre vide\n | \n | __str__(self)\n | renvoie une str contenant une ligne pour chaque noeud de l'arbre :\n | etiquette_parent : etiquette_fg, etiquette_fd\n | \n | addD(self, etiquette_parent, etiquette_fils) -> None\n | :param etiquette_parent: est une etiquette d'un noeud de l'arbre\n | :param etiquette_fils: est l'etiquette du fils droit à ajouter\n | addD :\n | - ajoute un fils droit au noeud parent : noeud_parent.fd = Node(etiquette_fils)\n | - modifie l'attribut noeuds de l'arbre :\n | noeuds[etiquette_fils] = Node(etiquette_fils)\n | \n | addG(self, etiquette_parent, etiquette_fils) -> None\n | :param etiquette_parent: est une etiquette d'un noeud de l'arbre\n | :param etiquette_fils: est l'etiquette du fils gauche à ajouter\n | addG :\n | - ajoute un fils gauche au noeud parent : noeud_parent.fg = Node(etiquette_fils)\n | - modifie l'attribut noeuds de l'arbre :\n | noeuds[etiquette_fils] = Node(etiquette_fils)\n | \n | add_fils_droite(self, a, noeud)\n | fonction privée\n | \n | add_fils_gauche(self, a, noeud)\n | fonction privée\n | \n | empty(self) -> bool\n | renvoie True si self est vide, False sinon\n | \n | est_feuille(self, etiquette) -> bool\n | Renvoie True si le noeud etiquette est une feuille\n | \n | filsD(self, etiquette) -> bool\n | :param self arbre:\n | :param etiquette: une etiquette d'un noeud\n | renvoie True si ce noeud à un fils droit, False si le fils droit est None\n | \n | filsG(self, etiquette) -> bool\n | :param self arbre:\n | :param etiquette: une etiquette d'un noeud\n | renvoie True si ce noeud à un fils gauche, False si le fils gauche est None\n | \n | get_etiquetteD(self)\n | renvoie l etiquette du fils droit de la racine (None si fd = None)\n | \n | get_etiquetteG(self)\n | renvoie l etiquette du fils gauche de la racine (None si fg = None)\n | \n | get_nodeD(self, etiquette)\n | Renvoie l objet Node du fils droit du noeud etiquette\n | (None si fd = None)\n | \n | get_nodeG(self, etiquette)\n | Renvoie l objet Node du fils gauche du noeud etiquette\n | (None si fg = None)\n | \n | make_nodes(self, g, cle, verts=None)\n | fonction privée\n | \n | racine(self)\n | renvoie l objet Node associé à la racine\n | \n | sad(self, etiquette=None)\n | Renvoie un Arbre SAD du noeud etiquette.\n | Si etiquette n'est pas présent, renvoie le SAD de la racine\n | \n | sag(self, etiquette=None)\n | Renvoie un Arbre SAG du noeud etiquette.\n | Si etiquette n'est pas présent, renvoie le SAG de la racine\n | \n | show(self, etiquette=None, verts=None)\n | :param etiquette: etiquette d'un noeud de l Arbre self\n | :param verts: une liste d etiquettes dont les noeuds seront coloriés en vert\n | Dessine l'arbre en partant du noeud etiquette\n | si etiquette n'est pas présent, dessinne l'Arbre entier.\n | \n | ----------------------------------------------------------------------\n | Data descriptors defined here:\n | \n | __dict__\n | dictionary for instance variables (if defined)\n | \n | __weakref__\n | list of weak references to the object (if defined)\n\n","name":"stdout"}]},{"metadata":{},"cell_type":"markdown","source":"Lire la documentation de la classe `Node` en exécutant ci-dessous."},{"metadata":{"id":"PWWLYvZCpKK6"},"cell_type":"markdown","source":"II. Création de l'arbre\n\nLe module **module_tree_2021** contient une fonction `addNodes`. \n\nCette fonction doit créer l'arbre du labyrinthe que nous étudions, mais elle est incomplète... (😢 quelques nœuds ont été oubliés ... )\n\nCi dessous, on crée un Arbre dont la racine porte l'étiquette \"04\" et on ajoute les nœuds avec addNodes\n\nRegardez le dessin de l'arbre obtenu et comparez avec le votre (fait à la main) pour déterminer les nœuds manquants.\n\nEnsuite, ajoutez les instructions qui permettent d'ajouter ces nœuds (voir les primitives d'ajout disponibles) .\n"},{"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":1000},"id":"f8yf0rEGTk2s","outputId":"8636a34c-467b-4558-abe7-eb6f0501ee39","trusted":true},"cell_type":"code","source":"arbre = Arbre(\"04\")\naddNodes(arbre)\n### après avoir vu l'arbre construit ci-dessous, ajoutez les instructions ci-dessous ###\narbre.addG(\"03\",\"02\")\narbre.addG(\"52\",\"51\")\narbre.addG(\"51\",\"50\")\n# puis refaire le dessin\narbre.show()","execution_count":3,"outputs":[{"output_type":"execute_result","execution_count":3,"data":{"text/plain":"","image/svg+xml":"\n\n\n\n\n"},"metadata":{}}]},{"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":322},"id":"mO1VPAC7G1tw","outputId":"8d643a49-f304-4a62-ce12-108c4502d1e6","trusted":true},"cell_type":"code","source":"# test de votre arbre\nfrom module_tree_2021 import test_arbre\ntest_arbre(arbre)","execution_count":4,"outputs":[{"output_type":"stream","text":"test1 ok: votre arbre contient tous les noeuds\ntest2 ok: votre arbre ne contient pas de noeud surnuméraire\ntest3 ok: votre arbre est correct\n","name":"stdout"}]},{"metadata":{"id":"qY9YC8aHKwCw"},"cell_type":"markdown","source":"En principe `arbre` contient maintenant (et jusqu'à la fin du TP) l'arbre correct. Si toutefois une fausse manipulation le détruisait, vous pouvez le reconstruire avec la cellule ci-dessous :"},{"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"6z4WU5dOK9M9","outputId":"79f9b080-d014-4b45-9719-02a135547c43","trusted":true},"cell_type":"code","source":"from module_tree_2021 import make_it\narbre = make_it()\ntest_arbre(arbre)","execution_count":5,"outputs":[{"output_type":"stream","text":"test1 ok: votre arbre contient tous les noeuds\ntest2 ok: votre arbre ne contient pas de noeud surnuméraire\ntest3 ok: votre arbre est correct\n","name":"stdout"}]},{"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":1000},"id":"GpvHvxNPYSC5","outputId":"4b1da0ab-d3e7-414b-f774-7a4e887495a9","trusted":true},"cell_type":"code","source":"arbre.show()","execution_count":6,"outputs":[{"output_type":"execute_result","execution_count":6,"data":{"text/plain":"","image/svg+xml":"\n\n\n\n\n"},"metadata":{}}]},{"metadata":{"id":"TWYXhD5k4RJe"},"cell_type":"markdown","source":"III. Les parcours en profondeur\n\nQue fait le code ci-dessous ?\n"},{"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"rYQiia7jvE1Y","outputId":"9d33ab84-fec4-4032-8613-8f2364dc0fa1","trusted":true},"cell_type":"code","source":"def mystere(arbre):\n\n print(arbre.etiquette_racine, end = \" -> \")\n\n if arbre.racine().fg is not None : \n mystere(arbre.sag())\n\n if arbre.racine().fd is not None : \n mystere(arbre.sad())\n\nmystere(arbre)","execution_count":7,"outputs":[{"output_type":"stream","text":"04 -> 14 -> 24 -> 23 -> 22 -> 12 -> 13 -> 03 -> 02 -> 32 -> 31 -> 21 -> 11 -> 10 -> 00 -> 01 -> 20 -> 30 -> 40 -> 41 -> 33 -> 34 -> 44 -> 43 -> 42 -> 52 -> 51 -> 50 -> 53 -> 54 -> ","name":"stdout"}]},{"metadata":{"id":"omn6is7tCBeg"},"cell_type":"markdown","source":"Réponse : \n
\n \n\nCe code affiche les nœuds avec un **parcours préfixe** de l'arbre. \n \n
\n\n"},{"metadata":{"id":"OcNa4bQULe15"},"cell_type":"markdown","source":" 💻 **A vous de jouer 1**\n\nComplétez le code pour qu'il renvoie la liste des sommets visités (au lieu d'afficher), en utilisant la même structure que dans la fonction `mystere`ci-dessus.\n"},{"metadata":{"id":"tiefOoD6A6jm","trusted":true},"cell_type":"code","source":"def parcours_prefixe(arbre):\n visites = [arbre.etiquette_racine]\n\n if arbre.racine().fg is not None : \n visites += parcours_prefixe(arbre.sag())\n\n if arbre.racine().fd is not None : \n visites += parcours_prefixe(arbre.sad()) \n \n return visites","execution_count":8,"outputs":[]},{"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":1000},"id":"d0NsjosOA-pA","outputId":"5cdd600a-2ac7-42e2-ed04-3399b8d4cb49","trusted":true},"cell_type":"code","source":"prefixe = parcours_prefixe(arbre)\nprint(prefixe)\n# l'appel de show avec une liste permet d'afficher en vert les noeuds présents dans la liste\n# vérifions que nous avons tout visité :\narbre.show(verts = prefixe)\n","execution_count":9,"outputs":[{"output_type":"stream","text":"['04', '14', '24', '23', '22', '12', '13', '03', '02', '32', '31', '21', '11', '10', '00', '01', '20', '30', '40', '41', '33', '34', '44', '43', '42', '52', '51', '50', '53', '54']\n","name":"stdout"},{"output_type":"execute_result","execution_count":9,"data":{"text/plain":"","image/svg+xml":"\n\n\n\n\n"},"metadata":{}}]},{"metadata":{"id":"7TBFwHJ-MtEz"},"cell_type":"markdown","source":" 💻 **A vous de jouer 2**\n\nFaire de même pour un parcours suffixe en utilisant la même structure que dans la fonction `mystere`ci-dessus.\n"},{"metadata":{"id":"dPNQDLKSC59Y","trusted":true},"cell_type":"code","source":"def parcours_suffixe(arbre):\n visites = []\n \n if arbre.racine().fg is not None : \n visites += parcours_suffixe(arbre.sag())\n\n if arbre.racine().fd is not None : \n visites += parcours_suffixe(arbre.sad()) \n\n visites += [arbre.etiquette_racine]\n\n return visites","execution_count":10,"outputs":[]},{"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":220},"id":"dOaJM9_5DEl4","outputId":"19275777-1397-4901-f4f1-c8887e73ab7d","trusted":true},"cell_type":"code","source":"suffixe = parcours_suffixe( arbre)\nprint(suffixe)\n# vérifiez si tous les noeuds ont été visités :\narbre.show(verts = suffixe)\n","execution_count":11,"outputs":[{"output_type":"stream","text":"['02', '03', '13', '12', '01', '00', '10', '11', '40', '30', '20', '21', '41', '31', '32', '22', '33', '23', '50', '51', '54', '53', '52', '42', '43', '44', '34', '24', '14', '04']\n","name":"stdout"},{"output_type":"execute_result","execution_count":11,"data":{"text/plain":"","image/svg+xml":"\n\n\n\n\n"},"metadata":{}}]},{"metadata":{"id":"xmlLTzLuM_oH"},"cell_type":"markdown","source":" 💻 **A vous de jouer 3**\n\nFaire de même pour un parcours infixe en utilisant la même structure que dans la fonction `mystere`ci-dessus.\n\n"},{"metadata":{"id":"t_rOmkjscP6Q","trusted":true},"cell_type":"code","source":"def parcours_infixe(arbre):\n visites = []\n if arbre.racine().fg is not None : \n visites += parcours_infixe(arbre.sag())\n\n visites += [arbre.etiquette_racine]\n\n if arbre.racine().fd is not None : \n visites += parcours_infixe(arbre.sad()) \n\n return visites","execution_count":12,"outputs":[]},{"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":1000},"id":"D17OZ21ScP6c","outputId":"f0d9af5c-546d-48f5-a16b-03e9ebb40954","trusted":true},"cell_type":"code","source":"infixe = parcours_infixe( arbre)\nprint(infixe)\n# vérifiez si tous les noeuds ont été visités :\narbre.show(verts = infixe)\n","execution_count":13,"outputs":[{"output_type":"stream","text":"['02', '03', '13', '12', '22', '01', '00', '10', '11', '21', '40', '30', '20', '31', '41', '32', '23', '33', '24', '50', '51', '52', '54', '53', '42', '43', '44', '34', '14', '04']\n","name":"stdout"},{"output_type":"execute_result","execution_count":13,"data":{"text/plain":"","image/svg+xml":"\n\n\n\n\n"},"metadata":{}}]},{"metadata":{"id":"InRsnetpY_hs"},"cell_type":"markdown","source":"💡 Une autre écriture plus concise\n\n"},{"metadata":{"id":"oTqnXJR6YJVt","trusted":true},"cell_type":"code","source":"def prefixe(arbre) :\n if arbre.empty():\n return []\n else :\n return [arbre.etiquette_racine] + prefixe(arbre.sag()) + prefixe(arbre.sad()) ","execution_count":14,"outputs":[]},{"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"PiwpQortYWvg","outputId":"5aa644c2-4350-4f83-c783-ccb36a7e3d15","trusted":true},"cell_type":"code","source":"print(prefixe(arbre))","execution_count":15,"outputs":[{"output_type":"stream","text":"['04', '14', '24', '23', '22', '12', '13', '03', '02', '32', '31', '21', '11', '10', '00', '01', '20', '30', '40', '41', '33', '34', '44', '43', '42', '52', '51', '50', '53', '54']\n","name":"stdout"}]},{"metadata":{"id":"sWjGkmWCZIkE"},"cell_type":"markdown","source":" 💻 **A vous de jouer 4**\n\nFaire de même pour un parcours suffixe et un parcours infixe\n"},{"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"P68KvaFEZPEj","outputId":"603db5e2-fb28-4e82-c26d-a3fb2df3234d","trusted":true},"cell_type":"code","source":"def suffixe(arbre) :\n if arbre.empty():\n return []\n else :\n return suffixe(arbre.sag()) + suffixe(arbre.sad()) + [arbre.etiquette_racine] ","execution_count":16,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(suffixe(arbre))","execution_count":17,"outputs":[{"output_type":"stream","text":"['02', '03', '13', '12', '01', '00', '10', '11', '40', '30', '20', '21', '41', '31', '32', '22', '33', '23', '50', '51', '54', '53', '52', '42', '43', '44', '34', '24', '14', '04']\n","name":"stdout"}]},{"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"18Lm1qQBZYhi","outputId":"eddad2a8-586b-4b2e-afdc-9da8c3d748a6","trusted":true},"cell_type":"code","source":"def infixe(arbre) :\n if arbre.empty():\n return []\n else :\n return infixe(arbre.sag()) + [arbre.etiquette_racine] + infixe(arbre.sad()) ","execution_count":18,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(infixe(arbre))","execution_count":19,"outputs":[{"output_type":"stream","text":"['02', '03', '13', '12', '22', '01', '00', '10', '11', '21', '40', '30', '20', '31', '41', '32', '23', '33', '24', '50', '51', '52', '54', '53', '42', '43', '44', '34', '14', '04']\n","name":"stdout"}]},{"metadata":{"id":"NXjXpYg0NasL"},"cell_type":"markdown","source":" 💻 **A vous de jouer 5**\n\nEcrire une fonction récursive `getFeuilles` qui renvoie la liste des culs de sac du labyrinthe (la sortie est comptée comme un cul de sac) "},{"metadata":{"trusted":true},"cell_type":"code","source":"def getFeuilles(arbre):\n if arbre.empty():\n return []\n elif arbre.est_feuille(arbre.etiquette_racine):\n return [arbre.etiquette_racine] \n else:\n return getFeuilles(arbre.sag()) + getFeuilles(arbre.sad())\nfeuilles = getFeuilles(arbre)\nprint(feuilles)\n# vérifiez si les feuilles sont vertes :\narbre.show(verts = feuilles)","execution_count":20,"outputs":[{"output_type":"stream","text":"['02', '01', '40', '41', '33', '50', '54']\n","name":"stdout"},{"output_type":"execute_result","execution_count":20,"data":{"text/plain":"","image/svg+xml":"\n\n\n\n\n"},"metadata":{}}]},{"metadata":{},"cell_type":"markdown","source":"### Autre solution : \nOn peut utiliser le principe du parcours suffixe, mais ne rajouter dans la liste des feuilles que le noeuds visités qui sont des feuilles."},{"metadata":{"trusted":true},"cell_type":"code","source":"def getFeuilles_2(arbre): \n feuilles = []\n \n if arbre.racine().fg is not None : \n feuilles += getFeuilles_2(arbre.sag())\n\n if arbre.racine().fd is not None : \n feuilles += getFeuilles_2(arbre.sad()) \n\n if arbre.est_feuille(arbre.etiquette_racine):\n feuilles += [arbre.etiquette_racine]\n \n return feuilles\n\n\nfeuilles = getFeuilles_2(arbre)\nprint(feuilles)\n# vérifiez si les feuilles sont vertes :\narbre.show(verts = feuilles)","execution_count":23,"outputs":[{"output_type":"stream","text":"['02', '01', '40', '41', '33', '50', '54']\n","name":"stdout"},{"output_type":"execute_result","execution_count":23,"data":{"text/plain":"","image/svg+xml":"\n\n\n\n\n"},"metadata":{}}]},{"metadata":{"id":"UrHwTvOZVX5-"},"cell_type":"markdown","source":"\n
\n\n---\n\n**Auteurs** Jean-Louis Thirot - Lycée Bertrand d'Argentré - Vitré (35) et Mireille Coilhac (Melun)\n\nPublié sous licence CC BY-NC-SA\n\n\n---\n This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. "}],"metadata":{"colab":{"collapsed_sections":[],"provenance":[]},"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"}},"nbformat":4,"nbformat_minor":2}