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:
parent
4aacfe8473
commit
71fa91644e
@ -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__)
|
||||||
|
@ -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):
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user