@@ -8,7 +8,7 @@ class Matrix:
88 Matrix object generated from a 2D array where each element is an array representing
99 a row.
1010 Rows can contain type int or float.
11- Common operations and information available.
11+ Common operations and properties are available.
1212 >>> rows = [
1313 ... [1, 2, 3],
1414 ... [4, 5, 6],
@@ -145,15 +145,297 @@ def order(self) -> tuple[int, int]:
145145
146146 @property
147147 def is_square (self ) -> bool :
148- return self .order [0 ] == self .order [1 ]
148+ """
149+ Returns True if the matrix is square, False otherwise.
150+ Wikipedia reference: https://en.wikipedia.org/wiki/Square_matrix
151+ >>> print(Matrix([[1, 2], [3, 4]]).is_square)
152+ True
153+ >>> print(Matrix([[1, 2, 3], [3, 4, 5]]).is_square)
154+ False
155+ >>> print(Matrix([[1]]).is_square)
156+ True
157+ >>> print(Matrix([[1, 2], [3,4], [5,6]]).is_square)
158+ False
159+ """
160+ return self .num_rows == self .num_columns
149161
150162 def identity (self ) -> Matrix :
163+ """
164+ Returns the identity matrix of the same order as the matrix.
165+ Wikipedia reference: https://en.wikipedia.org/wiki/Identity_matrix
166+ >>> print(Matrix([[1, 2], [3, 4]]).identity())
167+ [[1. 0.]
168+ [0. 1.]]
169+ >>> print(Matrix([[1, 2, 3], [3, 4, 5]]).identity())
170+ Traceback (most recent call last):
171+ ...
172+ ValueError: Only square matrices have an identity matrix
173+ """
174+ if not self .is_square :
175+ raise ValueError ("Only square matrices have an identity matrix" )
151176 values = [
152177 [0 if column_num != row_num else 1 for column_num in range (self .num_rows )]
153178 for row_num in range (self .num_rows )
154179 ]
155180 return Matrix (values )
156181
182+ @property
183+ def is_identy (self ) -> bool :
184+ """
185+ Returns True if the matrix is an identity matrix, False otherwise.
186+ Wikipedia reference: https://en.wikipedia.org/wiki/Identity_matrix
187+ >>> print(Matrix([[1, 0], [0, 1]]).is_identy)
188+ True
189+ >>> print(Matrix([[1, 2], [1, 4]]).is_identy)
190+ False
191+ >>> print(Matrix([[1, 0, 0], [0, 0, 1]]).is_identy)
192+ Traceback (most recent call last):
193+ ...
194+ ValueError: Only square matrices can be identity matrices
195+ """
196+ if not self .is_square :
197+ raise ValueError ("Only square matrices can be identity matrices" )
198+ for row in range (self .num_rows ):
199+ for col in range (self .num_columns ):
200+ if self .rows [row ][col ] != (0 if row != col else 1 ):
201+ return False
202+ return True
203+
204+ @property
205+ def is_zero_matrix (self ) -> bool :
206+ """
207+ Returns True if all elements of the matrix are zero, False otherwise.
208+ Wikipedia reference: https://en.wikipedia.org/wiki/Zero_matrix
209+ >>> print(Matrix([[1, 2, 3], [3, 4, 5]]).is_zero_matrix)
210+ False
211+ >>> print(Matrix([[0,0,0],[0,0,0],]).is_zero_matrix)
212+ True
213+ >>> print(Matrix([[0]]).is_zero_matrix)
214+ True
215+ >>> print(Matrix([[1]]).is_zero_matrix)
216+ False
217+ """
218+ for row in range (self .num_rows ):
219+ for col in range (self .num_columns ):
220+ if self .rows [row ][col ] != 0 :
221+ return False
222+ return True
223+
224+ @property
225+ def is_ones_matrix (self ) -> bool :
226+ """
227+ Returns True if all elements of the matrix are 1, False otherwise.
228+ Wikipedia: https://en.wikipedia.org/wiki/Matrix_of_ones
229+ >>> print(Matrix([[1, 2, 3], [3, 4, 5]]).is_ones_matrix)
230+ False
231+ >>> print(Matrix([[1,1,1],[1,1,1]]).is_ones_matrix)
232+ True
233+ >>> print(Matrix([[0]]).is_ones_matrix)
234+ False
235+ >>> print(Matrix([[1]]).is_ones_matrix)
236+ True
237+ """
238+
239+ for row in range (self .num_rows ):
240+ for col in range (self .num_columns ):
241+ if self .rows [row ][col ] != 1 :
242+ return False
243+ return True
244+
245+ @property
246+ def is_binary (self ) -> bool :
247+ """
248+ Returns True if all elements of the matrix are either 0 or 1, False otherwise.
249+ Wikipedia reference: https://en.wikipedia.org/wiki/Logical_matrix
250+ >>> print(Matrix([[1, 0], [0, 1]]).is_binary)
251+ True
252+ >>> print(Matrix([[1, 2], [3, 4]]).is_binary)
253+ False
254+ """
255+ return all (element in (0 , 1 ) for row in self .rows for element in row )
256+
257+ def diagonal (self ) -> list [int ]:
258+ """
259+ Returns a list containing the values on the diagonal of the matrix.
260+ Wikipedia reference: https://en.wikipedia.org/wiki/Main_diagonal
261+ >>> print(Matrix([[1,2,3], [4,5,6], [7,8,9]]).diagonal())
262+ [1, 5, 9]
263+ >>> print(Matrix([[2]]).diagonal())
264+ [2]
265+ >>> print(Matrix([[1,2,3,4], [5,6,7,8], [9,10,11,12]]).diagonal())
266+ [1, 6, 11]
267+ >>> print(Matrix([[1,2,3], [4,5,6], [7,8,9] ,[10,11,12]]).diagonal())
268+ [1, 5, 9]
269+ """
270+ return [self .rows [i ][i ] for i in range (min (self .num_rows , self .num_columns ))]
271+
272+ def anti_diagonal (self ) -> list [int ]:
273+ """
274+ Returns a list containing the anti-diagonal elements of the matrix.
275+ Wikipedia reference: https://en.wikipedia.org/wiki/Anti-diagonal_matrix
276+ >>> print(Matrix([[1,2,3], [4,5,6], [7,8,9]]).anti_diagonal())
277+ [3, 5, 7]
278+ >>> print(Matrix([[1,2,3,4], [5,6, 7, 8]]).anti_diagonal())
279+ [4, 7]
280+ >>> print(Matrix([[1,2], [3,4], [5,6]]).anti_diagonal())
281+ [2, 3]
282+ >>> print(Matrix([[2]]).anti_diagonal())
283+ [2]
284+ """
285+ return [
286+ self .rows [i ][- 1 - i ] for i in range (min (self .num_rows , self .num_columns ))
287+ ]
288+
289+ @property
290+ def is_diagonal (self ) -> bool :
291+ """
292+ Returns True if the matrix is diagonal, False otherwise.
293+ Wikipedia reference: https://en.wikipedia.org/wiki/Main_diagonal
294+
295+ >>> print(Matrix([[2, 0], [0, 1]]).is_diagonal)
296+ True
297+ >>> print(Matrix([[2, 0, 0], [0, 1, 0]]).is_diagonal)
298+ True
299+ >>> print(Matrix([[2, 0, 0], [0, 1, 0], [0, 0, 3], [0,0,0]]).is_diagonal)
300+ True
301+ >>> print(Matrix([[1, 2], [3, 4]]).is_diagonal)
302+ False
303+ >>> print(Matrix([[1,2,3,4], [5,6,7,8], [9,10,11,12]]).is_diagonal)
304+ False
305+ """
306+ size = min (self .num_rows , self .num_columns )
307+ return (
308+ sum (
309+ self .rows [r ][c ] if r != c else 0
310+ for r in range (size )
311+ for c in range (size )
312+ )
313+ == 0
314+ )
315+
316+ @property
317+ def is_exchange (self ) -> bool :
318+ """
319+ Returns True if the matrix is an exchange matrix, False otherwise.
320+ Wikipedia: https://en.wikipedia.org/wiki/Exchange_matrix
321+
322+ >>> print(Matrix([[1, 0], [0, 1]]).is_exchange)
323+ False
324+ >>> print(Matrix([[0, 1], [1, 0]]).is_exchange)
325+ True
326+ >>> print(Matrix([[0, 2], [3, 0]]).is_exchange)
327+ True
328+ >>> print(Matrix([[1, 2], [3, 4]]).is_exchange)
329+ False
330+ >>> print(Matrix([[1,2,3,4], [5,6,7,8], [9,10,11,12]]).is_exchange)
331+ Traceback (most recent call last):
332+ ...
333+ ValueError: Only square matrices can be exchange matrices
334+ """
335+ if not self .is_square :
336+ raise ValueError ("Only square matrices can be exchange matrices" )
337+
338+ size = self .num_rows
339+ return (
340+ sum (
341+ self .rows [r ][c ] if r != size - c - 1 else 0
342+ for r in range (size )
343+ for c in range (size )
344+ )
345+ == 0
346+ )
347+
348+ @property
349+ def is_elementary (self ) -> bool :
350+ """
351+ An elementary matrix is a matrix that can be obtained from the identity matrix
352+ by exactly one elementary row operation.
353+ Wikipedia reference: https://en.wikipedia.org/wiki/Elementary_matrix
354+
355+ For a square matrix, there are only three possibilities:
356+ Row swapping: A row can be swapped with another row.
357+ Row multiplication: A row can be multiplied by a value other than 0 or 1.
358+ Row addition: A row can be replaced by the sum of that row and
359+ a non-zero multiple of another row.
360+
361+ >>> print(Matrix([[0]]).is_elementary)
362+ False
363+ >>> print(Matrix([[1]]).is_elementary)
364+ False
365+ >>> print(Matrix([[2]]).is_elementary)
366+ True
367+ >>> print(Matrix([[1,0,0], [0,1,0], [0,0,1]]).is_elementary)
368+ False
369+ >>> print(Matrix([[1,0,0], [0,0,1], [0,1,0]]).is_elementary)
370+ True
371+ >>> print(Matrix([[0,0,1], [1,0,0], [1,0,0]]).is_elementary)
372+ False
373+ >>> print(Matrix([[2,0,0], [0,1,0], [0,0,1]]).is_elementary)
374+ True
375+ >>> print(Matrix([[1,0,0], [0,2,0], [0,0,1]]).is_elementary)
376+ True
377+ >>> print(Matrix([[2,0,0], [0,2,0], [0,0,1]]).is_elementary)
378+ False
379+ >>> print(Matrix([[1,2,0], [0,1,0], [0,0,1]]).is_elementary)
380+ True
381+ >>> print(Matrix([[1,2,0], [0,1,0], [0,0,1]]).is_elementary)
382+ True
383+ >>> print(Matrix([[1,2,0], [0,2,0], [0,0,1]]).is_elementary)
384+ False
385+ >>> print(Matrix([[1,0,0], [0,1,0], [0,3,1]]).is_elementary)
386+ True
387+ >>> print(Matrix([[1,0,3], [0,1,0], [0,3,1]]).is_elementary)
388+ False
389+ >>> print(Matrix([[1,0], [0,1], [0,3]]).is_elementary)
390+ Traceback (most recent call last):
391+ ...
392+ ValueError: Only square matrices can be elementary
393+ """
394+ if not self .is_square :
395+ raise ValueError ("Only square matrices can be elementary" )
396+ size = self .order [0 ]
397+ if size == 1 :
398+ # Special case:
399+ # A 1 x 1 matrix is elementary if its value is different from 0 or 1
400+ return self .rows [0 ][0 ] not in [0 , 1 ]
401+
402+ # Check row swapping
403+ # True when:
404+ # matrix is binary
405+ # matrix is not the identity matrix
406+ # exactly 2 values are not on the diagonal
407+ if (
408+ self .is_binary
409+ and self != self .identity ()
410+ and sum (
411+ 1 if r == c and self .rows [r ][c ] == 0 else 0
412+ for r in range (size )
413+ for c in range (size )
414+ )
415+ == 2
416+ ):
417+ return True
418+ # Type 2: row multiplication
419+ # True when:
420+ # matrix is diagonal
421+ # only 1 value differs from 1
422+ if self .is_diagonal and sum (x != 1 for x in self .diagonal ()) == 1 :
423+ return True
424+
425+ # Type 3: row addition
426+ # True when:
427+ # values on diagonal are all 1
428+ # only 1 value not on the diagonal differs from 0
429+ return (
430+ all (v == 1 for v in self .diagonal ())
431+ and sum (
432+ 0 if r == c or self .rows [r ][c ] == 0 else 1
433+ for r in range (size )
434+ for c in range (size )
435+ )
436+ == 1
437+ )
438+
157439 def determinant (self ) -> int :
158440 if not self .is_square :
159441 return 0
0 commit comments