{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "*ENSAM-Bordeaux, Mathématiques et informatique. Date : le 09/11/19. Auteur : Éric Ducasse. Version : 1.0*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
*On pourra faire exécuter ce notebook cellule par cellule $\\left(\\mathtt{Maj+Entrée}\\right)$ ou intégralement par $\\mathtt{\\;Kernel\\rightarrow Restart\\;\\&\\;Run\\;All}$.*
" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import sympy as sb\n", "sb.init_printing()\n", "print(\"Version de sympy :\",sb.__version__) \n", "from IPython.display import display" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# **Calcul formel : TD n°3, première partie

$\\hspace{5cm}$Approximation par différences finies**
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
**Pour chaque exercice, faire exécuter la partie *exemples* cellule par cellule $\\left(\\mathtt{Maj+Entrée}\\right)$, avant de passer à la partie *Travail à faire*.**
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## *Exercice 14* " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 14.1 Objectifs " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### * Savoir déterminer l’approximation par différences finies d’une dérivée d’ordre quelconque à un ordre quelconque et
sur une grille quelconque de points, par l'utilisation de la méthode `as_finite_difference` ;
connaître également la méthode de recherche des coefficients de cette approximation par écriture de développements limités,
puis construction et résolution d’un système linéaire.
*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 14.2 Exemples " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
**Principe de la méthode : lorsqu'on veut approcher la dérivée $n$-ème d'une fonction $f$ en $x$ à l'ordre $r$, il faut évaluer cette fonction sur une grille de $(n+r)$ points. En chaque point, on approche la valeur de la fonction $f$ en ce point comme un développement limité de $f$ en $x$ à l'ordre $n+r$.**
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**On crée d'abord une fonction `approx_DL` qui renvoie l'équation approchée ainsi que la liste des inconnues :**" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fonc_test = sb.Function(\"f0\")\n", "fonc_test.__name__" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "try : print(f\"fonc_test.name : '{fonc_test.name}'\")\n", "except Exception as e : \n", " print(f\"'fonc_test.name' non accepté par la version {sb.__version__} de sympy : {e}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def approx_DL(ordre_DL, fonction=\"f\", variable=\"x\", ecart=\"h\", valeur_dans_grille=True) :\n", " \"\"\"Cette fonction renvoie une équation approchée de fonction(variable+ecart) \n", " en fonction des valeurs de fonction(variable) et de ses dérivées jusqu'à\n", " l'ordre ordre_DL-1, ainsi que le liste de ces dérivées. \n", " Si valeur_dans_grille est False (cas inhabituel), la liste contient aussi \n", " fonction(variable).\n", " \"\"\"\n", " if not isinstance(fonction,sb.function.UndefinedFunction) : \n", " fonction = sb.Function(fonction) # fonction est une chaîne de caractères\n", " if not isinstance(variable,sb.Symbol) : \n", " variable = sb.symbols(variable) # variable est une chaîne de caractères\n", " if not isinstance(ecart,sb.Symbol) : \n", " ecart = sb.symbols(ecart) # ecart est une chaîne de caractères\n", " DL = fonction(variable+ecart).series(ecart,0,ordre_DL).doit()\n", " if valeur_dans_grille : inconnues = []\n", " else : inconnues = [ fonction(variable) ]\n", " regles = dict()\n", " if ordre_DL <= 4 :\n", " for d in range(1,ordre_DL) :\n", " ddf = sb.Function(fonction.__name__+d*\"'\")\n", " inconnues.append( ddf(variable) )\n", " regles[ fonction(variable).diff(variable,d)] = ddf(variable)\n", " else :\n", " for d in range(1,4) :\n", " ddf = sb.Function(fonction.__name__+d*\"'\")\n", " inconnues.append( ddf(variable) )\n", " regles[ fonction(variable).diff(variable,d)] = ddf(variable)\n", " for d in range(4,ordre_DL) :\n", " ddf = sb.Function(fonction.__name__+f\"^[{d}]\")\n", " inconnues.append( ddf(variable) )\n", " regles[ fonction(variable).diff(variable,d)] = ddf(variable)\n", " \n", " eq_approchee = sb.Eq( fonction(variable+ecart), DL.xreplace(regles).replace(sb.O,lambda *X : 0) )\n", " return eq_approchee, inconnues" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "approx_DL(4)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "approx_DL(4, valeur_dans_grille=False)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "approx_DL(6,\"g\",\"t\",\"tau\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
**Exemple de la dérivée première $f^{\\prime}(x)$ à l'ordre 2, en fonction de $f(x)$, $f(x+h)$ et $f(x+k)$ :**
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* **Utilisation de la méthode `as_finite_difference` : **" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x,h,k = sb.symbols(\"x,h,k\", real=True)\n", "f = sb.Function(\"f\")\n", "d1f_ordre2 = f(x).diff(x).as_finite_difference([x,x+h,x+k])\n", "d1f_ordre2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def simplifier_termes_somme(S) :\n", " \"\"\"Simplifie chaque terme de la somme S.\"\"\"\n", " if S.func.__name__ == 'Add' :\n", " liste = [ T.simplify() for T in S.args ]\n", " return sb.Add(*liste)\n", " else :\n", " return S" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "simplifier_termes_somme(d1f_ordre2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* **Recherche de ce développement « à la main » : **" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "eq_h, inconnues = approx_DL(3,f,x,h)\n", "inconnues" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"Développement limité en x+h :\")\n", "eq_h" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "eq_k = eq_h.xreplace({h:k})\n", "print(\"Développement limité en x+k :\")\n", "eq_k" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "solu = sb.solve([eq_h,eq_k], inconnues)\n", "print(\"La résolution du système de deux équations à deux inconnues donne :\")\n", "solu" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "d1f_ordre2_trouve = solu[inconnues[0]].expand().collect([f(x),f(x+h),f(x+k)])\n", "simplifier_termes_somme(d1f_ordre2_trouve)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"Vérification :\",d1f_ordre2.equals(d1f_ordre2_trouve))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
**Exemple de la dérivée seconde $f^{\\prime\\prime}(x)$ à l'ordre 2, en fonction de $f(x-h)$, $f(x)$, $f(x+h)$ et $f(x+2\\,h)$ :**
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Si on veut la dérivée seconde à l'ordre 2, il faut prendre $2+2=4$ points.*" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "d2f_ordre2 = f(x).diff(x,2).as_finite_difference( [x-h,x,x+h,x+2*h] )\n", "d2f_ordre2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Le coefficient de $f(x+2\\,h)$ étant nul, cette approximation est bien « centrée ».*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*On peut vérifier le résultat obtenu :*" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "d2f_ordre2.series(h,0,2).doit()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 14.3 Travail à faire " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$a)$ Approcher $f^{\\prime}(x)$ par différences finies d'ordre 2 en fonction des valeurs de la fonction $f$ en :
$\\hspace{2cm}\\displaystyle\\left\\|\\begin{array}{lllll}\n", "(i) & x-h & x & x+h & \\mathrm{(schéma\\;centré)\\;;} \\\\\n", "(ii) & x & x+h & x+2\\,h & \\mathrm{(schéma\\;décentré\\;avec\\;les\\;points\\;à\\;droite)\\;;} \\\\\n", "(iii) & x-2\\,h & x-h & x & \\mathrm{(schéma\\;décentré\\;avec\\;les\\;points\\;à\\;gauche).}\n", "\\end{array}\\right.$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Il faut bien prendre $3=1+2$ points pour avoir une approximation à l'ordre 2.*" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df_centre = f(x).diff(x).as_finite_difference([x-h,x,x+h]).simplify()\n", "df_centre" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df_droite = f(x).diff(x).as_finite_difference([x,x+h,x+2*h]).simplify()\n", "df_droite" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df_gauche = f(x).diff(x).as_finite_difference([x-2*h,x-h,x]).simplify()\n", "df_gauche" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Vérifications :\n", "[ df.series(h,0,2).doit() for df in (df_centre,df_gauche,df_droite) ]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "b) Donner toutes les approximations possibles à l'ordre 4 de $f^{\\prime}(x)$ et $f^{\\prime\\prime}(x)$ en fonction de valeurs de la fonction $f$ en des points régulièrement espacés (pas $h$) et contenant $x$. Parmi ces approximations, quelles sont celles qui sont centrées ?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pour la dérivée première, il faut prendre 5 points, et il y a 5 agencements possibles." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "points = [ x+i*h for i in range(-4,5) ]\n", "for d in range(5) :\n", " print(f\"série n°{d+1} :\",points[d:d+5] )" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Ld1 = [ f(x).diff(x).as_finite_difference(points[d:d+5]).simplify() for d in range(5) ]\n", "from IPython.display import display\n", "for e in Ld1 : display(e)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "d1f_ordre4_centre = Ld1[2] ; d1f_ordre4_centre" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Vérifications :\n", "[ df.series(h,0,4).doit() for df in Ld1 ]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pour la dérivée seconde, il faut prendre 6 points, et il y a 6 agencements possibles." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pts2 = [ x+i*h for i in range(-5,6) ]\n", "for d in range(6) :\n", " print(f\"série n°{d+1} :\",pts2[d:d+6] )" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Ld2 = [ f(x).diff(x,2).as_finite_difference(pts2[d:d+6]).simplify() for d in range(6) ]\n", "for e in Ld2 : display(e)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Schémas centrés :\n", "Ld2[2]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "(Ld2[2]).equals(Ld2[3])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Vérifications :\n", "[ df.series(h,0,4).doit() for df in Ld2 ]" ] } ], "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.6.5" } }, "nbformat": 4, "nbformat_minor": 2 }