1
0

Rewrite matrix.py to match test_serial.py and to be less dependent on numpy

This commit is contained in:
Niklas Birk 2024-02-14 23:51:35 +01:00
parent e914001d8d
commit 91f4191a65
3 changed files with 184 additions and 93 deletions

View File

@ -1,3 +1,5 @@
import math
import numpy import numpy
from numpy import linalg from numpy import linalg
@ -6,16 +8,18 @@ class Matrix:
""" """
This Matrix class represents a real 2D-matrix. This Matrix class represents a real 2D-matrix.
""" """
__data__: numpy.ndarray __data__: list
__shape__: (int, int) __shape__: (int, int)
def __init__(self, data=None, shape=None, structure=None, model=None, n=None): def __init__(self, data=None, shape=None, structure=None, model=None, offset=None, n=None):
""" """
Creates a new matrix. Creates a new matrix.
Thy type of the matrix depends on the signature and arguments. The type of the matrix depends on the signature and arguments.
- ``Matrix(list)``: will create a new matrix with the given data in the list and its shape.
- ``Matrix(numpy.ndarray)``: will create a new matrix with the given data in ndarray and its shape. - ``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, (int,int))``: will create a new nxm matrix with the given rows and columns and data in list.
- ``Matrix(list, str, int, int)``: will create a new square matrix of given size and structure of \"diagonal\"
- ``Matrix(list, str, int)``: will create a new square matrix of given size and structure of either \"unity\", \"diagonal\" or \"tridiagonal\" - ``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 - ``Matrix(str, int)``: will create a new square matrix of given size and TODO
@ -24,12 +28,14 @@ class Matrix:
:param shape: A tuple containing the amount of rows and columns :param shape: A tuple containing the amount of rows and columns
:param structure: Either \"unity\", \"diagonal\" or \"tridiagonal\" :param structure: Either \"unity\", \"diagonal\" or \"tridiagonal\"
:param model: TODO :param model: TODO
:param offset: Offset to diagonal axis
:param n: Amount of rows of a square matrix or offset in case of diagonal structure :param n: Amount of rows of a square matrix or offset in case of diagonal structure
:type data: list | numpy.ndarray :type data: list | numpy.ndarray
:type shape: (int, int) :type shape: (int, int)
:type structure: str :type structure: str
:type model: str :type model: str
:type offset: int
:type n: int :type n: int
:rtype: Matrix :rtype: Matrix
@ -37,41 +43,46 @@ class Matrix:
# Case Matrix(str, int) # Case Matrix(str, int)
if n is not None and model is not None: if n is not None and model is not None:
... # TODO: what shall one do here? ... # TODO: what shall one do here?
# Case: Matrix(list, str, int, int)
elif n is not None and offset is not None and structure == "diagonal" and data is not None:
diag = numpy.diag(data * (n - abs(offset)), offset)
self.__data__ = diag.tolist()
self.__shape__ = diag.shape
# Case: Matrix(list, str, int) # Case: Matrix(list, str, int)
elif n is not None and structure is not None and data is not None: elif n is not None and structure is not None and data is not None:
if structure == "unity": if structure == "unity":
... # TODO: what does it mean? ... # TODO: what does it mean?
elif structure == "diagonal":
diag = numpy.diag(data, n)
self.__data__ = diag
self.__shape__ = diag.shape
elif structure == "tridiagonal": elif structure == "tridiagonal":
if len(data) != 3: if len(data) != 3:
raise ValueError("If structure is tridiagonal, then the given data must be of length 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( tridiag = numpy.diag([data[0]] * (n - 1), -1) + numpy.diag([data[1]] * n, 0) + numpy.diag(
[data[2]] * (n - 1), 1) [data[2]] * (n - 1), 1)
self.__data__ = tridiag self.__data__ = tridiag.tolist()
self.__shape__ = tridiag.shape self.__shape__ = tridiag.shape
# Case: Matrix(list, str, int) # Case: Matrix(list, (int,int))
elif shape is not None and data is not None: elif shape is not None and data is not None:
self.__shape__ = shape self.__shape__ = shape
self.__data__ = numpy.array(data).reshape(shape) self.__data__ = numpy.array(data).reshape(shape).tolist()
# Case: Matrix(numpy.ndarray) # Case: Matrix(numpy.ndarray) or Matrix(list)
elif data is not None: elif data is not None:
if isinstance(data, numpy.ndarray):
try: try:
data.shape[1] data.shape[1]
except IndexError: except IndexError:
self.__shape__ = (data.shape[0], 1) self.__shape__ = (data.shape[0], 1)
else: else:
self.__shape__ = data.shape self.__shape__ = (data.shape[0], data.shape[1])
elif isinstance(data, list):
self.__shape__ = (len(data), len(data[0]))
self.__data__ = data self.__data__ = data
else: else:
raise ValueError( raise ValueError(
"Only following signatures are allowed: (numpy.ndarray), (list, tuple), (list, str, int), (str, int)") "Only following signatures are allowed: "
"(list), (numpy.ndarray), (list, tuple), (list, str, int), (list, str, int, int), (str, int)")
def get_data(self): def get_data(self):
""" """
:return: the data of the matrix as a ``numpy.ndarray`` :return: the data of the matrix as a ``list``
""" """
return self.__data__ return self.__data__
@ -85,7 +96,16 @@ class Matrix:
""" """
:return: the transpose of the matrix :return: the transpose of the matrix
""" """
return Matrix(self.__data__.transpose()) rows = self.__shape__[0]
cols = self.__shape__[1]
transposed_data = [[0 for _ in range(rows)] for _ in range(cols)]
for i in range(rows):
for j in range(cols):
transposed_data[j][i] = self.__data__[i][j]
return Matrix(transposed_data, (cols, rows))
def T(self): def T(self):
""" """
@ -103,28 +123,49 @@ class Matrix:
:return: True if data in the matrix are equal to the given data in other for each component, otherwise False :return: True if data in the matrix are equal to the given data in other for each component, otherwise False
""" """
if isinstance(other, Matrix): if isinstance(other, Matrix):
to_compare = other.__data__ data_to_compare = other.__data__
if self.__shape__ != other.__shape__:
return False
elif isinstance(other, list): elif isinstance(other, list):
to_compare = numpy.array(other) data_to_compare = other
if self.__shape__[0] != len(other) or self.__shape__[1] != len(other[0]):
return False
elif isinstance(other, numpy.ndarray): elif isinstance(other, numpy.ndarray):
to_compare = other data_to_compare = other.tolist()
else: else:
raise ValueError("Matrix type is not comparable to type of given ``other``") raise ValueError("Matrix type is not comparable to type of given ``other``")
return (self.__data__ == to_compare).all()
for i in range(len(self.__data__)):
for j in range(len(self.__data__[i])):
if self.__data__[i][j] != data_to_compare[i][j]:
return False
return True
def __str__(self): def __str__(self):
return str(self.__data__) return str(numpy.array(self.__data__))
def __neg__(self): def __neg__(self):
return Matrix(-self.__data__) rows = range(self.__shape__[0])
cols = range(self.__shape__[1])
return Matrix([[-(self.__data__[i][j]) for j in cols] for i in rows], self.__shape__)
def __add_matrix_internal__(self, other):
rows = self.__shape__[0]
cols = self.__shape__[1]
return [[(self.__data__[i][j] + other.__data__[i][j]) for j in range(cols)] for i in range(rows)]
def __add_scalar_internal__(self, other):
rows = self.__shape__[0]
cols = self.__shape__[1]
return [[(self.__data__[i][j] + other) for j in range(cols)] for i in range(rows)]
def __add__(self, other): def __add__(self, other):
if isinstance(other, Matrix): if isinstance(other, Matrix):
if self.__shape__ != other.__shape__: if self.__shape__ != other.__shape__:
raise ValueError("The shape of the operands must be the same") raise ValueError("The shape of the operands must be the same")
return Matrix(self.__data__ + other.__data__) return Matrix(self.__add_matrix_internal__(other), self.__shape__)
elif isinstance(other, int) or isinstance(other, float): elif isinstance(other, int) or isinstance(other, float):
return Matrix(self.__data__ + other) return Matrix(self.__add_scalar_internal__(other), self.__shape__)
else: else:
raise ValueError("Only a number or another ``Matrix`` can be added to a ``Matrix``") raise ValueError("Only a number or another ``Matrix`` can be added to a ``Matrix``")
@ -137,26 +178,47 @@ class Matrix:
def __rsub__(self, other): def __rsub__(self, other):
return -self + other return -self + other
def __truediv_scalar_internal__(self, other):
rows = self.__shape__[0]
cols = self.__shape__[1]
return [[(self.__data__[i][j] / other) for j in range(cols)] for i in range(rows)]
def __truediv__(self, other):
if isinstance(other, int) or isinstance(other, float):
return Matrix(self.__truediv_scalar_internal__(other), self.__shape__)
else:
raise ValueError("A ``Matrix`` can only be divided ba a number")
def __mul_matrix_internal__(self, other):
rows = self.__shape__[0]
cols = other.__shape__[1]
new_data = [[0 for _ in range(rows)] for _ in range(cols)]
for i in range(rows):
for k in range(cols):
new_data[i][k] = sum([self.__data__[i][j] * other.__data__[j][k] for j in range(self.__shape__[1])])
return new_data
def __mul_scalar_internal__(self, other):
cols = range(self.__shape__[1])
rows = range(self.__shape__[0])
return [[(self.__data__[i][j] * other) for j in cols] for i in rows]
def __mul__(self, other): def __mul__(self, other):
if isinstance(other, Matrix): if isinstance(other, Matrix):
if self.__shape__[1] != other.__shape__[0]: if self.__shape__[1] != other.__shape__[0]:
raise ValueError( raise ValueError(
"The amount of columns of the first operand must match the amount of rows of the second operand") "The amount of columns of the first operand must match the amount of rows of the second operand")
return Matrix(self.__data__ @ other.__data__) return Matrix(self.__mul_matrix_internal__(other), (self.__shape__[0], other.__shape__[1]))
elif isinstance(other, int) or isinstance(other, float): elif isinstance(other, int) or isinstance(other, float):
return Matrix(other * self.__data__) return Matrix(self.__mul_scalar_internal__(other), self.__shape__)
else: else:
raise ValueError("Only a number or another ``Matrix`` can be multiplied to a ``Matrix``") raise ValueError("Only a number or another ``Matrix`` can be multiplied to a ``Matrix``")
def __rmul__(self, other): def __rmul__(self, other):
return self * other return self * other
def __truediv__(self, other):
if isinstance(other, int) or isinstance(other, float):
return Matrix(self.__data__ / other)
else:
raise ValueError("A ``Matrix`` can only be divided ba a number")
def norm(self, f: str = "frobenius"): def norm(self, f: str = "frobenius"):
""" """
Calculates the norm of the matrix. Calculates the norm of the matrix.
@ -168,15 +230,35 @@ class Matrix:
:return: the norm as a number :return: the norm as a number
""" """
t = "fro" norm = 0
if f == "colsum":
t = 1 rows = self.__shape__[0]
elif f == "rowsum": cols = self.__shape__[1]
t = numpy.inf
return linalg.norm(self.__data__, t) if f == "frobenius":
abs_sum = 0
for i in range(rows):
for j in range(cols):
abs_sum += abs(self.__data__[i][j])**2
norm = math.sqrt(abs_sum)
elif f == "col sum":
row_sum = [0 for _ in range(cols)]
for j in range(cols):
for i in range(rows):
row_sum[j] += abs(self.__data__[i][j])
norm = max(row_sum)
elif f == "row sum":
col_sum = [0 for _ in range(rows)]
for i in range(rows):
for j in range(cols):
col_sum[i] += abs(self.__data__[i][j])
norm = max(col_sum)
return norm
def __getitem__(self, key): def __getitem__(self, key):
return self.__data__[key] return numpy.array(self.__data__)[key].tolist()
def __setitem__(self, key, value): def __setitem__(self, key, value):
self.__data__[key] = value manipulated_data = numpy.array(self.__data__)
manipulated_data[key] = value
self.__data__ = manipulated_data.tolist()

View File

@ -28,17 +28,6 @@ class TestMatrix(TestCase):
expected = [[0, 1, 2]] expected = [[0, 1, 2]]
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
def test_should_create_vectorlike_matrix_from_numpy_array_with_shape_3_1(self):
data = numpy.array([0, 1, 2])
actual = Matrix(data)
actual_shape = actual.shape()
expected_shape = (3, 1)
self.assertEqual(expected_shape, actual_shape)
expected = [0, 1, 2]
self.assertEqual(expected, actual)
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]
actual = Matrix(data, shape=(2, 2)) actual = Matrix(data, shape=(2, 2))
@ -50,9 +39,20 @@ class TestMatrix(TestCase):
expected = [[0, 1], [2, 3]] expected = [[0, 1], [2, 3]]
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
def test_should_create_matrix_from_matrixlike_list_with_shape_2_3(self):
data = [[0, 1, 2], [3, 4, 5]]
actual = Matrix(data, shape=(2, 3))
actual_shape = actual.shape()
expected_shape = (2, 3)
self.assertEqual(expected_shape, actual_shape)
expected = [[0, 1, 2], [3, 4, 5]]
self.assertEqual(expected, actual)
def test_should_create_diagonal_matrix_from_list(self): def test_should_create_diagonal_matrix_from_list(self):
data = [1, 1, 1] data = [1]
actual = Matrix(data, structure="diagonal", n=0) actual = Matrix(data, structure="diagonal", offset=0, n=3)
actual_shape = actual.shape() actual_shape = actual.shape()
expected_shape = (3, 3) expected_shape = (3, 3)
@ -62,8 +62,8 @@ class TestMatrix(TestCase):
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
def test_should_create_diagonal_matrix_from_list_with_offset_1(self): def test_should_create_diagonal_matrix_from_list_with_offset_1(self):
data = [1, 1, 1] data = [1]
actual = Matrix(data, structure="diagonal", n=1) actual = Matrix(data, structure="diagonal", offset=1, n=4)
actual_shape = actual.shape() actual_shape = actual.shape()
expected_shape = (4, 4) expected_shape = (4, 4)
@ -188,6 +188,15 @@ class TestMatrix(TestCase):
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
def test_should_div_matrix_by_scalar(self):
m = Matrix([5, 10, 15, 20], (2, 2))
s = 5
actual = m / s
expected = Matrix([1, 2, 3, 4], (2, 2))
self.assertEqual(expected, actual)
def test_should_raise_value_missmatch_error_while_dividing_with_other_than_scalar(self): def test_should_raise_value_missmatch_error_while_dividing_with_other_than_scalar(self):
m = Matrix([1, 2, 3, 4], (2, 2)) m = Matrix([1, 2, 3, 4], (2, 2))
o = "" o = ""
@ -195,20 +204,29 @@ class TestMatrix(TestCase):
self.assertRaises(ValueError, lambda: m / o) self.assertRaises(ValueError, lambda: m / o)
def test_should_mul_matrices_1(self): def test_should_mul_matrices_1(self):
m1 = Matrix([1, 2], (2, 1)) m1 = Matrix([1, 2, 3, 4], (2, 2))
m2 = Matrix([3, 4], (1, 2)) m2 = Matrix([4, 3, 2, 1], (2, 2))
actual = m1 * m2 actual = m1 * m2
expected = Matrix([3, 4, 6, 8], (2, 2)) expected = Matrix([8, 5, 20, 13], (2, 2))
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
def test_should_mul_matrices_2(self): def test_should_mul_matrices_2(self):
m1 = Matrix([1, 2], (1, 2)) m1 = Matrix([1, 2, 3, 4, 5, 6], (2, 3))
m2 = Matrix([3, 4], (2, 1)) m2 = Matrix([6, 5, 4, 3, 2, 1], (3, 2))
actual = m1 * m2 actual = m1 * m2
expected = Matrix([11], (1, 1)) expected = Matrix([20, 14, 56, 41], (2, 2))
self.assertEqual(expected, actual)
def test_should_mul_matrices_3(self):
m1 = Matrix([1, 2, 3, 4, 5, 6], (3, 2))
m2 = Matrix([6, 5, 4, 3, 2, 1], (2, 3))
actual = m1 * m2
expected = Matrix([12, 9, 6, 30, 23, 16, 48, 37, 26], (3, 3))
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
@ -236,15 +254,6 @@ class TestMatrix(TestCase):
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
def test_should_div_matrix_by_scalar(self):
m = Matrix([5, 10, 15, 20], (2, 2))
s = 5
actual = m / s
expected = Matrix([1, 2, 3, 4], (2, 2))
self.assertEqual(expected, actual)
def test_should_return_frobenius_norm(self): def test_should_return_frobenius_norm(self):
m = Matrix([1, 2, 3, 4], (2, 2)) m = Matrix([1, 2, 3, 4], (2, 2))
@ -256,7 +265,7 @@ class TestMatrix(TestCase):
def test_should_return_colsum_norm(self): def test_should_return_colsum_norm(self):
m = Matrix([1, 2, 3, 4], (2, 2)) m = Matrix([1, 2, 3, 4], (2, 2))
actual = m.norm("colsum") actual = m.norm("col sum")
expected = 6 expected = 6
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
@ -264,7 +273,7 @@ class TestMatrix(TestCase):
def test_should_return_rowsum_norm(self): def test_should_return_rowsum_norm(self):
m = Matrix([1, 2, 3, 4], (2, 2)) m = Matrix([1, 2, 3, 4], (2, 2))
actual = m.norm("rowsum") actual = m.norm("row sum")
expected = 7 expected = 7
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
@ -289,7 +298,7 @@ class TestMatrix(TestCase):
m = Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9], (3, 3)) m = Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9], (3, 3))
actual = m[0] actual = m[0]
expected = Matrix([1, 2, 3], (1, 3)) expected = [1, 2, 3]
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
@ -297,7 +306,7 @@ class TestMatrix(TestCase):
m = Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9], (3, 3)) m = Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9], (3, 3))
actual = m[2, 0:2] actual = m[2, 0:2]
expected = Matrix([7, 8], (1, 2)) expected = [7, 8]
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
@ -305,7 +314,7 @@ class TestMatrix(TestCase):
m = Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9], (3, 3)) m = Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9], (3, 3))
actual = m[:, 1] actual = m[:, 1]
expected = Matrix([2, 5, 8], (1, 3)) expected = [2, 5, 8]
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
@ -313,7 +322,7 @@ class TestMatrix(TestCase):
m = Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9], (3, 3)) m = Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9], (3, 3))
actual = m[[0, 2], 0] actual = m[[0, 2], 0]
expected = Matrix([1, 7], (1, 2)) expected = [1, 7]
self.assertEqual(expected, actual) self.assertEqual(expected, actual)

View File

@ -125,9 +125,9 @@ print("\n\nTesting the matrix class -----------------------------------\n\n")
print("Start 2a initialization") print("Start 2a initialization")
a_list = np.array([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 2 * np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])]) a_list = np.array([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 2 * np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])])
A = Matrix(a_list) A = Matrix(a_list)
B = Matrix(structure="tridiagonal", given_size=11) B = Matrix([-1, 2, -1], structure="tridiagonal", n=11)
c_list = [[(i + 1) / (index + 1) for index in range(10)] for i in range(10)] c_list = [[(i + 1) / (index + 1) for index in range(10)] for i in range(10)]
C = Matrix(c_list, given_shape=(10, 10)) C = Matrix(c_list, shape=(10, 10))
print("End 2a\n") print("End 2a\n")
### 1b __str__ function, string representation ### 1b __str__ function, string representation
@ -141,7 +141,7 @@ print("End 2b\n")
### 1c shape and transpose ### 1c shape and transpose
print("Start 2c shape and transpose") print("Start 2c shape and transpose")
# Initialization # Initialization
A = Matrix(np.array([i for i in range(12)]).reshape(-1, 1), given_shape=(4, 3)) A = Matrix(np.array([i for i in range(12)]).reshape(-1, 1), shape=(4, 3))
print(f"A has shape {A.shape()} | must be (4,3)") print(f"A has shape {A.shape()} | must be (4,3)")
print(f"A.T() has shape {A.T().shape()} | must be (3,4)") print(f"A.T() has shape {A.T().shape()} | must be (3,4)")
print(f"A.T().T() has shape {A.T().T().shape()} | must be (4,3)") print(f"A.T().T() has shape {A.T().T().shape()} | must be (4,3)")
@ -150,17 +150,17 @@ print("End 2c\n")
### 1d addition and substraction ### 1d addition and substraction
print("Start 2d addition and substraction") print("Start 2d addition and substraction")
# Initialization # Initialization
A = Matrix(structure="diagonal", given_values=[3], offset=0, given_size=10) A = Matrix(structure="diagonal", data=[3], offset=0, n=10)
print(str(A)) print(str(A))
A21 = Matrix(structure="diagonal", given_values=[-1], offset=-1, given_size=10) A21 = Matrix(structure="diagonal", data=[-1], offset=-1, n=10)
print(str(A21)) print(str(A21))
A12 = Matrix(structure="diagonal", given_values=[-1], offset=+1, given_size=10) A12 = Matrix(structure="diagonal", data=[-1], offset=+1, n=10)
print(str(A12)) print(str(A12))
B = Matrix(structure="diagonal", given_values=[1], offset=0, given_size=10) B = Matrix(structure="diagonal", data=[1], offset=0, n=10)
print(str(B)) print(str(B))
# computation # computation
C = A + A21 + A12 - B C = A + A21 + A12 - B
print(str(C) + f"must be\n{Matrix(structure='tridiagonal', given_values=[-1, 2, -1], given_size=10)}") print(str(C) + f"must be\n{Matrix(structure='tridiagonal', data=[-1, 2, -1], n=10)}")
print(str(5 + A - 3)) print(str(5 + A - 3))
print("End 2d\n") print("End 2d\n")
@ -195,21 +195,21 @@ print("End 2f\n")
### 1g norm ### 1g norm
print("Start 2g norm") print("Start 2g norm")
A = Matrix(structure="tridiagonal", given_size=50, given_values=[-1, 2, -1]) A = Matrix(structure="tridiagonal", n=50, data=[-1, 2, -1])
print(f"Frobenius norm of tridiagonal matrix: {A.norm('frobenius')} | must be 17.263") print(f"Frobenius norm of tridiagonal matrix: {A.norm('frobenius')} | must be 17.263")
print(f"Row sum norm of tridiagonal matrix: {A.norm('row sum')} | must be 2") print(f"Row sum norm of tridiagonal matrix: {A.norm('row sum')} | must be 4")
print(f"Col sum norm of tridiagonal matrix: {A.norm('col sum')} | must be 2") print(f"Col sum norm of tridiagonal matrix: {A.norm('col sum')} | must be 4")
print("End 2g\n") print("End 2g\n")
### 1h negation ### 1h negation
print("Start 2h negation") print("Start 2h negation")
A = Matrix(structure="tridiagonal", given_size=50, given_values=[-1, 2, 1]) A = Matrix(structure="tridiagonal", n=50, data=[-1, 2, 1])
print(f"Norm of (A + (-A)) is {(A + (-A)).norm('frobenius')} | must be < 1e-8") print(f"Norm of (A + (-A)) is {(A + (-A)).norm('frobenius')} | must be < 1e-8")
print("End 2h\n") print("End 2h\n")
### 1i manipulation ### 1i manipulation
print("Start 2i manipulation") print("Start 2i manipulation")
A = Matrix(structure="tridiagonal", given_size=10, given_values=[-1, 2, 1]) A = Matrix(structure="tridiagonal", n=10, data=[-1, 2, 1])
A[1, 1] = 4 A[1, 1] = 4
A[[1, 2, 3], 2] = [-5, -10, 100] A[[1, 2, 3], 2] = [-5, -10, 100]
print(str(A)) print(str(A))