Add distributed computing for negation and addition (no memory distributing)
This commit is contained in:
parent
c0908b4299
commit
e6a9d5a2f0
@ -84,6 +84,25 @@ class Matrix:
|
|||||||
"""
|
"""
|
||||||
return self.__data__
|
return self.__data__
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def flatten(matrices: list):
|
||||||
|
"""
|
||||||
|
Flattens a list of matrices into one bigger matrix.
|
||||||
|
The columns must match the first ``Matrix`` in the list and the rows can be arbitrarily.
|
||||||
|
|
||||||
|
:param matrices: A list of matrices.
|
||||||
|
:type matrices: list
|
||||||
|
:return: A ``Matrix`` extended by all matrices in the list.
|
||||||
|
:rtype: ``Matrix``
|
||||||
|
"""
|
||||||
|
flattened_data = []
|
||||||
|
rows = 0
|
||||||
|
for matrix in matrices:
|
||||||
|
flattened_data.extend(matrix.get_data())
|
||||||
|
rows += matrix.__shape__[0]
|
||||||
|
cols = matrices[0].__shape__[1]
|
||||||
|
return Matrix(flattened_data, (rows, cols))
|
||||||
|
|
||||||
def shape(self):
|
def shape(self):
|
||||||
"""
|
"""
|
||||||
:return: the shape of the matrix, which is ``(rows, columns)``
|
:return: the shape of the matrix, which is ``(rows, columns)``
|
||||||
@ -219,7 +238,7 @@ class Matrix:
|
|||||||
def __rmul__(self, other):
|
def __rmul__(self, other):
|
||||||
return self * other
|
return self * other
|
||||||
|
|
||||||
def __abs_sum__(self):
|
def __abs_sum_of_squares__(self):
|
||||||
rows = self.__shape__[0]
|
rows = self.__shape__[0]
|
||||||
cols = self.__shape__[1]
|
cols = self.__shape__[1]
|
||||||
abs_sum = 0
|
abs_sum = 0
|
||||||
@ -258,7 +277,7 @@ class Matrix:
|
|||||||
:return: the norm as a number
|
:return: the norm as a number
|
||||||
"""
|
"""
|
||||||
if f == "frobenius":
|
if f == "frobenius":
|
||||||
norm = math.sqrt(self.__abs_sum__())
|
norm = math.sqrt(self.__abs_sum_of_squares__())
|
||||||
elif f == "col sum":
|
elif f == "col sum":
|
||||||
norm = max(self.__col_sums__())
|
norm = max(self.__col_sums__())
|
||||||
elif f == "row sum":
|
elif f == "row sum":
|
||||||
|
@ -5,9 +5,9 @@ from matrix import Matrix
|
|||||||
|
|
||||||
|
|
||||||
class MatrixMPI:
|
class MatrixMPI:
|
||||||
__comm__ = MPI.COMM_WORLD
|
__mpi_comm__ = MPI.COMM_WORLD
|
||||||
__size__ = __comm__.Get_size()
|
__mpi_size__ = __mpi_comm__.Get_size()
|
||||||
__rank__ = __comm__.Get_rank()
|
__mpi_rank__ = __mpi_comm__.Get_rank()
|
||||||
|
|
||||||
__matrix__: Matrix = None
|
__matrix__: Matrix = None
|
||||||
__chunk__: list = None
|
__chunk__: list = None
|
||||||
@ -16,23 +16,103 @@ class MatrixMPI:
|
|||||||
self.__matrix__ = Matrix(data=data, shape=shape, structure=structure, model=model, offset=offset, n=n)
|
self.__matrix__ = Matrix(data=data, shape=shape, structure=structure, model=model, offset=offset, n=n)
|
||||||
|
|
||||||
total_amount_of_rows = self.__matrix__.shape()[0]
|
total_amount_of_rows = self.__matrix__.shape()[0]
|
||||||
chunks = numpy.array_split(list(range(total_amount_of_rows)), self.__size__)
|
chunks = numpy.array_split(list(range(total_amount_of_rows)), self.__mpi_size__)
|
||||||
self.__chunk__ = chunks[self.__rank__].tolist()
|
self.__chunk__ = chunks[self.__mpi_rank__].tolist()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def of(matrix: Matrix):
|
||||||
|
return MatrixMPI(matrix.get_data(), matrix.shape())
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.__matrix__)
|
return str(self.__matrix__)
|
||||||
|
|
||||||
def get_rank_data(self):
|
def get_rank_submatrix(self):
|
||||||
rows = len(self.__chunk__)
|
rows = len(self.__chunk__)
|
||||||
cols = self.__matrix__.shape()[1]
|
cols = self.__matrix__.shape()[1]
|
||||||
return Matrix(self.__matrix__[self.__chunk__], (rows, cols))
|
return Matrix(self.__matrix__[self.__chunk__], (rows, cols))
|
||||||
|
|
||||||
def transpose(self):
|
def transpose(self):
|
||||||
return self.__matrix__.transpose()
|
"""
|
||||||
|
:return: the transpose of the matrix
|
||||||
|
"""
|
||||||
|
return MatrixMPI.of(self.__matrix__.transpose())
|
||||||
|
|
||||||
def T(self):
|
def T(self):
|
||||||
|
"""
|
||||||
|
Same as ``matrix.transpose()``
|
||||||
|
|
||||||
|
:return: see ``matrix.transpose()``
|
||||||
|
"""
|
||||||
return self.transpose()
|
return self.transpose()
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
"""
|
||||||
|
Return ``self==value``
|
||||||
|
|
||||||
mpi_matrix = MatrixMPI(list(range(1, 25)), (12, 2))
|
:param other: The object to compare to; must be either a ``MatrixMPI``, ``Matrix``, a ``list`` or a ``numpy.ndarray``
|
||||||
print(mpi_matrix.transpose())
|
: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.__matrix__ == other.__matrix__
|
||||||
|
else:
|
||||||
|
return self.__matrix__ == other
|
||||||
|
|
||||||
|
def __neg__(self):
|
||||||
|
gathered_data = self.__mpi_comm__.gather(-self.get_rank_submatrix())
|
||||||
|
data = self.__mpi_comm__.bcast(gathered_data)
|
||||||
|
return MatrixMPI.of(Matrix.flatten(data))
|
||||||
|
|
||||||
|
def __add__(self, other):
|
||||||
|
if isinstance(other, MatrixMPI):
|
||||||
|
other = other.get_rank_submatrix()
|
||||||
|
gathered_data = self.__mpi_comm__.gather(self.get_rank_submatrix() + other)
|
||||||
|
data = self.__mpi_comm__.bcast(gathered_data)
|
||||||
|
return MatrixMPI.of(Matrix.flatten(data))
|
||||||
|
|
||||||
|
def __radd__(self, other):
|
||||||
|
return self + other
|
||||||
|
|
||||||
|
def __sub__(self, other):
|
||||||
|
return self + (-other)
|
||||||
|
|
||||||
|
def __rsub__(self, other):
|
||||||
|
return -self + other
|
||||||
|
|
||||||
|
def __truediv__(self, other):
|
||||||
|
gathered_data = self.__mpi_comm__.gather(self.get_rank_submatrix() / other)
|
||||||
|
data = self.__mpi_comm__.bcast(gathered_data)
|
||||||
|
return MatrixMPI.of(Matrix.flatten(data))
|
||||||
|
|
||||||
|
def __mul__(self, other):
|
||||||
|
if isinstance(other, MatrixMPI):
|
||||||
|
return self.__matrix__ * other.__matrix__
|
||||||
|
else:
|
||||||
|
return self.__matrix__ * other
|
||||||
|
|
||||||
|
def __rmul__(self, other):
|
||||||
|
return self * other
|
||||||
|
|
||||||
|
def norm(self, f: str = "frobenius"):
|
||||||
|
"""
|
||||||
|
Calculates the norm of the matrix.
|
||||||
|
|
||||||
|
A norm is a positive definit, absolute homogeneous and subadditive function.
|
||||||
|
For Matrices a norm is also sub-multiplicative.
|
||||||
|
|
||||||
|
:param f: The norm to be used, could be either "frobenius", "row sum" or "col sum"
|
||||||
|
|
||||||
|
:return: the norm as a number
|
||||||
|
"""
|
||||||
|
return self.__matrix__.norm(f)
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self.__matrix__[key]
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
self.__matrix__[key] = value
|
||||||
|
|
||||||
|
|
||||||
|
# m1 = MatrixMPI(numpy.random.uniform(0, 1, 1_000_000), (1000, 1000))
|
||||||
|
m1 = MatrixMPI([1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6], (5, 3))
|
||||||
|
|
||||||
|
print(m1 - m1)
|
||||||
|
@ -378,3 +378,12 @@ class TestMatrix(TestCase):
|
|||||||
expected = Matrix([1, 2, 3, 4, 5, 60, 70, 8, 9, 100, 110, 12, 13, 14, 15, 16], (4, 4))
|
expected = Matrix([1, 2, 3, 4, 5, 60, 70, 8, 9, 100, 110, 12, 13, 14, 15, 16], (4, 4))
|
||||||
|
|
||||||
self.assertEqual(expected, actual)
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
|
def test_should_flatten_list_of_matrices(self):
|
||||||
|
m1 = Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9], (3, 3))
|
||||||
|
m2 = Matrix([1, 2, 3, 4, 5, 6], (2, 3))
|
||||||
|
|
||||||
|
actual = m1.flatten([m1, m2])
|
||||||
|
expected = Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6], (5, 3))
|
||||||
|
|
||||||
|
self.assertEqual(expected, actual)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user