Skip to content

improved implementation - all test passing now #6973

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
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
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ repos:
- id: requirements-txt-fixer

- repo: https://github.com/psf/black
rev: 22.8.0
rev: 22.10.0
hooks:
- id: black

Expand All @@ -26,7 +26,7 @@ repos:
- --profile=black

- repo: https://github.com/asottile/pyupgrade
rev: v2.38.2
rev: v3.0.0
hooks:
- id: pyupgrade
args:
Expand All @@ -42,7 +42,7 @@ repos:
- --max-line-length=88

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.981
rev: v0.982
hooks:
- id: mypy
args:
Expand Down
1 change: 1 addition & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,7 @@
## Scheduling
* [First Come First Served](scheduling/first_come_first_served.py)
* [Highest Response Ratio Next](scheduling/highest_response_ratio_next.py)
* [Job Sequencing With Deadline](scheduling/job_sequencing_with_deadline.py)
* [Multi Level Feedback Queue](scheduling/multi_level_feedback_queue.py)
* [Non Preemptive Shortest Job First](scheduling/non_preemptive_shortest_job_first.py)
* [Round Robin](scheduling/round_robin.py)
Expand Down
140 changes: 127 additions & 13 deletions matrix/inverse_of_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]:
"""
A matrix multiplied with its inverse gives the identity matrix.
This function finds the inverse of a 2x2 matrix.
This function finds the inverse of a 2x2 and 3x3 matrix.
If the determinant of a matrix is 0, its inverse does not exist.

Sources for fixing inaccurate float arithmetic:
https://stackoverflow.com/questions/6563058/how-do-i-use-accurate-float-arithmetic-in-python
https://docs.python.org/3/library/decimal.html

Demo for 2x2
>>> inverse_of_matrix([[2, 5], [2, 0]])
[[0.0, 0.5], [0.2, -0.2]]
>>> inverse_of_matrix([[2.5, 5], [1, 2]])
Expand All @@ -25,24 +26,137 @@ def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]:
[[0.16666666666666666, -0.0625], [-0.3333333333333333, 0.25]]
>>> inverse_of_matrix([[10, 5], [3, 2.5]])
[[0.25, -0.5], [-0.3, 1.0]]

Demo for 3x3
>>> inverse_of_matrix([[2, 5, 7], [2, 0, 1], [1, 2, 3]])
[[2.0, 1.0, -5.0], [5.0, 1.0, -12.0], [-4.0, -1.0, 10.0]]
>>> inverse_of_matrix([[1, 2, 2], [1, 2, 2], [3, 2, -1]])
Traceback (most recent call last):
...
ValueError: This matrix has no inverse.
Copy link
Member

@cclauss cclauss Oct 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add some more doctests:

>>> inverse_of_matrix([])
>>> inverse_of_matrix([1])
>>> inverse_of_matrix([[], []])
>>> inverse_of_matrix([[1, 2], [3, 4], [5, 6]])
>>> inverse_of_matrix([[1, 2, 3], [4, 5, 6]])

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok sir, I am adding

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done sir


More examples:

>>> inverse_of_matrix([])
Traceback (most recent call last):
...
ValueError: Please provide a matrix of size 2x2 or 3x3.

>>> inverse_of_matrix([[],[]])
Traceback (most recent call last):
...
ValueError: Please provide a matrix of size 2x2 or 3x3.

>>> inverse_of_matrix([[1, 2], [3, 4], [5, 6]])
Traceback (most recent call last):
...
ValueError: Please provide a matrix of size 2x2 or 3x3.

>>> inverse_of_matrix([[1, 2, 1], [0,3, 4]])
Traceback (most recent call last):
...
ValueError: Please provide a matrix of size 2x2 or 3x3.

>>> inverse_of_matrix([[1, 2, 3], [7, 8, 9], [7, 8, 9]])
Traceback (most recent call last):
...
ValueError: This matrix has no inverse.

>>> inverse_of_matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]
"""

D = Decimal # An abbreviation for conciseness

# Check if the provided matrix has 2 rows and 2 columns
# since this implementation only works for 2x2 matrices
if len(matrix) != 2 or len(matrix[0]) != 2 or len(matrix[1]) != 2:
raise ValueError("Please provide a matrix of size 2x2.")
if len(matrix) == 2 and len(matrix[0]) == 2 and len(matrix[1]) == 2:
# Calculate the determinant of the matrix
determinant = D(matrix[0][0]) * D(matrix[1][1]) - D(matrix[1][0]) * D(
matrix[0][1]
)
if determinant == 0:
raise ValueError("This matrix has no inverse.")

# Creates a copy of the matrix with swapped positions of the elements
swapped_matrix = [[0.0, 0.0], [0.0, 0.0]]
swapped_matrix[0][0], swapped_matrix[1][1] = matrix[1][1], matrix[0][0]
swapped_matrix[1][0], swapped_matrix[0][1] = -matrix[1][0], -matrix[0][1]

# Calculate the inverse of the matrix
return [
[float(D(n) / determinant) or 0.0 for n in row] for row in swapped_matrix
]
elif (
len(matrix) == 3
and len(matrix[0]) == 3
and len(matrix[1]) == 3
and len(matrix[2]) == 3
):
# Calculate the determinant of the matrix using Sarrus rule
determinant = (
(D(matrix[0][0]) * D(matrix[1][1]) * D(matrix[2][2]))
+ (D(matrix[0][1]) * D(matrix[1][2]) * D(matrix[2][0]))
+ (D(matrix[0][2]) * D(matrix[1][0]) * D(matrix[2][1]))
) - (
(D(matrix[0][2]) * D(matrix[1][1]) * D(matrix[2][0]))
+ (D(matrix[0][1]) * D(matrix[1][0]) * D(matrix[2][2]))
+ (D(matrix[0][0]) * D(matrix[1][2]) * D(matrix[2][1]))
)
if determinant == 0:
raise ValueError("This matrix has no inverse.")

# Creating cofactor matrix
cofactor_matrix = [
[D(0.0), D(0.0), D(0.0)],
[D(0.0), D(0.0), D(0.0)],
[D(0.0), D(0.0), D(0.0)],
]
cofactor_matrix[0][0] = (D(matrix[1][1]) * D(matrix[2][2])) - (
D(matrix[1][2]) * D(matrix[2][1])
)
cofactor_matrix[0][1] = -(
(D(matrix[1][0]) * D(matrix[2][2])) - (D(matrix[1][2]) * D(matrix[2][0]))
)
cofactor_matrix[0][2] = (D(matrix[1][0]) * D(matrix[2][1])) - (
D(matrix[1][1]) * D(matrix[2][0])
)
cofactor_matrix[1][0] = -(
(D(matrix[0][1]) * D(matrix[2][2])) - (D(matrix[0][2]) * D(matrix[2][1]))
)
cofactor_matrix[1][1] = (D(matrix[0][0]) * D(matrix[2][2])) - (
D(matrix[0][2]) * D(matrix[2][0])
)
cofactor_matrix[1][2] = -(
(D(matrix[0][0]) * D(matrix[2][1])) - (D(matrix[0][1]) * D(matrix[2][0]))
)
cofactor_matrix[2][0] = (D(matrix[0][1]) * D(matrix[1][2])) - (
D(matrix[0][2]) * D(matrix[1][1])
)
cofactor_matrix[2][1] = -(
(D(matrix[0][0]) * D(matrix[1][2])) - (D(matrix[0][2]) * D(matrix[1][0]))
)
cofactor_matrix[2][2] = (D(matrix[0][0]) * D(matrix[1][1])) - (
D(matrix[0][1]) * D(matrix[1][0])
)

# Calculate the determinant of the matrix
determinant = D(matrix[0][0]) * D(matrix[1][1]) - D(matrix[1][0]) * D(matrix[0][1])
if determinant == 0:
raise ValueError("This matrix has no inverse.")
# Transpose the cofactor matrix (Adjoint matrix)
adjoint_matrix = [
[D(0.0), D(0.0), D(0.0)],
[D(0.0), D(0.0), D(0.0)],
[D(0.0), D(0.0), D(0.0)],
]
for i in range(3):
for j in range(3):
adjoint_matrix[i][j] = cofactor_matrix[j][i]

# Creates a copy of the matrix with swapped positions of the elements
swapped_matrix = [[0.0, 0.0], [0.0, 0.0]]
swapped_matrix[0][0], swapped_matrix[1][1] = matrix[1][1], matrix[0][0]
swapped_matrix[1][0], swapped_matrix[0][1] = -matrix[1][0], -matrix[0][1]
# Inverse of the matrix using the formula (1/determinant) * adjoint matrix
inverse_matrix = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
for i in range(3):
for j in range(3):
inverse_matrix[i][j] = float(adjoint_matrix[i][j]) / float(determinant)

# Calculate the inverse of the matrix
return [[float(D(n) / determinant) or 0.0 for n in row] for row in swapped_matrix]
# Calculate the inverse of the matrix
return [[float(D(n)) or 0.0 for n in row] for row in inverse_matrix]
else:
raise ValueError("Please provide a matrix of size 2x2 or 3x3.")