MathSolver / solver.py
Taizun's picture
Update solver.py
f4b04e0 verified
raw
history blame
9.85 kB
import sympy as sp
from sympy.parsing.sympy_parser import parse_expr, standard_transformations, implicit_multiplication_application
from sympy.solvers import solve
from sympy import integrate, diff, latex,simplify, expand, log, exp, sin, cos, tan, asin, acos, atan, Symbol, factorial, laplace_transform
import re
def format_expression(expr):
latex_expr = latex(expr)
replacements = {
'**': '^', # Power notation
'*x': 'x', # Remove unnecessary multiplication signs
'*(': '(', # Remove multiplication before parentheses
'exp': 'e^', # Exponential notation
'sqrt': '√', # Square root
'factorial': '!', # Factorial symbol
'gamma': 'Γ', # Gamma function
'Gamma': 'Γ', # Sometimes SymPy capitalizes it
'fresnels': 'S', # Fresnel S integral
'fresnelc': 'C', # Fresnel C integral
'hyper': '₁F₂', # Generalized hypergeometric function
'log': 'ln', # Natural logarithm
'oo': '∞', # Infinity symbol
'pi': 'π', # Pi symbol
'E': 'ℯ', # Euler's constant
'I': '𝒊', # Imaginary unit
'Abs': '|', # Absolute value
'Integral': '∫', # Integral symbol
'Derivative': 'd/dx', # Differentiation
'Sum': 'Σ', # Summation symbol
'Product': '∏', # Product symbol
'sin': 'sin', 'cos': 'cos', 'tan': 'tan', # Trig functions (unchanged)
'asin': 'sin⁻¹', 'acos': 'cos⁻¹', 'atan': 'tan⁻¹', # Inverse trig
'sinh': 'sinh', 'cosh': 'cosh', 'tanh': 'tanh', # Hyperbolic trig
'asinh': 'sinh⁻¹', 'acosh': 'cosh⁻¹', 'atanh': 'tanh⁻¹', # Inverse hyperbolic trig
'diff': 'd/dx', # Derivative notation
'integrate': '∫', # Integral notation
'Limit': 'lim', # Limit notation
'floor': '⌊', # Floor function
'ceiling': '⌈', # Ceiling function
'mod': 'mod', # Modulus (unchanged)
'Re': 'ℜ', # Real part
'Im': 'ℑ' # Imaginary part
}
for old, new in replacements.items():
latex_expr = latex_expr.replace(old, new)
return f"$$ {latex_expr} $$"
def preprocess_equation(equation_str):
"""Convert user-friendly equation format to SymPy format."""
try:
# Replace common mathematical notations
replacements = {
'^': '**',
'sin⁻¹': 'asin',
'cos⁻¹': 'acos',
'tan⁻¹': 'atan',
'e^': 'exp',
'ln': 'log', # Convert ln to log (SymPy default)
'√': 'sqrt', # Convert square root symbol to sqrt()
'!': '.factorial()', # Convert factorial to function call
}
for old, new in replacements.items():
equation_str = equation_str.replace(old, new)
equation_str = re.sub(r'(\d+)!', r'factorial(\1)', equation_str)
# Handle exponential expressions
if 'exp' in equation_str:
parts = equation_str.split('exp')
for i in range(1, len(parts)):
if parts[i] and parts[i][0] != '(':
parts[i] = '(' + parts[i]
if '=' in parts[i]:
exp_part, rest = parts[i].split('=', 1)
parts[i] = exp_part + ')=' + rest
else:
parts[i] = parts[i] + ')'
equation_str = 'exp'.join(parts)
# Add multiplication symbol where needed
processed = ''
i = 0
while i < len(equation_str):
if i + 1 < len(equation_str):
if equation_str[i].isdigit() and equation_str[i+1] == 'x':
processed += equation_str[i] + '*'
i += 1
continue
processed += equation_str[i]
i += 1
return processed
except Exception as e:
raise Exception(f"Error in equation format: {str(e)}")
def process_expression(expr_str):
"""Process mathematical expressions without equations."""
try:
processed_expr = preprocess_equation(expr_str)
x = Symbol('x')
if expr_str.startswith('∫'): # Integration
expr_to_integrate = processed_expr[1:].strip()
expr = parse_expr(expr_to_integrate, transformations=(standard_transformations + (implicit_multiplication_application,)))
result = integrate(expr, x)
return f"∫{format_expression(expr)} = {format_expression(result)}"
elif expr_str.startswith('d/dx'): # Differentiation
expr_to_diff = processed_expr[4:].strip()
if expr_to_diff.startswith('(') and expr_to_diff.endswith(')'):
expr_to_diff = expr_to_diff[1:-1]
expr = parse_expr(expr_to_diff, transformations=(standard_transformations + (implicit_multiplication_application,)))
result = diff(expr, x)
return f"d/dx({format_expression(expr)}) = {format_expression(result)}"
elif 'factorial' in processed_expr: # Factorial case
expr = parse_expr(processed_expr, transformations=(standard_transformations + (implicit_multiplication_application,)))
result = expr.doit() # Compute the factorial correctly
return f"{format_expression(expr)} = {result}"
elif '/' in expr_str: # Handle fractions and return decimal
expr = parse_expr(processed_expr, transformations=(standard_transformations + (implicit_multiplication_application,)))
simplified = simplify(expr)
decimal_value = float(simplified)
return f"Simplified: {format_expression(simplified)}\nDecimal: {decimal_value}"
else: # Regular expression simplification
expr = parse_expr(processed_expr, transformations=(standard_transformations + (implicit_multiplication_application,)))
simplified = simplify(expr)
expanded = expand(simplified)
return f"Simplified: {format_expression(simplified)}\nExpanded: {format_expression(expanded)}"
except Exception as e:
raise Exception(f"Error processing expression: {str(e)}")
except Exception as e:
raise Exception(f"Error processing expression: {str(e)}")
def solve_equation(equation_str):
"""Solves an equation and returns a detailed step-by-step solution."""
try:
if '=' not in equation_str:
return process_expression(equation_str)
# Split into left and right-hand sides
left_side, right_side = [side.strip() for side in equation_str.split('=')]
# Parse expressions
transformations = standard_transformations + (implicit_multiplication_application,)
left_expr = sp.parse_expr(left_side, transformations=transformations)
right_expr = sp.parse_expr(right_side, transformations=transformations)
equation = left_expr - right_expr
x = Symbol('x')
solutions = solve(equation, x)
steps = []
steps.append(f"**Step 1:** Original equation: \n{format_expression(left_expr)} = {format_expression(right_expr)}")
steps.append(f"**Step 2:** Move all terms to one side: \n{format_expression(equation)} = 0")
# Factoring if possible
factored = sp.factor(equation)
if factored != equation:
steps.append(f"**Step 3:** Factorizing the equation: \n{format_expression(factored)} = 0")
# Solve for x
steps.append(f"**Step 4:** Solving for x:")
for sol in solutions:
steps.append(f" x = {format_expression(sol)}")
# Verification
steps.append("**Step 5:** Verification:")
for sol in solutions:
verification = equation.subs(x, sol)
steps.append(f" When x = {format_expression(sol)}, the equation evaluates to {format_expression(verification)}")
return "\n".join(steps)
except Exception as e:
return f"Error: {str(e)}"
def integrate_expression(expression_str):
"""Computes the integral of a given expression and provides detailed steps."""
try:
x = Symbol('x')
expr = sp.parse_expr(expression_str, transformations=standard_transformations + (implicit_multiplication_application,))
steps = []
steps.append(f"**Step 1:** Original integral: \n∫ {format_expression(expr)} dx")
# Check if substitution can simplify
if '^' in expression_str:
steps.append("**Step 2:** Substituting variables if needed")
# Example: If we have x^n, we might use substitution
# More cases can be handled as needed
result = integrate(expr, x)
steps.append(f"**Step 3:** Applying integration formula(s):")
steps.append(f" ∫ f(x) dx = F(x) + C")
steps.append(f"**Step 4:** Solution: \n{format_expression(result)} + C")
return "\n".join(steps)
except Exception as e:
return f"Error: {str(e)}"
def laplace_transform_expression(expression_str):
"""Computes the Laplace transform of a given expression with detailed steps."""
try:
t, s = sp.symbols('t s')
expr = sp.parse_expr(expression_str, transformations=standard_transformations + (implicit_multiplication_application,))
steps = []
steps.append(f"**Step 1:** Original function: \nL[{format_expression(expr)}](t)")
# Compute Laplace transform
L_transform = laplace_transform(expr, t, s, noconds=True)
steps.append(f"**Step 2:** Applying Laplace Transform:")
steps.append(" L[f(t)] = ∫ e^(-st) f(t) dt, from 0 to ∞")
steps.append(f"**Step 3:** Solution: \n{format_expression(L_transform)}")
return "\n".join(steps)
except Exception as e:
return f"Error: {str(e)}"