Time measurement feature (#6)

* making new branch and importing time

* add time_measurement decorator

* add measurement functionality to solve()
This commit is contained in:
Gromiusz 2024-10-31 17:50:21 +01:00 committed by GitHub
parent c938e63b7f
commit 73a12d3859
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 63 additions and 4 deletions

View File

@ -2,6 +2,7 @@ import math
from abc import ABC, abstractmethod
from concurrent.futures import ThreadPoolExecutor
from functools import partial
from time_measurement import time_measurement, threads_time_accumulator
class LinearAlgebraUtils(ABC):
@staticmethod
@ -90,10 +91,9 @@ class SequentialLinearAlgebraUtils(ABC):
return [x+y for x, y in zip(v1, v2)]
@staticmethod
def scalar_vector_multiply(omega, vector): # na pewno scalar matrix? a nie scalar vector?
def scalar_vector_multiply(omega, vector):
return [omega * x for x in vector]
@staticmethod
def matrix_norm(A):
return math.sqrt(sum(sum(element ** 2 for element in row) for row in A))
@ -171,6 +171,7 @@ class ThreadsLinearAlgebraUtils(ABC):
@staticmethod
@time_measurement(threads_time_accumulator)
def dot_product(v1, v2):
chunks = ThreadsLinearAlgebraUtils.divide_vectors_to_chunks(v1, v2)
with ThreadPoolExecutor(max_workers=ThreadsLinearAlgebraUtils.NUM_THREADS) as executor:
@ -178,6 +179,7 @@ class ThreadsLinearAlgebraUtils(ABC):
return sum(results)
@staticmethod
@time_measurement(threads_time_accumulator)
def matrix_vector_multiply(A, x):
chunks = ThreadsLinearAlgebraUtils.divide_vector_or_matrix_to_chunks(A)
with ThreadPoolExecutor(max_workers=ThreadsLinearAlgebraUtils.NUM_THREADS) as executor:
@ -186,6 +188,7 @@ class ThreadsLinearAlgebraUtils(ABC):
return [item for sublist in results for item in sublist]
@staticmethod
@time_measurement(threads_time_accumulator)
def vector_norm(v):
chunks = ThreadsLinearAlgebraUtils.divide_vector_or_matrix_to_chunks(v)
@ -198,6 +201,7 @@ class ThreadsLinearAlgebraUtils(ABC):
return total_sum**0.5
@staticmethod
@time_measurement(threads_time_accumulator)
def vector_scalar_divide(x, scalar):
chunks = ThreadsLinearAlgebraUtils.divide_vector_or_matrix_to_chunks(x)
@ -206,6 +210,7 @@ class ThreadsLinearAlgebraUtils(ABC):
return [item for sublist in results for item in sublist]
@staticmethod
@time_measurement(threads_time_accumulator)
def matrix_scalar_multiply(A, w):
chunks = ThreadsLinearAlgebraUtils.divide_vector_or_matrix_to_chunks(A)
with ThreadPoolExecutor(max_workers=ThreadsLinearAlgebraUtils.NUM_THREADS) as executor:
@ -213,6 +218,7 @@ class ThreadsLinearAlgebraUtils(ABC):
return [item for sublist in results for item in sublist]
@staticmethod
@time_measurement(threads_time_accumulator)
def vector_vector_subtraction(v1, v2):
chunks = ThreadsLinearAlgebraUtils.divide_vectors_to_chunks(v1, v2)
with ThreadPoolExecutor(max_workers=ThreadsLinearAlgebraUtils.NUM_THREADS) as executor:
@ -221,6 +227,7 @@ class ThreadsLinearAlgebraUtils(ABC):
@staticmethod
@time_measurement(threads_time_accumulator)
def vector_vector_addition(v1, v2):
chunks = ThreadsLinearAlgebraUtils.divide_vectors_to_chunks(v1, v2)
with ThreadPoolExecutor(max_workers=ThreadsLinearAlgebraUtils.NUM_THREADS) as executor:
@ -228,6 +235,7 @@ class ThreadsLinearAlgebraUtils(ABC):
return [item for sublist in results for item in sublist]
@staticmethod
@time_measurement(threads_time_accumulator)
def scalar_vector_multiply(omega, vector):
chunks = ThreadsLinearAlgebraUtils.divide_vector_or_matrix_to_chunks(vector)
with ThreadPoolExecutor(max_workers=ThreadsLinearAlgebraUtils.NUM_THREADS) as executor:
@ -236,6 +244,7 @@ class ThreadsLinearAlgebraUtils(ABC):
return [item for sublist in results for item in sublist]
@staticmethod
@time_measurement(threads_time_accumulator)
def matrix_norm(A):
chunks = ThreadsLinearAlgebraUtils.divide_vector_or_matrix_to_chunks(A)
@ -249,11 +258,13 @@ class ThreadsLinearAlgebraUtils(ABC):
return math.sqrt(total_sum)
@staticmethod
@time_measurement(threads_time_accumulator)
def divide_matrixes_to_chunks(A, B):
chunk_size = len(A) // ThreadsLinearAlgebraUtils.NUM_THREADS
return [(A[i:i + chunk_size], B[i:i + chunk_size]) for i in range(0, len(A), chunk_size)]
@staticmethod
@time_measurement(threads_time_accumulator)
def matrix_matrix_subtraction(A, B):
def subtract_chunk(pair):
@ -266,6 +277,7 @@ class ThreadsLinearAlgebraUtils(ABC):
return [row for chunk in results for row in chunk]
@staticmethod
@time_measurement(threads_time_accumulator)
def gaussian_elimination(A, b):
n = len(A)
M = [row[:] for row in A]

View File

@ -4,6 +4,9 @@ from linear_algebra_utils import ThreadsLinearAlgebraUtils
from eigenvalue_methods import EigenvalueMethods
from matrix_generator import MatrixGenerator
from processing_type import ProcessingType
from time_measurement import threads_time_accumulator
import time
import gc
class RichardsonMethod:
def __init__(self, method: ProcessingType, A, b, max_iterations, size: int, x0=None, tol=1e-5):
@ -47,6 +50,9 @@ class RichardsonMethod:
raise ValueError("Unknown method, please use 'SEQUENTIAL' or 'THREADS'.")
def solve(self):
gc.disable()
threads_time_accumulator.total_time = 0
start = time.time()
x = self.x0[:]
#if RichardsonMethod.convergence_norm(self.LinAlg, self.A, self.omega, self.I) >= 1:
# return RichardsonMethod.convergence_norm(self.A, self.omega, self.I), "Richardson method for those values will NOT converge",
@ -56,4 +62,13 @@ class RichardsonMethod:
residual = self.LinAlg.vector_vector_subtraction(self.b, Ax)
x = self.LinAlg.vector_vector_addition(x, self.LinAlg.scalar_vector_multiply(self.omega, residual))
end = time.time()
total_time = end - start
gc.enable()
if(self.LinAlg == SequentialLinearAlgebraUtils):
print(f"Total: {total_time:.3e}s")
elif(self.LinAlg == ThreadsLinearAlgebraUtils):
sequential_time = total_time - threads_time_accumulator.total_time
print(f"Total: {total_time:.3e}s, Seq: {sequential_time:.3e}s, Parallel: {threads_time_accumulator.total_time:.3e}s")
return x, 0

View File

@ -32,13 +32,21 @@ def calcualte_norm_from_matrix_numpy(A, n, max_iterations):
@pytest.mark.parametrize("n", [2, 3, 4, 5, 10, 20, 50, 100])
@pytest.mark.parametrize("processing_type", [ProcessingType.SEQUENTIAL, ProcessingType.THREADS])
def test_richardson_vs_cg(n: int, processing_type: ProcessingType):
def test_richardson_vs_cg(n: int, processing_type: ProcessingType, capsys):
print("matrix size: ", n)
tolerance = 1e-5
max_iterations=1000
A, b = MatrixGenerator.generate_random_matrix_and_vector(n)
richardson_solver = RichardsonMethod(processing_type, A, b, max_iterations, size=n, tol=1e-7)
solution_richardson, info_richardson = richardson_solver.solve()
# solution_richardson, info_richardson = richardson_solver.solve()
solution_richardson, info_richardson = None, None
with capsys.disabled():
solution_richardson, info_richardson = richardson_solver.solve()
# Przechwytywanie wyjścia po solve
captured = capsys.readouterr()
print("Captured output:", captured.out)
solution_cg, info = cg(A, b)

24
code/time_measurement.py Normal file
View File

@ -0,0 +1,24 @@
import time
from functools import wraps
class TimeAccumulator:
def __init__(self):
self.total_time = 0
threads_time_accumulator = TimeAccumulator()
def time_measurement(accumulator):
def decorator(func):
@wraps(func)
def inner(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
accumulator.total_time += end - start
return result
return inner
return decorator