diff --git a/README.md b/README.md index 60c58c9..2fabb65 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -# pwr_project +# Project for PWR Project in python for module "Praktikum Wissenschaftliche Rechnen" in "Applied Mathematics" at *TU Bergakademie Freiberg*. -# \ No newline at end of file +# 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/matrix.py b/src/matrix.py index 73f67c2..2a17ba4 100644 --- a/src/matrix.py +++ b/src/matrix.py @@ -1,2 +1,35 @@ +import numpy + + class Matrix: - + __data__ = [] + __shape__ = () + + def __init__(self, data=None, shape=None, structure=None, model=None, size=None): + if isinstance(data, numpy.ndarray): + try: + data.shape[1] + except IndexError: + self.__shape__ = (data.shape[0], 1) + else: + self.__shape__ = data.shape + self.__data__ = data.tolist() + elif isinstance(data, list) and isinstance(shape, tuple): + self.__shape__ = shape + self.__data__ = numpy.array(data).reshape(shape).tolist() + elif isinstance(data, list) and isinstance(structure, str) and isinstance(size, int): + ... + elif isinstance(model, str) and isinstance(size, int): + ... + else: + raise ValueError("Only following signatures are allowed: " + "(numpy.ndarray), (list, tuple), (list, str, int), (str, int)") + + def get_data(self): + return self.__data__ + + def shape(self): + return self.__shape__ + + def __eq__(self, other): + return self.__data__ == other.__data__ diff --git a/src/vector.py b/src/vector.py index 39fc575..f8b5b07 100644 --- a/src/vector.py +++ b/src/vector.py @@ -1,4 +1,7 @@ -class Vector: +from matrix import Matrix + + +class Vector(Matrix): __data__ = [] def __init__(self, data): @@ -24,21 +27,33 @@ class Vector: def __str__(self): return f"{self.__data__}" + def __neg__(self): + return Vector([-x for x in self.__data__]) + def __add__(self, other): - if self.get_dimension() != other.get_dimension(): - raise ValueError("The vectors to be added must have the same dimension") + if isinstance(other, Vector): + if self.get_dimension() != other.get_dimension(): + raise ValueError("The vectors to be added must have the same dimension") + return Vector([(x + y) for (x, y) in zip(self, other)]) + elif isinstance(other, int) or isinstance(other, float): + return Vector([(x + other) for x in self.__data__]) + else: + raise ValueError("A vector can only be multiplied with an vector (dot product) or a scalar") - data = [] - for (i, j) in zip(self, other): - data.append(i + j) + def __radd__(self, other): + return self + other - return Vector(data) + def __sub__(self, other): + return self + (-other) + + def __rsub__(self, other): + return -self + other def __mul__(self, other): if isinstance(other, Vector): - ... + return sum([(x * y) for (x, y) in zip(self, other)]) elif isinstance(other, int) or isinstance(other, float): - ... + return Vector([(other * x) for x in self.__data__]) else: raise ValueError("A vector can only be multiplied with an vector (dot product) or a scalar") diff --git a/test/test_matrix.py b/test/test_matrix.py new file mode 100644 index 0000000..48f1912 --- /dev/null +++ b/test/test_matrix.py @@ -0,0 +1,55 @@ +from unittest import TestCase + +import numpy + +from matrix import Matrix + + +class TestMatrix(TestCase): + def test_should_create_matrix_from_numpy_array_with_shape_3_2(self): + data = numpy.array([[0, 1], [2, 3], [4, 5]]) + m = Matrix(data) + + actual_shape = m.shape() + expected_shape = (3, 2) + self.assertEqual(expected_shape, actual_shape) + + actual_data = m.get_data() + expected_data = [[0, 1], [2, 3], [4, 5]] + self.assertEqual(expected_data, actual_data) + + def test_should_create_matrix_from_numpy_array_with_shape_1_3(self): + data = numpy.array([[0, 1, 2]]) + m = Matrix(data) + + actual_shape = m.shape() + expected_shape = (1, 3) + self.assertEqual(expected_shape, actual_shape) + + actual_data = m.get_data() + expected_data = [[0, 1, 2]] + self.assertEqual(expected_data, actual_data) + + def test_should_create_vectorlike_matrix_from_numpy_array_with_shape_3_1(self): + data = numpy.array([0, 1, 2]) + m = Matrix(data) + + actual_shape = m.shape() + expected_shape = (3, 1) + self.assertEqual(expected_shape, actual_shape) + + actual_data = m.get_data() + expected_data = [0, 1, 2] + self.assertEqual(expected_data, actual_data) + + def test_should_create_matrix_from_list_with_shape_2_2(self): + data = [0, 1, 2, 3] + m = Matrix(data, shape=(2, 2)) + + actual_shape = m.shape() + expected_shape = (2, 2) + self.assertEqual(expected_shape, actual_shape) + + actual_data = m.get_data() + expected_data = [[0, 1], [2, 3]] + self.assertEqual(expected_data, actual_data) diff --git a/test/test_vector.py b/test/test_vector.py index 80a051c..474cdf4 100644 --- a/test/test_vector.py +++ b/test/test_vector.py @@ -5,21 +5,17 @@ from vector import Vector class TestVector(TestCase): def test_should_create_vector_dim_5(self): - dim = 5 - vector = Vector(dim) + vector = Vector(5) actual = vector.get_dimension() - expected = dim - + expected = 5 self.assertEqual(expected, actual) def test_should_create_zero_vector(self): - dim = 5 - vector = Vector(dim) + vector = Vector(5) actual = vector.get_data() expected = [0, 0, 0, 0, 0] - self.assertEqual(expected, actual) def test_should_create_vector(self): @@ -28,7 +24,13 @@ class TestVector(TestCase): actual = vector.get_data() expected = [0, 1, 2, 3, 4] + self.assertEqual(expected, actual) + def test_should_neg_vector(self): + v = Vector([1, 2]) + + expected = Vector([-1, -2]) + actual = -v self.assertEqual(expected, actual) def test_should_add_vectors(self): @@ -37,11 +39,83 @@ class TestVector(TestCase): expected = Vector([4, 6]) actual = v1 + v2 - self.assertEqual(expected, actual) - def test_should_raise_error_while_adding_vectors(self): + def test_should_add_scalar_to_vector(self): + v = Vector([1, 2]) + s = 2 + + expected = Vector([3, 4]) + actual = v + s + self.assertEqual(expected, actual) + + def test_should_radd_scalar_to_vector(self): + v = Vector([1, 2]) + s = 2 + + expected = Vector([3, 4]) + actual = s + v + self.assertEqual(expected, actual) + + def test_should_raise_value_missmatch_error_while_adding_vectors(self): v1 = Vector(1) v2 = Vector(2) - self.assertRaises(ValueError, lambda: v1 + v2) + + def test_should_raise_dimension_error_while_adding_vectors(self): + v1 = Vector(1) + v2 = '0' + self.assertRaises(ValueError, lambda: v1 + v2) + + def test_should_subtract_vectors(self): + v1 = Vector([1, 2]) + v2 = Vector([3, 4]) + + expected = Vector([-2, -2]) + actual = v1 - v2 + self.assertEqual(expected, actual) + + def test_should_subtract_scalar_of_vector(self): + v = Vector([1, 2]) + s = 2 + + expected = Vector([-1, 0]) + actual = v - s + self.assertEqual(expected, actual) + + def test_should_rsubtract_scalar_of_vector(self): + v = Vector([1, 2]) + s = 2 + + expected = Vector([1, 0]) + actual = s - v + self.assertEqual(expected, actual) + + def test_should_multiply_vectors(self): + v1 = Vector([1, 2]) + v2 = Vector([3, 4]) + + expected = 11 + actual = v1 * v2 + self.assertEqual(expected, actual) + + def test_should_multiply_scalar_with_vector(self): + v = Vector([1, 2]) + s = 2 + + expected = Vector([2, 4]) + actual = v * s + self.assertEqual(expected, actual) + + def test_should_rmultiply_scalar_with_vector(self): + v = Vector([1, 2]) + s = 2 + + expected = Vector([2, 4]) + actual = s * v + self.assertEqual(expected, actual) + + def test_should_raise_value_missmatch_error_while_multiplying_vectors(self): + v1 = Vector([1, 2]) + v2 = '0' + self.assertRaises(ValueError, lambda: v1 * v2)