Fix: Correct jacobi, gauss, cholesky
This commit is contained in:
95
ex3.py
95
ex3.py
@@ -5,81 +5,62 @@ import numpy as np
|
||||
# D_inv = np.diag(1 / np.diag(A))
|
||||
|
||||
|
||||
def to_D(A: np.array) -> np.array:
|
||||
D = np.zeros_like(A)
|
||||
for i in range(len(A)):
|
||||
D[i, i] = A[i, i]
|
||||
return D
|
||||
|
||||
|
||||
def to_L(A: np.array) -> np.array:
|
||||
L = np.zeros_like(A)
|
||||
for i in range(len(A)):
|
||||
for j in range(len(A)):
|
||||
if i < j:
|
||||
L[i, j] = A[i, j]
|
||||
return L
|
||||
|
||||
|
||||
def to_U(A: np.array) -> np.array:
|
||||
U = np.zeros_like(A)
|
||||
for i in range(len(A)):
|
||||
for j in range(len(A)):
|
||||
if i > j:
|
||||
U[i, j] = A[i, j]
|
||||
return U
|
||||
|
||||
|
||||
def diag_strict_dominante(A) -> bool:
|
||||
diag_sum = 0
|
||||
for i in range(len(A)):
|
||||
diag_sum += A[i, i]
|
||||
other_sum = 0
|
||||
for i in range(len(A)):
|
||||
for j in range(len(A)):
|
||||
if i != j:
|
||||
other_sum += A[i, j]
|
||||
return diag_sum > other_sum
|
||||
"""
|
||||
Pour chaque ligne, il faut que la somme des coefs non-diagonaux soit inférieure au coef diagonal
|
||||
TOUT EST EN VALEUR ABSOLUE.
|
||||
:param A:
|
||||
:return:
|
||||
"""
|
||||
A = np.array(A)
|
||||
n = len(A)
|
||||
for i in range(n):
|
||||
diag = abs(A[i,i])
|
||||
row_sum = np.sum(np.abs(A[i,:])) - diag # On fait la somme de toute la ligne puis on soustrait le coef diagonal
|
||||
if diag <= row_sum:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def jacobi(A, b):
|
||||
def jacobi(A, b, epsilon=1e-6, max_iter=100_000):
|
||||
if not diag_strict_dominante(A):
|
||||
raise Exception('A doit être à diagnonale strictement dominante')
|
||||
raise ValueError("A doit être à diagonale strictement dominante")
|
||||
|
||||
L = to_L(A)
|
||||
U = to_U(A)
|
||||
x0 = np.array([0,0,0])
|
||||
epsilon = 1e-6
|
||||
max_iter = 100_000
|
||||
x = np.zeros_like(b, dtype=float)
|
||||
L = np.tril(A, k=-1) # Partie triangulaire inférieure (sans diagonale)
|
||||
U = np.triu(A, k=1) # Partie triangulaire supérieure (sans diagonale)
|
||||
|
||||
x = x0
|
||||
for k in range(max_iter):
|
||||
x_new = np.diag(1 / np.diag(A)) @ ((L + U) @ x) + np.diag(1 / np.diag(A)) @ b
|
||||
if np.linalg.norm(x_new - x, ord=2) < epsilon or np.linalg.norm(b - A @ x_new, ord=2) < epsilon:
|
||||
for _ in range(max_iter):
|
||||
x_new = np.diag(1 / np.diag(A)) @ (b - (L + U) @ x)
|
||||
if np.linalg.norm(x_new - x, ord=2) < epsilon:
|
||||
break
|
||||
x = x_new
|
||||
|
||||
return x
|
||||
return x_new
|
||||
|
||||
|
||||
def gauss_seidel(A, b):
|
||||
x0 = np.array([0, 0, 0])
|
||||
|
||||
D = to_D(A)
|
||||
L = to_L(A)
|
||||
U = to_U(A)
|
||||
D = np.diag(np.diag(A))
|
||||
L = np.tril(A, k=-1)
|
||||
U = np.triu(A, k=1)
|
||||
epsilon = 1e-6
|
||||
done = False
|
||||
max_iter = 100_000
|
||||
|
||||
# Pré-calcul de l'inverse de (D - L) pour éviter de le recalculer à chaque itération
|
||||
inv_D_minus_L = np.linalg.inv(D - L)
|
||||
|
||||
x = x0
|
||||
|
||||
while not done:
|
||||
x_new = np.linalg.inv(D - L) @ U @ x + np.linalg.inv(D - L) @ b
|
||||
for _ in range(max_iter):
|
||||
x_new = inv_D_minus_L @ (-U @ x) + inv_D_minus_L @ b
|
||||
|
||||
done: bool = np.linalg.norm(x_new - x, ord=2) < epsilon
|
||||
if np.linalg.norm(x_new - x, ord=2) < epsilon:
|
||||
return x_new
|
||||
x = x_new
|
||||
|
||||
return x
|
||||
raise RuntimeError('Gauss-Seidel')
|
||||
|
||||
|
||||
def relaxation(A, b, omega=1.0, epsilon=1e-6, max_iter=100_000):
|
||||
@@ -113,9 +94,9 @@ if __name__ == '__main__':
|
||||
|
||||
b = np.array([1,0,0])
|
||||
|
||||
D = to_D(A)
|
||||
L = to_L(A)
|
||||
U = to_U(A)
|
||||
D = np.diag(A)
|
||||
L = np.tril(A)
|
||||
U = np.triu(A)
|
||||
|
||||
res_jacobi = jacobi(A, b)
|
||||
print(res_jacobi)
|
||||
|
||||
Reference in New Issue
Block a user