CoolFace
Apppublic

NavyDevilDoc/Systems_of_Equations

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
sys_of_eqn_solver.py472 linesDownload Raw Back to src
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']}")