11"""
2- function based version of matrix operations, which are just 2D arrays
2+ Functions for 2D matrix operations
33"""
44
5+ from typing import List , Tuple
56
6- def add (matrix_a , matrix_b ):
7+
8+ def add (matrix_a : List [list ], matrix_b : List [list ]) -> List [list ]:
9+ """
10+ >>> add([[1,2],[3,4]],[[2,3],[4,5]])
11+ [[3, 5], [7, 9]]
12+ >>> add([[1.2,2.4],[3,4]],[[2,3],[4,5]])
13+ [[3.2, 5.4], [7, 9]]
14+ """
715 if _check_not_integer (matrix_a ) and _check_not_integer (matrix_b ):
8- rows , cols = _verify_matrix_sizes (matrix_a , matrix_b )
9- matrix_c = []
10- for i in range (rows [0 ]):
11- list_1 = []
12- for j in range (cols [0 ]):
13- val = matrix_a [i ][j ] + matrix_b [i ][j ]
14- list_1 .append (val )
15- matrix_c .append (list_1 )
16+ _verify_matrix_sizes (matrix_a , matrix_b )
17+ matrix_c = [[i + j for i , j in zip (m , n )]
18+ for m , n in zip (matrix_a , matrix_b )]
1619 return matrix_c
1720
1821
19- def subtract (matrix_a , matrix_b ):
22+ def subtract (matrix_a : List [list ], matrix_b : List [list ]) -> List [list ]:
23+ """
24+ >>> subtract([[1,2],[3,4]],[[2,3],[4,5]])
25+ [[-1, -1], [-1, -1]]
26+ >>> subtract([[1,2.5],[3,4]],[[2,3],[4,5.5]])
27+ [[-1, -0.5], [-1, -1.5]]
28+ """
2029 if _check_not_integer (matrix_a ) and _check_not_integer (matrix_b ):
21- rows , cols = _verify_matrix_sizes (matrix_a , matrix_b )
22- matrix_c = []
23- for i in range (rows [0 ]):
24- list_1 = []
25- for j in range (cols [0 ]):
26- val = matrix_a [i ][j ] - matrix_b [i ][j ]
27- list_1 .append (val )
28- matrix_c .append (list_1 )
30+ _verify_matrix_sizes (matrix_a , matrix_b )
31+ matrix_c = [[i - j for i , j in zip (m , n )]
32+ for m , n in zip (matrix_a , matrix_b )]
2933 return matrix_c
3034
3135
32- def scalar_multiply (matrix , n ):
36+ def scalar_multiply (matrix : List [list ], n : int ) -> List [list ]:
37+ """
38+ >>> scalar_multiply([[1,2],[3,4]],5)
39+ [[5, 10], [15, 20]]
40+ >>> scalar_multiply([[1.4,2.3],[3,4]],5)
41+ [[7.0, 11.5], [15, 20]]
42+ """
3343 return [[x * n for x in row ] for row in matrix ]
3444
3545
36- def multiply (matrix_a , matrix_b ):
46+ def multiply (matrix_a : List [list ], matrix_b : List [list ]) -> List [list ]:
47+ """
48+ >>> multiply([[1,2],[3,4]],[[5,5],[7,5]])
49+ [[19, 15], [43, 35]]
50+ >>> multiply([[1,2.5],[3,4.5]],[[5,5],[7,5]])
51+ [[22.5, 17.5], [46.5, 37.5]]
52+ """
3753 if _check_not_integer (matrix_a ) and _check_not_integer (matrix_b ):
3854 matrix_c = []
3955 rows , cols = _verify_matrix_sizes (matrix_a , matrix_b )
@@ -48,41 +64,55 @@ def multiply(matrix_a, matrix_b):
4864 for j in range (cols [1 ]):
4965 val = 0
5066 for k in range (cols [1 ]):
51- val = val + matrix_a [i ][k ] * matrix_b [k ][j ]
67+ val += matrix_a [i ][k ] * matrix_b [k ][j ]
5268 list_1 .append (val )
5369 matrix_c .append (list_1 )
5470 return matrix_c
5571
5672
57- def identity (n ) :
73+ def identity (n : int ) -> List [ list ] :
5874 """
5975 :param n: dimension for nxn matrix
6076 :type n: int
6177 :return: Identity matrix of shape [n, n]
78+ >>> identity(3)
79+ [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
6280 """
6381 n = int (n )
6482 return [[int (row == column ) for column in range (n )] for row in range (n )]
6583
6684
67- def transpose (matrix , return_map = True ):
85+ def transpose (matrix : List [list ], return_map : bool = True ) -> List [list ]:
86+ """
87+ >>> transpose([[1,2],[3,4]]) # doctest: +ELLIPSIS
88+ <map object at ...
89+ >>> transpose([[1,2],[3,4]], return_map=False)
90+ [[1, 3], [2, 4]]
91+ """
6892 if _check_not_integer (matrix ):
6993 if return_map :
7094 return map (list , zip (* matrix ))
7195 else :
72- # mt = []
73- # for i in range(len(matrix[0])):
74- # mt.append([row[i] for row in matrix])
75- # return mt
7696 return [[row [i ] for row in matrix ] for i in range (len (matrix [0 ]))]
7797
7898
79- def minor (matrix , row , column ):
80- minor = matrix [:row ] + matrix [row + 1 :]
81- minor = [row [:column ] + row [column + 1 :] for row in minor ]
99+ def minor (matrix : List [list ], row : int , column : int ) -> List [list ]:
100+ """
101+ >>> minor([[1, 2], [3, 4]], 1, 1)
102+ [[1]]
103+ """
104+ minor = matrix [:row ] + matrix [row + 1 :]
105+ minor = [row [:column ] + row [column + 1 :] for row in minor ]
82106 return minor
83107
84108
85- def determinant (matrix ):
109+ def determinant (matrix : List [list ]) -> int :
110+ """
111+ >>> determinant([[1, 2], [3, 4]])
112+ -2
113+ >>> determinant([[1.5, 2.5], [3, 4]])
114+ -1.5
115+ """
86116 if len (matrix ) == 1 :
87117 return matrix [0 ][0 ]
88118
@@ -92,12 +122,18 @@ def determinant(matrix):
92122 return res
93123
94124
95- def inverse (matrix ):
125+ def inverse (matrix : List [list ]) -> List [list ]:
126+ """
127+ >>> inverse([[1, 2], [3, 4]])
128+ [[-2.0, 1.0], [1.5, -0.5]]
129+ >>> inverse([[1, 1], [1, 1]])
130+ """
131+ # https://stackoverflow.com/questions/20047519/python-doctests-test-for-none
96132 det = determinant (matrix )
97133 if det == 0 :
98134 return None
99135
100- matrix_minor = [[] for _ in range ( len ( matrix )) ]
136+ matrix_minor = [[] for _ in matrix ]
101137 for i in range (len (matrix )):
102138 for j in range (len (matrix )):
103139 matrix_minor [i ].append (determinant (minor (matrix , i , j )))
@@ -110,17 +146,18 @@ def inverse(matrix):
110146 return scalar_multiply (adjugate , 1 / det )
111147
112148
113- def _check_not_integer (matrix ) :
149+ def _check_not_integer (matrix : List [ list ]) -> bool :
114150 if not isinstance (matrix , int ) and not isinstance (matrix [0 ], int ):
115151 return True
116152 raise TypeError ("Expected a matrix, got int/list instead" )
117153
118154
119- def _shape (matrix ) :
155+ def _shape (matrix : List [ list ]) -> list :
120156 return list ((len (matrix ), len (matrix [0 ])))
121157
122158
123- def _verify_matrix_sizes (matrix_a , matrix_b ):
159+ def _verify_matrix_sizes (
160+ matrix_a : List [list ], matrix_b : List [list ]) -> Tuple [list ]:
124161 shape = _shape (matrix_a )
125162 shape += _shape (matrix_b )
126163 if shape [0 ] != shape [2 ] or shape [1 ] != shape [3 ]:
@@ -134,21 +171,24 @@ def _verify_matrix_sizes(matrix_a, matrix_b):
134171def main ():
135172 matrix_a = [[12 , 10 ], [3 , 9 ]]
136173 matrix_b = [[3 , 4 ], [7 , 4 ]]
137- matrix_c = [[11 , 12 , 13 , 14 ], [21 , 22 , 23 , 24 ], [31 , 32 , 33 , 34 ], [41 , 42 , 43 , 44 ]]
174+ matrix_c = [[11 , 12 , 13 , 14 ], [21 , 22 , 23 , 24 ],
175+ [31 , 32 , 33 , 34 ], [41 , 42 , 43 , 44 ]]
138176 matrix_d = [[3 , 0 , 2 ], [2 , 0 , - 2 ], [0 , 1 , 1 ]]
139177 print (
140- "Add Operation, %s + %s = %s \n "
141- % (matrix_a , matrix_b , (add (matrix_a , matrix_b )))
142- )
178+ f"Add Operation, { matrix_a } + { matrix_b } "
179+ f" = { add (matrix_a , matrix_b )} \n " )
143180 print (
144- "Multiply Operation, %s * %s = %s \n "
145- % ( matrix_a , matrix_b , multiply (matrix_a , matrix_b ))
181+ f "Multiply Operation, { matrix_a } * { matrix_b } " ,
182+ f"= { multiply (matrix_a , matrix_b )} \n " ,
146183 )
147- print ("Identity: %s \n " % identity (5 ))
148- print ("Minor of {} = {} \n " . format ( matrix_c , minor (matrix_c , 1 , 2 )) )
149- print ("Determinant of {} = {} \n " . format ( matrix_b , determinant ( matrix_b )) )
150- print ("Inverse of {} = {} \n " . format ( matrix_d , inverse (matrix_d )) )
184+ print (f "Identity: { identity (5 )} \n " )
185+ print (f "Minor of { matrix_c } = { minor (matrix_c , 1 , 2 )} \n " )
186+ print (f "Determinant of { matrix_b } = { determinant ( matrix_b ) } \n " )
187+ print (f "Inverse of { matrix_d } = { inverse (matrix_d )} \n " )
151188
152189
153190if __name__ == "__main__" :
191+ import doctest
192+
193+ doctest .testmod ()
154194 main ()
0 commit comments