1
0

Change type of Matrix data from list to numpy.ndarray;

Restructure tests to use directly == on a Matrix using ==.all() from numpy.ndarray;
Further implementation of the Matrix class
This commit is contained in:
Niklas Birk 2023-12-15 01:47:16 +01:00
parent 4aacfe8473
commit 71fa91644e
3 changed files with 144 additions and 32 deletions

View File

@ -2,10 +2,37 @@ import numpy
class Matrix: class Matrix:
__data__ = [] """
__shape__ = () This Matrix class represents a real 2D-matrix.
"""
__data__: numpy.ndarray
__shape__: (int, int)
def __init__(self, data=None, shape=None, structure=None, model=None, size=None): def __init__(self, data=None, shape=None, structure=None, model=None, n=None):
"""
Creates a new matrix.
Thy type of the matrix depends on the signature and arguments.
- ``Matrix(numpy.ndarray)``: will create a new matrix with the given data in ndarray and its shape.
- ``Matrix(list, (int,int))``: will create a new nxm matrix with the given rows and columns and data in list.
- ``Matrix(list, str, int)``: will create a new square matrix of given size and structure of either \"unity\", \"diagonal\" or \"tridiagonal\"
- ``Matrix(str, int)``: will create a new square matrix of given size and TODO
:param data: Either a list or an numpy ndarray
:param shape: A tuple containing the amount of rows and columns
:param structure: Either \"unity\", \"diagonal\" or \"tridiagonal\"
:param model: TODO
:param n: Amount of rows of a square matrix or offset in case of diagonal structure
:type data: list | numpy.ndarray
:type shape: (int, int)
:type structure: str
:type model: str
:type n: int
:rtype: Matrix
"""
if isinstance(data, numpy.ndarray): if isinstance(data, numpy.ndarray):
try: try:
data.shape[1] data.shape[1]
@ -13,23 +40,61 @@ class Matrix:
self.__shape__ = (data.shape[0], 1) self.__shape__ = (data.shape[0], 1)
else: else:
self.__shape__ = data.shape self.__shape__ = data.shape
self.__data__ = data.tolist() self.__data__ = data
elif isinstance(data, list) and isinstance(shape, tuple): elif isinstance(data, list) and isinstance(shape, tuple):
self.__shape__ = shape self.__shape__ = shape
self.__data__ = numpy.array(data).reshape(shape).tolist() self.__data__ = numpy.array(data).reshape(shape)
elif isinstance(data, list) and isinstance(structure, str) and isinstance(size, int): elif isinstance(data, list) and isinstance(structure, str) and isinstance(n, int):
... if structure == "unity":
elif isinstance(model, str) and isinstance(size, int): ... # TODO: what does it mean?
... elif structure == "diagonal":
diag = numpy.diag(data, n)
self.__data__ = diag
self.__shape__ = diag.shape
elif structure == "tridiagonal":
if len(data) != 3:
raise ValueError("If structure is tridiagonal, then the given data must be of length 3")
tridiag = numpy.diag([data[0]] * (n-1), -1) + numpy.diag([data[1]] * n, 0) + numpy.diag([data[2]] * (n-1), 1)
self.__data__ = tridiag
self.__shape__ = tridiag.shape
elif isinstance(model, str) and isinstance(n, int):
... # TODO: what shall one do here?
else: else:
raise ValueError("Only following signatures are allowed: " raise ValueError("Only following signatures are allowed: (numpy.ndarray), (list, tuple), (list, str, int), (str, int)")
"(numpy.ndarray), (list, tuple), (list, str, int), (str, int)")
def get_data(self): def get_data(self):
"""
:return: the data of the matrix as a ``numpy.ndarray``
"""
return self.__data__ return self.__data__
def shape(self): def shape(self):
"""
:return: the shape of the matrix, which is ``(rows, columns)``
"""
return self.__shape__ return self.__shape__
def transpose(self):
"""
:return: the transpose of the matrix
"""
return Matrix(self.__data__.transpose())
def __eq__(self, other): def __eq__(self, other):
return self.__data__ == other.__data__ """
Return ``self==value``
:param other: The object to compare to; must be either a ``Matrix``, a ``list`` or a ``numpy.ndarray``
:return: True if data in the matrix is totally equal to the given data in other, otherwise False
"""
if isinstance(other, Matrix):
return (self.__data__ == other.__data__).all()
elif isinstance(other, list):
return (self.__data__ == numpy.array(other)).all()
elif isinstance(other, numpy.ndarray):
return (self.__data__ == other).all()
else:
raise ValueError("Matrix type is not comparable to type of given ``other``")
def __str__(self):
return str(self.__data__)

View File

@ -1,3 +1,5 @@
import numpy
from matrix import Matrix from matrix import Matrix
@ -5,6 +7,11 @@ class Vector(Matrix):
__data__ = [] __data__ = []
def __init__(self, data): def __init__(self, data):
"""
:type data: list | int
"""
super().__init__(numpy.array([0])) # TODO: remove in future
if isinstance(data, list): if isinstance(data, list):
self.__data__ = data self.__data__ = data
elif isinstance(data, int): elif isinstance(data, int):

View File

@ -8,48 +8,88 @@ from matrix import Matrix
class TestMatrix(TestCase): class TestMatrix(TestCase):
def test_should_create_matrix_from_numpy_array_with_shape_3_2(self): def test_should_create_matrix_from_numpy_array_with_shape_3_2(self):
data = numpy.array([[0, 1], [2, 3], [4, 5]]) data = numpy.array([[0, 1], [2, 3], [4, 5]])
m = Matrix(data) actual = Matrix(data)
actual_shape = m.shape() actual_shape = actual.shape()
expected_shape = (3, 2) expected_shape = (3, 2)
self.assertEqual(expected_shape, actual_shape) self.assertEqual(expected_shape, actual_shape)
actual_data = m.get_data() expected = [[0, 1], [2, 3], [4, 5]]
expected_data = [[0, 1], [2, 3], [4, 5]] self.assertEqual(expected, actual)
self.assertEqual(expected_data, actual_data)
def test_should_create_matrix_from_numpy_array_with_shape_1_3(self): def test_should_create_matrix_from_numpy_array_with_shape_1_3(self):
data = numpy.array([[0, 1, 2]]) data = numpy.array([[0, 1, 2]])
m = Matrix(data) actual = Matrix(data)
actual_shape = m.shape() actual_shape = actual.shape()
expected_shape = (1, 3) expected_shape = (1, 3)
self.assertEqual(expected_shape, actual_shape) self.assertEqual(expected_shape, actual_shape)
actual_data = m.get_data() expected = [[0, 1, 2]]
expected_data = [[0, 1, 2]] self.assertEqual(expected, actual)
self.assertEqual(expected_data, actual_data)
def test_should_create_vectorlike_matrix_from_numpy_array_with_shape_3_1(self): def test_should_create_vectorlike_matrix_from_numpy_array_with_shape_3_1(self):
data = numpy.array([0, 1, 2]) data = numpy.array([0, 1, 2])
m = Matrix(data) actual = Matrix(data)
actual_shape = m.shape() actual_shape = actual.shape()
expected_shape = (3, 1) expected_shape = (3, 1)
self.assertEqual(expected_shape, actual_shape) self.assertEqual(expected_shape, actual_shape)
actual_data = m.get_data() expected = [0, 1, 2]
expected_data = [0, 1, 2] self.assertEqual(expected, actual)
self.assertEqual(expected_data, actual_data)
def test_should_create_matrix_from_list_with_shape_2_2(self): def test_should_create_matrix_from_list_with_shape_2_2(self):
data = [0, 1, 2, 3] data = [0, 1, 2, 3]
m = Matrix(data, shape=(2, 2)) actual = Matrix(data, shape=(2, 2))
actual_shape = m.shape() actual_shape = actual.shape()
expected_shape = (2, 2) expected_shape = (2, 2)
self.assertEqual(expected_shape, actual_shape) self.assertEqual(expected_shape, actual_shape)
actual_data = m.get_data() expected = [[0, 1], [2, 3]]
expected_data = [[0, 1], [2, 3]] self.assertEqual(expected, actual)
self.assertEqual(expected_data, actual_data)
def test_should_create_diagonal_matrix_from_list(self):
data = [1, 1, 1]
actual = Matrix(data, structure="diagonal", n=0)
actual_shape = actual.shape()
expected_shape = (3, 3)
self.assertEqual(expected_shape, actual_shape)
expected = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
self.assertEqual(expected, actual)
def test_should_create_diagonal_matrix_from_list_with_offset_1(self):
data = [1, 1, 1]
actual = Matrix(data, structure="diagonal", n=1)
actual_shape = actual.shape()
expected_shape = (4, 4)
self.assertEqual(expected_shape, actual_shape)
expected = [[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1], [0, 0, 0, 0]]
self.assertEqual(expected, actual)
def test_should_raise_value_error_while_creating_tridiagonal_matrix(self):
self.assertRaises(ValueError, lambda: Matrix([-1, 1, -1, 0], structure="tridiagonal", n=1))
def test_should_create_tridiagonal_matrix_from_list_with_size_4(self):
data = [-1, 1, -1]
actual = Matrix(data, structure="tridiagonal", n=4)
actual_shape = actual.shape()
expected_shape = (4, 4)
self.assertEqual(expected_shape, actual_shape)
expected = [[1, -1, 0, 0], [-1, 1, -1, 0], [0, -1, 1, -1], [0, 0, -1, 1]]
self.assertEqual(expected, actual)
def test_should_transpose_matrix(self):
data = [1, 2, 3, 4, 5, 6, 7, 8, 9]
actual = Matrix(data, (3, 3))
actual = actual.transpose()
expected = [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
self.assertEqual(expected, actual)