Exercice ma21¶
import numpy as np
import numpy.linalg as lin
import matplotlib.pylab as plt
%matplotlib inline
np.set_printoptions(precision=3, linewidth=150, suppress=True)
On va augmenter le rayon de convergence la méthode Jacobi amméliorée faite en TD à savoir la méthode de Gauss-Seidel.
On étudiera sa convergence dans différents cas.
Gauss-Seidel¶
Lorsqu'on calcul le x suivant avec Jacobi on ne profite pas du fait que N est triangulaire et donc qu'on connait la nouvelle valeur de $x_n$ lorsqu'on calcule $x_{n-1}$. Avec Gauss-Seidel on utilise toujours la dernière valeur calculée ce qui accélère la convergence.
Pour résumer Gauss-Seidel d'un point de vu matriciel on a :
- D = la matrice diagonale extraite de A :
D = np.diag(np.diag(A))
- L = la matrice stritecement triangulaire inférieure de A :
L = np.tril(A, -1)
- U = la matrice stritecement triangulaire supérieure de A :
U = np.triu(A, 1)
et une itération est donnée par la formule suivante :
$$ (D + L)\, {\bf x}^{k+1} = -U\; {\bf x}^k + {\bf b} $$ ou $$ {\bf x}^{k+1} = D^{-1} \, ( -L\, {\bf x}^{k+1} - U\; {\bf x}^k + {\bf b}) $$ c.a.d. $$ \begin{bmatrix} x_{1}^{k+1} \\ x_{2}^{k+1} \\ \vdots \\ x_{n}^{k+1} \\ \end{bmatrix} = \begin{bmatrix} 1/a_{11} \quad 0 \quad \ldots \quad 0 \\ 0 \quad 1/a_{22} \quad \ldots \quad 0 \\ \vdots \\ 0 \quad 0 \quad \ldots \quad 1/a_{nn} \\ \end{bmatrix} \; \left( \; - \begin{bmatrix} 0 \quad 0 \quad \ldots \quad 0 \\ a_{21} \; 0 \quad \ldots \quad 0 \\ \vdots \\ a_{n1} \, a_{n2} \; \ldots \quad 0 \\ \end{bmatrix} \; \begin{bmatrix} x_{1}^{k+1} \\ x_{2}^{k+1} \\ \vdots \\ x_{n}^{k+1} \\ \end{bmatrix} - \begin{bmatrix} 0 \; a_{12} \; \ldots \; a_{1n} \\ 0 \quad 0 \; \ldots \; a_{2n} \\ \vdots \\ 0 \quad 0 \; \ldots \; 0 \\ \end{bmatrix} \; \begin{bmatrix} x_{1}^k \\ x_{2}^k \\ \vdots \\ x_{n}^k \\ \end{bmatrix} + \begin{bmatrix} b_{1} \\ b_{2} \\ \vdots \\ b_{n} \\ \end{bmatrix} \; \right) $$
Notons que je peux mettre $L\, {\bf x}^{k+1}$ à droite du signe égal si je résoud mon système ligne par ligne en commencant par le haut puisque dans ce cas les ${\bf x}^{k+1}$ utilisés sont connus. C'est ce qu'on a fait lors du dernier TP.
Surrelaxation de Gauss-Seidel¶
Comme on a fait avec Jacobi, on introduit de l'inertie avec $w$ :
$$ {\bf x}^{k+1} = w \, D^{-1} \, ( -L\, {\bf x}^{k+1} - U\; {\bf x}^k + {\bf b}) + (1-w) \; {\bf x}^k $$
Vérifiez que l'on arrive à l'écriture matricielle suivante :
$$ \left(\frac{D}{w} + L\right)\, {\bf x}^{k+1} = \left(\frac{1-w}{w} \, D - U\right)\; {\bf x}^k + {\bf b} $$
Écrit ainsi on voit que cette méthode consiste à avoir les éléments de la diagonale des 2 cotés de l'égalité. On peut interpréter cela comme un avantage lié à une meilleure répartition de l'information contenue dans la matrice (à tester pour savoir).
Programmons Gauss-Seidel surrelaxé¶
On écrira deux fonctions :
solve_triangular(L,b)
qui retourne la solution de L x = b lorsque L est triangulaire inférieuregauss_seidel_r(A, b, x0, w, n)
qui faitn
iteration de Gauss-Seidel en démarrant àx0
avecw
le coefficient de relaxation donné en argument. Cette fonction retourne un tableau des valeurs de x calculées (donc tableau en 2D).
Comme toujours, attention à limiter les for
et à faire le plus possible d'opérations vectorielles et matricielles.
np.random.seed(123)
A = np.random.randint(10, size=(4,4))
b = A.sum(axis=1)
x0 = np.random.random(4)
res = gauss_seidel_r(A, b, x0, w=0.2, n=100)
print(res[-1])
def plot_convergences(values, result):
error = np.square(values - result).sum(axis = -1) / np.square(result).sum(axis=-1)
error2 = np.square(np.diff(values)).sum(axis = -1) / np.square(values).sum(axis=-1)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14,4))
ax1.plot(range(len(error)), error)
ax1.set_title('Erreur absolue normalisée')
ax1.semilogy();
ax2.plot(range(len(error2)), error2)
ax2.set_title('Erreur relative normalisée')
ax2.semilogy()
print("Itération du minimum :",np.argmin(error), np.argmin(error2))
plot_convergences(res, np.ones(4))
Est-ce que la méthode de Gauss-Seidel non relaxée converge dans ce cas ?
Le bon cas¶
Trouver un seed
qui permet de générer un cas qui ne converge pas avec Gauss-Seidel de base mais qui
converge avec la relaxation ($w=0.2$).
Tracer les courbes de convergence pour le cas retenu avec et sans relaxation.
Étude de $w$¶
Toujours dans notre cas retenu,
indiquer quel est l'intervale de
valeurs de $w$ qui garantit la convergence pour notre système matriciel A x = b avec toujours le même x0
et un nombre d'itérations à déterminer.
Trouver la valeur optimiale de $w$ pour converger le plus rapidement pour ce cas.
La précision demandée pour l'intervale et la valeur optimale est de $10^{-2}$.