1515def determinant_recursive (matrix : NDArray [float64 ]) -> float :
1616 """
1717 Calculate the determinant of a square matrix using recursive cofactor expansion.
18-
18+
1919 This method is suitable for small matrices but becomes inefficient for large matrices.
2020
2121 Parameters:
@@ -39,33 +39,33 @@ def determinant_recursive(matrix: NDArray[float64]) -> float:
3939 """
4040 if matrix .shape [0 ] != matrix .shape [1 ]:
4141 raise ValueError ("Matrix must be square" )
42-
42+
4343 n = matrix .shape [0 ]
44-
44+
4545 # Base cases
4646 if n == 1 :
4747 return float (matrix [0 , 0 ])
48-
48+
4949 if n == 2 :
5050 return float (matrix [0 , 0 ] * matrix [1 , 1 ] - matrix [0 , 1 ] * matrix [1 , 0 ])
51-
51+
5252 # Recursive case: cofactor expansion along the first row
5353 det = 0.0
5454 for col in range (n ):
5555 # Create submatrix by removing row 0 and column col
5656 submatrix = np .delete (np .delete (matrix , 0 , axis = 0 ), col , axis = 1 )
57-
57+
5858 # Calculate cofactor
5959 cofactor = ((- 1 ) ** col ) * matrix [0 , col ] * determinant_recursive (submatrix )
6060 det += cofactor
61-
61+
6262 return det
6363
6464
6565def determinant_lu (matrix : NDArray [float64 ]) -> float :
6666 """
6767 Calculate the determinant using LU decomposition.
68-
68+
6969 This method is more efficient for larger matrices than recursive expansion.
7070
7171 Parameters:
@@ -79,54 +79,54 @@ def determinant_lu(matrix: NDArray[float64]) -> float:
7979 """
8080 if matrix .shape [0 ] != matrix .shape [1 ]:
8181 raise ValueError ("Matrix must be square" )
82-
82+
8383 n = matrix .shape [0 ]
84-
84+
8585 # Create a copy to avoid modifying the original matrix
8686 A = matrix .astype (float64 , copy = True )
87-
87+
8888 # Keep track of row swaps for sign adjustment
8989 swap_count = 0
90-
90+
9191 # Forward elimination to get upper triangular matrix
9292 for i in range (n ):
9393 # Find pivot
9494 max_row = i
9595 for k in range (i + 1 , n ):
9696 if abs (A [k , i ]) > abs (A [max_row , i ]):
9797 max_row = k
98-
98+
9999 # Swap rows if needed
100100 if max_row != i :
101101 A [[i , max_row ]] = A [[max_row , i ]]
102102 swap_count += 1
103-
103+
104104 # Check for singular matrix
105105 if abs (A [i , i ]) < 1e-14 :
106106 return 0.0
107-
107+
108108 # Eliminate below pivot
109109 for k in range (i + 1 , n ):
110110 factor = A [k , i ] / A [i , i ]
111111 for j in range (i , n ):
112112 A [k , j ] -= factor * A [i , j ]
113-
113+
114114 # Calculate determinant as product of diagonal elements
115115 det = 1.0
116116 for i in range (n ):
117117 det *= A [i , i ]
118-
118+
119119 # Adjust sign based on number of row swaps
120120 if swap_count % 2 == 1 :
121121 det = - det
122-
122+
123123 return det
124124
125125
126126def determinant (matrix : NDArray [float64 ]) -> float :
127127 """
128128 Calculate the determinant of a square matrix using the most appropriate method.
129-
129+
130130 Uses recursive expansion for small matrices (≤3x3) and LU decomposition for larger ones.
131131
132132 Parameters:
@@ -143,9 +143,9 @@ def determinant(matrix: NDArray[float64]) -> float:
143143 """
144144 if matrix .shape [0 ] != matrix .shape [1 ]:
145145 raise ValueError ("Matrix must be square" )
146-
146+
147147 n = matrix .shape [0 ]
148-
148+
149149 # Use recursive method for small matrices, LU decomposition for larger ones
150150 if n <= 3 :
151151 return determinant_recursive (matrix )
@@ -156,42 +156,44 @@ def determinant(matrix: NDArray[float64]) -> float:
156156def test_determinant () -> None :
157157 """
158158 Test function for matrix determinant calculation.
159-
159+
160160 >>> test_determinant() # self running tests
161161 """
162162 # Test 1: 2x2 matrix
163163 matrix_2x2 = np .array ([[1.0 , 2.0 ], [3.0 , 4.0 ]], dtype = float )
164164 det_2x2 = determinant (matrix_2x2 )
165165 assert abs (det_2x2 - (- 2.0 )) < 1e-10 , "2x2 determinant calculation failed"
166-
166+
167167 # Test 2: 3x3 matrix
168- matrix_3x3 = np .array ([[ 2.0 , - 3.0 , 1.0 ],
169- [2.0 , 0.0 , - 1.0 ],
170- [ 1.0 , 4.0 , 5.0 ]], dtype = float )
168+ matrix_3x3 = np .array (
169+ [[ 2.0 , - 3.0 , 1.0 ], [2.0 , 0.0 , - 1.0 ], [ 1.0 , 4.0 , 5.0 ]], dtype = float
170+ )
171171 det_3x3 = determinant (matrix_3x3 )
172172 assert abs (det_3x3 - 49.0 ) < 1e-10 , "3x3 determinant calculation failed"
173-
173+
174174 # Test 3: Singular matrix
175175 singular_matrix = np .array ([[1.0 , 2.0 ], [2.0 , 4.0 ]], dtype = float )
176176 det_singular = determinant (singular_matrix )
177177 assert abs (det_singular ) < 1e-10 , "Singular matrix should have zero determinant"
178-
178+
179179 # Test 4: Identity matrix
180180 identity_3x3 = np .eye (3 , dtype = float )
181181 det_identity = determinant (identity_3x3 )
182182 assert abs (det_identity - 1.0 ) < 1e-10 , "Identity matrix should have determinant 1"
183-
183+
184184 # Test 5: Compare recursive and LU methods
185- test_matrix = np .array ([[ 1.0 , 2.0 , 3.0 ],
186- [0.0 , 1.0 , 4.0 ],
187- [ 5.0 , 6.0 , 0.0 ]], dtype = float )
185+ test_matrix = np .array (
186+ [[ 1.0 , 2.0 , 3.0 ], [0.0 , 1.0 , 4.0 ], [ 5.0 , 6.0 , 0.0 ]], dtype = float
187+ )
188188 det_recursive = determinant_recursive (test_matrix )
189189 det_lu = determinant_lu (test_matrix )
190- assert abs (det_recursive - det_lu ) < 1e-10 , "Recursive and LU methods should give same result"
190+ assert abs (det_recursive - det_lu ) < 1e-10 , (
191+ "Recursive and LU methods should give same result"
192+ )
191193
192194
193195if __name__ == "__main__" :
194196 import doctest
195-
197+
196198 doctest .testmod ()
197199 test_determinant ()
0 commit comments