POIRET Aurélien Ingénierie Numérique MPSI Chapitre N o 4 : Le pivot de Gauss Dans ce chapitre, on présente divers algorithmes de calcul matriciel et on évalue leurs complexités 1 Le type «matriciel» sous Python 11 Présentation des variables de types array Rappelons que sous python les tableaux, qui sont de types list, ne permettent pas de faire de calcul matriciel En effet, la syntaxe suivante [1,,3]+[1,,3] dans l interpréteur retourne [1,,3,1,,3] et non [,4,6] comme on pourrait s y attendre Pour contourner ce problème, il suffit de convertir nos variables de type list en type array (matriciel) Par exemple, la syntaxe suivante, import numpy T=numpyarray([1,,3]) print(t+t) retourne array([,3,4]) Pour définir une matrice, par exemple de taille 3 3, sous Python, on peut utiliser la syntaxe suivante, A=numpyarray([[1,,3],[4,5,6],[7,8,9]]) qui correspond à la matrice 1 3 4 5 6 7 8 9 1 Création de matrice sous Python Pour faire du calcul matriciel sous Python, il faut nécessairement importer la bibliothèque numpy, ce que l on fera systématiquement à chaque début de programme et à chaque début de TP import numpy Pour définir une matrice standard sous Python, on peut utiliser les mots-clefs et syntaxes suivantes : 1
numpyarray(l) retourne la matrice ligne formée où L est un tableau ligne des coefficients du tableau L numpyzeros(n) retourne la matrice ligne où N est un entier non nul de longueur N formée de 0 numpyzeros(l) retourne la matrice, de taille les éléments de où L est un tableau ligne de deux entiers non nuls L, formée de 0 numpyones(n) retourne la matrice ligne où N est un entier non nul de longueur N formée de 1 numpyones(l) retourne la matrice, de taille les éléments de où L est un tableau ligne de deux entiers non nuls L, formée de 1 numpydiag(l) retourne la matrice diagonale avec où L est un tableau ligne les coefficients de L sur la diagonale numpydiag(l,i) retourne la matrice avec les coefficients de où L est un tableau ligne L sur la i-ème diagonale supérieure numpydiag(l,-i) retourne la matrice avec les coefficients de où L est un tableau ligne L sur la i-ème diagonale inférieure numpyidentity(n) retourne la matrice identité où N est un entier de taille N numpyarange(m,n,p) retourne la matrice ligne allant de M (inclus) où M, N et P sont des entiers à N (exclus) avec pas de P numpylinspace(m,n,p) retourne la matrice ligne allant de M (inclus) à où M, N et P sont des entiers N avec P éléments uniformément répartis 13 Extraction de sous-matrices Les mots-clefs et syntaxe permettant d extraire des matrices à partir d une matrice donnée sont plus souples que pour le type list Les différentes syntaxes sont les suivantes : Ashape où A est une matrice A[i][j] où A est une matrice et i et j deux entiers A[:,i] où A est une matrice A[:,:i] où A est une matrice A[:,i:] où A est une matrice A[:,i:j+1] où A est une matrice et i et j deux entiers A[i,:] où A est une matrice A[:i,:] où A est une matrice A[i:,:] où A est une matrice A[i:j+1,:] où A est une matrice et i et j deux entiers retourne les dimensions de A sous forme de tupple extrait le coefficient d indice (i+1,j+1) de A extrait la i+1-ème colonne de A extrait les i premières colonnes de A extrait les i+1 dernières colonnes de A extrait de la i-ième à la j-ième colonne de A extrait la i+1-ème ligne de A extrait les i premières lignes de A extrait les i+1 dernières lignes de A extrait de la i-ième à la j-ième ligne de A
14 Outils mathématiques pour les matrices sous python Les outils mathématiques à notre disposition sous Python sont les suivants : Amax() où A est une matrice Amax(0) où A est une matrice Amax(1) où A est une matrice Amin() où A est une matrice Amin(0) où A est une matrice Amin(1) où A est une matrice Asum() où A est une matrice Asum(0) où A est une matrice Asum(1) où A est une matrice Aprod() où A est une matrice Aprod(0) où A est une matrice Aprod(1) où A est une matrice Amean() où A est une matrice Amean(0) où A est une matrice Amean(1) où A est une matrice A+B où A et B sont deux matrices t*a où A est une matrice et t un scalaire numpydot(a,b) où A et B sont deux matrices f(a) où A est une matrice et f une fonction retourne le maximum global des coefficients retourne le maximum de chaque colonne retourne le maximum de chaque ligne retourne le minimum global des coefficients retourne le minimum de chaque colonne retourne le minimum de chaque ligne retourne la somme totale des coefficients retourne la somme de chaque colonne retourne la somme de chaque ligne retourne le produit total des coefficients retourne le produit de chaque colonne retourne le produit de chaque ligne retourne la moyenne totale des coefficients retourne la moyenne de chaque colonne retourne la moyenne de chaque ligne retourne la matrice somme retourne la matrice multipliée retourne la matrice produit retourne la matrice dont les coefficients sont les coefficients images de ceux de A par f Vous pourrez avoir besoin d autre outils plus puissants comme ceux qui suivent : Atranspose() où A est une matrice Aconj() où A est une matrice Aconj()transpose() où A est une matrice numpylinalgdet(a) où A est une matrice numpylinalginv(a) où A est une matrice numpylinalgsolve(a,b) où A est une matrice et b est une matrice ligne (ou colonne) numpylinalgeigvals(a) où A est une matrice numpylinalgeig(a) où A est une matrice numpyinner(x,y) où x et y sont deux matrices lignes retourne la matrice transposée de A retourne la matrice conjuguée de A retourne la matrice adjointe de A retourne le déterminant de la matrice A retourne la matrice inverse de la matrice A retourne la matrice ligne (ou colonne) solution de Ax=b retourne les valeurs propres de A retourne sous forme de tableau le vecteur colonne des valeurs propres de A et la matrice des vecteurs propres de A retourne la valeur du produit scalaire de x et y 3
15 Les phénomènes paranormaux du type array Avec le type array, certaines opérations peuvent retourner des résultats très surprenant Par exemple, avec une liste de type list, le code suivant, C=[[1,,3],[4,5,6],[7,8,9]] X=C[][:] X[0]=4 print("c=",c) produit le résultat attendu, autrement dit, [[1,,3],[4,5,6],[7,8,9]] Alors qu avec une liste de type array, le code suivant, D= numpyarray([[1,,3],[4,5,6],[7,8,9]]) X=D[][:] X[0]=4 print("d=",d) ne produit pas le résultat attendu, autrement dit, [[1,,3],[4,5,6],[4,8,9]] Pour remédier à ce problème, il faut faire une copie à l aide de la fonction deepcopy D ailleurs, dés que vous devez faire une copie de liste, qu elle soit de type list ou array, je vous conseille fortement d utiliser deepcopy En effet, le code suivant, from copy import deepcopy C = [[1,,3],[4,5,6],[7,8,9]] D = numpyarray([[1,,3],[4,5,6],[7,8,9]]) X = deepcopy(c[]) X[0] = 4 print("c=",c) X = deepcopy(d[][:]) X[0] = 4 print("d=",d) produit doublement le résultat attendu L algorithme du pivot de Gauss pour la résolution de système linéaire 1 Rappel sur les systèmes linéaires Définition A Un système linéaire de n équations à p inconnues est la donnée de coefficients a i,j pour i {1,, n} et j {1,, p}, de coefficients y i pour i {1,, n} et d inconnues x j pour j {1,, p} vérifiant i {1,, n}, p a i,j x j = y i j=1 4
Remarque I L ensemble des solutions d un système linéaire est soit vide, soit fini ou soit infini Définition B Désignons par L i la i-ème ligne du système linéaire et définissons les 3 opérations élémentaires suivantes : - L i L k qui correspond à intervertir les lignes i et k - L i λl i avec λ complexe non nul, qui correspond à multiplier la ligne i par λ - L i L i + λl k qui correspond à remplacer la ligne i par L i + λl k Théorème 1 Les opérations élémentaires laissent invariant l ensemble des solutions d un système linéaire Preuve : Elle se situe dans votre cours de mathématiques L algorithme du pivot de Gauss consiste à appliquer ces opérations pour se ramener à la résolution d un système linéaire triangulaire supérieur Le principe est le suivant : Étape N o 1 : Si les coefficients a 1,1,, a n,1 devant l inconnue x 1 sont tous nuls, on permute les inconnues pour se ramener à une situation où cela n a plus lieu On repère ensuite un coefficient devant x 1 qui soit non nul, appelé premier pivot Si ce coefficient apparaît en ligne i, on commence par intervertir les lignes 1 et i Cela permet donc, par opérations élémentaires, d éliminer tous les coefficients devant x 1 de la ligne à la ligne n Étape N o : On reprend l étude précédente en travaillant avec les coefficients de l inconnue x mais sans plus utiliser la première équation qui restera dès lors inchangée On poursuit cette démarche tant qu il apparaît des coefficients non nuls dans les équations qui n ont pas servi de pivot A terme, on parvient à un système triangulaire supérieur de la forme suivante : p 1 x 1 + + x r + x r+1 + + x p = y 1 (1) p r x r + x r+1 + + x p = y r (r) 0 = y r+1 (r + 1) 0 = y n (n) où les x 1,, x p désignent, à l ordre près, les inconnues initiales x 1,, x p (certaines ont pu être permutées comme cela a été détaillé lors de l étape 1) Définition C Les équations (1),, (r) sont appelées équations principales Les équations (r + 1),, (n) sont appelées équations de compatibilité Les scalaires p 1,, p r sont appelés les pivots Si l une des équations de compatibilité est fausse, l ensemble des solutions est vide 5
Si les équations de compatibilité sont vérifiées, le système est équivalent à : p 1 x 1 + + x r + x r+1 + + x p = y 1 (1) p r x r + x r+1 + + x p = y r (r) Ce système triangulaire se résout en cascade et permet d exprimer les inconnues principales x 1,, x r en fonction des inconnues x r+1,, x p qui serviront à paramétrer l ensemble solution Remarque II En posant, X = x 1 x p M p,1 (K), Y = y 1 y n M n,1 (K) et A = a 1,1 a 1, a 1,p a,1 a, a,p M n,p(k), a n,1 a n, a n,p le système linéaire est équivalent à AX = Y Si A est inversible alors le système linéaire admet une unique solution donnée par A 1 Y Implémentation sous Python Pour simplifier, on supposera que p = n, que A est inversible et donc que le système linéaire possède une unique solution, X = A 1 Y Dans le cas ou la matrice A est triangulaire supérieure, il n y a plus qu à remonter le système linéaire via des substitutions On a donc à résoudre a 1,1 a 1, a 1,n a, a,n (0) a n,n x 1 x n = On calcule donc les valeurs de x 1,, x n par récurrence descendante Nous avons x n = yn a n,n ( ) i {n 1,, 1}, x i = 1 a i,i y i n a i,k x k y 1 y n k=i+1 En tenant compte du décalage d indice pythonien, l algorithme obtenu est le suivant : Pour i de n 1 à 0 faire Pour k de i + 1 à n 1 faire y i y i a i,k x k x i y i a i,i 6
Dans le cas général, nous devons appliquer les opérations élémentaires sur les lignes pour se ramener à un système triangulaire supérieur On commence alors par repérer un coefficient devant de x 1 qui soit non nul (sous Python, on cherchera même le plus grand coefficient en valeur absolue devant x 1 pour minimiser les erreurs d arrondis) Si ce coefficient apparaît en ligne i, on commence par intervertir les lignes 1 et i Cela permet donc, par opérations élémentaires, d éliminer tous les coefficients devant x 1 de la ligne à la ligne n On continue ensuite le procédé sur la colonne suivante puis de proche en proche pour obtenir un système triangulaire supérieur et se ramener ainsi au cas précédent L algorithme obtenu est le suivant (en tenant toujours compte du décalage d indice pythonien) : Pour j de 0 à n faire Trouver i entre j et n 1 tel que a i,j soit maximal # Cela permet de trouver un terme #non nul et de minimiser les erreurs d arrondis Échanger L i et L j Pour i de j + 1 à n 1 faire L i L i a i,j a j,j L j # A ce stade, le système est triangulaire supérieur Pour i de n 1 à 0 faire Pour k de i + 1 à n 1 faire y i y i a i,k x k x i y i a i,i Algorithme 1: L algorithme du pivot pour la résolution de systèmes linéaires 3 Calcul de la complexité Rappelons que si a, b Z vérifient a < b alors b i=a 1 = b a + 1 Dans le cas d une résolution d un système triangulaire, nous avons n(n 1) sommes et n(n+1) multiplications Trouver tous les pivots partiels demande n j=0 (n 1 j) = n(n 1) comparaisons Pour transformer le système en système triangulaire, le nombre d addition vaut n n 1 n + 1 n(n + 1)(n 1) = j=0 i=j+1 7
Pour transformer le système en système triangulaire, le nombre de multiplication vaut n n 1 n + (n + )n(n 1) = j=0 i=j+1 L algorithme du pivot de Gauss est donc de complexité n(n +3n 3) n n 3 Remarque III L algorithme de Straussens permet de diminuer la complexité précédente et d obtenir une complexité de l ordre de O(n,807 ) Remarque IV A savoir que dans le cas A inversible, il existe des formules explicites (appelées formules de Cramer) permettant d exprimer la solution du système linéaire Cette formule repose sur des calculs de déterminants et donne une complexité de l ordre de O(n!) 3 L algorithme du pivot de Gauss pour le calcul d inverse 31 Principe L algorithme du pivot de Gauss nous a amené à faire des opérations sur les lignes d une matrice, ce qui revient à multiplier à gauche cette matrice par des matrices élémentaires, disons L 1,, L N (après N opérations) Le système Ax = y est alors équivalent à L 1 Ax = L 1 y puis L L 1 Ax = L L 1 y, puis L N L 1 Ax = L N L 1 y et si on a correctement appliqué l algorithme du pivot de Gauss, le membre de droite vaut exactement x Ainsi A 1 = L N L 1 Cette matrice est en fait exactement celle obtenue en appliquant à la matrice identité (et dans le même ordre) les opérations réalisées sur A 3 Implémentation sous Python On peut donc appliquer l algorithme suivant pour calculer l inverse d une matrice A : 8
X I n Pour j de 0 à n faire Trouver i entre j et n 1 tel que a i,j soit maximale Échanger L i et L j # Pour la matrice A et la matrice X Pour i de j + 1 à n 1 faire L i L i a i,j a j,j L j # Pour la matrice A et la matrice X # A ce stade, la matrice A est triangulaire supérieure Pour j de n 1 à 0 faire Pour i de j 1 à 0 faire L i L i a i,j a j,j L j # Pour la matrice A et la matrice X # A ce stade, la matrice A est diagonale Pour i de 0 à n 1 faire L i 1 a i,i L i # Pour la matrice A et la matrice X Algorithme : L algorithme du pivot de Gauss pour le calcul d inverse 33 Calcul de la complexité Transformer la matrice A en une matrice triangulaire supérieure nécessite n(n 1)(n+1) opérations, puis la transformer en matrice diagonale nécessite n (n 1) additions et n(n+1)(n 1) multiplications Enfin la dernière étape consomme n divisions Toutes ces opérations sont également à effectuées sur la matrice identité On obtient alors une complexité égale à n(n 1) 4n 3 n Remarque V Il est bien sûr possible d implémenter un algorithme reposant sur le pivot de Gauss permettant de calculer le rang d une matrice 9