feat: convergence method suggested by wikipedia

This commit is contained in:
Krzysztof Rudnicki 2024-10-20 17:47:37 +02:00
parent 52d6012092
commit d3b0e8e0cc
5 changed files with 31 additions and 11 deletions

View File

@ -10,7 +10,7 @@ class EigenvalueMethods:
for _ in range(max_iter): for _ in range(max_iter):
x = LinearAlgebraUtils.matrix_vector_multiply(A, x) x = LinearAlgebraUtils.matrix_vector_multiply(A, x)
lambda_new = LinearAlgebraUtils.vector_norm(x) lambda_new = LinearAlgebraUtils.vector_norm(x)
x = LinearAlgebraUtils.scalar_divide(x, lambda_new) x = LinearAlgebraUtils.vector_scalar_divide(x, lambda_new)
if abs(lambda_new - lambda_old) < tol: if abs(lambda_new - lambda_old) < tol:
break break
lambda_old = lambda_new lambda_old = lambda_new

View File

@ -1,3 +1,5 @@
import math
class LinearAlgebraUtils: class LinearAlgebraUtils:
@staticmethod @staticmethod
def dot_product(v1, v2): def dot_product(v1, v2):
@ -8,15 +10,19 @@ class LinearAlgebraUtils:
return [LinearAlgebraUtils.dot_product(row, x) for row in A] return [LinearAlgebraUtils.dot_product(row, x) for row in A]
@staticmethod @staticmethod
def vector_subtraction(v1, v2): def matrix_scalar_multiply(A, w):
return [[w * A[i][j] for j in range(len(A[0]))] for i in range(len(A))]
@staticmethod
def vector_vector_subtraction(v1, v2):
return [x-y for x, y in zip(v1, v2)] return [x-y for x, y in zip(v1, v2)]
@staticmethod @staticmethod
def vector_addition(v1, v2): def vector_vector_addition(v1, v2):
return [x+y for x, y in zip(v1, v2)] return [x+y for x, y in zip(v1, v2)]
@staticmethod @staticmethod
def scalar_multiply(omega, vector): def scalar_matrix_multiply(omega, vector):
return [omega * x for x in vector] return [omega * x for x in vector]
@staticmethod @staticmethod
@ -24,5 +30,13 @@ class LinearAlgebraUtils:
return sum(x*x for x in v)**0.5 return sum(x*x for x in v)**0.5
@staticmethod @staticmethod
def scalar_divide(x, scalar): def matrix_norm(A):
return math.sqrt(sum(sum(element ** 2 for element in row) for row in A))
@staticmethod
def vector_scalar_divide(x, scalar):
return [xi / scalar for xi in x] return [xi / scalar for xi in x]
@staticmethod
def matrix_matrix_subtraction(A, B):
return [[A[i][j] - B[i][j] for j in range(len(A[0]))] for i in range(len(A))]

View File

@ -7,3 +7,6 @@ class MatrixGenerator:
A = np.dot(A.T, A) + np.eye(size) * size # dodanie `size` do przekątnej zwiększa wartości własne -> obejście problemu z overflow A = np.dot(A.T, A) + np.eye(size) * size # dodanie `size` do przekątnej zwiększa wartości własne -> obejście problemu z overflow
b = np.random.uniform(-1, 1, size) b = np.random.uniform(-1, 1, size)
return A, b return A, b
def generate_identity_matrix(size):
return np.eye(size)

View File

@ -1,13 +1,15 @@
from linear_algebra_utils import LinearAlgebraUtils from linear_algebra_utils import LinearAlgebraUtils
from eigenvalue_methods import EigenvalueMethods from eigenvalue_methods import EigenvalueMethods
from matrix_generator import MatrixGenerator
class RichardsonMethod: class RichardsonMethod:
def __init__(self, A, b, x0=None, max_iterations=1000, tol=1e-5): def __init__(self, A, b, size: int, x0=None, max_iterations=1000, tol=1e-5):
self.A = A self.A = A
self.b = b self.b = b
self.x0 = x0 if x0 is not None else [0.0] * len(b) self.x0 = x0 if x0 is not None else [0.0] * len(b)
self.max_iterations = max_iterations self.max_iterations = max_iterations
self.tol = tol self.tol = tol
self.I = MatrixGenerator.generate_identity_matrix(size)
def solve(self): def solve(self):
x = self.x0[:] x = self.x0[:]
@ -21,13 +23,14 @@ class RichardsonMethod:
for iteration in range(self.max_iterations): for iteration in range(self.max_iterations):
Ax = LinearAlgebraUtils.matrix_vector_multiply(self.A, x) Ax = LinearAlgebraUtils.matrix_vector_multiply(self.A, x)
residual = LinearAlgebraUtils.vector_subtraction(self.b, Ax) residual = LinearAlgebraUtils.vector_vector_subtraction(self.b, Ax)
wA = LinearAlgebraUtils.matrix_scalar_multiply(self.A, omega)
if LinearAlgebraUtils.vector_norm(residual) < self.tol: IMinuswA = LinearAlgebraUtils.matrix_matrix_subtraction(self.I, wA)
if LinearAlgebraUtils.matrix_norm(IMinuswA) < 1:
print('Convergence achieved.') print('Convergence achieved.')
return x return x
x = LinearAlgebraUtils.vector_addition(x, LinearAlgebraUtils.scalar_multiply(omega, residual)) x = LinearAlgebraUtils.vector_vector_addition(x, LinearAlgebraUtils.scalar_matrix_multiply(omega, residual))
print('Maximum number of iterations reached without convergence.') print('Maximum number of iterations reached without convergence.')
return x return x

View File

@ -12,7 +12,7 @@ def run_tests():
A, b = MatrixGenerator.generate_random_matrix_and_vector(n) A, b = MatrixGenerator.generate_random_matrix_and_vector(n)
richardson_solver = RichardsonMethod(A, b, max_iterations=10000000, tol=1e-7) richardson_solver = RichardsonMethod(A, b, size=n, max_iterations=10000000, tol=1e-7)
solution_richardson = richardson_solver.solve() solution_richardson = richardson_solver.solve()
print("Richardson Method Solution:", solution_richardson) print("Richardson Method Solution:", solution_richardson)