-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_solver.py
More file actions
145 lines (126 loc) · 5 KB
/
Copy pathtest_solver.py
File metadata and controls
145 lines (126 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
"""
test_solver.py
Comprehensive test suite for linear_solver module.
Tests cover:
- Rank computation (full rank, rank-deficient, tolerance)
- System analysis (all three types)
- Solver outputs (unique solutions, None for inconsistent, minimum-norm for infinite)
- Condition number (well-conditioned, ill-conditioned)
- Verification: solutions satisfy the original equations
"""
import numpy as np
from linear_solver import (
compute_rank,
compute_condition_number,
analyze_system,
solve_linear_system,
)
def test_rank_full_rank():
"""Full-rank 2x2 matrix should have rank 2."""
A = np.array([[1, 2], [3, 4]], dtype=float)
assert compute_rank(A) == 2, "DFull-rank 2x2 should have rank 2"
print("✓ rank: full-rank 2x2 = 2")
def test_rank_rank_deficient():
"""Linearly dependent rows: rank should be 1."""
A = np.array([[1, 2], [2, 4]], dtype=float) # row2 = 2*row1
assert compute_rank(A) == 1, "Rank-deficient 2x2 should have rank 1"
print("✓ rank: rank-deficient matrix = 1")
def test_rank_zero_matrix():
"""Zero matrix has rank 0."""
Z = np.zeros((3, 4))
assert compute_rank(Z) == 0, "Zero matrix should have rank 0"
print("✓ rank: zero matrix = 0")
def test_rank_tall_matrix():
"""More rows than columns: max rank = n (columns)."""
A = np.array([[1, 0], [0, 1], [1, 1]], dtype=float)
assert compute_rank(A) == 2, "3x2 full-column-rank should be 2"
print("✓ rank: tall full-column-rank matrix = 2")
def test_analyze_unique():
"""Full-rank square system -> unique type."""
A = np.array([[2, 1], [1, 3]], dtype=float)
b = np.array([5, 7], dtype=float)
result = analyze_system(A, b)
assert result['system_type'] == 'unique', (
f"Expected unique, got {result['system_type']}"
)
print("✓ analyze: full-rank square → unique")
def test_analyze_inconsistent():
"""Singular A with contradictory b -> inconsistent type."""
A = np.array([[1, 2], [2, 4]], dtype=float)
b = np.array([3, 5], dtype=float) # 5 ≠ 2*3
result = analyze_system(A, b)
assert result['system_type'] == 'inconsistent', (
f"Expected inconsistent, got {result['system_type']}"
)
print("✓ analyze: singular A, contradictory b → inconsistent")
def test_analyze_infinite():
"""Underdetermined consistent system -> infinite type."""
A = np.array([[1, 2, 1], [2, 4, 3]], dtype=float)
b = np.array([5, 11], dtype=float)
result = analyze_system(A, b)
assert result['system_type'] == 'infinite', (
f"Expected infinite, got {result['system_type']}"
)
print("✓ analyze: underdetermined consistent → infinite")
def test_solve_unique_and_verify():
"""Unique system: solution must satisfy A @ x = b"""
A = np.array([[2, 1], [1, 3]], dtype=float)
b = np.array([5, 7], dtype=float)
x = solve_linear_system(A, b, verbose=False)
assert x is not None, "Should return a solution"
assert np.allclose(A @ x, b, atol=1e-10), (
f"Solution does not satisfy equations: A@x = {A @ x}, b = {b}"
)
print("✓ solve: unique solution satisfies A@x = b")
def test_solve_inconsistent_returns_none():
"""Inconsistent system: solver must return None."""
A = np.array([[1, 2], [2, 4]], dtype=float)
b = np.array([3, 5], dtype=float)
x = solve_linear_system(A, b, verbose=False)
assert x is None, "Inconsistent system should return None"
print(" ✓ solve: inconsistent system returns None")
def test_solve_infinite_satisfies_equations():
"""Infinite system: minimum-norm solution must satisfy A@x = b."""
A = np.array([[1, 2, 1], [2, 4, 3]], dtype=float)
b = np.array([5, 11], dtype=float)
x = solve_linear_system(A, b, verbose=False)
assert x is not None, "Should return minimum-norm solution"
assert np.allclose(A @ x, b, atol=1e-10), (
f"Minimum-norm solution does not satisfy equations"
)
print(" ✓ solve: infinite system — minimum-norm solution satisfies A@x = b")
def test_condition_number_identity():
"""Identity matrix: condition number must be 1.0."""
I = np.eye(4)
cond = compute_condition_number(I)
assert np.isclose(cond, 1.0), (
f"Identity condition number should be 1.0, got {cond}"
)
print(" ✓ condition: κ(I) = 1.0")
def test_condition_number_ill_conditioned():
"""Near-singular matrix: condition number must be very large."""
A = np.array([[1.0, 1.0 ], [1.0, 1.0 + 1e-5]], dtype=float)
cond = compute_condition_number(A)
assert cond > 1e4, (
f"Near-singular matrix should have κ > 1e4, got {cond:.2e}"
)
print(f" ✓ condition: near-singular matrix κ = {cond:.2e} > 1e4")
if __name__ == "__main__":
print("\n" + "="*60)
print(" LINEAR SOLVER TEST SUITE")
print("="*60 + "\n")
test_rank_full_rank()
test_rank_rank_deficient()
test_rank_zero_matrix()
test_rank_tall_matrix()
test_analyze_unique()
test_analyze_inconsistent()
test_analyze_infinite()
test_solve_unique_and_verify()
test_solve_inconsistent_returns_none()
test_solve_infinite_satisfies_equations()
test_condition_number_identity()
test_condition_number_ill_conditioned()
print("\n" + "="*60)
print(" ALL 12 TESTS PASSED")
print("="*60 + "\n")