fix: mypy 0.991 issues (#7988)

* fix: mypy 0.991 issues

* fix: invalid condition for base case
This commit is contained in:
Dhruv Manilawala 2022-11-15 22:59:14 +05:30 committed by GitHub
parent 4ce8ad9ce6
commit 8bfd1c844b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 370 additions and 369 deletions

View File

@ -76,8 +76,9 @@ def decimal_to_any(num: int, base: int) -> str:
div, mod = divmod(num, base) div, mod = divmod(num, base)
if base >= 11 and 9 < mod < 36: if base >= 11 and 9 < mod < 36:
actual_value = ALPHABET_VALUES[str(mod)] actual_value = ALPHABET_VALUES[str(mod)]
mod = actual_value else:
new_value += str(mod) actual_value = str(mod)
new_value += actual_value
div = num // base div = num // base
num = div num = div
if div == 0: if div == 0:

View File

@ -49,7 +49,7 @@ class LinkedList:
>>> print(linked_list) >>> print(linked_list)
9 --> 14 --> 23 9 --> 14 --> 23
""" """
if not self.is_empty: if self.is_empty():
return "" return ""
else: else:
iterate = self.head iterate = self.head

View File

@ -1,366 +1,366 @@
# An OOP approach to representing and manipulating matrices # An OOP approach to representing and manipulating matrices
from __future__ import annotations from __future__ import annotations
class Matrix: class Matrix:
""" """
Matrix object generated from a 2D array where each element is an array representing Matrix object generated from a 2D array where each element is an array representing
a row. a row.
Rows can contain type int or float. Rows can contain type int or float.
Common operations and information available. Common operations and information available.
>>> rows = [ >>> rows = [
... [1, 2, 3], ... [1, 2, 3],
... [4, 5, 6], ... [4, 5, 6],
... [7, 8, 9] ... [7, 8, 9]
... ] ... ]
>>> matrix = Matrix(rows) >>> matrix = Matrix(rows)
>>> print(matrix) >>> print(matrix)
[[1. 2. 3.] [[1. 2. 3.]
[4. 5. 6.] [4. 5. 6.]
[7. 8. 9.]] [7. 8. 9.]]
Matrix rows and columns are available as 2D arrays Matrix rows and columns are available as 2D arrays
>>> matrix.rows >>> matrix.rows
[[1, 2, 3], [4, 5, 6], [7, 8, 9]] [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> matrix.columns() >>> matrix.columns()
[[1, 4, 7], [2, 5, 8], [3, 6, 9]] [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
Order is returned as a tuple Order is returned as a tuple
>>> matrix.order >>> matrix.order
(3, 3) (3, 3)
Squareness and invertability are represented as bool Squareness and invertability are represented as bool
>>> matrix.is_square >>> matrix.is_square
True True
>>> matrix.is_invertable() >>> matrix.is_invertable()
False False
Identity, Minors, Cofactors and Adjugate are returned as Matrices. Inverse can be Identity, Minors, Cofactors and Adjugate are returned as Matrices. Inverse can be
a Matrix or Nonetype a Matrix or Nonetype
>>> print(matrix.identity()) >>> print(matrix.identity())
[[1. 0. 0.] [[1. 0. 0.]
[0. 1. 0.] [0. 1. 0.]
[0. 0. 1.]] [0. 0. 1.]]
>>> print(matrix.minors()) >>> print(matrix.minors())
[[-3. -6. -3.] [[-3. -6. -3.]
[-6. -12. -6.] [-6. -12. -6.]
[-3. -6. -3.]] [-3. -6. -3.]]
>>> print(matrix.cofactors()) >>> print(matrix.cofactors())
[[-3. 6. -3.] [[-3. 6. -3.]
[6. -12. 6.] [6. -12. 6.]
[-3. 6. -3.]] [-3. 6. -3.]]
>>> # won't be apparent due to the nature of the cofactor matrix >>> # won't be apparent due to the nature of the cofactor matrix
>>> print(matrix.adjugate()) >>> print(matrix.adjugate())
[[-3. 6. -3.] [[-3. 6. -3.]
[6. -12. 6.] [6. -12. 6.]
[-3. 6. -3.]] [-3. 6. -3.]]
>>> matrix.inverse() >>> matrix.inverse()
Traceback (most recent call last): Traceback (most recent call last):
... ...
TypeError: Only matrices with a non-zero determinant have an inverse TypeError: Only matrices with a non-zero determinant have an inverse
Determinant is an int, float, or Nonetype Determinant is an int, float, or Nonetype
>>> matrix.determinant() >>> matrix.determinant()
0 0
Negation, scalar multiplication, addition, subtraction, multiplication and Negation, scalar multiplication, addition, subtraction, multiplication and
exponentiation are available and all return a Matrix exponentiation are available and all return a Matrix
>>> print(-matrix) >>> print(-matrix)
[[-1. -2. -3.] [[-1. -2. -3.]
[-4. -5. -6.] [-4. -5. -6.]
[-7. -8. -9.]] [-7. -8. -9.]]
>>> matrix2 = matrix * 3 >>> matrix2 = matrix * 3
>>> print(matrix2) >>> print(matrix2)
[[3. 6. 9.] [[3. 6. 9.]
[12. 15. 18.] [12. 15. 18.]
[21. 24. 27.]] [21. 24. 27.]]
>>> print(matrix + matrix2) >>> print(matrix + matrix2)
[[4. 8. 12.] [[4. 8. 12.]
[16. 20. 24.] [16. 20. 24.]
[28. 32. 36.]] [28. 32. 36.]]
>>> print(matrix - matrix2) >>> print(matrix - matrix2)
[[-2. -4. -6.] [[-2. -4. -6.]
[-8. -10. -12.] [-8. -10. -12.]
[-14. -16. -18.]] [-14. -16. -18.]]
>>> print(matrix ** 3) >>> print(matrix ** 3)
[[468. 576. 684.] [[468. 576. 684.]
[1062. 1305. 1548.] [1062. 1305. 1548.]
[1656. 2034. 2412.]] [1656. 2034. 2412.]]
Matrices can also be modified Matrices can also be modified
>>> matrix.add_row([10, 11, 12]) >>> matrix.add_row([10, 11, 12])
>>> print(matrix) >>> print(matrix)
[[1. 2. 3.] [[1. 2. 3.]
[4. 5. 6.] [4. 5. 6.]
[7. 8. 9.] [7. 8. 9.]
[10. 11. 12.]] [10. 11. 12.]]
>>> matrix2.add_column([8, 16, 32]) >>> matrix2.add_column([8, 16, 32])
>>> print(matrix2) >>> print(matrix2)
[[3. 6. 9. 8.] [[3. 6. 9. 8.]
[12. 15. 18. 16.] [12. 15. 18. 16.]
[21. 24. 27. 32.]] [21. 24. 27. 32.]]
>>> print(matrix * matrix2) >>> print(matrix * matrix2)
[[90. 108. 126. 136.] [[90. 108. 126. 136.]
[198. 243. 288. 304.] [198. 243. 288. 304.]
[306. 378. 450. 472.] [306. 378. 450. 472.]
[414. 513. 612. 640.]] [414. 513. 612. 640.]]
""" """
def __init__(self, rows: list[list[int]]): def __init__(self, rows: list[list[int]]):
error = TypeError( error = TypeError(
"Matrices must be formed from a list of zero or more lists containing at " "Matrices must be formed from a list of zero or more lists containing at "
"least one and the same number of values, each of which must be of type " "least one and the same number of values, each of which must be of type "
"int or float." "int or float."
) )
if len(rows) != 0: if len(rows) != 0:
cols = len(rows[0]) cols = len(rows[0])
if cols == 0: if cols == 0:
raise error raise error
for row in rows: for row in rows:
if len(row) != cols: if len(row) != cols:
raise error raise error
for value in row: for value in row:
if not isinstance(value, (int, float)): if not isinstance(value, (int, float)):
raise error raise error
self.rows = rows self.rows = rows
else: else:
self.rows = [] self.rows = []
# MATRIX INFORMATION # MATRIX INFORMATION
def columns(self) -> list[list[int]]: def columns(self) -> list[list[int]]:
return [[row[i] for row in self.rows] for i in range(len(self.rows[0]))] return [[row[i] for row in self.rows] for i in range(len(self.rows[0]))]
@property @property
def num_rows(self) -> int: def num_rows(self) -> int:
return len(self.rows) return len(self.rows)
@property @property
def num_columns(self) -> int: def num_columns(self) -> int:
return len(self.rows[0]) return len(self.rows[0])
@property @property
def order(self) -> tuple[int, int]: def order(self) -> tuple[int, int]:
return (self.num_rows, self.num_columns) return (self.num_rows, self.num_columns)
@property @property
def is_square(self) -> bool: def is_square(self) -> bool:
return self.order[0] == self.order[1] return self.order[0] == self.order[1]
def identity(self) -> Matrix: def identity(self) -> Matrix:
values = [ values = [
[0 if column_num != row_num else 1 for column_num in range(self.num_rows)] [0 if column_num != row_num else 1 for column_num in range(self.num_rows)]
for row_num in range(self.num_rows) for row_num in range(self.num_rows)
] ]
return Matrix(values) return Matrix(values)
def determinant(self) -> int: def determinant(self) -> int:
if not self.is_square: if not self.is_square:
return 0 return 0
if self.order == (0, 0): if self.order == (0, 0):
return 1 return 1
if self.order == (1, 1): if self.order == (1, 1):
return int(self.rows[0][0]) return int(self.rows[0][0])
if self.order == (2, 2): if self.order == (2, 2):
return int( return int(
(self.rows[0][0] * self.rows[1][1]) (self.rows[0][0] * self.rows[1][1])
- (self.rows[0][1] * self.rows[1][0]) - (self.rows[0][1] * self.rows[1][0])
) )
else: else:
return sum( return sum(
self.rows[0][column] * self.cofactors().rows[0][column] self.rows[0][column] * self.cofactors().rows[0][column]
for column in range(self.num_columns) for column in range(self.num_columns)
) )
def is_invertable(self) -> bool: def is_invertable(self) -> bool:
return bool(self.determinant()) return bool(self.determinant())
def get_minor(self, row: int, column: int) -> int: def get_minor(self, row: int, column: int) -> int:
values = [ values = [
[ [
self.rows[other_row][other_column] self.rows[other_row][other_column]
for other_column in range(self.num_columns) for other_column in range(self.num_columns)
if other_column != column if other_column != column
] ]
for other_row in range(self.num_rows) for other_row in range(self.num_rows)
if other_row != row if other_row != row
] ]
return Matrix(values).determinant() return Matrix(values).determinant()
def get_cofactor(self, row: int, column: int) -> int: def get_cofactor(self, row: int, column: int) -> int:
if (row + column) % 2 == 0: if (row + column) % 2 == 0:
return self.get_minor(row, column) return self.get_minor(row, column)
return -1 * self.get_minor(row, column) return -1 * self.get_minor(row, column)
def minors(self) -> Matrix: def minors(self) -> Matrix:
return Matrix( return Matrix(
[ [
[self.get_minor(row, column) for column in range(self.num_columns)] [self.get_minor(row, column) for column in range(self.num_columns)]
for row in range(self.num_rows) for row in range(self.num_rows)
] ]
) )
def cofactors(self) -> Matrix: def cofactors(self) -> Matrix:
return Matrix( return Matrix(
[ [
[ [
self.minors().rows[row][column] self.minors().rows[row][column]
if (row + column) % 2 == 0 if (row + column) % 2 == 0
else self.minors().rows[row][column] * -1 else self.minors().rows[row][column] * -1
for column in range(self.minors().num_columns) for column in range(self.minors().num_columns)
] ]
for row in range(self.minors().num_rows) for row in range(self.minors().num_rows)
] ]
) )
def adjugate(self) -> Matrix: def adjugate(self) -> Matrix:
values = [ values = [
[self.cofactors().rows[column][row] for column in range(self.num_columns)] [self.cofactors().rows[column][row] for column in range(self.num_columns)]
for row in range(self.num_rows) for row in range(self.num_rows)
] ]
return Matrix(values) return Matrix(values)
def inverse(self) -> Matrix: def inverse(self) -> Matrix:
determinant = self.determinant() determinant = self.determinant()
if not determinant: if not determinant:
raise TypeError("Only matrices with a non-zero determinant have an inverse") raise TypeError("Only matrices with a non-zero determinant have an inverse")
return self.adjugate() * (1 / determinant) return self.adjugate() * (1 / determinant)
def __repr__(self) -> str: def __repr__(self) -> str:
return str(self.rows) return str(self.rows)
def __str__(self) -> str: def __str__(self) -> str:
if self.num_rows == 0: if self.num_rows == 0:
return "[]" return "[]"
if self.num_rows == 1: if self.num_rows == 1:
return "[[" + ". ".join(str(self.rows[0])) + "]]" return "[[" + ". ".join(str(self.rows[0])) + "]]"
return ( return (
"[" "["
+ "\n ".join( + "\n ".join(
[ [
"[" + ". ".join([str(value) for value in row]) + ".]" "[" + ". ".join([str(value) for value in row]) + ".]"
for row in self.rows for row in self.rows
] ]
) )
+ "]" + "]"
) )
# MATRIX MANIPULATION # MATRIX MANIPULATION
def add_row(self, row: list[int], position: int | None = None) -> None: def add_row(self, row: list[int], position: int | None = None) -> None:
type_error = TypeError("Row must be a list containing all ints and/or floats") type_error = TypeError("Row must be a list containing all ints and/or floats")
if not isinstance(row, list): if not isinstance(row, list):
raise type_error raise type_error
for value in row: for value in row:
if not isinstance(value, (int, float)): if not isinstance(value, (int, float)):
raise type_error raise type_error
if len(row) != self.num_columns: if len(row) != self.num_columns:
raise ValueError( raise ValueError(
"Row must be equal in length to the other rows in the matrix" "Row must be equal in length to the other rows in the matrix"
) )
if position is None: if position is None:
self.rows.append(row) self.rows.append(row)
else: else:
self.rows = self.rows[0:position] + [row] + self.rows[position:] self.rows = self.rows[0:position] + [row] + self.rows[position:]
def add_column(self, column: list[int], position: int | None = None) -> None: def add_column(self, column: list[int], position: int | None = None) -> None:
type_error = TypeError( type_error = TypeError(
"Column must be a list containing all ints and/or floats" "Column must be a list containing all ints and/or floats"
) )
if not isinstance(column, list): if not isinstance(column, list):
raise type_error raise type_error
for value in column: for value in column:
if not isinstance(value, (int, float)): if not isinstance(value, (int, float)):
raise type_error raise type_error
if len(column) != self.num_rows: if len(column) != self.num_rows:
raise ValueError( raise ValueError(
"Column must be equal in length to the other columns in the matrix" "Column must be equal in length to the other columns in the matrix"
) )
if position is None: if position is None:
self.rows = [self.rows[i] + [column[i]] for i in range(self.num_rows)] self.rows = [self.rows[i] + [column[i]] for i in range(self.num_rows)]
else: else:
self.rows = [ self.rows = [
self.rows[i][0:position] + [column[i]] + self.rows[i][position:] self.rows[i][0:position] + [column[i]] + self.rows[i][position:]
for i in range(self.num_rows) for i in range(self.num_rows)
] ]
# MATRIX OPERATIONS # MATRIX OPERATIONS
def __eq__(self, other: object) -> bool: def __eq__(self, other: object) -> bool:
if not isinstance(other, Matrix): if not isinstance(other, Matrix):
return NotImplemented return NotImplemented
return self.rows == other.rows return self.rows == other.rows
def __ne__(self, other: object) -> bool: def __ne__(self, other: object) -> bool:
return not self == other return not self == other
def __neg__(self) -> Matrix: def __neg__(self) -> Matrix:
return self * -1 return self * -1
def __add__(self, other: Matrix) -> Matrix: def __add__(self, other: Matrix) -> Matrix:
if self.order != other.order: if self.order != other.order:
raise ValueError("Addition requires matrices of the same order") raise ValueError("Addition requires matrices of the same order")
return Matrix( return Matrix(
[ [
[self.rows[i][j] + other.rows[i][j] for j in range(self.num_columns)] [self.rows[i][j] + other.rows[i][j] for j in range(self.num_columns)]
for i in range(self.num_rows) for i in range(self.num_rows)
] ]
) )
def __sub__(self, other: Matrix) -> Matrix: def __sub__(self, other: Matrix) -> Matrix:
if self.order != other.order: if self.order != other.order:
raise ValueError("Subtraction requires matrices of the same order") raise ValueError("Subtraction requires matrices of the same order")
return Matrix( return Matrix(
[ [
[self.rows[i][j] - other.rows[i][j] for j in range(self.num_columns)] [self.rows[i][j] - other.rows[i][j] for j in range(self.num_columns)]
for i in range(self.num_rows) for i in range(self.num_rows)
] ]
) )
def __mul__(self, other: Matrix | int | float) -> Matrix: def __mul__(self, other: Matrix | int | float) -> Matrix:
if isinstance(other, (int, float)): if isinstance(other, (int, float)):
return Matrix( return Matrix(
[[int(element * other) for element in row] for row in self.rows] [[int(element * other) for element in row] for row in self.rows]
) )
elif isinstance(other, Matrix): elif isinstance(other, Matrix):
if self.num_columns != other.num_rows: if self.num_columns != other.num_rows:
raise ValueError( raise ValueError(
"The number of columns in the first matrix must " "The number of columns in the first matrix must "
"be equal to the number of rows in the second" "be equal to the number of rows in the second"
) )
return Matrix( return Matrix(
[ [
[Matrix.dot_product(row, column) for column in other.columns()] [Matrix.dot_product(row, column) for column in other.columns()]
for row in self.rows for row in self.rows
] ]
) )
else: else:
raise TypeError( raise TypeError(
"A Matrix can only be multiplied by an int, float, or another matrix" "A Matrix can only be multiplied by an int, float, or another matrix"
) )
def __pow__(self, other: int) -> Matrix: def __pow__(self, other: int) -> Matrix:
if not isinstance(other, int): if not isinstance(other, int):
raise TypeError("A Matrix can only be raised to the power of an int") raise TypeError("A Matrix can only be raised to the power of an int")
if not self.is_square: if not self.is_square:
raise ValueError("Only square matrices can be raised to a power") raise ValueError("Only square matrices can be raised to a power")
if other == 0: if other == 0:
return self.identity() return self.identity()
if other < 0: if other < 0:
if self.is_invertable: if self.is_invertable():
return self.inverse() ** (-other) return self.inverse() ** (-other)
raise ValueError( raise ValueError(
"Only invertable matrices can be raised to a negative power" "Only invertable matrices can be raised to a negative power"
) )
result = self result = self
for _ in range(other - 1): for _ in range(other - 1):
result *= self result *= self
return result return result
@classmethod @classmethod
def dot_product(cls, row: list[int], column: list[int]) -> int: def dot_product(cls, row: list[int], column: list[int]) -> int:
return sum(row[i] * column[i] for i in range(len(row))) return sum(row[i] * column[i] for i in range(len(row)))
if __name__ == "__main__": if __name__ == "__main__":
import doctest import doctest
doctest.testmod() doctest.testmod()