Skip to content

Commit 249e64e

Browse files
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
1 parent b371553 commit 249e64e

File tree

1 file changed

+36
-34
lines changed

1 file changed

+36
-34
lines changed

linear_algebra/determinant.py

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
def 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

6565
def 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

126126
def 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:
156156
def 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

193195
if __name__ == "__main__":
194196
import doctest
195-
197+
196198
doctest.testmod()
197199
test_determinant()

0 commit comments

Comments
 (0)