diff --git a/.gitignore b/.gitignore index d060d41..75ea0dd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,20 @@ *.aux *.log *.nav *.out *.snm *.toc *.vrb .DS_Store .ipynb_checkpoints/ /1.1 Interpolation.pdf /1.1 Interpolation.slides.html +/InterpolationLibSol.py +/NonLinearEquationsLibSol.py /__pycache__ +/analyse-numerique* /numerical_analysis_handout.ipynb /numerical_analysis_handout.pdf /numerical_analysis_handout.tex /numerical_analysis_handout_files /reveal.js -/analyse-numerique* \ No newline at end of file diff --git a/Jupyter tutorial.ipynb b/0.1 Jupyter tutorial.ipynb similarity index 98% rename from Jupyter tutorial.ipynb rename to 0.1 Jupyter tutorial.ipynb index 92a693d..5e4c4a2 100644 --- a/Jupyter tutorial.ipynb +++ b/0.1 Jupyter tutorial.ipynb @@ -1,153 +1,153 @@ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Jupyter Notebook Tutorial\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Course**: [_Analyse Numérique pour SV_](https://moodle.epfl.ch/course/info.php?id=) (MATH-2xx)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Prof** _Simone Deparis_\n", "\n", "SSV, BA4, 2020" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Adapted from the [Jupyter tutorial](https://github.com/aparrish/rwet/blob/master/jupyter-notebook-tutorial.ipynb) by [Allison Parrish](https://www.decontextualize.com/) and the version of Prof. Felix Naef for BIO-341" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Jupyter Notebook gives you a convenient way to experiment with Python code, interspersing your experiments with notes and documentation. You can do all of this without having to muck about on the command line, and the resulting file can be easily published and shared with other people. In this course, I'll be using Jupyter Notebook to do in-class examples, and the notes will be made available as Jupyter Notebooks. Some of the homeworks will be assigned in the form of Jupyter Notebooks as well.\n", "\n", "A Jupyter Notebook consists of a number of \"cells,\" stacked on the page from top to bottom. Cells can have text or code in them. You can change a cell's type using the \"Cell\" menu at the top of the page; go to `Cell > Cell Type` and select either `Code` for Python code or `Markdown` for text. (You can also change this for the current cell using the drop-down menu in the toolbar.)\n", "\n", "## Text cells\n", "\n", "Make a new cell, change its type to `Markdown`, type some stuff and press `Ctrl-Enter`. Jupyter Notebook will \"render\" the text and display it on the page in rendered format. You can hit `Enter` or click in the cell to edit its contents again. Text in `Markdown` cells is rendered according to a set of conventions called Markdown. Markdown is a simple language for marking up text with basic text formatting information (such as bold, italics, hyperlinks, tables, etc.). [Here's a tutorial](http://markdowntutorial.com/). You'll also be learning Markdown in more detail in the Foundations course.\n", "\n", "## Code cells\n", "\n", "You can also press `Alt-Enter` to render the current cell and create a new cell. New cells will by default be `Code` cells. Try it now!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"This is a code cell.\")\n", "print(\"\")\n", "print(\"Any Python code you type in this cell will be run when you press the 'Run' button,\")\n", "print(\"or when you press Ctrl-Enter.\")\n", "print(\"\")\n", "print(\"If the code evaluates to something, or if it produces output, that output will be\")\n", "print(\"shown beneath the cell after you run it.\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"If your Python code generates an error, the error will be displayed in addition\")\n", "print(\"to any output already produced.\")\n", "\n", "1 / 0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Any variables you define or modules you import in one code cell will be available in subsequent code cells. Start with this:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import random\n", "stuff = [\"cheddar\", \"daguerrotype\", \"elephant\", \"flea market\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... and in subsequent cells you can do this:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(random.choice(stuff))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Keyboard shortcuts\n", "\n", "As mentioned above, `Ctrl-Enter` runs the current cell; `Alt-Enter` runs the current cell and then creates a new cell. `Enter` will start editing whichever cell is currently selected. To quit editing a cell, hit `Esc`. If the cursor isn't currently active in any cell (i.e., after you've hit `Esc`), a number of other keyboard shortcuts are available to you:\n", "\n", "* `m` converts the selected cell to a Markdown cell\n", "* `b` inserts a new cell below the selected one\n", "* `x` \"cuts\" the selected cell; `v` pastes a previously cut cell below the selected cell\n", "* `h` brings up a help screen with many more shortcuts.\n", "\n", "## Saving your work\n", "\n", "Hit `Cmd-S` at any time to save your notebook. Jupyter Notebook also automatically saves occasionally. Make sure to give your notebook a descriptive title by clicking on \"Untitled0\" at the top of the page and replacing the text accordingly. Notebooks you save will be available on your server whenever you log in again, from wherever you log into the server.\n", "\n", "You can \"download\" your notebook in various formats via `File > Download as`. You can download your notebook as a static HTML file (for, e.g., uploading to a web site), or as a `.ipynb` file, which you can share with other people who have Jupyter Notebook or make available online through, e.g., [nbviewer](http://nbviewer.ipython.org/)." ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python 3", + "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.7.6" + "version": "3.7.7" } }, "nbformat": 4, "nbformat_minor": 4 } diff --git a/Python tutorial.ipynb b/0.2 Python tutorial.ipynb similarity index 100% rename from Python tutorial.ipynb rename to 0.2 Python tutorial.ipynb diff --git a/0.3 Some Exercises.ipynb b/0.3 Some Exercises.ipynb new file mode 100644 index 0000000..3120da4 --- /dev/null +++ b/0.3 Some Exercises.ipynb @@ -0,0 +1,420 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Some exercises\n", + "\n", + "**Course**: [_Analyse Numérique pour SV_](https://moodle.epfl.ch/course/info.php?id=) (MATH-2xx)\n", + "\n", + "Original by prof. Fabio Nobile\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Before starting to work on this exercise session, you should review the material in the short `Python tutorial` available on Moodle." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 0 -- Learning Python using Python." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Type the following commands and look at the results. Begin by importing numpy and matplotlib.pyplot as " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "These are the libraries that python relies upon for scientific computing and plotting. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| No. | Code | Instruction |\n", + "| --- | --- | --- |\n", + "| 1 | `a=7` | Define $a$ as a scalar variable which has type `int` |\n", + "| 2 | `a=7.1` | Define $a$ as a scalar variable which has type `float` |\n", + "| 3 | `b=np.array([1,2,3])` | Define $b\\in\\mathbb{R}^{1 \\times 3}$. What happens if you replace `,` by `''` or `;`? |\n", + "| 4 | `g=b[2]` | Return the **third** element of $b$. Note: Indexation starts at 0. |\n", + "| 5 | `E=np.array([[1, 2, 3],[4, 5, 6]])` | Create matrix $E\\in\\mathbb{R}^{2\\times3}$. Note: Python is case sensitive. |\n", + "| 6 | `E[0,:]` | Return first row of $E;$ $(1,4)^T$ |\n", + "| 7 | `h=E[1,2]` | Return the element $E_{2,3}$ of the matrix $E$ ($E_{2,3}=6$). |\n", + "| 8 | `%whos` | Fetch information about the used variables. |\n", + "| 9 | `help(np.sin)` | Fetch help for the command ` np.sin`. Same as `? np.sin` in iPython. |\n", + "| 10 | `A=np.eye(3)` | Return the identity matrix $3\\times 3$ |\n", + "| 11 | `I=np.ones((4,4))` | Return matrix $4\\times 4$ for which each value is 1 |\n", + "| 12 | `F=np.zeros((2,3))` | Return $F\\in\\mathbb{R}^{2\\times 3}$ for which each value is 0 |\n", + "| 13 | `F.T` | Perform transpose of $F$ |\n", + "| 14 | `x=np.linspace(0,1,3)` | Return a vector of length $3$ whose values are equally distributed between $0$ and $1$ |\n", + "| 15 | `D=np.diag(b)` | Return diagonal matrix with diagonal given by vector b. |\n", + "| 16 | `np.shape(F)` | Return the number of lines and columns of $F$ in a line vector. |\n", + "| 17 | `A@D` | Return product of two matrices |\n", + "| 18 | `E@x` | Return matrix vector product |\n", + "| 19 | `A[-1,1]` | Return element of $A$ which is on the last line, second column |\n", + "| 20 | `H=np.array([[1, 3],[9, 11]]);np.linalg.solve(H,E)` | Compute $H^{-1}E$. Note: Never use `np.linalg.inv(H)@E` |\n", + "| 21 | `np.linalg.det(H)` | Compute determinant of $H$ |" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "## type here and execute the 21 commands above\"\n", + "#1\n", + "a=7\n", + "print('#1',a),\n", + "#2 continue by yourself" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 1\n", + "\n", + "Fibonacci's series is defined as follows:\n", + "$$\\begin{align*}\n", + "F_0&=1\\\\\n", + "F_1&=1\\\\\n", + "F_{n}&=F_{n-1}+F_{n-2}, \\quad \\forall n \\geq 2\n", + "\\end{align*}$$\n", + "* Complete the `Python` function below which computes the $30^{\\text{th}}$ Fibonacci's number.\n", + "\n", + "* Write a function which takes as an argument a natural number $n$ and returns the $n^{\\text{th}}$ Fibonacci's number.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "jupyter": { + "source_hidden": true + } + }, + "outputs": [], + "source": [ + "#COMPLETE THIS CODE\n", + "def Fibonacci(n):\n", + " # n should be a positive integer\n", + " # Complete this code\n", + " Fn=None #Change this value\n", + " # ...\n", + " return Fn\n", + "\n", + "F30=Fibonacci(30)\n", + "print(F30)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 2\n", + "Let us consider the matrices \n", + "\\begin{align*}\n", + "A=\n", + "\\begin{bmatrix}\n", + "5 & 3 & 0\\\\\n", + "1 & 1 & -4\\\\\n", + "3 & 0 & 0\n", + "\\end{bmatrix}, \\quad\n", + "B=\n", + "\\begin{bmatrix}\n", + "4 & 3 & 2\\\\\n", + "0 & 1 & 0\\\\\n", + "5 & 0 & 1/2\n", + "\\end{bmatrix}.\n", + "\\end{align*}\n", + "Compute (without using any loops), the matrix $C=AB$ (matrix product) and the matrix $D$ which\n", + "has as elements $D_{ij}=A_{ij}B_{ij}$ (element-wise product)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Solution:\n", + "\n", + "We can use the Python commands `@` for matrix multiplication and `*` for element-wise multiplication, as shown below:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "A=np.array([ [5,3,0],\n", + " [1,1,-4],\n", + " [3,0,0]])\n", + "B=np.array([ [4,3,2],\n", + " [0,1,0],\n", + " [5,0,1/2]])\n", + "\n", + "\n", + "# Complete this code\n", + "C=None #Change this value\n", + "D=None #Change this value\n", + "\n", + "\n", + "print('C matrix')\n", + "print(C)\n", + "\n", + "print('D matrix')\n", + "print(D)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 3\n", + "\n", + "Define (without using any loops) the\n", + "bidiagonal matrix of size $n=5$ whose main diagonal is a vector\n", + "of equally distributed points between $3$ and $6$, i.e. $$D=(3, 3.75, 4.5, 5.25, 6)^T,$$\n", + "\n", + "and the sub-diagonal is the vector of equally distributed points between $2$ and $3.5$, i.e. $$S=(2, 2.5, 3, 3.5)^T.$$\n", + "\n", + "\n", + "Tip: See ``https://numpy.org/doc/stable/reference/generated/numpy.diag.html``\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Solution\n", + "\n", + "Following the reference for the`diag` method of numpy we obtain:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Complete this code\n", + "D=None #Change this value\n", + "S=None #Change this value\n", + "M=None #Change this value\n", + "\n", + "print('The matrix M is')\n", + "print(M)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Remember that you can also obtain help from a python function using the command \n", + "`help(NAME OF FUNCTION)`. In this case: `help(np.diag)`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "help(np.diag)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 4\n", + "Let us consider the vectors $x=(1,4,7,2,1,2)$ and $y=(0,9,1,4,3,0)$. \n", + "Compute (without using any loops for points a and b):\n", + "1. the product, component by component, between two vectors $x$ and $y$ (tip: use the operator `*`)\n", + "2. the scalar product between the same vectors $x$ and $y$ (tip: use the operator `@`)\n", + "3. a vector whose elements are defined by:\n", + "$v_1=x_1\\,y_n, \\quad v_2=x_2\\, y_{n-1},\\quad \\dots, \\quad v_{n-1}=x_{n-1}\\, y_2,\\quad v_n=x_n\\,y_1$.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x=np.array([1,4,7,2,1,2])\n", + "y=np.array([0,9,1,4,3,0])\n", + "\n", + "# Complete this code\n", + "v1=None #Change this value\n", + "v2=None #Change this value\n", + "v3=None #Change this value\n", + "\n", + "print('v1 = '+str(v1))\n", + "print('v2 = '+str(v2))\n", + "print('v3 = '+str(v3))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 5\n", + "\n", + "Plot the functions\n", + "\\begin{align*}\n", + "f(x)=x^3 , \\quad x \\in [1,10]\n", + "\\end{align*}\n", + "\\begin{align*}\n", + "g(x)=\\exp(4x) , \\quad x \\in [1,10]\n", + "\\end{align*}\n", + "\n", + "in linear scale (i.e. using the function `plt.plot()` and logarithmic scale (i.e. using the function `plt.semilogy()` and `plt.loglog()`. We will use the definition interval to plot these graphs considering 200 equally distributed points.\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Solution \n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Complete this code\n", + "f=None #Change this value to define inline function f\n", + "g=None #Change this value to define inline function g \n", + "\n", + "x=np.linspace(1,10,200)\n", + "\n", + "\n", + "#plot ins plot plot \n", + "plt.title(' Normal scale')\n", + "plt.plot(x,f(x),label=r'$f(x)$')\n", + "# Complete this code\n", + "# add a plot here for g\n", + "plt.legend()\n", + "plt.show()\n", + "\n", + "#plot in semilogy \n", + "\n", + "\n", + "# Complete this code\n", + "\n", + "\n", + "\n", + "\n", + "#plot in log-log\n", + "\n", + "# Complete this code\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 6\n", + "\n", + "1. Given \n", + "\\begin{align*}\n", + "f(x)=\\frac{x^2}{2}\\sin(x) , \\quad x \\in [1,20]\n", + "\\end{align*}\n", + "plot the function $f$ using 10, 20 and 100 equidistant points in the given interval.\n", + "Plot the three graphs on the same figure with three\n", + "different colors. Which one gives the best representation of $f$?\n", + "\n", + "2. Do the same for the functions:\n", + "\\begin{align*}\n", + "g(x) &= \\frac{x^3}{6}\\cos(\\sin(x))\\exp(-x)+\\left(\\frac{1}{1+x}\\right)^2 , \\quad x \\in [1,20] \\\\\n", + "h(x) &= x(1-x)+\\frac{\\sin(x)\\cos(x)}{x^3}, \\quad x \\in [1,20].\n", + "\\end{align*}\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# complete the code here for question 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# complete the code here for question 2\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.7.7" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/1.1 Dichotomie.ipynb b/1.1 Dichotomie.ipynb index bb560f5..bece09a 100644 --- a/1.1 Dichotomie.ipynb +++ b/1.1 Dichotomie.ipynb @@ -1,272 +1,279 @@ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Equations non-linéaires\n", "\n", "**Objectif :** trouver les zéros (ou racines) d'une fonction $f:[a,b] \\rightarrow \\mathbf R$ : \n", "$$\\alpha \\in [a,b] \\,:\\, f(\\alpha) = 0$$" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# importing libraries used in this book\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# defining the fonction\n", "def f(x):\n", " return x*np.sin(x*2.*np.pi) + 0.5*x - 0.25\n", "\n", "[a,b] = [-2,2]\n", "\n", "# points used to plot the graph \n", "z = np.linspace(a, b, 100)\n", "\n", "plt.plot(z, f(z),'-')\n", "\n", "# labels, title, legend\n", "plt.xlabel('x'); plt.ylabel('$f(x)$'); #plt.title('data')\n", "plt.legend(['$f(t)$'])\n", "plt.grid(True)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Méthode de dichotomie ou bissection\n", "\n", "Si $f$ est continue et elle change de signe dans $[a,b]$, alors il existe au moins un $\\alpha$ tel que $f(\\alpha) = 0$.\n", "\n", "On peut alors définir l'algorithme suivant :\n", "\n", "$a^{(0)}=a$, $b^{(0)}=b$. Pour $k=0,1,...$\n", "\n", "1. $x^{(k)}=\\frac{a^{(k)}+b^{(k)}}{2}$\n", "2. si $f(x^{(k)})=0$, alors $x^{(k)}$ est le zéro cherché.\n", "\n", " Autrement:\n", "\n", " 1. soit $f(x^{(k)})f(a^{(k)})<0$, alors le zéro\n", " $\\alpha\\in[a^{(k)},x^{(k)}]$. \n", "\n", " On pose $a^{(k+1)}=a^{(k)}$ et $b^{(k+1)}=x^{(k)}$\n", "\n", " 2. soit $f(x^{(k)}f(b^{(k)})<0$, alors le zéro\n", " $\\alpha\\in[x^{(k)},b^{(k)}]$. \n", "\n", " On pose $a^{(k+1)}=x^{(k)}$ et $b^{(k+1)}=b^{(k)}$\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercice\n", - "Ecrivez une fonction qui effectue l'algorithme de dichotomie ayant la structure suivante:\n", - "```python\n", - "def bisection(a,b,f,tolerance,maxIterations) :\n", - " # [a,b] interval of interest\n", - " # f function\n", - " # tolerance desired accuracy\n", - " # maxIterations : maximum number of iteration\n", - " # returns:\n", - " # zero, residual, number of iterations\n", - "```\n", + "Comprenez et completez la fonction suivante qui effectue l'algorithme de dichotomie \n", "\n", "Ensuite testez-la pour trouver la racine de la fonction $f(x) = x\\sin(2\\pi x) + \\frac12 x - \\frac14$ dans l'intervalle $[-1.5,1]$." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def bisection(a,b,fun,tolerance,maxIterations) :\n", " # [a,b] interval of interest\n", " # fun function\n", " # tolerance desired accuracy\n", " # maxIterations : maximum number of iteration\n", " # returns:\n", " # zero, residual, number of iterations\n", " \n", " if (a >= b) :\n", " print(' b must be greater than a (b > a)')\n", " return 0,0,0\n", " \n", " # what we consider as \"zero\"\n", " eps = 1e-12\n", " \n", " # evaluate f at the endpoints\n", " fa = fun(a)\n", " fb = fun(b)\n", "\n", " if abs(fa) < eps : # a is the solution\n", " zero = a\n", " esterr = fa\n", " k = 0\n", " return zero, esterr, k\n", " \n", " if abs(fb) < eps : # b is the solution\n", " zero = b\n", " esterr = fb\n", " k = 0\n", " return zero, esterr, k\n", "\n", " if fa*fb > 0 :\n", " print(' The sign of FUN at the extrema of the interval must be different')\n", " return 0,0,0\n", "\n", "\n", "\n", " # We want the final error to be smaller than tol, \n", " # i.e. k > log( (b-a)/tol ) / log(2)\n", "\n", " nmax = int(np.ceil(np.log( (b-a)/tol ) / np.log(2)))\n", "\n", " \n", " # but nmax shall be smaller the the nmaximum iterations asked by the user\n", " if ( maxIterations < nmax ) :\n", " nmax = int(round(maxIterations))\n", " print('Warning: nmax is smaller than the minimum number of iterations necessary to reach the tolerance wished');\n", "\n", " # vector of intermadiate approximations etc\n", " x = np.zeros(nmax)\n", "\n", " # initial error is the length of the interval.\n", " esterr = (b - a)\n", "\n", " # do not need to store all the a^k and b^k, so I call them with a new variable name:\n", " ak = a\n", " bk = b\n", " # the values of f at those points are fa and fk\n", "\n", " for k in range(nmax) :\n", "\n", " # approximate solution is midpoint of current interval\n", - " x[k] = (ak + bk) / 2\n", - " fx = fun(x[k]);\n", + " # COMPLETE the code below\n", + " #> x[k] = \n", + " #> fx = \n", + " \n", " # error estimator is the half of the previous error\n", - " esterr = esterr / 2\n", + " #> esterr =\n", + "\n", + " # COMPLETE the code below\n", + "\n", + " # if we found the solution, stop the algorithm\n", + " if np.abs(fx) < eps :\n", + " # error is zero\n", + " #> zero = \n", + " #> esterr = \n", + " #> return \n", "\n", - " # (Complete the code below)\n", + " if fx*fa < 0 : # alpha is in (a,x)\n", + " #> bk = \n", + " elif fx*fb < 0 : # alpha is in (x,b)\n", + " #> ak = \n", + " else :\n", + " error('Algorithm not operating correctly')\n", "\n", "\n", "\n", " zero = x[k];\n", "\n", " if esterr > tol :\n", " print('Warning: bisection stopped without converging to the desired tolerance because the maximum number of iterations was reached');\n", "\n", " return zero, esterr, k, x \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "[a,b] = [-.5,1]\n", "tol = 1e-10\n", "maxIter = 4\n", "zero, esterr, k, x = bisection(a,b,f,tol,maxIter)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def plotBisectionIterations (a,b,f,x,N=200) :\n", " # plot the graphical interpretation of the Bisection method\n", " import matplotlib.pyplot as plt\n", "\n", " def putSign(y,f,text) :\n", " if (f(y) < 0) :\n", " plt.annotate(text, (y, 0.02*deltaAxis) )\n", " else :\n", " plt.annotate(text, (y, -0.05*deltaAxis) )\n", " \n", " \n", " z = np.linspace(a,b,N)\n", " plt.plot(z,f(z), 'b-')\n", " \n", " plt.plot([a,a], [0,f(a)], 'g:')\n", " plt.plot([b,b], [0,f(b)], 'g:')\n", "\n", " # For putting a sign at the initial point\n", " deltaAxis = plt.gca().axes.get_ylim()[1] - plt.gca().axes.get_ylim()[0]\n", "\n", " putSign(a,f,\"a\")\n", " putSign(b,f,\"b\")\n", " \n", " for k in range(x.size) :\n", " plt.plot([x[k],x[k]], [0, f(x[k])], 'g:')\n", " putSign(x[k],f,\"$x_\"+str(k)+\"$\")\n", "\n", " # Plot the x,y-axis \n", " plt.plot([a,b], [0,0], 'k-',linewidth=0.1)\n", " plt.plot([0,0], [np.min(f(z)),np.max(f(z))], 'k-',linewidth=0.1)\n", "\n", " plt.ylabel('$f$'); plt.xlabel('$x$');\n", "\n", " return" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.rcParams.update({'font.size': 16})\n", "plt.figure(figsize=(8, 5))\n", "\n", "plotBisectionIterations(a,b,f,x)\n", "\n", "# plt.savefig('Bisection-iterations.png', dpi=600)\n", "\n", "print(f'The estimated root is {zero:2.12f}, the estimated error {esterr:1.3e} and the residual is {f(zero):1.3e}, after {k} iterations')" ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "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.7.7" } }, "nbformat": 4, "nbformat_minor": 4 } diff --git a/1.2 NetwonRaphson.ipynb b/1.2 NetwonRaphson.ipynb index 38bb0b1..a1db454 100644 --- a/1.2 NetwonRaphson.ipynb +++ b/1.2 NetwonRaphson.ipynb @@ -1,457 +1,247 @@ { "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# importing libraries used in this book\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Méthode de Newton\n", "\n", "Soit $f:\\mathbb R \\rightarrow\\mathbb R$ une fonction différentiable.\n", "\n", "Soit $x^{(0)}$ un point donné. On considère l'équation de la droite $y(x)$ qui\n", "passe par le point $(x^{(k)},f(x^{(k)}))$ et qui a comme pente\n", "$f'(x^{(k)})$,\n", "\\begin{equation*}\n", " y(x)=f'(x^{(k)})(x-x^{(k)})+f(x^{(k)}).\n", "\\end{equation*}\n", "On définit $x^{(k+1)}$ comme étant le point où cette droite\n", "intersecte l'axe $x$, c'est-à-dire $y(x^{(k+1)})=0$. On en\n", "déduit que :\n", "$$ x^{(k+1)}=x^{(k)}-\\frac{f(x^{(k)})}{f'(x^{(k)})},\\,\\,\\,k=0,1,2\\ldots .$$\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "#### Exercice (4, Série 11)\n", + "#### Exercice (5, Série 1)\n", "\n", "On cherche les zéros de la fonction\n", "\n", "$$f(x) = \\dfrac{1}{2} \\sin \\left( \\dfrac{\\pi x}{2} \\right) + 1 - x \\; .$$\n", "\n", "\n", "1. Vérifiez qu'il y a au moins un zéro $\\alpha$ dans l'intervalle $[0,2]$.\n", "\n", "2. Ecrivez la méthode de Newton pour trouver le zéro $\\alpha$ de la fonction $f(x)$ et\n", "calculez la première itération à partir de la valeur initiale $x^{(0)}=1$.\n", "\n", "3. Calculez les zéros $\\alpha$ de la fonction\n", " $f$ avec la méthode de Newton (fonction `newton` que vous devrez écrire)\n", "\n", "```python\n", "def Newton( F, dF, x0, tol, nmax ) :\n", " # NEWTON Find the zeros of a nonlinear equations.\n", " # NEWTON(F,DF,X0,TOL,NMAX) tries to find the zero X of the \n", " # continuous and differentiable function F nearest to X0 using \n", " # the Newton method. DF is a function which take X and return the derivative of F.\n", " # If the search fails an error message is displayed.\n", " # \n", " # returns the value of the\n", " # residual R in X,the number of iterations N required for computing X and\n", " # INC the increments computed by Newton.\n", " \n", " return x, r, n, inc\n", "```\n", "\n", "Choisissez $x^{(0)} = 1$ comme point de départ pour la méthode\n", "et utilisez une tolérance $tol=10^{-4}$ sur la valeur absolue de l'incrément\n", "entre deux itérations\n", "successives $|x^{(k+1)}-x^{(k)}|$. \n", "\n", "*Dans le cas de la méthode de Newton,\n", "l'incrément est une bonne approximation de l'erreur.*\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def Newton( F, dF, x0, tol, nmax ) :\n", " '''\n", " NEWTON Find the zeros of a nonlinear equations.\n", " NEWTON(F,DF,X0,TOL,NMAX) tries to find the zero X of the \n", " continuous and differentiable function F nearest to X0 using \n", " the Newton method. DF is a function which take X and return the derivative of F.\n", " If the search fails an error message is displayed.\n", " \n", " Outputs : [x, r, n, inc, x_sequence]\n", " x : the approximated root of the function\n", " r : the absolute value of the residualin X\n", " n : the number of iterations N required for computing X and\n", " inc : the increments computed by Newton.\n", " x_sequence : the sequence computed by Newton\n", " '''\n", " \n", " # Initial values\n", " n = 0\n", " xk = x0\n", "\n", " # initialisation of loop components\n", " # increments (in abs value) at each iteration\n", " inc = []\n", " # in case we wish to plot the sequence \n", " x = [x0]\n", " \n", " # (Complete the code below)\n", " \n", " # Warning if not converged\n", " if n > nmax :\n", " print('Newton stopped without converging to the desired tolerance ')\n", " print('because the maximum number of iterations was reached')\n", " \n", " # (Complete the code below)\n", " \n", " \n", " return xk1, rk1, n, inc, np.array(x)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f = lambda x : 0.5*np.sin(np.pi*x/2)+1-x\n", "df = lambda x : 0.25*np.pi*np.cos(np.pi*x/2)-1\n", "\n", "x0 = 1\n", "tol = 1e-4\n", "nmax = 10\n", "\n", "zero, residual, niter, inc, x = Newton(f, df, x0, tol, nmax)\n", "\n", "print(f'The zero computed is {zero:1.4f}')\n", "print(f'Newton stoppedconverged in {niter} iterations'); \n", "print(f'with a residual of {residual:1.4e}.\\n');\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from NonLinearEquationsLib import plotNewtonIterations" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "[a,b] = [0,3.5]\n", "x0 = 3\n", "zero, residual, niter, inc, x = Newton(f, df, x0, tol, nmax)\n", "\n", "# Rezise plots, which are usually too small\n", "plt.figure(figsize=(12, 4))\n", "plt.rcParams.update({'font.size': 12})\n", "\n", "# Subplot 1 over 2, 1st one\n", "plt.subplot(121)\n", "\n", "#plt.plot(range(MaxIterations), RelativeError, 'b:.')\n", "plt.plot(range(niter), inc, 'b:.')\n", " \n", "plt.xlabel('n'); plt.ylabel('$\\\\delta x$');\n", "plt.grid(True)\n", "#plt.xscale('log') \n", "plt.yscale('log')\n", "plt.legend(['$|\\\\delta x|$'])\n", "\n", "\n", "# Subplot 1 over 2, 2nd one\n", "plt.subplot(122)\n", "\n", "plotNewtonIterations (a,b,f,x,200)\n", "\n", "plt.show()\n", "\n", "# Rezise plots, which are usually too small\n", "plt.figure(figsize=(8, 4))\n", "plt.rcParams.update({'font.size': 16})\n", "\n", "plotNewtonIterations (a,b,f,x,200)\n", "# plt.savefig('Newton-iterations.png', dpi=600)\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "[a,b] = [-1,3.5]\n", "z = np.linspace(a,b,200)\n", "plt.plot(z,f(z), 'b-', x[6],f(x[6]), 'rx')\n", "plt.ylabel('$f(x)$'); plt.xlabel('$x$');\n", "\n", "# Plot the x,y-axis \n", "plt.plot([a,b], [0,0], 'k-',linewidth=0.1)\n", "plt.plot([0,0], [np.min(f(z)),np.max(f(z))], 'k-',linewidth=0.1)\n", "\n", "plt.legend(['$f$','$\\\\alpha$'])\n", "# plt.savefig('Newton-fx-alpha.png', dpi=600)\n", "\n", "plt.show()\n", "\n" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercice (2, Série 11)\n", - "\n", - "On considère les méthodes de point fixe $x^{(n+1)} = g_i(x^{(n)})\n", - "\\quad (i=1,2,3)$ avec:\n", - "\n", - "$$g_1(x^{(n)}) = \\dfrac{1}{2} e^{x^{(n)}/2} , \\qquad g_2(x^{(n)}) = -\\dfrac{1}{2}\n", - " e^{x^{(n)}/2}, \\qquad g_3(x^{(n)}) = 2 \\ln(2x^{(n)}),$$\n", - "dont les fonctions d'itération $g_i(x)$ sont visualisées sur la figure plus bas\n", - "\n", - "\n", - "1. Pour chaque point fixe $\\bar{x}$ de la fonction d'itération $g_i$ ($i=1,2,3$), on suppose d'avoir choisi une valeur \n", - "initiale $x^{(0)}$ proche de $\\bar{x}$. Etudiez si la méthode converge vers $\\bar{x}$.\n", - "\n", - "2. Pour chaque fonction d'itération $g_i$, déterminez graphiquement \n", - "pour quelles valeurs initiales $x^{(0)}$ la méthode de point fixe correspondante \n", - "converge et vers quel point fixe. \n", - "\n", - "3. Montrez que si $\\bar{x}$ est un point fixe de la fonction $g_i$ \n", - " ($i=1,2,3$), alors il est aussi un zéro de la fonction \n", - " $f(x)= e^x - 4x^2$ (dont le comportement est tracé sur la dernière figure). \n", - "\n", - "4. Comment peut-on calculer les zéros de $f$? \n", - "\n", - "*L'exercice 2 est à faire sur papier, ici une indication par ordinateur*\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from NonLinearEquationsLib import plotPhi, FixedPoint, plotPhiIterations" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "plt.rcParams['figure.figsize'] = [20, 5]\n", - "\n", - "plt.subplot(1,3,1)\n", - "[a,b] = [-2,5]\n", - "phi1 = lambda x : np.exp(x/2)/2\n", - "plotPhi(a,b,phi1,'$g_1$')\n", - "\n", - "plt.subplot(1,3,2)\n", - "[a,b] = [-2,5]\n", - "phi2 = lambda x : - np.exp(x/2)/2\n", - "plotPhi(a,b,phi2,'$g_2$')\n", - "\n", - "plt.subplot(1,3,3)\n", - "[a,b] = [1e-1,5]\n", - "phi3 = lambda x : 2*np.log(2*x)\n", - "plotPhi(a,b,phi3,'$g_3$')\n", - "\n", - "plt.show()\n", - "\n", - "# Graph of the fonction $f(x)=e^x-4x^2$\n", - "N = 100\n", - "z = np.linspace(a,b,N)\n", - "f = lambda x : np.exp(x) - 4*x*x\n", - "\n", - "plt.subplot(1,3,1)\n", - "plt.plot(z,f(z),'k-')\n", - "\n", - "plt.xlabel('x'); plt.ylabel('f(x)');\n", - "# Plot the x,y-axis \n", - "plt.plot([a,b], [0,0], 'k-',linewidth=0.1)\n", - "plt.plot([0,0], [np.min(f(z)),np.max(f(z))], 'k-',linewidth=0.1)\n", - "plt.legend(['f(x)'])\n", - "plt.title('Graph of $f(x)=e^x-4x^2$')\n", - "\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Partie 1**\n", - "*Pour chaque point fixe $\\bar{x}$ de la fonction d'itération $g_i$ ($i=1,2,3$), on suppose choisir une valeur \n", - "initiale $x^{(0)}$ proche de $\\bar{x}$. Etudiez si la méthode converge vers $\\bar{x}$.*\n", - "\n", - "On va utiliser la fonction `FixedPoint` qui se trouve dans `NonLinearEquationsLib.py`\n", - "```python\n", - "def FixedPoint( phi, x0, a, b tol, nmax ) :\n", - " '''\n", - " FixedPoint Find the fixed point of a function by iterative iterations\n", - " FixedPoint( PHI,X0,a,b, TOL,NMAX) tries to find the fixedpoint X of the a\n", - " continuous function PHI nearest to X0 using \n", - " the fixed point iterations method. \n", - " [a,b] : if the iterations exit the interval, the method stops\n", - " If the search fails an error message is displayed.\n", - " \n", - " Outputs : [x, r, n, inc, x_sequence]\n", - " x : the approximated fixed point of the function\n", - " r : the absolute value of the residual in X : |phi(x) - x|\n", - " n : the number of iterations N required for computing X and\n", - " x_sequence : the sequence computed by Newton\n", - " \n", - " ...\n", - " return xk1, rk1, n, np.array(x) \n", - " '''\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "tol = 1e-2\n", - "nmax = 10\n", - "\n", - "# Choose fonction phi\n", - "[a,b] = [-2,5]\n", - "phi = phi1\n", - "label = '$phi_1$'\n", - "\n", - "# Initial Point\n", - "x0 = 3\n", - "zero, residual, niter, x = FixedPoint(phi, x0, a,b, tol, nmax)\n", - "\n", - "plt.subplot(131)\n", - "plotPhi (a,b,phi,label)\n", - "plt.plot(x,phi(x), 'rx')\n", - "\n", - "# plot the graphical interpretation of the Fixed Point method\n", - "plotPhiIterations(x)\n", - "\n", - "plt.show()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "tol = 1e-2\n", - "nmax = 10\n", - "\n", - "# Choose fonction phi\n", - "intervals = [ [-2,5] , [-2,5] , [1e-2,5] ]\n", - "phiFunctions = [phi1, phi2, phi3]\n", - "labels = ['$phi_1$', '$phi_2$', '$phi_3$']\n", - "# Initial Points\n", - "initialPoints = [4.2,2,1]\n", - "\n", - "alpha = np.empty(3)\n", - "\n", - "for k in range(3) :\n", - " phi = phiFunctions[k]; x0 = initialPoints[k]\n", - " a = intervals[k][0]; b = intervals[k][1]\n", - " label = labels[k]\n", - " \n", - " alpha[k], residual, niter, x = FixedPoint(phi, x0, a,b, tol, nmax)\n", - "\n", - " plt.subplot(1,3,k+1)\n", - "\n", - " plotPhi (a,b,phi,label[k])\n", - " plt.plot(x,phi(x), 'rx')\n", - "\n", - " # plot the graphical interpretation of the Fixed Point method\n", - " plotPhiIterations(x)\n", - " \n", - " \n", - "\n", - "plt.show()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Graph of the fonction $f(x)=e^x-4x^2$\n", - "N = 100\n", - "a,b = [-2,5]\n", - "z = np.linspace(a,b,N)\n", - "f = lambda x : np.exp(x) - 4*x*x\n", - "\n", - "plt.subplot(1,3,1)\n", - "plt.plot(z,f(z),'k-')\n", - "\n", - "# Solutions found:\n", - "plt.plot(alpha,f(alpha),'ro')\n", - "plt.annotate(\"$\\\\alpha_1$\", (alpha[0], 2))\n", - "plt.annotate(\"$\\\\alpha_2$\", (alpha[1], 2))\n", - "plt.annotate(\"$\\\\alpha_3$\", (alpha[2]+0.1, -4))\n", - "\n", - "plt.xlabel('x'); plt.ylabel('f(x)');\n", - "# Plot the x,y-axis \n", - "plt.plot([a,b], [0,0], 'k-',linewidth=0.1)\n", - "plt.plot([0,0], [np.min(f(z)),np.max(f(z))], 'k-',linewidth=0.1)\n", - "plt.legend(['f(x)','$\\\\alpha$'])\n", - "plt.title('Graph of $f(x)=e^x-4x^2$')\n", - "\n", - "plt.show()" - ] - }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "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.7.7" } }, "nbformat": 4, "nbformat_minor": 4 } diff --git a/2.1 Interpolation.ipynb b/2.1 Interpolation.ipynb index bc8f1e1..701f05e 100644 --- a/2.1 Interpolation.ipynb +++ b/2.1 Interpolation.ipynb @@ -1,347 +1,347 @@ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 1 Interpolation et approximation de données\n", "\n", "## 1.1 Position du problème" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Interpolation de données\n", "\n", "Soit $n \\geq 0$ un nombre entier. Etant donnés $(n+1)$ noeuds \n", "distincts $x_0$, $x_1$,$\\dots$ $x_n$ et $(n+1)$ valeurs $y_0$,\n", "$y_1$,$\\dots$ $y_n$, on cherche un polynôme $p$\n", " de degré $n$, tel que\n", "\n", "$$p(x_j)=y_j \\qquad \\text{ pour } \\, 0\\leq j\\leq n.$$\n", "\n", "**Exemple** On cherche le polynôme $\\Pi_n$ de degré $n=4$ tel que $\\Pi_n(x_j) = y_j, j =1,...,5$ avec \n", "les données suivantes \n", "\n", "| $x_k$ | $y_k$ |\n", "| --- | --- |\n", "| 1 | 3 |\n", "| 1.5 | 4 |\n", "| 2 | 2 |\n", "| 2.5 | 5 |\n", "| 3 | 1 |\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "# importing libraries used in this book\n", "import numpy as np\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "# Some data given: x=1, 1.5, 2, 2.5, 3 and y = 3,4,2,5,1 \n", "x = np.linspace(1, 3, 5) # equivalent to np.array([ 1, 1.5, 2, 2.5, 3 ])\n", "y = np.array([3, 4, 2, 5, 1])\n", "\n", "# Plot the points using matplotlib\n", "plt.plot(x, y, 'ro')\n", "\n", "plt.xlabel('x'); plt.ylabel('y'); #plt.title('data')\n", "plt.legend(['data'])\n", "plt.show()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Si ce polynôme existe, on le note $p=\\Pi_n$. On appelle $\\Pi_n$ le\n", "polynôme d'interpolation des valeurs $y_j$ aux noeuds $x_j,\\, j=0,\\dots,n$." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Plot the interpolating function\n", "\n", "# Defining the polynomial function \n", "def p(x):\n", " # coefficients of the interpolating polynomial\n", " a = np.array([-140.0, 343.0, -872./3., 104.0, -40./3.])\n", " \n", " # value of the polynomial in all the points t\n", " return a[0] + a[1]*x + a[2]*(x**2) + a[3]*(x**3) + a[4]*(x**4)\n", "\n", "\n", "# points used to plot the graph \n", "z = np.linspace(1, 3, 100)\n", "\n", "plt.plot(x, y, 'ro', z, p(z))\n", "plt.xlabel('x'); plt.ylabel('y'); #plt.title('data')\n", "plt.legend(['data','$\\Pi_2(x)$'])\n", "plt.show()\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Interpolation de fonctions\n", "\n", "\n", "Soit $f\\in C^0(I)$ et $x_0,\\ldots,x_n\\in I$. \n", "Si on prend $$y_j=f(x_j),\\quad 0\\leq j\\leq n,$$ \n", "alors le polynôme d'interpolation\n", "$\\Pi_n(x)$ est noté $\\Pi_n f(x)$ et est appelé l'interpolant de $f$ aux\n", "noeuds $x_0$,$\\dots$ $x_n$.\n", "\n", "**Exemple** Soient $$x_1=1, x_2=1.75, x_3=2.5, x_4=3.25, x_5=4$$ les points d'interpolation et $$f(x) = x \\sin(2\\pi x).$$ On cherche l'interpolant $\\Pi_n f$ de degré $n=4$\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# defining the fonction that we want to interpolate\n", "def f(x):\n", " return x*np.sin(x*2.*np.pi) \n", "\n", "# The interpolation must occour at points x=1, 1.75, 2.5, 3.25, 4\n", "x = np.linspace(1, 4, 5)\n", "\n", "# points used to plot the graph \n", "z = np.linspace(1, 4, 100)\n", "\n", "plt.plot(x, f(x), 'ro', z, f(z),':')\n", "\n", "# labels, title, legend\n", "plt.xlabel('x'); plt.ylabel('$f(x)$'); #plt.title('data')\n", "plt.legend(['$f(x_k)$','$f(x)$'])\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Plot the interpolating function\n", "\n", "# Defining the polynomial function \n", "def p(x):\n", " # coefficients of the interpolating polynomial\n", " a = np.array([0, 7.9012, -13.037, 5.9259, -0.79012])\n", " \n", " # value of the polynomial in all the points x\n", " return a[0] + a[1]*x + a[2]*(x**2) + a[3]*(x**3) + a[4]*(x**4)\n", "\n", "\n", "# points where to evaluate the polynomial\n", "z = np.linspace(1, 4, 100)\n", "\n", "plt.plot(x, f(x), 'ro', z, f(z),':', z, p(z))\n", "plt.xlabel('$x$'); plt.ylabel('$f(x)$'); #plt.title('data')\n", "plt.legend(['$f(x_k)$','$f(x)$','$\\Pi_n(x)$'])\n", "\n", "plt.show()\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Matrice de Vandermonde\n", "\n", "Il est possible d'écrire un système d'équations et de trouver les coefficients de manière directe.\n", "Ce n'est pas toujours la meilleure solution.\n", "\n", "Nous cherchons les coefficients du polynôme $p(x) = a_0 + a_1 x + ... + a_n x^n$ qui satisfont les $(n+1)$ équations $p(x_k) = y_k, k=0,...,n$, c'est-à-dire\n", "\n", "$$a_0 + a_1 x_k + ... + a_n x_k^n = y_k, k=0,...,n$$\n", "\n", "Ce système s'écrit sous forme matricielle\n", "\n", "$$\\begin{pmatrix}\n", "1 & x_0 & x_0^2 & \\cdots & x_0^n \\\\\n", "\\vdots & & & & \\vdots \\\\\n", "1 & x_n & x_n^2 & \\cdots & x_n^n\n", "\\end{pmatrix}\n", "\\begin{pmatrix} a_0 \\\\ \\vdots \\\\ a_n \\end{pmatrix}\n", "=\\begin{pmatrix} y_0 \\\\ \\vdots \\\\ y_n \\end{pmatrix}$$\n", "\n", "Pour construire cette matrice, vous pouvez utiliser la fonction\n", "```python\n", "# Defining the mxn Vandermonde matrix \n", "def VandermondeMatrix(x):\n", " # Input\n", " # x : +1 array with interpolation nodes\n", " # Output\n", " # Matrix of Vandermonde of size n x n\n", "```\n", "que vous pouvez importer avec la commande\n", "```python\n", "from InterpolationLib import VandermondeMatrix \n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Exemple** On cherche les coefficients du polynôme d'interpolation de degré $n=4$ \n", "des valeurs suivantes \n", "\n", "| $x_k$ | $y_k$ |\n", "| --- | --- |\n", "| 1 | 3 |\n", "| 1.5 | 4 |\n", "| 2 | 2 |\n", "| 2.5 | 5 |\n", "| 3 | 1 |\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from InterpolationLib import VandermondeMatrix \n", "\n", "# Some data given: x=1, 1.5, 2, 2.5, 3 and y = 3,4,2,5,1 \n", "x = np.linspace(1, 3, 5)\n", "y = np.array([3, 4, 2, 5, 1])\n", "n = x.size - 1\n", "\n", "A = VandermondeMatrix(x)\n", "# print(A)\n", "\n", "# compute coefficients\n", "# Resouds Ax = b avec b=y et rends x\n", "# >>> COMPLETE HERE <<<\n", "\n", "# print the coefficients on screen\n", "print('The coefficients a_0, ..., a_n are')\n", "print(a)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Now we can define the polynomial\n", "p = lambda x : a[0] + a[1]*x + a[2]*(x**2) + a[3]*(x**3) + a[4]*(x**4)\n", "\n", "# points used to plot the graph \n", "z = np.linspace(1, 3, 100)\n", "\n", "# Plot points and function\n", "# >>> COMPLETE HERE <<<\n", "plt.xlabel('x'); plt.ylabel('y'); #plt.title('data')\n", "plt.legend(['data','p(x)'])\n", "plt.show()\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Alternatives : polyfit et polyval\n", "\n", "Les fonctions `polyfit` et `polyval` de `numpy` font essentiellement la même chose que les paragraphes ci-dessous. Plus tard nous verrons des méthodes plus performantes.\n", "\n", "`a = numpy.polyfit(x, y, n, ... )` :\n", "\n", " * input : $x,y$ les données à interpoler, $n$ le degré du polynôme recherché\n", " * output : les coefficients du polynôme, _dans l'ordre inverse_ de ce que nous avons vu !\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Some data given: x=1, 1.5, 2, 2.5, 3 and y = 3,4,2,5,1 \n", "x = np.linspace(1, 3, 5)\n", "y = np.array([3, 4, 2, 5, 1])\n", "n = x.size - 1\n", "\n", "a = np.polyfit(x,y,n)\n", "\n", "# Now we can define the polynomial, with coeffs in the reverse order !\n", "p = lambda x : a[4] + a[3]*x + a[2]*(x**2) + a[1]*(x**3) + a[0]*(x**4)\n", "\n", "# We can also use polyval instead !\n", "# np.polyval(a,x)\n", "\n", "# points used to plot the graph \n", "z = np.linspace(1, 3, 100)\n", "\n", "plt.plot(x, y, 'ro', z, p(z), '.', z, np.polyval(a,z))\n", "plt.xlabel('x'); plt.ylabel('y'); #plt.title('data')\n", "plt.legend(['data','p(x)','polyval'])\n", "plt.show()\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "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.7.7" } }, "nbformat": 4, "nbformat_minor": 4 } diff --git a/2.2 Interpolation de Lagrange.ipynb b/2.2 Interpolation de Lagrange.ipynb index 9559b95..e8a3190 100644 --- a/2.2 Interpolation de Lagrange.ipynb +++ b/2.2 Interpolation de Lagrange.ipynb @@ -1,191 +1,191 @@ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.2 Interpolation de Lagrange\n", "\n", "### Base de Lagrange\n", "\n", "On considère les polynômes $\\varphi_k$, $k=0,\\dots, n$ de\n", "degré $n$ tels que\n", "\n", "$$\\varphi_k(x_j)=\\delta_{jk}, \\qquad k,j=0,\\dots, n,$$\n", "\n", "où $\\delta_{jk}=1$ si $j=k$ et $\\delta_{jk}=0$ si $j\\neq k$.\n", "Explicitement, on a\n", "\n", "$$\\varphi_k(x)=\\prod_{j=0,j\\ne k}^n\\dfrac{(x-x_j)}{(x_k-x_j)}.$$" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# importing libraries used in this book\n", "import numpy as np\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Exercice (théorique)** Vérifiez que\n", "\n", "1. $B = \\{\\varphi_k, k=0,\\dots, n\\}$ est une base de $P_n(\\mathbb R)$\n", "2. Chaque polynôme $\\varphi_k$ est de degré $n$\n", "3. $\\varphi_k(x_j)=\\delta_{jk}, \\qquad k,j=0,\\dots, n$\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Defining the Lagrange basis functions\n", "def phi(x,k,z):\n", " # the input variables are:\n", " # x : the interpolatory points\n", " # k : which basis function\n", " # z : where to evaluate the function\n", " \n", "\n", " # careful, there are n+1 interpolation points!\n", " n = x.size - 1 \n", "\n", " # init result to one, of same type and size as z\n", " result = np.zeros_like(z) + 1\n", "\n", " # first few checks on k:\n", " if (type(k) != int) or (x.size < 1) or (k > n) or (k < 0):\n", " raise ValueError('Lagrange basis needs a positive integer k, smaller than the size of x')\n", " \n", " # loop on n to compute the product\n", " for j in range(0,n+1) :\n", " if (j == k) :\n", " continue\n", " if (x[k] == x[j]) :\n", " raise ValueError('Lagrange basis: all the interpolation points need to be distinct')\n", "\n", " # >>> COMPLETE HERE <<<\n", " result = \n", "\n", " return result\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Exemple\n", "\n", "Pour $n=2$, $x_0=-1$, $x_1=0$, $x_2=1$, les polynômes de la base de Lagrange\n", "sont\n", "\n", "\\begin{equation*}\n", "\\begin{array}{lcl}\n", "\\varphi_0(x)&=&\\displaystyle\\dfrac{(x-x_1)(x-x_2)}{(x_0-x_1)(x_0-x_2)}=\n", "\\dfrac{1}{2}x(x-1),\\\\[2mm]\n", "\\varphi_1(x)&=&\\displaystyle\\dfrac{(x-x_0)(x-x_2)}{(x_1-x_0)(x_1-x_2)}=\n", "-(x+1)(x-1),\\\\[2mm]\n", "\\varphi_2(x)&=&\\displaystyle\\dfrac{(x-x_0)(x-x_1)}{(x_2-x_0)(x_2-x_1)}=\n", "\\dfrac{1}{2}x(x+1).\n", "\\end{array}\n", "\\end{equation*}\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# plot the Lagrange Basis functions \n", "x = np.linspace(-1., 1, 3)\n", "z = np.linspace(-1.1, 1.1, 100)\n", "\n", "plt.plot(z, phi(x,0,z), 'g', z, phi(x,1,z), 'r', z, phi(x,2,z),':')\n", "\n", "plt.xlabel('x'); plt.ylabel('$\\\\varphi_{k}(x)$'); plt.title('Lagrange basis functions')\n", "plt.legend(['$\\\\varphi_{0}$','$\\\\varphi_{1}$','$\\\\varphi_{2}$'])\n", "plt.grid(True)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Exercice\n", "\n", "Visualisez la base de Lagrange associée aux points $x_k = 1, 1.5, 2, 2.5, 3$.\n", "Evaluez sur le graphique les valeurs de $\\varphi_k(x_j)$\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# plot the Lagrange Basis functions \n", "x = np.linspace(1., 3, 5)\n", "z = np.linspace(0.9, 3.1, 100)\n", "\n", "plt.plot(z, phi(x,0,z), 'g', z, phi(x,1,z), 'r', z, phi(x,2,z),':', z, phi(x,3,z),':', z, phi(x,4,z),':')\n", "\n", "plt.xlabel('x'); plt.ylabel('phi(x)'); plt.title('Lagrange Basis functions')\n", "plt.legend(['$\\\\varphi_0$','$\\\\varphi_1$','$\\\\varphi_2$',\n", " '$\\\\varphi_3$','$\\\\varphi_4$'])\n", "plt.grid(True)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Polynôme d'interpolation\n", "\n", "Le polynôme d'interpolation $\\Pi_n$ des\n", "valeurs $y_j$ aux noeuds $x_j$, $j=0,\\dots,n$, s'écrit\n", "\\begin{equation}\\label{e:int_lagr}\n", " \\Pi_n(x)=\\sum_{k=0}^n y_k \\varphi_k(x),\n", "\\end{equation}\n", "car il vérifie $\\Pi_n(x_j)=\\sum_{k=0}^n y_k \\varphi_k(x_j)=y_j$.\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "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.7.7" } }, "nbformat": 4, "nbformat_minor": 4 } diff --git a/2.3 Interpolation de fonction.ipynb b/2.3 Interpolation de fonction.ipynb index b2ce518..01a6abb 100644 --- a/2.3 Interpolation de fonction.ipynb +++ b/2.3 Interpolation de fonction.ipynb @@ -1,401 +1,401 @@ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.3 Interpolation d'une fonction continue\n", "\n", "Soit $f: \\mathbf [a,b] \\rightarrow R$ continue et $x_0,\\ldots,x_n\\in [a,b]$ des noeuds distincts. Le polynôme d'interpolation\n", "$\\Pi_n(x)$ est noté $\\Pi_n f(x)$ et est appelé l'interpolant de $f$ aux\n", "noeuds $x_0,\\dots,x_n$.\n", "\n", "\n", "Si on prend $$y_k=f(x_k), k= 0,..., n,$$ \n", "alors on aura\n", "\\begin{equation*}\n", "\\Pi_nf(x)=\\sum_{k=0}^n\n", "f(x_k)\\varphi_k(x).\n", "\\end{equation*}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Exercice\n", "\n", "Ecrivez une fonction Python qui a la définition suivante, en utilisant la fonction `phi` définie plus haut.\n", "Ecrivez aussi un petit test sur la base de l'exercice précédent.\n", "\n", "```python\n", "# Lagrange Interpolation of data (x,y), evaluated at ordinate(s) z\n", "def LagrangePi(x,y,z):\n", " # the input variables are:\n", " # x : the interpolatory points\n", " # y : the corresponding data at the points x\n", " # z : where to evaluate the function\n", " \n", "```\n", "\n", "Utilisez le fait que $\\{\\varphi_k, k = 0,...,n\\}$ est une base des polynômes de degré $\\leq n$\n", "et que le vecteur $y$ représente les coordonnées du polynôme d'interpolation recherché par rapport à cette base,\n", "c'est-à-dire\n", "$$\\Pi_n (z) = y_0 \\varphi_0 + ... + y_n \\varphi_n$$\n", "\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# importing libraries used in this book\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "from InterpolationLib import LagrangeBasis as phi" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Lagrange Interpolation of data (x,y), evaluated at ordinate(s) z\n", "def LagrangePi(x,y,z):\n", " # the input variables are:\n", " # x : the interpolatory points\n", " # y : the corresponding data at the points x\n", " # z : where to evaluate the function\n", " \n", " # {phi(x,k,.), k=0,...,n} is a basis of the polynomials of degree n\n", " # y represents the coordinates of the interpolating polynomial with respect to this basis.\n", " # Therefore LagrangePi(x,y,.) = y[0] phi(x,0,.) + ... + y[n] phi(x,n,.)\n", "\n", " # >>> COMPLETE HERE <<<\n", "\n", " return result" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# vecteur des points d'interpolation\n", "x = np.linspace(0, 1, 5)\n", "\n", "# vecteur des valeurs\n", "y = np.array([3.38, 3.86, 3.85, 3.59, 3.49])\n", "\n", "z = np.linspace(-0.1, 1.1, 100)\n", "plt.plot(x, y, 'ro', z, LagrangePi(x,y,z))\n", "\n", "plt.xlabel('x'); plt.ylabel('y');\n", "plt.legend(['data','p(x)'])\n", "plt.show()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Erreur d'interpolation\n", "\n", "Soient $x_0$, $x_1$, $\\ldots$, $x_n$,\n", "$(n+1)$ nœuds *équirépartis* dans $I=[a,b]$ et soit $f\\in C^{n+1}(I)$.\n", "Alors\n", "\\begin{equation}\n", " \\max_{x\\in I} |f(x) - \\Pi_n f(x)| \\leq \\dfrac{1}{4(n+1)}\n", "\\left(\\frac{b-a}{n}\\right)^{n+1}\\max_{x\\in I}|f^{(n+1)}(x)|.\n", "\\end{equation}\n", "\n", "On remarque que l'erreur d'interpolation dépend de la dérivée\n", "$(n+1)$-ième de $f$." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Exercice\n", "\n", "On considère les points d'interpolation $$x_0=1, x_1=1.75, x_2=2.5, x_3=3.25, x_4=4$$ \n", "et la fonction $$f(x) = x \\sin(2\\pi x)$$.\n", "\n", "1. Calculez la base de Lagrange associée à ces points. D'abord sur papier, ensuite utilisez Python pour en dessiner le graphique.\n", "\n", "2. Calculez le polynôme d'interpolation $\\Pi_n$ à l'aide de la base de Lagrange. D'abord sur papier, ensuite avec Python.\n", "\n", "4. Quelle est l'erreur théorique d'interpolation ? \n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Comportement pour $n$ grand: eg, la fonction de Runge.\n", "\n", "Le fait que\n", "$$\\lim_{n\\rightarrow\\infty} \\dfrac{1}{4(n+1)}\\left(\\dfrac{b-a}{n}\\right)^{n+1}=0$$\n", "n'implique pas forcément que $\\max_{x \\in I} |E_nf(x)|$ tende vers zéro quand $n\\rightarrow\\infty$.\n", "\n", "Soit $f(x)=\\dfrac{1}{1+x^2}$, $x\\in [-5,5]$. Si on l'interpole dans des\n", "noeuds équirépartis, l'interpolant présente des oscillations au voisinage des extrémités de l'intervalle.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Runge fonction\n", "f = lambda x : 1./(1+x**2)\n", "\n", "# Values of N to use\n", "Nrange = [3,5,10]\n", "# plotting points\n", "z = np.linspace(-5, 5, 100)\n", "\n", "for n in Nrange :\n", "\n", " # define x and y=f(x)\n", " # compute the Lagrange interpolant\n", " # plot it\n", "\n", " # >>> COMPLETE HERE <<<\n", "\n", "\n", "plt.plot(z,f(z), 'b')\n", "plt.xlabel('x'); plt.ylabel('y'); plt.title('Runge function')\n", "plt.legend(Nrange)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`sympy` est une librairie pour le calcul symbolique en Python. Nous allons l'utiliser pour étudier le comportement de l'erreur d'interpolation de la fonction de Runge." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Using symbolic python to compute derivatives\n", "import sympy as sp\n", "\n", "# define x as symbol\n", "x = sp.symbols('x')\n", "\n", "# define Runge function\n", "f = 1/(1+x**2)\n", "\n", "# pretty print the 5th derivative of f\n", "f5 = sp.diff(f, x,5)\n", "# display f5\n", "sp.init_printing(use_unicode=True)\n", "display(f5)\n", "\n", "\n", "# evalf can be used to compute the value of a function at a given point\n", "print('5th derivative evaluated at 3 :')\n", "print( f5.evalf(subs={x: 3}) )\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pour définir une fonction qui accepte un array de valeur, il faut utiliser les lignes suivantes.\n", "\n", "Ensuite on peut aussi dessiner le graphe ..." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "# to evaluate a function at many given points, we need the following trick\n", "diff_f_func = lambda t: float(sp.diff(f,x,k).evalf(subs={x: t}))\n", "diff_f = np.vectorize(diff_f_func)\n", "\n", "# the derivative can be set with k (not very elegant...)\n", "k = 4\n", "print(diff_f(4.5))\n", "\n", "# plotting points\n", "z = np.linspace(-5, 5, 100)\n", "# plot the derivative between -5 and 5\n", "\n", "plt.plot(z,diff_f(z), 'b')\n", "plt.xlabel('t'); plt.ylabel('y'); plt.title('Derivatives of Runge function')\n", "plt.legend(Nrange)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... ou évaluer le maximum pour plusieurs $n$ et voir le comportement de $\\max |f^{(n)}|$ en fonction de $n$." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Plot max(abs(fn)) in the range -5,5\n", "z = np.linspace(-5, 5, 100)\n", "\n", "Nmax = 10\n", "maxValFn = np.zeros(Nmax)\n", "for k in range(Nmax):\n", " maxValFn[k] = np.max(np.abs(diff_f(z)))\n", " \n", "plt.plot(range(10), maxValFn)\n", "\n", "plt.yscale('log')\n", "plt.xlabel('n'); plt.ylabel('$\\max|\\partial f|$');\n", "plt.title('Max of $|\\partial^n f|$');\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Interpolation de Chebyshev\n", "\n", "\n", "Pour chaque entier positif $n\\geq 1$, pour $i=0,\\dots n$, on note\n", "$$\\hat{x}_i=-\\cos(\\pi i/n)\\in[-1,1]$$\n", "**les points de Chebyshev** et on définit\n", "\n", "$$x_i=\\dfrac{a+b}{2}+\\dfrac{b-a}{2}\\hat{x}_i\\in[a,b],$$\n", "\n", "pour un intervalle arbitraire $[a,b]$. Pour une fonction continue $f\\in\n", "C^1([a,b])$, le polynôme d'interpolation $\\Pi_n f$ de degré $n$ aux noeuds\n", "$\\{x_i,i=0,\\ldots,n\\}$ converge uniformément vers $f$ quand\n", "$n\\rightarrow \\infty$.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Chebichev points on the interval [-1,1]\n", "\n", "z = np.linspace(0,1, 100)\n", "plt.plot(np.cos(np.pi*z), np.sin(np.pi*z))\n", "\n", "n =5\n", "z = np.linspace(0,1, n+1)\n", "plt.plot(np.cos(np.pi*z), np.sin(np.pi*z), 'o')\n", "plt.plot(np.cos(np.pi*z), 0*z, 'x')\n", "\n", "for k in range(0,n+1) :\n", " plt.plot([np.cos(np.pi*z[k]),np.cos(np.pi*z[k])],[0,np.sin(np.pi*z[k])],':')\n", "\n", "plt.axis('equal')\n", "\n", "plt.xlabel('t'); \n", "plt.title('Chebyshev points')\n", "plt.show()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Exemple\n", "\n", "On reprend le\n", " même exemple mais on interpole la fonction de Runge dans les points de\n", "Chebyshev. La figure montre les polynômes de\n", "Chebyshev de degrés $n=5$ et $n=10$. On remarque que les oscillations\n", "diminuent lorsqu'on augmente le degré du polynôme.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Runge fonction\n", "f = lambda x : 1./(1+x**2)\n", "\n", "# Values of N to use\n", "Nrange = [3,5,10]\n", "# plotting points\n", "[a,b] = [-5,5]\n", "z = np.linspace(a,b, 100)\n", "\n", "for n in Nrange :\n", "\n", " # Chebyshev points on [-1,1]\n", " hx = -np.cos(np.pi*np.linspace(0,n,n+1)/n)\n", " # mapped to [a,b]\n", " x =(a+b)/2 + (b-a)/2*hx\n", "\n", " y = f(x);\n", "\n", " plt.plot(z, LagrangePi(x,y,z), ':')\n", "\n", "plt.plot(z,f(z), 'b')\n", "plt.xlabel('x'); plt.ylabel('y'); plt.title('Chebyshev interpolation')\n", "plt.legend(Nrange)\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "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.7.7" } }, "nbformat": 4, "nbformat_minor": 4 } diff --git a/2.4 Interpolation par intervalles.ipynb b/2.4 Interpolation par intervalles.ipynb index 831760f..8ba8535 100644 --- a/2.4 Interpolation par intervalles.ipynb +++ b/2.4 Interpolation par intervalles.ipynb @@ -1,287 +1,287 @@ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.4 Interpolation par intervalles\n", "\n", "### Interpolation linéaire par morceaux\n", "\n", "Soit $f: \\mathbf [a,b] \\rightarrow R$ continue et $a=x_0<\\ldots>> COMPLETE HERE <<<\n", "\n", "\n", "\n", "plt.xlabel('x'); plt.ylabel('y');\n", "plt.legend(['data','p(x)'])\n", "plt.show()\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercice\n", "\n", "Dessinez le graphe de la fonction de Runge et l'interpolateur linéaire par morceaux \n", "sur l'intervalle $[-5,5]$ pour $N=3,5,10$\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# interval and function\n", "a = -5; b = 5\n", "f = lambda x : 1/(1+x**2)\n", "\n", "# >>> COMPLETE HERE <<<\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Erreur d'interpolation linéaire par morceaux \n", "\n", "#### Théorème \n", "\n", "Soient $f\\in C^{2}([a,b])$, $H = \\frac{b-a}{N}$, $x_i = a + iH$ pour $i=0,...,N$.\n", " \n", "Soit $E^H_1f(x) = f(x) - \\Pi_1^{H} f(x)$, alors\n", "$$\\max_{x\\in I}\\mid E^H_1f(x) \\mid\\leq \\dfrac{H^2}{8}\\max_{x \\in I} | f''(x)|.$$\n", "\n", "**Preuve**\n", "D'après la formule, sur chaque intervalle $I_i=[x_i,x_{i+1}]$, on a\n", " \n", "$$\\max_{x\\in[x_i,x_{i+1}]}\\mid E^H_1f(x)\\mid \\leq\n", " \\dfrac{H^2}{4(1+1)}\\max_{x\\in I_i}\\mid f''(x)\\mid.$$\n", "\n", "**Remarque**\n", "On peut aussi montrer que, si l'on utilise un polynôme\n", "de degré $n$ ($\\geq 1$) et si l'on dénote $E^H_nf(x) = f(x) - \\Pi_n^{H} f(x)$,\n", " dans chaque sous-intervalle $I_i$, on\n", "trouve\n", "\n", "$$\\max_{x\\in I}\\mid E^H_nf(x) \\mid \\leq \\dfrac{H^{n+1}}{4(n+1)} \\max_{x \\in I} |f^{(n+1)} (x)| \\, .$$\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Interpolation quadratique par morceaux\n", "\n", "Soit $f: \\mathbf [a,b] \\rightarrow R$ continue et $a=x_0<\\ldots$(n+1)$ points \n", "~~distincts~~ $x_0$, $x_1$,$\\dots$ $x_n$ et $(n+1)$ valeurs $y_0$,\n", "$y_1$,$\\dots$ $y_n$, on cherche un polynôme $p$\n", " de degré $m , tel que\n", "\n", "$$\\sum_{j=0}^n |y_j - p(x_j)|^2 \\qquad \\text{ soit le plus petit possible}.$$\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On appelle **polynôme aux moindres carrés de degré $m$**\n", "le polynôme $\\hat{p}_n(x)$ de degré $m$ tel que\n", "\\begin{equation}\n", " \\sum_{j=0}^n |y_j - \\hat{p}_n(x_j)|^2 \\leq \\sum_{j=0}^n |y_j - p_n(x_j)|^2\n", " \\qquad \\forall p_m(x) \\in \\mathbb{P}_m\n", "\\end{equation}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nous cherchons les coefficients du polynôme $p(x) = a_0 + a_1 x + ... + a_m x^m$ qui satisfait *au mieux* les $(n+1)$ équations $p(x_k) = y_k, k=0,...,n$, c'est-à-dire\n", "\n", "$$a_0 + a_1 x_k + ... + a_m x_k^m = y_k, k=0,...,n$$\n", "\n", "Ce système s'écrit sous forme matricielle \n", "\n", "$$\\begin{pmatrix}\n", "1 & x_0 & \\cdots & x_0^m \\\\\n", "\\vdots & & & \\vdots \\\\\n", "1 & x_n & \\cdots & x_n^m\n", "\\end{pmatrix}\n", "\\begin{pmatrix} a_0 \\\\ \\vdots \\\\ a_m \\end{pmatrix}\n", "=\\begin{pmatrix} y_0 \\\\ \\vdots \\\\ y_n \\end{pmatrix}$$\n", "\n", "Puisque $m>> COMPLETE HERE <<<\n", "a = \n", "\n", "# print the coefficients on screen\n", "print('The coefficients a_0, ..., a_m are')\n", "print(a)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def polynomial(a,x):\n", " m = a.size-1\n", " # \\hat p = a_0 + a_1 x + ... + a_n x^m\n", " # is equal to the scalar product between the vectors a and (1, x, ..., x^m) :\n", " return np.power( np.tile(x, (m+1, 1)).T , np.linspace(0,m,m+1)).dot(a)\n", "\n", "\n", "# points used to plot the graph, slightly larger than data\n", "# >>> COMPLETE HERE <<<\n", "z = \n", "\n", "plt.plot(sigma, epsilon, 'ro', z, polynomial(a,z),'b')\n", "plt.xlabel('$\\sigma$'); plt.ylabel('$\\epsilon$');\n", "plt.legend(['data','$\\hat p_n$'])\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Exercice\n", "\n", "Depuis https://hsso.ch/fr/2012/b/14 on a téléchargé les données de la population suisse dans\n", "le fichier `Data/PopulationSuisse.csv`.\n", "\n", "Approximez l'évolution de la population avec un polynôme de degré $n=1,2,3,7$. \n", "\n", "Ensuite faites l'hypothèse de croissance exponentielle de la population, c'est-à-dire $p(x) = e^{a_1 x+a_0}$ où $a_0$ et $a_1$ sont des paramètres. Comment utiliser l'approximation polynômiale dans ce contexte ? " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Data of the population has been dowloaded from https://hsso.ch/fr/2012/b/14\n", "# into the file Data/PopulationSuisse.csv\n", "import pandas as pd \n", "\n", "# Read data from file 'PopulationSuisse.csv' \n", "data = pd.read_csv(\"Data/PopulationSuisse.csv\") \n", "# Preview the first 5 lines of the loaded data \n", "data.head()\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = data['Année'].to_numpy()\n", "y = data['Population'].to_numpy()\n", "\n", "m = 2\n", "B = VandermondeMatrix(x,m)\n", "\n", "# >>> COMPLETE HERE <<<\n", "# ... and solve the exercise\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def polynomial(a,x):\n", " m = a.size-1\n", " # \\hat p = a_0 + a_1 x + ... + a_n x^m\n", " # is equal to the scalar product between the vectors a and (1, x, ..., x^m) :\n", " return np.power( np.tile(x, (m+1, 1)).T , np.linspace(0,m,m+1)).dot(a)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On assume une croissance exponentielle : $population (x) = C * e^{a_1x} = e^{a_o + a_1 x}$\n", "\n", "En d'autres termes: $\\log (population) (x) = a_o + a_1 x$\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "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.7.7" } }, "nbformat": 4, "nbformat_minor": 4 } diff --git a/4.2 Methodes iteratives.ipynb b/4.2 Methodes iteratives.ipynb index 364530c..371c7cf 100644 --- a/4.2 Methodes iteratives.ipynb +++ b/4.2 Methodes iteratives.ipynb @@ -1,686 +1,701 @@ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Méthodes itératives" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# importing libraries used in this notebook\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "\n", "# scipy.linalg.eig : eigenvalues of a matrix\n", "from scipy.linalg import eig\n", "# scipy.linalg.lu : LU decomposition\n", "from scipy.linalg import lu\n", "# scipy.linalg.cholesky : Cholesky decomposition\n", "from scipy.linalg import cholesky\n", "# scipy.linalg.hilbert : Hilbert matrix\n", "from scipy.linalg import hilbert\n", "\n", "np.set_printoptions(precision=4, suppress=True, linewidth=120)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Example 1\n", "On considère la matrice $A$ suivante\n", "\n", "$$A=\\begin{pmatrix}\n", "1 & 2 & 3 & 4 \\\\\n", "5 & 6 & 7 & 8\\\\\n", "9 & 10 & 11 & 12\\\\\n", "13 & 14 & 15 & 16\n", "\\end{pmatrix}.$$\n", "\n", "On a alors que\n", "$$D=\\begin{pmatrix}\n", "1 & 0 & 0 & 0 \\\\\n", "0 & 6 & 0 & 0\\\\\n", "0 & 0 & 11 & 0\\\\\n", "0 & 0 & 0 & 16\n", "\\end{pmatrix};$$\n", "La matrice d'itération de la méthode de Jacobi est donc égale à\n", "$$B_J = D ^{-1}(D - A) = I - D^{-1}A =\n", "\\begin{pmatrix}\n", "0 & -2 & -3 & -4 \\\\\n", "-5/6 & 0 & -7/6 & -4/3\\\\\n", "-9/11 & -10/11 & 0 & -12/11\\\\\n", "-13/16 & -14/16 & -15/16 & 0\n", "\\end{pmatrix}.$$" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A = np.array([[1,2,3,4],\n", " [5,6,7,8],\n", " [9,10,11,12],\n", " [13,14,15,16]])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Méthode de Jacobi" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Jacobi\n", "# the first diag extracts the diagonal of A, the second one builds a diagonal matrix starting from a vector\n", "D = np.diag(np.diag(A)) \n", "\n", "# efficiently computing the Jacobi iteration matrix without explicitely computing the inverse of D\n", "Bj = np.linalg.solve(D,(D-A))\n", "\n", "# What are the eigenvlues of Bj ? \n", "lk, v = eig(Bj)\n", "print(f'The eigenvalues of Bj are {lk}\\n')\n", "print(f'The spectral radius of Bj is {np.max(np.abs(lk)):.4f} > 1, therefore the Jacobi method does not converge')\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Méthode de Gauss-Siedel" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Gauss-Seidel\n", "# Return a copy of an array with elements above the k-th diagonal set to zero. \n", "Pgs = np.tril(A, k=0)\n", "\n", "# efficiently computing the Gauss-Siedel iteration matrix without explicitely computing the inverse of D\n", "Bgs = np.linalg.solve(Pgs,(Pgs-A))\n", "\n", "# What are the eigenvlues of Bgs ? \n", "lk, v = eig(Bgs)\n", "print(f'The eigenvalues of Bgs are {lk}\\n')\n", "print(f'The spectral radius of Bgs is {np.max(np.abs(lk)):.4f} > 1, therefore the Gauss-Seidel method does not converge')\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Exercice \n", "Réprenez cet exemple avec la matrice \n", "\n", "$$A=\\begin{pmatrix}\n", "3 & 2 & 1 & 0 \\\\\n", "3 & 4 & 3 & 2\\\\\n", "3 & 2 & 5 & 2\\\\\n", "1 & 2 & 3 & 4\n", "\\end{pmatrix}.$$\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exemple 2\n", "\n", "Considerez la matrice $A$ et le vecteur $b$ suivants\n", "\n", "$$A = \\left(\n", " \\begin{array}{ccc}\n", " 3 & 2 & 1 \\\\[0.5em]\n", " 1 & 4 & 1 \\\\[0.5em]\n", " 2 & 4 & 8\n", " \\end{array} \\right), \\quad\n", " \\mathbf{b} = \\left( \\begin{array}{c} 4 \\\\ 5 \\\\ 6 \\end{array} \n", "\\right) \\, .$$\n", "\n", - "Exprimez (sans calculer) $P$, $B$, et $\\rho(B)$ dans les cas de Jacobi et Gauss-Seidel.\n" + "Exprimez (sans calculer) $P$, $B$, et $\\rho(B)$ dans le cas de Jacobi et Gauss-Seidel.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A = np.array([[3, 2, 1],\n", " [1, 4, 1],\n", " [2, 4, 8] ])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Jacobi\n", "\n", "# To complete\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Gauss-Seidel\n", "\n", "# To complete\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Méthode de Richardson\n", "\n", "$A$ et $\\mathbf b$ donnés; on cherche à approximer la solution $\\mathbf x$ de $A\\mathbf x = \\mathbf b$.\n", "\n", "Soit $\\mathbf x^{(0)}$ donné, $\\mathbf r^{(0)}= \\mathbf b - A\\mathbf x^{(0)}$ pour $k=0,1,2,...$ :\n", "\n", "\\begin{eqnarray*}\n", - "\\text{trouver }\\mathbf{z}^{(k)} \\text{ tel que } && P \\mathbf{z}^{(k)} = \\mathbf{r}^{(k)}\\\\\n", - "\\text{choisir }\\alpha_k && \\\\\n", + "\\text{trouvez }\\mathbf{z}^{(k)} \\text{ tel que } && P \\mathbf{z}^{(k)} = \\mathbf{r}^{(k)}\\\\\n", + "\\text{choisissez }\\alpha_k && \\\\\n", "&& \\mathbf{x}^{(k+1)} = \\mathbf{x}^{(k)} + \\alpha_k \\mathbf{z}^{(k)} \\\\\n", "&& \\mathbf{r}^{(k+1)} = \\mathbf{r}^{(k)} - \\alpha_k A \\mathbf{z}^{(k)}.\n", "\\end{eqnarray*}\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exemple 3 - Jacobi et Gauss-Seidel avec relaxation\n", "\n", - "On a vu que la méthode de Jacobi appliquée à la matrice\n", + "Nous avons vu que la méthode de Jacobi appliquée à la matrice\n", "$$A=\\begin{pmatrix}\n", "3 &2&1&0\\\\3&4&3&2\\\\3&2&5&2\\\\1&2&3&4\n", "\\end{pmatrix}$$\n", - "ne converge pas, alors que la méthode de Gauss-Seidel converge.\n", + "ne converge pas, alors que celle de Gauss-Seidel converge.\n", + "\n", + "Nous allons utiliser la méthode de Richardson stationnaire avec un paramètre de relaxation $\\alpha$ constant pour voir si on peut améliorer la convergence.\n", "\n", "On va utiliser la méthode de Richardson stationnaire avec un paramètre de relaxation $\\alpha$ constant pour voir si on peut améliorer la convergence." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Partie 1 - Matrices d'itérations\n", "\n", - "La matrice d'itérations pour la méthode de Richardson est $B(\\alpha_k) = I - \\alpha_k P^{-1}A$. En particulier, pour $\\alpha$ constant, on peut faire un graphique du rayon spectral $\\rho(B(\\alpha))$ dans les cas de Jacobi et Gauss-Seidel.\n" + "La matrice d'itérations pour la méthode de Richardson est $B(\\alpha_k) = I - \\alpha_kP^{-1}A$. En particulier, pour $\\alpha$ constant, nous pouvons faire un graphique du rayon spectral $\\rho(B(\\alpha))$ dans les cas d'un préconditionneur égale à la diagonale de $A$ (similaire à Jacobi) ou au triangle inférieur de $A$ (similaire à Gauss-Seidel):\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Voici comment voir que $B(\\alpha_k) = I - \\alpha_kP^{-1}A$ :\n", + "\n", + "Pour Richardson préconditionné nous avons que\n", + "\n", + "$$Px^{(k+1)} = Px^{(k)} + \\alpha_k (b - Ax^{(k)})$$\n", + "$$Px^{(k+1)} = \\alpha_k b + (P - \\alpha_k A)x^{(k)}$$\n", + "$$x^{(k+1)} = \\alpha_k P^{-1}b + P^{-1}(P - \\alpha_k A)x^{(k)}$$\n", + "\n", + "On reconnait la matric d'itération en $B(\\alpha_k) = P^{-1}(P - \\alpha_k A) = I - \\alpha_kP^{-1} A)$\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A = np.array([[3,2,1,0],\n", " [3,4,3,2],\n", " [3,2,5,2],\n", " [1,2,3,4]])\n", "D = np.diag(np.diag(A)) \n", "Pgs = np.tril(A,k=0)\n", "\n", "Alphas = np.linspace(0, 2, 3001)\n", "\n", "rhoBj = []\n", "rhoBgs = []\n", "\n", "for alpha in Alphas :\n", " Bgs = np.linalg.solve(Pgs,(Pgs-alpha*A))\n", " Bj = np.linalg.solve(D,(D-alpha*A))\n", "\n", " lk, v = eig(Bj)\n", " rhoBj.append( np.max(np.abs(lk)) )\n", "\n", " lk, v = eig(Bgs)\n", " rhoBgs.append( np.max(np.abs(lk)) )\n", "\n", "plt.plot(Alphas, rhoBj, 'b:', label=r'$\\rho(B_J(\\alpha))$')\n", "plt.plot(Alphas, rhoBgs, 'g:', label=r'$\\rho(B_{GS}(\\alpha))$')\n", "\n", "plt.xlabel(r'$\\alpha$'); plt.ylabel(r'$\\rho$');\n", "plt.title('Spectral radius')\n", "plt.grid(True)\n", "plt.legend()\n", "plt.show()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On constate que:\n", "\n", - "1. En utilisant $P=D$, Richardson converge pour $\\alpha\\lessapprox 0.8$ et la convergence est optimale pour $\\alpha \\approx 0.75$\n", - "2. En utilisant $P$ égale au triangle inférieur de $A$, Richardson converge pour $\\alpha\\lessapprox 2$ et la convergence est optimale pour $\\alpha \\approx 1.5$\n", + "1. En utilisant $P=D$, Richardson converge pour $\\alpha\\lessapprox 0.8$ and the optimal one is for $\\alpha \\approx 0.75$\n", + "2. En utilisant $P$ égal au triangle inférieur de $A$, Richardson converge pour $\\alpha\\lessapprox 2$ ; le paramètre optimale est $\\alpha \\approx 1.5$\n", "\n", "#### Partie 2 - Implémentation de la Méthode de Richardson\n", "\n", "Définissez une fonction Python qui implémente la méthode de Richardson stationnaire avec la structure suivante:\n", "```python\n", "def Richardson(A, b, x0, P, alpha, maxIterations, tolerance) :\n", " # Stationary Richardson method to approximate the solution of Ax=b\n", " # INPUT :\n", " # x0 : initial guess\n", " # P : preconditioner\n", " # alpha : constant relaxation parameter\n", " # maxIterations : maximum number of iterations\n", " # tolerance : tolerance for relative residual\n", " # OUTPUT :\n", " # xk : approximate solution to the linear system\n", " # rk : vector of relative norm of the residuals\n", "```\n", "\n", - "La méthode de Richardson, comme toute méthode iterative, a besoin d'un critère d'arrêt. Dans ce cas, le plus simple est de poser les critères suivants:\n", + "La méthode de Richardson, comme toute méthode iterative a besoin d'un critère d'arrêt. Dans ce cas, le plus simple est de poser les critères suivants:\n", "\n", "1. On fixe le nombre maximal d'itérations\n", - "2. Le résidu rélatif est plus petit qu'une tolérance $\\epsilon$ : \n", + "2. Le résidu relatif est plus petit qu'une tolérance $\\epsilon$ : \n", " $$ \\frac{\\| \\mathbf b - A \\mathbf x^{(k)} \\|}{\\|\\mathbf b \\|} < \\epsilon$$\n", " \n", "On s'arrête dès que l'un des ces critières est rempli.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def Richardson(A, b, x0, P, alpha, maxIterations, tolerance) :\n", " # Stationary Richardson method to approximate the solution of Ax=b\n", " # INPUT :\n", " # x0 : initial guess\n", " # P : preconditioner\n", " # alpha : constant relaxation parameter\n", " # maxIterations : maximum number of iterations\n", " # tolerance : tolerance for relative residual\n", " # OUTPUT :\n", " # xk : approximate solution to the linear system\n", " # rk : vector of relative norm of the residuals\n", " \n", "\n", " # To complete\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Partie 3 - Utilisation de la Méthode de Richardson\n", "\n", - "Uliliser la fonction `Richardson` pour approcher la solution de $A\\mathbf x = \\mathbf b$ pour $\\mathbf b = (0, 1, -1, 1)^T$; considérer une tolerance sur le residu rélatif de $10^{-6}$,\n", - "le vecteur null comme point initial $x^{(0)}$ et un nombre maximum d'itération de $200$. Faire des tests\n", + "Utilisez la fonction `Richardson` pour approcher la solution de $A\\mathbf x = \\mathbf b$ pour $\\mathbf b = (0, 1, -1, 1)^T$ avec une tolérance sur le résidu relatif de $10^{-6}$ et\n", + "le vecteur nul comme point initial et un nombre maximum d'itérations de $200$\n", "\n", - "1. En utilisant $P=D$, avec $\\alpha = 0.7, 0.75, 0.79,0.81, 0.9$\n", - "2. En utilisant $P$ égale au triangle inférieur de $A$, avec $\\alpha = 1, 1.5, 1.95,2.05$ \n", + "1. En utilisant $P=D$, avec : $\\alpha = 0.7, 0.75, 0.79,0.81, 0.9$\n", + "2. En utilisant $P$ égal au triangle inférieur de $A$, avec : $\\alpha = 1, 1.5, 1.95,2.05$ \n", "\n", - "Comment intérprétez-vous ces résultats ?" + "Comment interprétez-vous ces résultats ?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "b = np.array([0,1,-1,1])\n", "# Define the initial guess\n", "x0 = 0*b # trick to have the right size for x0\n", "\n", "tolerance = 1e-6\n", "maxIter = 200" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Jacobi-like preconditioner\n", "P = np.diag(np.diag(A))\n", "legend = []\n", "\n", "for alpha in [0.7, 0.75, 0.79,0.81, 0.9] :\n", " x,relRes = Richardson(A,b,x0,P,alpha,maxIter,tolerance)\n", " print(relRes[-1])\n", " plt.plot( relRes, ':')\n", " legend.append(str(alpha))\n", "\n", "plt.legend(legend)\n", "\n", "plt.xlabel('n'); plt.ylabel('res');\n", "plt.title('Relative residuals')\n", "plt.yscale('log')\n", "plt.show()\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Gauss-Seidel-like preconditioner\n", "P = np.tril(A,k=0)\n", "legend = []\n", "\n", "for alpha in [1, 1.5, 1.95,2.05] :\n", " x,relRes = Richardson(A,b,x0,P,alpha,maxIter,tolerance)\n", " print(relRes[-1])\n", " plt.plot( relRes, ':')\n", " legend.append(str(alpha))\n", "\n", "plt.legend(legend)\n", "\n", "plt.xlabel('n'); plt.ylabel('res');\n", "plt.title('Relative residuals')\n", "plt.yscale('log')\n", "plt.show()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Partie 4 - Implémentation de la Méthode du Gradient Préconditionné\n", "\n", - "Définissez une fonction Python qui implémente la méthode du Gradient Préconditionné avec la structure suivante:\n", + "Définissez une fonction Python qui implémente la méthode de Gradient Préconditionné et qui a la structure \n", "```python\n", "def PrecGradient(A, b, x0, P, maxIterations, tolerance) :\n", " # Preconditioned Gradient method to approximate the solution of Ax=b\n", " # INPUT :\n", " # x0 : initial guess\n", " # P : preconditioner\n", " # maxIterations : maximum number of iterations\n", " # tolerance : tolerance for relative residual\n", " # OUTPUTS :\n", " # xk : approximate solution to the linear system\n", " # rk : vector of relative norm of the residuals\n", "```\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def PrecGradient(A, b, x0, P, maxIterations, tolerance) :\n", " # Preconditioned Gradient method to approximate the solution of Ax=b\n", " # INPUT :\n", " # x0 : initial guess\n", " # P : preconditioner\n", " # maxIterations : maximum number of iterations\n", " # tolerance : tolerance for relative residual\n", " # OUTPUTS :\n", " # xk : approximate solution to the linear system\n", " # rk : vector of relative norm of the residuals\n", " \n", " # To complete. Start from Richardson, it is easier\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Partie 5 - Implémentation de la Méthode du Gradient Conjugué Préconditionné\n", "\n", "Définissez une fonction Python qui implémente la méthode du Gradient Conjugué Préconditionné avec la structure suivante:\n", "```python\n", "def PrecConjugateGradient(A, b, x0, P, maxIterations, tolerance) :\n", " # Preconditionate Conjugate Gradient method to approximate the solution of Ax=b\n", " # INPUT :\n", " # x0 : initial guess\n", " # P : preconditioner\n", " # maxIterations : maximum number of iterations\n", " # tolerance : tolerance for relative residual\n", " # OUTPUTS :\n", " # xk : approximate solution to the linear system\n", " # rk : vector of relative norm of the residuals\n", "```\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def PrecConjugateGradient(A, b, x0, P, maxIterations, tolerance) :\n", " # Preconditionate Conjugate Gradient method to approximate the solution of Ax=b\n", " # INPUT :\n", " # x0 : initial guess\n", " # P : preconditioner\n", " # maxIterations : maximum number of iterations\n", " # tolerance : tolerance for relative residual\n", " # OUTPUTS :\n", " # xk : approximate solution to the linear system\n", " # rk : vector of relative norm of the residuals\n", " \n", " # we do not keep track of all the sequence, just the last two entries\n", " xk = x0\n", " rk = b - A.dot(xk)\n", " zk = np.linalg.solve(P,rk)\n", " pk = zk\n", " \n", " # To complete. Start from PrecGradient, it is easier" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Partie 6 - Utilisation de la Méthode du Gradient Preconditioné et du Gradient Conjugué Préconditionné\n", "\n", - "Uliliser les fonctions `PrecGradient` et `PrecConjugateGradient` pour approcher la solution de $A\\mathbf x = \\mathbf b$ pour $\\mathbf b = (0, 1, -1, 1)^T$; considérer une tolerance sur le residu rélatif de $10^{-6}$,\n", - "le vecteur null comme point initial $x^{(0)}$ et un nombre maximum d'itération de $200$. Faire des tests\n", + "Utilisez les fonctions `PrecGradient` et `PrecConjugateGradient` pour approcher la solution de $A\\mathbf x = \\mathbf b$ pour $\\mathbf b = (0, 1, -1, 1)^T$ avec une tolérance sur le résidu relatif de $10^{-6}$ et\n", + "le vecteur nul comme point initial, et un nombre maximum d'itérations de $200$\n", "\n", "1. En utilisant $P=D$\n", - "2. En utilisant $P$ égale au triangle inférieur de $A$\n", + "2. En utilisant $P$ égal au triangle inférieur de $A$\n", "\n", - "Comment intérprétez-vous ces résultats ?" + "Comment interprétez-vous ces résultats ?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "legend = []\n", "\n", "# 1) Jacobi-like precondtioner\n", "P = np.diag(np.diag(A))\n", "\n", "x,relRes = PrecGradient(A,b,x0,P,maxIter,tolerance)\n", "print(relRes[-1])\n", "plt.plot( relRes, ':')\n", "legend.append('Gradient, P=D')\n", "\n", "# repeat the same for PrecConjugateGradient\n", "\n", "# 2) Gauss-Seidel-like precondtioner \n", "\n", "# repeat the same for PrecGradient\n", "\n", "# repeat the same for PrecConjugateGradient\n", "\n", "plt.legend(legend)\n", "\n", "plt.xlabel('n'); plt.ylabel('res');\n", "plt.title('Relative residuals')\n", "plt.yscale('log')\n", "plt.show()\n", "\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Autres Exemples\n", "\n", - "Répétez les expériences numériques ci-dessous pour approcher les solutions des systèmes linéaires suivants\n", + "Répétez les expériences numériques ci-dessous pour approcher les solutions de\n", "\n", "$$\\left(\n", " \\begin{array}{ccc}\n", " 2 & 1 \\\\[0.5em]\n", " 1 & 3 \n", " \\end{array} \\right)\n", " \\mathbf x = \n", " \\left( \\begin{array}{c} 1 \\\\ 0 \\end{array} \\right) \\quad,\\quad \n", " \\left(\n", " \\begin{array}{ccc}\n", " 2 & 2 \\\\[0.5em]\n", " -1 & 3 \n", " \\end{array} \\right)\n", " \\mathbf x = \n", " \\left( \\begin{array}{c} 1 \\\\ 0 \\end{array} \\right) \\quad\\text{et}\\quad \n", " \\left(\n", " \\begin{array}{ccc}\n", " 5 & 7 \\\\[0.5em]\n", " 7 & 10 \n", " \\end{array} \\right)\n", " \\mathbf x = \n", " \\left( \\begin{array}{c} 1 \\\\ 0 \\end{array} \\right) .$$\n", " \n", - "Pour quelles matrices et méthodes vous vous attendez convergence ? \n", - "\n", - "Pour la dernière matrice, le résultat n'est pas celui attendu. Pourquoi ?" + "Pour quelles matrices et méthodes vous attendez-vous à une convergence ? Pour la dernière matrice, le résultat n'est pas celui attendu, pourquoi ?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "b = np.array([1,0])\n", "# Define the initial guess\n", "x0 = np.array([1,1])\n", "\n", "tolerance = 1e-6\n", "maxIter = 10\n", "A = np.array([[2,1],[1,3]])\n", "# A = np.array([[2,2],[-1,3]])\n", "# A = np.array([[5,7],[7,10]])\n", "\n", "legend = []\n", "\n", "# To complete: similarly to previous example:\n", "# 1) Jacobi, Gauss-Seidel (simple)\n", "# 2) PrecGradient and PrecConjGradient, with\n", "# both Jacobi-like and Gauss-Seidel-like preconditioning\n", "\n", "plt.legend(legend)\n", "\n", "plt.xlabel('n'); plt.ylabel('res');\n", "plt.title('Relative residuals')\n", "plt.yscale('log')\n", "plt.show()\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### La matrice de Hilbert\n", "\n", - "Peut-on utiliser une la méthode de Richardson pour resoudre le problème du mauvais conditionnement de la matrice de Hilbert ?" + "Peut-on utiliser une méthode de Richardson pour résoudre le problème du mauvais conditionnement de la matrice de Hilbert ?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "n = 10\n", "A = hilbert(n)\n", "xexact = np.ones(n)\n", "b = A.dot(xexact)\n", "\n", "# Define the initial guess\n", "x0 = b\n", "\n", "tolerance = 1e-6\n", "maxIter = 10\n", "\n", "legend = []\n", "\n", "# To complete: similarly to previous example:\n", "# 1) Jacobi, Gauss-Seidel (simple)\n", "# 2) PrecGradient and PrecConjGradient, with\n", "# both Jacobi-like and Gauss-Seidel-like preconditioning\n", "\n", "plt.legend(legend)\n", "\n", "plt.xlabel('n'); plt.ylabel('res');\n", "plt.title('Relative residuals')\n", "plt.yscale('log')\n", "plt.show()\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "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" } }, "nbformat": 4, "nbformat_minor": 4 } diff --git a/6.1 Equations Differentielles Ordinaires.ipynb b/6.1 Equations Differentielles Ordinaires.ipynb index a64ee8f..b6844a7 100644 --- a/6.1 Equations Differentielles Ordinaires.ipynb +++ b/6.1 Equations Differentielles Ordinaires.ipynb @@ -1,367 +1,281 @@ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Equations Différentielles Ordinaires\n", "\n", "## Problème de Cauchy\n", "\n", "$\\newcommand{\\rr}{\\mathbb R}\n", "f:\\rr_+\\times\\rr \\rightarrow\\rr$ continue, $y_0\\in\\rr$ donné.\n", "On cherche $y:t\\in I \\subset \\rr_+\\rightarrow y(t)\\in\\rr$\n", "qui satisfait le problème suivant\n", "$$\\left\\{\n", "\\begin{array}{l}\n", "y'(t)=f(t,y(t))\\qquad \\,\\forall t \\in I \\\\\n", "y(t_0)=y_0\n", "\\end{array}\n", "\\right.$$\n", "où $y'(t)=\\displaystyle\\frac{d y(t)}{d t}$.\n", "\n", "#### Exemple\n", "\n", "Approximer la solution du problème de Cauchy\n", "$$\\left\\{\n", "\\begin{array}{l}\n", "y'(t)=-t \\,y(t)^2\\qquad \\,\\forall t \\in [0,4] \\\\\n", "y(t_0)=2\n", "\\end{array}\n", "\\right.$$\n", "La solution de ce problème est $y(t) = \\frac{2}{1+t^2}$\n", "Avec les méthodes de Euler Proressive et Rétrograde, Heun, Crank-Nicolson, et Euler modifié.\n" ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# importing libraries used in this book\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "from OrdinaryDifferentialEquationsLib import forwardEuler,backwardEuler,Heun,CrankNicolson,modifiedEuler\n" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "f = lambda t,x : -t*x**2\n", "y0 = 2; tspan=[0, 4]\n", "Nh = 20\n", "\n", "for method in [forwardEuler,backwardEuler,Heun,CrankNicolson,modifiedEuler] :\n", "\n", " t, y = method(f, tspan, y0, Nh)\n", " plt.plot(t, y,'o-')\n", " plt.plot(t, y,'o-')\n", "\n", "y = lambda t : 2/(1+t**2)\n", "t = np.linspace(tspan[0],tspan[1],100)\n", "plt.plot(t, y(t),'-')\n", "# labels, title, legend\n", "plt.xlabel('$t$'); plt.ylabel('$y$')\n", "plt.legend(['forwardEuler','backwardEuler','Heun','CrankNicolson','modifiedEuler','$y(t)$'])\n", "plt.grid(True)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Stabilité\n", "\n", "On considère le problème de Cauchy\n", "$$\\begin{cases}\n", " y'(t) = -2y(t), \\quad t>0 \\\\\n", " y(0) = 1\n", "\\end{cases}$$\n", "La solution exacte de ce prolème est $y(t)= e^{-2t}$\n", "\n", "Résolvez ce problème par les méthodes d'Euler Progressive et Rétrograde\n", "sur l'intervalle $[0,10]$ avec\n", "un pas de temps $h=0.9$ et $1.1$." ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAZIAAAEICAYAAAB1f3LfAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAAAsTAAALEwEAmpwYAABeMUlEQVR4nO2deXxb5Znvv6/kXXI2W3YSx1mkBNIkBAJhDQUDpVA6lLQdGHp7C0N7J0NbphuXAaa0ZWZuL7TQ0mXaAqW0tEOhXNaQskMMZU0ggSwkIZGcxdksO3FiyYss6b1/HB1ZUSRbyznSOSfnC/5IOuv75kjnOe/zPs/vEVJKbGxsbGxsCsVR7gbY2NjY2Jgb25DY2NjY2BSFbUhsbGxsbIrCNiQ2NjY2NkVhGxIbGxsbm6KoKHcDykFjY6OcOXNmQfuGw2FcLpe2DTI4dp+PDew+HxsU0+f33nuvW0rpSV9+TBqSmTNn8u677xa0b3t7O21tbdo2yODYfT42sPt8bFBMn4UQOzItt11bNjY2NjZFYRsSGxsbG5uisA2JjY2NjU1RHJNzJDY2+TA8PExnZyeDg4Plboqm1NTUMG3aNCorK8vdFBuTYxsSG5sx6OzspL6+npkzZyKEKHdzNEFKSU9PD52dncyaNavczbExOcIIoo1CiPuBvwO6pJQLMqwXwM+BS4B+4B+llGsS6y5OrHMC90kpbx/rfIsXL5b5Rm2tXn4PrWvuoEkG6RIedp18A6d+5p/zOobZeHLtbu54fgu7ewdomVDLDRcdz9JFLeVulq5k6vPxNYeZO3euZYyIipSSzZs3s2VwnH2d7T7nhBDiPSnl4vTlRpkj+QNw8SjrPwXMSfwtA34DIIRwAr9KrJ8HfEEIMU/rxq1efg8L3ruFyQRxCJhMkAXv3cLq5fdofSrD8OTa3dz8+Hp29w4AsLt3gJsfX8+Ta3eXuWX6ka3P/ZGo5YwIgBCC/kjUvs52n4vGEIZESvkacGCUTS4D/igV3gYmCCGmAKcB26SUASllBHg4sa2mtK65g1oR4bXaGu4bPw6AWhGhdc0dWp/KMNzx/BYGhmNHLBsYjnHH81vK1CL9ydbnwwPRMrVIfw4PRO3rjN3nYjHLHEkLsCvlc2diWablp2c6gBBiGcpohubmZtrb23M++TkyCALeqa3hL/Vurjl0GCfQJLvzOo6ZUJ9cMi0/1vocjUv6+vpK3JojmTBhAvPnz09+/vznP893vvMdLrnkEvbt20dNTQ0ul4tf//rXzJkzJ+fjRuOZXdvH4nW2+1w4ZjEkmfwKcpTlRy+U8l7gXlDmSPLJ7NzX7mEyQWZHhhlyONhdUcH0aJQu0WjZrNiWt1/J+OVrmVB7zPW5wiGor6/P+TiqL3pP7wBTNfK/19bWsm7duqOWO51OHnroIRYvXsy9997LrbfeyvLly3M+boUjs8vuWLzOdp8LxxCurRzoBFpTPk8D9oyyXFN2nXwDA7KK2ZFhALZWVTIgq9h18g1an8ow3HDR8dRUHvn1qK10csNFx5epRfpzw0XHU11xdJ/H1eb+vJXqi5aU1v9+zjnnsG3btrz2GVdbQZXzSGNyLFzndAN6LPTZqWOfzTIiWQ5cJ4R4GMV1dUhKuVcIEQTmCCFmAbuBK4H/ofXJT/3MP7MaaFirzIn4KyuZO+VsS0dtLV3UQkd3mJ+/vBWASa4qvv938ywd2bJ0UQvv7TjAn97eCUBTfTX/dsnHqKs6nNzm35/eyId7Dmc7BGt39hKJxY9YNjAc418fXcdDq3Zm3Gfe1HH84NL5GdcljzEwwEknnZT8fPPNN/MP//APR2zz9NNPc8IJJ4x6nHTqqiq4cF4zf12/D4Ap42u48eK5lr/OD6/aydsdyrTssRC1tXRRC79euY2OnjDDMal5nw1hSIQQDwFtQKMQohP4AVAJIKW8G3gGJfR3G0r47zWJdVEhxHXA8yjhv/dLKTfq0cZTP/PPyEuXIX93LmtcdSw7+B5E+qGqTo/TGYJpE2uT768912vpH5rKRFd18v2tn5nPJSdMYdOm7IYjnXQjMtbyXKmtreX999/PuO6LX/witbW1zJw5k1/+8pd5H7u60pl8f++XFnPCtPGFNtM0pE4NrfiXs5noqipfY0pEaCjKpQun8pnmXs1deIYwJFLKL4yxXgJfz7LuGRRDoztCCKpjk9lQ2QUDB2Dtf8Ppy0px6rLgD4apdAqqHRJ/V7jczSkJ/mAIT301wb4h/F2ho9aPNXJYcnt2X/Rf/vlMzdqZyoMPPsjixUeF9ueMPximqb6arr4h/MHQMWFI/MFQss+B7hCnuCaVu0m60h+JsufQIF6PC+jV/PhmmSMxDOOZzCFHL8PTToW3fgkx64aGBoIhZja4mOp2EOg++qZqRQLBMAumjmNSjSDQnb/xvOGi46lNecIH4/vfA8EQ589tQiTeW51D/cP0hCNcOK8ZUAyp1Qkk+ujzuHU5vm1I8qS5cgqIGFsXXgm9O+HDJ8vdJN0IdIfxelxMdjmSX0QrE49LOrpDeD1uprhEQTfVpYtauO1zJ9AyoRaBMhK57XMnFO0WVOdI1L+bbrqpqOOpxOKSvsEocyfX46kT+AswnmbDn3goOuc4DxWCY+K77U98l706GRJDuLbMxIyaKWwYhjeck5jXMAfe+Dks+DxYLPM5GouzoyfMhfOaORA9yGudEXr7I0yos64vec+hAQaH43g9LrbvdPDO/jCFSAgtXdSi+XxSLBbLuLzYHIBoXJm78XrcTHY5MrrzrIbaxzlNbppcInmTtTKBYBghYEZDHXt1OL49IsmTue7JSClYH/wIlnwD9q2DwMpyN0tzdh0cYDgm8SWezsH6LoDU4f8Ul4PQUJRg31CZW6Uv0ZhiKH1NynXu6A4Tz5KkaBUC3crcX+ukOqa4HMeEOy/QHaZ1Yh01aW5XrbANSZ60uKuRww0EDvlh4T+Ae7IyKrEY6lOb6toCLP/kNjL8H+nzNov3eTguqal0MGVcDVNcDoai8axZ0FbB3xVi+qQ6Kp0Oprgc7OjpZ7jIqDqj4+8KJSba9cE2JHlS6RBUx6fSNbgDKqrhjK9CoB32vF/upmmKOrnua3TjqRVUOoXlfcmBYJj6mgo87urkKMzqfY7G4ngb3TgcgikJ41lIkIGZCHSHk5POU1yCaFyy60B/mVulH8rcX1i3iXawDUlBNFZPZ0DuZyg2BIuvgap6y41KAsEwje4qxtdV4nQIZjS4LO8CCCQm2oUQTKwR1FY6jwFDIpNPquoozMrXWZ37UyedR/ps3eu89/AgA8Mxe0RiNGbUe0HECRzsgJrxijH58Ek40FHupmmGPxjC2zjyBONtdFnftdUVxteo/NgcQjDL4n2OS0ksLpM31XFVUF9TYek+q3N/6cbTyn1WHwxSf89aYxuSAljgUXIC3t27SVlwxldBOOGtX5WxVdoSCIbxNY08wfia3Ow8YF1fcmgoyr7Dg/iaRn5svia3pfNnItE4EvAlbqpCCHwet6WfztWbqurmcVUKGt3Vlu6zOt+Z+nvWGtuQFMApU49DSgfv79+sLBg3FU78ByXTPdxd3sZpQG9/hJ5w5KgRyXDMur7kjsSNxNs48mPzNrroPDhQUAiw1jidziPySG6/XSkE2tbWxvHHH8+JJ57IqaeemlVGJRNDifoUqb5zr8faozB/0pCkXGeL9znQHaa+Wpn70wvbkBTA8c0TiUca8femKK2e9Q2IDsCqe8vXMI1Qw3zTRyRgXV9yMrggbUQiZfaaHVlZ9wjctQBunaC8rnuk6PapWlvqX2pC4oMPPsgHH3zA1772NW64IXdF6qGoMrqclWI8fR43+w8PERqypmJDIBimwVV1RD6Uz+O2dIBBIBjG2+TWtcqnbUgKoNFdhXN4MnsHto8s9BwPx1+iGJKIub+U/gw+VV/ivVWf3PxdIRyJhC0VdXSi5lrkxLpH4OlvwKFdgFRen/6GJsZkLM4880x2785drn4oGqfCIXBVj+Qlq0/qVp1w9wePDoP1eVwcCEc4GI6UqVX64g+GknN/emFntheAEIKJlTM4GF9HKBLCXZW44S75Jmx5JiHmaF6J+UBCrDFV/Xd8XSWN7irLjkj83WFaJ9VRXTGSsKXecIbjKfNCz94E+9ZnP1DnaoilJTEOD8BT18F7D2TeZ/IJ8KnbR21fLjLyzz33HEuXLh31OKmohiQV1c0VCIZZOG1CzscyC4FgOKmxpZLsswXFG8NDUfYeOnLuTw9sQ1IgM+vncjDyNB/2fMhpU05TFk4/A1rPgDf/CxZ/BZzm/OdVxRornEcOWL2N1p18DgTDR8yPgFKrY+r4mvxGJOlGZKzlOTKWjHw4HCYWi7FmzZqcjielZCgaoyKtqNX0hjocwpojkuTcX9qIRP3sD4Y5ZYa1DElH99Fzf3pgzjudAVjoWcDa3bBm/7oRQwLKqOThL8DGJ2Dh5eVrYBH4gyFmZ3iC8XpcvPDh/jK0SF9UscazfA1HrfN63Ek9KmDMkQN3LUi4tdIY3wrX/LXIlmbmwQcf5MQTT+Smm27i61//Oo8//viY+0TjSuhv+sNCdYWT1kl1lpTD8ScDKo78bk+bWEeV02FJt63eYo0q9hxJgSyYPIV4ZBKr935w5IrjLobG45QERQNE++TLcCzOzgP9GbNgfR63JX3Jqlhj5j67iMZk7pFbF3wfKmuPXFZZqyzXkcrKSv7P//k/vP3222zatGnM7dWJ9kw1230etyVvqsnQ37SHJKdDMLOxzpJuW38wfNTcnx4YwpAIIS4WQmwRQmwTQhyljy2EuEEI8X7ib4MQIiaEmJRYt10IsT6x7t1StdnrcRMbnMaWgx8eucLhUCK49q8H/yulao5m7DrQn0jYyjwiASzn3ko+qWbI/PV63MTzidxaeAVc+gtlBIJQXi/9hbK8CHKRka+treX666/nzjvvHPN4auhv+ogEFDeIFcUb1UJtrRNrj1rnbbSu8Zymo1ijStldW0IIJ/Ar4EKgE1gthFgupUzeoaWUdwB3JLa/FPi2lPJAymHOk1KWNIFjRkMd8cFpHBpeR89ADw21KW6RhVfAyh8qo5LZF5SyWUUzooB79E1VfWK3mi85PUktFZ/HzUDwAEPDMSoz3HQzsvCKog1HOrnKyF9//fU5HW8oGschBI4MIaG+JndSvLF1knVKSQeCIWZkmPsDJdT9pU37GY7Fc7/OJiAQDGf8LWuNEf7FTgO2SSkDUsoI8DBw2SjbfwF4qCQtG4XqCieNlbMB2NiTViZeFXPseBX2rC1D6wpHHW1kGpFMm1hrSfFGVayx0X10rRV1lKK6gqzCUDROdYUjYxkddWLWarkVge6jAypUvI1uy4k3xuMyqR+nN2UfkQAtQOrsZCdweqYNhRB1wMXAdSmLJfCCEEIC90gpM2YECiGWAcsAmpubCy4IFAqFkvtOijXRJwUr3l1BfNuRNxpndDZnOus48MR3+XD+vxZ0rnLw+oYhxlXB2nfeSC5L7bOnBt7ZtJ322n1laqH2vPvRAJ5qePXVV5PL1D7HpUTUjKevf5AqaZ25oYFInGonDA4OJq+t2udDQ4pL6/k330fuqSxjK7UjFpd0BPs5zjV0xG9f7XNvrzLie2rl2yxqMsJtsXh6BuIMDseJHthNe3tXcnnq71krjPAvlindMptz9lLgjTS31hIp5R4hRBPwohBis5TytaMOqBiYewEWL14s29raCmpse3s76r6vhz6kY08zfa4+Mh5P/hNNb/6SpoXTYZK3oPOVml9tfpO5LYK2tjOTy1L7fMKud9nWFcrcX5Ny05svc9bsBtraTkouS+3zq++sRToqqK/X30VQCuJxSezQIdzuGiI1NSxatAgY6bOUku+99QKOCZNpazuhzK3Vho7uMLEX2jnvlI/Rtrg1uVzt86KBYf7z7Reoa55F27m+MrZUO177KAivruJTZ5/MGd4R13vqd1srjODa6gRaUz5PA/Zk2fZK0txaUso9idcu4AkUV1lJ8HrcxAZaWNe9IXNUz+lfBUeFqcQc/WP4VL0et6UKASXFGkcZ/lc4HcnJaSsQiSlijdUVmX/+Qgi8Hjf+Luu4tkYKtWW+zuNrK2l0V1tqwj2QUqhNb4xgSFYDc4QQs4QQVSjGYnn6RkKI8cC5wFMpy1xCiHr1PfBJYENJWo0yIR0baOVwpJc94Qy2b9wUpYri2v+GULBUzSqYg+EIB8KRUW+qPo+1fMkdowQXqFQ4BZFY3DJRTKpRzGZIQNWfstBNVdVSG+U6+zwuS83/BbpHCrXpTdkNiZQyijLn8TywCXhESrlRCHGtEOLalE0/C7wgpUy90s3A60KID4BVwF+llM+Vqu1qCDDAhu4s9uusb0B00BRijiMT7aONSEaygK1ALglbFQ7lZ2KVCXe1H1UV2UNCvR4X+w8P0Tc4XKpm6Yq/62ixxnS8FsufUXTF9BVrVCm7IQGQUj4jpTxOSumTUv4wsexuKeXdKdv8QUp5Zdp+ASnliYm/+eq+paLRXYWLaTioyG5IPMfB8Z9WDMmQsb+k2TJ/U1HFG60ioREIHi3WmE5lQkZkKGoN99ZQVAlxdWZIRlRRR6UdFoncCnSHxiw16/O4ONg/bJmE21KF/oJBDIlZUQoBTaA63prdkACc/S0Y7FVcXAYmEAxT5XQcIdaYjtXEGzOJNaaj3nCtNCIZza0FqSrA1rjOgWB4zLmCVPFGs5MUayxB6C/YhqRovB4Xw/0tfNjzIbF4lifW1tNg+pnw1n9BzLiuAn8wxIyGuowJW6lYKQvY3xUaU9DOIQSVTodhDcnAwADnnntuMmmxs7OTv/zlL0QiEc455xyi0ZHaIlJKhoZjVI+R6ayKN1rhOmcTa0wn6ba1QJBBqcQaVWxDUiQ+j5u+Qy30R/v56OBH2Tdc8k1FzG/jE6VrXJ4EgmMP/0HJArZCspoi1hjOqc/VFQ7Durbuv/9+Pve5z+F0Ksbh5ZdfZs2aNVRVVXHBBRfwl7/8JbltNC6JSTnmiKS6wsn0SdbQn0oWahvjOifFGy0wIvFn0RXTC9uQFInP4yLWr+SIrNq3KvuGcy4Cz1zDijkOx+Ls6OnPKVTQ22gN8cbdvQMMReM5Zf5WVzoZGo6Xrezu+vXrWbJkSfLzmjVrOP/88wFF/feyyxQxiNdff53vfOc7PProo5x00kksXbqUBx98MLnf0LAyqhrLkIB1Jp9zVcBVxRutMCIplVijihESEk2Nz+NGRsfTUNXCqn2ruHr+1Zk3VMUcn/oa+F+G2Z8obUPHYNeBfqJxmfOIBMxfCEgdVeUyIVld4SAuJbet+hFbD27RtB1zJ83lxtNuHHWb+fPn4/f7icViOJ1Orr/+en7yk58QiUQIBALMnDkTgLPPPptTTz2VO++8kwULFhCLxVi9enXyOOqoarQ5IRWfx8Ub27qJxyWOUSbmjU5gFLHGdHweN1v295WgVfoSCIbGnPvTEntEUiSqL7mhYh7v7X+PaHyUWtcnXA71U+D1n5WsfbkSGEUBNx1v44h4o5kJ5FGrQX2Cj5UpEdPhcDB//nw2btzIY489xvTp0zn55JPp7u5mwoQJR2y7ZcsWjj/+eACcTidVVVX09Sk3R1WssdI5tmHwekbEG83MaGKN6Xg9LnZaIOHWn6FQm57YI5IiUQsBOQbnEI6/yKaeTZzgySIrUVEFZ3wNXvwe7H4PWk4pbWNHIZ8COKp4o9ndHv5gKKtYYzrqk93XFl5PQwkSvDJxxhln8MYbb/DrX/+a555T0qVqa2sZHBxMbtPT08P48eOprBzRyBoaGqKmpkZ5nxRrzMGQNKo5QyFTqwD7c5z7gxHxxmw1eczAaIXa9MIekWiAz+Om94Ci8jLqPAnAKf8I1ePhjV/o37A8CATDNLqrGV87tkhfhdPBzAbzZwErcfa5JWxVOhXJ9XJGbp1xxhnccsstfPazn6WlpQWAiRMnEovFksako6ODqVOnJvfp6enB4/EkDctQNJazu0OdqDXzdU4Wastx0tkKfR6tUJte2IZEA7yNLnYGnXjH+8Y2JDXj4NQvw6bl0OMvTQNzQMmCzX0o7PW4LDEiybXPQohE5Fb5DMncuXOprq7mxhuPnE/55Cc/yeuvv57cpru7mwULFvDmm2+ycuVKLrnkEkB5Uo1E41RX5vazb3BVMa6mwtTXOVmoLUc3z4hyg3n7nI+bWitsQ6IBaiGg+RNPZm3XWobHyhU5/dqEmON/laaBORDIMQxWxedxm9qXHBqKsv/wUF59rq5wllW88ec//zm33XYbLteRN4jrrruOBx54AAC3282qVavYsGEDZ511Fn/+859ZtmwZoIg1Qm4RW5BIuG1ym/rpPFmoLccRybiaSjz11aZWbvCPUqhNL2xDogHq005T1XwGogNs6BlDN7J+Mpx4Jax9EEJdo29bAkbEGvMZkYz4ks3ISFXE3PtcXekoi3ij3+9n7ty5DAwMcPXVR0cFLlq0iPPOO++oKoqRSISlS5cmJ95zEWtMx+zJp8mb6iiyP+l4G12mDiQZrVCbXtiGRAPUp53KyGwEglV7x3BvgRIKHIsYQswxF7HGdMwuoRHIMUktFfUGXGr3ls/nY/Pmzfzud7/Lus2Xv/zlZEKiSlVVFVdddVXycy5ijUedu8lFV595xRuVub8qxtflXqBLGYWZ13iqumKlEGtUsQ2JBqi+5D0HHBw38bix50kAGufA3E/Dqt+WXcwx18zfVNToLrP+4FSxxul5JGyNGBJjZriPRS5ijemood5mFW8MdIdGFSHNhLdREW88YNKEW3/X2LpiWmMbEg1QCwEFgmFOnXwq73e9z1BsaOwdl3xLEXNc80e9mzgq/mAoIdaY+01VKQRUZVq3hz84tlhjOuqTvFE1t8ZCidjK7yfvM/nksz8HscZ0fCZ+SMqlUJse2IZEI9RCQGdOPZNIPMLqfavH3qn1VJh+llJBsYxijoFgmJmNdXk9qQJJ42lG8sktAEXs0OkQVBlYvHE0FLHG+BFijbnIvUxvUL4XZrzOuRRqy8SIITFfn3Mp1KYHtiHRCLUQ0LyJJ1NbUcvKnStz23HJN+FwJ2x4XN8GjoI/mP/wH5QvqxmfVFWxxlxDQmtqaujp6UFKSVWFOcvupos1Sinp6elJJipmo7rCSevEWlNe50Lm/gBaJtZSVeEweZ9LOyIxRGa7EOJi4OeAE7hPSnl72vo2lBK7HYlFj0sp/yOXfUuF+hSz52CUs1vOZuWulXz3jO/iEGPY6jmfBM/HFDHHhVdACSfIIJGw1dPPxfMn572vz+NOFgKa6CpdhEixqGKNuYaETps2jc7OToLBIL39w/RHokQPjK3bZCSGhmMEQxFiB6oIJkYlNTU1TJs2bcx9fSYdeRYy9weKeOOsBnNGbpVarFGl7IZECOEEfgVcCHQCq4UQy6WUH6Zt+jcp5d8VuK/upPqSz2s9jxd3vMiG7g0s9CwcfUeHA5Z8A578Kmx7CeZcWILWjpCPWGM66pOe2cQbA3nWaqisrGTWrFkA/PGt7Xz/qY28828X0Dxu9Kd5I/HgOzv47vINvHnT+UydkJ8R9HpcvL6tm1hc5u3+LCeqWONohdqy4fW4TCne6C+xWKOKEVxbpwHbEmVzI8DDwGUl2FdTVPHGQDDMOdPOwSmcvLLzldx2XvD3UD9VGZWUGH8RWbCq8TGb7La/q/BaDSN9Npfbw98Vpq7KyeQCjJ8vId64x2Tijf5giJk5ijWmY9aE20CJxRpVyj4iAVqAXSmfO4HTM2x3phDiA2AP8L+llBvz2BchxDJgGUBzczPt7e0FNTYUCmXd11MrePvDDk6p2ouv2seKzSs4qe+knI47rekiZvt/z3vL76Vv3HEFta0QXuxQQhz3bHmfQ4HMT5vZ+hyXkgoB7Ws20RQ2jtzLWLy+cYi6Cli/+s2ssfbZ+nxgULmxPPfmWiKduecmlJt3twziqZG89tqrWbfJ1udDB5Q5oSdefpOFHiPcMnJjw45+prodo/7Ws/V5qHuYaFzy6LPtTHEb4Xl7bOJS4t/fz/TqioL6XAxG+FZk+iWnh5OsAWZIKUNCiEuAJ4E5Oe6rLJTyXuBegMWLF8u2traCGtve3k62fedvX82e3gHa2s5hz6Y93LbqNmYsmsGs8bPGPvDQKfDTxzll8HX4zLKC2lYIz3R/QKM7yKcvPC/rNqP1edbaV4nUuGhrW6xTC7Xnno/e5rgpMc47b0nWbbL1WUrJLW8+j2PCVNra5uvYSm353qpXOGnWRNraFmXdJlufF4SGuG3VS7im+Gg7O4fvsgEYjsUJvvAcS0+dSVvb3KzbZevzhF29/Hb9GzTMmkdbAfOH5aDzYD+R51dy7qKP0Xb69KzbjfZ7LhQjmNpOoDXl8zSUUUcSKeVhKWUo8f4ZoFII0ZjLvqXE53HR0R0mFpecP12pXrdyV47RW9X1cOpX4MPSijkqCriFD4XVsGczoWb+FoKSM2SuUsODwzE6Dw4UfJ0bXFWMr600VV5FMXN/kDr/Z57r7C9T6C8Yw5CsBuYIIWYJIaqAK4HlqRsIISaLhA9CCHEaSrt7ctm3lHhTfMmTXZOZ1zAv93kSUMQcnZXw5i/1a2QaigJu4aGCZisE1Dc4zP7DQ0Vl/nob3aaaI9neE0bKwkNCVeNppnDYYub+YES80UzXOZ9CbVpTdkMipYwC1wHPA5uAR6SUG4UQ1wohrk1s9vfAhsQcyS+AK6VCxn1L3wuF5ERs4oKe33o+64LrCPYHcztAfTOc+AV4/88lEXM8GI5wsH+46BGJmcQbO7oLCwlNxedxJ2o+mCOfJKDBk6rZQoADBYg1puMz2cgzEAwzrsRijSplNySguKuklMdJKX1Syh8mlt0tpbw78f6/pJTzpZQnSinPkFK+Odq+5WKkloHy5btw5oVIJM90PJP7QVQxx3fu0aOJR6C6pIq5qXpNJt6oxU3V63EhpXn0p9Sb6qwionm8HnOJNxYi1piOotxgnhGJ6l0opVijiiEMiVVQxRuTQ8zxXhZ6FvLE1idykqMAoHE2fOzvYPVvYUjfOHY1bLcoN0/aKMzo+AsQa0zHbMWP/MEwU8fXUFdVeGyNqnxglgeGQtUaUjGbeGOgAF0xrbANiYZkKgT02dmfxX/Iz4buMWqUpLLkWzB4SHcxR393/mKN6SjijeYpBBQIhpleZMKW2W6qgWCooJyZVGY3jSSfmoFAdxhfU3E31ZGyu8bvc7nEGlVsQ6Ix6YWALp55MTXOGp7Y9kTuB5m2GGYs0V3M0d9VmFhjOspErDluqsUGFwDUVjlpmWAO/SkppaKAW2SS2vRJLpwOYYrkU1WssdgRiTq/YobrXC6xRhXbkGhMeiEgd5WbC2dcyLMdzzIQzSMzeMm34PBu2PCYPg2lsFoNmfCZxJesijVq8WPzelymGJEE+4YIDUWLHpFUVTiYPqnOFCOS5NxfkSMSVbzRDNe5HOV1U7ENicZkcnssnb2U0HCIl3e+nPuB5lwITfMU2ZRc51fyQBVrLPbHBspTkBl8yapYoxbhkarxzHnuq0wkw2A1eGDwNprDeGrVZzOJNxZSqE1LbEOiMT7P0b7kxZMX0+Ju4cltT+Z+ICGUCK6uD2Hrixq3EnYmEra0GpGA8X3JWj61+TwuwpEY+w/nUMCsjCT7rMUDQ5ObQCLh1siMFGorXqHZ1+Qy/PcawN+df6E2LbENicZkKgTkEA6Wzl7KO3vfobOvM/eDLfg8jGvRRcwxGQZbpMsDzBMCHCgySS0Vs5QaDgQLF2tMx9voImIC8cZAMMyMhrqCxBrT8Ta62XnA+Am3/q7C1Rq0wDYkGpOtENDS2UupEBU8uOnB3A9WUQVnfh12vA53zoFbJ8BdC2DdI0W305/Mgi3+pjptYh1VTuMXAvIHQ4yrqaBBg9opZgkB9gdDzGp0aZJboBrPbSbos1ZhsF6Pi2hcsqPHuAm3+RZq0wPbkOhApizgya7JfGrWp3hs62P0DvbmfrDqeuU11AVIOLQLnv5G0cYkEAzR6K5mXE3xCrZOh2BmY53hfcmBYBhfkzYJW5PH1VBX5TR+n4vQFUvHZ4KRZ3LuT7M+G3/kmW+hNj2wDYkOqKJ+6b7kaxZcw0B0gIe2PJT7wV798dHLhgfg5f8oqo3+IsUa0/E2Gj9yS4skNRUz6E+pYo1aPZ1PSog3GrnPybk/jQxJulqFEcm3UJse2IZEB3wed0Zf8pyJc2ib1safN/2Z/uEch8qHssypZFueIwEN8ilS8TW5DO1L7hscpqtvSJNJZxWj60+pYo1aPZ0LIRT9KQMbEi0kcFKpr6mkqd7YCbdJXTF7RGItRvMlf/mEL9M71Jt7guL4LDW1x00ptHkc0ECsMR1vo7HFGzu6tQuDVfE2KuKNAxFjijdqGVyg4jW48dRDAdfoZQO0nPsrFNuQ6MBoUUyLmhZxctPJPLDxAYbjOWStX/B9qMwQxjgUAn+OtU7SCOiQvJR0ARhUdnsk9FfLm6qxxRvVa1GMWGM6Rhdv9AdDilhjrXbVK70et6HdeYrGVnnEGlVsQ6IDYxUC+soJX2FveC9P+58e+2ALr4BLfwHjWwGhvF7wfaifAn9aCi98D6L5JQKODP+1NCSJSUmD3lQDwTBOh9A0YSs5EWvQbO9Ad5iWCbVFiTWmMzL5bNzrrHU9Dp/HTa+BE279wfKG/oJtSHRhrInYj7d8nBM9J/LLtb8kPJzDD3LhFfDtDXBrr/L68ethWTuccg28+Qv43YV5VVX0B0NUVTho0SBhS0UVbzTyiKR1Yq2mCVvqk75R9ae0DINV8Rk87Fm5qWrbZyOHeoeGokUXatMCQxgSIcTFQogtQohtQoibMqz/ohBiXeLvTSHEiSnrtgsh1gsh3hdCvFvalmdntIlYIQQ3nnoj3QPd3Lf+vsJOUFUHl/4MrvgTHNwOd38c1j6Yk5yKPxhmZkPxYo3pGLkQkFJSWNunNlW80YgjEimlLn1WxRuNOCIZKdSmbZ9nGzgEWA83dSGU3ZAIIZzAr4BPAfOALwgh5qVt1gGcK6VcCPwncG/a+vOklCdJKRfr3uAcGcuXfILnBC71XsofN/4xv2z3dOZ9Br76JkxdBE99DR77iiJBPwpa5hakYtRCQDE1YUuHpzajijeqYo1a99nI4o1qm7Tu89QJxhVv1DpKrVDKbkiA04BtUsqAlDICPAxclrqBlPJNKeXBxMe3gSyhTMYhl5oV3zj5GzgdTn763k+LO9n4Frh6OZx/C2x8Eu4+G3atyripmrClx03VqOKNe9SELR2Mp1HFG7fp+KTq87gM6c5T26R1n50OgbfRmDlD5RZrVNFuFq5wWoBdKZ87gdNH2f4rwLMpnyXwghBCAvdIKdNHKwAIIZYBywCam5tpb28vqLGhUCinfQ+ElHyKv/7tXQ5Ozf7PfJ7rPJ7Z8Qy/fe63zKmZU1CbRjiVcSf9Xz626SfU/O4its+8kh0z/h7EyLzA3lCcaFwS6d5Fe/u+nI6aa5/DwSgAj73wN+ZMLI94XCbWJdp1qHMr7f2BnPbJtc+x3mHCkRhPPr+SiTVGeC5TeGWnMhLev20d7Z25tSvXPlcMRPAHh3ll5UocZYwUSqd9S4QKAf51q+jIsV259tktB9mwI7dtS8lbHw7iqRW89frfct4n1z7nhZSyrH/A5cB9KZ+/BPwyy7bnAZuAhpRlUxOvTcAHwDljnfOUU06RhbJy5cqcthsajknvzX+Vdzy3edTt+of75cWPXiwvevQi2TfUV3C7jmCgV8pHvyLlD8ZJ+buLpTy4M7nq+Q175YwbV8i1Ow/mfLhc+7y9OyRn3LhCPrxqR54N1pf7/haQM25cIYN9gznvk2ufX98alDNuXCFf3xossHX6cOvyDfJj33tWxuPxnPfJtc8PvbNDzrhxhdzRHS6wdfrwlT+slp/4SXte++Ta5zue2yy9N/9VDg3HCmiZflx016vymt+vymufXPucCeBdmeGeaoRHqE6gNeXzNGBP+kZCiIXAfcBlUsoedbmUck/itQt4AsVVVnZy9SXXVtRy28dvY294Lz9a/SNtTl4zHj73W1h6N+xbB3cvgQ+fAlLkFHRwbanijUbzJQeCIcbXVuqSsGVULSa1frceuQVqBrXfYPMkes39gaLcEDNYwq2WhdqKxQiGZDUwRwgxSwhRBVwJLE/dQAgxHXgc+JKU8qOU5S4hRL36HvgkkEdxdH3xNubmSz6p6SS+suArPLntSV7a8ZI2JxcCTvoC/PNrMMkLj1wFy7/Bzn1BPPXaiDWmMyLeaKwbjBoGq8dNtXlcNS4DijdqqSuWjrfReMmnes79wcicp5G+21oWaiuWshsSKWUUuA54HsVt9YiUcqMQ4lohxLWJzb4PNAC/TgvzbQZeF0J8AKwC/iqlfK7EXciKr8lNR09uhYC+etJXmdcwj39/698J9ge1a0SDD778glK6d80f+dpH/4vzxuc2N1IIRtSf0iMMVkXJGTJW5vPgcIzdvQO69XmSq4oJdZWGCvVWxRr16rMRa+6Uu7xuKmU3JABSymeklMdJKX1Syh8mlt0tpbw78f5/SSknSiXENxnmK5VIrxMTf/PVfY2CWgho98GxCwFVOiq57eO3MRgd5Dvt32EopmHlvYoquPDf4aonqY6F+L8934K3fq1LCV+vx1jijapYo54JW0YLAVbFGvXqsxAiUXbXOMZTD12xVIwo3qh3n/PBEIbEqqhDzlx9yd7xXn549g95P/g+33vje5qHlB5oPotPDt7G7oYz4fmb4cHLIaTh6IcR8UajFAJK/th0cvOox97daxzxRtWdqq/xdBvKnefXQawxHaOVDQh0l1+sUcU2JDpSSCGgT878JN86+Vs82/Esv3r/V5q2JxAMcZBxBC64Dy65Ezpeg9+cBds0mpdhZCLWKE9uarDDbA3l49NRpemNIt6YVMDV0Xj6PG6CfUMcNoh4o1qoTUuxxnR8CeOp9QNeofi7tCvUViy2IdGRQgsBfXnBl/ncnM9xz7p7eOyjxzRrT9Kn2lQPp/0TLFsJdQ3w35+H578L0eLdaUYrBOTvSog1TtLx6dxgE7H+YIiWCbXUVumXy2O0OQN/UB/lglS8HjeHBoyTcBvo1i+gIl9sQ6IjhRYCEkJwyxm3sKRlCbe+dSsPb35Yk/YEguEjxRqb5yvG5NT/BW/9F9z3CejeWtQ5xtVU4jGQLznQHWL6pDqqKvT7qis10Y1zUw3oJAeTitHCngMlUMBNehgMMPLsGxxm/2FtC7UVg21IdKZQX3Klo5JfnPcL2lrb+OE7P+T+DfcX3RZ/MMysBteRYo2VtfDpn8CVf1bqwd9zDqz5Y1ET8d5G44g3BoJh3UuQ1lY5mTreGOKNUiexxnSmT6ozjHijHoXaMmEk46lHobZisA2Jzqi+5EIKAVU5q/hp20+5eObF3PXeXfz03Z8Sixc+oRsYTVZ87qcV8ceWU2D5v8Cj18C7f4C7FnBu+1K4awGseySn8/iajBEOG4tLAt3hkpQgNUqfuxJijXrfVKsqHMyYZIycoVIp4E6dUEt1hcMQblvVgOs595cPtiHRmWJ9yZWOSm7/+O1ccdwV/H7j77n2pWs5OHhw7B3TGI7F2Xmgf/Qf27ipcNVTcMEPFPHHFd+CQ7sQSGW08vQ3cjIm3kaXIQoB7ekdIBKN6z4igcQozAATsaWIXlIxSthzqcJgnQ7BLIOEPfuDId3n/vLBNiQ6o0UhIKfDyffO/B7/fta/s2b/Gq5YcQUfBD/I6xg7epSErTF/bA4nfPw74Pag6GGmMDwAL//HmOdSjVW5n1a3lfCm6vO46I/E2Hd4UPdzjYa/hLkFXk/uCbd64g+GqHI6mDZRfwVcJQTYGMazdWKtrnN/+WCMVlgYLQsBfW7O5/jjJX/EKZxc9exV/Hj1j+kfzi1fI5DvTTVbfsmhXYrr64OHoXdnxk2M4ksuZa0Go5SgDQRD1FU5mTyuRvdz+Ty5J9zqiT8YZmaj9oXaMuHzuNl5oJ9ItLwJt0Yor5uKbUh0RhVv1OrpfH7DfP7fpf+Py4+7nD99+Cc++9Rnad/VPqZLJe8n1fFZSr5U1MDGp+CJf4afnQA/nQ+P/RO8ez8Et4CUtCSelMr95OZPiDVOKkHCltcgozA1DLYUuQVG6XNAR12xdLweVbyxfN9tPQu1FYptSEqAT2Nfcn1VPbeccQsPXPwA1RXV/Msr/8JVz17F6n2rs+4TCIbyE2u84PtKRFcqlbXwmV/CjR1w7evwqTtg2mLoeBVWfBt+dRrc4cP5yP/kO+6XiHWugVi0iJ4WRyBRv7sUN1VVvNEII5JSPakawYWZnPsr0aTzSJ/Ld531LNRWKEYobGV5vB43r23tJhaXmg6/T24+mccufYwntj3BPR/cw5ef/zKnTT6NL37si5w77VycjpGEtEC+ctMLr1BeX/4P5KFOxPhpinFRl08+Qfk7fZkSKnwgADvegB1vwY43uHZwhVIM4Ec3QutpMOMsmLEEWk6GimrN/g1GIxAMc85xnpKcywjijapY4+WntI69sQYYQbxRFWss1YhkVmP5EzFLGVCRK7YhKQGp4o1al8SsdFZyxfFX8BnfZ/jLlr/wpw//xDdXfpMWdwuXH3c5n/Z+msmuyfiDIS45YUp+B194BSy8glfb22lra8u+nRCKynCDD06+CoDfLH+VLate4Cen9OPc+Ra88p/Kts5qZRQz/UzFuLSeBtX1Rx5v3SPKpP6hTsXFlmrAcqQUYo3peD0u3t2ef0SdVnR06yvWmAmlVEL5jKd67lL1WRVvLOcDg5HEGlVsQ1ICUgsB6VVbuaaihqvnX80XP/ZFVu5ayZ83/ZmfrfkZP1vzM05oOIlwdSsN4/9Ol3Nnonmajx+9eRbXnX4usy91Q/8B2PkW7HhT+Xv9LvjbnUoZ4CkLldHK9DMh1AUv/JsSIQYjYceQlzEZmWgv3VObz+Pmqff3MBCJ6SpPko1y9bn9I22FP/NhpFBbaftczkASde7PCGKNKrYhKQGphYDOO75J13NVOCq4cMaFXDjjQnYd3sWz25/lsS1PUzP5ff6w62nan5jJkpYlnNx0MouaFuGp08f1kzoRO7vJDXWTlKTHuZ9WNhjqg87VI4Zl1W8VmZZMDA/Aiz+A+Z8FZ25zPCO1Gko7IgFFlmX+1PElO6+K2udZJcibUfF63Py/9zo5PDisS7G0sfB36S/WmI7X42LFur1IKcsimKhn9ctCsQ1JCSiXL7l1XCvLFi5j3OBF3LxiJdd/RrKh9x0e++gxHtz0IAAt7hbmNcxj7qS5zJ00F+94L1NcU46YXymEMRMxq+vBd77yB4pg5O418PuLM2/ftwf+s1EpI1zXAHWN4GpUDFRdo7LM1Zhc17PrEOMcg0zPN7cg4VY791AnrM3PrZYaAlwOQxIogVhjOqkK1ye1TijZeVXynvvTAF+KeGODuzTzfan4g6GSzf3liiEMiRDiYuDngBO4T0p5e9p6kVh/CdAP/KOUck0u+xoBtRBQuXzJHd39VMab+erJF+N0XMNwbJhNBzaxtmstHwQ/YPOBzby448Xk9lWOKqaPm05rfSst7hb6D/cT2R6hqa6JpromGmobqHaO/gPKW7yxohpmnAnjWxV3Vjo1E+CMr0J/D4S7ldfenbBnrfI5fqQEzT8B/1QF3H5tiqFpGDFCmT7veBNevAWGBxCQt1utKPFGDeaFChZrLMJ4elNyhvI2JFr0ORji4gV5zv2lnLuwPo+IN+ZtSIrsc1Fzf0X0eSzKbkiEEE7gV8CFQCewWgixXEr5YcpmnwLmJP5OB34DnJ7jvoagnL5kfzB0hFhjpbOShZ6FLPQsTG4TioTY2ruVjkMddBzqYPuh7ezq28Xbe99mIDrA468+fsQxXZUuJlZPZGLNRMZVjWNc9TjGVY3DVenCXenGVeliUvNe3j9QyWudh6itqKXaWX3EX6WzkipnFZWOSiodlTiFE3HB95Wb93BKkltlLVxyR/YvvZSKq6y/W5mLCXdz55NvMqOmn8vn1UG4RzE8/d2K8Qn3wNCh3P7xhgfgya8prreKanBWjbw6q5Tqk85qqKimxlnF91x7aNpcD7Uzs2yfuqxa2d//Cqz8vxBNZMUf2gXLv6F8XvB5EI7EnzPxKpS/I/4JJP6uEJcvzjNia90jyX/vQoznjIY6Khwi/8nnlPNSwHmhCLHGIvucDAHuCnHqzEkFnZcCzgtFzIMV2eexEGMlsgkhXgKul1Lmp8mRawOEOBO4VUp5UeLzzQBSyttStrkHaJdSPpT4vAVoA2aOtW8mFi9eLN99993RNslK+1gRTFn4TbufHz23mXW3frLkvuTz72zn+Mn1/OZ/npL3vlJKnnnlGWYvmk1Xfxdd/V0cGDzAgcED9Az2cHjoMIcjhzk0dIi+SB99w31E44XljggEFY4KKoCKaIQKGccpHDiqx1FRVY9DOHA6nMqrUF4dwoFAjLwXAoGDtTt7aR5Xy/RJdcn1AoHyv0BIiYhHEbFhiEchFkHsW59oh/JHyit1DQgZBxmHeOI18SfS36fve1Q/8/13GWWNUForgWhc0YNyONQepBqclPepyyJhjpLCUdfVjD/i49EtUT4fGhjG6RC4j/peiwxvE2/6e5R/s6NO61BGiEcsy/wvEInF6e0fZnxtJdVHSIWM8S8cDoLMIH4qnOAeew5TSklX3xB1VU7q8/kth7qKOi/AwHCMQwPDNLqrqcgnlSDl3P/Ue4iPRRIj+PGt8O0NOR9GCPGeWuo8lVxGJP8K3CWE2AH8m5Ryb85nzY0WINWX0Yky6hhrm5Yc9wVACLEMWAbQ3NxMe3t7QY0NhUIF7du/X7m5Pvrca3gnlM6HHY1Ltvf0M39cpOA+ywHJ3nXKZW9I/JekMvGX8lA4LIcZjA/y0q5+nu4Icf2pDqoqokRkhEg8QlRGiRJlWA4TkzGiMkpMxogx8j5OnLiMEyNGXMaTn+PROBJJnDhSypH3SKIyikQyFIsTjzthOMKhXuUHE0e5acnETVN9gEp+RuKuqEbI4eRtVSZuSFJUEKpKefKUqW/lEe97ByXhaJwWl0jc3iVIUt4nXhN/Qkqqh7KPVCNVE0dOmDzVyDlF4n00DoNRSW0FOI+4vxy97chiibPSmfG2K4EYIzc9cZStGVkwXKn0vSo+lL4q4/YAjgoHIkM+tATi0dFcgyPHiUuIVcFhGYEcxLWT5rNCIDLc+iQgI7mNVIerJL0IKvLQJdXivDEpiVdBOM8idKnnHhAj/+7yUCevFnhfSGVMQ5KYizhfCPF54DkhxOPAj6WUWgnsZPse57JNLvsqC6W8F7gXlBFJIaMKKHxEMq0rxC/XvsqE6cfTdnIW+REd2NYVIv7Cq5y3eF7B5y20z+4tXTy1eTWnLTgzPxdAkazc0sU1v1/Nj67N87zprgdQ3GqX/iLn4f+f3t7B957cwB9uPp8p42vH3gEUif5M80LjW+Hbb+d13rdvvoDJ4/PQ2Rr13O/ndIjbntnE79/Yzqb/vDj3hNtRz7tOv/OOee71OR3i6w+u4cO9h1n5v9tKet6vPfgem/b28Uw+5x3l3GL8tIJ+2+nkJJGSmOzegjI38S/AViHEl4o+u0InkOrYnYaSE53LNrnsawjUQkClTmQaCYMtfRasr3HEl1xKkklq+YbBLrxCMRrjW5XRyPjWvIwIgC8Z6p3HhHs2OZoLvp/zIfxdIVxVTprH5Tn5q8G5vR4XkViczoO5CYhqdV5/MFSYWKNGfc5bvFGD8xZcqE2Dc4/GmIZECPE6sBu4C8WV9I8o8xOnCSHu1aANq4E5QohZQogq4Epgedo2y4GrhMIZwKGEiy2XfQ2BWgio1NIK5cyCVcUbSx32HOgOM6GuQLHGhVfAtzfwatuTiu84z4lINfk0r2qJKQaMAg2YErHlzj+3QAvjWYjysRZ9LrQSpEZ9zlu8scg+F1WoTYM+j0YucyTXAhvl0bPy/yKE2FRsA6SUUSHEdcDzKCG890spNwohrk2svxt4BiX0dxtK+O81o+1bbJv0QqllUNqn80AwRFN9dX6TghrhdAhmNZS+EJCiBluehK2m+gLFGxNyNIUSCIY4ZcbEwnbOVQonC6nJp+fNzSPhtog+q2KNnzphckH7F99ntc5QmNlN9WNsffR5C6HoQm1F9nk0cpkjGW1K/9NaNEJK+QyKsUhddnfKewl8Pdd9jYpe4o2j4R+tvG4J8HpcbN7XV9Jz+oNhzi1TwlY5xBtLLdaYjppwW0pF3GShtjLVLFfVA0p5nY0o1qhSlIy8lDKgVUOOBUpdCEhKmahPUb4vXqkLAR0eHCbYN1RWiW2tywaMhSrWWCop9UyUWn8qWae9EDePBtTXVNI8rrqk19lfwkJt+WLXIykhpS4EdCAc4dDAcFlvqqUuBGQEZVSvx83u3gH6I6WpxZJ8Ui3T07ly7tKWoC1lSeFseBtLO/IMlLBQW77YhqSElLoQ0IgyanmfVKF0hYACZYxSU1HP3VGiIINAMIwQpRVrTMfX5KY7NMThwRwSOjQg70JtOuBrUkaeYyV1a4W/hIXa8sU2JCWk1L5k9aY6u8wjEqUtpbupOh2C6ZP0kevPhdL3OcTU8aUVa0zHW+KCT4HuAsNgNcTbOCLeWAoCZXZTj4ZtSEpMKX3J/mCYqgoHUyfkmBinA6UuBOQPhpgxqY6qivJ9tVXxxtL1ucCQUA1J1twpUc6QPxgyTp9LYDxVsUYjlddNxTYkJcbb6CpZXkUgTayxXHg9pQsBVms1lJOaSictE2pL8nQupUyGO5eT6ZMU8ca88mcK5EA4Qm//cNn7PDIK07/PRpj7Gw3bkJQYr8dNsK80vmTlSbX8XzwlHFZ/X3IsLunoMcbwv1QhwPsPDxGOxMoeyVPpdDB9Ul1+Gf0FUk61hlRaJtRSXeEoyXVWDXS5r3M2bENSYnwl8p9HokrCVjkjeVRSCwHpye6DSsKWEX5saghwPK6v8TRCcIGK1+MuyYjEKH12OASzGksT6u3vUuf+yv/dzoRtSEpMMgRYZ1/yzgNhYnFpkBHJSBawnhgpYcvrcTMwHGPf4UFdz2OkPvs8LrZ39xPT2Xiqc38tE8s396fiK9HIM9AdYnqZ5/5Gw5itsjBqISC9n9yScfYGGJGoUWN6+5KN4vJQ2lCakac/GC5MrFEHfB53/uKNBWCUuT9QrvOuxEhYT/xdpS8pnA+2ISkxpfIlG2lybuqE0og3FiXWqDFJIUOdHxgKFmvUgVKFPRshoELFW4h4Y54Yae4vG7YhKQNej6sEI5LyiTWmo4o36u3O83eVP3pJRRVvLEmfDXRTBX3DniPRODsO9Buoz0o7tun4YKjO/Rnlu50J25CUAZ/HrbsvOVBmscZ0fE36hz0HuguUFdcBIQS+JreufR6IxNhzaMAwfZ7kqmKizgm3Ow8ovxuj9NlbgpGnX43YKnPezGjYhqQMFFQIKA9UsUaj/NhAmavRU7xRFWs00vDf26jvKEwVazTSA4PeYc9GCi4AcFdX0DyuWldXddJNbY9IbFIpqBBQHqhijUb5sYEyItHTl6z+WxppQtLncbPn0KBu4o0juQUGus46Kx8bae5Pxadz2LM/GDLM3F82bENSBvT2JavuFCPdVNXoMb3cHgGDPanCSFv0Em80glhjOl6PIt54aECfhFsjiDWm4/XoK95YzkJtuVJWQyKEmCSEeFEIsTXxelSJNyFEqxBipRBikxBioxDimynrbhVC7BZCvJ/4u6S0PSgMvX3JqjvFSE+qI7kk+hhPfzBEhUMwo6F8Yo3pqDk8ul3nYIiWCbXUVJZPrDEdn86h3qoCrpFQE257dEq4NZqbOhPlHpHcBLwspZwDvJz4nE4UuF5K+THgDODrQoh5KevvklKelPgzRaVESGQB6zgiKbdYYzqqeKNebo9AMMz0SXVUOsv9lR5hZoMi3qjbdTagGqyeIcBGKNSWCa+Oruo+A879ZaLcv7rLgAcS7x8AlqZvIKXcK6Vck3jfB2wCWkrVQL3QsxCQGgZrhIStVPSsWV/uksKZUMUb9bjORhFrTEcVb9TjOifn/gzWZ6+OZXeNOCeUiTFrtutMs5RyLygGQwjRNNrGQoiZwCLgnZTF1wkhrgLeRRm5HMyy7zJgGUBzczPt7e0FNTgUChW87xHt6YvQHRrmry+uxFWp7Q1/w85+WusdmrQTtOtz7fAQ6/dFWblypab+3riUBLr68dUNGa7PE50R1nXs06xdKgcH44QjMeK9e2hvD2pyTK363FgL72zaTnvNvuIblcJHB2MA9O8L0N6+U5NjatHnuJRUOuDVNZuY0q9t9fE3ditzTT0dH9Ie3KzJMbW6zkcgpdT1D3gJ2JDh7zKgN23bg6Mcxw28B3wuZVkz4EQZWf0QuD+XNp1yyimyUFauXFnwvqk8v2GvnHHjCrlmxwFNjqcyNByT3pv/Ku98frNmx9Sqz/f9LSBn3LhCBvsGNTmeyvbukJxx4wr58Kodmh1Tqz7funyDnHvLszIWi2tyPJXXtwbljBtXyDe2BjU7plZ9/sofVstP/KRdk2Ol8tA7O+SMG1fIHd1hzY6pVZ8vuutVec3vV2lyrFTueG6z9N78Vzk0HNPsmMX0GXhXZrin6j4ikVJ+Its6IcR+IcQUqYxGpgBdWbarBB4DHpRSPp5y7P0p2/wWWKFdy/VFTS4KBMMsmn5UjEHBqGKNRhwKp+pPNbq104YaCf01nh/ZlyLeqOWcVVIB14BJar4mF699FCQWl5q6V9W5PyOINabja3KzcfchzY9rhEJtuVDu1i0Hrk68vxp4Kn0DofhAfgdsklL+NG3dlJSPn0UZ6ZgCvXzJRhJrTEeviB6jJamlotfksyrW2FRffrHGdHyN+og3GkmsMR1foyLeOBSNaXpcI+mKjUa5DcntwIVCiK3AhYnPCCGmCiHUCKwlwJeA8zOE+f5YCLFeCLEOOA/4donbXzCqeKP2Nxj1pmq8L58q3qiH8TRqwpZPp5whJbjAGGKN6egV6u038E01Kd7Yo53xNINYo0pZJ9ullD3ABRmW7wEuSbx/Hcj4a5FSfknXBuqMHoWAAsGwYcQa03E6hFJqWGPjGQiGDOnWAkW80V1dofkoLBAMc+pM7VyiWpKq3HD+XG2OqRZq+/QJU8beuAyMPDCEmdNcr8kxjVSobSzKPSI5ptGjEJDfwDdV0CcE2B8MGy4kVEUIkeizdsZzIBJjd++AYZ9UJyYTbrW7zkae+wOYpcMoTBVrNOp1TsU2JGVE60JAUkrD+1R9HremvuRDA8N0h4YMOems4tM4+bSj27jBBSpK5UDtjKffwAEVoIg3Th5Xo+lo24gKFdmwDUkZ0dqX3GNAscZ0vB6Xpr7kpMaWQUckoLRNS/FGI8+DqSj6Uxo+nZukz1qOSIxUqG0sbENSRrRWATaiAm46qb5kLUj22cgjkibtr7PRxBrT8XncdIcimok3GnnuT0UdeUqNxBv9XcZ2U6diG5IyMlFj8cZkboGBv3zqzU+rIINAtyLWOH2SccQa00mGAGukAhzoNp5YYzpejUO9jVaoLRNej4vDg1HNxBsD3cad+0vHNiRlRstCQP5giGqDiTWmo4o3alUIyN9lPLHGdFTxRq2KXKmhv0ZmxG1b/HWWBhVrTCdZHkKD62zEQm2jYdxf3zGCloWAAsEwswwo1piOloWAAt3Gv6nWVDqZNrFWkxGJGlBhZPcljCTcajEiUcUajTzShhTlBg2usxnc1KnYhqTMaFkIyOihvypej1KCtlhfciwu2d7db4ofm7fRrcmT6r7Dg/RHYoY3npVOB9Mb6jQZbSfVGgx+naeOr6Wm0qHJdTZiobbRsA1JmdFKNiQSjbPr4IDhf2yg9FkLX3LnwX4isbgpjKfP46ajO0y8yJwhMz2pKpPPWjydK7+N2Qa/zg6HYFajW5MRiRELtY2GbUjKjFZaTEZP2EpFqz6bpVYDKG1UxRuLwQwBFSpej4sdPf1EY/GijmPEQm3Z0Crs2YiF2kbDHK20MFqJN27rMnbCVipa6U8ZWawxHa1yhows1pjOiHjjQFHH8XcZV6wxHV+ji50H+otOuDViobbRsA1JmVF9yUU/nScmr42cW6AydUIt1RWOop/c/MEwE02SsDVbo5whfzCEr8mYYo3pqDXriw2sCHSHk8cyOr4mN3FJUQm3sbhke0+/KR4KVWxDYgC8jcWHAPu7wjSPM3bClorTIZilQalhM4TBqngS4o3FXueAgXXF0lFLGRQT6q2KNRqxLEImkn0u4jqrYo32iMQmL3xNxfuSA90h0/zYQBv9KTOEwaoIIYoO9VbFGs3ypDrRVcUkV1VRIxJ17s8sIxIt8mf8JpoHU7ENiQEo1pcspcTfZS6fqtdTnC9ZFWs0y4gEik8+DZhIDVbF2+gqakSizv2Z5SHJlRBvLOY6m2nuT6WshkQIMUkI8aIQYmviNWOBBSHE9kQBq/eFEO/mu7/RKdaX3BOOcHgwaqonGJ+nOF+ymaKXVHweF3uLEG8c0RUzzwNDscmnI8bTRH1uKm7kaaa5P5Vyj0huAl6WUs4BXk58zsZ5UsqTpJSLC9zfsKhPW4V++cwUBqtSrAvAnH0u/joLoUiumAWvx6WIN/YXlnBrBrHGdLyNxYk3Bkw096dSbkNyGfBA4v0DwNIS728Iii0EZEafqhpdVkyfjS7WmE6xIcD+oPHFGtNJ6k8VOCoxWxgsjIg3docKS7g1cqG2bJS11C7QLKXcCyCl3CuEaMqynQReEEJI4B4p5b157o8QYhmwDKC5uZn29vaCGhwKhQredzQaq2Ks2bqb9vYDee/76uYhKh2w9YN38OsQFqpXnydUC95c72e+6Mx733c2DdJYC2/87TXN2wX69DkSkwjgldUbGd+7Ne/9P+gYYGKV0OVagD597gkrASTP/O1dDrfkN6qQUvLR3n5Om1xhqj6HuxXX5eMvvs7xk/Iz+v3Dku7QEKJvv6n6rLshEUK8BEzOsOq7eRxmiZRyT8JQvCiE2CylzOsOkjA+9wIsXrxYtrW15bN7kvb2dgrddzSe6f6AVzZ3FXTsP25fja9pgPPPO0fzdoF+ff7YR28THo7R1rYk731/uOZVFkx30da2eOyNC0CvPk977xVirgm0tZ2c135SSoKvPM/5J7TS1jZf83aBPn0ejsW55Y3nqGxopa0tvwLu3aEhws+/xNknHkfb2bM0bZeKHn2efbCfO99dSX3LHNpOn57Xvu/v6oWX3+ATpy+kbX6m22bx6NFn3V1bUspPSCkXZPh7CtgvhJgCkHjtynKMPYnXLuAJ4LTEqpz2NwPFFAIKmESsMR1lUjJ/X3IsLtnR02+qSWeVQvWnVLFGs13nSqeDGQ11BYV6m0lXLBVVvLGQPifL6xq4UFsmyj1Hshy4OvH+auCp9A2EEC4hRL36HvgksCHX/c1CoYWAhqIx04g1puNtLEy8MSnWaJKQ0FS8jYWJN5oxuEDFW6DxNGNkHhQn3miGQm2ZKLchuR24UAixFbgw8RkhxFQhxDOJbZqB14UQHwCrgL9KKZ8bbX8zUmgU086efiVhy2Q/Nkjpc56y22ao350NVbxxb57ijWYMqFDxelxs7wnnnXDrD4ZMI9aYTqH1281QqC0TZZ1sl1L2ABdkWL4HuCTxPgCcmM/+ZqTQQkBmqdWQiaSEfneY070NOe834vIw3001tWxASx43yEAwjLu6whRijen4PG6GY5LOgwPMzCMaSZWDMYNYYzo+j5tn1+9lKBqjuiL3CXczFGrLhLnMnoUptBCQGbNgVVoS4o2FjEgm1lUy0UQJWyq+IkZhXo/LFGKN6fgKDHs2Y+ivis/jIi5hRx4Jt2Yq1JaObUgMRCETsYGgItbori53JHf+OBLijfn6kv3BsClHI6CIN9ZXV+Td54CJ+1xIwq0692fWPhdSsM5MhdrSsQ2JgSjEl+wPmkusMR1fAfpTARM/qQoh8vaf90ei7O4dMF2Smooq3phPn9W5P7Ne55GE29yNp5kDKmxDYiBSfcm5IKVUQn9NGAar4vO42JWHeKMi1hgx5VObSr4jz45uVWPLzH3OT3/Kb+J5MFDEG6eMz0+80cwBFbYhMRCqbzRXkTtVrNHMIxJvnuKNARPPCal4E+KN4aHcxBvN/KSq4m3MT7zRTIXasuEtwHiade7PNiQGIt9CQGZNXkolX/0pM0epqahGsCPHeRJ/MGQ6scZ08hVv9HeZT6wxHbVgXa4Jt2Yq1JaObUgMRL6FgNQJW7P6ziFF1C/HJ7eACcUa08m3Zn0gGGbaRHOJNaaT7HPO321zqjWk4vO46MtDvNFMhdrSsQ2JwcinEJC/K0R1hSOvfASj4a6uoHlcdR4jkhDTG8yXsJXKjIY6hMjdeJo9oALySz41Y6G2THjzeGAwY6G2VMz7a7Qo+RQCCnSHmdXowmHChK1U8pl8NnMYrEpNpZPWibnpT0kp6eg2f59bJ9VR6RQ5hT2bsVBbJlSXcy7fbbPKwajYhsRg5ONLNqtYYzrKpOTYvuRoLM6Onn7TP6lC7hOxqlij2ftc6XQwfVJuxtMKwQUAU8bV5CzeaPY+24bEYORaCGgoGmPnAXNmwaajijeO5UvuPDhgWrHGdNQoprHEG1U3p1lvMKkoNevHNp5mDoNNRRVvzMW1ZcZCbanYhsRgJEOAx/jB7ezpJy7NHQarMuICGP0Hp7r8zJw3o+JrcjE4HB9TvFHt82wrXGePmx05JNwGgsrcnxnFGtPxeXJTbggEw6ae+zNnqy1Ma0K8caynGDMr4KbjzTELOPl0bpERCYw9+ezvCuGursBjQrHGdLweF8Mxya4xEm79QWXuz4xijel4Pe6cEm7NHlBhGxKDkWshoJF8CvN++VRU8cZcRiSTXFWmTNhKRx1Vjd1nJSTUjGKN6eSqP2WVuT/ITbzRzIXaVGxDYkBy8SX7gyHTijWmo4o3jjkK6wqbOmcmFY9bEW8cexRm3iS1dHJRAVbn/qww0oaU/JlRRp5mLtSmYhsSA5KLL9kKYbCp+JrGrihnhSQ1FSEE3qbRQ737I1H2HBq0REAFwIS6KhpcVaPO/6lzf1a5zqrEy2jf7WRwgT0iKQwhxCQhxItCiK2J14kZtjleCPF+yt9hIcS3EutuFULsTll3Sck7oQOqLzmbeKMq1miVpzYAX+Po4o2H+hWxRqv1ebSbqiqhYpURCYwd9mwFCZxUchFvTIb+2iOSgrkJeFlKOQd4OfH5CKSUW6SUJ0kpTwJOAfqBJ1I2uUtdL6V8Jn1/MzKWC6A7ZI2ErVRU8cZsvmQ1HNpqN9XRxButdlOFEf2pbKjrzCzWmI5SNmD0EYlZxRpVym1ILgMeSLx/AFg6xvYXAH4p5Q49G1VuxioEZAUF3HTGmogdKa9rnRuM2uds4o0BC4g1puNrctETjtDbnzlnSC3UZmaxxnQU5YbsCbdmLtSmUu6Z2mYp5V4AKeVeIUTTGNtfCTyUtuw6IcRVwLvA9VLKg5l2FEIsA5YBNDc3097eXlCDQ6FQwfvmQ30l/G3dVubEdx61rn2XkvXetW097Xv0fxYoRZ8HosqP7MV31lPTveWo9Su3RHAKCKxfzc4ShIWWos89fcoc2NOvrqZ76tE/xbc2DNJYI3j7jb/p2g6VUvQ53KWMvh59/m/Mnni0COVa/wCTKijJbwxK0+dY7zB9g1GeemElE6qP/r1u3h3mRE+FufsspdT1D3gJ2JDh7zKgN23bg6McpwroRjE+6rJmwIkysvohcH8ubTrllFNkoaxcubLgffPh73/zhrz8N29mXPefT2+Ux333GRmLxUvSllL1+fQfviS//Ze1Gdct++Nqef6dpWmHlKXp80AkKmfdtEL+5IUtGddf8vPX5NX3v6N7O1RK0edAMCRn3LhCPrJ651Hr4vG4POEHz8nvPrFO93aolKLPr33UJWfcuEK+5e8+al1vf0TOuHGFvLt9m+7tUCmmz8C7MsM9VfcRiZTyE9nWCSH2CyGmSGU0MgXoGuVQnwLWSCn3pxw7+V4I8VtghRZtNgLeRjcvb96fcZ1VxBrTGW0iNhAMW8qVB4p447Qs4o3xuCQQDHP6rIYytEw/WifWZhVvtEKhtkx4PSOu6jO8R15Pq7ipyz1Hshy4OvH+auCpUbb9AmlurYTxUfksykjHEowm3ugPhkxdzCobav12meZLjsbibO8xvx85E74sE7H7Dg8yMBwzdUhoJiqcDmY0uDLmVVihUFsmpoyrobbSmTHIwCoBFeU2JLcDFwohtgIXJj4jhJgqhEhGYAkh6hLrH0/b/8dCiPVCiHXAecC3S9Ns/clWCGgoGmPXgX58FopqUfFmKQTUeXCA4Zg0/Y8tE16Pm44M4o1WCAnNhrcxs/6UFQq1ZUJNuM008rRCoTYo82S7lLIHJRIrffke4JKUz/3AUWN8KeWXdG1gGUktBHTy9JH0mh0WEmtMJ7UQUKq21IgarLVuMKBc58HhOHsODTBt4sjNxNp9drNySxfRWJyKFJFCKxRqy4bX42Jd56GjlluhUBuUf0Rik4VshYDMXgBnNLIpH1v56dznyRzqHQiGqLeIWGM6vizijVad+wPlOnce7Gdw+MiEW6soVNiGxKCohYDSfcmqT3WWBZ9Up46vpabScZQv2R+0jlhjOt4syaf+YBivRcQa0/Fm0Z/yW0isMR1vBvFGKxVqsw2JgVHK7h75pOoPhpg8rsYSYo3pqIWA0n3JylOb+X9smfC4q6mvqcg4IrHqTTU58kyZ/0vO/Vn0OmdKuE0WarPAdbYNiYHxZhBvDCSeVK2KN0MhoEC3uWs1jIYQAq/nSPFGVazRqtc5k3ijlQq1ZcLrOVq8MVmozQLX2TYkBia9EJCUUimAY4EvXjbSxRutKNaYjq/RlSzaBan1u615UwVVf2rEeFqpUFsm6qoS4o0p7jwrFWqzDYmBSR8Od4ci9FlMrDEdX9OR4o3+busGF6j4mtzsOzxIKCHeqD61WrrPHvcRIxIrFWrLhs/jxp82IrHK3J9tSAxMugqw3yJZsKORXoJWfbXqkyqM5E10JG6m/i5FrHFGg7lzC0bD6zlSvNFKhdqy4fW4CHSNJNxaqVCbbUgMTLov2YoKuOmk+5ID3WEqnYJWkydsjYaaya36zAPdYVon1lFTebSooVVIJtymfLetPAIDpc99Q1GCoSHAWoXabENicFL1pwLBEDWVDqaOt17CloqruoLJ40YKAQWCIaZPMn/C1mjMaKjDIVJvqtaeB4NU/amQJQu1ZcKbkidltbk/6/46LYKqPwXK8H9Wo9uSCVup+JpG9KesUKthLKornLROqsMfDCXFGq3eZ1W80R8MW7JQWyZGRmEhy8392YbE4KT6kgPd1g79VfEmckmUhC3rqf5mwpsou6uKNVr9OqvijYFgyDIKuGMxOSHeGAiGUyLzrHGdbUNicNTJ5017+ywr1piOKt64dlevZcUa01HFG7eqwQUWCAkdC2+jEgKcjNiy+HdbFW9U+qyINVpl7s82JAZHnYhduaWLuLSexHYm1OH+ix/uP+KzlfF53AwOx3ljW7fy2WLy8ZnwNbnZeaCfj/b3WVasMR1fkzsxIgkxwwJijSrW6IWFUX3J6k31mHhSTYxARgyJ9W+qqX2ur67A47aeWGM63kYl4fbVj4KWFWtMx9voYtfBfjbt7bOUK882JAZH9SV3dFvLpzoaqnhjR3eYBlcVE+rMn7A1Fuqoq6M7jLfJbUmxxnTU0XVHd/iYGGmD0mcpYeeBfkuNtG1DYgJU3/HkcTW4LJywpaKKN8KxYTgBGt1V1Nco1/ZYmAcD8KWMro+VPqfOA1npu11WQyKEuFwIsVEIERdCLB5lu4uFEFuEENuEEDelLJ8khHhRCLE18Tox2zHMTCxRPW/f4UGW3P4KT67dXeYW6cuTa3ezPREeuXHPYcv3F+Cp9/cka1W8tGn/MdHnlVu6UL1Zf3p7xzHR5w/3jBS3+vFzmy3T53KPSDYAnwNey7aBEMIJ/Ar4FDAP+IIQYl5i9U3Ay1LKOcDLic+W4sm1u3ltazD5eXfvADc/vt4yX8B0nly7m5sfX8/AsKJ43B+JWbq/MNLn4ZjywHB4MHrM9FmtMHywf/iY6PMPln+Y/Nwdilimz2U1JFLKTVLKLWNsdhqwTUoZkFJGgIeByxLrLgMeSLx/AFiqS0PLyB3Pb0neYFQGhmPc8fxY/2zm5I7ntzCQVkXOyv0Fu88qdp/Nixkc7i3ArpTPncDpiffNUsq9AFLKvUKIpmwHEUIsA5YBNDc3097eXlBjQqFQwfsWwu7egazLS9WOUvbZCP0Fu896Y/f5yOVm77PuhkQI8RIwOcOq70opn8rlEBmWyQzLRkVKeS9wL8DixYtlW1tbvocAoL29nUL3LYSWt1/J+AVsmVBbsnaUss9G6C/YfdYbu88pyy3QZ91dW1LKT0gpF2T4y8WIgDICaU35PA3Yk3i/XwgxBSDx2qVdy43BDRcdT22aCmxtpZMbLjq+TC3Sl2Otv2D3WcXus3kxg2trNTBHCDEL2A1cCfyPxLrlwNXA7YnXXI2TaVi6qAVQ/Kt7egeYOqGWGy46Prncahxr/QW7z3afzd/nshoSIcRngV8CHuCvQoj3pZQXCSGmAvdJKS+RUkaFENcBzwNO4H4p5cbEIW4HHhFCfAXYCVxehm7oztJFLZb4suXKsdZfsPt8rGDVPpfVkEgpnwCeyLB8D3BJyudngGcybNcDXKBnG21sbGxsRqfceSQ2NjY2NibHNiQ2NjY2NkVhGxIbGxsbm6KwDYmNjY2NTVEIKfPO7TM9QoggsKPA3RuBbg2bYwbsPh8b2H0+NiimzzOklJ70hcekISkGIcS7UsqsSsVWxO7zsYHd52MDPfpsu7ZsbGxsbIrCNiQ2NjY2NkVhG5L8ubfcDSgDdp+PDew+Hxto3md7jsTGxsbGpijsEYmNjY2NTVHYhsTGxsbGpihsQ5IHQoiLhRBbhBDbhBCWqw+fjhCiVQixUgixSQixUQjxzXK3qRQIIZxCiLVCiBXlbkspEEJMEEI8KoTYnLjWZ5a7TXojhPh24ju9QQjxkBCiptxt0hohxP1CiC4hxIaUZZOEEC8KIbYmXidqcS7bkOSIEMIJ/Ar4FDAP+IIQYl55W6U7UeB6KeXHgDOArx8DfQb4JrCp3I0oIT8HnpNSzgVOxOJ9F0K0AN8AFkspF6CUp7iyvK3ShT8AF6ctuwl4WUo5B3g58blobEOSO6cB26SUASllBHgYuKzMbdIVKeVeKeWaxPs+lBuM9YoppCCEmAZ8Griv3G0pBUKIccA5wO8ApJQRKWVvWRtVGiqAWiFEBVDHSNVVyyClfA04kLb4MuCBxPsHgKVanMs2JLnTAuxK+dyJxW+qqQghZgKLgHfK3BS9+Rnwr0C8zO0oFV4gCPw+4c67TwjhKnej9ERKuRu4E6UY3l7gkJTyhfK2qmQ0Syn3gvKgCDRpcVDbkOSOyLDsmIidFkK4gceAb0kpD5e7PXohhPg7oEtK+V6521JCKoCTgd9IKRcBYTRydxiVxLzAZcAsYCrgEkL8z/K2ytzYhiR3OoHWlM/TsOBwOB0hRCWKEXlQSvl4udujM0uAzwghtqO4Ls8XQvx3eZukO51Ap5RSHWk+imJYrMwngA4pZVBKOQw8DpxV5jaViv1CiCkAidcuLQ5qG5LcWQ3MEULMEkJUoUzOLS9zm3RFCCFQfOebpJQ/LXd79EZKebOUcpqUcibK9X1FSmnpJ1Up5T5glxDi+MSiC4APy9ikUrATOEMIUZf4jl+AxQMMUlgOXJ14fzXwlBYHLWvNdjMhpYwKIa4DnkeJ8rhfSrmxzM3SmyXAl4D1Qoj3E8v+TUr5TPmaZKMD/wI8mHhACgDXlLk9uiKlfEcI8SiwBiUycS0WlEoRQjwEtAGNQohO4AfA7cAjQoivoBjUyzU5ly2RYmNjY2NTDLZry8bGxsamKGxDYmNjY2NTFLYhsbGxsbEpCtuQ2NjY2NgUhW1IbGxsbGyKwjYkNjY2NjZFYRsSGxsbG5uisA2JjY1BEEJME0L8Q7nbYWOTL7YhsbExDhdgfZ0rGwtiZ7bb2BgAIcTZKLpHvUAf8FkpZUdZG2VjkyO2IbGxMQhCiOeA/y2l3DDmxjY2BsJ2bdnYGIfjgS3lboSNTb7YhsTGxgAIIRpQKvUNl7stNjb5YhsSGxtjMItjoFCajTWxDYmNjTHYjFI3YoMQ4lip1mdjEezJdhsbGxuborBHJDY2NjY2RWEbEhsbGxuborANiY2NjY1NUdiGxMbGxsamKGxDYmNjY2NTFLYhsbGxsbEpCtuQ2NjY2NgUxf8Hvd6EKpH5nUEAAAAASUVORK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "l = -2\n", "f = lambda t,x : l*x\n", "y0 = 1; tspan=[0, 10]\n", "h = 1.1; Nh = np.ceil((tspan[1] - tspan[0])/h).astype(int)\n", "t_EP, y_EP = forwardEuler(f, tspan, y0, Nh)\n", "t_ER, y_ER = backwardEuler(f, tspan, y0, Nh)\n", "\n", "plt.plot(t_EP, y_EP,'o-')\n", "plt.plot(t_ER, y_ER,'o-')\n", "\n", "y = lambda t : np.exp(l*t)\n", "t = np.linspace(tspan[0],tspan[1],100)\n", "plt.plot(t, y(t),'-')\n", "# labels, title, legend\n", "plt.xlabel('$t$'); plt.ylabel('$y$')\n", "plt.legend(['EP','ER','$y(t)$'])\n", "plt.grid(True)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Convergence\n", "\n", "On considère le problème de Cauchy\n", "$$\\begin{cases}\n", " y'(t) = - y(0.1-\\cos(t)), \\quad t>0 \\\\\n", " y(0) = 1\n", "\\end{cases}$$\n", "\n", "Resolvez ce problème par les méthodes d'Euler progressive et de\n", "Heun sur l'intervalle $[0,12]$ avec\n", "un pas de temps $h=0.4$.\n", "\n", "La solution exacte est $y(t) = e^{-0.1t +\\sin(t)}$. \n", "On remarque que la solution obtenue par la méthode de\n", "Heun est beaucoup plus précise que celle d'Euler progressive.\n", "Par ailleurs, on peut voir que si on réduit le pas de temps, la solution obtenue par la\n", "méthode d'Euler progressive s'approche de la solution exacte." ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Figure: Approximation par le méthodes de Euler Retrograde et Heun.\n" - ] - } - ], + "outputs": [], "source": [ "f = lambda t,y : (np.cos(t) - 0.1)*y\n", "\n", "tspan = [0,12]; y0 = 1;\n", "h = 0.4; Nh = np.ceil((tspan[1] - tspan[0])/h).astype(int)\n", "Nh = np.ceil(12/h).astype(int)\n", "\n", "t_EP, y_EP = forwardEuler(f, tspan, y0, Nh)\n", "t_H, y_H = Heun(f, tspan, y0, Nh)\n", "\n", "plt.plot(t_EP, y_EP,'o-')\n", "plt.plot(t_H, y_H,'o-')\n", "\n", "y = lambda t : np.exp(-0.1*t+np.sin(t))\n", "t = np.linspace(tspan[0],tspan[1],100)\n", "plt.plot(t, y(t),'-')\n", "# labels, title, legend\n", "plt.xlabel('$t$'); plt.ylabel('$y$')\n", "plt.legend(['EP','Heun','$y(t)$'])\n", "plt.grid(True)\n", "plt.show()\n", "print(\"Figure: Approximation par le méthodes de Euler Retrograde et Heun.\")" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Figure: Solutions obtenues par la méthode d'Euler progressive pour différents pas de temps.\n" - ] - } - ], + "outputs": [], "source": [ "tspan = [0,12]; y0 = 1;\n", "NhRange = [30, 50, 100, 500]\n", "for Nh in NhRange :\n", " t, y = forwardEuler(f,tspan,y0,Nh)\n", " plt.plot(t, y,'-')\n", "\n", "yt = lambda t : np.exp(-0.1*t+np.sin(t))\n", "t = np.linspace(tspan[0],tspan[1],100)\n", "plt.plot(t, yt(t),':')\n", "# labels, title, legend\n", "plt.xlabel('$t_n$'); plt.ylabel('$u_n$')\n", "plt.legend(NhRange+['$y(t)$'])\n", "plt.title('$u_n\\\\approx u(t_n)$')\n", "plt.grid(True)\n", "plt.show()\n", "print(\"Figure: Solutions obtenues par la méthode d'Euler progressive pour différents pas de temps.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On veut, maintenant, estimer l'ordre de convergence de ces deux\n", "méthodes. Pour cela, on résout le problème avec\n", "différents pas de temps et on compare les résultats obtenus à\n", "l'instant $t=6$ avec la solution exacte." ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Figure: Erreurs en échelle logarithmique commises par les méthodes d'Euler progressive et de Heun dans le calcul de y(6).\n" - ] - } - ], + "outputs": [], "source": [ "tspan=[0,6]\n", "NhRange = [30, 50, 100, 500]\n", "errEP = []\n", "errH = []\n", "# Solution at end time\n", "y6 = yt(tspan[1])\n", "for Nh in NhRange :\n", " # Forward Euler\n", " t, y = backwardEuler(f,tspan,y0,Nh)\n", " # Error at the end of the simulation\n", " errEP.append( np.abs(y6 - y[-1] ) )\n", " \n", " # Heun\n", " [t, y] = Heun(f, tspan, y0, Nh);\n", " # Error at the end of the simulation\n", " errH.append( np.abs(y6 - y[-1] ) )\n", "\n", - "h = 1./np.array(NhRange)\n", + "h = (tspan[1] - tspan[0])/np.array(NhRange)\n", "plt.loglog(h,errEP,'o-b',h,errH,'o-r')\n", "plt.loglog(h,h*(errEP[0]/h[0]),':',h,(h**2*(errH[0]/h[0]**2)),':')\n", "plt.xlabel('$h$'); plt.ylabel('$|y(6)-u_{N_h}|$')\n", "plt.legend(['EP','Heun','$h$','$h^2$'])\n", "plt.title('Decay of the error')\n", "plt.grid(True)\n", "plt.show()\n", "\n", "print(\"Figure: Erreurs en échelle logarithmique commises par les méthodes\" +\n", " \" d'Euler progressive et de Heun dans le calcul de y(6).\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "La figure montre, en échelle logarithmique, les erreurs\n", "commises par les deux méthodes en fonction de $h$.\n", "On voit bien que la\n", "méthode d'Euler progressive converge à l'ordre 1 tandis que celle de\n", "Heun à l'ordre 2.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "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.7.7" } }, "nbformat": 4, "nbformat_minor": 4 }