diff options
| author | martial.simon <martial.simon@epita.fr> | 2025-04-13 19:54:19 +0200 |
|---|---|---|
| committer | martial.simon <martial.simon@epita.fr> | 2025-04-13 19:54:19 +0200 |
| commit | 66c3bbfa94d8a41e58adf154be25e6d86fee8e30 (patch) | |
| tree | 9c5e998f324f2f60c1717759144da3f996c5ae1a /PVCM/cama/en/ma32 Conditionnement d'une matrice.ipynb | |
init: initial commit
Diffstat (limited to 'PVCM/cama/en/ma32 Conditionnement d'une matrice.ipynb')
| -rw-r--r-- | PVCM/cama/en/ma32 Conditionnement d'une matrice.ipynb | 589 |
1 files changed, 589 insertions, 0 deletions
diff --git a/PVCM/cama/en/ma32 Conditionnement d'une matrice.ipynb b/PVCM/cama/en/ma32 Conditionnement d'une matrice.ipynb new file mode 100644 index 0000000..9ff805a --- /dev/null +++ b/PVCM/cama/en/ma32 Conditionnement d'une matrice.ipynb @@ -0,0 +1,589 @@ +{ + "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.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 2, + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import numpy.linalg as lin\n", + "\n", + "np.set_printoptions(precision=3, linewidth=150, suppress=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conditionnement d'une matrice\n", + "\n", + "Soit la matrice A suivante :" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[10, 7, 8, 7],\n", + " [ 7, 5, 6, 5],\n", + " [ 8, 6, 10, 9],\n", + " [ 7, 5, 9, 10]])" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A = np.array([[10, 7, 8, 7], [7, 5, 6, 5], [8, 6, 10, 9], [7, 5, 9, 10]])\n", + "A" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Une matrice symétrique qui n'a rien de méchant a priori. Son déterminant est 1." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.9999999999999869" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lin.det(A)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Construisons **b** de telle sorte que la solution du système matriciel A **x** = **b** soit [1,1,1,1] :" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[32 23 33 31]\n" + ] + }, + { + "data": { + "text/plain": [ + "array([1., 1., 1., 1.])" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b = A.sum(axis=1)\n", + "print(b)\n", + "x = lin.solve(A, b)\n", + "x" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Perturbons légèrement **b**. Dans le cas d'une expérience cela s'appelle une erreur de mesure. En informatique\n", + "cela peut être le résultat d'erreurs d'arrondi." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.0033319453118976702" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bp = [32.1, 22.9, 33.1, 30.9]\n", + "eb = lin.norm(b - bp) / lin.norm(b) # une erreur se mesure par rapport à la valeur de la donnée\n", + "eb" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On a une erreur sur **b** de l'ordre de 0,3 %. On la note $ ||{\\bf \\delta b}|| \\, / \\,||{\\bf b}||$.\n", + "\n", + "On pourrait espérer une erreur sur le résultat du même ordre de\n", + "grandeur.\n", + "Regardons la solution **x** de notre système matriciel perturbé :" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 9.2, -12.6, 4.5, -1.1])" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "xp = lin.solve(A, bp)\n", + "xp" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Cette solution n'a rien à voir avec [1, 1, 1, 1]." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "8.19847546803699" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ex = lin.norm(x - xp) / lin.norm(x)\n", + "ex" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "L'erreur est de l'ordre de 8 pour 1.\n", + "\n", + "L'erreur est 2460 fois plus grande que l'erreur sur **b**." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2460.567236431514" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ex / eb" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Pourquoi ?\n", + "\n", + "On a \n", + "\n", + "$$\n", + "\\begin{align}\n", + "& A ({\\bf x} + {\\bf \\delta x}) = {\\bf b} + {\\bf \\delta b} \\quad \\textrm{et donc} \\\\\n", + "& A \\, {\\bf \\delta x} = {\\bf \\delta b} \\; \\textrm{ puisque } A {\\bf x} = {\\bf b} \\quad \\textrm{et finalement}\\\\\n", + "& {\\bf \\delta x} = A^{-1} \\, {\\bf \\delta b}\n", + "\\end{align}\n", + "$$\n", + "\n", + "Comme A et son inverse sont des applications linéaires on a\n", + "\n", + "$$\n", + "\\begin{align}\n", + "& ||{\\bf b}|| \\le ||A|| \\, ||{\\bf x}||\n", + "\\quad \\textrm{et} \\quad ||{\\bf \\delta x}|| \\le ||A^{-1}|| \\, ||{\\bf \\delta b}||\n", + "\\end{align}\n", + "$$\n", + "\n", + "donc \n", + "\n", + "$$\n", + "\\begin{align}\n", + "\\frac{||{\\bf \\delta x}||}{||{\\bf x}||} \\le ||A^{-1}|| \\, \\frac{||{\\bf \\delta b}||}{||{\\bf x}||}\n", + "\\le ||A^{-1}|| \\, ||A|| \\, \\frac{||{\\bf \\delta b}||}{||{\\bf b}||}\n", + "\\end{align}\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3009.5787080586942" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lin.norm(lin.inv(A)) * lin.norm(A)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Le problème est là.\n", + "\n", + "On appelle cela le conditionnement de A :\n", + " \n", + "cond(A) = $||A^{-1}|| \\, ||A||$\n", + "\n", + "**Une matrice mal conditionnée va générer des erreurs de calcul lors de la résolution du système matriciel.**" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2984.0927016757555" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.linalg.cond(A) # scipy n'a pas le conditionnement mais numpy l'a. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Bizarre cette différence avec le calul ci-dessus qui a donné 3009." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Perturbons la matrice\n", + "\n", + "Que ce passe-t-il si on perturbe A et non b ?" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 0.098, 0.43 , 0.206, 0.09 ],\n", + " [-0.153, 0.292, -0.125, 0.784],\n", + " [ 0.927, -0.233, 0.583, 0.058],\n", + " [ 0.136, 0.851, -0.858, -0.826]])" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Erreur relative sur A : 0.06868857112100454\n" + ] + } + ], + "source": [ + "np.random.seed(0)\n", + "\n", + "dA = 2 * np.random.random(size = A.shape) - 1\n", + "display(dA)\n", + "ea = lin.norm(dA) / lin.norm(A)\n", + "print('Erreur relative sur A :', ea)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[10.098, 7.43 , 8.206, 7.09 ],\n", + " [ 6.847, 5.292, 5.875, 5.784],\n", + " [ 8.927, 5.767, 10.583, 9.058],\n", + " [ 7.136, 5.851, 8.142, 9.174]])" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Ap = A + dA\n", + "Ap" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([-12.365, 15.574, 10.146, -5.94 ])" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "xp = lin.solve(Ap, b)\n", + "xp" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "11.432687335993894" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ex = lin.norm(xp - x) / lin.norm(x)\n", + "ex" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "166.44235204505293" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ex / ea" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On note que l'erreur est nettement moins grande. La raison est qu'on n'a pas trouvé l'erreur sur A qui\n", + "perturbera le plus possible le résultat. En fait ce n'est pas que le conditionnement de A qui compte,\n", + "l'erreur est aussi importante. Deux erreurs de même norme pertuberont différemment le résultat.\n", + "\n", + "\n", + "Notons aussi que dans ce cas les maths sont un peu différente mais on retrouve le conditionnement de A :\n", + "\n", + "$$\n", + "\\begin{align}\n", + "& (A + \\Delta A) \\, ({\\bf x} + {\\bf \\delta x}) = {\\bf b} \\quad \\textrm{et donc} \\\\\n", + "& A \\, {\\bf \\delta x} + \\Delta A \\, ({\\bf x} + {\\bf \\delta x}) = 0 \\; \\textrm{ puisque } A {\\bf x} = {\\bf b} \\quad \\textrm{et finalement}\\\\\n", + "& {\\bf \\delta x} = -A^{-1} \\,\\Delta A \\, ({\\bf x} + {\\bf \\delta x}) \\quad \\textrm{et} \\\\\n", + "& ||{\\bf \\delta x}|| \\le ||A^{-1}|| \\, ||\\Delta A|| \\, ||{\\bf x} + {\\bf \\delta x}||\n", + "\\end{align}\n", + "$$\n", + "\n", + "Ainsi\n", + "\n", + "$$\n", + "\\begin{align}\n", + "\\frac{||{\\bf \\delta x}||}{||{\\bf x} + {\\bf \\delta x}||} \n", + "\\le ||A^{-1}|| \\, ||\\Delta A|| = ||A^{-1}|| \\, ||A|| \\, \\frac{||\\Delta A||}{||A||}\n", + "\\end{align}\n", + "$$\n", + "\n", + "ou\n", + "\n", + "$$\n", + "\\begin{align}\n", + "\\frac{||{\\bf \\delta x}||}{||{\\bf x} + {\\bf \\delta x}||} \n", + "\\le cond(A) \\, \\frac{||\\Delta A||}{||A||}\n", + "\\end{align}\n", + "$$\n", + "\n", + "L'erreur ne se mesure pas par rapport à **x** mais par rapport à ${\\bf x} + {\\bf \\delta x}$." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Propriétés\n", + "\n", + "* $cond(A) \\ge 1$ car $Id = A\\, A^{-1}$ et donc $1 \\le ||A||\\, ||A^{-1}||$ (pour les normes subordonnées car $||Id||_F = \\sqrt{n}$)\n", + "* $cond(A) = cond(A^{-1})$ par définition du conditionnement\n", + "* $\\displaystyle cond_2(A) = \\frac{\\max_i |\\lambda_i|}{\\min_i |\\lambda_i|}$ si la matrice est normale \n", + " où le 2 indique qu'on utilise la norme 2 et $\\lambda_i$ sont les valeurs propres de A" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(2984.092701676269+0j)" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vp = lin.eigvals(A)\n", + "vp.max() / vp.min() # et voici la différence avec le calcul ||A|| ||inv(A)|| ci-dessus\n", + " # ca sent l'erreur numérique" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* si A est unitaire ou orthogonale alors $cond_2(A) = 1$ (une rotation ou symétrie ne va pas agrandir l'erreur)\n", + "* le conditionnement n'est pas modifié par transformation unitaire " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Préconditionnement\n", + "\n", + "Si le conditionnement n'est pas modifié par une transformation unitaire, il l'est par d'autres transformations.\n", + "Ainsi\n", + "\n", + "$$\n", + "\\forall A, \\exists B \\; \\textrm{appelée matrice de préconditionnement t.q.} \\quad cond(B\\, A) \\le cond(A)\n", + "$$\n", + "\n", + "aussi on lieu de résoudre $A {\\bf x} = {\\bf b}$ on résoud $B\\, A {\\bf x} = B\\, {\\bf b}$\n", + "\n", + "Toute la difficulté consiste à trouver une matrice de préconditionnement B qui soit simple à calculer.\n", + "\n", + "#### Exercice 11.1\n", + "\n", + "Quelle est la meilleure matrice de préconditionnement de A ? Pourquoi ?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ] +}
\ No newline at end of file |
