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" index 5e29319..55f3b1f 100644 --- "a/Chapitre 10 - Matrices orthogonales, matrices sym\303\251triques/Ch10_lib.py" +++ "b/Chapitre 10 - Matrices orthogonales, matrices sym\303\251triques/Ch10_lib.py" @@ -1,1199 +1,1199 @@ 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 import ipywidgets as widgets from ipywidgets import interact_manual, Layout from sympy import sqrt import random 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 A.shape[0]!=2 or A.shape[1]!=2: raise ValueError("A should be a 2 by 2 numpy array") 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.")) if np.allclose(A @ A.transpose(), np.eye(2)): display(Latex("La matrice $A = " + al.texMatrix(A) + "$ est une matrice orthogonale." )) else: display(Latex("La matrice $A = " + al.texMatrix(A) + "$ n'est pas une matrice orthogonale." )) 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): A = sp.Matrix(A) 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.")) def interactive_is_orthogonal(A): A = sp.Matrix(A) n = A.shape[0] if n != A.shape[1]: raise ValueError("A should be a square matrix") display(Latex("La matrice suivante est-elle orthogonale ? $A = " + latexp(A) + "$")) answer = widgets.RadioButtons(options=["Oui", "Non"], description="Réponse : ", disabled=False) sol = A.transpose()*A - sp.eye(n) == sp.zeros(n) display(answer) def f(): if answer.value == "Oui": answer_bool = True else: answer_bool = False if answer_bool == sol: display(Latex("Correct !")) else: display(Latex("Incorrect")) interact_manual(f) display(Latex("Si vous n'arrivez pas à trouver la solution, vous pouvez afficher la solution détaillée en" " cliquant ici")) def f_sol(): is_orthogonal(A) im = interact_manual(f_sol) im.widget.children[0].description = 'Solution' def ortho_diag(A): A = sp.Matrix(A) n = A.shape[0] if A - A.transpose() != sp.zeros(n): display(Latex("La matrice $A = " + latexp(A) + "$ n'est pas orthogonalement diagonalisable car elle n'est pas " "symétrique.")) return eig = A.eigenvals() eig_list = list(eig.keys()) eig_list.sort() display(Latex("On cherche à diagonaliser orthogonalement la matrice $ A = " + latexp(A) + "$.")) default_value_P = str(np.ones(A.shape, dtype=np.int16).tolist()) default_value_P = default_value_P.replace("],", "],\n") default_value_D = str(np.ones(A.shape[0], dtype=np.int16).tolist()) answer_P = widgets.Text(value=default_value_P, description='P: ', disabled=False) answer_D = widgets.Text(value=default_value_D, description='D: ', disabled=False) display(Latex("Pour les réponses aux questions suivantes, ne faites pas d'approximations numériques, " "toutes les valeurs doivent être exactes. Pour les racines carrées " "(utiles pour normaliser les vecteurs), utilisez 'sqrt('votre valeur')', ex: sqrt(2).")) display(Latex("Donnez les éléments diagonaux de la matrice $D$")) display(answer_D) display(Latex("Donnez la matrice P permettant de diagonaliser orthogonalement la matrice $A$ de sorte que " "$ A = PDP^T = PDP^{-1} $")) display(answer_P) def f(): P_user = eval(answer_P.value) P_user = sp.Matrix(P_user) D_diag= eval(answer_D.value) D_diag_order = set(D_diag.copy()) D_diag_order = list(D_diag_order) D_diag_order.sort() D_user = sp.zeros(n) for i in range(n): D_user[i, i] = D_diag[i] D_user = sp.Matrix(D_user) if np.allclose(np.array(D_diag_order, dtype=np.float64), np.array(eig_list, dtype=np.float64)): if P_user*P_user.transpose()-sp.eye(n) == sp.zeros(n): if P_user * D_user * P_user.transpose() - A == sp.zeros(n): display(Latex("Correct !")) else: display(Latex("Incorrect. On a $PDP^{T}\\neq A$ avec $P = " + latexp(P_user) + "$ et $D =" + latexp(D_user) + "$.")) else: display(Latex("La matrice $P = " + latexp(P_user) + "$ n'est pas orthogonale, i.e. $P P^{T} \\neq I$.")) else: display(Latex("Incorrect. " "Les éléments diagonaux de $D$ ne correspondent pas aux valeurs propres de la matrice $A$.")) return interact_manual(f) def correction_ortho_diag(): display(Latex("Pour diagonaliser orthogonalement une matrice, on a applique la méthode donnée dans le cours et rappelée plus haut")) lamda = sp.symbols('lamda') poly_char_exp = sp.expand(A.charpoly(lamda).as_expr()) poly_char_fac = sp.factor(A.charpoly(lamda).as_expr()) poly_char_exp_str = sp.latex(poly_char_exp) poly_char_fac_str = sp.latex(poly_char_fac) display(Latex("Le polynôme caractéristique de $A$ s'exprime comme: $c_A (t) = " + poly_char_exp_str + "$.")) display(Latex("On trouve les racines du polynôme caractéristique et on factorise. On obtient $c_A (t) = " + poly_char_fac_str + "$.")) eig_list_ = list(eig.keys()) mult_list_ = list(eig.values()) display(Latex("On obtient donc les valeurs propres $\lambda$ et leur multiplicité respective $m$: " " $ \lambda = " + sp.latex(eig_list_) + " \hspace{10mm} m = " + sp.latex(mult_list_) + "$.")) display(Markdown("**On trouve une base orthonormée pour tous les espaces propres.**")) final_basis = [] P = sp.Matrix([]) k = 0 for l in eig_list_: basis_orthonorm = [] basis, basic_idx, free_idx = eigen_basis(A, l, prop_basis=None, disp=True, return_=True, dispA=False) for v in basis: if np.all(v == np.round(v)): v = v.astype(np.int16) basis_orthonorm.append(sp.Matrix(v)) basis_orthonorm = sp.GramSchmidt(basis_orthonorm, True) for v in basis_orthonorm: final_basis.append(v) P = P.col_insert(k, v) k+=1 display(Latex("On applique le procédé de Gram-Schmidt pour obtenir des vecteurs de norme 1 et orthogonaux. " "On obtient $" + sp.latex(basis_orthonorm) + "$")) display(Latex("Finalement, on construit la matrice $P$ en utilisant chaque vecteur de base " "trouvé précedemment comme colonne de cette matrice. Cette dernière est bien orthogonale car " "les vecteurs de base sont orthogonaux entre eux et tous de norme unitaire. " "On construit la matrice $D$ en plaçant les valeurs propres de $A$ sur la diagonale. " "Le placement des valeurs propres sur la diagonale de $D$ " "doit correspondre avec celui des vecteurs propres dans $P$.")) D = sp.zeros(n) i = 0 for idx in range(len(eig_list_)): for _ in range(mult_list_[idx]): D[i, i] = eig_list_[idx] i += 1 display(Latex("On obtient $P = " + latexp(P) + "\hspace{5mm} \mbox{et} \hspace{5mm} D = " + latexp(D) + "$")) display(Latex("On vérifie le résultat par un calcul :")) display(Latex("$P D P^T = "+ latexp(P) + latexp(D) + latexp(P.transpose()) + " = " + latexp(P*D*P.transpose()) + "=A$")) display(Latex("Si vous n'arrivez pas à résoudre l'exercice, vous pouvez afficher la solution étape " "par étape en cliquant ici.")) im = interact_manual(correction_ortho_diag) im.widget.children[0].description = 'Solution' def nl(): return "$$ $$" def sol_is_ortho(A): A = sp.Matrix(A) n = A.shape[0] if n != A.shape[1]: display(Latex("La matrice $A = " + latexp(A) + "$ n'est pas carrée !")) return display(Latex("Pour vérifier si la matrice $A$ est orthogonale, on effectue dans cette correction " "le produit de $A$ et de sa transposée $A^T$." " On vérifie ensuite si l'on obtient la matrice identité.")) if sp.simplify(A*A.transpose()-sp.eye(n)) == sp.zeros(n): display(Latex("On a que : $A A^T = " + latexp(A) + latexp(A.transpose()) + "= " + latexp(sp.eye(n)) + "= I_n $")) display(Latex("La matrice $A$ est donc orthogonale.")) else: display(Latex("On a que : $A A^T = " + latexp(A) + latexp(A.transpose()) + "\\neq I_n $")) display(Latex("Par consequent, la matrice $A$ n'est pas orthogonale.")) return def is_ortho_10_2(A): A = sp.Matrix(A) n = A.shape[0] display(Latex("La matrice $A =" + latexp(A) + "$ est-elle orthogonale ?")) answer = widgets.RadioButtons(options=["Oui", "Non"], description="Réponse : ", disabled=False) display(answer) sol = sp.simplify(A * A.transpose() - sp.eye(n)) == sp.zeros(n) if n != A.shape[1]: sol = False def f(): if answer.value == "Oui": answer_bool = True else: answer_bool = False if answer_bool == sol: display(Latex("Correct !")) else: display(Latex("Incorrect")) if sol: display(Latex("La matrice $A$ est orthogonale.")) else: display(Latex("La matrice $A$ n'est pas orthogonale.")) interact_manual(f) def f_sol(): sol_is_ortho(A) display(Latex("Pour afficher la solution, cliquez-ici.")) im = interact_manual(f_sol) im.widget.children[0].description = 'Solution' def vf_10_2_2(): display(Latex("Soit $A \in M_{n \\times n}(\mathbb{R})$ une matrice orthogonale. On construit la matrice" " $B \in M_{n \\times n}(\mathbb{R})$ en réarrangeant les colonnes de $A$ dans un ordre quelquonque. " "La matrice $B$ est aussi orthogonale.")) answer = widgets.RadioButtons(options=["Vrai", "Faux"], description="Réponse : ", disabled=False) display(answer) def f(): if answer.value=="Vrai": display(Latex("Correct ! En effet, si l'ordre des colonnes est modifié, l'ensemble de ces dernières reste " "toujours une base orthonormée de l'espace $V$. " "La proposition (5) est donc vérifiée pour la matrice $B$.")) else: display(Latex("Incorrect, changez votre réponse !")) interact_manual(f) def vf_10_2_3(): display(Latex("Soit $A \in M_{n \\times n}(\mathbb{R})$ une matrice orthogonale. On construit la matrice" " $B \in M_{n \\times n}(\mathbb{R})$ en réarrangeant les lignes de $A$ dans un ordre quelquonque. " "La matrice $B$ est aussi orthogonale.")) answer = widgets.RadioButtons(options=["Vrai", "Faux"], description="Réponse : ", disabled=False) display(answer) def f(): if answer.value=="Vrai": display(Latex("Correct ! En effet, si l'ordre des lignes est modifié, l'ensemble de ces dernières reste " "toujours une base orthonormée de l'espace $V$. " "La proposition (4) est donc vérifiée pour la matrice $B$.")) else: display(Latex("Incorrect, changez votre réponse !")) interact_manual(f) def vf_10_2_1(): display(Latex("Soit $A \in M_{n \\times n}(\mathbb{R})$ une matrice orthogonale. $A^T$ est aussi orthogonale.")) answer = widgets.RadioButtons(options=["Vrai", "Faux"], description="Réponse : ", disabled=False) display(answer) def f(): if answer.value == "Vrai": display(Latex("Correct ! En effet, comme $A$ est orthogonale, on sait que ses colonnes forment " "une base orthonormée de l'espace $V$. Comme les lignes de $A^T$ sont les colonnes de $A$, " "alors la proposition (4) est vérifiée pour $A^T$, i.e. les lignes de $A^T$ forment une base " "orthonormée de $V$. $A^T$ est donc une matrice orthogonale.")) else: display(Latex("Incorrect, changez votre réponse !")) interact_manual(f) def vf_10_2_4(): display(Latex("Soit $A \in M_{n \\times n}(\mathbb{R})$ une matrice ayant une valeur propre $\lambda = 2$. " "Il est possible que $A$ soit orthogonale.")) answer = widgets.RadioButtons(options=["Vrai", "Faux"], description="Réponse : ", disabled=False) display(answer) def f(): if answer.value == "Faux": display(Latex("Correct ! Etant donné que $A$ a pour valeur propre $\lambda=2$, cela signifique qu'il existe " "un vecteur $v$ tel que $A v = 2 v$. Donc la matrice $A$ ne conserve pas toujours les longeurs lors " "d'une multiplication avec un vecteur. La proposition (1) n'est pas vérifiée." " $A$ ne peut donc pas être orthogonale.")) else: display(Latex("Incorrect, changez votre réponse !")) interact_manual(f) def vf_10_4_1(): display(Markdown("**Dire si l'affirmation suivante est vraie ou fausse.**")) display(Latex("La matrice $A$ est orthogonalement diagonalisable.")) n_pos = [3, 4, 5] n = random.choice(n_pos) sym = bool(random.getrandbits(1)) A = sp.randMatrix(n, symmetric=sym, percent=70, min=-20, max=20) if sp.simplify(A-A.transpose())==sp.zeros(n): sol = True else: sol = False display(Latex("$A = " + latexp(A) + "$")) answer = widgets.RadioButtons(options=["Vrai", "Faux"], description="Réponse : ", disabled=False) display(answer) def f(): if answer.value == "Vrai": answer_value = True else: answer_value = False if answer_value == sol: display(Latex("Correct ! ")) if sol: display(Latex("La matrice $A$ est orthogonalement diagonalisable car elle est symétrique.")) else: display(Latex("La matrice $A$ n'est pas orthogonalement diagonalisable car elle n'est pas symétrique.")) else: display(Latex("Incorrect, changez votre réponse.")) interact_manual(f) def quest_10_4_2(): A = sp.Matrix([[2, -4], [1, -1]]) charpol = A.charpoly().as_expr() * -1 display(Latex("Soit $A$ une matrice carrée ayant pour polynome caractéristique $c_A(\lambda) = " + sp.latex(charpol) + "$")) display(Latex("La matrice $A$ est-elle symétrique ?")) answer = widgets.RadioButtons(options=["Oui", "Pas nécessairement", "Non"], description="Réponse : ", disabled=False) display(answer) sol = "Non" def f(): if answer.value == sol: display(Latex("Correct !")) else: display(Latex("Incorrect.")) interact_manual(f) def f_sol(): display(Latex("Le polynome caractéristique de $A$ admet une ou des racine(s) non réelle(s). " "Donc la matrice $A$ ne peut pas être symétrique.")) display(Latex("Pour afficher la solution détaillée, cliquez-ici.")) im = interact_manual(f_sol) im.widget.children[0].description = 'Solution' def quest_10_4_3(): # Non symmetric values A = sp.Matrix([[0, -1, -4], [0, 0, -2], [0, -2, 0]]) charpol = A.charpoly().as_expr()*-1 charpol = charpol.factor() display(Latex("Soit $A$ une matrice carrée ayant pour polynome caractéristique $c_A(\lambda) = " + sp.latex(charpol) + "$")) display(Latex("La matrice $A$ est-elle symétrique ?")) answer = widgets.RadioButtons(options=["Oui", "Pas nécessairement", "Non"], description="Réponse : ", disabled=False) display(answer) sol = "Pas nécessairement" def f(): if answer.value == sol: display(Latex("Correct !")) else: display(Latex("Incorrect.")) interact_manual(f) def f_sol(): A2 = sp.Matrix([[0, 0, 0], [0, 2, 0], [0, 0, -2]]) display(Latex("On sait que le polynome caractéristique d'une matrice symétrique admet uniquement des racines réelles. " "Or la réciproque est fausse, i.e., les polynomes caractéristiques à racines réelles peuvent être issus de matrices non symétriques. " + nl() + "On voit que le polynome caractéristique $c_A(\lambda)$ a uniquement des racines réelles mais cela ne suffit pas pour conclure que $A$ est symétrique. ")) display(Latex("La bonne réponse est donc: Pas nécessairement")) display(Latex("Dans ce cas précis, les matrices $A_1 =" + latexp(A) + "$ et $A_2 = " + latexp(A2) + "$ ont " "toutes les deux $c_A(\lambda)$ pour polynome caractéristique. On voit que une des matrices est symétrique et l'autre pas.")) display(Latex("Pour afficher la solution détaillée, cliquez-ici.")) im = interact_manual(f_sol) im.widget.children[0].description = 'Solution' def exo_2_1_10_4(): v1 = sp.Matrix([3, 4]) v2 = sp.Matrix([-1, 1/2]) display(Latex("La matrice $A \in M_{2 \\times 2}$ ( $\mathbb{R}$ ) a pour valeur propres $3$ et $-2$. " "$" + latexp(v1) + "\mbox{ et } " + latexp(v2) + "$ sont des vecteurs propres de $A$ respectivement " "associés aux valeurs propres $3$ et $-2$. ")) display(Latex("La matrice $A$ est-elle symétrique ?")) answer = widgets.RadioButtons(options=["Oui", "Non", "Manque d'informations"], description="Réponse : ", disabled=False) display(answer) sol = "Non" def f(): if answer.value == sol: display(Latex("Correct !")) else: display(Latex("Incorrect.")) interact_manual(f) def f_sol(): display(Latex("Les vecteurs propres $" + latexp(v1) + "$ et $" + latexp(v2) + "$ sont associés à des valeurs propres différentes mais ne sont pas orthogonaux. " "La matrice $A$ ne peut donc pas être symétrique.")) display(Latex("Pour afficher la solution détaillée, cliquez ici.")) im = interact_manual(f_sol) im.widget.children[0].description = 'Solution' def exo_2_2_10_4(): v1 = sp.Matrix([1, 0, 2]) v2 = sp.Matrix([-2, 0, -4]) v3 = sp.Matrix([2, 5, -1]) display(Latex("La matrice $A \in M_{3 \\times 3}$ ( $\mathbb{R}$ ) a pour valeur propres $4$ et $2$. " "$" + latexp(v1) + ", " + latexp(v2) + "\mbox{ et } " + latexp(v3) + "$ sont des vecteurs propres de $A$ respectivement " "associés aux valeurs propres $4$, $4$ et $-2$. ")) display(Latex("La matrice $A$ est-elle symétrique ?")) opt = ["Oui", "Non", "Manque d'informations"] answer = widgets.RadioButtons(options=opt, description="Réponse : ", disabled=False) display(answer) sol = opt[2] def f(): if answer.value == sol: display(Latex("Correct !")) else: display(Latex("Incorrect.")) interact_manual(f) def f_sol(): display(Latex("Les vecteurs propres associés à des valeurs propres différentes sont bien orthogonaux. " "Mais on ne connait pas la dimension de l'espace propre associé à $\lambda = 4$ car les deux " "vecteurs donnés dans l'énoncé, $ " + latexp(v1) + " \mbox{ et } " + latexp(v2) + "$, " "sont colinéaires." + nl() + "Pour connaitre la dimension de cette espace, il faudrait une base de ce dernier. " "Cela permettrait de vérifier si la dimension de l'espace est de 2 et si tous les vecteurs de " "cet espace sont orthogonaux aux vecteurs composant l'espace propre associé à $\lambda = 2$. " "Si ces deux conditions étaient vérifiées, la matrice $A$ serait symétrique.")) display(Latex("Il manque donc d'informations pour répondre.")) display(Latex("Pour afficher la solution détaillée, cliquez ici.")) im = interact_manual(f_sol) im.widget.children[0].description = 'Solution' def exo_2_3_10_4(): v1 = sp.Matrix([1, 0, 1]) v2 = sp.Matrix([-2, 0, 1]) v3 = sp.Matrix([0, 3, 0]) display(Latex("La matrice $A \in M_{3 \\times 3}$ ( $\mathbb{R}$ ) a pour valeur propres $-1$, $2$ et $4$. " "$" + latexp(v1) + ", " + latexp(v2) + "\mbox{ et } " + latexp(v3) + "$ sont des vecteurs propres de $A$ respectivement " "associés aux valeurs propres $-1$, $2$ et $4$. ")) display(Latex("La matrice $A$ est-elle symétrique ?")) opt = ["Oui", "Non", "Manque d'informations"] answer = widgets.RadioButtons(options=opt, description="Réponse : ", disabled=False) display(answer) sol = opt[1] def f(): if answer.value == sol: display(Latex("Correct !")) else: display(Latex("Incorrect.")) interact_manual(f) def f_sol(): display(Latex("Les vecteurs propres $" + latexp(v1) + "$ et $" + latexp(v2) + "$ sont associés à des valeurs propres différentes mais ne sont pas orthogonaux. " "La matrice $A$ ne peut donc pas être symétrique.")) display(Latex("Pour afficher la solution détaillée, cliquez ici.")) im = interact_manual(f_sol) im.widget.children[0].description = 'Solution' def exo_2_4_10_4(): v1 = sp.Matrix([1, 0, 1]) v2 = sp.Matrix([-2, 0, 1]) v3 = sp.Matrix([0, 3, 0]) display(Latex("La matrice $A \in M_{3 \\times 3}$ ( $\mathbb{R}$ ) a pour valeur propres $-1$, et $4$. " "$" + latexp(v1) + ", " + latexp(v2) + "\mbox{ et } " + latexp(v3) + "$ sont des vecteurs propres de $A$ respectivement " "associés aux valeurs propres $-1$, $-1$ et $4$. ")) display(Latex("La matrice $A$ est-elle symétrique ?")) opt = ["Oui", "Non", "Manque d'informations"] answer = widgets.RadioButtons(options=opt, description="Réponse : ", disabled=False) display(answer) sol = opt[0] def f(): if answer.value == sol: display(Latex("Correct !")) else: display(Latex("Incorrect.")) interact_manual(f) def f_sol(): base_1 = sp.GramSchmidt([v1, v2], orthonormal=True) base_4 = sp.GramSchmidt([v3], orthonormal=True) display(Latex("Les vecteurs propres $" + latexp(v1) + "$ et $" + latexp(v2) + "$ associés à $\lambda = -1$ sont linéairement indépendant " "et orthogonaux au vecteur propre $" + latexp(v3) + "$ associé à $\lambda = 4$. " "On peut utiliser ces deux ensembles de vecteurs propres pour former des bases des espaces propres " "associés à $\lambda = -1$ et $\lambda = 4$, respectivement. " "On peut othogonaliser et normaliser ces bases avec le schema de Gram-Schmidt.")) display(Latex("On obtient les bases des espaces propres associées respectivement à $\lambda = -1$ et $\lambda = 4$")) display(Latex("$ " + latexp(base_1[0]) + ", " + latexp(base_1[1]) + "\hspace{15mm} " + latexp(base_4[0]) + "$")) display(Latex("On voit que l'espace $V = \mathbb{R}^3$ possède une base othornormée composée de vecteurs propres de $A$. " "La transformation associée à la matrice $A$ est donc orthogonalement diagonalisable et $A$ est donc symétrique.")) display(Latex("Pour afficher la solution détaillée, cliquez ici.")) im = interact_manual(f_sol) im.widget.children[0].description = 'Solution' def ex_3_1_10_4(): l_1 = 2 l_2 = -1 v_1 = sp.Matrix([1, -1]) display(Latex("Trouver une matrice $A \in M_{2 \\times 2} (\mathbb{R})$ symétrique ayant pour valeurs propres 2 " "et -1 et $" + latexp(v_1) + "$ comme vecteur propres associé à $\lambda = 2$.")) default_value_A = str(np.ones((2, 2), dtype=np.int16).tolist()) answer = widgets.Text(value=default_value_A, description='A: ', disabled=False, display='flex') display(answer) def f(): A = eval(answer.value) A = sp.Matrix(A) if A.shape[0] != 2 or A.shape[1] != 2: display(Latex("Incorrect, la matrice doit être carrée et 2x2.")) return if sp.simplify(A - A.transpose()) != sp.zeros(2): display(Latex("Incorrect, la matrice n'est pas symétrique !")) return eig = A.eigenvals() eig_list = list(eig.keys()) if l_1 not in eig_list or l_2 not in eig_list: if l_1 not in eig_list: display(Latex("Incorrect, 2 n'est pas une valeur propre de la matrice rentrée.")) if l_2 not in eig_list: display(Latex("Incorrect, -1 n'est pas une valeur propre de la matrice rentrée.")) return A_v = A*v_1 if sp.simplify(A_v - l_1 * v_1) != sp.zeros(2, 1): display(Latex("Incorrect, le vecteur $" + latexp(v1) + "$ n'est pas un vecteur propre de $A$ associé à " "la valeur propre $\lambda = 2$.")) return display(Latex("Correct !")) interact_manual(f) def f_sol(): display(Latex("On utilise la formule $A=PDP^T$ pour constuire la matrice symetrique $A$. $P$ est une matrice " "orthogonale composée de vecteurs propres de $A$ et $D$ est une matrice diagonale avec les valeurs" " propres de $A$ sur la diagonale. ")) D = sp.Matrix([[2, 0],[0, -1]]) display(Latex("On construit simplement la matrice $D =" + latexp(D) + "$")) v_2 = sp.Matrix([1, 1]) display(Latex("On ne dispose pas d'informations sur les vecteurs propres associés à $\lambda = -1$. " "Mais pour obtenir une matrice symétrique on sait que $P$ est orthogonale, " "donc il faut trouver un vecteur propre orthogonal à $" + latexp(v_1) + "$. Simplement, on prend $" + latexp(v_2) + "$.")) display(Latex("On normalise les deux vecteurs propres orthogonaux et on forme les colonnes de $P$. " "Chaque vecteur est placé dans la même colonne que sa valeur propre correspondante dans $D$.")) P = sp.Matrix([[1, 1], [-1, 1]])/sp.sqrt(2) display(Latex("On obtient $P = " + latexp(P) + "$.")) A = P*D*P.transpose() display(Latex("$A = P D P^T = " + latexp(P) + latexp(D) + latexp(P.transpose()) + "=" + latexp(A) +"$")) display(Latex("Pour afficher la solution détaillée, cliquez ici.")) im = interact_manual(f_sol) im.widget.children[0].description = 'Solution' def ch10_7_ex_1_1(): x1, x2, x3, x4 = sp.symbols("x_1 x_2 x_3 x_4") Q = x1**2 - 5*x1*x2 + x1*x3 - x1*x4 + 4*x2**2 + 2*x2*x3 - 4*x2*x4 + x3**2 + x3*x4 - x4**2 sol = "Oui" display(Latex("Le polynôme $Q = " + sp.latex(Q) + "$ est-il une forme quadratique ?")) answer = widgets.RadioButtons(options=["Oui", "Non"], description="Réponse : ", disabled=False) display(answer) def f(): if answer.value == sol: display(Latex("Correct ! ")) display(Latex("Le polynôme $Q = "+ sp.latex(Q) + "$ est une forme quadratique car " "il contient uniquement des termes d'ordre 2.")) else: display(Latex("Incorrect, changez votre réponse.")) interact_manual(f) def ch10_7_ex_1_2(): x1, x2, x3 = sp.symbols("x_1 x_2 x_3") Q = (x1 + x2)**2 + (x3 - 1)**2 sol = "Non" display(Latex("Le polynôme $Q = " + sp.latex(Q) + "$ est-il une forme quadratique ?")) answer = widgets.RadioButtons(options=["Oui", "Non"], description="Réponse : ", disabled=False) display(answer) def f(): if answer.value == sol: display(Latex("Correct ! ")) display(Latex("Le polynôme $Q = " + sp.latex(Q) + "$ n'est pas une forme quadratique car " "il ne contient pas uniquement des termes d'ordre 2.")) display(Latex("On peut developper $Q$ pour expliciter l'ordre de chaque terme.")) display(Latex("$$ Q = " + sp.latex(Q.expand()) + "$$")) else: display(Latex("Incorrect, changez votre réponse.")) interact_manual(f) def ch10_7_ex_1_3(): x1, x2, x3 = sp.symbols("x_1 x_2 x_3") Q = 3 * x1 ** 2 + x1 * x2 + x2 ** 2 + 2 * x2 * x3 - x1 * x3 + x3 ** 3 sol = "Non" display(Latex("Le polynôme $Q = " + sp.latex(Q) + "$ est-il une forme quadratique ?")) answer = widgets.RadioButtons(options=["Oui", "Non"], description="Réponse : ", disabled=False) display(answer) def f(): if answer.value == sol: display(Latex("Correct ! ")) display(Latex("Le polynôme $Q = " + sp.latex(Q) + "$ n'est pas une forme quadratique car " "il ne contient pas uniquement des termes d'ordre 2.")) else: display(Latex("Incorrect, changez votre réponse.")) interact_manual(f) def ch10_7_ex_2(n): x1, x2, x3, x4, x5 = sp.symbols("x_1 x_2 x_3 x_4 x_5") x_list = [sp.Matrix([x1, x2]), sp.Matrix([x1, x2, x3]), sp.Matrix([x1, x2, x3, x4])] A1 = sp.Matrix([[-2, 3], [3, 4]]) A2 = sp.Matrix([[1, 0, 3], [0, -2, -1/4], [3, -1/4, 4]]) A3 = sp.Matrix([[-1, -1, 3, 0], [-1, -2, 0, 4], [3, 0, 0, -1], [0, 4, -1, 2]]) A_list = [A1, A2, A3] A = A_list[n-1] x = x_list[n-1] Q = x.dot(A * x).expand() display(Latex("Rentrez la matrice symétrique $A$ telle que $\mathbf{x}^T A \mathbf{x} = Q(\mathbf{x})$ " "avec $\mathbf{x} = " + latexp(x) + "$")) display(Latex("où $Q(\mathbf{x}) = " + sp.latex(Q) + "$")) default_value_A = str(np.ones(A.shape, dtype=np.int16).tolist()) answer = widgets.Text(value=default_value_A, description='A = ', disabled=False, layout=widgets.Layout(width='600px')) display(answer) def f(): A_user = eval(answer.value) A_user = sp.Matrix(A_user) display(Latex("Vous avez rentré la matrice $A_{user} = " + latexp(A_user) + "$")) if A_user.shape != A.shape: display(Latex("Incorrect, la matrice $A$ n'a pas les bonnes dimensions.")) return if sp.simplify(A_user - A_user.transpose()) != sp.zeros(A.shape[0]): display(Latex("Incorrect, la matrice rentrée n'est pas symétrique. ")) return Q_user = x.dot(A_user * x).expand() if sp.simplify(Q_user - Q) == 0: display(Latex("Correct !")) else: display(Latex("Incorrect, avec votre matrice on obtient $ Q_{user}(\mathbf{x}) = " + sp.latex(Q_user) + "\\neq Q(\mathbf{x}) $")) interact_manual(f) def f_sol(): display(Latex("La matrice $A = " + latexp(A) + "$ est telle que $Q(\mathbf{x}) = \mathbf{x}^T A \mathbf{x} $")) display(Latex("Pour afficher la solution, cliquez ici.")) im = interact_manual(f_sol) im.widget.children[0].description = 'Solution' def plot_quad(A, n_points=50j, lims=2): A_sp = sp.Matrix(A) eig = A_sp.eigenvects() # Create list with principal axis p_axis = [] for x in eig: v_list = sp.GramSchmidt(x[2], orthonormal=True) for v in v_list: p_axis.append(np.array(v).astype(np.float64).flatten()) A = np.array(A) if A.shape == (3, 3): X, Y, Z = np.mgrid[-lims:lims:n_points, -lims:lims:n_points, -lims:lims:n_points] # ellipsoid values = A[0, 0] * X * X + A[1, 1] * Y * Y + A[2, 2] * Z * Z + (A[0, 1]+A[1, 0])* X * Y + (A[0, 2] + A[2, 0]) * X * Z + (A[1, 2] + A[1, 2]) * Y * Z layout = go.Layout(scene=go.layout.Scene(aspectmode="cube")) fig = go.Figure(data=go.Isosurface( x=X.flatten(), y=Y.flatten(), z=Z.flatten(), value=values.flatten(), isomin=1, isomax=1, showscale=False, opacity=0.5, caps=dict(x_show=False, y_show=False), showlegend=True, name='Quadrique' ), layout=layout) fig.add_trace(go.Scatter3d(x=[0, p_axis[0][0]], y=[0, p_axis[0][1]], z=[0, p_axis[0][2]], line=dict(width=2, color='black'), mode='lines+markers', marker=dict(size=3), showlegend=True, name='Axes principaux', )) fig.add_trace(go.Scatter3d(x=[0, p_axis[1][0]], y=[0, p_axis[1][1]], z=[0, p_axis[1][2]], line=dict(width=2, color='black'), mode='lines+markers', marker=dict(size=3), showlegend=False, name='Principal axis 2', )) fig.add_trace(go.Scatter3d(x=[0, p_axis[2][0]], y=[0, p_axis[2][1]], z=[0, p_axis[2][2]], mode='lines+markers', line=dict(width=2, color='black'), marker=dict(size=3), showlegend=False, name='Principal axis 3', )) elif A.shape == (2, 2): X, Y = np.mgrid[-lims:lims:n_points, -lims:lims:n_points] Z = A[0, 0] * X * X + A[1, 1] * Y * Y + (A[1, 0] + A[0, 1]) * X * Y fig = go.Figure(data=go.Contour( x=X[:, 0], y=Y[0, :], z=Z, contours=dict(start=1, end=1), contours_coloring='lines', line_width=2, opacity=0.5, showscale=False, showlegend=True, name='Quadrique'), ) fig.update_layout(xaxis=dict(range=[-lims, lims], constrain="domain",), yaxis = dict(scaleanchor= "x", scaleratio = 1,)) fig.add_trace(go.Scatter(x=[0, p_axis[0][0]], - y=[0, p_axis[0][1]], - mode='lines+markers', - line=dict(width=2, color='black'), - marker=dict(size=3), - showlegend=True, - name='Axes principaux', - )) + y=[0, p_axis[0][1]], + mode='lines+markers', + line=dict(width=2, color='black'), + marker=dict(size=3), + showlegend=True, + name='Axes principaux', + )) fig.add_trace(go.Scatter(x=[0, p_axis[1][0]], y=[0, p_axis[1][1]], mode='lines+markers', line=dict(width=2, color='black'), marker=dict(size=3), showlegend=False, name = 'Principal axis 2', )) else: return fig.show() def ex1_10_8(n): A_list = [sp.Matrix([[5, 2], [2, 5]]), sp.Matrix([[3, 2, 0], [2, 0, 0], [0, 0, 2]])] x1, x2, x3 = sp.symbols("x_1 x_2 x_3") x_list = [sp.Matrix([x1, x2]), sp.Matrix([x1, x2, x3])] A = A_list[n-1] x = x_list[n-1] Q = x.dot(A * x).expand() display(Latex("$Q(x) = " + sp.latex(Q) + "$")) display(Latex("Donnez les coefficients $d_1, ..., d_n$ et la matrice $S$ de changement de variable tel " "que $x = Sy$. ")) default_value_d = str(np.ones(A.shape[0], dtype=np.int16).tolist()) default_value_S = str(np.ones(A.shape, dtype=np.int16).tolist()) answer_d = widgets.Text(value=default_value_d, description='d = ', disabled=False, layout=widgets.Layout(width='600px')) answer_S = widgets.Text(value=default_value_S, description='S = ', disabled=False, layout=widgets.Layout(width='600px')) display(answer_d) display(answer_S) def f(): d_user = eval(answer_d.value) d_user = np.array(d_user, dtype=np.int16) D_user = np.diag(d_user) D_user = sp.Matrix(D_user) S_user = eval(answer_S.value) S_user = sp.Matrix(S_user) display(Latex("Vous avez rentré la matrice suivante: $S_{user} = " + latexp(S_user) + "$")) A_user = S_user * D_user * S_user.transpose() if sp.simplify(A-A_user) == sp.zeros(A.shape[0]): display(Latex("Correct !")) else: display(Latex("Incorrect.")) interact_manual(f) def f_sol(): display(Latex("On commence par trouver la matrice symétrique $A$ telle que $Q(x) = x^T A x$ avec " "$x = " + latexp(x) + "$.")) display(Latex("Par identification, on trouve $A = " + latexp(A) + "$.")) display(Latex("Ensuite, l'exercice consiste simplement à diagonaliser orthogonalement la matrice symétrique " "$A$.")) display(Latex("En effet, si on a $D = S^T A S$, avec $D$ diagonale, en effectuant le changement de variable " "$x = Sy$, on obtient : " + nl() + " $Q(x) = x^T A x = (Sy)^T A (Sy) = y^T S^T A S y = y^T D y = " "d_1 y_1^2 + d_2 y_2^2 + ... + d_n y_n^2 $ ")) lamda = sp.symbols('lamda') poly_char_exp = sp.expand(A.charpoly(lamda).as_expr()) poly_char_fac = sp.factor(A.charpoly(lamda).as_expr()) poly_char_exp_str = sp.latex(poly_char_exp) poly_char_fac_str = sp.latex(poly_char_fac) display(Latex("Le polynôme caractéristique de $A$ s'exprime comme: $c_A (t) = " + poly_char_exp_str + "$.")) display(Latex("On trouve les racines du polynôme caractéristique et on factorise. On obtient $c_A (t) = " + poly_char_fac_str + "$.")) eig = A.eigenvals() eig_list_ = list(eig.keys()) mult_list_ = list(eig.values()) display(Latex("On obtient donc les valeurs propres $\lambda$ et leur multiplicité respective $m$: " " $ \lambda = " + sp.latex(eig_list_) + " \hspace{10mm} m = " + sp.latex(mult_list_) + "$.")) display(Markdown("**On trouve une base orthonormée pour tous les espaces propres.**")) final_basis = [] P = sp.Matrix([]) k = 0 for l in eig_list_: basis_orthonorm = [] basis, basic_idx, free_idx = eigen_basis(A, l, prop_basis=None, disp=True, return_=True, dispA=False) for v in basis: # if all ints if np.all(v == np.round(v)): v = v.astype(np.int16) # if there is some float else: for idx, el in enumerate(v): v = sp.Matrix(v) q = sp.Rational(el) # If rational are not too high and weird if abs(q.numerator()) < 100 and abs(q.denominator()) < 100: v[idx] = q basis_orthonorm.append(sp.Matrix(v)) basis_orthonorm = sp.GramSchmidt(basis_orthonorm, True) for v in basis_orthonorm: final_basis.append(v) P = P.col_insert(k, v) k += 1 display( Latex("On applique le procédé de Gram-Schmidt pour obtenir des vecteurs de norme 1 et orthogonaux. " "On obtient $" + sp.latex(basis_orthonorm) + "$")) display(Latex("Finalement, on construit la matrice $S$ en utilisant chaque vecteur de base " "trouvé précedemment comme colonne de cette matrice. Cette dernière est bien orthogonale car " "les vecteurs de base sont orthogonaux entre eux et tous de norme unitaire. " "On construit la matrice $D$ en plaçant les valeurs propres de $A$ sur la diagonale. " "Le placement des valeurs propres sur la diagonale de $D$ " "doit correspondre avec celui des vecteurs propres dans $S$.")) D = sp.zeros(A.shape[0]) i = 0 for idx in range(len(eig_list_)): for _ in range(mult_list_[idx]): D[i, i] = eig_list_[idx] i += 1 display( Latex("On obtient $S = " + latexp(P) + "\hspace{5mm} \mbox{et} \hspace{5mm} D = " + latexp(D) + "$")) display(Latex("On vérifie le résultat par un calcul :")) display(Latex( "$S D S^T = " + latexp(P) + latexp(D) + latexp(P.transpose()) + " = " + latexp(P * D * P.transpose()) + "=A$")) display(Latex("Pour afficher la solution, cliquez ici.")) im = interact_manual(f_sol) im.widget.children[0].description = 'Solution' def f_plot(): A_np = np.array(A, dtype=np.float64) plot_quad(A_np) if A.shape[0]==2 or A.shape[0]==3: display(Latex("Pour visualiser la quadrique associée et les axes principaux, cliquez ici")) im = interact_manual(f_plot) im.widget.children[0].description = 'Plot' \ No newline at end of file diff --git "a/Chapitre 4 - Bases et dimension/4.11. Coordonn\303\251es par rapport \303\240 une base.ipynb" "b/Chapitre 4 - Bases et dimension/4.11. Coordonn\303\251es par rapport \303\240 une base.ipynb" index 5e59aaf..335d8a1 100644 --- "a/Chapitre 4 - Bases et dimension/4.11. Coordonn\303\251es par rapport \303\240 une base.ipynb" +++ "b/Chapitre 4 - Bases et dimension/4.11. Coordonn\303\251es par rapport \303\240 une base.ipynb" @@ -1,302 +1,305 @@ { "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from Ch4Functions import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Concept(s)-clé(s)\n", "\n", "### DÉFINITION 1 :\n", - "Soient $V$ un $\\mathbb{R}$ -espace vectoriel de dimension finie $n, \\mathscr{B}=\\left(v_{1}, \\ldots, v_{n}\\right)$ une base ordonnée de $V$ et $v \\in V$. Comme $\\mathscr{B}$ est une base de $V,$ il existe des uniques scalaires $\\alpha_{1}, \\ldots, \\alpha_{n} \\in \\mathbb{R}$ tels que $v=\\alpha_{1} v_{1}+\\cdots+\\alpha_{n} v_{n} .$ On appelle $\\alpha_{1}, \\ldots, \\alpha_{n}$ les coordonnées de $v$ par rapport $\\dot{a}$ la base $\\mathscr{B}$ et on écrit\n", + "Soient $V$ un $\\mathbb{R}$-espace vectoriel de dimension finie $n, \\mathscr{B}=\\left(v_{1}, \\ldots, v_{n}\\right)$ une base ordonnée de $V$ et $v \\in V$. Comme $\\mathscr{B}$ est une base de $V,$ il existe des uniques scalaires $\\alpha_{1}, \\ldots, \\alpha_{n} \\in \\mathbb{R}$ tels que $v=\\alpha_{1} v_{1}+\\cdots+\\alpha_{n} v_{n} .$ On appelle $\\alpha_{1}, \\ldots, \\alpha_{n}$ les coordonnées de $v$ par rapport $\\dot{a}$ la base $\\mathscr{B}$ et on écrit\n", "$$\n", "[v]_{\\mathscr{B}}=\\left(\\begin{array}{c}\n", "\\alpha_{1} \\\\\n", "\\alpha_{2} \\\\\n", "\\vdots \\\\\n", "\\alpha_{n}\n", "\\end{array}\\right)\n", "$$\n", "\n", "### PROPOSITION 2 :\n", "Soient $V$ un $\\mathbb{R}$-espace vectoriel de dimension finie $n$ et $\\mathscr{B}=\\left(v_{1}, \\ldots, v_{n}\\right)$ une base ordonnée de $V$. Alors les deux affirmations suivantes sont vérifiées.\n", "1. Pour tous $v_{1}, v_{2} \\in V,$ on a $\\left[v_{1}+v_{2}\\right]_{\\mathscr{B}}=\\left[v_{1}\\right]_{\\mathscr{B}}+\\left[v_{2}\\right]_{\\mathscr{B}}$\n", "2. Pour tout $v \\in V$ et tout $\\lambda \\in \\mathbb{R},$ on a $[\\lambda v]_{\\mathscr{B}}=\\lambda[v]_{\\mathscr{B}}$." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercice 1:\n", "\n", - "Soit $\\mathbb{R}^2$ l'espace du plan. La base la plus évidente de cet espace vectoriel est la base orthonormée $\\mathscr{B} = \\left\\{\\left(\\begin{array}{l}1 \\\\ 0 \\end{array}\\right),\\left(\\begin{array}{l}0 \\\\ 1 \\end{array}\\right)\\right\\}$. Cette base est représentée dans le graphique suivant." + "Soit $\\mathbb{R}^2$ l'espace du plan. La base la plus évidente de cet espace vectoriel est la base canonique $\\mathscr{B} = \\left\\{\\left(\\begin{array}{l}1 \\\\ 0 \\end{array}\\right), \\left(\\begin{array}{l}0 \\\\ 1 \\end{array}\\right)\\right\\}$. Cette base est représentée dans le graphique suivant." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "#ici un graph pas distordu (graph 1)" + "ch4_11_plot(show_can_base=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Quelle base de $\\mathbb{R}^2$ est représentée ci-dessous?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "#ici un graph avec grille distordue (graph 2)" + "ch4_11ex1_plot()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Entrez les vecteurs qui forment la base réprésentée ci-dessus\n", "# Par exemple : [[1, 2], [3, 4]]\n", - "base = [[-2,1],[4,1]]\n", + "base = [[0, 0],[0, 0]]\n", "\n", "ch4_11ex1(base)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercice 2\n", "\n", - "a) Soit le vecteur $\\textbf{v}$ représenté dans le graph suivant, $\\mathscr{B}_1$ la base orthonormée de $\\mathbb{R}^2$ et $\\mathscr{B}_2 = ((1,2),(3,2))$. Quelles sont les coordonnées de de $\\textbf{v}$ dans $\\mathscr{B}_1$? " + "a) Soit le vecteur $\\textbf{v}$ représenté dans le graph suivant, $\\mathscr{B}_1$ la base canonique de $\\mathbb{R}^2$ et $\\mathscr{B}_2 = \\left\\{\\left(\\begin{array}{l}1 \\\\ 2 \\end{array}\\right),\\left(\\begin{array}{l}3 \\\\ 2 \\end{array}\\right)\\right\\}$. Quelles sont les coordonnées de de $\\textbf{v}$ dans $\\mathscr{B}_1$? " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "#ici graph avec v desssus (graph 3)" + "#ici graph avec v desssus (graph 3)\n", + "ch4_11ex2a_plot()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Entrez les coordonnées du vecteur v dans la base B1\n", "# Par exemple : [1,2]\n", - "vB1 = [5,6]\n", + "vB1 = [0, 0]\n", "\n", "ch4_11ex2aB1(vB1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Et dans $\\mathscr{B}_2$?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Entrez les coordonnées du vecteur v dans la base B2\n", "# Par exemple : [1,2]\n", - "vB2 = [2,1]\n", + "vB2 = [0, 0]\n", "\n", "ch4_11ex2aB2(vB2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "b) Avec les mêmes bases, quelles sont les coordonnées du vecteur $\\textbf{u}$ dans $\\mathscr{B}_1$?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "#ici graph avec u desssus (graph 4)" + "#ici graph avec u desssus (graph 4)\n", + "ch4_11ex2b_plot()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Entrez les coordonnées du vecteur u dans la base B1\n", "# Par exemple : [1,2]\n", - "uB1 = [8,4]\n", + "uB1 = [0, 0]\n", "\n", "ch4_11ex2bB1(uB1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Et dans $\\mathscr{B}_2$?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Entrez les coordonnées du vecteur u dans la base B2\n", "# Par exemple : [1,2]\n", - "uB2 = [-1,3]\n", + "uB2 = [0, 0]\n", "\n", "ch4_11ex2bB2(uB2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "c) Toujours avec les mêmes bases, quelles sont les coordonnées du vecteur $\\textbf{w}$ dans $\\mathscr{B}_1$?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "#ici graph avec w desssus (graph 5)" + "#ici graph avec w desssus (graph 5)\n", + "ch4_11ex2c_plot()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Entrez les coordonnées du vecteur w dans la base B1\n", "# Par exemple : [1,2]\n", - "wB1 = [5,4]\n", + "wB1 = [0, 0]\n", "\n", "ch4_11ex2cB1(wB1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Et dans $\\mathscr{B}_2$?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Entrez les coordonnées du vecteur w dans la base B2\n", "# Par exemple : [1,2]\n", - "wB2 = [.5,1.5]\n", + "wB2 = [0, 0]\n", "\n", "ch4_11ex2cB2(wB2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercice 3\n", "\n", - "Considérons maintenant le vecteur $\\textbf{s}$ tel que $\\textbf{s} = \\textbf{v}+\\textbf{u}$. A l'aide de la proposition 2 et de l'exerciceprécédent, déduire les coordonnées de $\\textbf{s}$ dans $\\mathscr{B}_1$." + "Considérons maintenant le vecteur $\\textbf{s}$ tel que $\\textbf{s} = \\textbf{v}+\\textbf{u}$. A l'aide de la proposition 2 et de l'exercice précédent, déduire les coordonnées de $\\textbf{s}$ dans $\\mathscr{B}_1$." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Entrez les coordonnées du vecteur s dans la base B1\n", "# Par exemple : [1,2]\n", - "sB1 = [13,10]\n", + "sB1 = [0, 0]\n", "\n", "ch4_11ex3B1(sB1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Et dans $\\mathscr{B}_2$?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Entrez les coordonnées du vecteur s dans la base B2\n", "# Par exemple : [1,2]\n", - "sB2 = [1,4]\n", + "sB2 = [0, 0]\n", "\n", "ch4_11ex3B2(sB2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[Passez au notebook du chapitre 4.12. Trouver une base à partir d'un système générateur](./4.12.%20Trouver%20une%20base%20%C3%A0%20partir%20d'un%20syst%C3%A8me%20g%C3%A9n%C3%A9rateur.ipynb)" ] } ], "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": 4 } diff --git a/Chapitre 4 - Bases et dimension/Ch4Functions.py b/Chapitre 4 - Bases et dimension/Ch4Functions.py index e7f31eb..789a587 100644 --- a/Chapitre 4 - Bases et dimension/Ch4Functions.py +++ b/Chapitre 4 - Bases et dimension/Ch4Functions.py @@ -1,1257 +1,1404 @@ import sys sys.path.insert(0,'..') import Librairie.AL_Fct as al sys.path.pop(0) import numpy as np from IPython.display import display, Markdown, Latex import plotly.graph_objs as go import plotly import ipywidgets as widgets from ipywidgets import interact, interactive, fixed, interact_manual, Layout, VBox, HBox import plotly.express as px import sympy as sp import matplotlib.pyplot as plt from itertools import permutations from IPython.display import display, Latex, Markdown def ch4_1_2ex1(solution): v = np.array([[1, 0, 2], [0, 1, 0], [1, 1, 1]]).transpose() e = np.array([3, 5, 4]) s = np.array(solution) r = v @ s if np.allclose(e, r): display(Markdown("**Correction:** C'est correct!")) else: display(Markdown("**Correction:** C'est incorrect car: $\lambda_1 v_1 + \lambda_2 v_2 + \lambda_3 v_3 = \\begin{pmatrix} %s \\\\ %s \\\\ %s \end{pmatrix} \\neq \\begin{pmatrix} %s \\\\ %s \\\\ %s \end{pmatrix}$" % (r[0], r[1], r[2], e[0], e[1], e[2]))) w = s * v cumsum = np.cumsum(np.insert(w, 0, 0, axis=1), axis=1).transpose() colors = px.colors.qualitative.Plotly global color_index color_index = 0 data = [] def addVector(start, v): global color_index color = colors[color_index] color_index = (color_index + 1) % len(colors) end = start + v trace = go.Scatter3d( x=[start[0], end[0], None], y=[start[1], end[1], None], z=[start[2], end[2], None], mode='lines', name=str(v), line=dict(color=color, width=4) ) norm = np.sqrt(np.sum(v * v)) n = v if norm == 0 else v / norm n = 1.5 * n c_end = end - 0.37 * n cone = go.Cone(x=[c_end[0]], y=[c_end[1]], z=[c_end[2]], u=[n[0]], v=[n[1]], w=[n[2]], name=str(v), colorscale=[[0, color], [1, color]], hoverinfo="none", showscale=False) data.append(trace) data.append(cone) addVector(np.zeros(3), e) for i in range(len(cumsum) - 1): start = cumsum[i] v = cumsum[i + 1] - start addVector(start, v) fig = go.Figure(data=data) fig.show() def ch4_1_2ex2(): radio = widgets.RadioButtons( options=['Oui, les vecteurs sont dépendants', 'Non, les vecteurs sont indépendants'], layout={'width': 'max-content'}, value=None, description='Réponse:', ) button = widgets.Button(description='Vérifier') out = widgets.Output() display(radio) display(button) display(out) def verification_2(e): if radio.value is not None: out.clear_output() with out: if radio.value.startswith('Non'): display(Markdown("C'est incorrect, il existe $\lambda_1$, $\lambda_2$ et $\lambda_3$ tels que $\lambda_1 v_1 + \lambda_2 v_2 + \lambda_3 v_3 - \\begin{pmatrix} 3 \\\\ 0 \\\\ 4 \end{pmatrix} = 0$.")) else: display(Markdown("C'est correct!")) button.on_click(verification_2) def ch4_1_2ex3(answer): radio = widgets.RadioButtons( options=['Oui, les vecteurs sont dépendants', 'Non, les vecteurs sont indépendants'], layout={'width': 'max-content'}, value=None, description='Réponse:', ) button = widgets.Button(description='Vérifier') out = widgets.Output() display(radio) display(button) display(out) def verification_3(e): if radio.value is not None: out.clear_output() with out: if radio.value.startswith('Oui') == answer: display(Markdown("C'est correct!")) else: display(Markdown("C'est incorrect!")) button.on_click(verification_3) def ch4_1_2ex3a(): ch4_1_2ex3(True) def ch4_1_2ex3b(): ch4_1_2ex3(True) def ch4_1_2ex3c(): ch4_1_2ex3(False) def ch4_3ex1(answer, reason, callback, options=['Oui, les vecteurs forment une base', 'Non, les vecteurs ne forment pas une base']): radio = widgets.RadioButtons( options=options, layout={'width': 'max-content'}, value=None, description='Réponse:', ) button = widgets.Button(description='Vérifier') out = widgets.Output() display(radio) display(button) display(out) def verification(e): if radio.value is not None: out.clear_output() with out: if options.index(radio.value) == answer: display(Markdown("C'est correct!
%s" % reason)) else: display(Markdown("C'est incorrect!
%s" % reason)) callback() button.on_click(verification) def plot_vectors(vectors, selected, solution): v = np.array(vectors).transpose() e = np.array(selected) s = np.array(solution) r = v @ s w = s * v cumsum = np.cumsum(np.insert(w, 0, 0, axis=1), axis=1).transpose() colors = px.colors.qualitative.Plotly global color_index color_index = 0 data = [] def addVector(start, v): global color_index color = colors[color_index] color_index = (color_index + 1) % len(colors) end = start + v trace = go.Scatter3d( x=[start[0], end[0], None], y=[start[1], end[1], None], z=[start[2], end[2], None], mode='lines', name=str(v), line=dict(color=color, width=4) ) norm = np.sqrt(np.sum(v * v)) n = v if norm == 0 else v / norm n = 0.5 * n c_end = end - 0.37 * n cone = go.Cone(x=[c_end[0]], y=[c_end[1]], z=[c_end[2]], u=[n[0]], v=[n[1]], w=[n[2]], name=str(v), colorscale=[[0, color], [1, color]], hoverinfo="none", showscale=False) data.append(trace) data.append(cone) addVector(np.zeros(3), e) for i in range(len(cumsum) - 1): start = cumsum[i] v = cumsum[i + 1] - start addVector(start, v) fig = go.Figure(data=data) fig.show() def ch4_3ex1a(): ch4_3ex1(1, """ En effet, les quatres vecteurs ne sont pas linéairement indépendants (Déf. 1-2) car il est possible d'exprimer l'un avec une combinaison linéaire des autres. Par exemple : $$\\begin{pmatrix} 1 \\\\ 1 \\\\ 1 \end{pmatrix} = \\begin{pmatrix} 1 \\\\ 0 \\\\ 1 \end{pmatrix} + \\frac{1}{2} \\begin{pmatrix} 0 \\\\ 2 \\\\ 0 \end{pmatrix} + 0 \\begin{pmatrix} 0 \\\\ 0 \\\\ 3 \end{pmatrix}$$ Comme tous les vecteurs sont issus de $\mathbb{R}^3$ on peut facilement représenter la combinaison dans l'espace : """, lambda: plot_vectors([[1, 0, 1], [0, 2, 0], [0, 0, 3]], [1, 1, 1], [1, 0.5, 0])) def ch4_3ex1b(): ch4_3ex1(1, """ On ne peut pas générer $\mathbb{R}^3$ à partir de cet ensemble. En effet, on ne peut par exemple pas obtenir le vecteur $\\begin{pmatrix} 1 \\\\ 0 \\\\ 0 \end{pmatrix} \\in \mathbb{R}^3$ avec une combinaison linéaire de $\\begin{pmatrix} 1 \\\\ 0 \\\\ 1 \end{pmatrix}$ et $\\begin{pmatrix} 0 \\\\ 1 \\\\ 0 \end{pmatrix}$. Graphiquement les deux vecteurs ne peuvent engendrer qu'un plan: """, lambda: plot_vectors([[1, 0, 0]], [0, 1, 0], [1])) def ch4_3ex1c(): ch4_3ex1(0, """ Ces trois vecteurs sont linéairement indépendants, ils engendrent donc $\mathbb{R}^3$ et forment une base de cet espace. """, lambda: None) def ch4_3ex2(): vecs = np.array([[1, 1, 1], [0, 1, 2], [2, 1, 4], [2, 1, 0], [1, 0, -1]]) select = widgets.SelectMultiple( options=['v1', 'v2', 'v3', 'v4', 'v5'], description='Sélection :', disabled=False ) button = widgets.Button(description='Vérifier') out = widgets.Output() def callback(e): answer = [int(v[1:])-1 for v in select.value] out.clear_output() with out: if len(answer) == 0: # Empty pass elif len(answer) < 3: display(Markdown("C'est incorrect!
La solution entrée ne permet pas d'engendrer $\mathbb{R}^3$.")) elif len(answer) > 3: display(Markdown("C'est incorrect!
La solution entrée contient des vecteurs qui sont dépendants.")) else: mat = np.array([vecs[answer[0]], vecs[answer[1]], vecs[answer[2]]]).transpose() det = np.linalg.det(mat) if det == 0: display(Markdown("C'est incorrect!
La solution entrée contient des vecteurs qui sont dépendants.")) else: # Correct display(Markdown("C'est correct!
Il s'agit d'_une_ base de $\mathbb{R}^3$.")) button.on_click(callback) display(select) display(button) display(out) def ch4_3ex3(): ch4_3ex1(1, """ Cet ensemble n'est pas une base de $\mathbb{P}^n(\mathbb{R})$ car il ne permet pas (par exemple) de générer les polynômes constants. $\mathbb{P}^n(\mathbb{R})$ est néanmoins engendré par $\{1, x, x^2, x^3, ..., x^{n-1}\}$. """, lambda: None) def ch4_3ex4(): ch4_3ex1(2, """ L'espace engendré par cet ensemble est $M_{2 \\times 2}(\mathbb{R})$ et donc sa dimension est $4$. Attention cet ensemble n'est pas une base de $M_{2 \\times 2}(\mathbb{R})$ car ses éléments sont linéairement dépendants ! """, lambda: None, ['2', '3', '4', '5']) def ch4_4_5ex1(): vs = np.array([[1, 1, 1], [2, 0, 3], [4, 0, 0], [1, 0, 0]]) select = widgets.SelectMultiple( options=['v1', 'v2', 'v3', 'v4'], description='Sélection :', disabled=False ) button = widgets.Button(description='Vérifier') out = widgets.Output() def callback(e): answer = [int(v[1:])-1 for v in select.value] out.clear_output() with out: if len(answer) == 0: # Empty pass elif len(answer) < 3: display(Markdown("C'est incorrect!
La solution entrée ne permet pas d'engendrer $\\mathbb{R}^3$, et n'est donc pas une base.")) elif len(answer) > 3: display(Markdown("C'est incorrect!
La solution entrée engendre $\\mathbb{R}^3$ mais n'est pas une base.")) else: mat = np.array([vs[answer[0]], vs[answer[1]], vs[answer[2]]]).transpose() if np.linalg.matrix_rank(mat) != len(mat): display(Markdown("C'est incorrect!
La solution entrée ne permet pas d'engendrer $\\mathbb{R}^3$, et n'est donc pas une base.")) else: # Correct display(Markdown("C'est correct!
Il s'agit d'_une_ base de $\\mathbb{R}^3$.")) button.on_click(callback) display(select) display(button) display(out) def ch4_4_5ex2(v): v = np.array(v) vs = np.array([[1, 4, 3, 0], [1, 0, 0, 1], [0, 1, 1, 0], v.flatten()]) is_base = np.linalg.matrix_rank(vs) == len(vs) out = widgets.Output() display(out) with out: if is_base: display(Markdown("C'est correct!")) else: display(Markdown("C'est incorrect, ce vecteur ne permet pas de former une base.")) def ch4_6ex1(): text = widgets.IntText( description='Réponse :', disabled=False ) button = widgets.Button(description='Vérifier') out = widgets.Output() def callback(e): out.clear_output() r = text.value feedback = "" is_correct = False if r == 6: feedback = "Comme la matrice n'est pas nulle, au moins une variable n'est pas libre." elif r >= 7: feedback = "La dimension de l'espace des solutions ne peut excéder la dimension de l'espace des variables." elif r == 5: is_correct = True feedback = "Le nombre maximal de variables libres dans ce système est $5$. Par la proposition 1 on en déduit la dimension maximale de l'espace des solutions du système homogène $AX = 0$." elif r >= 2 and r <= 4: feedback = "Ce n'est pas le nombre maximal de variables libres dans ce système." elif r <= 1: feedback = "Le nombre maximal de variables libres dans ce système ne peut être inférieur à $2$ ($\\text{nb. colonnes} - \\text{nb. lignes}$)." correct_text = "C'est correct!
" incorrect_text = "C'est incorrect.
" with out: display(Markdown((correct_text if is_correct else incorrect_text) + feedback)) button.on_click(callback) display(text) display(button) display(out) def ch4_6ex2(): text = widgets.IntText( description='Réponse :', disabled=False ) button = widgets.Button(description='Vérifier') out = widgets.Output() def callback(e): out.clear_output() r = text.value with out: if r == 2: display(Markdown("C'est correct!
Le nombre de variables libres est $2$, par la proposition 1 on trouve la dimension de l'espace des solutions.")) else: display(Markdown("C'est incorrect.")) button.on_click(callback) display(text) display(button) display(out) def ch4_7_8ex3_venn(): ax = plt.gca() r = 5 rd = r / 2 rc = rd * 2 f = 25 a = plt.Circle((-rd, 0), radius=r, color="#fc032c90") b = plt.Circle((rd, 0), radius=r, color="#0377fc90") ax.add_patch(a) ax.add_patch(b) ax.annotate("A", xy=(-rc, 0), fontsize=f, ha='center', va='center') ax.annotate("A ∩ B", xy=(0, 0), fontsize=f, ha='center', va='center') ax.annotate("B", xy=(rc, 0), fontsize=f, ha='center', va='center') plt.axis('scaled') plt.axis('off') plt.show() def ch4_6ex3(base): base = np.array(base) out = widgets.Output() display(out) with out: out.clear_output() feedback = "" is_correct = False s = base.shape if len(base) == 0: feedback = "L'ensemble ne peut pas être vide." elif len(s) != 2 or s[1] != 5: feedback = "Le format des vecteurs n'est pas bon." elif s[0] < 2: feedback = "L'ensemble entré ne contient pas assez de vecteurs pour engendrer toutes les solutions du système." elif s[0] > 2: feedback = "L'ensemble entré n'est pas une base." else: expected = np.array(sp.Matrix([[6, 1, -2, 0, 1], [8, 2, -3, 1, 0]]).rref()[0]) actual = np.array(sp.Matrix(base).rref()[0]) if not np.array_equal(actual, expected): feedback = "L'ensemble entré n'engendre pas l'espace solution du système." else: is_correct = True correct_text = "C'est correct!
" incorrect_text = "C'est incorrect.
" display(Markdown((correct_text if is_correct else incorrect_text) + feedback)) def ch4_7_8ex1(): select = widgets.SelectMultiple( options=['0', '1', '2', '3', '4', '5'], description='Réponse :', disabled=False ) button = widgets.Button(description='Vérifier') out = widgets.Output() display(select) display(button) display(out) def verification(e): if len(select.value) > 0: out.clear_output() with out: other = "
La dimension de l'espace des solutions dépend du nombre de variables libres : dans ce système celle-ci peut être au plus $5-3=2$." if select.value != ('0', '1', '2'): display(Markdown("C'est incorrect!" + other)) else: display(Markdown("C'est correct." + other)) button.on_click(verification) def ch4_7_8ex2(): text = widgets.IntText(description='Réponse :') button = widgets.Button(description='Vérifier') out = widgets.Output() def callback(e): out.clear_output() r = text.value with out: other = "
En effet, comme la solution de $S_1$ est un plan les deux équations sont dépendantes. La solution de $S_2$ est donc aussi un plan, donc sa dimension est $2$." if r == 2: display(Markdown("C'est correct!" + other)) else: display(Markdown("C'est incorrect." + other)) button.on_click(callback) display(text) display(button) display(out) def ch4_7_8ex3_cube(name, color): return go.Mesh3d( name=name, x=[-1, -1, 1, 1, -1, -1, 1, 1], y=[-1, 1, 1, -1, -1, 1, 1, -1], z=[-1, -1, -1, -1, 1, 1, 1, 1], i=[7, 0, 0, 0, 4, 4, 6, 6, 4, 0, 3, 2], j=[3, 4, 1, 2, 5, 6, 5, 2, 0, 1, 6, 3], k=[0, 7, 2, 3, 6, 7, 1, 1, 5, 5, 7, 6], color=color, opacity=0.25 ) def ch4_7_8ex3_plane(name, color, variant): ep = 1.25 p1 = ep * np.array([-1, 1, 1, -1]) p2 = ep * np.array([-1, -1, 1, 1]) pz = np.array([0, 0, 0, 0] if variant == 0 else [0, 0.01, 0.02, 0.03]) # Bug workaround ps = list(permutations([p1, p2, pz]))[variant] return go.Mesh3d( name=name, x=ps[0], y=ps[1], z=ps[2], color=color, opacity=0.25 ) def ch4_7_8ex3_line(name, color, variant): el = 1.5 l1 = [-el, el, None] lz = [0, 0, None] ps = list(permutations([l1, lz, lz]))[variant] return go.Scatter3d( name=name, x=ps[0], y=ps[1], z=ps[2], opacity=0.25, line=dict(color=color, width=4) ) def ch4_7_8ex3(answer, explanation, plot): text = widgets.IntText(description='Réponse :') button = widgets.Button(description='Vérifier') show = widgets.Button(description='Visualiser') box = widgets.HBox(children=[button, show]) out = widgets.Output() out2 = widgets.Output() def callback(e): out.clear_output() r = text.value with out: other = "
" + explanation if r == answer: display(Markdown("C'est correct!" + other)) else: display(Markdown("C'est incorrect." + other)) def callback2(e): with out2: plot() button.on_click(callback) show.on_click(callback2) display(text) display(box) display(out) display(out2) def ch4_7_8ex3a(): ch4_7_8ex3(2, "$V$ est un sous-ensemble de $W$, donc $\dim (W + V) = \dim W = 2$.", lambda: go.Figure(data=[ch4_7_8ex3_plane('A', 'red', 0), ch4_7_8ex3_line('B', 'blue', 0)]).show()) def ch4_7_8ex3b(): ch4_7_8ex3(3, "$W$ et $V$ sont deux espaces indépendants, donc $\dim (W + V) = \dim W + \dim V = 2 + 1 = 3$.", lambda: go.Figure(data=[ch4_7_8ex3_plane('A', 'red', 0), ch4_7_8ex3_line('B', 'blue', 3)]).show()) def ch4_7_8ex3c(): ch4_7_8ex3(1, "La somme d'un même espace n'a pas d'effet : $\dim (V + V) = \dim V = 1$.", lambda: go.Figure(data=[ch4_7_8ex3_line('A', 'red', 0), ch4_7_8ex3_line('B', 'blue', 0)]).show()) def ch4_7_8ex3d(): ch4_7_8ex3(2, "$V_1$ et $V_2$ sont deux espaces indépendants, donc $\dim (V_1 + V_2) = \dim V_1 + \dim V_2 = 1 + 1 = 2$.", lambda: go.Figure(data=[ch4_7_8ex3_line('A', 'red', 0), ch4_7_8ex3_line('B', 'blue', 2)]).show()) def ch4_7_8ex3e(): ch4_7_8ex3(3, "$\dim (W_1 + W_2) = 2 + 2 - 1 = 3$.", lambda: go.Figure(data=[ch4_7_8ex3_plane('A', 'red', 0), ch4_7_8ex3_plane('B', 'blue', 1)]).show()) def ch4_7_8ex3f(): ch4_7_8ex3(3, "$\dim (U + X) = 0 + 3 - 0 = 3$.", lambda: go.Figure(data=[ch4_7_8ex3_cube('B', 'blue')]).show()) def ch4_9ex1(): r = ['Le rang ligne de 𝐴 est plus petit ou égal à 2 car c\'est un sous-espace vectoriel de ℝ2.', 'Le rang ligne de 𝐴 est plus petit ou égal à 3 car c\'est un sous-espace vectoriel de ℝ3.', 'Le rang ligne de 𝐴 est plus petit ou égal à 3 car engendré par 3 vecteurs.', 'Le rang ligne de 𝐴 est plus petit ou égal à 2 car engendré par 2 vecteurs.', 'Le rang colonne de A est plus petit ou égal à 2.'] buttons = [] for i in range(5): b = widgets.ToggleButton( value=False, description=r[i], disabled=False, button_style='', # 'success', 'info', 'warning', 'danger' or '' tooltip='Description', layout=Layout(width='auto', height='auto') ) buttons.append(b) button = widgets.Button(description='Vérifier', layout=Layout(width='auto', height='auto'), button_style='info' ) def callback(e): out.clear_output() with out: if (buttons[0].value or buttons[2].value): print('Mauvaise réponse. \nAttention à ne pas confondre les espaces des lignes et colonnes') elif (not buttons[1].value) or (not buttons[3].value) or (not buttons[4].value): print('Il manque au moins une réponse.') elif (buttons[1].value and buttons[3].value and buttons[4].value): print('Correct !') buttons.append(button) buttons[5].on_click(callback) box = VBox(children = buttons) out = widgets.Output() display(box) display(out) def ch4_9ex2_1(): text = widgets.IntText( description='Réponse :', disabled=False ) button = widgets.Button(description='Vérifier') out = widgets.Output() def callback(e): out.clear_output() r = text.value with out: if r == 2: display(Markdown("Correct!")) elif r > 2: display(Markdown("Incorrect, le rang ligne est plus petit.")) else: display(Markdown("Incorrect, le rang ligne est plus grand.")) button.on_click(callback) display(text) display(button) display(out) def ch4_9ex2_2(): options = ['E1', 'E2', 'E3', 'E4'] buttons = [] for i in range(4): b = widgets.ToggleButton( value=False, description=options[i], disabled=False, button_style='', # 'success', 'info', 'warning', 'danger' or '' tooltip='Description' ) buttons.append(b) button = widgets.Button(description='Vérifier', # layout=Layout(width='auto', height='auto'), button_style='info' ) out = widgets.Output() def callback(e): out.clear_output() with out: if buttons[1].value or buttons[2].value or buttons[3].value: display(Markdown("Faux")) elif buttons[0].value: display(Markdown("Correct !")) buttons.append(button) buttons[4].on_click(callback) box = VBox(children=buttons) display(box) display(out) def ch4_9ex2_3(): text = widgets.IntText(description='Réponse :', disabled=False) button = widgets.Button(description='Vérifier') button2 = widgets.Button(description='Solution', disabled=True) box = widgets.HBox(children=[button, button2]) out = widgets.Output() def callback(e): out.clear_output() button2.disabled = False with out: if (text.value == 2): print('Correct !') else: print('Faux, essayez encore ou regardez la solution.') def solution(e): out.clear_output() with out: A = np.array([[1, 2, 3], [0, 1, 2]]) A_t = A.transpose() display(Markdown( 'Pour trouver le rang colonne de $A$, on utilise la remarque 1 et trouve le rang ligne de la transposée de $A$.')) display(Markdown( 'Par les propositions 1 et 2, on échelonne la matrice transposée et on trouve le nombre de lignes contenant des pivots')) M = al.echelonMat('E', A_t) display(Markdown('Ainsi le rang colonne de $A$ est 2.')) button.on_click(callback) button2.on_click(solution) display(text) display(box) display(out) def ch4_10ex1_1(A, b): A_sol = [[1, 4, 3, 4],[2, 6, 5, 8],[1, 0, 1, 4]] b_sol = [[1], [1], [1]] if A == [] or b == []: print("Attention, vous avez laissé au moins une des deux entrée vide") elif not (len(A) == len(b)): print("Les tailles de la matrice et du vecteur ne correspondent pas") else: b = np.reshape(np.array(b), (len(b), 1)).tolist() if A == A_sol: if b == b_sol: print("Correct !") else: print("Le vecteur b est faux, votre reponse correspond au système suivant:") al.printSyst(A, b) elif b == b_sol: print("La Matrice A est fausse, votre reponse correspond au système suivant:") al.printSyst(A, b) else: print("Faux, votre réponse correspond au système suivant:") al.printSyst(A, b) def ch4_10ex1_2_1_ech(): global m display(Latex('Échelonnez la matrice transposée de A')) A_sol = np.array([[1, 4, 3, 4], [2, 6, 5, 8], [1, 0, 1, 4]]) A_sol_t = A_sol.transpose() al.printA(A_sol_t) [i, j, r, alpha] = al.manualEch(A_sol_t) MatriceList = [np.array(A_sol_t)] m = A_sol_t button = widgets.Button(description='Appliquer') out = widgets.Output() def applique(e): global m out.clear_output() with out: m = al.echelonnage(i, j, r, alpha, A_sol_t, m, MatriceList) button.on_click(applique) display(button) display(out) def f_sol(): al.echelonMat('E', A_sol.transpose()) display(Latex("Pour afficher la solution, cliquez-ici.")) im = interact_manual(f_sol) im.widget.children[0].description = 'Solution' def ch4_10ex1_2_1(): text_rang = widgets.IntText() box = widgets.VBox([widgets.Label('Rang colonne de A:'), text_rang]) button = widgets.Button(description='Vérifier') out = widgets.Output() def callback(e): out.clear_output() with out: if(text_rang.value == 2): display(Latex('Correct !')) else: display(Latex('Faux, essayez encore ou regardez la solution.')) button.on_click(callback) display(box) display(button) display(out) def f_sol(): display(Latex("Le rang colonne de $A$ correspond au nombre de pivot(s) de la forme échelonnée de $A^T$.")) display(Latex("Pour afficher la solution, cliquez-ici.")) im = interact_manual(f_sol) im.widget.children[0].description = 'Solution' def ch4_10ex1_2_2(base): base_sol = [[1, 2, 1], [0, 1, 2]] correct = check_basis(base_sol, base) def f_sol(): display(Latex("Une base de l'espace ligne de $A$ est donnée par les lignes de la forme echelonnée contenant " "un pivots. Pour trouver une base de l'espace colonne $A$, on utilise l'espace ligne de $A^T$.")) display(Latex("Une base de l'espace colone de $A$ est donc:")) print(base_sol) if base_sol == []: display(Latex("L'entrée est vide")) display(Latex("Pour afficher la solution, cliquez-ici.")) im = interact_manual(f_sol) im.widget.children[0].description = 'Solution' else: if correct: display(Latex("Correct !")) if base_sol != base: display(Latex("Pour la suite de l'exercice, on utilise la base equivalente suivante:")) print(base_sol) else: display(Latex("Faux")) display(Latex("Pour afficher la solution, cliquez-ici.")) im = interact_manual(f_sol) im.widget.children[0].description = 'Solution' 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 """ sol = np.array(sol, dtype=np.float64) prop = np.array(prop, dtype=np.float64) # number of vector in basis n = len(sol) # Check dimension if n != len(prop): 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 ch4_10ex1_3_ech(): display(Latex("Echelonnez la matrice suivante.")) global m2 A = [[1, 2, 1], [0, 1, 2], [1, 1, 1]] al.printA(A) [i, j, r, alpha] = al.manualEch(A) MatriceList = [np.array(A)] m2 = A button = widgets.Button(description='Appliquer') out = widgets.Output() def callback(e): global m2 out.clear_output() with out: m2 = al.echelonnage(i, j, r, alpha, A, m2, MatriceList) button.on_click(callback) display(button) display(out) def ch4_10ex1_3(): display(Latex("Le système admet-il une solution ?")) radio = widgets.RadioButtons( options=['Oui', 'Non'], description='Réponse:', disabled=False ) button = widgets.Button(description='Vérifier') button2 = widgets.Button(description='Solution', disabled=True) box = widgets.HBox(children=[button, button2]) out = widgets.Output() def callback(e): out.clear_output() button2.disabled = False with out: if (radio.value == "Oui"): print('Mauvaise réponse.') else: print('Correct !') def solution(e): out.clear_output() with out: A = np.array([[1, 2, 1], [0, 1, 2], [0, 0, 1]]) display(Markdown('Après échelonnage, la matrice devient')) al.printA(A) display( Markdown("Ainsi le rang colonne de la matrice augmentée est 3, et le système n'admet pas de solution.")) button2.on_click(solution) button.on_click(callback) display(radio) display(box) display(out) def ch4_10ex1_3_2_ech(): display(Latex("Echelonnez la matrice suivante.")) global m3 A = [[1, 4, 3, 4], [2, 6, 5, 8], [1, 0, 1, 4]] b = [[1], [1], [1]] al.printA(A, b) [i, j, r, alpha] = al.manualEch(A, b) MatriceList = [np.array(A)] RHSList = [np.array(b)] m3 = np.concatenate((A, b), axis=1) button = widgets.Button(description='Appliquer') out = widgets.Output() def callback(e): global m3 out.clear_output() with out: m3 = al.echelonnage(i, j, r, alpha, A, m3, MatriceList, RHSList) button.on_click(callback) display(button) display(out) def ch4_10ex2_1_ech(): global m21 A = [[1, 2, 1], [0, 1, 2], [2, 5, 4]] al.printA(A) [i, j, r, alpha] = al.manualEch(A) MatriceList = [np.array(A)] m21 = A button = widgets.Button(description='Appliquer') out = widgets.Output() def callback(e): global m21 out.clear_output() with out: m21 = al.echelonnage(i, j, r, alpha, A, m21, MatriceList) button.on_click(callback) display(button) display(out) def ch4_10ex2_2(): radio = widgets.RadioButtons( options=['Oui', 'Non'], description='Réponse:', disabled=False ) button = widgets.Button(description='Vérifier') button2 = widgets.Button(description='Solution', disabled=True) box = HBox(children=[button, button2]) out = widgets.Output() def callback(e): out.clear_output() button2.disabled = False with out: if (radio.value == "Oui"): print('Correct !') else: print('Mauvaise réponse.') def solution(e): out.clear_output() with out: A = np.array([[1, 2, 1], [0, 1, 2], [0, 0, 0]]) display(Markdown('Après échelonnage, la matrice devient')) al.printA(A) display(Markdown( "Ainsi le rang colonne de la matrice augmentée est 2, et d'après le lemme, le système admet une solution.")) button2.on_click(solution) button.on_click(callback) display(radio) display(box) display(out) +def ch4_11_plot(base=None, show_grid_lines=False, show_can_base=False, vector_list=[], vector_name_list=[]): + + if base is not None: + x1 = np.array(base[0]) + x2 = np.array(base[1]) + n1 = 30 + n2 = 20 + + fig = go.Figure() + fig.update_layout(xaxis=dict(range=[-8.5, 8.5], constrain="domain", ), + yaxis=dict(range=[-8.5, 8.5], scaleanchor="x", scaleratio=1), showlegend=True) + fig.update_xaxes(tick0=0, dtick=2) + fig.update_yaxes(tick0=0, dtick=2) + + if show_grid_lines: + grid_x1_x = np.array([[-n1 * x1[0] + i * x2[0] for i in range(-n2, n2)], + [n1 * x1[0] + i * x2[0] for i in range(-n2, n2)]]) + grid_x1_y = np.array([[-n1 * x1[1] + i * x2[1] for i in range(-n2, n2)], + [n1 * x1[1] + i * x2[1] for i in range(-n2, n2)]]) + + grid_x2_x = np.array([[-n1 * x2[0] + i * x1[0] for i in range(-n2, n2)], + [n1 * x2[0] + i * x1[0] for i in range(-n2, n2)]]) + grid_x2_y = np.array([[-n1 * x2[1] + i * x1[1] for i in range(-n2, n2)], + [n1 * x2[1] + i * x1[1] for i in range(-n2, n2)]]) + + grid_lines = go.scatter.Line(color='grey', width=0.5) + + for i in range(2 * n2): + fig.add_trace(go.Scatter(x=grid_x1_x[:, i], y=grid_x1_y[:, i], mode='lines', showlegend=False, + line=grid_lines)) + + fig.add_trace(go.Scatter(x=grid_x2_x[:, i], y=grid_x2_y[:, i], mode='lines', showlegend=False, + line=grid_lines)) + + if show_can_base: + fig.add_annotation(x=1, # arrows' head + y=0, # arrows' head + ax=0, # arrows' tail + ay=0, # arrows' tail + xref='x', + yref='y', + axref='x', + ayref='y', + text='', # if you want only the arrow + showarrow=True, + arrowhead=3, + arrowsize=2, + arrowwidth=1, + arrowcolor='black', + ) + + fig.add_annotation(x=1.3, y=0, text="$x_1$", showarrow=False) + + fig.add_annotation(x=0, # arrows' head + y=1, # arrows' head + ax=0, # arrows' tail + ay=0, # arrows' tail + xref='x', + yref='y', + axref='x', + ayref='y', + text='', # if you want only the arrow + showarrow=True, + arrowhead=3, + arrowsize=2, + arrowwidth=1, + arrowcolor='black' + ) + fig.add_annotation(x=0, y=1.3, text="$y_1$", showarrow=False) + + if base is not None: + + fig.add_annotation(x=base[0][0], # arrows' head + y=base[0][1], # arrows' head + ax=0, # arrows' tail + ay=0, # arrows' tail + xref='x', + yref='y', + axref='x', + ayref='y', + text='', # if you want only the arrow + showarrow=True, + arrowhead=3, + arrowsize=2, + arrowwidth=1, + arrowcolor='blue' + ) + fig.add_annotation(x=base[0][0]+0.2, y=base[0][1]+0.2, text="$x_2$", showarrow=False) + + fig.add_annotation(x=base[1][0], # arrows' head + y=base[1][1], # arrows' head + ax=0, # arrows' tail + ay=0, # arrows' tail + xref='x', + yref='y', + axref='x', + ayref='y', + text='', # if you want only the arrow + showarrow=True, + arrowhead=3, + arrowsize=2, + arrowwidth=1, + arrowcolor='blue' + ) + fig.add_annotation(x=base[1][0]+0.2, y=base[1][1]+0.2, text="$y_2$", showarrow=False) + + color_list = ['red', 'orange', 'grey', 'brown'] + for idx, v in enumerate(vector_list): + fig.add_trace(go.Scatter(x=[0, v[0]], y=[0, v[1]], mode='lines + markers', showlegend=True, + name=vector_name_list[idx], + line=dict(color=color_list[idx]), + marker=dict(color=color_list[idx]), + )) + + fig.show() + + return + + +def ch4_11ex1_plot(): + ch4_11_plot(base=[[1, 2], [3, 2]], show_can_base=True, show_grid_lines=True, vector_list=[], vector_name_list=[]) + return + + def ch4_11ex1(base): base_solution = [[1, 2], [3, 2]] is_correct = all(item in base_solution for item in base) if is_correct: is_correct = all(item in base for item in base_solution) correct_text = "C'est correct!" incorrect_text = "C'est incorrect." display(correct_text if is_correct else incorrect_text) +def ch4_11ex2a_plot(): + ch4_11_plot(base=[[1, 2], [3, 2]], show_can_base=True, show_grid_lines=True, vector_list=[[5, 6]], + vector_name_list=['v']) + return + def ch4_11ex2aB1(vB1): v = [5, 6] if vB1 == v: is_correct = 1 else: is_correct = 0 correct_text = "C'est correct!" incorrect_text = "C'est incorrect." display(correct_text if is_correct else incorrect_text) def ch4_11ex2aB2(vB2): v = [2, 1] if vB2 == v: is_correct = 1 else: is_correct = 0 correct_text = "C'est correct!" incorrect_text = "C'est incorrect." display(correct_text if is_correct else incorrect_text) +def ch4_11ex2b_plot(): + ch4_11_plot(base=[[1, 2], [3, 2]], show_can_base=True, show_grid_lines=True, vector_list=[[8, 4]], + vector_name_list=['u']) + return + + def ch4_11ex2bB1(uB1): u = [8, 4] if uB1 == u: is_correct = 1 else: is_correct = 0 correct_text = "C'est correct!" incorrect_text = "C'est incorrect." display(correct_text if is_correct else incorrect_text) def ch4_11ex2bB2(uB2): u = [-1, 3] if uB2 == u: is_correct = 1 else: is_correct = 0 correct_text = "C'est correct!" incorrect_text = "C'est incorrect." display(correct_text if is_correct else incorrect_text) +def ch4_11ex2c_plot(): + ch4_11_plot(base=[[1, 2], [3, 2]], show_can_base=True, show_grid_lines=True, vector_list=[[5, 4]], + vector_name_list=['w']) + return + + def ch4_11ex2cB1(wB1): w = [5, 4] if wB1 == w: is_correct = 1 else: is_correct = 0 correct_text = "C'est correct!" incorrect_text = "C'est incorrect." display(correct_text if is_correct else incorrect_text) - + + def ch4_11ex2cB2(wB2): - w = [0.5,1.5] + w = [0.5, 1.5] if wB2==w: is_correct = 1 else: is_correct = 0 correct_text = "C'est correct!" incorrect_text = "C'est incorrect." display(correct_text if is_correct else incorrect_text) - + + def ch4_11ex3B1(sB1): s = [13,10] if sB1==s: is_correct = 1 else: is_correct = 0 correct_text = "C'est correct!" incorrect_text = "C'est incorrect." display(correct_text if is_correct else incorrect_text) + def ch4_11ex3B2(sB2): s = [1,4] if sB2==s: is_correct = 1 else: is_correct = 0 correct_text = "C'est correct!" incorrect_text = "C'est incorrect." display(correct_text if is_correct else incorrect_text) - + + def ch4_12ex1(): style = {'description_width': 'initial'} nbr_ligne = widgets.IntText( description='Nombre de lignes : \n', disabled=False, style=style ) nbr_colonne = widgets.IntText( description='Nombre de colonnes : \n', disabled=False, style=style ) button = widgets.Button(description='Vérifier') out = widgets.Output() def callback(e): out.clear_output() r_l = nbr_ligne.value r_c = nbr_colonne.value with out: if r_l == 5 and r_c == 6: display(Markdown("C'est correct!")) else: display(Markdown("C'est incorrect.")) button.on_click(callback) display(nbr_ligne) display(nbr_colonne) display(button) display(out) + def ch4_12ex2(): text = widgets.IntText( description='Réponse :', disabled=False ) button = widgets.Button(description='Vérifier') out = widgets.Output() def callback(e): out.clear_output() r = text.value with out: if r == 2: display(Markdown("C'est correct!")) else: display(Markdown("C'est incorrect.")) button.on_click(callback) display(text) display(button) display(out) + def ch4_12ex3a(): text = widgets.IntText( description='Réponse :', disabled=False ) button = widgets.Button(description='Vérifier') out = widgets.Output() def callback(e): out.clear_output() r = text.value with out: if r == 3: display(Markdown("C'est correct!")) else: display(Markdown("C'est incorrect.")) button.on_click(callback) display(text) display(button) display(out) def ch4_12ex3b(base): base = base + [[1, 4, 0, 2, 0, 1], [0, 1, 1, 2, 1, 0], [0, 0, 1, 3, 3, 2]] base = np.array(base) out = widgets.Output() display(out) with out: out.clear_output() feedback = "" is_correct = False s = base.shape if len(base) == 0: feedback = "Les vecteurs nuls ne peuvent pas ." elif len(s) != 2 or s[1] != 6: feedback = "Le format des vecteurs n'est pas bon." elif s[0] < 6: feedback = "L'ensemble entré ne contient pas assez de vecteurs pour engendrer toutes les solutions du système." elif s[0] > 6: feedback = "L'ensemble entré contient trop de vecteurs pour être une famille libre." else: expected = np.array(sp.Matrix( [[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1]]).rref()[0]) actual = np.array(sp.Matrix(base).rref()[0]) if not np.array_equal(actual, expected): feedback = "L'ensemble entré n'engendre pas l'espace solution du système." else: is_correct = True correct_text = "C'est correct!
" incorrect_text = "C'est incorrect.
" display(Markdown((correct_text if is_correct else incorrect_text) + feedback))