1
0

Merge branch 'refs/heads/feature/mpi'

This commit is contained in:
Niklas Birk 2024-07-27 15:58:10 +02:00
commit 0fc5b61844
3 changed files with 36 additions and 89 deletions

View File

@ -85,11 +85,8 @@ class Matrix:
@staticmethod
def flatten_internal(matrices):
flattened_data = []
rows = 0
for matrix in matrices:
flattened_data.extend(matrix.get_data())
rows += matrix.__shape__[0]
flattened_data = [element for matrix in matrices for row in matrix.get_data() for element in row]
rows = sum(matrix.__shape__[0] for matrix in matrices)
cols = matrices[0].__shape__[1]
return flattened_data, (rows, cols)
@ -114,13 +111,8 @@ class Matrix:
return self.__shape__
def __transpose_internal__(self):
rows = self.__shape__[0]
cols = self.__shape__[1]
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)
rows, cols = self.__shape__
return [[self.__data__[i][j] for i in range(rows)] for j in range(cols)], (cols, rows)
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``
: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 self.__shape__ != other.__shape__:
return False
@ -154,45 +149,33 @@ class Matrix:
return False
elif isinstance(other, numpy.ndarray):
data_to_compare = other.tolist()
else:
raise ValueError("Matrix type is not comparable to type of given ``other``")
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
return all(value == other_value
for row, other_row in zip(self.__data__, data_to_compare)
for value, other_value in zip(row, other_row))
def __str__(self):
return str(numpy.array(self.__data__))
def __neg_internal__(self):
rows = range(self.__shape__[0])
cols = range(self.__shape__[1])
return [[-(self.__data__[i][j]) for j in cols] for i in rows]
return list(map(lambda row: [-value for value in row], self.__data__))
def __neg__(self):
return Matrix(self.__neg_internal__(), self.__shape__)
def __add_matrix_internal__(self, other):
rows = self.__shape__[0]
cols = self.__shape__[1]
return [[(self.__data__[i][j] + other.__data__[i][j]) for j in range(cols)] for i in range(rows)]
return [list(map(sum, zip(*rows))) for rows in zip(self.__data__, other.__data__)]
def __add_scalar_internal__(self, other):
rows = self.__shape__[0]
cols = self.__shape__[1]
return [[(self.__data__[i][j] + other) for j in range(cols)] for i in range(rows)]
return [[value + other for value in row] for row in self.__data__]
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 self.__shape__ != other.__shape__:
raise ValueError("The shape of the operands must be the same")
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__)
else:
raise ValueError("Only a number or another ``Matrix`` can be added to a ``Matrix``")
def __radd__(self, other):
return self + other
@ -204,28 +187,21 @@ class Matrix:
return -self + other
def __truediv_scalar_internal__(self, other):
rows = self.__shape__[0]
cols = self.__shape__[1]
return [[(self.__data__[i][j] / other) for j in range(cols)] for i in range(rows)]
return [list(map(lambda value: value / other, row)) for row in self.__data__]
def __truediv__(self, other):
if isinstance(other, int) or isinstance(other, float):
return Matrix(self.__truediv_scalar_internal__(other), self.__shape__)
else:
if not isinstance(other, (int, float)):
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):
cols = other.__shape__[1]
new_data = [0] * 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
rows, cols = self.__shape__[1], other.__shape__[1]
return [sum(self.__data__[0][j] * other.__data__[j][i] for j in range(rows)) for i in range(cols)]
def __mul_matrix_internal__(self, other):
if self.__shape__[0] == 1:
return self.__mul_rowmatrix_matrix__internal__(other)
rows = self.__shape__[0]
cols = other.__shape__[1]
rows, cols = self.__shape__[0], other.__shape__[1]
new_data = [([0] * cols) for _ in range(rows)]
for i in range(rows):
for k in range(cols):
@ -233,9 +209,7 @@ class Matrix:
return new_data
def __mul_scalar_internal__(self, other):
rows = range(self.__shape__[0])
cols = range(self.__shape__[1])
return [[(self.__data__[i][j] * other) for j in cols] for i in rows]
return [list(map(lambda value: value * other, row)) for row in self.__data__]
def __mul__(self, other):
if isinstance(other, Matrix):
@ -255,31 +229,13 @@ class Matrix:
return self.__abs_sum_of_squares__()
def __abs_sum_of_squares__(self):
rows = self.__shape__[0]
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
return sum(abs(element) ** 2 for row in self.__data__ for element in row)
def __col_sums__(self):
rows = self.__shape__[0]
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
return [sum(abs(row[j]) for row in self.__data__) for j in range(self.__shape__[1])]
def __row_sums__(self):
rows = self.__shape__[0]
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
return [sum(abs(value) for value in row) for row in self.__data__]
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
"""
if isinstance(other, MatrixMPI):
return self.__data__ == other.__data__
return all(self.__mpi_comm__.allgather(self.__rank_subdata__ == other.__rank_subdata__))
else:
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``")
def __mul_vector_same_shape_internal__(self, other):
rows = self.__shape__[0]
cols = self.__shape__[1]
rows, cols = self.__shape__
if rows >= cols:
new_data = [(self.__data__[i][0] * other.__data__[i][0]) for i in range(rows)]
else:
@ -89,8 +88,7 @@ class Vector(Matrix):
return new_data
def __mul_tensor_internal__(self, other):
rows = self.__shape__[0]
cols = other.__shape__[1]
rows, cols = self.__shape__[0], other.__shape__[1]
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):
@ -112,31 +110,24 @@ class Vector(Matrix):
"a compatible ``Matrix`` or a scalar")
def __mul_matrix_vector_internal__(self, other):
rows = other.__shape__[0]
new_data = [0] * 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
rows, vector_rows = other.__shape__[0], self.__shape__[0]
return [sum([other.__data__[i][j] * self.__data__[j][0] for j in range(vector_rows)]) for i in range(rows)]
def __rmul__(self, other):
if isinstance(other, Matrix):
return Vector(self.__mul_matrix_vector_internal__(other))
return self * other
return Vector(self.__mul_matrix_vector_internal__(other)) if isinstance(other, Matrix) else self * other
def __truediv_vector_internal__(self, other):
rows = self.__shape__[0]
cols = self.__shape__[1]
rows, cols = self.__shape__
return [[(self.__data__[i][j] / other.__data__[i][j]) for j in range(cols)] for i in range(rows)]
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 self.__shape__ != other.__shape__:
raise ValueError("The ``Vector``s to be divided must have the same shape")
return Vector(self.__truediv_vector_internal__(other))
elif isinstance(other, int) or isinstance(other, float):
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):
"""