1
0

Merge remote-tracking branch 'origin/feature/mpi-refactor' into feature/mpi

This commit is contained in:
Niklas Birk 2024-07-27 15:46:33 +02:00
commit 9008c57d04
3 changed files with 36 additions and 89 deletions

View File

@ -85,11 +85,8 @@ class Matrix:
@staticmethod @staticmethod
def flatten_internal(matrices): def flatten_internal(matrices):
flattened_data = [] flattened_data = [element for matrix in matrices for row in matrix.get_data() for element in row]
rows = 0 rows = sum(matrix.__shape__[0] for matrix in matrices)
for matrix in matrices:
flattened_data.extend(matrix.get_data())
rows += matrix.__shape__[0]
cols = matrices[0].__shape__[1] cols = matrices[0].__shape__[1]
return flattened_data, (rows, cols) return flattened_data, (rows, cols)
@ -114,13 +111,8 @@ class Matrix:
return self.__shape__ return self.__shape__
def __transpose_internal__(self): def __transpose_internal__(self):
rows = self.__shape__[0] rows, cols = self.__shape__
cols = self.__shape__[1] return [[self.__data__[i][j] for i in range(rows)] for j in range(cols)], (cols, rows)
transposed_data = [([0] * rows) for _ in range(cols)]
for i in range(rows):
for j in range(cols):
transposed_data[j][i] = self.__data__[i][j]
return transposed_data, (cols, rows)
def transpose(self): def transpose(self):
""" """
@ -144,6 +136,9 @@ class Matrix:
:param other: The object to compare to; must be either a ``Matrix``, a ``list`` or a ``numpy.ndarray`` :param other: The object to compare to; must be either a ``Matrix``, a ``list`` or a ``numpy.ndarray``
:return: True if data in the matrix are equal to the given data in other for each component, otherwise False :return: True if data in the matrix are equal to the given data in other for each component, otherwise False
""" """
if not isinstance(other, (Matrix, list, numpy.ndarray)):
raise ValueError("Matrix type is not comparable to type of given ``other``")
data_to_compare = other
if isinstance(other, Matrix): if isinstance(other, Matrix):
if self.__shape__ != other.__shape__: if self.__shape__ != other.__shape__:
return False return False
@ -154,45 +149,33 @@ class Matrix:
return False return False
elif isinstance(other, numpy.ndarray): elif isinstance(other, numpy.ndarray):
data_to_compare = other.tolist() data_to_compare = other.tolist()
else: return all(value == other_value
raise ValueError("Matrix type is not comparable to type of given ``other``") for row, other_row in zip(self.__data__, data_to_compare)
for value, other_value in zip(row, other_row))
for i in range(len(self.__data__)):
for j in range(len(self.__data__[i])):
if self.__data__[i][j] != data_to_compare[i][j]:
return False
return True
def __str__(self): def __str__(self):
return str(numpy.array(self.__data__)) return str(numpy.array(self.__data__))
def __neg_internal__(self): def __neg_internal__(self):
rows = range(self.__shape__[0]) return list(map(lambda row: [-value for value in row], self.__data__))
cols = range(self.__shape__[1])
return [[-(self.__data__[i][j]) for j in cols] for i in rows]
def __neg__(self): def __neg__(self):
return Matrix(self.__neg_internal__(), self.__shape__) return Matrix(self.__neg_internal__(), self.__shape__)
def __add_matrix_internal__(self, other): def __add_matrix_internal__(self, other):
rows = self.__shape__[0] return [list(map(sum, zip(*rows))) for rows in zip(self.__data__, other.__data__)]
cols = self.__shape__[1]
return [[(self.__data__[i][j] + other.__data__[i][j]) for j in range(cols)] for i in range(rows)]
def __add_scalar_internal__(self, other): def __add_scalar_internal__(self, other):
rows = self.__shape__[0] return [[value + other for value in row] for row in self.__data__]
cols = self.__shape__[1]
return [[(self.__data__[i][j] + other) for j in range(cols)] for i in range(rows)]
def __add__(self, other): def __add__(self, other):
if not isinstance(other, (Matrix, int, float)):
raise ValueError("Only a number or another ``Matrix`` can be added to a ``Matrix``")
if isinstance(other, Matrix): if isinstance(other, Matrix):
if self.__shape__ != other.__shape__: if self.__shape__ != other.__shape__:
raise ValueError("The shape of the operands must be the same") raise ValueError("The shape of the operands must be the same")
return Matrix(self.__add_matrix_internal__(other), self.__shape__) return Matrix(self.__add_matrix_internal__(other), self.__shape__)
elif isinstance(other, int) or isinstance(other, float):
return Matrix(self.__add_scalar_internal__(other), self.__shape__) return Matrix(self.__add_scalar_internal__(other), self.__shape__)
else:
raise ValueError("Only a number or another ``Matrix`` can be added to a ``Matrix``")
def __radd__(self, other): def __radd__(self, other):
return self + other return self + other
@ -204,28 +187,21 @@ class Matrix:
return -self + other return -self + other
def __truediv_scalar_internal__(self, other): def __truediv_scalar_internal__(self, other):
rows = self.__shape__[0] return [list(map(lambda value: value / other, row)) for row in self.__data__]
cols = self.__shape__[1]
return [[(self.__data__[i][j] / other) for j in range(cols)] for i in range(rows)]
def __truediv__(self, other): def __truediv__(self, other):
if isinstance(other, int) or isinstance(other, float): if not isinstance(other, (int, float)):
return Matrix(self.__truediv_scalar_internal__(other), self.__shape__)
else:
raise ValueError("A ``Matrix`` can only be divided ba a number") raise ValueError("A ``Matrix`` can only be divided ba a number")
return Matrix(self.__truediv_scalar_internal__(other), self.__shape__)
def __mul_rowmatrix_matrix__internal__(self, other): def __mul_rowmatrix_matrix__internal__(self, other):
cols = other.__shape__[1] rows, cols = self.__shape__[1], other.__shape__[1]
new_data = [0] * cols return [sum(self.__data__[0][j] * other.__data__[j][i] for j in range(rows)) for i in range(cols)]
for i in range(cols):
new_data[i] = sum([self.__data__[0][j] * other.__data__[j][i] for j in range(self.__shape__[1])])
return new_data
def __mul_matrix_internal__(self, other): def __mul_matrix_internal__(self, other):
if self.__shape__[0] == 1: if self.__shape__[0] == 1:
return self.__mul_rowmatrix_matrix__internal__(other) return self.__mul_rowmatrix_matrix__internal__(other)
rows = self.__shape__[0] rows, cols = self.__shape__[0], other.__shape__[1]
cols = other.__shape__[1]
new_data = [([0] * cols) for _ in range(rows)] new_data = [([0] * cols) for _ in range(rows)]
for i in range(rows): for i in range(rows):
for k in range(cols): for k in range(cols):
@ -233,9 +209,7 @@ class Matrix:
return new_data return new_data
def __mul_scalar_internal__(self, other): def __mul_scalar_internal__(self, other):
rows = range(self.__shape__[0]) return [list(map(lambda value: value * other, row)) for row in self.__data__]
cols = range(self.__shape__[1])
return [[(self.__data__[i][j] * other) for j in cols] for i in rows]
def __mul__(self, other): def __mul__(self, other):
if isinstance(other, Matrix): if isinstance(other, Matrix):
@ -255,31 +229,13 @@ class Matrix:
return self.__abs_sum_of_squares__() return self.__abs_sum_of_squares__()
def __abs_sum_of_squares__(self): def __abs_sum_of_squares__(self):
rows = self.__shape__[0] return sum(abs(element) ** 2 for row in self.__data__ for element in row)
cols = self.__shape__[1]
abs_sum = 0
for i in range(rows):
for j in range(cols):
abs_sum += abs(self.__data__[i][j]) ** 2
return abs_sum
def __col_sums__(self): def __col_sums__(self):
rows = self.__shape__[0] return [sum(abs(row[j]) for row in self.__data__) for j in range(self.__shape__[1])]
cols = self.__shape__[1]
col_sums = [0] * cols
for j in range(cols):
for i in range(rows):
col_sums[j] += abs(self.__data__[i][j])
return col_sums
def __row_sums__(self): def __row_sums__(self):
rows = self.__shape__[0] return [sum(abs(value) for value in row) for row in self.__data__]
cols = self.__shape__[1]
row_sums = [0] * rows
for i in range(rows):
for j in range(cols):
row_sums[i] += abs(self.__data__[i][j])
return row_sums
def norm(self, f: str = "frobenius"): def norm(self, f: str = "frobenius"):
""" """

View File

@ -111,7 +111,7 @@ class MatrixMPI:
:return: True if data in the matrix are equal to the given data in other for each component, otherwise False :return: True if data in the matrix are equal to the given data in other for each component, otherwise False
""" """
if isinstance(other, MatrixMPI): if isinstance(other, MatrixMPI):
return self.__data__ == other.__data__ return all(self.__mpi_comm__.allgather(self.__rank_subdata__ == other.__rank_subdata__))
else: else:
return self.__data__ == other return self.__data__ == other

View File

@ -80,8 +80,7 @@ class Vector(Matrix):
raise ValueError("Only a number or another ``Vector`` can be added to a ``Vector``") raise ValueError("Only a number or another ``Vector`` can be added to a ``Vector``")
def __mul_vector_same_shape_internal__(self, other): def __mul_vector_same_shape_internal__(self, other):
rows = self.__shape__[0] rows, cols = self.__shape__
cols = self.__shape__[1]
if rows >= cols: if rows >= cols:
new_data = [(self.__data__[i][0] * other.__data__[i][0]) for i in range(rows)] new_data = [(self.__data__[i][0] * other.__data__[i][0]) for i in range(rows)]
else: else:
@ -89,8 +88,7 @@ class Vector(Matrix):
return new_data return new_data
def __mul_tensor_internal__(self, other): def __mul_tensor_internal__(self, other):
rows = self.__shape__[0] rows, cols = self.__shape__[0], other.__shape__[1]
cols = other.__shape__[1]
return [[self.__data__[i][0] * other.__data__[0][j] for j in range(cols)] for i in range(rows)], (rows, cols) return [[self.__data__[i][0] * other.__data__[0][j] for j in range(cols)] for i in range(rows)], (rows, cols)
def __mul__(self, other): def __mul__(self, other):
@ -112,31 +110,24 @@ class Vector(Matrix):
"a compatible ``Matrix`` or a scalar") "a compatible ``Matrix`` or a scalar")
def __mul_matrix_vector_internal__(self, other): def __mul_matrix_vector_internal__(self, other):
rows = other.__shape__[0] rows, vector_rows = other.__shape__[0], self.__shape__[0]
new_data = [0] * rows return [sum([other.__data__[i][j] * self.__data__[j][0] for j in range(vector_rows)]) for i in range(rows)]
for i in range(rows):
new_data[i] = sum([other.__data__[i][j] * self.__data__[j][0] for j in range(self.__shape__[0])])
return new_data
def __rmul__(self, other): def __rmul__(self, other):
if isinstance(other, Matrix): return Vector(self.__mul_matrix_vector_internal__(other)) if isinstance(other, Matrix) else self * other
return Vector(self.__mul_matrix_vector_internal__(other))
return self * other
def __truediv_vector_internal__(self, other): def __truediv_vector_internal__(self, other):
rows = self.__shape__[0] rows, cols = self.__shape__
cols = self.__shape__[1]
return [[(self.__data__[i][j] / other.__data__[i][j]) for j in range(cols)] for i in range(rows)] return [[(self.__data__[i][j] / other.__data__[i][j]) for j in range(cols)] for i in range(rows)]
def __truediv__(self, other): def __truediv__(self, other):
if not isinstance(other, (Vector, int, float)):
raise ValueError("A ``Vector`` can only be divided ba a number or another same-shaped ``Vector``")
if isinstance(other, Vector): if isinstance(other, Vector):
if self.__shape__ != other.__shape__: if self.__shape__ != other.__shape__:
raise ValueError("The ``Vector``s to be divided must have the same shape") raise ValueError("The ``Vector``s to be divided must have the same shape")
return Vector(self.__truediv_vector_internal__(other)) return Vector(self.__truediv_vector_internal__(other))
elif isinstance(other, int) or isinstance(other, float):
return Vector(super().__truediv_scalar_internal__(other)) return Vector(super().__truediv_scalar_internal__(other))
else:
raise ValueError("A ``Vector`` can only be divided ba a number or another same-shaped ``Vector``")
def norm(self, **kwargs): def norm(self, **kwargs):
""" """