2024-01-13 12:55:53 +01:00
import numpy as np
from mpi4py import MPI
class Vector :
start_idx = 0 # Nullter Eintrag des Vektors auf dem aktuellen Rang
end_idx = 0 # Letzer Eintrag des Vektors auf dem aktuellen Rang
rank_size = 0 # Dimension des Vektors der auf dem aktuellen Rang gespeichert wird
kind = ' ' # Art des Vektors, Zeilen oder Spaltenvektor
vec = np . arange ( rank_size )
vshape = np . arange ( 2 ) # Array mit Länge 2, um die Shape des Vektors zu speichern
dim = 0 # Gesamtdimension des Vektors, Länge des Vektors
comm = MPI . COMM_WORLD
size = comm . Get_size ( )
rank = comm . Get_rank ( )
# Konstruktor
def __init__ ( self , array ) :
if isinstance ( array , np . ndarray ) :
form = array . shape
if len ( array ) < self . size :
raise ValueError ( " ERROR_3: Die Dimension des Vektors ist kleiner als die Anzahl der benutzten Ränge. " )
if len ( form ) > 2 :
raise ValueError ( " ERROR_2: Falsche Dimension, kann kein 1 x n oder n x 1 Vektor sein. " )
# Array ist Zeilenvektor:
if len ( form ) == 1 or ( len ( form ) == 2 and form [ 0 ] == 1 ) :
self . vshape [ 0 ] = 1
self . vshape [ 1 ] = len ( array ) # Shape des Vectors
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 . vec = array [
self . start_idx : self . end_idx + 1 ] # Auf jedem Rang werden die Einträge vom Start bis zum Endindex gespeichert
self . kind = ' row '
self . dim = len ( array )
# Array ist Spaltenvektor
if len ( form ) == 2 and form [ 1 ] == 1 :
self . vshape [ 0 ] = len ( array )
self . vshape [ 1 ] = 1
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 = (
2024-01-13 14:00:04 +01:00
self . end_idx - self . start_idx ) + 1 # Größe des Teilvektors auf dem akt. Rang: Differenz zw. Start- und Endindex + 1
2024-01-13 12:55:53 +01:00
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 '
self . dim = len ( array )
elif isinstance ( array , list ) :
self . vshape [ 0 ] = 1
self . vshape [ 1 ] = len ( array )
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
self . vec = np . array ( array [ self . start_idx : self . end_idx + 1 ] )
self . kind = ' row '
self . dim = len ( array )
else :
raise ValueError (
" ERROR_1: Die übergebene Variable ist kein Numpy-Array, Keine Initialisierung der Vector-Klasse möglich. " )
def __add__ ( self , other ) : # Überschreibung der Addition
2024-01-13 14:00:04 +01:00
if isinstance ( self , Vector ) and isinstance ( other , Vector ) :
2024-01-13 12:55:53 +01:00
Add_Vec = Vector ( np . arange ( self . dim ) )
2024-01-13 14:00:04 +01:00
if self . vshape [ 0 ] == other . vshape [ 0 ] and self . vshape [ 1 ] == other . vshape [ 1 ] :
2024-01-13 12:55:53 +01:00
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. " )
2024-01-13 14:00:04 +01:00
elif isinstance ( self , Vector ) and isinstance ( other , ( int , float , complex ) ) :
2024-01-13 12:55:53 +01:00
Add_Vec = Vector ( np . arange ( self . dim ) )
for i in range ( 0 , self . rank_size ) :
Add_Vec . vec [ i ] = self . vec [ i ] + other
2024-01-13 14:00:04 +01:00
elif isinstance ( self , ( int , float , complex ) ) and isinstance ( other , Vector ) :
2024-01-13 12:55:53 +01:00
Add_Vec = Vector ( np . arange ( other . dim ) )
for i in range ( 0 , other . rank_size ) :
Add_Vec . vec [ i ] = other . vec [ i ] + self
else :
raise ValueError ( " Ungeeigneter Datentyp für die Addition mit einem Vektor. " )
return Add_Vec
def __radd__ ( self , other ) : # Überschreibung der Addition eines Vektors von rechts
2024-01-13 14:00:04 +01:00
Vector ( np . arange ( self . dim ) )
if isinstance ( self , Vector ) and isinstance ( other , ( int , float , complex ) ) :
2024-01-13 12:55:53 +01:00
Add_Vec = Vector ( np . arange ( self . dim ) )
for i in range ( 0 , self . rank_size ) :
Add_Vec . vec [ i ] = self . vec [ i ] + other
else :
raise ValueError ( " Ungeeigneter Datentyp für die Addition mit einem Vektor. " )
return Add_Vec
def __sub__ ( self , other ) : # Überschreibung der Subtraktion
2024-01-13 14:00:04 +01:00
if isinstance ( self , Vector ) and isinstance ( other , Vector ) :
2024-01-13 12:55:53 +01:00
Sub_Vec = Vector ( np . arange ( self . dim ) )
2024-01-13 14:00:04 +01:00
if self . vshape [ 0 ] == other . vshape [ 0 ] and self . vshape [ 1 ] == other . vshape [ 1 ] :
2024-01-13 12:55:53 +01:00
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. " )
2024-01-13 14:00:04 +01:00
elif isinstance ( self , Vector ) and isinstance ( other , ( int , float , complex ) ) :
2024-01-13 12:55:53 +01:00
Sub_Vec = Vector ( np . arange ( self . dim ) )
for i in range ( 0 , self . rank_size ) :
Sub_Vec . vec [ i ] = self . vec [ i ] - other
2024-01-13 14:00:04 +01:00
elif isinstance ( self , ( int , float , complex ) ) and isinstance ( other , Vector ) :
2024-01-13 12:55:53 +01:00
Sub_Vec = Vector ( np . arange ( self . dim ) )
for i in range ( 0 , other . rank_size ) :
Sub_Vec . vec [ i ] = other . vec [ i ] - self
else :
raise ValueError ( " Ungeeigneter Datentyp für die Subtraktion mit einem Vektor. " )
return Sub_Vec
def __rsub__ ( self , other ) : # Subtraktion einer Zahl von einem Vektor
Sub_Vec = Vector ( np . arange ( self . dim ) )
2024-01-13 14:00:04 +01:00
if isinstance ( self , Vector ) and isinstance ( other , ( float , int , complex ) ) :
2024-01-13 12:55:53 +01:00
for i in range ( 0 , self . rank_size ) :
Sub_Vec . vec [ i ] = self . vec [ i ] - other
else :
raise ValueError ( " Ungeeigneter Datentyp für die Subtraktion von einem Vektor. " )
return Sub_Vec
def __mul__ ( self , other ) : # Überschreibung der Multiplikation
2024-01-13 14:00:04 +01:00
if isinstance ( self , Vector ) and isinstance ( other , Vector ) :
2024-01-13 12:55:53 +01:00
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 ]
2024-01-13 14:00:04 +01:00
elif self . vshape [ 1 ] == other . vshape [ 0 ] and self . vshape [ 0 ] == 1 : # Inneres Produkt (Skalarprodukt)
2024-01-13 12:55:53 +01:00
skal_prod = 0
for i in range ( 0 , self . rank_size ) :
skal_prod = skal_prod + self . vec [ i ] * other . vec [ i ]
return skal_prod
2024-01-13 14:00:04 +01:00
elif self . vshape [ 0 ] == other . vshape [ 1 ] and self . vshape [ 1 ] == 1 :
2024-01-13 12:55:53 +01:00
raise ValueError ( " Kann erst implementiert werden, wenn Matrix-Klasse existiert. " )
else :
raise ValueError ( " Die Dimensionen der Vektoren stimmen nicht überein, Multiplikation nicht möglich. " )
2024-01-13 14:00:04 +01:00
elif isinstance ( self , Vector ) and isinstance ( other , ( int , float , complex ) ) :
2024-01-13 12:55:53 +01:00
Mult_Vec = Vector ( np . arange ( self . dim ) )
for i in range ( 0 , self . rank_size ) :
Mult_Vec . vec [ i ] = self . vec [ i ] * other
2024-01-13 14:00:04 +01:00
elif isinstance ( self , ( int , float , complex ) ) and isinstance ( other , Vector ) :
2024-01-13 12:55:53 +01:00
Mult_Vec = Vector ( np . arange ( self . dim ) )
for i in range ( 0 , other . rank_size ) :
Mult_Vec . vec [ i ] = other . vec [ i ] * self
else :
raise ValueError ( " Ungeeigneter Datentyp für die Multiplikation mit einem Vektor. " )
return Mult_Vec
def __rmul__ ( self , other ) : # Rechtsseitige Multiplikation von einer Zahl an einen Vektor
Mult_Vec = Vector ( np . arange ( self . dim ) )
2024-01-13 14:00:04 +01:00
if isinstance ( self , Vector ) and isinstance ( other , ( int , float , complex ) ) :
2024-01-13 12:55:53 +01:00
for i in range ( 0 , self . rank_size ) :
Mult_Vec . vec [ i ] = self . vec [ i ] * other
else :
raise ValueError ( " Ungeeigneter Datentyp für die Multiplikation mit einem Vektor. " )
return Mult_Vec
def __truediv__ ( self , other ) :
Div_Vec = Vector ( np . arange ( self . dim , dtype = np . double ) )
2024-01-13 14:00:04 +01:00
if isinstance ( self , Vector ) and isinstance ( other , Vector ) :
if self . vshape [ 0 ] == other . vshape [ 0 ] and self . vshape [ 1 ] == other . vshape [ 1 ] :
2024-01-13 12:55:53 +01:00
for i in range ( 0 , self . rank_size ) :
2024-01-13 14:00:04 +01:00
if other . vec [ i ] == 0 :
2024-01-13 12:55:53 +01:00
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. " )
2024-01-13 14:00:04 +01:00
elif isinstance ( self , ( int , float , complex ) ) and isinstance ( other , Vector ) :
2024-01-13 12:55:53 +01:00
for i in range ( 0 , other . rank_size ) :
2024-01-13 14:00:04 +01:00
if other . vec [ i ] == 0 :
2024-01-13 12:55:53 +01:00
raise ValueError ( " Ein Eintrag des Divisor-Vektors ist 0, Divion nicht möglich. " )
Div_Vec . vec [ i ] = self / other . vec [ i ]
2024-01-13 14:00:04 +01:00
elif isinstance ( self , Vector ) and isinstance ( other , ( float , int , complex ) ) :
if other == 0 :
2024-01-13 12:55:53 +01:00
raise ValueError ( " Division durch Null ist nicht möglich. " )
else :
for i in range ( 0 , self . rank_size ) :
Div_Vec . vec [ i ] = self . vec [ i ] / other
else :
raise ValueError ( " ERROR 11: Ungeeigneter Datentyp für die Division mit einem Vektor. " )
return Div_Vec
def __rtruediv__ ( self , other ) :
Div_Vec = Vector ( np . arange ( self . dim , dtype = np . double ) )
2024-01-13 14:00:04 +01:00
if isinstance ( self , Vector ) and isinstance ( other , ( float , int , complex ) ) :
if other == 0 :
2024-01-13 12:55:53 +01:00
raise ValueError ( " Division durch Null ist nicht möglich. " )
else :
for i in range ( 0 , self . rank_size ) :
Div_Vec . vec [ i ] = self . vec [ i ] / other
else :
raise ValueError ( " ERROR 10: Uneignete Datentyp, um einen Vektor durch diesen zu dividieren " )
return Div_Vec
def __neg__ ( self ) :
Neg_Vec = - 1 * self
return Neg_Vec
def shape ( self ) :
2024-01-13 14:00:04 +01:00
if self . rank == 0 :
2024-01-13 12:55:53 +01:00
return self . vshape
def T ( self ) :
Transpose = self
2024-01-13 14:00:04 +01:00
if self . kind == ' row ' :
2024-01-13 12:55:53 +01:00
Transpose . kind = ' column '
else :
Transpose . kind = ' row '
# Tauschen der Dimensionen
var_shift = self . vshape [ 0 ]
Transpose . vshape [ 0 ] = self . vshape [ 1 ]
Transpose . vshape [ 1 ] = var_shift
return Transpose
def str ( self ) : # Rückgabe des gesamten Vektors als string
str_rep = ' '
2024-01-13 14:00:04 +01:00
if self . rank == 0 :
if self . kind == ' row ' :
2024-01-13 12:55:53 +01:00
str_rep = ' [ ' + ' , ' . join ( map ( str , self . vec ) )
2024-01-13 14:00:04 +01:00
if self . kind == ' column ' :
2024-01-13 12:55:53 +01:00
str_rep = ' [ ' + ' \n ' . join ( map ( str , self . vec ) )
2024-01-13 14:00:04 +01:00
if self . size > 1 :
2024-01-13 12:55:53 +01:00
self . comm . send ( str_rep , dest = self . rank + 1 )
2024-01-13 14:00:04 +01:00
elif self . rank == self . size - 1 :
if self . kind == ' row ' :
2024-01-13 12:55:53 +01:00
str_rep = self . comm . recv ( source = self . rank - 1 ) + ' , ' + ' , ' . join ( map ( str , self . vec ) )
2024-01-13 14:00:04 +01:00
if self . kind == ' column ' :
2024-01-13 12:55:53 +01:00
str_rep = self . comm . recv ( source = self . rank - 1 ) + ' \n ' + ' \n ' . join ( map ( str , self . vec ) )
else :
2024-01-13 14:00:04 +01:00
if self . kind == ' row ' :
2024-01-13 12:55:53 +01:00
str_rep = self . comm . recv ( source = self . rank - 1 ) + ' , ' + ' , ' . join ( map ( str , self . vec ) )
2024-01-13 14:00:04 +01:00
if self . kind == ' column ' :
2024-01-13 12:55:53 +01:00
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 )
2024-01-13 14:00:04 +01:00
if self . rank == 0 :
2024-01-13 12:55:53 +01:00
return str_rep + ' ] '
def string ( self , limit_entry ) : # Gibt den Vektor als String zurück bis zum Eintrag limit_entry
str_rep = ' '
2024-01-13 14:00:04 +01:00
if limit_entry > self . vec_size :
2024-01-13 12:55:53 +01:00
raise ValueError ( " ERROR_4: Die eingegebene Zahl ist größer, als der größte Index des Vectors. " )
# Rank 0
2024-01-13 14:00:04 +01:00
if self . rank == 0 and limit_entry < = self . end_idx : # Limit_entry befindet sich im Rang 0
if self . kind == ' row ' :
2024-01-13 12:55:53 +01:00
str_rep = ' [ ' + ' , ' . join ( map ( str , self . vec [ : limit_entry ] ) )
2024-01-13 14:00:04 +01:00
if self . kind == ' column ' :
2024-01-13 12:55:53 +01:00
str_rep = ' [ ' + ' \n ' . join ( map ( str , self . vec [ : limit_entry ] ) )
2024-01-13 14:00:04 +01:00
if self . size > 1 :
2024-01-13 12:55:53 +01:00
self . comm . send ( str_rep , dest = self . rank + 1 )
2024-01-13 14:00:04 +01:00
if self . rank == 0 and limit_entry > self . end_idx : # Limit_entry befindet sich nicht im Rang 0
if self . kind == ' row ' :
2024-01-13 12:55:53 +01:00
str_rep = ' [ ' + ' , ' . join ( map ( str , self . vec ) )
2024-01-13 14:00:04 +01:00
if self . kind == ' column ' :
2024-01-13 12:55:53 +01:00
str_rep = ' [ ' + ' \n ' . join ( map ( str , self . vec ) )
2024-01-13 14:00:04 +01:00
if self . size > 1 :
2024-01-13 12:55:53 +01:00
self . comm . send ( str_rep , dest = self . rank + 1 )
# Rank im Intervall [1,size-1]
if (
2024-01-13 14:00:04 +01:00
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
2024-01-13 12:55:53 +01:00
str_rep = self . comm . recv ( source = self . rank - 1 )
self . comm . send ( str_rep , dest = self . rank + 1 )
if (
2024-01-13 14:00:04 +01:00
0 < self . rank < self . size - 1 and self . start_idx < limit_entry < = self . end_idx ) :
if self . kind == ' row ' :
2024-01-13 12:55:53 +01:00
str_rep = self . comm . recv ( source = self . rank - 1 ) + ' , ' + ' , ' . join (
map ( str , self . vec [ : ( limit_entry - self . start_idx ) ] ) )
2024-01-13 14:00:04 +01:00
if self . kind == ' column ' :
2024-01-13 12:55:53 +01:00
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 )
2024-01-13 14:00:04 +01:00
if 0 < self . rank < self . size - 1 and limit_entry > self . end_idx :
if self . kind == ' row ' :
2024-01-13 12:55:53 +01:00
str_rep = self . comm . recv ( source = self . rank - 1 ) + ' , ' + ' , ' . join ( map ( str , self . vec ) )
2024-01-13 14:00:04 +01:00
if self . kind == ' column ' :
2024-01-13 12:55:53 +01:00
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
2024-01-13 14:00:04 +01:00
if self . rank == self . size - 1 and limit_entry < = self . start_idx and self . rank > 1 :
2024-01-13 12:55:53 +01:00
str_rep = self . comm . recv ( source = self . rank - 1 )
2024-01-13 14:00:04 +01:00
if self . rank == self . size - 1 and limit_entry > = self . start_idx and self . rank > 1 :
if self . kind == ' row ' :
2024-01-13 12:55:53 +01:00
str_rep = self . comm . recv ( source = self . rank - 1 ) + ' , ' + ' , ' . join (
map ( str , self . vec [ : ( limit_entry - self . start_idx ) ] ) )
2024-01-13 14:00:04 +01:00
if self . kind == ' column ' :
2024-01-13 12:55:53 +01:00
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 )
2024-01-13 14:00:04 +01:00
if self . rank == 0 :
2024-01-13 12:55:53 +01:00
return str_rep + ' ] '
def norm ( self ) : # Berechnung der 2-Norm / euklidischen Norm
2024-01-13 14:00:04 +01:00
0
2024-01-13 12:55:53 +01:00
sum_of_squares = 0
2024-01-13 14:00:04 +01:00
if self . rank == 0 :
2024-01-13 12:55:53 +01:00
for i in range ( 0 , self . rank_size ) :
sum_of_squares = sum_of_squares + self . vec [ i ] * * 2
2024-01-13 14:00:04 +01:00
if self . size > 1 :
2024-01-13 12:55:53 +01:00
self . comm . send ( sum_of_squares , dest = self . rank + 1 )
2024-01-13 14:00:04 +01:00
elif self . rank == self . size - 1 :
2024-01-13 12:55:53 +01:00
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
else :
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
self . comm . send ( sum_of_squares , dest = self . rank + 1 )
sum_of_squares = self . comm . bcast ( sum_of_squares , root = self . size - 1 )
norm = np . sqrt ( sum_of_squares )
return norm
def normalize ( self ) : # Normalisierung eines Vectors
norm = self . norm ( )
2024-01-13 14:00:04 +01:00
if norm == 0 :
2024-01-13 12:55:53 +01:00
return self
normalized_vec = self / norm
return normalized_vec
# Main-Funktion
x = Vector ( np . arange ( 10 ) )
print ( x . str ( ) , x . shape ( ) )
print ( x . vshape [ 0 ] , x . vshape [ 1 ] )
minus = - 1 * x
_x = - x
print ( _x . str ( ) )
print ( minus . str ( ) )
y = Vector ( 2 * np . arange ( 10 ) )
print ( y . str ( ) )
z = x - y
print ( z . str ( ) )
ae = x + 5
print ( ae . str ( ) )
o = x * y
print ( o . str ( ) )
a = Vector ( np . array ( [ [ 1 ] , [ 2 ] ] ) )
b = Vector ( np . array ( [ 1 , 2 ] ) )
print ( a . shape ( ) )
# c = a * b
# print(c.vec)