Pivot de Gauss
Transcription
Pivot de Gauss
INS3 Pivot de Gauss Code INS3.1: Implémentation de la fonction principale pour le pivot de Gauss 1 import copy # pour la copie profonde 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 def pivot_gauss(A0,Y0): ’’’Algorithme de résolution du système matriciel A0.X = Y0. * La matrice A0 doit être inversible pour que l’algorithme fonctionne (système de Cramer) et est donnée sous forme de liste de listes où chaque sous-liste représente une ligne de la matrice. * Y0 est une simple liste. L’algorithme renvoie la valeur attendue de X sous forme d’une liste. ’’’ # Initialisation: on copie les matrices/listes en profondeur pour ne pas # modifier les données de l’utilisateur A,Y = [copy.deepcopy(v) for v in [A0,Y0]] n = len(A) # Quelques vérifications de base: assert n == len(A[0]) # A doit être une matrice carrée n*n, assert n == len(Y) # Y doit être un vecteur de taille n for i in range(n): # On itère sur chacune des n lignes j = cherche_pivot(A,i) # Recherche parmi les lignes j >= i if j > i: # Si le pivot n’est pas en i, on échange echange_lignes(A,i,j) # à la fois pour A Y[i],Y[j] = Y[j],Y[i] # et pour Y for k in range(i+1,n): # On itère sur les lignes restantes # On effectue la transvection Lk = Lk - alpha*Li alpha = A[k][i]/A[i][i] # avec alpha bien choisi transvection(A,k,i,alpha) # transvection sur A Y[k] = Y[k] - alpha*Y[i] # et sur Y # Il ne reste plus qu’à remonter en partant de la fin. X = [0]*n for i in range(n-1,-1,-1): X[i] = (Y[i] - sum(A[i][j]*X[j] for j in range(i+1,n)))/A[i][i] return X E Bougnol, JJ Fleck, M Heckmann & M Kostyra, Kléber, PCSI& - INS3 Pivot de Gauss 2/8 Code INS3.2: Algorithme général du pivot de Gauss # # # # # # # # # # Initialisation Quelques vérifications de base, puis On itère sur chacune des n lignes via le compteur i On cherche le meilleur pivot pour la i-eme variable parmi les lignes j >= i Si le pivot n’est pas en ligne i, on échange les deux lignes. On itère alors sur les lignes restantes via le compteur k On effectue la transvection Lk = Lk - alpha*Li avec alpha bien choisi Il ne reste plus qu’à remonter en partant de la fin. Code INS3.3: Implémentation de la recherche du pivot à partir de la ie ligne 1 2 3 4 5 6 7 8 9 10 def cherche_pivot(A,i): ’’’Recherche du meilleur pivot pour la i-eme variable dans les lignes suivant la ligne courante. Pour éviter d’avoir un pivot presque nul (pb de comparaison à 0 pour les flottants...), on va prendre le plus grand en valeur absolue.’’’ i_mem = i # Initialisation de la mémoire for j in range(i+1,len(A)): # On regarde les lignes ultérieures if abs(A[j][i]) > abs(A[i_mem][i]):# Si le pivot de la j-eme ligne est meilleur, i_mem = j # on le garde. return i_mem # On renvoie le numéro de la ligne du pivot. Code INS3.4: Implémentation de l’échange des lignes i et j d’une matrice. 1 2 3 4 5 def echange_lignes(A,i,j): ’’’Échange des lignes i et j dans la matrice A. Ne renvoie rien mais *modifie* la matrice A directement.’’’ for k in range(len(A)): # On itère sur les éléments de la ligne A[i][k],A[j][k] = A[j][k],A[i][k] # et on fait l’échange Code INS3.5: Implémentation de la procédure de transvection Lk ← Lk − αLi 1 2 3 4 5 def transvection(A,k,i,alpha): ’’’Transvection de la ligne Lk sous la forme Lk = Lk - alpha*Li. Ne renvoie rien mais *modifie* la matrice A directement.’’’ for j in range(len(A)): # On itère sur les éléments de la ligne A[k][j] = A[k][j] - alpha*A[i][j] # et on effectue la transvection E Bougnol, JJ Fleck, M Heckmann & M Kostyra, Kléber, PCSI& - INS3 Pivot de Gauss 3/8 Code INS3.6: Vérification sur l’exemple initial 1 2 3 4 5 6 7 8 9 10 A = [[1, 1, 1, 1], [1, 1, 2, 3], [2, 3, 1,-1], [3,-1,-1, 1]] Y = [ 4, 13, -5, 6] X = pivot_gauss(A,Y) print(X) 11 12 import numpy as np 13 14 15 X_np = np.matrix(A)**-1 * np.matrix(Y).transpose() print(X_np) 16 17 18 19 20 21 22 A = np.random.rand(9,9) Y = np.random.rand(9) X2= pivot_gauss(A,Y) X2_np = np.matrix(A)**-1 * np.matrix(Y).transpose() print([round(v,4) for v in X2]) print(np.around(X2_np,decimals=4)) Code INS3.7: Résultat du test précédent [-1.0000000000000167, 3.000000000000041, -5.0000000000000595, 7.000000000000032] [[-1.] [ 3.] [-5.] [ 7.]] [0.5642, -1.5298, -0.0893, -0.83, -0.41, 1.2085, 1.3018, 0.9811, 0.3951] [[ 0.5642] [-1.5298] [-0.0893] [-0.83 ] [-0.41 ] [ 1.2085] [ 1.3018] [ 0.9811] [ 0.3951]] E Bougnol, JJ Fleck, M Heckmann & M Kostyra, Kléber, PCSI& - INS3 Pivot de Gauss 4/8 Code INS3.8: Tests de rapidité Taille n | pivot | echange | transvection simple | transvections a partir de n/2 | ---------------------------------------------------------------------------------2 | 0.006 | 0.010 | 0.009 | 0.002 | 4 | 0.006 | 0.005 | 0.006 | 0.007 | 8 | 0.004 | 0.009 | 0.009 | 0.027 | 16 | 0.008 | 0.017 | 0.017 | 0.113 | 32 | 0.013 | 0.032 | 0.032 | 0.439 | 64 | 0.022 | 0.056 | 0.056 | 1.702 | 128 | 0.043 | 0.110 | 0.111 | 6.060 | 256 | 0.085 | 0.183 | 0.198 | 23.405 | 512 | 0.152 | 0.357 | 0.359 | 110.292 | 1024 | 0.350 | 0.911 | 1.389 | 414.461 | 2048 | 0.867 | 2.061 | 1.947 | 1693.602 | E Bougnol, JJ Fleck, M Heckmann & M Kostyra, Kléber, PCSI& - INS3 Pivot de Gauss Code INS3.9: Tests de vitesse globaux Taille n | Triangulation | Remontee | Pivot complet | Pivot via NumPy | ----------------------------------------------------------------------2 | 0.074 | 0.013 | 0.037 | 0.129 | 4 | 0.056 | 0.012 | 0.059 | 0.063 | 8 | 0.251 | 0.025 | 0.272 | 0.070 | 16 | 1.669 | 0.065 | 1.620 | 0.075 | 32 | 11.870 | 0.242 | 11.742 | 0.119 | 64 | 88.498 | 0.777 | 90.760 | 0.674 | 128 | 700.960 | 2.921 | 699.308 | 2.113 | 5/8 E Bougnol, JJ Fleck, M Heckmann & M Kostyra, Kléber, PCSI& - INS3 Pivot de Gauss Code INS3.10: Même NumPy marche tout de même en n3 ... Taille n | Pivot via NumPy | ---------------------------2 | 0.102 | 4 | 0.056 | 8 | 0.066 | 16 | 0.061 | 32 | 0.091 | 64 | 0.377 | 128 | 1.648 | 256 | 9.230 | 512 | 39.846 | 1024 | 232.507 | 2048 | 1556.124 | 4096 | 10732.557 | 8192 | 95080.232 | 6/8 E Bougnol, JJ Fleck, M Heckmann & M Kostyra, Kléber, PCSI& - INS3 Pivot de Gauss 7/8 Code INS3.11: Aménagement du pivot de Gauss pour inverser la matrice A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 def inversion(A0): ’’’Algorithme d’inversion matricielle de la matrice A0 par pivot de Gauss. L’idée est d’appliquer les transformations induite sur A0 à la matrice identité au fur et à mesure. Quand A0 arrive à l’identité, alors les transformations initiées sur l’identité donne l’inverse de A0. * La matrice A0 doit être inversible pour que l’algorithme fonctionne et est donnée sous forme de liste de listes où chaque sous-liste représente une ligne de la matrice. Le format np.array() fonctionne aussi. NB: la matrice doit être carrée. L’algorithme renvoie L’inverse de la matrice sous forme de np.array()’’’ # Initialisation: on copie la matrice A0 en profondeur pour ne pas # modifier les données de l’utilisateur A = copy.deepcopy(A0) n = len(A) # Quelques vérifications de base: assert n == len(A[0]) # A doit être une matrice carrée n*n, # Initialisation de l’inverse sous forme de la matrice identité A_inv = np.eye(n) # renvoie automatiquement un np.array() for i in range(n): # On itère sur chacune des n lignes j = cherche_pivot(A,i) # Recherche parmi les lignes j >= i if j > i: # Si le pivot n’est pas en i, on échange echange_lignes(A,i,j) # à la fois pour A echange_lignes(A_inv,i,j) # et pour son "inverse to be" for k in range(i+1,n): # On itère sur les lignes restantes # On effectue la transvection Lk = Lk - alpha*Li alpha = A[k][i]/A[i][i] # avec alpha bien choisi transvection(A,k,i,alpha) # transvection sur A transvection(A_inv,k,i,alpha) # et sur l’inverse to be # Il ne reste plus qu’à remonter en partant de la fin. for i in range(n-1,-1,-1): a = A[i][i] ligne = A[i][:] substitution(A,i,a,ligne) # Substitution sur A substitution(A_inv,i,a,ligne) # puis sur son "inverse to be" return A_inv 35 36 37 38 39 40 41 42 43 44 def substitution(A,i,a,ligne): ’’’Substitution vue comme une multiplication de ligne puis une série de transvections avec les lignes suivantes pour virer les termes non diagonaux’’’ n = len(A) # La substitution se fait en deux phases: for j in range(n): A[i][j] /= a # d’abord un passage Li = Li/a for k in range(n-1,i,-1): # ensuite une suite de transvections transvection(A,i,k,ligne[k]/a) # Li = Li - Lik/a * Lk 45 46 47 48 A = [[1,2,3],[4,5,6],[1/2,3,4]] print(inversion(A)) # Résultat de notre algorithme print(np.matrix(A)**(-1)) # Résultat by NumPy E Bougnol, JJ Fleck, M Heckmann & M Kostyra, Kléber, PCSI& - INS3 Pivot de Gauss Code INS3.12: Résultat du test d’inversion de matrice: ça marche ! [[ 0.44444444 0.22222222 -0.66666667] [-2.88888889 0.55555556 1.33333333] [ 2.11111111 -0.44444444 -0.66666667]] [[ 0.44444444 0.22222222 -0.66666667] [-2.88888889 0.55555556 1.33333333] [ 2.11111111 -0.44444444 -0.66666667]] 8/8