Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 33 additions & 25 deletions matrix/matrix_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@

def add(*matrix_s: list[list[int]]) -> list[list[int]]:
"""
>>> add([[1,2],[3,4]],[[2,3],[4,5]])
>>> add([[1, 2], [3, 4]], [[2, 3], [4, 5]])
[[3, 5], [7, 9]]
>>> add([[1.2,2.4],[3,4]],[[2,3],[4,5]])
>>> add([[1.2, 2.4], [3, 4]], [[2, 3], [4, 5]])
[[3.2, 5.4], [7, 9]]
>>> add([[1, 2], [4, 5]], [[3, 7], [3, 4]], [[3, 5], [5, 7]])
[[7, 14], [12, 16]]
>>> add([[1, 2, 3], [4, 5, 6]], [[2, 3, 4], [5, 6, 7]])
[[3, 5, 7], [9, 11, 13]]
>>> add([3], [4, 5])
Traceback (most recent call last):
...
Expand All @@ -29,55 +31,61 @@ def add(*matrix_s: list[list[int]]) -> list[list[int]]:

def subtract(matrix_a: list[list[int]], matrix_b: list[list[int]]) -> list[list[int]]:
"""
>>> subtract([[1,2],[3,4]],[[2,3],[4,5]])
>>> subtract([[1, 2], [3, 4]], [[2, 3], [4, 5]])
[[-1, -1], [-1, -1]]
>>> subtract([[1,2.5],[3,4]],[[2,3],[4,5.5]])
>>> subtract([[1, 2.5], [3, 4]], [[2, 3], [4, 5.5]])
[[-1, -0.5], [-1, -1.5]]
>>> subtract([[3, 4, 5], [6, 7, 8]], [[1, 2, 3], [4, 5, 6]])
[[2, 2, 2], [2, 2, 2]]
>>> subtract([3], [4, 5])
Traceback (most recent call last):
...
TypeError: Expected a matrix, got int/list instead
"""
if (
_check_not_integer(matrix_a)
and _check_not_integer(matrix_b)
and _verify_matrix_sizes(matrix_a, matrix_b)
):
if _check_not_integer(matrix_a) and _check_not_integer(matrix_b):
_verify_matrix_sizes(matrix_a, matrix_b)
return [[i - j for i, j in zip(*m)] for m in zip(matrix_a, matrix_b)]
raise TypeError("Expected a matrix, got int/list instead")


def scalar_multiply(matrix: list[list[int]], n: float) -> list[list[float]]:
"""
>>> scalar_multiply([[1,2],[3,4]],5)
>>> scalar_multiply([[1, 2], [3, 4]], 5)
[[5, 10], [15, 20]]
>>> scalar_multiply([[1.4,2.3],[3,4]],5)
>>> scalar_multiply([[1.4, 2.3], [3, 4]], 5)
[[7.0, 11.5], [15, 20]]
"""
return [[x * n for x in row] for row in matrix]


def multiply(matrix_a: list[list[int]], matrix_b: list[list[int]]) -> list[list[int]]:
"""
>>> multiply([[1,2],[3,4]],[[5,5],[7,5]])
>>> multiply([[1, 2], [3, 4]], [[5, 5], [7, 5]])
[[19, 15], [43, 35]]
>>> multiply([[1,2.5],[3,4.5]],[[5,5],[7,5]])
>>> multiply([[1, 2.5], [3, 4.5]], [[5, 5], [7, 5]])
[[22.5, 17.5], [46.5, 37.5]]
>>> multiply([[1, 2, 3]], [[2], [3], [4]])
[[20]]
>>> multiply([[1, 2, 3], [4, 5, 6]], [[1, 2], [3, 4], [5, 6]])
[[22, 28], [49, 64]]
>>> multiply([3], [4, 5])
Traceback (most recent call last):
...
TypeError: Expected a matrix, got int/list instead
"""
if _check_not_integer(matrix_a) and _check_not_integer(matrix_b):
rows, cols = _verify_matrix_sizes(matrix_a, matrix_b)

if cols[0] != rows[1]:
msg = (
"Cannot multiply matrix of dimensions "
f"({rows[0]},{cols[0]}) and ({rows[1]},{cols[1]})"
)
raise ValueError(msg)
return [
[sum(m * n for m, n in zip(i, j)) for j in zip(*matrix_b)] for i in matrix_a
]
rows_a, cols_a = _shape(matrix_a)
rows_b, cols_b = _shape(matrix_b)
if cols_a != rows_b:
msg = (
"Cannot multiply matrix of dimensions "
f"({rows_a},{cols_a}) and ({rows_b},{cols_b})"
)
raise ValueError(msg)
return [
[sum(m * n for m, n in zip(i, j)) for j in zip(*matrix_b)] for i in matrix_a
]
raise TypeError("Expected a matrix, got int/list instead")


def identity(n: int) -> list[list[int]]:
Expand Down Expand Up @@ -187,7 +195,7 @@ def _verify_matrix_sizes(
matrix_a: list[list[int]], matrix_b: list[list[int]]
) -> tuple[tuple[int, int], tuple[int, int]]:
shape = _shape(matrix_a) + _shape(matrix_b)
if shape[0] != shape[3] or shape[1] != shape[2]:
if shape[0] != shape[2] or shape[1] != shape[3]:
msg = (
"operands could not be broadcast together with shape "
f"({shape[0], shape[1]}), ({shape[2], shape[3]})"
Expand Down
38 changes: 31 additions & 7 deletions matrix/tests/test_matrix_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
mat_e = [[3, 0, 2], [2, 0, -2], [0, 1, 1], [2, 0, -2]]
mat_f = [1]
mat_h = [2]
mat_rect_a = [[1, 2, 3], [4, 5, 6]]
mat_rect_b = [[7, 8, 9], [10, 11, 12]]
mat_rect_mult = [[1, 2], [3, 4], [5, 6]]

logger = logging.getLogger()
logger.level = logging.DEBUG
Expand All @@ -33,7 +36,14 @@

@pytest.mark.mat_ops
@pytest.mark.parametrize(
("mat1", "mat2"), [(mat_a, mat_b), (mat_c, mat_d), (mat_d, mat_e), (mat_f, mat_h)]
("mat1", "mat2"),
[
(mat_a, mat_b),
(mat_c, mat_d),
(mat_rect_a, mat_rect_b),
(mat_d, mat_e),
(mat_f, mat_h),
],
)
def test_addition(mat1, mat2) -> None:
if (np.array(mat1)).shape < (2, 2) or (np.array(mat2)).shape < (2, 2):
Expand All @@ -53,7 +63,14 @@ def test_addition(mat1, mat2) -> None:

@pytest.mark.mat_ops
@pytest.mark.parametrize(
("mat1", "mat2"), [(mat_a, mat_b), (mat_c, mat_d), (mat_d, mat_e), (mat_f, mat_h)]
("mat1", "mat2"),
[
(mat_a, mat_b),
(mat_c, mat_d),
(mat_rect_a, mat_rect_b),
(mat_d, mat_e),
(mat_f, mat_h),
],
)
def test_subtraction(mat1, mat2) -> None:
if (np.array(mat1)).shape < (2, 2) or (np.array(mat2)).shape < (2, 2):
Expand All @@ -68,19 +85,26 @@ def test_subtraction(mat1, mat2) -> None:
else:
logger.info(f"\n\t{test_subtraction.__name__} with different matrix dims")
with pytest.raises(ValueError):
assert matop.subtract(mat1, mat2)
matop.subtract(mat1, mat2)


@pytest.mark.mat_ops
@pytest.mark.parametrize(
("mat1", "mat2"), [(mat_a, mat_b), (mat_c, mat_d), (mat_d, mat_e), (mat_f, mat_h)]
("mat1", "mat2"),
[
(mat_a, mat_b),
(mat_c, mat_d),
(mat_rect_a, mat_rect_mult),
(mat_d, mat_e),
(mat_f, mat_h),
],
)
def test_multiplication(mat1, mat2) -> None:
if (np.array(mat1)).shape < (2, 2) or (np.array(mat2)).shape < (2, 2):
logger.info(f"\n\t{test_multiplication.__name__} returned integer")
with pytest.raises(TypeError):
matop.add(mat1, mat2)
elif (np.array(mat1)).shape == (np.array(mat2)).shape:
matop.multiply(mat1, mat2)
elif np.array(mat1).shape[1] == np.array(mat2).shape[0]:
logger.info(f"\n\t{test_multiplication.__name__} meets dim requirements")
act = (np.matmul(mat1, mat2)).tolist()
theo = matop.multiply(mat1, mat2)
Expand All @@ -90,7 +114,7 @@ def test_multiplication(mat1, mat2) -> None:
f"\n\t{test_multiplication.__name__} does not meet dim requirements"
)
with pytest.raises(ValueError):
assert matop.subtract(mat1, mat2)
matop.multiply(mat1, mat2)


@pytest.mark.mat_ops
Expand Down
Loading