Spaces:
Running
Running
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,sqrt, 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 'sqrt' in processed_expr.lower(): | |
try: | |
transformations = standard_transformations + (implicit_multiplication_application,) | |
# Remove "sqrt" and parse the expression inside | |
expr = sp.parse_expr(processed_expr.replace("sqrt", ""), transformations=transformations) | |
sqrt_result = sp.sqrt(expr) | |
# If it's sqrt(x^2), simplify it to |x| | |
simplified_result = sp.simplify(sqrt_result) | |
steps = [] | |
steps.append(f"**Step 1:** Original expression: \n{to_latex(expr)}") | |
# Case 1: Perfect Squares → Show exact value (e.g., sqrt(9) = ±3) | |
if sqrt_result.is_Integer: | |
steps.append(f"**Step 2:** √{to_latex(expr)} is a perfect square") | |
steps.append(f"**Step 3:** Solution: \n±{to_latex(sqrt_result)}") | |
solution = "\n".join(steps) | |
# Case 2: Non-Perfect Squares → Show decimal value (e.g., sqrt(2) ≈ 1.41) | |
elif sqrt_result.is_real and not sqrt_result.is_rational: | |
decimal_value = float(sqrt_result.evalf()) | |
steps.append(f"**Step 2:** √{to_latex(expr)} is not a perfect square") | |
steps.append(f"**Step 3:** Approximate value: \n{decimal_value}") | |
solution = "\n".join(steps) | |
# Case 3: Expressions like √x² → |x| | |
elif simplified_result != sqrt_result: | |
steps.append(f"**Step 2:** Simplification using identity: \n{to_latex(simplified_result)}") | |
solution = "\n".join(steps) | |
# Case 4: General Expression → Return as-is | |
else: | |
steps.append(f"**Step 2:** Taking square root: \n{to_latex(sqrt_result)}") | |
steps.append(f"**Step 3:** Considering both positive and negative roots: \n±{to_latex(sqrt_result)}") | |
solution = "\n".join(steps) | |
except Exception as e: | |
solution = f"Error: {str(e)}" | |
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): | |
"""Solve the given equation and return the solution.""" | |
try: | |
if '=' not in equation_str: | |
return process_expression(equation_str) | |
# Preprocess equation | |
equation_str = preprocess_equation(equation_str) | |
# Split equation into left and right parts | |
left_side, right_side = [side.strip() for side in equation_str.split('=')] | |
# Parse both sides with implicit multiplication | |
transformations = standard_transformations + (implicit_multiplication_application,) | |
left_expr = parse_expr(left_side, transformations=transformations) | |
right_expr = parse_expr(right_side, transformations=transformations) | |
equation = left_expr - right_expr | |
# Solve the equation | |
x = Symbol('x') | |
solution = solve(equation, x) | |
# Format solution | |
if len(solution) == 0: | |
return "No solution exists" | |
elif len(solution) == 1: | |
return f"x = {format_expression(solution[0])}" | |
else: | |
return "x = " + ", ".join([format_expression(sol) for sol in solution]) | |
except Exception as e: | |
raise Exception(f"Invalid equation format: {str(e)}") | |
def generate_steps(equation_str): | |
"""Generate step-by-step solution for the equation or expression.""" | |
steps = [] | |
try: | |
if '=' not in equation_str: | |
steps.append(f"1. Original expression: {equation_str}") | |
result = process_expression(equation_str) | |
steps.append(f"2. Result: {result}") | |
return steps | |
# Preprocess equation | |
processed_eq = preprocess_equation(equation_str) | |
# Split equation into left and right parts | |
left_side, right_side = [side.strip() for side in processed_eq.split('=')] | |
# Parse expressions with implicit multiplication | |
transformations = standard_transformations + (implicit_multiplication_application,) | |
left_expr = parse_expr(left_side, transformations=transformations) | |
right_expr = parse_expr(right_side, transformations=transformations) | |
# Step 1: Show original equation | |
steps.append(f"1. Original equation: {format_expression(left_expr)} = {format_expression(right_expr)}") | |
# Step 2: Move all terms to left side | |
equation = left_expr - right_expr | |
steps.append(f"2. Move all terms to left side: {format_expression(equation)} = 0") | |
# Step 3: Factor if possible | |
factored = sp.factor(equation) | |
if factored != equation: | |
steps.append(f"3. Factor the equation: {format_expression(factored)} = 0") | |
# Step 4: Solve | |
x = Symbol('x') | |
solution = solve(equation, x) | |
steps.append(f"4. Solve for x: x = {', '.join([format_expression(sol) for sol in solution])}") | |
# Step 5: Verify solutions | |
steps.append("5. Verify solutions:") | |
for sol in solution: | |
result = equation.subs(x, sol) | |
steps.append(f" When x = {format_expression(sol)}, equation equals {format_expression(result)}") | |
return steps | |
except Exception as e: | |
raise Exception(f"Error generating steps: {str(e)}") |