fabianad commited on
Commit
8591daa
·
verified ·
1 Parent(s): 02876c2

Upload solver.py

Browse files
Files changed (1) hide show
  1. solver.py +263 -0
solver.py ADDED
@@ -0,0 +1,263 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sympy as sp
2
+ from sympy.parsing.sympy_parser import parse_expr, standard_transformations, implicit_multiplication_application
3
+ from sympy.solvers import solve
4
+ from sympy import integrate, diff, latex,simplify, expand,sqrt, log, exp, sin, cos, tan, asin, acos, atan, Symbol, factorial, laplace_transform
5
+ import re
6
+ def format_expression(expr):
7
+ latex_expr = latex(expr)
8
+ replacements = {
9
+ '**': '^', # Power notation
10
+ '*x': 'x', # Remove unnecessary multiplication signs
11
+ '*(': '(', # Remove multiplication before parentheses
12
+ 'exp': 'e^', # Exponential notation
13
+ 'sqrt': '√', # Square root
14
+ 'factorial': '!', # Factorial symbol
15
+ 'gamma': 'Γ', # Gamma function
16
+ 'Gamma': 'Γ', # Sometimes SymPy capitalizes it
17
+ 'fresnels': 'S', # Fresnel S integral
18
+ 'fresnelc': 'C', # Fresnel C integral
19
+ 'hyper': '₁F₂', # Generalized hypergeometric function
20
+ 'log': 'ln', # Natural logarithm
21
+ 'oo': '∞', # Infinity symbol
22
+ 'pi': 'π', # Pi symbol
23
+ 'E': 'ℯ', # Euler's constant
24
+ 'I': '𝒊', # Imaginary unit
25
+ 'Abs': '|', # Absolute value
26
+ 'Integral': '∫', # Integral symbol
27
+ 'Derivative': 'd/dx', # Differentiation
28
+ 'Sum': 'Σ', # Summation symbol
29
+ 'Product': '∏', # Product symbol
30
+ 'sin': 'sin', 'cos': 'cos', 'tan': 'tan', # Trig functions (unchanged)
31
+ 'asin': 'sin⁻¹', 'acos': 'cos⁻¹', 'atan': 'tan⁻¹', # Inverse trig
32
+ 'sinh': 'sinh', 'cosh': 'cosh', 'tanh': 'tanh', # Hyperbolic trig
33
+ 'asinh': 'sinh⁻¹', 'acosh': 'cosh⁻¹', 'atanh': 'tanh⁻¹', # Inverse hyperbolic trig
34
+ 'diff': 'd/dx', # Derivative notation
35
+ 'integrate': '∫', # Integral notation
36
+ 'Limit': 'lim', # Limit notation
37
+ 'floor': '⌊', # Floor function
38
+ 'ceiling': '⌈', # Ceiling function
39
+ 'mod': 'mod', # Modulus (unchanged)
40
+ 'Re': 'ℜ', # Real part
41
+ 'Im': 'ℑ' # Imaginary part
42
+ }
43
+ for old, new in replacements.items():
44
+ latex_expr = latex_expr.replace(old, new)
45
+
46
+ return f"$$ {latex_expr} $$"
47
+
48
+ def preprocess_equation(equation_str):
49
+ """Convert user-friendly equation format to SymPy format."""
50
+ try:
51
+ # Replace common mathematical notations
52
+ replacements = {
53
+ '^': '**',
54
+ 'sin⁻¹': 'asin',
55
+ 'cos⁻¹': 'acos',
56
+ 'tan⁻¹': 'atan',
57
+ 'e^': 'exp',
58
+ 'ln': 'log', # Convert ln to log (SymPy default)
59
+ '√': 'sqrt', # Convert square root symbol to sqrt()
60
+ '!': '.factorial()', # Convert factorial to function call
61
+ }
62
+ for old, new in replacements.items():
63
+ equation_str = equation_str.replace(old, new)
64
+
65
+ equation_str = re.sub(r'(\d+)!', r'factorial(\1)', equation_str)
66
+
67
+ # Handle exponential expressions
68
+ if 'exp' in equation_str:
69
+ parts = equation_str.split('exp')
70
+ for i in range(1, len(parts)):
71
+ if parts[i] and parts[i][0] != '(':
72
+ parts[i] = '(' + parts[i]
73
+ if '=' in parts[i]:
74
+ exp_part, rest = parts[i].split('=', 1)
75
+ parts[i] = exp_part + ')=' + rest
76
+ else:
77
+ parts[i] = parts[i] + ')'
78
+ equation_str = 'exp'.join(parts)
79
+
80
+ # Add multiplication symbol where needed
81
+ processed = ''
82
+ i = 0
83
+ while i < len(equation_str):
84
+ if i + 1 < len(equation_str):
85
+ if equation_str[i].isdigit() and equation_str[i+1] == 'x':
86
+ processed += equation_str[i] + '*'
87
+ i += 1
88
+ continue
89
+ processed += equation_str[i]
90
+ i += 1
91
+
92
+ return processed
93
+ except Exception as e:
94
+ raise Exception(f"Error in equation format: {str(e)}")
95
+
96
+ def process_expression(expr_str):
97
+ """Process mathematical expressions without equations."""
98
+ try:
99
+ processed_expr = preprocess_equation(expr_str)
100
+ x = Symbol('x')
101
+
102
+ if expr_str.startswith('∫'): # Integration
103
+ expr_to_integrate = processed_expr[1:].strip()
104
+ expr = parse_expr(expr_to_integrate, transformations=(standard_transformations + (implicit_multiplication_application,)))
105
+ result = integrate(expr, x)
106
+ return f"∫{format_expression(expr)} = {format_expression(result)}"
107
+
108
+ elif expr_str.startswith('d/dx'): # Differentiation
109
+ expr_to_diff = processed_expr[4:].strip()
110
+ if expr_to_diff.startswith('(') and expr_to_diff.endswith(')'):
111
+ expr_to_diff = expr_to_diff[1:-1]
112
+ expr = parse_expr(expr_to_diff, transformations=(standard_transformations + (implicit_multiplication_application,)))
113
+ result = diff(expr, x)
114
+ return f"d/dx({format_expression(expr)}) = {format_expression(result)}"
115
+
116
+
117
+ elif 'sqrt' in processed_expr.lower():
118
+ try:
119
+ transformations = standard_transformations + (implicit_multiplication_application,)
120
+
121
+ # Remove "sqrt" and parse the expression inside
122
+ expr = sp.parse_expr(processed_expr.replace("sqrt", ""), transformations=transformations)
123
+
124
+ sqrt_result = sp.sqrt(expr)
125
+
126
+ # If it's sqrt(x^2), simplify it to |x|
127
+ simplified_result = sp.simplify(sqrt_result)
128
+
129
+ steps = []
130
+ steps.append(f"**Step 1:** Original expression: \n{to_latex(expr)}")
131
+
132
+ # Case 1: Perfect Squares → Show exact value (e.g., sqrt(9) = ±3)
133
+ if sqrt_result.is_Integer:
134
+ steps.append(f"**Step 2:** √{to_latex(expr)} is a perfect square")
135
+ steps.append(f"**Step 3:** Solution: \n±{to_latex(sqrt_result)}")
136
+ solution = "\n".join(steps)
137
+
138
+ # Case 2: Non-Perfect Squares → Show decimal value (e.g., sqrt(2) ≈ 1.41)
139
+ elif sqrt_result.is_real and not sqrt_result.is_rational:
140
+ decimal_value = float(sqrt_result.evalf())
141
+ steps.append(f"**Step 2:** √{to_latex(expr)} is not a perfect square")
142
+ steps.append(f"**Step 3:** Approximate value: \n{decimal_value}")
143
+ solution = "\n".join(steps)
144
+
145
+ # Case 3: Expressions like √x² → |x|
146
+ elif simplified_result != sqrt_result:
147
+ steps.append(f"**Step 2:** Simplification using identity: \n{to_latex(simplified_result)}")
148
+ solution = "\n".join(steps)
149
+
150
+ # Case 4: General Expression → Return as-is
151
+ else:
152
+ steps.append(f"**Step 2:** Taking square root: \n{to_latex(sqrt_result)}")
153
+ steps.append(f"**Step 3:** Considering both positive and negative roots: \n±{to_latex(sqrt_result)}")
154
+ solution = "\n".join(steps)
155
+
156
+ except Exception as e:
157
+ solution = f"Error: {str(e)}"
158
+ elif 'factorial' in processed_expr: # Factorial case
159
+ expr = parse_expr(processed_expr, transformations=(standard_transformations + (implicit_multiplication_application,)))
160
+ result = expr.doit() # Compute the factorial correctly
161
+ return f"{format_expression(expr)} = {result}"
162
+
163
+
164
+ elif '/' in expr_str: # Handle fractions and return decimal
165
+ expr = parse_expr(processed_expr, transformations=(standard_transformations + (implicit_multiplication_application,)))
166
+ simplified = simplify(expr)
167
+ decimal_value = float(simplified)
168
+ return f"Simplified: {format_expression(simplified)}\nDecimal: {decimal_value}"
169
+
170
+ else: # Regular expression simplification
171
+ expr = parse_expr(processed_expr, transformations=(standard_transformations + (implicit_multiplication_application,)))
172
+ simplified = simplify(expr)
173
+ expanded = expand(simplified)
174
+ return f"Simplified: {format_expression(simplified)}\nExpanded: {format_expression(expanded)}"
175
+
176
+ except Exception as e:
177
+ raise Exception(f"Error processing expression: {str(e)}")
178
+
179
+
180
+ except Exception as e:
181
+ raise Exception(f"Error processing expression: {str(e)}")
182
+
183
+ def solve_equation(equation_str):
184
+ """Solve the given equation and return the solution."""
185
+ try:
186
+ if '=' not in equation_str:
187
+ return process_expression(equation_str)
188
+
189
+ # Preprocess equation
190
+ equation_str = preprocess_equation(equation_str)
191
+
192
+ # Split equation into left and right parts
193
+ left_side, right_side = [side.strip() for side in equation_str.split('=')]
194
+
195
+ # Parse both sides with implicit multiplication
196
+ transformations = standard_transformations + (implicit_multiplication_application,)
197
+ left_expr = parse_expr(left_side, transformations=transformations)
198
+ right_expr = parse_expr(right_side, transformations=transformations)
199
+ equation = left_expr - right_expr
200
+
201
+ # Solve the equation
202
+ x = Symbol('x')
203
+ solution = solve(equation, x)
204
+
205
+ # Format solution
206
+ if len(solution) == 0:
207
+ return "No solution exists"
208
+ elif len(solution) == 1:
209
+ return f"x = {format_expression(solution[0])}"
210
+ else:
211
+ return "x = " + ", ".join([format_expression(sol) for sol in solution])
212
+
213
+ except Exception as e:
214
+ raise Exception(f"Invalid equation format: {str(e)}")
215
+
216
+ def generate_steps(equation_str):
217
+ """Generate step-by-step solution for the equation or expression."""
218
+ steps = []
219
+ try:
220
+ if '=' not in equation_str:
221
+ steps.append(f"1. Original expression: {equation_str}")
222
+ result = process_expression(equation_str)
223
+ steps.append(f"2. Result: {result}")
224
+ return steps
225
+
226
+ # Preprocess equation
227
+ processed_eq = preprocess_equation(equation_str)
228
+
229
+ # Split equation into left and right parts
230
+ left_side, right_side = [side.strip() for side in processed_eq.split('=')]
231
+
232
+ # Parse expressions with implicit multiplication
233
+ transformations = standard_transformations + (implicit_multiplication_application,)
234
+ left_expr = parse_expr(left_side, transformations=transformations)
235
+ right_expr = parse_expr(right_side, transformations=transformations)
236
+
237
+ # Step 1: Show original equation
238
+ steps.append(f"1. Original equation: {format_expression(left_expr)} = {format_expression(right_expr)}")
239
+
240
+ # Step 2: Move all terms to left side
241
+ equation = left_expr - right_expr
242
+ steps.append(f"2. Move all terms to left side: {format_expression(equation)} = 0")
243
+
244
+ # Step 3: Factor if possible
245
+ factored = sp.factor(equation)
246
+ if factored != equation:
247
+ steps.append(f"3. Factor the equation: {format_expression(factored)} = 0")
248
+
249
+ # Step 4: Solve
250
+ x = Symbol('x')
251
+ solution = solve(equation, x)
252
+ steps.append(f"4. Solve for x: x = {', '.join([format_expression(sol) for sol in solution])}")
253
+
254
+ # Step 5: Verify solutions
255
+ steps.append("5. Verify solutions:")
256
+ for sol in solution:
257
+ result = equation.subs(x, sol)
258
+ steps.append(f" When x = {format_expression(sol)}, equation equals {format_expression(result)}")
259
+
260
+ return steps
261
+
262
+ except Exception as e:
263
+ raise Exception(f"Error generating steps: {str(e)}")