diff --git "a/Chapitre 10 - Matrices orthogonales, matrices sym\303\251triques/10.1 Matrices et transformations orthogonales.ipynb" "b/Chapitre 10 - Matrices orthogonales, matrices sym\303\251triques/10.1 Matrices et transformations orthogonales.ipynb" new file mode 100644 index 0000000..0db067d --- /dev/null +++ "b/Chapitre 10 - Matrices orthogonales, matrices sym\303\251triques/10.1 Matrices et transformations orthogonales.ipynb" @@ -0,0 +1,149 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import sympy as sp\n", + "from IPython.display import display, Latex, Markdown\n", + "import plotly\n", + "import plotly.graph_objects as go\n", + "import sys, os\n", + "sys.path.append('../Chapitre 8 - Valeurs propres, vecteurs propres, diagonalisation')\n", + "from Ch8_lib import *\n", + "sys.path.append('../Librairie')\n", + "import AL_Fct as al\n", + "from Ch10_lib import *" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### DÉFINITION 1:\n", + "Soient $V$ un espace euclidien et $T: V \\rightarrow V$ une application linéaire. On dit que $T$ est orthogonale si $\\|T(v)\\|=\\|v\\|$ pour tout $v \\in V$\n", + "\n", + "### DÉFINITION 2:\n", + "Soient $V=\\mathbb{R}^{n}$ muni du produit scalaire usuel et $A \\in M_{n \\times n}(\\mathbb{R})$ une matrice de taille $n \\times n$ à coefficients réels. On dit que $A$ est orthogonale si $\\|A X\\|=\\|X\\|$ pour tout $X \\in M_{n \\times 1}(\\mathbb{R})$\n", + "\n", + "### CONSTAT 3:\n", + "Soit $T: V \\rightarrow V$ une transformation orthogonale d'un espace euclidien $V$. Alors $T$ est injective (et donc bijective par le théorème du rang)\n", + "\n", + "### PROPOSITION 4:\n", + "Soient $V$ un espace euclidien et $T: V \\rightarrow V$ une application linéaire orthogonale. Soient également $u, v \\in V$ et désignons par $\\theta$ (respectivement $\\gamma$) l'angle entre les deux vecteurs $u, v$ (respectivement, l'angle entre les deux vecteurs $T(u)$ et $T(v)$ ). Alors $\\theta=\\gamma$, i.e. $T$ préserve les angles." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercice 1:\n", + "En utilisant la définition 1 donnée ci-dessus, determinez si les matrices suivantes sont orthogonales.\n", + "\n", + "*La fonction `is_orthogonal(A)` donne la reponse détaillée pour la matrice `A` donnée en argument.*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "A1 = sp.Matrix([[1/2 , - sp.sqrt(3)/2], [sp.sqrt(3)/2, 1/2]])\n", + "A2 = sp.Matrix([[1, -1], [0, 1]])\n", + "A3 = sp.Matrix([[sp.sqrt(2)/2, -sp.sqrt(2)/2], [sp.sqrt(2)/2, sp.sqrt(2)/2]])\n", + "A4 = sp.Matrix([[sp.sqrt(2)/2, sp.sqrt(2)/2], [sp.sqrt(2)/2, sp.sqrt(2)/2]])\n", + "A5 = sp.Matrix([[0, 0, -1], [0, 1, 0], [-1, 0, 0]])\n", + "A6 = sp.Matrix([[1, -7, -1, 4], [0, 0, 1, -3], [0, 0, 1, -2], [0, 0, 0, -1]])\n", + "\n", + "A = A1\n", + "display(Latex(\"$ A = \" + latexp(A) + \"$\"))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "is_orthogonal(A)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exemple 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sp_tri, ep_tri = points_on_circle(3, [3,1])\n", + "sp_sq, ep_sq = points_on_circle(4)\n", + "sp_pent, ep_pent = points_on_circle(5)\n", + "sp_cir, ep_cir = points_on_circle(50)\n", + "\n", + "A1 = np.array([[np.sqrt(2)/2, -np.sqrt(2)/2], [np.sqrt(2)/2, np.sqrt(2)/2]])\n", + "A2= np.array([[1, 1],[-1, 2]])\n", + "A3 = np.array([[3, 0],[0, 2]])\n", + "\n", + "plot_geom_2D(sp_pent, ep_pent, A1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plot_geom_2D(sp_sq, ep_sq, A2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plot_geom_2D(sp_tri, ep_tri, A3)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plot_geom_2D(sp_cir, ep_cir, A3)" + ] + } + ], + "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.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git "a/Chapitre 10 - Matrices orthogonales, matrices sym\303\251triques/10.2 Matrices orthogonales, \303\251quivalences.ipynb" "b/Chapitre 10 - Matrices orthogonales, matrices sym\303\251triques/10.2 Matrices orthogonales, \303\251quivalences.ipynb" new file mode 100644 index 0000000..5cf4c15 --- /dev/null +++ "b/Chapitre 10 - Matrices orthogonales, matrices sym\303\251triques/10.2 Matrices orthogonales, \303\251quivalences.ipynb" @@ -0,0 +1,46 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### PROPOSITION:\n", + "Soient $V=\\mathbb{R}^{n}$ muni du produit scalaire usuel et $A \\in M_{n \\times n}(\\mathbb{R})$ une matrice de taille $n \\times n$ à coefficients réels. Alors les conditions suivantes sont équivalentes.\n", + "1. $\\|A X\\|=\\|X\\|$ pour tout $X \\in M_{n \\times 1}(\\mathbb{R})$\n", + "2. $\\langle A X, A Y\\rangle=\\langle X, Y\\rangle$ pour tous $X, Y \\in M_{n \\times 1}(\\mathbb{R})$\n", + "3. $A A^{T}=I_{n}=A^{T} A$\n", + "4. Les lignes de $A$ forment une base orthonormée de $V$\n", + "5. Les colonnes de $A$ (vues comme vecteurs de $\\mathbb{R}^{n}$ ) forment une base orthonormée de $V$.\n", + "Aussi, si $A$ est orthogonale, alors det $A=\\pm 1$" + ] + }, + { + "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.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git "a/Chapitre 10 - Matrices orthogonales, matrices sym\303\251triques/Ch10_lib.py" "b/Chapitre 10 - Matrices orthogonales, matrices sym\303\251triques/Ch10_lib.py" new file mode 100644 index 0000000..4065260 --- /dev/null +++ "b/Chapitre 10 - Matrices orthogonales, matrices sym\303\251triques/Ch10_lib.py" @@ -0,0 +1,118 @@ +import sys, os +import numpy as np +import sympy as sp +from IPython.display import display, Latex, Markdown +import plotly +import plotly.graph_objects as go +sys.path.append('../Chapitre 8 - Valeurs propres, vecteurs propres, diagonalisation') +from Ch8_lib import * +sys.path.append('../Librairie') +import AL_Fct as al + + +def points_on_circle(n, center=np.array([0, 0])): + theta = 2 * np.pi / n + + s_pts = np.zeros((n, 2)) + e_pts = np.zeros((n, 2)) + + for i in range(n): + s_pts[i] = [np.cos(i * theta) + center[0], np.sin(i * theta) + center[1]] + e_pts[i] = [np.cos((i + 1) * theta) + center[0], np.sin((i + 1) * theta) + center[1]] + + return np.array(s_pts), np.array(e_pts) + + +def plot_geom_2D(s_pts, e_pts, A): + n = len(s_pts) + + if n != len(e_pts): + raise ValueError("start_points and end_points must have same length.") + + layout = go.Layout(yaxis=dict(scaleanchor="x", scaleratio=1)) + + display(Latex("On montre la transformation provoquée par la multiplication par la matrice $A = " + + al.texMatrix(A) + "$ sur une figure géométrique.")) + + fig = go.Figure(layout=layout) + + color = ['black', 'red', 'blue', 'green', 'yellow', 'brown', 'grey', 'cyan', 'orange', 'violet'] + + n_col = len(color) + + if n > n_col: + color = ['blue'] + n_col = 1 + + for i in range(n): + a = np.array(s_pts[i]) + b = np.array(e_pts[i]) + + a2 = A @ a + b2 = A @ b + + if i == 0: + show_legend = True + else: + show_legend = False + + fig.add_trace(go.Scatter(x=[a[0], b[0]], y=[a[1], b[1]], + line=dict(color=color[i % n_col], width=2), + mode='lines+markers', showlegend=show_legend, name='Original Figure')) + + fig.add_trace(go.Scatter(x=[a2[0], b2[0]], y=[a2[1], b2[1]], + line=dict(color=color[i % n_col], width=2, dash='dot'), + mode='lines+markers', showlegend=show_legend, name='Modified Figure')) + + fig.show() + + +def is_orthogonal(A): + if not isinstance(A, sp.Matrix): + raise ValueError("A should be a sympy matrix") + + n = A.shape[0] + if n != A.shape[1]: + raise ValueError("A should be a square matrix") + + display(Latex("On cherche à savoir si la matrice $A = " + latexp(A) + "$ est orthogonale en utilisant la " + + "définition 1.")) + + if A.is_lower or A.is_upper: + for i in range(n): + if A[i, i] != 1 and A[i, i] != -1: + display(Latex("Les valeurs propres de $A$ sont ses éléments diagonaux. Une des valeurs propres de " + + "$A$ est différente de 1 ou -1. Il existe donc un vecteur propres $v$ de $A$ tel " + + " que $A v = \lambda v$ avec $\lambda \\neq \pm 1$. Donc dans ce cas on a $\|A v\| " + + "\\neq \|v\| $." + )) + return + + v = sp.zeros(n, 1) + for i in range(n): + symb_name = "x_" + str(i + 1) + v[i] = sp.symbols(symb_name, real=True) + + b = A * v + b_norm = b.norm() ** 2 + v_norm = v.norm() ** 2 + + display(Latex("Il faut vérifier si $\|A v\| = \|v\|$ pour tout $v \in \mathbb{R}^" + str(n) + "$." + + " On utilise le carré des normes pour s'affranchir des racines carrées.")) + display(Latex("On calcule d'abord la norme au carré de $v$ et on obtient: $\|v\|^2 = " + sp.latex(v_norm) + + "$.")) + display(Latex("On calcule ensuite le produit $Av = " + latexp(b) + "$")) + + if sp.simplify(b_norm) != b_norm: + display(Latex("On calcule la norme au carré de $Av$ et on obtient: $\|Av\|^2 = " + sp.latex(b_norm) + + "=" + sp.latex(sp.simplify(b_norm)) + "$")) + else: + display(Latex("On calcule la norme au carré de $Av$ et on obtient: $\|Av\|^2 = " + sp.latex(b_norm) + + "$")) + + if sp.simplify(b_norm - v_norm) == 0: + display(Latex("Les normes sont toujours égales. La matrice est donc orthogonale.")) + else: + display(Latex("Les normes sont différente. La matrice n'est donc pas orthogonale.")) + + diff --git "a/Chapitre 8 - Valeurs propres, vecteurs propres, diagonalisation/8.8 Crit\303\250re de diagonalisabilit\303\251.ipynb" "b/Chapitre 8 - Valeurs propres, vecteurs propres, diagonalisation/8.8 Crit\303\250re de diagonalisabilit\303\251.ipynb" index 11f258e..7a05c9c 100644 --- "a/Chapitre 8 - Valeurs propres, vecteurs propres, diagonalisation/8.8 Crit\303\250re de diagonalisabilit\303\251.ipynb" +++ "b/Chapitre 8 - Valeurs propres, vecteurs propres, diagonalisation/8.8 Crit\303\250re de diagonalisabilit\303\251.ipynb" @@ -1,1689 +1,196 @@ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "### Théorème\n", "Soit $\\phi: V \\rightarrow V$ une transformation linéaire d'un $\\mathbb{R}$-espace vectoriel $V$ de dimension finie $n \\in \\mathbb{N}$. Alors $\\phi$ est diagonalisable si et seulement si il existe $a \\in \\mathbb{R}, \\lambda_{1}, \\ldots, \\lambda_{r} \\in \\mathbb{R}$ distincts et $m_{1}, \\ldots, m_{r} \\in \\mathbb{N}$ tels que\n", "$$c_{\\phi}(t)=a\\left(t-\\lambda_{1}\\right)^{m_{1}} \\ldots\\left(t-\\lambda_{r}\\right)^{m_{r}}$$\n", "et $m_{i}=\\operatorname{dim} E_{\\lambda_{i}}$ pour tout $1 \\leq i \\leq n$\n", "\n", "### Critère equivalent de diagonalisabilité\n", "Une matrice $A$ $n \\times n$ est diagonalisable si et seulement si A possède $n$ vecteurs propres linéairement indépendant." ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - " \n", - " " - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "import sys, os\n", "sys.path.append('../Librairie')\n", "import AL_Fct as al\n", "import numpy as np\n", "import sympy as sp\n", "from IPython.utils import io\n", "from IPython.display import display, Latex, Markdown\n", "import plotly\n", "import plotly.graph_objects as go\n", "from Ch8_lib import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercice 1\n", "À l'aide de la représentation graphique des espaces propres associés aux différentes valeurs propres d'une matrice, determinez si cette dernière est diagonalisable. (Aucun long calcul requis).\n", "\n", "**Si besoin, la méthode à appliquer est donnée plus bas.**" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.plotly.v1+json": { - "config": { - "linkText": "Export to plot.ly", - "plotlyServerURL": "https://plot.ly", - "showLink": false - }, - "data": [ - { - "marker": { - "size": 6 - }, - "mode": "lines+markers", - "name": "$\\lambda = 7$", - "type": "scatter", - "x": [ - -5, - -4.5, - -4, - -3.5, - -3, - -2.5, - -2, - -1.5, - -1, - -0.5, - 0, - 0.5, - 1, - 1.5, - 2, - 2.5, - 3, - 3.5, - 4, - 4.5, - 5 - ], - "y": [ - -10, - -9, - -8, - -7, - -6, - -5, - -4, - -3, - -2, - -1, - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10 - ] - }, - { - "marker": { - "size": 6 - }, - "mode": "lines+markers", - "name": "$\\lambda = -1$", - "type": "scatter", - "x": [ - 15, - 13.5, - 12, - 10.5, - 9, - 7.5, - 6, - 4.5, - 3, - 1.5, - 0, - -1.5, - -3, - -4.5, - -6, - -7.5, - -9, - -10.5, - -12, - -13.5, - -15 - ], - "y": [ - -10, - -9, - -8, - -7, - -6, - -5, - -4, - -3, - -2, - -1, - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10 - ] - } - ], - "layout": { - "autosize": true, - "showlegend": true, - "template": { - "data": { - "bar": [ - { - "error_x": { - "color": "#2a3f5f" - }, - "error_y": { - "color": "#2a3f5f" - }, - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - } - }, - "type": "bar" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - } - }, - "type": "barpolar" - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "baxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "type": "carpet" - } - ], - "choropleth": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "choropleth" - } - ], - "contour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "contour" - } - ], - "contourcarpet": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "contourcarpet" - } - ], - "heatmap": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "heatmap" - } - ], - "heatmapgl": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "heatmapgl" - } - ], - "histogram": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "histogram" - } - ], - "histogram2d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2d" - } - ], - "histogram2dcontour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2dcontour" - } - ], - "mesh3d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "mesh3d" - } - ], - "parcoords": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "parcoords" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ], - "scatter": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter" - } - ], - "scatter3d": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter3d" - } - ], - "scattercarpet": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattercarpet" - } - ], - "scattergeo": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergeo" - } - ], - "scattergl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergl" - } - ], - "scattermapbox": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermapbox" - } - ], - "scatterpolar": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolar" - } - ], - "scatterpolargl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolargl" - } - ], - "scatterternary": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterternary" - } - ], - "surface": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "surface" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#EBF0F8" - }, - "line": { - "color": "white" - } - }, - "header": { - "fill": { - "color": "#C8D4E3" - }, - "line": { - "color": "white" - } - }, - "type": "table" - } - ] - }, - "layout": { - "annotationdefaults": { - "arrowcolor": "#2a3f5f", - "arrowhead": 0, - "arrowwidth": 1 - }, - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ], - "sequential": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ] - }, - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#2a3f5f" - }, - "geo": { - "bgcolor": "white", - "lakecolor": "white", - "landcolor": "#E5ECF6", - "showlakes": true, - "showland": true, - "subunitcolor": "white" - }, - "hoverlabel": { - "align": "left" - }, - "hovermode": "closest", - "mapbox": { - "style": "light" - }, - "paper_bgcolor": "white", - "plot_bgcolor": "#E5ECF6", - "polar": { - "angularaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "radialaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "scene": { - "xaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "yaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "zaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - } - }, - "shapedefaults": { - "line": { - "color": "#2a3f5f" - } - }, - "ternary": { - "aaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "baxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "caxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "title": { - "x": 0.05 - }, - "xaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - }, - "yaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - } - } - } - } - }, - "text/html": [ - "
\n", - " \n", - " \n", - "
\n", - " \n", - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "A1 = sp.Matrix([[3, 4], [0, 3]])\n", "A2 = sp.Matrix([[1, 3], [4,5]])\n", "A3 = sp.Matrix([[5, 0, 0],[0, 1, 0], [1, 0, 1]])\n", "A4 = sp.Matrix([[1, 0, -2],[2 ,1, 0], [0, 0, 3]])\n", "\n", "# Choisir matrice (A = A1 ou A = A2 ...)\n", "A = A1\n", "\n", "# La fonction plot_eigspace affiche l'espace propre associé a chaque valeurs propre de la matrice A.\n", "plot_eigspace(A)\n" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "Oui la matrice $A = \\left(\\begin{matrix}1 & 3\\\\4 & 5\\end{matrix}\\right)$ est diagonalisable." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "Votre réponse est correcte !" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# Votre réponse a : La matrice A est-elle diagonlisable ? (True pour oui, False pour non)\n", "my_answer = True\n", "\n", "ch8_8_ex_1(A, my_answer)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Méthode exercice 1 (en utilisant le théorème donné dans le MOOC)\n", "On sait que le polynôme caractéristique d'une matrice $A (n \\times n)$ est d'ordre $n$. \n", "\n", "Avec $c_A(t)=a(t-\\lambda_{1})^{m_{1}} \\ldots (t-\\lambda_{r})^{m_{r}}$, avec $a \\in \\mathbb{R}$, $r\\leq n$ et $\\lambda_{1}, \\ldots, \\lambda_{r} \\in \\mathbb{R}$ distincts, on peut en déduire que $\\sum_{i=1}^r m_i = n$\n", "\n", "Sachant également que $\\dim E_{\\lambda_i} \\leq m_i$, on a $m_i = \\dim E_{\\lambda_i} $ pour tout $ i = 1, .., r$ si et seulement si $\\sum_{i=1}^r \\dim E_{\\lambda_i} = n$ \n", "\n", "Le théorème donné plus haut indique qu'une matrice est diagonalisable si et seulement si $m_i = \\dim E_{\\lambda_i}$ pour tout $ i = 1, .., r$. \n", "\n", "On vient de montrer que c'est équivalent à $\\sum_{i=1}^r \\dim E_{\\lambda_i} = n$.\n", "\n", "Grâce à la représentation graphique des espaces propres, on connait la dimension de chaque espace propre (droite -> $\\dim E_{\\lambda_i} = 1$, plan -> $\\dim E_{\\lambda_i}=2$). Il suffit donc de vérifier que la somme des dimensions de tous les espaces propres est bien égal à $n$.\n", "\n", "#### Méthode exercice 1 (en utilisant le critère equivalent de diagonalisabilité)\n", "Plus simplement, on peut simplement vérifier si il existe $n$ vecteur propres linéairement indépendants. En sachant que deux vecteurs propres associés à des valeurs propres différentes sont linéairement indépendants.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercice 2\n", "Determinez si les matrices suivantes sont diagonalisables. Essayez d'utiliser la méthode la plus simple pour chaque cas.\n" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\displaystyle \\left[\\begin{matrix}3 & 5 & -10\\\\1 & 7 & 2\\\\-2 & 2 & 4\\end{matrix}\\right]$" - ], - "text/plain": [ - "Matrix([\n", - "[ 3, 5, -10],\n", - "[ 1, 7, 2],\n", - "[-2, 2, 4]])" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "A1 = sp.Matrix([[1, 2], [3, 2]])\n", "A2 = sp.Matrix([[5, -7], [0, 5]])\n", "A3 = sp.Matrix([[3, 5, -10], [1, 7, 2], [-2, 2, 4]])\n", "A4 = sp.Matrix([[3, 5, -10], [1, 7, 2], [-2, 2, 4]])\n", "A5 = sp.Matrix([[1, 0, 0, 0],[11, -5, 0, 0],[-1, 2, 3, 0],[0, -2, 1, -3]])\n", "A6 = sp.Matrix([[-1, 0, 0, 0],[11, -5, 0, 0],[-1, 2, -1, 0],[0, -2, 1, -1]])\n", "\n", "A = A1\n", "display(A)" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "On cherche à déterminer si la matrice $A=\\left(\\begin{matrix}3 & 5 & -10\\\\1 & 7 & 2\\\\-2 & 2 & 4\\end{matrix}\\right)$ de taille $n \\times n$ avec $n = 3$ est diagonalisable." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "On cherche les valeurs propres de la matrice $ A=\\left(\\begin{matrix}3 & 5 & -10\\\\1 & 7 & 2\\\\-2 & 2 & 4\\end{matrix}\\right)$." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "Le polynome caractéristique de $A$ est: $$\\det(A- \\lambda I)= - \\lambda^{3} + 14 \\lambda^{2} - 32 \\lambda - 128=- \\left(\\lambda - 8\\right)^{2} \\left(\\lambda + 2\\right)$$" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "Les racines du polynôme caractéristique sont $\\left[ -2, \\ 8\\right]$." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "Ces racines sont les valeurs propres de la matrice $A$." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "Les valeurs propres ne sont pas toutes distinctes. On va donc vérifier la multiplicité géométrique des valeurs propres ayant une multiplicité algébrique supérieur à 1." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "L'ensemble des valeurs propres ayant une multiplicité algébrique supérieur à 1 est [8]." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "**On calcule la multiplicité géométrique pour $\\lambda= 8$ ayant une multiplicité algébrique de 2.**" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "On a $ A = \\left(\\begin{matrix}3 & 5 & -10\\\\1 & 7 & 2\\\\-2 & 2 & 4\\end{matrix}\\right)$." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "On cherche une base de l'espace propre associé à $\\lambda = 8$." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "On échelonne la matrice du système $A -\\lambda I = 0 \\Rightarrow \\left(\\begin{array}{ccc| cc} -5 & 5 & -10 & 0 \\\\1 & -1 & 2 & 0 \\\\-2 & 2 & -4 & 0 \\end{array}\\right)$" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "On obtient: $\\left(\\begin{array}{ccc| cc} 1 & -1 & 2 & 0 \\\\0 & 0 & 0 & 0 \\\\0 & 0 & 0 & 0 \\end{array}\\right)$" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "Variable(s) libre(s): $x_2 \\ x_3 \\ $" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "On peut donc exprimer la base de l'espace propre comme: $x_2 \\cdot\\left(\\begin{array}{c} 1 \\\\1 \\\\0 \\end{array}\\right) + x_3 \\cdot\\left(\\begin{array}{c} -2 \\\\0 \\\\1 \\end{array}\\right)$" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "**La multiplicité géométrique pour $\\lambda= 8$ est de 2.**" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "On a bien multiplicité algébrique = multiplicité géométrique pour cette valeur propre." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "**Toutes les valeurs propres ont une multiplicité algébrique et géométrique égales. La matrice $A$ est donc bien diagonalisable !**" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# Affiche la solution étape par étape pour la matrice donné en argument de la fonction isDiagonalizable\n", "isDiagonalizable(A)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Méthode de diagonalisation\n", "Une matrice diagonalisable peut s'exprimer comme: $$A = PDP^{-1}$$ avec $D$ une matrice diagonale, si et seulement si les colonnes de $P$ sont $n$ vecteurs propres de $A$ linéairement indépendants. Dans ce cas, les éléments diagonaux de $D$ sont les valeurs propres de $A$ qui correspondent, respectivement, aux vecteurs propres dans $P$." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercice 3\n", "Pour les matrices $A$ diagonalisables suivantes, donnez les matrices $P$ et $D$ telles que $A = P D P^{-1}$." ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\displaystyle \\left[\\begin{matrix}2 & 3\\\\1 & 4\\end{matrix}\\right]$" - ], - "text/plain": [ - "Matrix([\n", - "[2, 3],\n", - "[1, 4]])" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "A1 = sp.Matrix([[2, 3], [1, 4]])\n", "A2 = sp.Matrix([[0, 0], [-2, -4]])\n", "A3 = sp.Matrix([[1, 6, 2], [0, 3, 0], [2, -6, 1]])\n", "A4 = sp.Matrix([[-2, -7, -1], [0, 1, 0], [-1, -13, -2]])\n", "\n", "A = A1\n", "display(A)\n" ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "On cherche à déterminer les matrices $P$ et $D$ telles que $A=\\left(\\begin{matrix}2 & 3\\\\1 & 4\\end{matrix}\\right)= P D P^{-1}$." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "On cherche les valeurs propres de la matrice $ A=\\left(\\begin{matrix}2 & 3\\\\1 & 4\\end{matrix}\\right)$." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "Le polynome caractéristique de $A$ est: $$\\det(A- \\lambda I)= \\lambda^{2} - 6 \\lambda + 5=\\left(\\lambda - 5\\right) \\left(\\lambda - 1\\right)$$" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "Les racines du polynôme caractéristique sont $\\left[ 1, \\ 5\\right]$." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "Ces racines sont les valeurs propres de la matrice $A$." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "Pour chaque valeur propre $\\lambda_i$, on cherche $n_i$ vecteurs propres linéairement indépendants (avec $n_i = \\dim E_{\\lambda_i}$). On trouve ces vecteurs on calculant une base pour chaque espace propre. On peut ensuite utiliser les vecteurs de base comme colonnes pour la matrice $P$." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "On cherche une base de l'espace propre associé à $\\lambda = 1$." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "On échelonne la matrice du système $A -\\lambda I = 0 \\Rightarrow \\left(\\begin{array}{cc| cc} 1 & 3 & 0 \\\\1 & 3 & 0 \\end{array}\\right)$" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "On obtient: $\\left(\\begin{array}{cc| cc} 1 & 3 & 0 \\\\0 & 0 & 0 \\end{array}\\right)$" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "Variable(s) libre(s): $x_2 \\ $" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "On peut donc exprimer la base de l'espace propre comme: $x_2 \\cdot\\left(\\begin{array}{c} -3 \\\\1 \\end{array}\\right)$" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "On cherche une base de l'espace propre associé à $\\lambda = 5$." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "On échelonne la matrice du système $A -\\lambda I = 0 \\Rightarrow \\left(\\begin{array}{cc| cc} -3 & 3 & 0 \\\\1 & -1 & 0 \\end{array}\\right)$" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "On obtient: $\\left(\\begin{array}{cc| cc} 1 & -1 & 0 \\\\0 & 0 & 0 \\end{array}\\right)$" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "Variable(s) libre(s): $x_2 \\ $" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "On peut donc exprimer la base de l'espace propre comme: $x_2 \\cdot\\left(\\begin{array}{c} 1 \\\\1 \\end{array}\\right)$" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "En utilisant les vecteurs de base trouvés ci dessus pour les colonnes de la matrice $P$ et en plaçant les valeurs propres de $A$ correspondantes sur la diagonal de $D$, on obtient les matrices $P$ et $D$." - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "$P = \\left(\\begin{matrix}-3 & 1\\\\1 & 1\\end{matrix}\\right)$, $D = \\left(\\begin{matrix}1 & 0\\\\0 & 5\\end{matrix}\\right)$" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "Votre réponse est incorrecte, $A \\neq PDP^{-1}$" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# Entrez les matrices P et D trouvée\n", "P_user = sp.Matrix([[1,0], [0,1]])\n", "D_user = sp.Matrix([[1, 0], [0, 1]])\n", "\n", "find_P_D(A, P_user, D_user)" ] } ], "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.2" } }, "nbformat": 4, "nbformat_minor": 2 } diff --git a/Chapitre 8 - Valeurs propres, vecteurs propres, diagonalisation/Ch8_lib.py b/Chapitre 8 - Valeurs propres, vecteurs propres, diagonalisation/Ch8_lib.py index a968bd9..628ab11 100644 --- a/Chapitre 8 - Valeurs propres, vecteurs propres, diagonalisation/Ch8_lib.py +++ b/Chapitre 8 - Valeurs propres, vecteurs propres, diagonalisation/Ch8_lib.py @@ -1,963 +1,962 @@ import sys, os sys.path.append('../Librairie') import AL_Fct as al import numpy as np import sympy as sp from IPython.utils import io from IPython.display import display, Latex, Markdown import plotly import plotly.graph_objects as go from sympy import I as I_sym def vector_plot(v, b): """ Show plot of a two vector v and b to identify if a vector is an eigenvector. (b is equal to A*v with A a matrix) @param v: numpy array of shape (2,) or (3,) @param b: numpy array of shape as v """ if not isinstance(v, np.ndarray) or not isinstance(b, np.ndarray): raise ValueError('Both vector should be numpy array') if v.shape != b.shape or len(v.shape)>1: raise ValueError('Both vector should be of same shape (2,) or (3,)') if v.shape[0]==3: vector_plot_3D(v, b) elif v.shape[0] == 2: vector_plot_2D(v, b) else: raise ValueError('Vector should 2D or 3D') def vector_plot_3D(v, b): """ Show 3D plot of a vector (v) and of b = A * v @param v: numpy array of shape (3,) @param b: numpy array of shape (3,) @return: """ fig = go.Figure() fig.add_trace(go.Scatter3d(x=[0, v[0]], y=[0, v[1]], z=[0, v[2]], line=dict(color='red', width=4), mode='lines+markers', name='$v$')) fig.add_trace(go.Scatter3d(x=[0, b[0]], y=[0, b[1]], z=[0, b[2]], line=dict(color='royalblue', width=4, dash='dash'), mode='lines+markers', name='$A \ v$')) fig.show() def vector_plot_2D(v, b): """ Show 2D plot of a vector (v) and of b = A * v @param v: numpy array of shape (2,) @param b: numpy array of shape (2,) @return: """ fig = go.Figure() fig.add_trace(go.Scatter(x=[0, v[0]], y=[0, v[1]], line=dict(color='red', width=4), mode='lines+markers', name='$v$')) fig.add_trace(go.Scatter(x=[0, b[0]], y=[0, b[1]], line=dict(color='royalblue', width=4, dash='dash'), mode='lines+markers', name='$A \ v$')) fig.show() def CheckEigenVector(A, v): """ Check if v is an eigenvector of A, display step by step solution @param A: square sympy Matrix of shape (n,n) @param v: 1D sympy Matrix of shape (n,1) @return: """ if not isinstance(A, sp.Matrix) or not isinstance(v, sp.Matrix): raise ValueError('A and v should be of type sympy matrix') # Check Dimensions if A.shape[0] != A.shape[1] or v.shape[0] != A.shape[1]: raise ValueError('Dimension problem, A should be square (n x n) and v (n x 1)') if v == sp.zeros(v.shape[0], 1): display(Latex("$v$ est le vecteur nul, il ne peut pas être un vecteur propre par définition.")) else: # Matrix Multiplication b = A * v # Print some explanation about the method display(Latex("On voit que $ b = A v = " + latexp(b) + "$")) display(Latex("On cherche alors un nombre $\lambda \in \mathbb{R}$ tel que $b = \lambda v" \ + "\Leftrightarrow" + latexp(b) + " = \lambda" + latexp(v) + '$')) # Symbol for lambda l = sp.symbols('\lambda', real=True) # Check if there is a solution lambda of eq: A*v = lambda * v eq = sp.Eq(b, l * v) sol = sp.solve(eq, l) # If there is l st b = l*v if sol: display(Latex("Il existe bien une solution pour $\lambda$. Le vecteur $v$ est donc un vecteur \ propre de la matrice $A$.")) display(Latex("La valeur propre associée est $\lambda = " + sp.latex(sol[l]) + "$.")) # Otherwise else: display(Latex("L'equation $b = \lambda v$ n'a pas de solution.")) display(Latex("Le vecteur $v$ n'est donc pas un vecteur propre de la matrice $A$.")) def ch8_1_exo_2(A, l, vp, v): """ Display step by step @param A: Square sympy matrix @param l: eigenvalue (float or int) @param vp: Boolean, given answer to question is l an eigenvalue of A @param v: proposed eigenvector @return: """ if not isinstance(A, sp.Matrix): raise ValueError("A should be a sympy matrix") # Check Dimensions if A.shape[0] != A.shape[1] or v.shape[0] != A.shape[1]: raise ValueError('Dimension problem, A should be square (n x n) and v (n x 1)') n = A.shape[0] eig = list(A.eigenvals().keys()) for i, w in enumerate(eig): eig[i] = float(w) eig = np.array(eig) if np.any(abs(l-eig) < 10**-10): if vp: display(Latex("$\lambda = " + str(l) + "$ est bien une valeur propre de la matrice $A$.")) else: display(Latex("Non, $\lambda = " + str(l) + "$ est bien une valeur propre de la matrice $A$.")) if v != sp.zeros(n, 1): # Check the eigen vector v z = sp.simplify(A * v - l * v) if z == sp.zeros(n, 1): display(Latex("$v$ est bien un vecteur propre de $A$ associé à $\lambda = " + str(l) + "$ car on a:")) display(Latex("$$" + latexp(A) + latexp(v) + "= " + str(l) + "\cdot " + latexp(v) + "$$")) else: display(Latex("$v$ n'est pas un vecteur propre de $A$ associé à $\lambda = " + str(l) + "$ car on a:")) display(Latex("$$" + latexp(A) + latexp(v) + "\\neq \lambda" + latexp(v) + "$$")) else: display(Latex("$v$ est le vecteur nul et ne peut pas être par définition un vecteur propre.")) else: if vp: display(Latex("En effet, $\lambda$ n'est pas une valeur propre de $A$.")) else: display(Latex("Non, $\lambda = " + str(l) + "$ n'est pas une valeur propre de $A$.")) def red_matrix(A, i, j): """ Return reduced matrix (without row i and col j)""" row = [0, 1, 2] col = [0, 1, 2] row.remove(i - 1) col.remove(j - 1) return A[row, col] def pl_mi(i, j, first=False): """ Return '+', '-' depending on row and col index""" if (-1) ** (i + j) > 0: if first: return "" else: return "+" else: return "-" def brackets(expr): """Takes a sympy expression, determine if it needs parenthesis and returns a string containing latex of expr with or without the parenthesis.""" expr_latex = sp.latex(expr) if '+' in expr_latex or '-' in expr_latex: return "(" + expr_latex + ")" else: return expr_latex def Determinant_3x3(A, step_by_step=True, row=True, n=1): """ Step by step computation of the determinant of a 3x3 sympy matrix strating with given row/col number @param A: 3 by 3 sympy matrix @param step_by_step: Boolean, True: print step by step derivation of det, False: print only determinant @param row: True to compute determinant from row n, False to compute determinant from col n @param n: row or col number to compute the determinant from (int between 1 and 3) @return: display step by step solution for """ if not isinstance(A, sp.Matrix): raise ValueError("A should be a sympy matrix") if A.shape != (3, 3): raise ValueError('Dimension of matrix A should be 3x3. The input A must be a sp.Matrix of shape (3,3).') if n < 1 or n > 3 or not isinstance(n, int): raise ValueError('n should be an integer between 1 and 3.') # Construc string for determinant of matrix A detA_s = sp.latex(A).replace('[', '|').replace(']', '|') # To print all the steps if step_by_step: # If we compute the determinant with row n if row: # Matrix with row i and col j removed (red_matrix(A, i, j)) A1 = red_matrix(A, n, 1) A2 = red_matrix(A, n, 2) A3 = red_matrix(A, n, 3) detA1_s = sp.latex(A1).replace('[', '|').replace(']', '|') detA2_s = sp.latex(A2).replace('[', '|').replace(']', '|') detA3_s = sp.latex(A3).replace('[', '|').replace(']', '|') line1 = "$" + detA_s + ' = ' + pl_mi(n, 1, True) + brackets(A[n - 1, 0]) + detA1_s + pl_mi(n, 2) + \ brackets(A[n - 1, 1]) + detA2_s + pl_mi(n, 3) + brackets(A[n - 1, 2]) + detA3_s + '$' line2 = '$' + detA_s + ' = ' + pl_mi(n, 1, True) + brackets(A[n - 1, 0]) + "\cdot (" + sp.latex(sp.det(A1)) \ + ")" + pl_mi(n, 2) + brackets(A[n - 1, 1]) + "\cdot (" + sp.latex(sp.det(A2)) + ")" + \ pl_mi(n, 3) + brackets(A[n - 1, 2]) + "\cdot (" + sp.latex(sp.det(A3)) + ')$' line3 = '$' + detA_s + ' = ' + sp.latex(sp.simplify(sp.det(A))) + '$' # If we compute the determinant with col n else: # Matrix with row i and col j removed (red_matrix(A, i, j)) A1 = red_matrix(A, 1, n) A2 = red_matrix(A, 2, n) A3 = red_matrix(A, 3, n) detA1_s = sp.latex(A1).replace('[', '|').replace(']', '|') detA2_s = sp.latex(A2).replace('[', '|').replace(']', '|') detA3_s = sp.latex(A3).replace('[', '|').replace(']', '|') line1 = "$" + detA_s + ' = ' + pl_mi(n, 1, True) + brackets(A[0, n - 1]) + detA1_s + pl_mi(n, 2) + \ brackets(A[1, n - 1]) + detA2_s + pl_mi(n, 3) + brackets(A[2, n - 1]) + detA3_s + '$' line2 = '$' + detA_s + ' = ' + pl_mi(n, 1, True) + brackets(A[0, n - 1]) + "\cdot (" + sp.latex(sp.det(A1))\ + ")" + pl_mi(n, 2) + brackets(A[1, n - 1]) + "\cdot (" + sp.latex(sp.det(A2)) + ")" + \ pl_mi(n, 3) + brackets(A[2, n - 1]) + "\cdot (" + sp.latex(sp.det(A3)) + ')$' line3 = '$' + detA_s + ' = ' + sp.latex(sp.simplify(sp.det(A))) + '$' # Display step by step computation of determinant display(Latex(line1)) display(Latex(line2)) display(Latex(line3)) # Only print the determinant without any step else: display(Latex("$" + detA_s + "=" + sp.latex(sp.det(A)) + "$")) def valeurs_propres(A): if not isinstance(A, sp.Matrix): raise ValueError("A should be a sympy matrix") if A.shape[0] != A.shape[1]: raise ValueError("A should be a square matrix") l = sp.symbols('\lambda') n = A.shape[0] poly = sp.det(A - l * sp.eye(n)) poly_exp = sp.expand(poly) poly_factor = sp.factor(poly) det_str = sp.latex(poly_exp) + "=" + sp.latex(poly_factor) display(Latex("On cherche les valeurs propres de la matrice $ A=" + latexp(A) + "$.")) display(Latex("Le polynome caractéristique de $A$ est: $$\det(A- \lambda I)= " + det_str + "$$")) eq = sp.Eq(poly, 0) sol = sp.solve(eq, l) if len(sol) > 1: display(Latex("Les racines du polynôme caractéristique sont $" + sp.latex(sol) + "$.")) display(Latex("Ces racines sont les valeurs propres de la matrice $A$.")) else: display(Latex("L'unique racine du polynôme caractéristique est" + str(sol[0]))) def texVector(v): """ Return latex string for vertical vector Input: v, 1D np.array() """ n = v.shape[0] return al.texMatrix(v.reshape(n, 1)) def check_basis(sol, prop): """ Checks if prop basis is equivalent to sol basis @param sol: verified basis, 2D numpy array, first dim: vector indexes, second dim: idx of element in a basis vect @param prop: proposed basis @return: boolean """ prop = np.array(prop, dtype=np.float64) # number of vector in basis n = len(sol) # Check dimension of proposed eigenspace if n != len(prop): display(Latex("Le nomber de vecteur(s) propre(s) donné(s) est incorrecte. " + "La dimension de l'espace propre est égale au nombre de variable(s) libre(s).")) return False else: # Check if the sol vector can be written as linear combination of prop vector # Do least squares to solve overdetermined system and check if sol is exact A = np.transpose(prop) lin_comb_ok = np.zeros(n, dtype=bool) for i in range(n): x, _, _, _ = np.linalg.lstsq(A, sol[i], rcond=None) res = np.sum((A @ x - sol[i]) ** 2) lin_comb_ok[i] = res < 10 ** -13 return np.all(lin_comb_ok) def eigen_basis(A, l, prop_basis=None, disp=True, return_=False, dispA=True): """ Display step by step method for finding a basis of the eigenspace of A associated to eigenvalue l Eventually check if the proposed basis is correct. Display or not @param A: Square sympy Matrix with real coefficients @param l: real eigen value of A (float or int) @param prop_basis: Proposed basis: list of base vector (type list of list of floats) @param disp: boolean if display the solution. If false it displays nothing @param return_: boolean if return something or nothing @return: basis: a correct basis for the eigen space (2D numpy array) basic_idx: list with indices of basic variables of A - l*I free_idx: list with indices of free variables of A - l*I """ if not isinstance(A, sp.Matrix): raise ValueError("A should be a sympy Matrix.") # Check if A is square n = A.shape[0] if n != A.shape[1]: raise ValueError('A should be a square matrix.') # Compute eigenvals in symbolic eig = A.eigenvals() eig = list(eig.keys()) # Deal with complex number (removal) complex_to_rm = [] for idx, el in enumerate(eig): if not el.is_real: complex_to_rm.append(idx) for index in sorted(complex_to_rm, reverse=True): del eig[index] eig = np.array(eig) # evaluate symbolic expression eig_eval = np.array([float(el) for el in eig]) # Check that entered eigenvalue is indeed an eig of A if np.all(abs(l - eig_eval) > 1e-10) and len(eig) > 0: display(Latex("$\lambda$ n'est pas une valeur propre de $A$.")) return None, None, None # Change value of entered eig to symbolic expression (for nice print) l = eig[np.argmin(np.abs(l - eig))] I = sp.eye(n) Mat = A - l * I b = np.zeros(n) if disp: if dispA: display(Latex("On a $ A = " + latexp(A) + "$.")) display(Latex("On cherche une base de l'espace propre associé à $\lambda = " + str(l) + "$.")) # ER matrix e_Mat, basic_idx = Mat.rref() # Idx of basic and free varialbe basic_idx = list(basic_idx) basic_idx.sort() free_idx = [idx for idx in range(n) if idx not in basic_idx] free_idx.sort() n_free = len(free_idx) # String to print free vars free_str = "" for i in range(n): if i in free_idx: free_str += "x_" + str(i + 1) + " \ " # Display echelon matrix if disp: display(Latex("On échelonne la matrice du système $A -\lambda I = 0 \Rightarrow " + al.texMatrix(np.array(Mat), np.reshape(b, (n, 1))) + "$")) display(Latex("On obtient: $" + al.texMatrix(np.array(e_Mat[:, :n]), np.reshape(b, (n, 1))) + "$")) display(Latex("Variable(s) libre(s): $" + free_str + "$")) # Build a list of n_free basis vector: # first dim: which eigenvector (size of n_free) # second dim: which element of the eigenvector (size of n) basis = np.zeros((n_free, n)) for i in range(n_free): basis[i, free_idx[i]] = 1.0 for idx, j in enumerate(free_idx): for i in basic_idx: basis[idx, i] = - float(e_Mat[i, j]) # Show calculated basis basis_str = "" for idx, i in enumerate(free_idx): basis_str += "x_" + str(i + 1) + " \cdot" + texVector(basis[idx]) if idx < n_free - 1: basis_str += " + " if disp: display(Latex("On peut donc exprimer la base de l'espace propre comme: $" + basis_str + "$")) if prop_basis is not None and disp: correct_answer = check_basis(basis, prop_basis) if correct_answer: display(Latex("La base donnée est correcte car on peut retrouver la base calculée ci-dessus" \ " avec une combinaison linéaire de la base donnée. " "Aussi les deux bases ont bien le même nombre de vecteurs.")) else: display(Latex("La base donnée est incorrecte.")) if return_: return basis, basic_idx, free_idx def generate_eigen_vector(basis, l, limit): """ Function to generate a random eigenvector associated to a eigenvalue given a basis of the eigenspace The returned eigenvector is such that itself and its multiplication with the matrix will stay in range of limit in order to have a nice plot @param basis: basis of eigenspace associated to eigenvalue lambda @param l: eigenvalue @param limit: limit of the plot: norm that the engenvector or its multiplication with the matrix will not exceed @return: eigen vector (numpy array) """ n = len(basis) basis_mat = np.array(basis).T basis_mat = basis_mat.astype(np.float64) coeff = 2 * np.random.rand(n) - 1 vect = basis_mat @ coeff if abs(l) <= 1: vect = vect / np.linalg.norm(vect) * (limit - 1) else: vect = vect / np.linalg.norm(vect) * (limit - 1) / l return vect def plot3x3_eigspace(A, xL=-10, xR=10, p=None, plot_vector=False): # To have integer numbers if p is None: p = xR - xL + 1 n = A.shape[0] # Check 3 by 3 if n != 3 or n != A.shape[1]: raise ValueError("A should be 3 by 3") w = A.eigenvals() w = list(w.keys()) # Deal with complex number (removal) complex_to_rm = [] for idx, el in enumerate(w): if not el.is_real: complex_to_rm.append(idx) for index in sorted(complex_to_rm, reverse=True): del w[index] display("Des valeurs propres sont complexes, on les ignore.") if len(w)==0: display("Toute les valeurs propres sont complexes.") return gr = 'rgb(102,255,102)' org = 'rgb(255,117,26)' # red = 'rgb(255,0,0)' blue = 'rgb(51, 214, 255)' colors = [blue, gr, org] s = np.linspace(xL, xR, p) t = np.linspace(xL, xR, p) tGrid, sGrid = np.meshgrid(s, t) data = [] A_np = np.array(A).astype(np.float64) for i, l in enumerate(w): l_eval = float(l) basis, basic_idx, free_idx = eigen_basis(A, l_eval, disp=False, return_=True) n_free = len(basis) if n_free != len(free_idx): raise ValueError("len(basis) and len(free_idx) should be equal.") gr = 'rgb(102,255,102)' colorscale = [[0.0, colors[i]], [0.1, colors[i]], [0.2, colors[i]], [0.3, colors[i]], [0.4, colors[i]], [0.5, colors[i]], [0.6, colors[i]], [0.7, colors[i]], [0.8, colors[i]], [0.9, colors[i]], [1.0, colors[i]]] X = [None] * 3 if n_free == 2: X[free_idx[0]] = tGrid X[free_idx[1]] = sGrid X[basic_idx[0]] = tGrid * basis[0][basic_idx[0]] + sGrid * basis[1][basic_idx[0]] plot_obj = go.Surface(x=X[0], y=X[1], z=X[2], showscale=False, showlegend=True, colorscale=colorscale, opacity=1, name="$ \lambda= " + sp.latex(l) + "$") elif n_free == 1: plot_obj = go.Scatter3d(x=t * basis[0][0], y=t * basis[0][1], z=t * basis[0][2], line=dict(colorscale=colorscale, width=4), mode='lines', name="$\lambda = " + sp.latex(l) + "$") elif n_free == 3: display(Latex("La dimension de l'espace propre de l'unique valeur propre est 3: tous les vecteurs" \ "$v \in \mathbb{R}^3 $ appartiennent à l'espace propre de la matrice $A$." \ "On ne peut donc pas reprensenter sous la forme d'un plan ou d'une droite.")) return else: print("error") return data.append(plot_obj) if (plot_vector): v1 = generate_eigen_vector(basis, l_eval, xR) v2 = A_np @ v1 data.append(go.Scatter3d(x=[0, v1[0]], y=[0, v1[1]], z=[0, v1[2]], line=dict(width=6), marker=dict(size=4), mode='lines+markers', name='$v_{' + sp.latex(l) + '}$')) data.append(go.Scatter3d(x=[0, v2[0]], y=[0, v2[1]], z=[0, v2[2]], line=dict(width=6, dash='dash'), marker=dict(size=4), mode='lines+markers', name="$A \ v_{" + sp.latex(l) + "}$")) layout = go.Layout( showlegend=True, # not there WHY???? --> LEGEND NOT YET IMPLEMENTED FOR SURFACE OBJECTS!! legend=dict(orientation="h"), autosize=True, width=800, height=800, scene=go.layout.Scene( xaxis=dict( gridcolor='rgb(255, 255, 255)', zerolinecolor='rgb(255, 255, 255)', showbackground=True, backgroundcolor='rgb(230, 230,230)', range=[xL, xR] ), yaxis=dict( gridcolor='rgb(255, 255, 255)', zerolinecolor='rgb(255, 255, 255)', showbackground=True, backgroundcolor='rgb(230, 230,230)', range=[xL, xR] ), zaxis=dict( gridcolor='rgb(255, 255, 255)', zerolinecolor='rgb(255, 255, 255)', showbackground=True, backgroundcolor='rgb(230, 230,230)', range=[xL, xR] ), aspectmode="cube", ) ) fig = go.Figure(data=data, layout=layout) plotly.offline.iplot(fig) return def plot2x2_eigspace(A, xL = -10, xR = 10, p=None): if p is None: p = xR - xL + 1 w = A.eigenvals() w = list(w.keys()) # Deal with complex number (removal) complex_to_rm = [] for idx, el in enumerate(w): if not el.is_real: complex_to_rm.append(idx) for index in sorted(complex_to_rm, reverse=True): del w[index] display("Une valeur propre est complexe, on l'ignore.") if len(w) == 0: display("Toute les valeurs propres sont complexes.") return data = [] for i, l in enumerate(w): l_eval = float(l) basis, basic_idx, free_idx = eigen_basis(A, l_eval, disp=False, return_=True) n_free = len(basis) if n_free != len(free_idx): raise ValueError("len(basis) and len(free_idx) should be equal.") if n_free == 2: display(Latex("Tous les vecteurs du plan appartiennent à l'espace propre de A associé à $\lambda = " \ + sp.latex(l) + "$. On ne peut donc pas le représenter.")) return else: t = np.linspace(xL, xR, p) trace = go.Scatter(x=t*basis[0][0], y=t*basis[0][1], marker=dict(size=6), mode='lines+markers', name="$\lambda = " + sp.latex(l) + "$") data.append(trace) layout = go.Layout(showlegend=True, autosize=True) fig = go.Figure(data=data, layout=layout) plotly.offline.iplot(fig) return def plot_eigspace(A, xL=-10, xR=10, p=None): """ Plot the eigenspaces associated to all eigenvalues of A @param A: Sympy matrix of shape (2,2) or (3,3) @param xL: Left limit of plot @param xR: Right limit of plot @param p: Number of points to use """ if not isinstance(A, sp.Matrix): raise ValueError("A should be a sympy Matrix.") n = A.shape[0] # Check 3 by 3 or 2 by 2 if (n != 2 and n!=3) or n != A.shape[1]: raise ValueError("A should be 2 by 2 or 3 by 3.") if n==2: plot2x2_eigspace(A, xL, xR, p) else: plot3x3_eigspace(A, xL, xR, p) def latexp(A): """ Function to output latex expression of a sympy matrix but with round parenthesis @param A: sympy matrix @return: latex string """ return sp.latex(A, mat_delim='(', mat_str='matrix') def ch8_8_ex_1(A, prop_answer): """ Check if a matrix is diagonalisable. @param A: sympy square matrix @param prop_answer: boolean, answer given by the student @return: """ if not isinstance(A, sp.Matrix): raise ValueError("A should be a sympy Matrix.") n = A.shape[0] if n != A.shape[1]: raise ValueError('A should be a square matrix.') eig = A.eigenvects() dim_geom = 0 for x in eig: dim_geom += len(x[2]) answer = dim_geom == n if answer: display(Latex("Oui la matrice $A = " + latexp(A) + "$ est diagonalisable.")) else: display(Latex("Non la matrice $A = " + latexp(A) + "$ n'est pas diagonalisable.")) if answer == prop_answer: display(Latex("Votre réponse est correcte !")) else: display(Latex("Votre réponse est incorrecte.")) def isDiagonalizable(A): """ Step by step method to determine if a given matrix is diagonalizable. This methods uses always (I think) the easiest way to determine it (as seen in the MOOC) @param A: sympy matrix @return: nothing """ if not isinstance(A, sp.Matrix): raise ValueError("A should be a sympy Matrix.") n = A.shape[0] if n != A.shape[1]: raise ValueError('A should be a square matrix.') display(Latex("On cherche à déterminer si la matrice $A=" + latexp(A) + "$ de taille $n \\times n$ avec $n = " + str(n) + "$ est diagonalisable.")) if A.is_lower or A.is_upper: display(Latex("Les valeurs propres sont simple à trouver, ce sont les éléments diagonaux.")) else: valeurs_propres(A) # Check if eigenvalue are all distincts eig = A.eigenvects() if len(eig) == n: display(Latex("On a $n$ valeurs propres distinctes. La matrice est donc diagonalisable.")) return else: display(Latex("Les valeurs propres ne sont pas toutes distinctes. On va donc vérifier la multiplicité " + "géométrique des valeurs propres ayant une multiplicité algébrique supérieur à 1.")) # Some list to have info about eigenvalues with algebraic mult > 1 idx = [] eigenvalues = [] mult_al = [] mult_geo = [] for i in range(len(eig)): if eig[i][1] > 1: idx.append(i) eigenvalues.append(eig[i][0]) mult_al.append(eig[i][1]) mult_geo.append(len(eig[i][2])) display(Latex("L'ensemble des valeurs propres ayant une multiplicité algébrique supérieur à 1 est " + str( eigenvalues) + ".")) for i, l in enumerate(eigenvalues): display(Markdown("**On calcule la multiplicité géométrique pour $\lambda= " + sp.latex(l) + "$ ayant une multiplicité algébrique de " + str(mult_al[i]) + ".**")) basis, basic, free = eigen_basis(A, l, prop_basis=None, disp=True, return_=True) display(Markdown("**La multiplicité géométrique pour $\lambda= " + sp.latex(l) + "$ est de " + str(len(free)) + ".**")) if (len(free) < mult_al[i]): display(Markdown("**La multiplicité géométrique est strictement inférieur à la multiplicité" + "algébrique pour cette valeur propre. La matrice n'est donc pas diagonalisable.**")) return else: display(Latex("On a bien multiplicité algébrique = multiplicité géométrique pour cette valeur propre.")) display(Markdown("**Toutes les valeurs propres ont une multiplicité algébrique et géométrique égales." + " La matrice $A$ est donc bien diagonalisable !**")) def find_P_D(A, P_user, D_user, step_by_step=True): """ :param A: sympy square matrix :param P_user: sympy square matrix :param D_user: sympa sqaure matrix :param step_by_step: Print step by step solution :return: """ if not isinstance(A, sp.Matrix) or not isinstance(P_user, sp.Matrix) or not isinstance(D_user, sp.Matrix): raise ValueError("A, P and D should be a sympy Matrix.") n = A.shape[0] if n != A.shape[1] or P_user.shape[0] != n or P_user.shape[1] != n or D_user.shape[0] != n or D_user.shape[1] != n: raise ValueError('A, P and D should be a square matrix of the same size.') if not D_user.is_diagonal(): raise ValueError("D should be a diagonal matrix.") if not A.is_diagonalizable(): raise ValueError("A is not diagonalizable.") if step_by_step: display(Latex("On cherche à déterminer les matrices $P$ et $D$ telles que $A=" + latexp(A) + "= P D P^{-1}$.")) if A.is_lower or A.is_upper: display(Latex("Les valeurs propres sont simple à trouver, ce sont les éléments diagonaux.")) else: valeurs_propres(A) display( Latex("Pour chaque valeur propre $\lambda_i$, on cherche $n_i$ vecteurs propres linéairement indépendants" + " (avec $n_i = \dim E_{\lambda_i}$). On trouve ces vecteurs on calculant une base pour " + "chaque espace propre. On peut ensuite utiliser les vecteurs de base comme colonnes pour la " + "matrice $P$.")) eig = A.eigenvects() # Some list to have info about eigenvalues with algebraic mult > 1 idx = [] eigenvalues = [] mult_al = [] mult_geo = [] D = sp.zeros(n) for i in range(len(eig)): idx.append(i) eigenvalues.append(eig[i][0]) mult_al.append(eig[i][1]) mult_geo.append(len(eig[i][2])) P = [] k = 0 for i, l in enumerate(eigenvalues): basis, _, _ = eigen_basis(A, l, return_=True, disp=step_by_step, dispA=False) for j in range(len(basis)): D[k, k] = l k += 1 P.append(basis[j]) P = np.transpose(np.array(P)) if np.all(np.mod(P, 1) == 0): P = P.astype(int) P = sp.Matrix(P) display(Latex("En utilisant les vecteurs de base trouvés ci dessus pour les colonnes de la matrice $P$ et en " + "plaçant les valeurs propres de $A$ correspondantes sur la diagonal de $D$, on obtient " + "les matrices $P$ et $D$.")) display(Latex("$P = " + latexp(P) + "$, " + "$D = " + latexp(D) + "$")) - if (P.det()!=0) + if (P.det()!=0): P_1_user = P_user ** -1 - else if ((A - P_user * D_user * P_1_user).norm() < 1e-10): display(Latex("Votre réponse est correcte, on a bien $A = PDP^{-1}$")) else: display(Latex("Votre réponse est incorrecte, $A \\neq PDP^{-1}$")) def diagonalizeComplex(A): """ @param A: """ if not isinstance(A, sp.Matrix): raise ValueError("A should be a sympy matrix") if not A.is_diagonalizable(): display(Latex("A n'est pas diagonalisable.")) return lamda = sp.symbols('lamda') poly = A.charpoly(lamda) poly = sp.factor(poly, extension=[I_sym]) eig = A.eigenvects() eigenval = [] mult = [] for el in eig: eigenval.append(sp.simplify(el[0])) mult.append(el[1]) display(Latex("Le polynome caractéristique de la matrice $A = " + latexp(A) + "$ est $ c_A (\lambda) = " + sp.latex( poly) + "$")) display(Latex("Les valeurs propres de A sont donc: " + listsp_to_str(eigenval))) display(Latex("Pour chaque valeur propre $\lambda$, on calcule une base de l'espace propre associé " "($\ker (A -\lambda I)$). On se sert ensuite des vecteurs propres (vecteur de base de l'espaces" + " propre) pour diagonaliser la matrice.")) k = 0 P = sp.zeros(A.shape[0], A.shape[0]) D = sp.zeros(A.shape[0], A.shape[0]) for i, l in enumerate(eigenval): display(Latex( "Pour la valeur propres $\lambda = " + sp.latex(l) + "$, on trouve une base de l'espace propre associé. " + "On obtient comme base: " + listsp_to_str(eig[i][2]))) for vec in eig[i][2]: P[:, k] = vec D[k, k] = l k += 1 P = sp.simplify(P) D = sp.simplify(D) display(Latex("Avec la matrice $D= " + latexp(D) + "$ on obtient la matrice $P = " + latexp(P) + "$.")) display(Latex("La matrice $A$ se diagonalise donc avec comme $A = P D P^{-1}$")) display(Latex("$P D P^{-1} = " + latexp(P) + latexp(D) + latexp(sp.simplify(P ** -1)) + " = " + latexp(sp.simplify(P * D * P ** -1)) + " = A$ ")) def listsp_to_str(splist): out = "$" + sp.latex(sp.simplify(splist[0]), mat_delim='(') + "$" if len(splist) == 1: return out for i in range(1, len(splist) - 1): out += ", $" + sp.latex(sp.simplify(splist[i]), mat_delim='(') + "$" out += " et $" + sp.latex(sp.simplify(splist[-1]), mat_delim='(') + "$" return out