Skip to content

Commit 24ed3c6

Browse files
perf(matrix-calc): optimize determinant calculation to O(n^3) using Gaussian Elimination (steam-bell-92#733)
1 parent 7471761 commit 24ed3c6

2 files changed

Lines changed: 121 additions & 5 deletions

File tree

math/Matrix-Calculator/Matrix-Calculator.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,13 +167,36 @@ def calculate_inverse(matrix):
167167
matrix.append(row)
168168

169169
def determinant(m):
170-
if len(m) == 1:
170+
n = len(m)
171+
if n == 1:
171172
return m[0][0]
172-
if len(m) == 2:
173+
if n == 2:
173174
return m[0][0] * m[1][1] - m[0][1] * m[1][0]
174-
det = 0
175-
for c in range(len(m)):
176-
det += ((-1)**c) * m[0][c] * determinant([row[:c] + row[c+1:] for row in m[1:]])
175+
176+
mat = [row[:] for row in m]
177+
det = 1.0
178+
179+
for i in range(n):
180+
pivot_row = i
181+
while pivot_row < n and abs(mat[pivot_row][i]) < 1e-9:
182+
pivot_row += 1
183+
184+
if pivot_row == n:
185+
return 0.0
186+
187+
if pivot_row != i:
188+
mat[i], mat[pivot_row] = mat[pivot_row], mat[i]
189+
det *= -1.0
190+
191+
pivot_val = mat[i][i]
192+
for r in range(i + 1, n):
193+
factor = mat[r][i] / pivot_val
194+
for c in range(i, n):
195+
mat[r][c] -= factor * mat[i][c]
196+
197+
for i in range(n):
198+
det *= mat[i][i]
199+
177200
return det
178201

179202
det_value = determinant(matrix)

tests/test_matrix_calculator.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import unittest
2+
import subprocess
3+
import os
4+
import sys
5+
6+
class TestMatrixCalculator(unittest.TestCase):
7+
def setUp(self):
8+
self.script_path = os.path.join("math", "Matrix-Calculator", "Matrix-Calculator.py")
9+
10+
def run_script_with_input(self, user_input):
11+
process = subprocess.Popen(
12+
[sys.executable, self.script_path],
13+
stdin=subprocess.PIPE,
14+
stdout=subprocess.PIPE,
15+
stderr=subprocess.PIPE,
16+
text=True
17+
)
18+
stdout, stderr = process.communicate(input=user_input)
19+
return stdout, stderr
20+
21+
def test_addition(self):
22+
# Add two 2x2 matrices
23+
# Matrix 1: [[1, 2], [3, 4]]
24+
# Matrix 2: [[5, 6], [7, 8]]
25+
# Expected Result: [[6.00, 8.00], [10.00, 12.00]]
26+
user_input = "A\n2\n2\n1 2\n3 4\n5 6\n7 8\nQ\n"
27+
stdout, _ = self.run_script_with_input(user_input)
28+
self.assertIn("6.00\t8.00", stdout)
29+
self.assertIn("10.00\t12.00", stdout)
30+
31+
def test_subtraction(self):
32+
# Subtract two 2x2 matrices
33+
user_input = "S\n2\n2\n5 6\n7 8\n1 2\n3 4\nQ\n"
34+
stdout, _ = self.run_script_with_input(user_input)
35+
self.assertIn("4.00\t4.00", stdout)
36+
self.assertIn("4.00\t4.00", stdout)
37+
38+
def test_multiplication(self):
39+
# Multiply 2x3 by 3x2 matrix
40+
# Matrix 1: [[1, 2, 3], [4, 5, 6]] (2x3)
41+
# Matrix 2: [[7, 8], [9, 1], [2, 3]] (3x2)
42+
# Expected: [[31.00, 19.00], [85.00, 55.00]]
43+
user_input = "M\n2\n3\n1 2 3\n4 5 6\n3\n2\n7 8\n9 1\n2 3\nQ\n"
44+
stdout, _ = self.run_script_with_input(user_input)
45+
self.assertIn("31.00\t19.00", stdout)
46+
self.assertIn("85.00\t55.00", stdout)
47+
48+
def test_transpose(self):
49+
# Transpose a 2x3 matrix
50+
# Matrix: [[1, 2, 3], [4, 5, 6]]
51+
# Expected: [[1.00, 4.00], [2.00, 5.00], [3.00, 6.00]]
52+
user_input = "T\n2\n3\n1 2 3\n4 5 6\nQ\n"
53+
stdout, _ = self.run_script_with_input(user_input)
54+
self.assertIn("1.00\t4.00", stdout)
55+
self.assertIn("2.00\t5.00", stdout)
56+
self.assertIn("3.00\t6.00", stdout)
57+
58+
def test_determinant_3x3(self):
59+
# Determinant of 3x3 matrix
60+
# Matrix: [[1, 2, 3], [0, 4, 5], [1, 0, 6]]
61+
# Expected Det: 1*(24) - 2*(-5) + 3*(-4) = 24 + 10 - 12 = 22
62+
user_input = "D\n3\n1 2 3\n0 4 5\n1 0 6\nQ\n"
63+
stdout, _ = self.run_script_with_input(user_input)
64+
self.assertIn("Determinant: 22.00", stdout)
65+
66+
def test_determinant_with_row_swap(self):
67+
# Determinant of a matrix that requires row swapping during pivot selection
68+
# Matrix: [[0, 1], [1, 2]]
69+
# Expected: -1
70+
user_input = "D\n2\n0 1\n1 2\nQ\n"
71+
stdout, _ = self.run_script_with_input(user_input)
72+
self.assertIn("Determinant: -1.00", stdout)
73+
74+
def test_rank(self):
75+
# Rank of a 3x3 matrix (linearly dependent)
76+
# Matrix: [[1, 2, 3], [2, 4, 6], [1, 0, 1]]
77+
# Expected Rank: 2
78+
user_input = "R\n3\n3\n1 2 3\n2 4 6\n1 0 1\nQ\n"
79+
stdout, _ = self.run_script_with_input(user_input)
80+
self.assertIn("Rank of the Matrix: 2", stdout)
81+
82+
def test_inverse(self):
83+
# Inverse of a 2x2 matrix
84+
# Matrix: [[4, 7], [2, 6]]
85+
# Det = 24 - 14 = 10
86+
# Expected: [[0.6, -0.7], [-0.2, 0.4]]
87+
user_input = "I\n2\n4 7\n2 6\nQ\n"
88+
stdout, _ = self.run_script_with_input(user_input)
89+
self.assertIn("0.60\t-0.70", stdout)
90+
self.assertIn("-0.20\t0.40", stdout)
91+
92+
if __name__ == "__main__":
93+
unittest.main()

0 commit comments

Comments
 (0)