From 90b90e5d7c7d343a0b49e15c37f2345d5029f808 Mon Sep 17 00:00:00 2001 From: karthik Date: Mon, 17 Oct 2022 18:39:46 +0530 Subject: [PATCH 1/5] added support for inverse of 3x3 matrix --- matrix/inverse_of_matrix.py | 142 ++++++++++++++++++++++++++++++++---- 1 file changed, 128 insertions(+), 14 deletions(-) diff --git a/matrix/inverse_of_matrix.py b/matrix/inverse_of_matrix.py index 770ce39b584f..39e377dc2c99 100644 --- a/matrix/inverse_of_matrix.py +++ b/matrix/inverse_of_matrix.py @@ -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]]) @@ -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. + + 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 + d = Decimal # 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.") From 66f3247f6c6ccdcb6668643b710dcbdfb9682bef Mon Sep 17 00:00:00 2001 From: karthik Date: Sat, 22 Oct 2022 08:27:48 +0530 Subject: [PATCH 2/5] Modified Docstring and improved code --- matrix/inverse_of_matrix.py | 51 +++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/matrix/inverse_of_matrix.py b/matrix/inverse_of_matrix.py index 39e377dc2c99..27b5ab58e9e8 100644 --- a/matrix/inverse_of_matrix.py +++ b/matrix/inverse_of_matrix.py @@ -2,6 +2,8 @@ from decimal import Decimal +from numpy import array + def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]: """ @@ -18,7 +20,7 @@ def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]: [[0.0, 0.5], [0.2, -0.2]] >>> inverse_of_matrix([[2.5, 5], [1, 2]]) Traceback (most recent call last): - ... + ... ValueError: This matrix has no inverse. >>> inverse_of_matrix([[12, -16], [-9, 0]]) [[0.0, -0.1111111111111111], [-0.0625, -0.08333333333333333]] @@ -32,34 +34,34 @@ def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]: [[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. 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]]) @@ -72,8 +74,8 @@ def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]: # since this implementation only works for 2x2 matrices 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] + determinant = float( + 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.") @@ -85,7 +87,7 @@ def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]: # Calculate the inverse of the matrix return [ - [float(d(n) / determinant) or 0.0 for n in row] for row in swapped_matrix + [(float(d(n)) / determinant) or 0.0 for n in row] for row in swapped_matrix ] elif ( len(matrix) == 3 @@ -94,14 +96,17 @@ def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]: 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])) + determinant = float( + ( + (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.") @@ -141,20 +146,16 @@ def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]: ) # 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)], - ] + adjoint_matrix = array(cofactor_matrix) for i in range(3): for j in range(3): adjoint_matrix[i][j] = cofactor_matrix[j][i] # 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]] + inverse_matrix = array(cofactor_matrix) for i in range(3): for j in range(3): - inverse_matrix[i][j] = float(adjoint_matrix[i][j]) / float(determinant) + inverse_matrix[i][j] /= determinant # Calculate the inverse of the matrix return [[float(d(n)) or 0.0 for n in row] for row in inverse_matrix] From 10d392c4b0adca768153acab18a7b579984e9143 Mon Sep 17 00:00:00 2001 From: karthik Date: Sat, 22 Oct 2022 09:08:05 +0530 Subject: [PATCH 3/5] fixed an error --- matrix/inverse_of_matrix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/inverse_of_matrix.py b/matrix/inverse_of_matrix.py index 27b5ab58e9e8..b0cd26b3490e 100644 --- a/matrix/inverse_of_matrix.py +++ b/matrix/inverse_of_matrix.py @@ -155,7 +155,7 @@ def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]: inverse_matrix = array(cofactor_matrix) for i in range(3): for j in range(3): - inverse_matrix[i][j] /= determinant + inverse_matrix[i][j] /= d(determinant) # Calculate the inverse of the matrix return [[float(d(n)) or 0.0 for n in row] for row in inverse_matrix] From fcb10e9ca4a8356a4be296639a7498fcbc76420f Mon Sep 17 00:00:00 2001 From: karthik Date: Sat, 22 Oct 2022 09:19:15 +0530 Subject: [PATCH 4/5] Modified docstring --- matrix/inverse_of_matrix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/inverse_of_matrix.py b/matrix/inverse_of_matrix.py index b0cd26b3490e..e90a99cce0dd 100644 --- a/matrix/inverse_of_matrix.py +++ b/matrix/inverse_of_matrix.py @@ -31,7 +31,7 @@ def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]: 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]] + [[2.0, 5.0, -4.0], [1.0, 1.0, -1.0], [-5.0, -12.0, 10.0]] >>> inverse_of_matrix([[1, 2, 2], [1, 2, 2], [3, 2, -1]]) Traceback (most recent call last): ... From 81658e1a725454e40ebb503f37c94b415af2cc6c Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 26 Oct 2022 10:33:51 +0200 Subject: [PATCH 5/5] Apply all suggestions from code review Co-authored-by: Caeden Perelli-Harris Co-authored-by: Chris O <46587501+ChrisO345@users.noreply.github.com> --- matrix/inverse_of_matrix.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/matrix/inverse_of_matrix.py b/matrix/inverse_of_matrix.py index e90a99cce0dd..e53d90df8253 100644 --- a/matrix/inverse_of_matrix.py +++ b/matrix/inverse_of_matrix.py @@ -15,7 +15,7 @@ def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]: 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 + Doctests 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]]) @@ -29,7 +29,7 @@ def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]: >>> inverse_of_matrix([[10, 5], [3, 2.5]]) [[0.25, -0.5], [-0.3, 1.0]] - Demo for 3x3 + Doctests for 3x3 >>> inverse_of_matrix([[2, 5, 7], [2, 0, 1], [1, 2, 3]]) [[2.0, 5.0, -4.0], [1.0, 1.0, -1.0], [-5.0, -12.0, 10.0]] >>> inverse_of_matrix([[1, 2, 2], [1, 2, 2], [3, 2, -1]]) @@ -37,13 +37,6 @@ def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]: ... ValueError: This matrix has no inverse. - 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): ... @@ -159,5 +152,4 @@ def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]: # 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.") + raise ValueError("Please provide a matrix of size 2x2 or 3x3.")