NavyDevilDoc/Systems_of_Equations
0
1import numpy as np
2import sympy as sp
3from sympy import symbols, Eq, solve, Matrix
4from typing import Tuple, Dict, Any, Optional
5import matplotlib.pyplot as plt
6from fractions import Fraction
7
8class SystemSolver:
9 """
10 A class to solve systems of linear equations using multiple methods
11 for Algebra II level students.
12 """
13
14 def __init__(self):
15 self.x, self.y, self.z = symbols('x y z')
16
17 def solve_2x2_system(self, coefficients: list, constants: list, method: str = 'all') -> Dict[str, Any]:
18 """
19 Solve a 2x2 system of linear equations.
20
21 Args:
22 coefficients: [[a1, b1], [a2, b2]] for equations a1*x + b1*y = c1, a2*x + b2*y = c2
23 constants: [c1, c2]
24 method: 'graphical', 'substitution', 'elimination', 'matrix', or 'all'
25
26 Returns:
27 Dictionary containing solution and method details
28 """
29 a1, b1 = coefficients[0]
30 a2, b2 = coefficients[1]
31 c1, c2 = constants
32
33 result = {
34 'system_type': self._classify_2x2_system(coefficients, constants),
35 'coefficients': coefficients,
36 'constants': constants
37 }
38
39 if method == 'all' or method == 'matrix':
40 result['matrix_solution'] = self._solve_2x2_matrix(coefficients, constants)
41
42 if method == 'all' or method == 'elimination':
43 result['elimination_solution'] = self._solve_2x2_elimination(coefficients, constants)
44
45 if method == 'all' or method == 'substitution':
46 result['substitution_solution'] = self._solve_2x2_substitution(coefficients, constants)
47
48 if method == 'all' or method == 'graphical':
49 result['graphical_solution'] = self._solve_2x2_graphical(coefficients, constants)
50
51 return result
52
53 def solve_3x3_system(self, coefficients: list, constants: list, method: str = 'all') -> Dict[str, Any]:
54 """
55 Solve a 3x3 system of linear equations.
56
57 Args:
58 coefficients: [[a1, b1, c1], [a2, b2, c2], [a3, b3, c3]]
59 constants: [d1, d2, d3]
60 method: 'elimination', 'matrix', or 'all'
61 """
62 result = {
63 'system_type': self._classify_3x3_system(coefficients, constants),
64 'coefficients': coefficients,
65 'constants': constants
66 }
67
68 if method == 'all' or method == 'matrix':
69 result['matrix_solution'] = self._solve_3x3_matrix(coefficients, constants)
70
71 if method == 'all' or method == 'elimination':
72 result['elimination_solution'] = self._solve_3x3_elimination(coefficients, constants)
73
74 return result
75
76 def _classify_2x2_system(self, coefficients: list, constants: list) -> str:
77 """Classify the type of solution for a 2x2 system"""
78 a1, b1 = coefficients[0]
79 a2, b2 = coefficients[1]
80 c1, c2 = constants
81
82 # Calculate determinant
83 det = a1 * b2 - a2 * b1
84
85 if det != 0:
86 return "unique_solution" # Consistent independent
87 elif det == 0:
88 # Check if system is inconsistent or dependent
89 if abs(a1 * c2 - a2 * c1) < 1e-10 and abs(b1 * c2 - b2 * c1) < 1e-10:
90 return "infinite_solutions" # Consistent dependent
91 else:
92 return "no_solution" # Inconsistent
93
94 def _classify_3x3_system(self, coefficients: list, constants: list) -> str:
95 """Classify the type of solution for a 3x3 system"""
96 A = np.array(coefficients, dtype=float)
97 b = np.array(constants, dtype=float)
98
99 det_A = np.linalg.det(A)
100
101 if abs(det_A) > 1e-10:
102 return "unique_solution"
103 else:
104 # Check rank to determine if no solution or infinite solutions
105 rank_A = np.linalg.matrix_rank(A)
106 rank_Ab = np.linalg.matrix_rank(np.column_stack([A, b]))
107
108 if rank_A == rank_Ab:
109 return "infinite_solutions"
110 else:
111 return "no_solution"
112
113 def _solve_2x2_matrix(self, coefficients: list, constants: list) -> Dict[str, Any]:
114 """Solve using matrix method (Cramer's rule or inverse)"""
115 try:
116 A = np.array(coefficients, dtype=float)
117 b = np.array(constants, dtype=float)
118
119 det_A = np.linalg.det(A)
120
121 if abs(det_A) < 1e-10:
122 return {
123 'method': 'Matrix (Determinant)',
124 'steps': [
125 f"Coefficient matrix A = {A.tolist()}",
126 f"Constants vector b = {b.tolist()}",
127 f"det(A) = {det_A:.6f} ≈ 0",
128 "System has no unique solution"
129 ],
130 'solution': None,
131 'determinant': det_A
132 }
133
134 # Use Cramer's rule
135 det_x = np.linalg.det([[constants[0], coefficients[0][1]],
136 [constants[1], coefficients[1][1]]])
137 det_y = np.linalg.det([[coefficients[0][0], constants[0]],
138 [coefficients[1][0], constants[1]]])
139
140 x_val = det_x / det_A
141 y_val = det_y / det_A
142
143 return {
144 'method': 'Matrix (Cramers Rule)',
145 'steps': [
146 f"det(A) = {det_A}",
147 f"det(Ax) = {det_x} → x = {det_x}/{det_A} = {x_val}",
148 f"det(Ay) = {det_y} → y = {det_y}/{det_A} = {y_val}"
149 ],
150 'solution': {'x': x_val, 'y': y_val},
151 'determinant': det_A
152 }
153
154 except Exception as e:
155 return {'method': 'Matrix', 'error': str(e), 'solution': None}
156
157 def _solve_2x2_elimination(self, coefficients: list, constants: list) -> Dict[str, Any]:
158 """Solve using elimination method"""
159 a1, b1 = coefficients[0]
160 a2, b2 = coefficients[1]
161 c1, c2 = constants
162
163 steps = [
164 f"Original system:",
165 f" {a1}x + {b1}y = {c1} ... (1)",
166 f" {a2}x + {b2}y = {c2} ... (2)"
167 ]
168
169 # Eliminate x by multiplying equations
170 if a1 != 0 and a2 != 0:
171 mult1 = a2
172 mult2 = -a1
173
174 new_a1, new_b1, new_c1 = mult1 * a1, mult1 * b1, mult1 * c1
175 new_a2, new_b2, new_c2 = mult2 * a2, mult2 * b2, mult2 * c2
176
177 steps.extend([
178 f"Multiply equation (1) by {mult1}: {new_a1}x + {new_b1}y = {new_c1}",
179 f"Multiply equation (2) by {mult2}: {new_a2}x + {new_b2}y = {new_c2}",
180 "Add the equations:"
181 ])
182
183 final_b = new_b1 + new_b2
184 final_c = new_c1 + new_c2
185
186 if abs(final_b) < 1e-10:
187 if abs(final_c) < 1e-10:
188 return {
189 'method': 'Elimination',
190 'steps': steps + ["0 = 0 (Infinite solutions)"],
191 'solution': 'infinite'
192 }
193 else:
194 return {
195 'method': 'Elimination',
196 'steps': steps + [f"0 = {final_c} (No solution)"],
197 'solution': None
198 }
199
200 y_val = final_c / final_b
201 steps.append(f"{final_b}y = {final_c}")
202 steps.append(f"y = {y_val}")
203
204 # Back substitute
205 x_val = (c1 - b1 * y_val) / a1
206 steps.append(f"Substitute back: x = ({c1} - {b1}*{y_val})/{a1} = {x_val}")
207
208 return {
209 'method': 'Elimination',
210 'steps': steps,
211 'solution': {'x': x_val, 'y': y_val}
212 }
213
214 return {'method': 'Elimination', 'error': 'Cannot eliminate with zero coefficients'}
215
216 def _solve_2x2_substitution(self, coefficients: list, constants: list) -> Dict[str, Any]:
217 """Solve using substitution method"""
218 a1, b1 = coefficients[0]
219 a2, b2 = coefficients[1]
220 c1, c2 = constants
221
222 steps = [
223 f"Original system:",
224 f" {a1}x + {b1}y = {c1} ... (1)",
225 f" {a2}x + {b2}y = {c2} ... (2)"
226 ]
227
228 # Solve equation 1 for x (if a1 != 0) or y (if b1 != 0)
229 if abs(a1) >= abs(b1) and a1 != 0:
230 # Solve for x from equation 1
231 steps.append(f"Solve equation (1) for x:")
232 steps.append(f"x = ({c1} - {b1}y)/{a1}")
233
234 # Substitute into equation 2
235 steps.append("Substitute into equation (2):")
236 # a2*((c1 - b1*y)/a1) + b2*y = c2
237 # a2*(c1 - b1*y)/a1 + b2*y = c2
238 # a2*c1/a1 - a2*b1*y/a1 + b2*y = c2
239 # y*(b2 - a2*b1/a1) = c2 - a2*c1/a1
240
241 coeff_y = b2 - (a2 * b1) / a1
242 const_term = c2 - (a2 * c1) / a1
243
244 steps.append(f"{a2}*({c1} - {b1}y)/{a1} + {b2}y = {c2}")
245 steps.append(f"({coeff_y})y = {const_term}")
246
247 if abs(coeff_y) < 1e-10:
248 if abs(const_term) < 1e-10:
249 return {'method': 'Substitution', 'steps': steps + ["0 = 0 (Infinite solutions)"], 'solution': 'infinite'}
250 else:
251 return {'method': 'Substitution', 'steps': steps + [f"0 = {const_term} (No solution)"], 'solution': None}
252
253 y_val = const_term / coeff_y
254 x_val = (c1 - b1 * y_val) / a1
255
256 steps.append(f"y = {y_val}")
257 steps.append(f"x = ({c1} - {b1}*{y_val})/{a1} = {x_val}")
258
259 return {
260 'method': 'Substitution',
261 'steps': steps,
262 'solution': {'x': x_val, 'y': y_val}
263 }
264
265 elif b1 != 0:
266 # Solve for y from equation 1
267 steps.append(f"Solve equation (1) for y:")
268 steps.append(f"y = ({c1} - {a1}x)/{b1}")
269
270 # Substitute into equation 2
271 coeff_x = a2 - (b2 * a1) / b1
272 const_term = c2 - (b2 * c1) / b1
273
274 steps.append("Substitute into equation (2):")
275 steps.append(f"({coeff_x})x = {const_term}")
276
277 if abs(coeff_x) < 1e-10:
278 if abs(const_term) < 1e-10:
279 return {'method': 'Substitution', 'steps': steps + ["0 = 0 (Infinite solutions)"], 'solution': 'infinite'}
280 else:
281 return {'method': 'Substitution', 'steps': steps + [f"0 = {const_term} (No solution)"], 'solution': None}
282
283 x_val = const_term / coeff_x
284 y_val = (c1 - a1 * x_val) / b1
285
286 steps.append(f"x = {x_val}")
287 steps.append(f"y = ({c1} - {a1}*{x_val})/{b1} = {y_val}")
288
289 return {
290 'method': 'Substitution',
291 'steps': steps,
292 'solution': {'x': x_val, 'y': y_val}
293 }
294
295 return {'method': 'Substitution', 'error': 'Cannot solve - both coefficients are zero'}
296
297 def _solve_2x2_graphical(self, coefficients: list, constants: list) -> Dict[str, Any]:
298 """Prepare data for graphical solution"""
299 a1, b1 = coefficients[0]
300 a2, b2 = coefficients[1]
301 c1, c2 = constants
302
303 # Convert to slope-intercept form y = mx + b
304 lines = []
305
306 if b1 != 0:
307 slope1 = -a1 / b1
308 intercept1 = c1 / b1
309 lines.append({
310 'slope': slope1,
311 'y_intercept': intercept1,
312 'equation': f"y = {slope1:.3f}x + {intercept1:.3f}",
313 'original': f"{a1}x + {b1}y = {c1}"
314 })
315 else:
316 # Vertical line x = c1/a1
317 lines.append({
318 'vertical': True,
319 'x_value': c1 / a1 if a1 != 0 else None,
320 'equation': f"x = {c1/a1:.3f}" if a1 != 0 else "undefined",
321 'original': f"{a1}x + {b1}y = {c1}"
322 })
323
324 if b2 != 0:
325 slope2 = -a2 / b2
326 intercept2 = c2 / b2
327 lines.append({
328 'slope': slope2,
329 'y_intercept': intercept2,
330 'equation': f"y = {slope2:.3f}x + {intercept2:.3f}",
331 'original': f"{a2}x + {b2}y = {c2}"
332 })
333 else:
334 lines.append({
335 'vertical': True,
336 'x_value': c2 / a2 if a2 != 0 else None,
337 'equation': f"x = {c2/a2:.3f}" if a2 != 0 else "undefined",
338 'original': f"{a2}x + {b2}y = {c2}"
339 })
340
341 # Find intersection point
342 try:
343 A = np.array(coefficients, dtype=float)
344 b = np.array(constants, dtype=float)
345 solution = np.linalg.solve(A, b)
346 intersection = {'x': solution[0], 'y': solution[1]}
347 except:
348 intersection = None
349
350 return {
351 'method': 'Graphical',
352 'lines': lines,
353 'intersection': intersection,
354 'system_type': self._classify_2x2_system(coefficients, constants)
355 }
356
357 def _solve_3x3_matrix(self, coefficients: list, constants: list) -> Dict[str, Any]:
358 """Solve 3x3 system using matrix methods"""
359 try:
360 A = np.array(coefficients, dtype=float)
361 b = np.array(constants, dtype=float)
362
363 det_A = np.linalg.det(A)
364
365 if abs(det_A) < 1e-10:
366 return {
367 'method': 'Matrix (3x3)',
368 'steps': [f"det(A) = {det_A:.6f} ≈ 0", "System has no unique solution"],
369 'solution': None,
370 'determinant': det_A
371 }
372
373 solution = np.linalg.solve(A, b)
374
375 return {
376 'method': 'Matrix (3x3)',
377 'steps': [
378 f"Coefficient matrix A determinant = {det_A:.6f}",
379 f"Solution: x = {solution[0]:.6f}, y = {solution[1]:.6f}, z = {solution[2]:.6f}"
380 ],
381 'solution': {'x': solution[0], 'y': solution[1], 'z': solution[2]},
382 'determinant': det_A
383 }
384
385 except Exception as e:
386 return {'method': 'Matrix (3x3)', 'error': str(e), 'solution': None}
387
388 def _solve_3x3_elimination(self, coefficients: list, constants: list) -> Dict[str, Any]:
389 """Solve 3x3 system using Gaussian elimination"""
390 # Create augmented matrix
391 augmented = np.array([coefficients[i] + [constants[i]] for i in range(3)], dtype=float)
392
393 steps = [
394 "Augmented matrix:",
395 f"{augmented.tolist()}"
396 ]
397
398 # Forward elimination
399 for i in range(3):
400 # Find pivot
401 max_row = i + np.argmax(np.abs(augmented[i:, i]))
402 if max_row != i:
403 augmented[[i, max_row]] = augmented[[max_row, i]]
404 steps.append(f"Swap rows {i+1} and {max_row+1}")
405
406 # Check for zero pivot
407 if abs(augmented[i, i]) < 1e-10:
408 steps.append(f"Zero pivot encountered at position ({i+1}, {i+1})")
409 return {
410 'method': 'Elimination (3x3)',
411 'steps': steps,
412 'solution': None
413 }
414
415 # Eliminate below pivot
416 for j in range(i + 1, 3):
417 if abs(augmented[j, i]) > 1e-10:
418 factor = augmented[j, i] / augmented[i, i]
419 augmented[j] = augmented[j] - factor * augmented[i]
420 steps.append(f"R{j+1} = R{j+1} - ({factor:.3f})R{i+1}")
421
422 steps.append("After forward elimination:")
423 steps.append(f"{augmented.tolist()}")
424
425 # Back substitution
426 solution = np.zeros(3)
427 for i in range(2, -1, -1):
428 solution[i] = augmented[i, 3]
429 for j in range(i + 1, 3):
430 solution[i] -= augmented[i, j] * solution[j]
431 solution[i] /= augmented[i, i]
432
433 steps.append("Back substitution:")
434 steps.append(f"x = {solution[0]:.6f}, y = {solution[1]:.6f}, z = {solution[2]:.6f}")
435
436 return {
437 'method': 'Elimination (3x3)',
438 'steps': steps,
439 'solution': {'x': solution[0], 'y': solution[1], 'z': solution[2]}
440 }
441
442# Example usage and testing
443if __name__ == "__main__":
444 solver = SystemSolver()
445
446 # Test 2x2 system
447 print("=== 2x2 System Test ===")
448 coeffs_2x2 = [[2, 1], [1, -1]]
449 constants_2x2 = [7, 1]
450
451 result_2x2 = solver.solve_2x2_system(coeffs_2x2, constants_2x2)
452 print(f"System type: {result_2x2['system_type']}")
453
454 if 'elimination_solution' in result_2x2:
455 print("\nElimination method:")
456 for step in result_2x2['elimination_solution']['steps']:
457 print(f" {step}")
458 print(f"Solution: {result_2x2['elimination_solution']['solution']}")
459
460 # Test 3x3 system
461 print("\n=== 3x3 System Test ===")
462 coeffs_3x3 = [[1, 2, -1], [2, 1, 1], [1, -1, 2]]
463 constants_3x3 = [3, 7, 4]
464
465 result_3x3 = solver.solve_3x3_system(coeffs_3x3, constants_3x3, method='matrix')
466 print(f"System type: {result_3x3['system_type']}")
467
468 if 'matrix_solution' in result_3x3:
469 print("\nMatrix method:")
470 for step in result_3x3['matrix_solution']['steps']:
471 print(f" {step}")
472 print(f"Solution: {result_3x3['matrix_solution']['solution']}")