1
0
pwr_project/src/vector_mpi.py

85 lines
2.8 KiB
Python

import math
import numpy
from matrix_mpi import MatrixMPI
from vector import Vector
class VectorMPI(MatrixMPI):
def __init__(self, data=None, shape=None):
if isinstance(data, Vector):
self.__data__ = data
else:
self.__data__ = Vector(data=data, shape=shape)
# Calculate how much rows are delegated to the rank
total_amount_of_rows = self.__data__.shape()[0]
chunks = numpy.array_split(list(range(total_amount_of_rows)), self.__mpi_size__)
self.__chunk__ = chunks[self.__mpi_rank__].tolist()
# Store the delegated rows explicitly for calculations
self.__rank_subdata__ = Vector(self.__data__[self.__chunk__])
@staticmethod
def of(vector: Vector):
return VectorMPI(vector)
def transpose(self):
"""
:return: the transpose of the vector
"""
return VectorMPI.of(self.__data__.transpose())
def T(self):
return self.transpose()
def __str__(self):
return str(self.__data__)
def __neg__(self):
return VectorMPI.of(-self.__data__)
def __add__(self, other):
if isinstance(other, VectorMPI):
other = other.__rank_subdata__
return VectorMPI.of(Vector.flatten(self.__mpi_comm__.allgather(self.__rank_subdata__ + other)))
def __mul__(self, other):
if isinstance(other, VectorMPI):
other = other.__data__
if isinstance(other, int) or isinstance(other, float):
result = Vector.flatten(self.__mpi_comm__.allgather(self.__rank_subdata__ * other))
else:
result = self.__data__ * other
return VectorMPI.of(result) if isinstance(result, Vector) else result
def __rmul__(self, other):
if isinstance(other, MatrixMPI):
return VectorMPI.of(Vector.flatten(self.__mpi_comm__.allgather(other.get_rank_subdata() * self.get_data())))
return self * other
def __truediv__(self, other):
if isinstance(other, VectorMPI):
other = other.__rank_subdata__
return VectorMPI.of(Vector.flatten(self.__mpi_comm__.allgather(self.__rank_subdata__ / other)))
def norm(self, **kwargs):
"""
Computes the 2-norm of the vector which is the Frobenius-Norm of a nx1 matrix.
:param kwargs: ignored
:return: the 2-norm of the vector
"""
return math.sqrt(self.__mpi_comm__.allreduce(self.__rank_subdata__.get_abs_sum_of_squares()))
def normalize(self):
"""
A normalized vector has the length (norm) 1.
To achieve that the vector is divided by the norm of itself.
:return: the normalized vector
"""
return VectorMPI.of(Vector.flatten(self.__mpi_comm__.allgather(self.__rank_subdata__ / self.norm())))