Try   HackMD

CAMA : ma10 Système d'équations

Cours du 26 / 04

Systèmes matriciels

Un système de plusieurs équations à autant d'inconnues peut s'écrire comme système matriciel

Ax=b :
[a11a12a1na21a22a2nan1an2ann][x1x2xn]=[b1b2bn]

Exemple

On acheté 3 fois des quantités de fruits dont nous n'avons pas le prix.

# A est la quantité de chaque fruit achetée # x est le prix de chaque fruit # b est la somme qu'on a payé pour chaque course A = np.array([[6,5,4], [5,3,2], [7,3,2]]) b = np.array([11.7, 7.9, 9.5]) x = lin.inv(A) @ b
array([0.8, 0.9, 0.6])

Résolution d'un système matriciel

Méthode du pivot de Gauss

On transforme

A en une matrice triangulaire pour résoudre le système de
O(n2)
opérations.

On met des

0 sur la première colonne en dessous de la diagonale en multipliant
A
par la matrice
E1
suivante :
E1=[1000a21a11100a31a11010an1a11001]

E2
sera similaire avec des termes
ak2a22
sous la diagonale, de même pour les matrices
En
suivantes.

Si on multiplie

A par
E1
il faut également multiplier
b
par
E1
.

Système matriciel avec matrice triangulaire

Il faut résoudre

Ux=c avec
U
une matrice triangulaire supérieure.

On part de la dernière ligne et on obtient

x[1]=c[1]U[1,1]
Une fois
x[1]
connu, on en déduit la valeur de
x[2]
, puis celle de
x[3]
, etc.

def solve_gauss(A, b): for i in range(len(A)-1): E = np.diag(np.array([1.,] * len(A), dtype=A.dtype)) coefs = - A[i+1:,i] / A[i,i] E[i+1:,i] = coefs A[i:, i:] = E[i:,i:] @ A[i:,i:] b[i+1:] += coefs * b[i] # multiplication terme à terme # A est maintenant triangulaire supérieur res = np.zeros(len(b), dtype=b.dtype) res[-1] = b[-1] / A[-1,-1] for i in range(len(A)-1)[::-1]: res[i] = (b[i] - A[i,i+1:] @ res[i+1:]) / A[i,i] return res
A = 10 * np.random.random(size=(5,5)) b = A.sum(axis=1)
A
 [[5.655 3.042 3.18  9.672 8.761]
 [3.963 9.923 9.868 7.934 6.328]
 [0.697 9.189 7.799 2.046 2.184]
 [6.314 8.533 4.879 8.112 4.583]
 [3.803 6.89  2.266 6.087 0.361]] 
b
 [30.31  38.015 21.914 32.42  19.407]
solve_gauss(A, b)

Décomposition Lower Upper

Si on a besoin de résoudre plusieurs systèmes matriciels avec

A, on décompose
A
en un produit d'une matrice triangulaire inférieure et d'une matrice triangulaire supérieure.
A=LU

On utilise le pivot de Gauss mais au lieu de modifier

b, on calcule l'inverse de la matrice
EnE2E1
:

EnE2E1Ax=EnE2E1bdonc(EnE2E1)1EnE2E1Ax=bE11E21En1EnE2E1Ax=b

Ce calcul est simple, la matrice inverse a les valeurs opposées :

E11=[1000a21a11100a31a11010an1a11001]

Le produit

E1=E11E11E21E31En1 est la concaténation des colonnes :
E1=[1000a21a11100a31a11a32a2210an1a11an2a22an3a331]

Pour résoudre

LUx=b :

  1. on résoud
    Ly=b
    obtenant
    y
  2. on résoud
    Ux=y
    obtenant la solution
    x
def LU(A): L = np.diag([1.,] * len(A)) for i in range(len(A)-1): E = np.diag([1.,] * len(A)) E[i+1:,i] = - A[i+1:,i] / A[i,i] L[i+1:,i] = -E[i+1:,i] A[i:, i:] = E[i:,i:] @ A[i:,i:] return L, A
A = 10 * np.random.random(size=(5,5)) L,U = LU(A.copy()) # Attention, notre fonction modifie A donc si on veut le réutiliser il faut une copie
A
 [[2.697 6.265 5.876 1.927 3.951]
 [2.495 0.021 9.085 0.504 9.23 ]
 [0.788 1.982 5.048 9.656 8.581]
 [3.19  7.474 8.344 0.124 2.577]
 [4.209 6.825 9.223 9.025 4.733]]
L
[[ 1.     0.     0.     0.     0.   ]
 [ 0.925  1.     0.     0.     0.   ]
 [ 0.292 -0.026  1.     0.     0.   ]
 [ 1.183 -0.011  0.418  1.     0.   ]
 [ 1.561  0.511 -0.529 -1.924  1.   ]]
U
[[  2.697   6.265   5.876   1.927   3.951]
 [  0.     -5.776   3.647  -1.279   5.574]
 [  0.      0.      3.427   9.059   7.573]
 [  0.      0.      0.     -5.957  -5.201]
 [  0.      0.      0.      0.    -10.285]]
A - (L @ U)
array([[ 0.,  0.,  0.,  0.,  0.],
       [ 0., -0.,  0.,  0.,  0.],
       [ 0.,  0., -0.,  0.,  0.],
       [ 0.,  0.,  0., -0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.]])

Gauss Jordan

On diagonalise

A par des multiplications matricielles similaire à celles de Gauss qui annulent aussi les termes au dessus de la diagonale :
E3=[10a11a330001a21a33000010000a41a331000an1a3301]

def solve_gauss_jordan(A,b): for i in range(len(A)): d1 = np.diag([1.,] * len(A)) d1[:,i] = - A[:,i] / A[i,i] A = d1 @ A b = d1 @ b return b / np.diag(A)
A = 10 * np.random.random(size=(5,5)) b = A.sum(axis=1) solve_gauss_jordan(A, b)
array([1., 1., 1., 1., 1.])