Skip to content

Commit 1208636

Browse files
ojas-wanipre-commit-ci[bot]cclauss
authored andcommitted
Add matrix_multiplication (TheAlgorithms#10045)
* added laplacian_filter file * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * updated laplacian.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * updated laplacian_py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * updated laplacian_filter.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * updated laplacian_filter.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * updated laplacian_filter.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * required changes to laplacian file * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * changed laplacian_filter.py * changed laplacian_filter.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * changed laplacian_filter.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * changed laplacian_filter.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * updated laplacian_filter.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * update laplacian_filter.py * update laplacian_filter.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * update laplacian_filter.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * changed laplacian_filter.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * changed laplacian_filter.py * changed laplacian_filter.py * changed laplacian_filter.py * add matrix_multiplication.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * update matrix_multiplication * update matrix_multiplication * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * make changes * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * update * update * updates * resolve conflict * add doctest * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * make changes * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * update laplacian.py * add doctests * more doctest added * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * try to resolve ruff error * try to reslve ruff error * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * update doctest * attemp - resolve ruff error * resolve build error * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * resolve build issue * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * update build * doctest update * update doctest * update doctest * update doctest * fix ruff error * file location changed * Delete digital_image_processing/filters/laplacian_filter.py * Create laplacian_filter.py * Update matrix_multiplication_recursion.py * Update matrix_multiplication_recursion.py * Update matrix_multiplication_recursion.py * Update matrix_multiplication_recursion.py * Update matrix_multiplication_recursion.py --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Christian Clauss <[email protected]>
1 parent bf766af commit 1208636

File tree

1 file changed

+180
-0
lines changed

1 file changed

+180
-0
lines changed

Diff for: matrix/matrix_multiplication_recursion.py

+180
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# @Author : ojas-wani
2+
# @File : matrix_multiplication_recursion.py
3+
# @Date : 10/06/2023
4+
5+
6+
"""
7+
Perform matrix multiplication using a recursive algorithm.
8+
https://en.wikipedia.org/wiki/Matrix_multiplication
9+
"""
10+
# type Matrix = list[list[int]] # psf/black currenttly fails on this line
11+
Matrix = list[list[int]]
12+
13+
matrix_1_to_4 = [
14+
[1, 2],
15+
[3, 4],
16+
]
17+
18+
matrix_5_to_8 = [
19+
[5, 6],
20+
[7, 8],
21+
]
22+
23+
matrix_5_to_9_high = [
24+
[5, 6],
25+
[7, 8],
26+
[9],
27+
]
28+
29+
matrix_5_to_9_wide = [
30+
[5, 6],
31+
[7, 8, 9],
32+
]
33+
34+
matrix_count_up = [
35+
[1, 2, 3, 4],
36+
[5, 6, 7, 8],
37+
[9, 10, 11, 12],
38+
[13, 14, 15, 16],
39+
]
40+
41+
matrix_unordered = [
42+
[5, 8, 1, 2],
43+
[6, 7, 3, 0],
44+
[4, 5, 9, 1],
45+
[2, 6, 10, 14],
46+
]
47+
matrices = (
48+
matrix_1_to_4,
49+
matrix_5_to_8,
50+
matrix_5_to_9_high,
51+
matrix_5_to_9_wide,
52+
matrix_count_up,
53+
matrix_unordered,
54+
)
55+
56+
57+
def is_square(matrix: Matrix) -> bool:
58+
"""
59+
>>> is_square([])
60+
True
61+
>>> is_square(matrix_1_to_4)
62+
True
63+
>>> is_square(matrix_5_to_9_high)
64+
False
65+
"""
66+
len_matrix = len(matrix)
67+
return all(len(row) == len_matrix for row in matrix)
68+
69+
70+
def matrix_multiply(matrix_a: Matrix, matrix_b: Matrix) -> Matrix:
71+
"""
72+
>>> matrix_multiply(matrix_1_to_4, matrix_5_to_8)
73+
[[19, 22], [43, 50]]
74+
"""
75+
return [
76+
[sum(a * b for a, b in zip(row, col)) for col in zip(*matrix_b)]
77+
for row in matrix_a
78+
]
79+
80+
81+
def matrix_multiply_recursive(matrix_a: Matrix, matrix_b: Matrix) -> Matrix:
82+
"""
83+
:param matrix_a: A square Matrix.
84+
:param matrix_b: Another square Matrix with the same dimensions as matrix_a.
85+
:return: Result of matrix_a * matrix_b.
86+
:raises ValueError: If the matrices cannot be multiplied.
87+
88+
>>> matrix_multiply_recursive([], [])
89+
[]
90+
>>> matrix_multiply_recursive(matrix_1_to_4, matrix_5_to_8)
91+
[[19, 22], [43, 50]]
92+
>>> matrix_multiply_recursive(matrix_count_up, matrix_unordered)
93+
[[37, 61, 74, 61], [105, 165, 166, 129], [173, 269, 258, 197], [241, 373, 350, 265]]
94+
>>> matrix_multiply_recursive(matrix_1_to_4, matrix_5_to_9_wide)
95+
Traceback (most recent call last):
96+
...
97+
ValueError: Invalid matrix dimensions
98+
>>> matrix_multiply_recursive(matrix_1_to_4, matrix_5_to_9_high)
99+
Traceback (most recent call last):
100+
...
101+
ValueError: Invalid matrix dimensions
102+
>>> matrix_multiply_recursive(matrix_1_to_4, matrix_count_up)
103+
Traceback (most recent call last):
104+
...
105+
ValueError: Invalid matrix dimensions
106+
"""
107+
if not matrix_a or not matrix_b:
108+
return []
109+
if not all(
110+
(len(matrix_a) == len(matrix_b), is_square(matrix_a), is_square(matrix_b))
111+
):
112+
raise ValueError("Invalid matrix dimensions")
113+
114+
# Initialize the result matrix with zeros
115+
result = [[0] * len(matrix_b[0]) for _ in range(len(matrix_a))]
116+
117+
# Recursive multiplication of matrices
118+
def multiply(
119+
i_loop: int,
120+
j_loop: int,
121+
k_loop: int,
122+
matrix_a: Matrix,
123+
matrix_b: Matrix,
124+
result: Matrix,
125+
) -> None:
126+
"""
127+
:param matrix_a: A square Matrix.
128+
:param matrix_b: Another square Matrix with the same dimensions as matrix_a.
129+
:param result: Result matrix
130+
:param i: Index used for iteration during multiplication.
131+
:param j: Index used for iteration during multiplication.
132+
:param k: Index used for iteration during multiplication.
133+
>>> 0 > 1 # Doctests in inner functions are never run
134+
True
135+
"""
136+
if i_loop >= len(matrix_a):
137+
return
138+
if j_loop >= len(matrix_b[0]):
139+
return multiply(i_loop + 1, 0, 0, matrix_a, matrix_b, result)
140+
if k_loop >= len(matrix_b):
141+
return multiply(i_loop, j_loop + 1, 0, matrix_a, matrix_b, result)
142+
result[i_loop][j_loop] += matrix_a[i_loop][k_loop] * matrix_b[k_loop][j_loop]
143+
return multiply(i_loop, j_loop, k_loop + 1, matrix_a, matrix_b, result)
144+
145+
# Perform the recursive matrix multiplication
146+
multiply(0, 0, 0, matrix_a, matrix_b, result)
147+
return result
148+
149+
150+
if __name__ == "__main__":
151+
from doctest import testmod
152+
153+
failure_count, test_count = testmod()
154+
if not failure_count:
155+
matrix_a = matrices[0]
156+
for matrix_b in matrices[1:]:
157+
print("Multiplying:")
158+
for row in matrix_a:
159+
print(row)
160+
print("By:")
161+
for row in matrix_b:
162+
print(row)
163+
print("Result:")
164+
try:
165+
result = matrix_multiply_recursive(matrix_a, matrix_b)
166+
for row in result:
167+
print(row)
168+
assert result == matrix_multiply(matrix_a, matrix_b)
169+
except ValueError as e:
170+
print(f"{e!r}")
171+
print()
172+
matrix_a = matrix_b
173+
174+
print("Benchmark:")
175+
from functools import partial
176+
from timeit import timeit
177+
178+
mytimeit = partial(timeit, globals=globals(), number=100_000)
179+
for func in ("matrix_multiply", "matrix_multiply_recursive"):
180+
print(f"{func:>25}(): {mytimeit(f'{func}(matrix_count_up, matrix_unordered)')}")

0 commit comments

Comments
 (0)