Changement de pivot dans la méthode de Gauss
Nous avons déjà signalé que la méthode de Gauss échoue si un pivot s’annule. Voir l’exemple. |
Dans ce cas, on doit recourir à une technique dite de changement de pivot qui consiste à échanger des lignes (ou des colonnes) du système de manière à ce qu’aucun pivot ne soit nul.
Analysons comment la stratégie de pivot partiel affecte la factorisation LU induite par la méthode de Gauss. Lors de la première étape de l’élimination de Gauss avec changement de pivot partiel, après avoir trouvé l’élément \(a_{r 1}\) de module maximum dans la première colonne, on construit la matrice de permutation élémentaire \(\mathrm{P}_1\) qui échange la première et la \(r\)-ième ligne (si \(r=1, \mathrm{P}_1\) est la matrice identité). On crée ensuite la première matrice de transformation de Gauss \(\mathrm{M}_1\) et on pose \(A^{(2)}=M_1 P_1 A^{(1)}\). On procède de même avec \(A^{(2)}\), en cherchant les nouvelles matrices \(P_2\) et \(\mathrm{M}_2\) telles que
Après avoir effectué toutes les étapes de l’élimination, la matrice triangulaire supérieure \(U\) obtenue est donnée par
En posant \(\mathrm{M}=\mathrm{M}_{n-1} \mathrm{P}_{n-1} \ldots \mathrm{M}_1 \mathrm{P}_1\) et \(\mathrm{P}=\mathrm{P}_{n-1} \ldots \mathrm{P}_1\), on a \(\mathrm{U}=\mathrm{MA}\) et donc \(\mathrm{U}=\left(\mathrm{MP}^{-1}\right) \mathrm{PA}\). On vérifie facilement que la matrice \(\mathrm{L}=\mathrm{PM}^{-1}\) est triangulaire inférieure (avec des 1 sur la diagonale), de sorte que la factorisation LU s’écrit
On ne doit pas s’inquiéter de la présence de l’inverse de \(\mathrm{M}\), car \(\mathrm{M}^{-1}=\mathrm{P}_1^{-1} \mathrm{M}_1^{-1} \ldots \mathrm{P}_{n-1}^{-1} \mathrm{M}_{n-1}^{-1}\), \(\mathrm{P}_i^{-1}=\mathrm{P}_i^T\) et \(\mathrm{M}_i^{-1}=2 \mathrm{I}_n-\mathrm{M}_i\). |
Une fois calculées les matrices \(\mathrm{L}, \mathrm{U}\) et \(\mathrm{P}\), la résolution du système initial se ramène à la résolution des systèmes triangulaires \(\mathrm{Ly}=\mathrm{Pb}\) et \(\mathrm{Ux}=\mathbf{y}\).
Remarquer que les coefficients de la matrice \(L\) coïncident avec les multiplicateurs calculés par une factorisation \(LU\) de la matrice \(PA\) sans changement de pivot. |
Si on adopte une stratégie de pivot total, à la première étape, une fois trouvé l’élément \(a_{q r}\) de plus grand module dans la sous-matrice \(\mathrm{A}(1: n, 1: n)\), on doit échanger la première ligne et la première colonne avec la \(q\)-ième ligne et la \(r\)-ième colonne. Ceci conduit à la matrice \(\mathrm{P}_1 \mathrm{~A}^{(1)} \mathrm{Q}_1\), où \(\mathrm{P}_1\) et \(\mathrm{Q}_1\) sont respectivement des matrices de permutation de lignes et de colonnes. A ce stade, la matrice \(M_1\) est donc telle que \(A^{(2)}=M_1 P_1 A^{(1)} Q_1\). En répétant ce processus, on obtient à la dernière étape
au lieu de [eq24].
Dans le cas d’un changement de pivot total, la factorisation \(LU\) devient
où \(\mathrm{Q}=\mathrm{Q}_1 \ldots \mathrm{Q}_{n-1}\) est une matrice de permutation prenant en compte toutes les permutations effectuées. Par construction, la matrice \(L\) est encore triangulaire inférieure, et ses éléments ont tous un module inférieur ou égal à 1 . Comme pour le changement de pivot partiel, les éléments de L sont les multiplicateurs produits par la factorisation LU de la matrice PAQ sans changement de pivot. Une fois calculées les matrices \(\mathrm{L}, \mathrm{U}, \mathrm{P}\) et \(\mathrm{Q}\), pour résoudre le système linéaire on note qu' on peut écrire
Alors, on se ramème à la résolution des systèmes triangulaires \(\mathrm{Ly}=\mathrm{Pb}, \mathrm{Ux}^*=\mathrm{y}\) et finalement on trouve \(\mathbf{x}=\mathbf{Q} \mathbf{x}^*\).
1. Python
Dans Python, en utilisant la bibliothèque numpy
, on peut calculer la factorisation LU d’une matrice A
comme suit :
import numpy as np
P, L, U = np.linalg.lu(A)
La matrice P
est la matrice de permutation. Lorsque la matrice P
coïncide avec la matrice identité, les matrices L
et U
sont les matrices recherchées (telles que \(LU = A\)). Autrement, on a \(LU = PA\).
Mesurons la performance (en temps) de la méthode LU avec pivot partiel en augmentant la taille de la matrix et en utilisant les matrices du Laplacian
import numpy as np
from scipy.linalg import lu
import time
# Tailles des matrices
Ns = [10, 100, 1000, 2000] # 3000, 4000, 5000, 6000, 7000]
Ts = []
nsamples = 4
for N in Ns:
h = float(1./N)
x = np.linspace(start=h, stop=1 - h, num=N - 1)
# Construct the matrix A
A = (N**2) * (np.diag(2 * np.ones(N - 1)) - np.diag(np.ones(N - 2), 1) - np.diag(np.ones(N - 2), -1))
tavg = 0
for i in range(nsamples):
# Mesure du temps de la factorisation LU
start = time.time()
P, L, U = lu(A)
end = time.time()
tavg += end - start
tavg/=nsamples
# Affichage du temps de calcul
Ts.append( tavg )
print(f"N = {N:4d} | Temps de calcul: {tavg:.4f} s")
Results
N = 10 | Temps de calcul: 0.0001 s N = 100 | Temps de calcul: 0.0003 s N = 1000 | Temps de calcul: 0.0280 s N = 2000 | Temps de calcul: 0.1781 s
Nous tracons le graphe en loglog des résultats avec plotly
import plotly.graph_objects as go
fig = go.Figure()
fig.add_trace(go.Scatter(x=Ns, y=Ts, mode='markers+lines', name='LU'))
fig.update_layout(xaxis_type="log", yaxis_type="log")
fig.show()
Results
Nous pouvons enfin calculer la pente de la courbe en utilisant la fonction linregress
de la bibliothèque scipy.stats
from scipy.stats import linregress
slope, intercept, r_value, p_value, std_err = linregress(np.log(Ns[1:]), np.log(Ts[1:]))
print(f"La pente de la courbe est {slope:.4f}")
Results
La pente de la courbe est 2.1047