Vous êtes sur la page 1sur 7

TP 2 – DECOMPOSITION QR,

ALGORITHME DE GRAM-SCHIMDT
Ma313 – Algèbre linéaire numérique 09/10/2021

Renaud Vallette
3PA2
Introduction
Ce TP vise à éprouver l’efficacité de la résolution de systèmes linéaires de forme 𝐴𝑥 = 𝑏 à
l’aide de la décomposition 𝑄𝑅 par l’algorithme de Gram-Schmidt d’une matrice 𝐴 en comparant cette
méthode à d’autres procédés vus plus tôt ou proposés par la bibliothèque Numpy.

Pour cela, nous allons programmer sur Python l’algorithme Gram-Schmidt permettant d’obtenir la
décomposition 𝑄𝑅 d’une matrice dans le but de résoudre un grand nombre de systèmes linéaires et
d’observer les erreurs sur la solution. Comme outil de comparaison, nous utiliserons la méthode de
décomposition LU, la méthode de décomposition 𝑄𝑅 de 𝐻𝑜𝑢𝑠𝑒𝐻𝑜𝑙𝑑𝑒𝑟 via Numpy ainsi que la méthode
solve de Numpy.

L’algorithme de la décomposition 𝐿𝑈 et des méthodes de résolution de systèmes triangulaires


supérieurs et inférieurs sont déjà fournis avec l’énoncé, nous nous concentrerons donc sur la méthode
de Gram-Schmidt.

1
Implémentation de l’algorithme de Gram-Schmidt
A partir de l’énoncé du TP qui résume la 𝑗-ième étape de l’algorithme de Gram-Schmidt, nous allons
implémenter à notre code la méthode de décomposition 𝑄𝑅 d’une matrice 𝐴 par Gram-Schmidt.

Dans tout ce qui suit on notera :


- 𝑛 la taille de 𝐴
- 𝑎1 , 𝑎2 , … , 𝑎𝑛 les colonnes de 𝐴. Chaque 𝑎𝑗 est donc un vecteur de ℝ𝑛 .
- 𝑞1 , 𝑞2 , … , 𝑞𝑛 les colonnes de 𝑄. Chaque 𝑞𝑗 est donc un vecteur de ℝ𝑛 .
- On notera 𝑟𝑖𝑗 les coefficients de 𝑅

Le « procédé d’orthonormalisation de Gram-Schmidt » se décompose en 𝑛 étapes. La 𝑗-ième étape


contient le calcul des 𝑗-ième colonnes de 𝑄 et de 𝑅, et utilise les colonnes précédemment calculées de
𝑄. La 𝑗-ième étape se décrit ainsi :

Implémentation en Python :

On commence par récupérer la taille de 𝐴 et on crée les matrices carrées vides 𝑄 et 𝑅 de même taille
que 𝐴.

def DecompositionGS(A):
""" Méthode de décomposition QR d'une matrice carrée A
avec l'algorithme de Gram-Schmidt """
n = A.shape
R = np.zeros(n) #Création de la matrice R
Q = np.zeros(n) #Création de la matrice Q

On calcule dans la première étape les coefficients du triangle supérieur de 𝑅 par le produit scalaire
des colonnes 𝑎𝑗 et 𝑞𝑖 pour 𝑖 < 𝑗. L’étape 2 nous permet ensuite de calculer le vecteur colonne 𝑊.

for j in range(n[0]):
for i in range(j):
R[i,j] = A[:,j]@Q[:,i] #Etape 1
S = 0
for k in range (0,j): #Etape 2
S += Q[:,k]*R[k,j]
W = A[:,j] – S

Nous pouvons alors trouver le terme 𝑟𝑗𝑗 en calculant la norme du vecteur 𝑊 grâce à la méthode
np.linalg.norm() de Numpy.

R[j,j] = np.linalg.norm(W) #Etape 3

2
Enfin, la dernière étape permet d’obtenir le vecteur colonne 𝑞𝑗 qui à son tour permettra de réaliser la
(𝑗 + 1)-ième étape.

Q[:,j] = (1/R[j,j])*W #Etape 4


return Q,R

Cette fonction DecompositionGS(A) retourne donc les matrices 𝑄 et 𝑅 dont le produit est égal à la
matrice 𝐴.

Utilisation de Gram-Schmidt pour la résolution d’un système linéaire


Pour résoudre un système linéaire de la forme 𝐴𝑥 = 𝑏, on commence par trouver la décomposition
𝑄𝑅 de 𝐴 avec la fonction vue précédemment. On a alors :

𝑄𝑅𝑥 = 𝑏
Or 𝑄 est orthogonale donc 𝑄 𝑇 = 𝑄 −1, donc :

𝑅𝑥 = 𝑄 𝑇 𝑏

On calcule d’abord le vecteur 𝑌 = 𝑄 𝑇 𝑏, et on a alors l’expression 𝑅𝑥 = 𝑌. On résout ce système


triangulaire supérieur (𝑅 est triangulaire supérieure) avec la méthode ResolTriSup fournie avec
l’énoncé. Ci-dessous le code réalisant cette démarche :

#Exercice 2
def ResolGS(A,b):
"""Méthode de résolution d'un système linéraire à l'aide de la décompositi
on QR obtenue par l'algorithme de Gram-Schmidt"""
Q,R = DecompositionGS(A)
Y = Q.T@b
X = ResolTriSup(R,Y)
return X

3
Comparaison avec d’autres méthodes de résolution
Les autres méthodes que nous allons utiliser pour la comparaison sont les résolutions à partir de la
décomposition 𝐿𝑈, de la décomposition 𝑄𝑅 de 𝐻𝑜𝑢𝑠𝑒𝐻𝑜𝑙𝑑𝑒𝑟 avec la fonction numpy.linalg.qr(A), et
de la fonction numpy.linalg.solve(A,b) permettant la résolution d’un système linéaire 𝐴𝑥 = 𝑏.

Nous allons, pour une taille de matrice croissante, résoudre le système linéaire avec les différentes
méthodes et comparer les erreurs sur la solution (c’est-à-dire la norme du vecteur (𝐴𝑥 − 𝑏) qui doit
s’approcher de 0).

Après des essais de comparaison de l’erreur sur la résolution de plusieurs systèmes linéaires aléatoires,
on obtient des courbes de comparaison assez irrégulières et assez peu pratiques à lire. Nous allons
donc, pour chaque système aléatoire associé à une taille spécifique, résoudre le système un grand
nombre de fois avec chaque méthode, et ainsi obtenir une liste d’erreurs pour chaque taille de système
et pour chaque méthode.

Dans le but de pouvoir comparer fidèlement l’efficacité des différentes résolutions, nous allons
observer les erreurs moyenne puis médiane pour chaque taille de système et pour chaque méthode,
et les tracer sur un même graphique à l’aide de la bibliothèque 𝑚𝑎𝑡𝑝𝑙𝑜𝑡𝑙𝑖𝑏. Pour obtenir un
échantillon représentatif de la réalité, on réalise la comparaison pour des tailles de système allant de
2 à 100, et pour chaque taille on résoudra 100 fois le système.

Sur ce graphique de l’erreur moyenne, on observe que les méthodes les plus précises sont celles
utuilisant HouseHolder et Numpy.solve, suivies de celle utilisant Gram-Schmidt et enfin par celle
utilisant la décomposition 𝐿𝑈.

4
On peut relever que, comme on pouvait s’y attendre, l’erreur sur la solution augmente
proportionnellement avec la taille du système. Elle est assez faible pour toutes les méthodes pour des
petites tailles de système, mais croît assez vite jusqu’à des systèmes de taille 15 environ, avant de
croître plus lentement et de presque se stabiliser pour des systèmes dépassant la taille 60.

Pour obtenir un graphique plus lisible et pouvoir comparer de manière plus précise, on peut consulter
l’erreur médiane sur la résolution des différents systèmes, et ainsi avoir des résultats plus lisses
puisque libérés des valeurs extrêmes faussant quelque peu les moyennes.

On peut voir ici plus précisément que pour des systèmes de taille 2 à 30, la méthode sollicitant la
décomposition 𝑄𝑅 de Householder est moins précise que la méthode de résolution numpy.solve, puis
qu’elle devient plus précise que cette dernière à partir de systèmes de taille 30.

On remarque également que l’erreur pour des systèmes de grande taille ne se stabilise pas vraiment,
notamment pour la méthode passant la décomposition 𝐿𝑈.

Il est également intéressant d’analyser la différence entre les deux méthodes utilisant la
décomposition 𝑄𝑅. On observe en effet que la décomposition de Householder permet une résolution
un peu moins de 10 fois plus précise que la décomposition de Gram-Schmidt pour des systèmes de
grande taille. Cela s’explique par le fait que la méthode de Householder est beaucoup plus stable
numériquement puisqu’elle limite le nombre de divisions par des petits nombres. En contrepartie de
cette stabilité, son coût est relativement élevé.

Quant à la précision de la méthode numpy.solve, elle a tout comme la décomposition de Householder


été codée via la librairie LAPACK, elle-même codée en langage Fortran (mathematical FORmula

5
TRANslating system), créé dans les années 50 pour le calcul numérique. Bien plus poussées et plus
proche de la machine, ces méthodes sont donc naturellement plus performantes.

Pour tenter d’observer les différences de coût, nous allons observer le temps moyen de résolution de
systèmes linéaires de différentes tailles avec les quatre méthodes utilisées.

On peut là aussi observer à quel point les méthodes de résolution via la décomposition de Householder
via et numpy.linalg.solve sont plus performantes que les méthodes de résolution utilisant la
décomposition 𝑄𝑅 de Gram-Schmidt et la décomposition 𝐿𝑈, car en plus d’être plus précises, elles
sont également plus rapides. Cela peut toutefois être dû à des problèmes d’optimisation de notre code,
car la méthode de Householder est censée être plus coûteuse que celle de Gram-Schmidt du fait de sa
plus grande précision.

On remarque également que le temps moyen de calcul pour la résolution via la décomposition de
Gram-Schmidt est un peu plus lente que celle via la décomposition 𝐿𝑈. Son coût est en effet plus élevé
car la décomposition est réalisée avec plus de précision.

Il serait intéressant de prendre pour outil de comparaison complémentaire la résolution de systèmes


linéaires à l’aide d’une décomposition 𝑄𝑅 réalisée par la méthode de Givens, qui apporte encore plus
de stabilité numérique que la méthode de Householder, mais a de fait un coût plus élevé.

Vous aimerez peut-être aussi