Vous êtes sur la page 1sur 10

Résolution des systèmes linéaires

Travaux Dirigés/Travaux Pratiques N° 2


2023‑2024
Corrigé
Méthode directes
Objet ꞉ En utilisant Python, résoudre un système d’équations linéaires par les méthodes directes
1. Ecrire une fonction qui résout un système linéaire triangulaire inférieur
In [1]: import numpy as np
from math import *
import matplotlib.pyplot as plt
from matplotlib import cm

In [2]: def Descente(L,y)꞉


n = len(y)
x = np.zeros(n)
# tester si la matrice est triangulaire inférieure
if (np.triu(L,1) == np.zeros(n)).all()꞉
for i in range (n)꞉
x[i] = (y[i]‑np.vdot(L[i,0꞉i],x[0꞉i])) / L[i,i]
else꞉
print("la matrice n'est pas triangulaire inférieure")
return x

Une autre version de la fonction descente triangulaire꞉


In [3]: def system_lower_solve(A,b)꞉

m = np.size(A,0)
n = np.size(A,1)
assert(m==n)
d=np.diag(A)
p = np.prod(d)
assert(p != 0)

x = np.zeros((n,1))
x[0] = b[0]/A[0][0]
for i in range(1,n)꞉
s = 0
for k in range(i)꞉
s = s+A[i][k]*x[k]
x[i] = (b[i]‑s)/A[i][i]
return x

In [4]: n=4
L=np.zeros((n,n))
for i in range (n)꞉
for j in range (i+1)꞉
L[i,j]=1+i+j
print('L=')
print(L)
#y=5+10*np.random.rand﴾n﴿

y=np.array([1.,‑1.,2.,3.])
print('y=',y)
print('Solution de Lx=y ꞉')
x=Descente(L,y)
print(x)
print('erreur=',np.linalg.norm(np.dot(L,x)‑y))

L=
[[1. 0. 0. 0.]
[2. 3. 0. 0.]
[3. 4. 5. 0.]
[4. 5. 6. 7.]]
y= [ 1. ‑1. 2. 3.]
Solution de Lx=y ꞉
[ 1. ‑1. 0.6 0.05714286]
erreur= 0.0

In [5]: L=np.array([[3,0,0,0],
[‑1,2,0,0],
[2,‑2,1,0],
[1,‑1,2,‑3]],dtype = 'float64')
print(L)
#b=np.array﴾[[1],[‑1],[2],[3]]﴿
b=np.array([1.,‑1.,2.,3.])
print('b=',b)
x=Descente(L,b)
print('x=',x)
print('erreur=',np.linalg.norm(L.dot(x)‑b))

[[ 3. 0. 0. 0.]
[‑1. 2. 0. 0.]
[ 2. ‑2. 1. 0.]
[ 1. ‑1. 2. ‑3.]]
b= [ 1. ‑1. 2. 3.]
x= [ 0.33333333 ‑0.33333333 0.66666667 ‑0.33333333]
erreur= 0.0

1. Ecrire une fonction qui résout un système linéaire triangulaire supérieur


In [6]: def Remontee(U,y)꞉
n = len(y)
x = np.zeros(n)
if (np.tril(U,‑1) == np.zeros(n)).all()꞉
for i in range (n)꞉
x[n‑1‑i] = (y[n‑1‑i]‑np.vdot(U[n‑1‑i,n‑i꞉n],x[n‑i꞉n])) / U[n‑1‑i,n‑1‑i]
else꞉
print("la matrice n'est pas triangulaire supérieure")
return x

Une autre version de la fonction remontée triangulaire


In [7]: def system_upper_solve(A,b)꞉
m = np.size(A,0)
n = np.size(A,1)
assert(m==n)

d=np.diag(A)
p = np.prod(d)
assert(p != 0)

x = np.zeros((n,1))
x[n‑1] = b[n‑1]/A[n‑1][n‑1]
for i in range(n‑2,‑1,‑1)꞉
s = 0
for k in range(i+1,n)꞉
s = s+A[i][k]*x[k]

x[i] = (b[i]‑s)/A[i][i]
return x

In [8]: U=np.array([[3,1,2,‑1],
[0,2,2,1],
[0,0,1,3],
[0,0,0,‑3]],dtype = 'float64')
print(U)
#b=np.array﴾[[1],[‑1],[2],[3]]﴿
b=np.array([1.,‑1.,2.,3.])
print(b)
x=Remontee(U,b)
print(x)
print('erreur=',np.linalg.norm(U.dot(x)‑b))

[[ 3. 1. 2. ‑1.]
[ 0. 2. 2. 1.]
[ 0. 0. 1. 3.]
[ 0. 0. 0. ‑3.]]
[ 1. ‑1. 2. 3.]
[‑1.66666667 ‑5. 5. ‑1. ]
erreur= 0.0

1. Ecrire une fonction qui résout un système linéaire Ax = b par la méthode de décomposition LU
In [9]: def LU_Crout(A)꞉
n = len(A)
A1=np.array(A)
for k in range (n‑1)꞉
A1[k,k+1꞉n] = A1[k,k+1꞉n] / A1[k,k] #on divise par le pivot sur la ligne k à par
#on traite la matrice extraite entre les indices k+1 et n‑1
A1[k+1꞉n,k+1꞉n] = A1[k+1꞉n,k+1꞉n] ‑ (np.transpose([A1[k+1꞉n,k]])).dot([A1[k,k+1꞉
L = np.zeros((n,n))
for i in range (0,n)꞉
L[i,0꞉i+1]=A1[i,0꞉i+1]
U= A1 ‑ L + np.diag(np.ones(n))
return [L,U]

In [10]: def LU_Doolittle(A)꞉


n = len(A)
A1=np.array(A)
for k in range (n‑1)꞉
A1[k+1꞉n,k] = A1[k+1꞉n,k] / A1[k,k] #on divise par le pivot sur la colonne k à p
#on traite la matrice extraite entre les indices k+1 et n‑1
A1[k+1꞉n,k+1꞉n] = A1[k+1꞉n,k+1꞉n] ‑ (np.transpose([A1[k+1꞉n,k]])).dot([A1[k,k+1꞉
U = np.zeros((n,n))
for i in range (0,n)꞉
U[i,i꞉n]=A1[i,i꞉n]
L= A1 ‑ U + np.diag(np.ones(n))
return [L,U]

Une autre version de la fonction donnant la décomposition LU de Doolittle


In [11]: def lu_Doolittle(A)꞉
m = np.size(A,0)
n = np.size(A,1)
assert(n == m)
U = np.zeros((n,n))
L = np.eye(n)

U[0,0] = A[0,0]
for i in range(1,n)꞉
U[0][i] = A[0][i]
L[i][0] = A[i][0]/U[0][0]

for i in range(1,n)꞉
s = 0
for k in range(i)꞉
s = s+L[i][k]*U[k][i]

U[i][i] = A[i][i]‑s
for j in range(i+1,n)꞉
s = 0
for k in range(i)꞉
s = s+L[i][k]*U[k][j]

U[i][j] = A[i][j]‑s
s = 0
for k in range(i)꞉
s = s+L[j][k]*U[k][i]

L[j][i] = (A[j][i]‑s)/U[i][i]

return L,U

In [12]: def L_Cholesky(A)꞉


n = len(A)
A1=np.array(A)
C=(A!=A.T)
#print﴾"C=",C﴿
L = np.zeros((n,n))
sym=1
chol=1
if C.any()꞉
print("la matrice n'est pas symetrique")
sym=0
return [L,sym,chol]
for k in range (n)꞉
if A1[k,k] <= 0꞉
print("la matrice n'admet pas de decomposition Cholesky")
chol=0
return [L,sym,chol]
A1[k,k]=np.sqrt(A1[k,k])
A1[k+1꞉n,k] = A1[k+1꞉n,k] / A1[k,k] #on divise par le pivot sur la colonne k à p
A1[k,k+1꞉n] = A1[k,k+1꞉n] / A1[k,k] #on divise par le pivot sur la ligne k à par
#on traite la matrice extraite entre les indices k+1 et n‑1
A1[k+1꞉n,k+1꞉n] = A1[k+1꞉n,k+1꞉n] ‑ (np.transpose([A1[k+1꞉n,k]])).dot([A1[k,k+1꞉
for i in range (0,n)꞉
L[i,0꞉i+1]=A1[i,0꞉i+1]
return [L,sym,chol]

In [13]: import numpy as np


n = 3
A=np.array([[4,‑1,1],[4,‑8,1],[‑2,1,5]],dtype = 'float64')
b=np.array([7,‑21,15],dtype = 'float64')
print('A=',A)
print('Décomposition LU de Doolittle de A ꞉')
[L,U]=LU_Doolittle(A)
print('LU ꞉')
print('A=',A)
print('L=')
print(L)
print('U=')
print(U)
print('||A‑LU||=',np.linalg.norm(A‑L.dot(U)))
y=Descente(L,b)
print('y=',y)
x=Remontee(U,y)
print('x=',x)
print(A.dot(x))
print('||Ax‑b||=',np.linalg.norm(A.dot(x)‑b))

print('Décomposition LU de Crout de A ꞉')


[L,U]=LU_Crout(A)
print('LU ꞉')
print('A=',A)
print('L=')
print(L)
print('U=')
print(U)
print('||A‑LU||=',np.linalg.norm(A‑L.dot(U)))
y=Descente(L,b)
print('y=',y)
x=Remontee(U,y)
print('x=',x)
print(A.dot(x))
print('||Ax‑b||=',np.linalg.norm(A.dot(x)‑b))

A=np.array([[4.,6.,2.],[6.,10.,5.],[2.,5.,14.]])
print('Décomposition LLT de Cholesky de A ꞉')
[L,sym,chol]=L_Cholesky(A)
if chol==1 & sym==1꞉
print('LU ꞉')
print('A=',A)
print('L=')
print(L)
print('U=')
#U=transposée de L
U=L.T
print(U)
print('||A‑LU||=',np.linalg.norm(A‑L.dot(U)))
y=Descente(L,b)
print('y=',y)
x=Remontee(U,y)
print('x=',x)
print(A.dot(x))
print('||Ax‑b||=',np.linalg.norm(A.dot(x)‑b))

A= [[ 4. ‑1. 1.]
[ 4. ‑8. 1.]
[‑2. 1. 5.]]
Décomposition LU de Doolittle de A ꞉
LU ꞉
A= [[ 4. ‑1. 1.]
[ 4. ‑8. 1.]
[‑2. 1. 5.]]
L=
[[ 1. 0. 0. ]
[ 1. 1. 0. ]
[‑0.5 ‑0.07142857 1. ]]
U=
[[ 4. ‑1. 1. ]
[ 0. ‑7. 0. ]
[ 0. 0. 5.5]]
||A‑LU||= 0.0
y= [ 7. ‑28. 16.5]
x= [2. 4. 3.]
[ 7. ‑21. 15.]
||Ax‑b||= 0.0
Décomposition LU de Crout de A ꞉
LU ꞉
A= [[ 4. ‑1. 1.]
[ 4. ‑8. 1.]
[‑2. 1. 5.]]
L=
[[ 4. 0. 0. ]
[ 4. ‑7. 0. ]
[‑2. 0.5 5.5]]
U=
[[ 1. ‑0.25 0.25]
[ 0. 1. 0. ]
[ 0. 0. 1. ]]
||A‑LU||= 0.0
y= [1.75 4. 3. ]
x= [2. 4. 3.]
[ 7. ‑21. 15.]
||Ax‑b||= 0.0
Décomposition LLT de Cholesky de A ꞉
LU ꞉
A= [[ 4. 6. 2.]
[ 6. 10. 5.]
[ 2. 5. 14.]]
L=
[[2. 0. 0.]
[3. 1. 0.]
[1. 2. 3.]]
U=
[[2. 3. 1.]
[0. 1. 2.]
[0. 0. 3.]]
||A‑LU||= 0.0
y= [ 3.5 ‑31.5 24.83333333]
x= [ 69.69444444 ‑48.05555556 8.27777778]
[ 7. ‑21. 15.]
||Ax‑b||= 6.355287432313019e‑14

1. Ecrire une fonction qui teste si une matrice A est symétrique et définie positive
In [14]: def test(A)꞉
[L,sym,chol]=L_Cholesky(A)
if sym==0꞉
print("la matrice n'est pas symétrique")
else꞉
print("la matrice est symétrique")
if chol==0꞉
print("la matrice n'est pas définie positive")
else꞉
print("la matrice est définie positive")
return

print('Exemple 1')
A=np.array([[4.,6.,2.],[6.,10.,5.],[2.,5.,14.]])
test(A)
print('EXEMPLE 2')
A=np.array([[‑2.,6.,2.],[6.,10.,5.],[2.,5.,14.]])
test(A)
Exemple 1
la matrice est symétrique
la matrice est définie positive
EXEMPLE 2
la matrice n'admet pas de decomposition Cholesky
la matrice est symétrique
la matrice n'est pas définie positive

1. Ecrire une fonction qui calcule le déterminant d’une matrice A


In [15]: def determinant(A)꞉
[L,U]=LU_Doolittle(A)
determ=np.prod(np.diag(U))
return determ

A=np.array([[4,‑1,1],[4,‑8,1],[‑2,1,5]],dtype = 'float64')
print(determinant(A))
print(np.linalg.det(A))

‑154.0
‑154.00000000000006

Méthodes itératives
Objet ꞉ En utilisant Python, résoudre un système d’équations linéaires par les méthodes itératives
In [16]: def Jacobi(A,b,x0,eps,itmax)꞉
x = x0 #on initialise avec x0
M = np.diag(np.diag(A)) #M=D la matrice diagonale formée par la diagonale de A
N = M ‑ A #puisque N = L+U, ‑L et ‑U étant les parties sous‑diagonales et sur‑di
err = np.linalg.norm(A.dot(x) ‑ b) # l'erreur initiale est ||Ax0 ‑ b||
it = 0
while (err > eps and it < itmax)꞉ #on continue d'itérer tant qu'on n'a pas atteint
x = Descente(M,N.dot(x) + b) #on actualise x en trouvant la solution y de My =
err = np.linalg.norm(A.dot(x) ‑ b) #on actualise l'erreur
it = it + 1 #on actualise le paramètre d'itération
return [x,it] #on renvoie la solution approchée et le nombre d'itérations nécessai

In [17]: def GaussSeidel(A,b,x0,eps,itmax)꞉


x = x0
M = np.diag(np.diag(A))
for i in range (1,len(A))꞉ #on calcule M comme la somme des matrices sous‑diagonal
M = M + np.diag(np.diag(A,‑i),‑i)
N = M ‑ A
err = np.linalg.norm(A.dot(x)‑b)
it = 0
while err > eps and it < itmax꞉
x = Descente(M,N.dot(x)+b) #on utilise encore la méthode de descente car M est t
err = np.linalg.norm(A.dot(x)‑b)
it = it + 1
return [x,it]

In [18]: def Relaxation(A,b,x0,omega,eps,itmax)꞉ #on a un paramètre omega supplémentaire


x = x0
M = np.diag(np.diag(A)) / omega
for i in range (1,len(A))꞉
M = M + np.diag(np.diag(A,‑i),‑i)
N = M ‑ A
err = np.linalg.norm(A.dot(x) ‑ b)
it = 0
while err > eps and it < itmax꞉
x = Descente(M,N.dot(x) + b)
err = np.linalg.norm(A.dot(x) ‑ b)
it = it + 1
return [x,it]

1. Résoudre le problème Ax = b par la méthode de Jacobi


In [19]: n = 3
A=np.array([[4,‑1,1],[4,‑8,1],[‑2,1,5]],dtype = 'float64')
b=np.array([7,‑21,15],dtype = 'float64')
x0=np.array([0.,0.,0.])
eps=1.e‑6
itmax=100

print('**** JACOBI ****')


[x,it]=Jacobi(A,b,x0,eps,itmax)
print('x=',x)
print('it=',it)
print('erreur=',np.linalg.norm(A.dot(x) ‑ b))

print('**** GAUSS‑SEIDEL ****')


[x,it]=GaussSeidel(A,b,x0,eps,itmax)
print('x=',x)
print('it=',it)
print('erreur=',np.linalg.norm(A.dot(x) ‑ b))

**** JACOBI ****


x= [1.99999998 3.9999999 3. ]
it= 16
erreur= 7.44929842581221e‑07
**** GAUSS‑SEIDEL ****
x= [1.99999996 3.99999997 2.99999999]
it= 9
erreur= 1.493340495116296e‑07

1. Comparer le nombre des itérations et la qualité de la solution de cette méthode en variant les tests
d’arrêts.
In [20]: def Jacobi2(A,b,x0,eps,itmax)꞉

M = np.diag(np.diag(A)) #M=D la matrice diagonale formée par la diagonale de A


N = M ‑ A #puisque N = L+U, ‑L et ‑U étant les parties sous‑diagonales et sur‑di
x = x0 #on initialise avec x0
y=x0+2*eps
err = np.linalg.norm(y‑x) # l'erreur initiale est ||y ‑ x0||
it = 0
while (err > eps and it < itmax)꞉ #on continue d'itérer tant qu'on n'a pas atteint
y = x
x = Descente(M,N.dot(y) + b) #on actualise x en trouvant la solution y de My =
err = np.linalg.norm(y‑x) #on actualise l'erreur
it = it + 1 #on actualise le paramètre d'itération
return [x,it] #on renvoie la solution approchée et le nombre d'itérations nécessai

In [21]: print('**** JACOBI2 ****')


[x,it]=Jacobi2(A,b,x0,eps,itmax)
print('x=',x)
print('it=',it)
print('erreur=',np.linalg.norm(A.dot(x) ‑ b))

**** JACOBI2 ****


x= [1.99999985 3.9999997 2.99999978]
it= 15
erreur= 1.98293902309896e‑06
1. Résoudre le problème Ax = b par la méthode de relaxation
In [22]: print('**** RELAXATION ****')
omega=0.5
[x,it]=Relaxation(A,b,x0,omega,eps,itmax)
print('x=',x)
print('it=',it)
print('erreur=',np.linalg.norm(A.dot(x) ‑ b))

**** RELAXATION ****


x= [1.99999986 3.99999981 2.99999996]
it= 36
erreur= 9.909064479213725e‑07

1. Tracer le nombre d’itérations en fonction du paramètre w ∈]0, 2[ avec un test d’arrêt fixé
In [23]: import matplotlib.pyplot as plt
lomega=np.arange(0.1,2,0.01)
lit=[]
n=len(lomega)
for i in range(0,n)꞉
[x,it]=Relaxation(A,b,x0,lomega[i],eps,itmax)
lit.append(it)
plt.plot(lomega,np.array(lit),'r+',label="Nombre d'itérations vs Omega")
plt.xlabel(' Omega ')
plt.ylabel(" Nombre d'itérations ")
plt.show()

1. Déterminer le paramètre de relaxation qui résout un système linéaire


w

Ax = b en un nombre
optimal d’itérations
In [24]: indice=np.argmin(lit)
print(lomega[indice])
1.0099999999999996

Vous aimerez peut-être aussi