NavyDevilDoc commited on
Commit
b5149f8
·
verified ·
1 Parent(s): 4dcd213

Upload sys_of_eqn_solver.py

Browse files
Files changed (1) hide show
  1. src/sys_of_eqn_solver.py +472 -0
src/sys_of_eqn_solver.py ADDED
@@ -0,0 +1,472 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import sympy as sp
3
+ from sympy import symbols, Eq, solve, Matrix
4
+ from typing import Tuple, Dict, Any, Optional
5
+ import matplotlib.pyplot as plt
6
+ from fractions import Fraction
7
+
8
+ class 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
443
+ if __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']}")