diff --git a/README.md b/README.md index 2fabb65..d9e3c73 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Project for PWR -Project in python for module "Praktikum Wissenschaftliche Rechnen" in "Applied Mathematics" at *TU Bergakademie Freiberg*. +Project in python for module "Praktikum Wissenschaftliches Rechnen" in "Applied Mathematics" at *TU Bergakademie Freiberg*. # Task Implement MPI parallel Matrix and Vector classes in Python and apply them to a numerical problem / algorithm. \ No newline at end of file diff --git a/src/vector.py b/src/vector.py index a430d15..b6caedc 100644 --- a/src/vector.py +++ b/src/vector.py @@ -1,5 +1,3 @@ -import numpy - from matrix import Matrix diff --git a/src/vector_mpi.py b/src/vector_mpi.py index ab24cbf..b02bef3 100644 --- a/src/vector_mpi.py +++ b/src/vector_mpi.py @@ -45,7 +45,7 @@ class Vector: self.start_idx = int(self.rank * len(array) / self.size) self.end_idx = int(len(array) / self.size + self.rank * len(array) / self.size) - 1 self.rank_size = ( - self.end_idx - self.start_idx) + 1 # Größe des Teilvektors auf dem akt. Rang: Differenz zw. Start- und Endindex + 1 + self.end_idx - self.start_idx) + 1 # Größe des Teilvektors auf dem akt. Rang: Differenz zw. Start- und Endindex + 1 self.vec = array[ self.start_idx: self.end_idx + 1] # Auf jedem Rang werden die Einträge vom Start bis zum Endindex gespeichert self.kind = 'column' @@ -65,18 +65,18 @@ class Vector: "ERROR_1: Die übergebene Variable ist kein Numpy-Array, Keine Initialisierung der Vector-Klasse möglich.") def __add__(self, other): # Überschreibung der Addition - if (isinstance(self, Vector) and isinstance(other, Vector)): + if isinstance(self, Vector) and isinstance(other, Vector): Add_Vec = Vector(np.arange(self.dim)) - if (self.vshape[0] == other.vshape[0] and self.vshape[1] == other.vshape[1]): + if self.vshape[0] == other.vshape[0] and self.vshape[1] == other.vshape[1]: for i in range(0, self.rank_size): Add_Vec.vec[i] = self.vec[i] + other.vec[i] else: raise ValueError("Die Dimensionen der Vektoren stimmen nicht überein, Addition nicht möglich.") - elif (isinstance(self, Vector) and isinstance(other, (int, float, complex))): + elif isinstance(self, Vector) and isinstance(other, (int, float, complex)): Add_Vec = Vector(np.arange(self.dim)) for i in range(0, self.rank_size): Add_Vec.vec[i] = self.vec[i] + other - elif (isinstance(self, (int, float, complex)) and isinstance(other, Vector)): + elif isinstance(self, (int, float, complex)) and isinstance(other, Vector): Add_Vec = Vector(np.arange(other.dim)) for i in range(0, other.rank_size): Add_Vec.vec[i] = other.vec[i] + self @@ -85,8 +85,8 @@ class Vector: return Add_Vec def __radd__(self, other): # Überschreibung der Addition eines Vektors von rechts - Add_Vec = Vector(np.arange(self.dim)) - if (isinstance(self, Vector) and isinstance(other, (int, float, complex))): + Vector(np.arange(self.dim)) + if isinstance(self, Vector) and isinstance(other, (int, float, complex)): Add_Vec = Vector(np.arange(self.dim)) for i in range(0, self.rank_size): Add_Vec.vec[i] = self.vec[i] + other @@ -95,18 +95,18 @@ class Vector: return Add_Vec def __sub__(self, other): # Überschreibung der Subtraktion - if (isinstance(self, Vector) and isinstance(other, Vector)): + if isinstance(self, Vector) and isinstance(other, Vector): Sub_Vec = Vector(np.arange(self.dim)) - if (self.vshape[0] == other.vshape[0] and self.vshape[1] == other.vshape[1]): + if self.vshape[0] == other.vshape[0] and self.vshape[1] == other.vshape[1]: for i in range(0, self.rank_size): Sub_Vec.vec[i] = self.vec[i] - other.vec[i] else: raise ValueError("Die Dimension der Vektoren stimmen nicht überein, Subtraktion nicht möglich.") - elif (isinstance(self, Vector) and isinstance(other, (int, float, complex))): + elif isinstance(self, Vector) and isinstance(other, (int, float, complex)): Sub_Vec = Vector(np.arange(self.dim)) for i in range(0, self.rank_size): Sub_Vec.vec[i] = self.vec[i] - other - elif (isinstance(self, (int, float, complex)) and isinstance(other, Vector)): + elif isinstance(self, (int, float, complex)) and isinstance(other, Vector): Sub_Vec = Vector(np.arange(self.dim)) for i in range(0, other.rank_size): Sub_Vec.vec[i] = other.vec[i] - self @@ -116,7 +116,7 @@ class Vector: def __rsub__(self, other): # Subtraktion einer Zahl von einem Vektor Sub_Vec = Vector(np.arange(self.dim)) - if (isinstance(self, Vector) and isinstance(other, (float, int, complex))): + if isinstance(self, Vector) and isinstance(other, (float, int, complex)): for i in range(0, self.rank_size): Sub_Vec.vec[i] = self.vec[i] - other else: @@ -124,26 +124,26 @@ class Vector: return Sub_Vec def __mul__(self, other): # Überschreibung der Multiplikation - if (isinstance(self, Vector) and isinstance(other, Vector)): + if isinstance(self, Vector) and isinstance(other, Vector): Mult_Vec = Vector(np.arange(self.dim)) if (self.vshape[0] == other.vshape[0] and self.vshape[1] == other.vshape[ 1]): # Elementweise Multiplikation for i in range(0, self.rank_size): Mult_Vec.vec[i] = self.vec[i] * other.vec[i] - elif (self.vshape[1] == other.vshape[0] and self.vshape[0] == 1): # Inneres Produkt (Skalarprodukt) + elif self.vshape[1] == other.vshape[0] and self.vshape[0] == 1: # Inneres Produkt (Skalarprodukt) skal_prod = 0 for i in range(0, self.rank_size): skal_prod = skal_prod + self.vec[i] * other.vec[i] return skal_prod - elif (self.vshape[0] == other.vshape[1] and self.vshape[1] == 1): + elif self.vshape[0] == other.vshape[1] and self.vshape[1] == 1: raise ValueError("Kann erst implementiert werden, wenn Matrix-Klasse existiert.") else: raise ValueError("Die Dimensionen der Vektoren stimmen nicht überein, Multiplikation nicht möglich.") - elif (isinstance(self, Vector) and isinstance(other, (int, float, complex))): + elif isinstance(self, Vector) and isinstance(other, (int, float, complex)): Mult_Vec = Vector(np.arange(self.dim)) for i in range(0, self.rank_size): Mult_Vec.vec[i] = self.vec[i] * other - elif (isinstance(self, (int, float, complex)) and isinstance(other, Vector)): + elif isinstance(self, (int, float, complex)) and isinstance(other, Vector): Mult_Vec = Vector(np.arange(self.dim)) for i in range(0, other.rank_size): Mult_Vec.vec[i] = other.vec[i] * self @@ -153,7 +153,7 @@ class Vector: def __rmul__(self, other): # Rechtsseitige Multiplikation von einer Zahl an einen Vektor Mult_Vec = Vector(np.arange(self.dim)) - if (isinstance(self, Vector) and isinstance(other, (int, float, complex))): + if isinstance(self, Vector) and isinstance(other, (int, float, complex)): for i in range(0, self.rank_size): Mult_Vec.vec[i] = self.vec[i] * other else: @@ -162,21 +162,21 @@ class Vector: def __truediv__(self, other): Div_Vec = Vector(np.arange(self.dim, dtype=np.double)) - if (isinstance(self, Vector) and isinstance(other, Vector)): - if (self.vshape[0] == other.vshape[0] and self.vshape[1] == other.vshape[1]): + if isinstance(self, Vector) and isinstance(other, Vector): + if self.vshape[0] == other.vshape[0] and self.vshape[1] == other.vshape[1]: for i in range(0, self.rank_size): - if (other.vec[i] == 0): + if other.vec[i] == 0: raise ValueError("Ein Eintrag des Divisor-Vektors ist 0, Divion nicht möglich.") Div_Vec.vec[i] = self.vec[i] / other.vec[i] else: raise ValueError("Die Dimensionen der Vektoren stimmen nicht überein, Division nicht möglich.") - elif (isinstance(self, (int, float, complex)) and isinstance(other, Vector)): + elif isinstance(self, (int, float, complex)) and isinstance(other, Vector): for i in range(0, other.rank_size): - if (other.vec[i] == 0): + if other.vec[i] == 0: raise ValueError("Ein Eintrag des Divisor-Vektors ist 0, Divion nicht möglich.") Div_Vec.vec[i] = self / other.vec[i] - elif (isinstance(self, Vector) and isinstance(other, (float, int, complex))): - if (other == 0): + elif isinstance(self, Vector) and isinstance(other, (float, int, complex)): + if other == 0: raise ValueError("Division durch Null ist nicht möglich.") else: for i in range(0, self.rank_size): @@ -187,8 +187,8 @@ class Vector: def __rtruediv__(self, other): Div_Vec = Vector(np.arange(self.dim, dtype=np.double)) - if (isinstance(self, Vector) and isinstance(other, (float, int, complex))): - if (other == 0): + if isinstance(self, Vector) and isinstance(other, (float, int, complex)): + if other == 0: raise ValueError("Division durch Null ist nicht möglich.") else: for i in range(0, self.rank_size): @@ -202,12 +202,12 @@ class Vector: return Neg_Vec def shape(self): - if (self.rank == 0): + if self.rank == 0: return self.vshape def T(self): Transpose = self - if (self.kind == 'row'): + if self.kind == 'row': Transpose.kind = 'column' else: Transpose.kind = 'row' @@ -221,101 +221,101 @@ class Vector: def str(self): # Rückgabe des gesamten Vektors als string str_rep = '' - if (self.rank == 0): - if (self.kind == 'row'): + if self.rank == 0: + if self.kind == 'row': str_rep = '[' + ','.join(map(str, self.vec)) - if (self.kind == 'column'): + if self.kind == 'column': str_rep = '[' + '\n'.join(map(str, self.vec)) - if (self.size > 1): + if self.size > 1: self.comm.send(str_rep, dest=self.rank + 1) - elif (self.rank == self.size - 1): - if (self.kind == 'row'): + elif self.rank == self.size - 1: + if self.kind == 'row': str_rep = self.comm.recv(source=self.rank - 1) + ',' + ','.join(map(str, self.vec)) - if (self.kind == 'column'): + if self.kind == 'column': str_rep = self.comm.recv(source=self.rank - 1) + '\n' + '\n'.join(map(str, self.vec)) else: - if (self.kind == 'row'): + if self.kind == 'row': str_rep = self.comm.recv(source=self.rank - 1) + ',' + ','.join(map(str, self.vec)) - if (self.kind == 'column'): + if self.kind == 'column': str_rep = self.comm.recv(source=self.rank - 1) + '\n' + '\n'.join(map(str, self.vec)) self.comm.send(str_rep, dest=self.rank + 1) str_rep = self.comm.bcast(str_rep, root=self.size - 1) - if (self.rank == 0): + if self.rank == 0: return str_rep + ']' def string(self, limit_entry): # Gibt den Vektor als String zurück bis zum Eintrag limit_entry str_rep = '' - if (limit_entry > self.vec_size): + if limit_entry > self.vec_size: raise ValueError("ERROR_4: Die eingegebene Zahl ist größer, als der größte Index des Vectors.") # Rank 0 - if (self.rank == 0 and limit_entry <= self.end_idx): # Limit_entry befindet sich im Rang 0 - if (self.kind == 'row'): + if self.rank == 0 and limit_entry <= self.end_idx: # Limit_entry befindet sich im Rang 0 + if self.kind == 'row': str_rep = '[' + ','.join(map(str, self.vec[:limit_entry])) - if (self.kind == 'column'): + if self.kind == 'column': str_rep = '[' + '\n'.join(map(str, self.vec[:limit_entry])) - if (self.size > 1): + if self.size > 1: self.comm.send(str_rep, dest=self.rank + 1) - if (self.rank == 0 and limit_entry > self.end_idx): # Limit_entry befindet sich nicht im Rang 0 - if (self.kind == 'row'): + if self.rank == 0 and limit_entry > self.end_idx: # Limit_entry befindet sich nicht im Rang 0 + if self.kind == 'row': str_rep = '[' + ','.join(map(str, self.vec)) - if (self.kind == 'column'): + if self.kind == 'column': str_rep = '[' + '\n'.join(map(str, self.vec)) - if (self.size > 1): + if self.size > 1: self.comm.send(str_rep, dest=self.rank + 1) # Rank im Intervall [1,size-1] if ( - self.rank > 0 and self.rank < self.size - 1 and limit_entry <= self.start_idx): # wenn lim_ent == start_idx, dann wurden bereits alle relevanten Indizes im String gespeichert, da Vector nullinitialisiert ist + 0 < self.rank < self.size - 1 and limit_entry <= self.start_idx): # wenn lim_ent == start_idx, dann wurden bereits alle relevanten Indizes im String gespeichert, da Vector nullinitialisiert ist str_rep = self.comm.recv(source=self.rank - 1) self.comm.send(str_rep, dest=self.rank + 1) if ( - self.rank > 0 and self.rank < self.size - 1 and limit_entry > self.start_idx and limit_entry <= self.end_idx): - if (self.kind == 'row'): + 0 < self.rank < self.size - 1 and self.start_idx < limit_entry <= self.end_idx): + if self.kind == 'row': str_rep = self.comm.recv(source=self.rank - 1) + ',' + ','.join( map(str, self.vec[:(limit_entry - self.start_idx)])) - if (self.kind == 'column'): + if self.kind == 'column': str_rep = self.comm.recv(source=self.rank - 1) + '\n' + '\n'.join( map(str, self.vec[:(limit_entry - self.start_idx)])) + ']' self.comm.send(str_rep, dest=self.rank + 1) - if (self.rank > 0 and self.rank < self.size - 1 and limit_entry > self.end_idx): - if (self.kind == 'row'): + if 0 < self.rank < self.size - 1 and limit_entry > self.end_idx: + if self.kind == 'row': str_rep = self.comm.recv(source=self.rank - 1) + ',' + ','.join(map(str, self.vec)) - if (self.kind == 'column'): + if self.kind == 'column': str_rep = self.comm.recv(source=self.rank - 1) + '\n' + '\n'.join(map(str, self.vec)) self.comm.send(str_rep, dest=self.rank + 1) # Rank size-1 - if (self.rank == self.size - 1 and limit_entry <= self.start_idx and self.rank > 1): + if self.rank == self.size - 1 and limit_entry <= self.start_idx and self.rank > 1: str_rep = self.comm.recv(source=self.rank - 1) - if (self.rank == self.size - 1 and limit_entry >= self.start_idx and self.rank > 1): - if (self.kind == 'row'): + if self.rank == self.size - 1 and limit_entry >= self.start_idx and self.rank > 1: + if self.kind == 'row': str_rep = self.comm.recv(source=self.rank - 1) + ',' + ','.join( map(str, self.vec[:(limit_entry - self.start_idx)])) - if (self.kind == 'column'): + if self.kind == 'column': str_rep = self.comm.recv(source=self.rank - 1) + '\n' + '\n'.join( map(str, self.vec[:(limit_entry - self.start_idx)])) str_rep = self.comm.bcast(str_rep, root=self.size - 1) - if (self.rank == 0): + if self.rank == 0: return str_rep + ']' def norm(self): # Berechnung der 2-Norm / euklidischen Norm - norm = 0 + 0 sum_of_squares = 0 - if (self.rank == 0): + if self.rank == 0: for i in range(0, self.rank_size): sum_of_squares = sum_of_squares + self.vec[i] ** 2 - if (self.size > 1): + if self.size > 1: self.comm.send(sum_of_squares, dest=self.rank + 1) - elif (self.rank == self.size - 1): + elif self.rank == self.size - 1: sum_of_squares = self.comm.recv(source=self.rank - 1) for i in range(0, self.rank_size): sum_of_squares = sum_of_squares + self.vec[i] ** 2 @@ -333,7 +333,7 @@ class Vector: def normalize(self): # Normalisierung eines Vectors norm = self.norm() - if (norm == 0): + if norm == 0: return self normalized_vec = self / norm return normalized_vec