{"cells": [{"cell_type": "markdown", "id": "40540b19", "metadata": {}, "source": ["# Objets\n", "\n", "## Vecteur\n", "\n", "Cr\u00e9er une classe Vecteur3D. Chaque vecteur aura 3 attributs : x, y, z\n", "\n", "* \u00c9crire une m\u00e9thode norme qui renvoie la norme.\n", "* \u00c9crire la m\u00e9thode ``__add__`` pour faire la somme entre deux veteurs\n", "* \u00c9crire la m\u00e9thode ``__mul__`` pour faire soit le produit par un scalaire ($2\\vec{u}$) ou le produit scalaire ($\\vec{u}\\cdot\\vec{v}$)."]}, {"cell_type": "markdown", "id": "a4d45511", "metadata": {}, "source": ["## Bibliographie\n", "\n", "\n", "Un livre est d\u00e9crit par son titre, auteur et ann\u00e9e de publication (pour faire les choses simplements). \u00c9crire une classe ``Livre`` qui enregistre ces informations. Ecrire la m\u00e9thode ``__repr__`` et ``__str__``.\n", "\n", "Une bibliographe est une liste de livre. \u00c9crire la classe ``Bibliographie`` qui enregistre une liste de livre (on stockera la liste de livre sous forme d'une liste qui sera un attribut de la bibliographie).\n", "\n", "L'objectif final est de pouvoir faire ceci :: \n", "\n", " livre1 = Livre(\"A very nice book\", \"F. Dupont\", 2014)\n", " livre2 = Livre(\"A very smart book\", \"A. Einstein\", 1923)\n", " livre3 = Livre(\"A very stupid comic\", \"D. Duck\", 1937)\n", "\n", " bibliographie = Bibliographie([book1, book2, book3])\n", "\n", "Maintenant que tout est fait sous forme d'objet, on peut imaginer \u00e9crire plusieurs m\u00e9thode : \n", "\n", "* \u00c9crire une m\u00e9thode ``filter_by_year`` qui fait une nouvelle bibliographie ne contenant que les livres d'une ann\u00e9e don\u00e9e.\n", "* \u00c9crire une m\u00e9thode ``to_html`` qui formate correctement la bibliographie. La m\u00e9thode de la classe Bibliographie devra appeler une m\u00e9thode pour chaque Livre.\n", "\n", "Et en HTML :: \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
AuteurTitreAnn\u00e9e
F. Dupont2014A very nice book
A. Einstein1923A very smart book
D. Duck1937A very stupid comic
\n", "\n", "Remarque : si un objet poss\u00e8de une m\u00e9thode ``_repr_html_``, alors le jupyter notebook utilsera automatiquement la repr\u00e9sentation en HTML. Rajouter cette m\u00e9thode (qui appelera to_html)."]}, {"cell_type": "markdown", "id": "157d8474", "metadata": {}, "source": ["## Syst\u00e8me de calcul formel\n", "\n", "*Cet exercice est \u00e0 but purement p\u00e9dagogique. Pour utiliser un syst\u00e8me de calcul formel sous Python, la librairie ``sympy`` existe et fonctionnera bien mieux que ce que l'on va faire !*\n", "\n", "\n", "L'objectif de ce TD est de r\u00e9aliser un syst\u00e8me de calcul formel qui permettra de manipuler des expressions alg\u00e9briques simples et de r\u00e9aliser des op\u00e9rations simples. Par exemple, on souhaite pouvoir effectuer ::\n", "\n", "```\n", "x = Symbol('x')\n", "y = Symbol('y')\n", "\n", "s = 2*x*y + sin(x)*y\n", "\n", "print(s.diff(x)) # D\u00e9riv\u00e9e par rapport \u00e0 x\n", "```\n", "\n", "Chaque expression sera repr\u00e9sent\u00e9e par un arbre. Les feuilles de l'arbre seront soit les symboles soit les constantes num\u00e9riques. Les noeuds seront des fonctions \u00e0 un ou plusieurs argument (sinus, somme, oppos\u00e9, ...). Le nom de la classe du noeud d\u00e9signera la fonction. Les \"enfants\" du noeud seront les arguments de la fonction. Par exemple l'expression ci dessus correspondra \u00e0 l'objet suivant ::\n", "\n", "```\n", "# sA : 2*x*y\n", "sA = Prod(Prod(Number(2), Symbol('x')), Symbol('y'))\n", "# sB : sin(x)*y\n", "sB = Prod(Sin(Symbol('x')), Symbol('y'))\n", "\n", "s = Sum(sA, sB)\n", "```\n", "\n", "### Structure du programme\n", "\n", "Voici la structure de base ::\n", "\n", "```\n", "class Expr(object):\n", " pass\n", "\n", "class Node(Expr):\n", " pass\n", "\n", "class Leave(Expr):\n", " pass\n", "```\n", "\n", "Pour les feuilles ::\n", "\n", "```\n", "class Symbol(Leave):\n", " pass\n", "\n", "class Number(Leave):\n", " pass\n", "```\n", "\n", "Ensuite on d\u00e9finit les fonctions ::\n", "\n", "```\n", "class Function(Node):\n", " \"\"\" Function with an arbitrary number of arguments \"\"\"\n", " pass\n", "```\n", "\n", "Les op\u00e9rateurs sont des fonctions comme les autres, mais elle seront simplement affich\u00e9es diff\u00e9remment ::\n", "\n", "```\n", "class BinaryOperator(Function):\n", " pass\n", "\n", "class Sum(BinaryOperator):\n", " pass \n", "# Idem pour Sub, Div, Prod, Pow\n", "\n", "class UnitaryOperator(Function):\n", " pass\n", "\n", "class Neg(UnitaryOperateor):\n", " pass\n", "```\n", "\n", "Les fonction math\u00e9matiques, qui prennent un seul argument ::\n", "\n", "```\n", "class MathFunction(Function):\n", " pass\n", "\n", "class Sin(MathFunction):\n", " pass\n", "```\n", "\n", "### Questions\n", "\n", "On va proc\u00e9der \u00e9tape par \u00e9tape. Il sera plus facile de commencer par les feuilles avant d'\u00e9crire la structure globale. \n", "\n", "\n", "1. Ecrire le ``__init__`` de la classe Symbol et Number"]}, {"cell_type": "markdown", "id": "fa8ea3f4", "metadata": {}, "source": ["2. Ecrire une m\u00e9thode ``display`` sur ces classes afin de renvoyer une cha\u00eene de caract\u00e8re contenant le symbole ou le nombre"]}, {"cell_type": "markdown", "id": "1fe3cfba", "metadata": {}, "source": ["3. Ecrire le ``__init__`` de la class Sin ainsi que le display. Le display devra appeler le display de l'argument. Par exemple ceci devra fonctionner :: \n", "\n", "```\n", ">>> x = Symbol('x')\n", ">>> Sin(x).display()\n", "sin(x)\n", ">>> Sin(Sin(x)).display()\n", "sin(sin(x))\n", "```"]}, {"cell_type": "markdown", "id": "bef74c73", "metadata": {}, "source": ["4. G\u00e9n\u00e9raliser le __init__ et le display de ``Sin`` afin de le mettre dans la class MathFunction. On rajoutera un attribut de classe \u00e0 chaque sous classe de MathFunction :: \n", "\n", "```\n", "class Sin(MathFunction):\n", " funtion_name = 'sin'\n", "```"]}, {"cell_type": "markdown", "id": "5c963e24", "metadata": {}, "source": ["5. Faire de m\u00eame pour les op\u00e9rateurs binaires. On pourra commencer par simplement le faire pour Sum, puis g\u00e9n\u00e9raliser avec un attribut de classe :: \n", "\n", "```\n", "class Sum(BinaryOperator):\n", " operator_name = '+'\n", "```"]}, {"cell_type": "markdown", "id": "1e18c4b8", "metadata": {}, "source": ["6. A ce stade quelque chose comme ceci devrait fonctionner ::\n", "\n", "```\n", "x = Symbol('x')\n", "y = Symbol('y')\n", "Sum(x, Sin(Prod(x, y)))\n", "```\n", "\n", "Rajouter les m\u00e9thodes ``__add__``, ``__mul__``, etc \u00e0 la classe Expr afin de pouvoir \u00e9crire :\n", "\n", "```\n", ">>> x + Sin(x*y)\n", "```"]}, {"cell_type": "markdown", "id": "87f98e37", "metadata": {}, "source": ["7. Ecrire les m\u00e9thodes ``evaluate`` afin de calculer la valeur num\u00e9rique d'une expression. Cette m\u00e9thode fonctionnera de la sorte : \n", "\n", "```\n", ">>> expr = x + Sin(x*y)\n", ">>> expr.evaluate(x=1, y=3)\n", "```\n", "\n", "On aura donc le protocole suivant ::\n", " \n", "```\n", "def evaluate(self, **kwd):\n", " pass\n", "```\n", "\n", "Le dictionnaire kwd sera pass\u00e9 r\u00e9cursivement jusqu'aux feuilles et sera utilis\u00e9 pour \u00e9valuer les symboles. \n", "\n", "Les op\u00e9rateurs binaires num\u00e9riques sont d\u00e9finis dans le module ``operator`` et les fonctions dans le module ``math``. Afin de factoriser le code, on rajoutera donc simplement un attribut de classe du type ``operator_function = operator.add`` pour les op\u00e9rateurs binaires et ``math_function = math.sin`` pour les fonctions. "]}, {"cell_type": "markdown", "id": "d9967332", "metadata": {}, "source": ["8. Maintenant que vous avez compris le principe, il devrait \u00eatre facile d'\u00e9crire une m\u00e9thode ``diff`` qui effectue la d\u00e9riv\u00e9e par rapport \u00e0 une variable !\n", "\n", "9. Reste \u00e0 simplifier les expressions. Une technique consiste \u00e0 cr\u00e9er des r\u00e8gles de simplifications sous forme de m\u00e9thode que l'on regroupe ensuite dans une liste ::\n", "\n", "```\n", "class Sum(BinaryOperator):\n", " operator_name = '+'\n", " operator_function = operator.add\n", "\n", " def simplication_de_deux_nombres(self):\n", " if isinstance(self.arg1, Number) and \n", " isinstance(self.arg2, Number):\n", " return Number(self.arg1.value + self.arg2.value)\n", "\n", " def simplication_addition_avec_zero(self):\n", " pass\n", "\n", " liste_simplication = ['simplication_de_deux_nombres', \n", " 'simplication_addition_avec_zero'] \n", "```\n", "\n", "Ensuite, il faut r\u00e9ussir \u00e0 appeler correctement et de fa\u00e7on recursive ces m\u00e9thodes...\n", "\n", "10. Pour l'affichage des op\u00e9rateurs binaires, les r\u00e8gles de priorit\u00e9 peuvent \u00eatre utilis\u00e9es pour \u00e9viter de mettre trop de parenth\u00e8ses. Par exemple, dans le cas ``a*(b+c)``, la multiplication appelle le display de l'addition. Comme elle est prioritaire, l'addition va renvoyer le r\u00e9sulat avec des parenth\u00e8ses. Dans le cas inverse ``a + b*c``, c'est inutile. Il faut donc que le display d'un op\u00e9rateur passe sa priorit\u00e9 \u00e0 ses enfants lors de l'appel de display. Impl\u00e9menter ce principe."]}], "metadata": {"kernelspec": {"display_name": "Python 3", "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.8.8"}, "varInspector": {"cols": {"lenName": 16, "lenType": 16, "lenVar": 40}, "kernels_config": {"python": {"delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())"}, "r": {"delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) "}}, "types_to_exclude": ["module", "function", "builtin_function_or_method", "instance", "_Feature"], "window_display": false}}, "nbformat": 4, "nbformat_minor": 5}