Page MenuHomec4science

Ch10_lib.py
No OneTemporary

File Metadata

Created
Fri, May 17, 21:19

Ch10_lib.py

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
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):
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'approximation numériques, "
"toutes les valeurs doivent être exactes. Pour les racines carrées "
"(utiles pour normaliser les vecteurs), utilisez 'sqrt('votre valeur')'."))
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:"))
display(Markdown(
"**Méthode**. Soit $A \in M_{n \\times n}(\mathbb{R})$ symétrique. Soit $\mathcal{C}$ la base canonique de $\mathbb{R}^{n}$ "
+ nl() +
"(1) Cherchons le polynôme caractéristique $c_{A}(t)$" + nl() +
"(2) Trouver toutes les racines distinctes $\lambda_{1}, \ldots, \lambda_{r} \in \mathbb{R}$ de $c_{A}(t)$ t.q. $c_{A}(t)=\pm\left(t-\lambda_{1}\\right)^{m_{1}} \cdots\left(t-\lambda_{r}\\right)^{m_{r}}$"
+ nl() + "(3) Pour chaque $i,$ trouver une base $\mathcal{B}_{i}$ de $E_{\lambda_{i}}$" + nl() +
"(4) On sait que pour $v \in \mathcal{B}_{i}, w \in \mathcal{B}_{j}, i \\neq j, v \cdot w=0$" + nl() +
"(5) Pour chaque $i$, utiliser Gram-Schmidt pour trouver une base orthonormée $\mathcal{B}_{i}^{\prime}$ de $E_{\lambda_{i}}$" + nl() +
"(6) $\mathcal{B}^{\prime}=\mathcal{B}_{1}^{\prime} \cup \cdots \cup \mathcal{B}_{r}^{\prime}$ est une base orthonormée de $V$" + nl() +
"(7) $P=[\\text { id }]_{C \mathcal{B}^{\prime}}$ est orthogonale et $P^{T} A P=P^{-1} A P$ est diagonale."))
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."))
interact_manual(correction_ortho_diag)
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'
# Vrai faux
def vf(sol):
"""
:param sol: (bool) solution au vrai faux
:return: bool si réponse juste (vrai) ou non (faux)
"""
answer = widgets.RadioButtons(options=["Vrai", "Faux"], description="Réponse: ", disabled=False)
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)

Event Timeline