| """Deterministic symbolic mathematics engine for Saad.AI. |
| |
| This module intentionally contains no Streamlit or network dependencies so it can be |
| unit-tested independently of the UI and provider integrations. |
| """ |
|
|
| import re |
| import sympy as sp |
| from sympy.parsing.sympy_parser import ( |
| parse_expr, |
| standard_transformations, |
| implicit_multiplication_application, |
| ) |
|
|
| def run_sympy(problem: str) -> dict: |
| """ |
| Symbolic computation engine. Returns verified result dict. |
| Falls back silently on any error. |
| ELIF ORDER (important β must check ODE before Solve): |
| Derivative β Integral β Limit β ODE β NR β Solve β Matrix β Mod |
| """ |
| p = problem.lower().strip() |
| x = sp.Symbol('x') |
| tfms = standard_transformations + (implicit_multiplication_application,) |
| ld = { |
| "x": x, |
| "e": sp.E, "E": sp.E, |
| "pi": sp.pi, "PI": sp.pi, |
| "sin": sp.sin, "cos": sp.cos, "tan": sp.tan, |
| "exp": sp.exp, "log": sp.log, "ln": sp.log, |
| "sqrt": sp.sqrt, "inf": sp.oo, "oo": sp.oo |
| } |
|
|
| def clean(s): |
| s = re.sub(r"\s+", "", s) |
| s = re.sub(r"\^", "**", s) |
| return s |
|
|
| def to_coeff(s): |
| """Convert string to sympy integer/rational β never float (floats break dsolve).""" |
| s = s.replace(" ", "") |
| if s in ("", "+"): return sp.Integer(1) |
| if s == "-": return sp.Integer(-1) |
| try: |
| f = float(s) |
| return sp.Integer(int(f)) if f == int(f) else sp.Rational(s) |
| except Exception: |
| return sp.Integer(1) |
|
|
| try: |
| |
| if any(k in p for k in ["derivative", "differentiate", "d/dx", "diff"]): |
| raw = p |
| for kw in ["derivative of", "differentiate", "diff of", "d/dx of", "d/dx"]: |
| if kw in p: |
| raw = p.split(kw, 1)[-1].strip() |
| break |
| raw = re.sub(r"\s*(dx|with\s*respect\s*to\s*x).*$", "", raw).strip() |
| expr = parse_expr(clean(raw), transformations=tfms, local_dict=ld) |
| result = sp.diff(expr, x) |
| return {"type": "Derivative", "result": str(result), "latex": sp.latex(result)} |
|
|
| |
| elif any(k in p for k in ["integral", "integrate", "antiderivative"]): |
| raw = p |
| for kw in ["integral of", "integrate", "antiderivative of"]: |
| if kw in p: |
| raw = p.split(kw, 1)[-1].strip() |
| break |
| raw = re.sub(r"\s*dx.*$", "", raw).strip() |
| expr = parse_expr(clean(raw), transformations=tfms, local_dict=ld) |
| result = sp.integrate(expr, x) |
| return {"type": "Integral", "result": str(result), "latex": sp.latex(result)} |
|
|
| |
| elif "limit" in p: |
| match = re.search( |
| r"limit\s+of\s+([\w\s\(\)\+\-\*/\^\.\,]+?)" |
| r"\s+as\s+x\s*(?:->|β|approaches)\s*([\w\.\+\-]+)", p |
| ) |
| if match: |
| raw_expr = clean(match.group(1)) |
| pt = match.group(2).strip() |
| point = sp.oo if pt in ("inf", "infinity", "oo") else sp.sympify(pt) |
| expr = parse_expr(raw_expr, transformations=tfms, local_dict=ld) |
| result = sp.limit(expr, x, point) |
| return {"type": "Limit", "result": str(result), "latex": sp.latex(result)} |
|
|
| |
| elif any(k in p for k in ["dΒ²y", "d^2y", "d2y", "dy/dx", |
| "differential equation", "second order", "first order"]): |
| y_fn = sp.Function('y') |
| ode_sol = None |
| try: |
| |
| rhs_m = re.search(r"=\s*(.+?)(?:\s+with|\s*$)", p) |
| rhs_str = clean(rhs_m.group(1).strip()) if rhs_m else "0" |
| rhs_expr = parse_expr(rhs_str, transformations=tfms, local_dict=ld) |
| lhs = p.split("=")[0] |
|
|
| |
| if any(k in p for k in ["dΒ²y", "d^2y", "d2y", "second order"]): |
| |
| c1_m = re.search(r"([+\-]\s*\d*\.?\d*)\s*dy/dx", lhs) |
| |
| c0_m = re.search(r"([+\-]\s*\d+\.?\d*)\s*y\b", lhs) |
| a1 = to_coeff(c1_m.group(1)) if c1_m else sp.Integer(0) |
| a0 = to_coeff(c0_m.group(1)) if c0_m else sp.Integer(0) |
| ode_eq = sp.Eq( |
| y_fn(x).diff(x, 2) + a1*y_fn(x).diff(x) + a0*y_fn(x), |
| rhs_expr |
| ) |
| ode_sol = sp.dsolve(ode_eq, y_fn(x)) |
|
|
| |
| elif "dy/dx" in p: |
| c0_m = re.search(r"([+\-]\s*\d+\.?\d*)\s*y\b", lhs) |
| a0 = to_coeff(c0_m.group(1)) if c0_m else sp.Integer(0) |
| ode_eq = sp.Eq(y_fn(x).diff(x) + a0*y_fn(x), rhs_expr) |
| ode_sol = sp.dsolve(ode_eq, y_fn(x)) |
|
|
| except Exception: |
| ode_sol = None |
|
|
| if ode_sol is not None: |
| return { |
| "type": "ODE", |
| "result": f"General solution: y = {str(ode_sol.rhs)}", |
| "latex": f"y = {sp.latex(ode_sol.rhs)}" |
| } |
|
|
| |
| elif any(k in p for k in ["newton", "newton-raphson", "newton raphson"]): |
| |
| eq_m = re.search(r"(?:of|to|for)\s+(.+?)\s*=\s*0", p) |
| x0_m = re.search(r"x\s*0\s*[=:]\s*([\d\.]+)", p) |
| iter_m = re.search(r"(\d+)\s*iter", p) |
|
|
| if eq_m and x0_m: |
| raw_eq = clean(eq_m.group(1).strip()) |
| x0_val = float(x0_m.group(1)) |
| n_iter = int(iter_m.group(1)) if iter_m else 3 |
|
|
| expr_nr = parse_expr(raw_eq, transformations=tfms, local_dict=ld) |
| f_sym = sp.lambdify(x, expr_nr, modules="math") |
| df_sym = sp.lambdify(x, sp.diff(expr_nr, x), modules="math") |
|
|
| |
| iterations = [] |
| xn = x0_val |
| for i in range(n_iter): |
| fxn = f_sym(xn) |
| dfxn = df_sym(xn) |
| if abs(dfxn) < 1e-15: |
| break |
| xn1 = xn - fxn / dfxn |
| iterations.append({ |
| "n": i, "xn": round(xn, 8), |
| "fxn": round(fxn, 8), "dfxn": round(dfxn, 8), |
| "xn1": round(xn1, 8) |
| }) |
| xn = xn1 |
|
|
| final_x = iterations[-1]["xn1"] if iterations else x0_val |
| final_fx = round(f_sym(final_x), 10) |
| iter_str = "\n".join([ |
| f" x{it['n']+1} = {it['xn']} - ({it['fxn']}) / ({it['dfxn']}) = {it['xn1']}" |
| for it in iterations |
| ]) |
| result_str = ( |
| f"f(x) = {str(expr_nr)}, f'(x) = {str(sp.diff(expr_nr, x))}\n" |
| f"x0 = {x0_val}, iterations = {n_iter}\n" |
| f"VERIFIED ITERATIONS (AI MUST use these exact values):\n" |
| f"{iter_str}\n" |
| f"Final answer: x{n_iter} = {final_x}\n" |
| f"Verification: f({final_x}) = {final_fx} β 0" |
| ) |
| return { |
| "type": "Newton-Raphson", |
| "result": result_str, |
| "latex": f"x_{{{n_iter}}} = {final_x}" |
| } |
|
|
| |
| elif any(k in p for k in ["bisection", "secant method", "false position", |
| "regula falsi", "gauss elimination", "gauss elim", |
| "lu decomposition", "lu decomp", |
| "lagrange interpolation", "lagrange interp", |
| "newton divided", "divided difference", |
| "trapezoidal", "trapezoid rule", |
| "simpson", "euler method", "euler's method", |
| "runge-kutta", "runge kutta", "rk4"]): |
| import math as _math |
|
|
| |
| def get_expr(): |
| |
| |
| eq_m = re.search( |
| r"(?:of|to|for|function)\s+(.+?)(?=\s*(?:=\s*0|,|\bon\b|\bfrom\b|\bbetween\b|\[|$))", |
| p, |
| ) |
| if eq_m: |
| raw = clean(eq_m.group(1).strip()) |
| return parse_expr(raw, transformations=tfms, local_dict=ld) |
| return None |
|
|
| |
| def get_bounds(): |
| nums = re.findall(r"[-]?\d+\.?\d*", p) |
| floats = [float(n) for n in nums] |
| |
| x0_m = re.search(r"x\s*0\s*[=:]\s*([-]?\d+\.?\d*)", p) |
| x1_m = re.search(r"x\s*1\s*[=:]\s*([-]?\d+\.?\d*)", p) |
| |
| ab_m = re.search(r"\[\s*([-]?\d+\.?\d*)\s*,\s*([-]?\d+\.?\d*)\s*\]", p) |
| return floats, x0_m, x1_m, ab_m |
|
|
| |
| def get_iters(default=5): |
| m = re.search(r"(\d+)\s*iter", p) |
| return int(m.group(1)) if m else default |
|
|
| |
| def get_h(): |
| m = re.search(r"h\s*[=:]\s*([\d\.]+)", p) |
| return float(m.group(1)) if m else 0.1 |
|
|
| |
| def get_ode_rhs(): |
| |
| m = re.search(r"dy/dx\s*=\s*(.+?)(?:\s*,|\s*with|\s*y\s*\(|$)", p) |
| return m.group(1).strip() if m else None |
|
|
| floats, x0_m, x1_m, ab_m = get_bounds() |
| n_iter = max(1, get_iters()) |
|
|
| |
| |
| |
| if "bisection" in p: |
| expr_b = get_expr() |
| if expr_b is not None and ab_m: |
| a_val = float(ab_m.group(1)) |
| b_val = float(ab_m.group(2)) |
| f_b = sp.lambdify(x, expr_b, modules="math") |
| fa, fb = f_b(a_val), f_b(b_val) |
| if fa == 0: |
| return {"type": "Bisection", "result": f"Root = {a_val}", "latex": f"x = {a_val}"} |
| if fb == 0: |
| return {"type": "Bisection", "result": f"Root = {b_val}", "latex": f"x = {b_val}"} |
| if fa * fb > 0: |
| return { |
| "type": "Bisection", |
| "result": f"Cannot apply bisection: f({a_val}) and f({b_val}) have the same sign.", |
| "latex": "\\text{Invalid bracket}", |
| } |
| steps = [] |
| a_n, b_n = a_val, b_val |
| for i in range(n_iter): |
| c = (a_n + b_n) / 2 |
| fc = f_b(c) |
| steps.append({"iter": i+1, "a": round(a_n,8), |
| "b": round(b_n,8), "c": round(c,8), |
| "fc": round(fc,8)}) |
| if f_b(a_n) * fc < 0: b_n = c |
| else: a_n = c |
| step_str = "\n".join([ |
| f" Iter {s['iter']}: a={s['a']}, b={s['b']}, c={s['c']}, f(c)={s['fc']}" |
| for s in steps]) |
| final_c = steps[-1]["c"] |
| return { |
| "type": "Bisection", |
| "result": (f"f(x) = {str(expr_b)}\n" |
| f"Interval [{a_val},{b_val}], {n_iter} iterations\n" |
| f"VERIFIED ITERATIONS:\n{step_str}\n" |
| f"Root β {final_c}"), |
| "latex": f"x \\approx {final_c}" |
| } |
|
|
| |
| |
| |
| elif "secant" in p: |
| expr_s = get_expr() |
| if expr_s is not None and x0_m and x1_m: |
| x0_v = float(x0_m.group(1)) |
| x1_v = float(x1_m.group(1)) |
| f_s = sp.lambdify(x, expr_s, modules="math") |
| steps = [] |
| xp, xc = x0_v, x1_v |
| for i in range(n_iter): |
| fxp, fxc = f_s(xp), f_s(xc) |
| if abs(fxc - fxp) < 1e-15: break |
| xn_val = xc - fxc*(xc-xp)/(fxc-fxp) |
| steps.append({"iter": i+1, "x": round(xn_val, 8), |
| "fx": round(f_s(xn_val), 8)}) |
| xp, xc = xc, xn_val |
| step_str = "\n".join([ |
| f" Iter {s['iter']}: x={s['x']}, f(x)={s['fx']}" |
| for s in steps]) |
| return { |
| "type": "Secant", |
| "result": (f"f(x) = {str(expr_s)}\n" |
| f"x0={x0_v}, x1={x1_v}, {n_iter} iterations\n" |
| f"VERIFIED ITERATIONS:\n{step_str}\n" |
| f"Root β {steps[-1]['x']}"), |
| "latex": f"x \\approx {steps[-1]['x']}" |
| } |
|
|
| |
| |
| |
| elif any(k in p for k in ["false position", "regula falsi"]): |
| expr_fp = get_expr() |
| if expr_fp is not None and ab_m: |
| a_val = float(ab_m.group(1)) |
| b_val = float(ab_m.group(2)) |
| f_fp = sp.lambdify(x, expr_fp, modules="math") |
| steps = [] |
| a_n, b_n = a_val, b_val |
| for i in range(n_iter): |
| fa, fb = f_fp(a_n), f_fp(b_n) |
| c = (a_n*fb - b_n*fa) / (fb - fa) |
| fc = f_fp(c) |
| steps.append({"iter": i+1, "a": round(a_n,8), |
| "b": round(b_n,8), "c": round(c,8), |
| "fc": round(fc,8)}) |
| if fa * fc < 0: b_n = c |
| else: a_n = c |
| step_str = "\n".join([ |
| f" Iter {s['iter']}: a={s['a']}, b={s['b']}, c={s['c']}, f(c)={s['fc']}" |
| for s in steps]) |
| return { |
| "type": "FalsePosition", |
| "result": (f"f(x) = {str(expr_fp)}\n" |
| f"Interval [{a_val},{b_val}], {n_iter} iterations\n" |
| f"VERIFIED ITERATIONS:\n{step_str}\n" |
| f"Root β {steps[-1]['c']}"), |
| "latex": f"x \\approx {steps[-1]['c']}" |
| } |
|
|
| |
| |
| |
| elif any(k in p for k in ["gauss elimination", "gauss elim"]): |
| |
| mat_m = re.search(r"\[\s*\[(.+?)\]\s*\]", p) |
| rhs_m = re.search(r"(?:rhs|=|b)\s*[=:]?\s*\[([^\]]+)\]", p) |
| if mat_m and rhs_m: |
| rows = re.findall(r"\[([^\]]+)\]", p) |
| mat_data = [[sp.Rational(v) for v in re.split(r"[,\s]+", r.strip()) if v] |
| for r in rows[:-1]] |
| rhs_data = [sp.Rational(v) for v in re.split(r"[,\s]+", rows[-1].strip()) if v] |
| A = sp.Matrix(mat_data) |
| b_vec = sp.Matrix(rhs_data) |
| sol = A.solve(b_vec) |
| sol_str = ", ".join([f"x{i+1}={sol[i]}" for i in range(len(sol))]) |
| return { |
| "type": "GaussElimination", |
| "result": f"VERIFIED SOLUTION: {sol_str}", |
| "latex": sol_str |
| } |
|
|
| |
| |
| |
| elif any(k in p for k in ["lu decomposition", "lu decomp"]): |
| rows = re.findall(r"\[([^\]]+)\]", p) |
| if rows: |
| mat_data = [[sp.Rational(v) for v in re.split(r"[,\s]+", r.strip()) if v] |
| for r in rows] |
| M = sp.Matrix(mat_data) |
| L, U, _ = M.LUdecomposition() |
| return { |
| "type": "LUDecomposition", |
| "result": (f"VERIFIED:\nL = {str(L)}\nU = {str(U)}"), |
| "latex": f"L={sp.latex(L)}, U={sp.latex(U)}" |
| } |
|
|
| |
| |
| |
| elif any(k in p for k in ["lagrange interpolation", "lagrange interp"]): |
| |
| pts = re.findall(r"\(\s*([-\d\.]+)\s*,\s*([-\d\.]+)\s*\)", p) |
| if pts: |
| data = [(sp.Rational(px), sp.Rational(py)) for px, py in pts] |
| poly = sp.interpolate(data, x) |
| poly_exp = sp.expand(poly) |
| return { |
| "type": "LagrangeInterpolation", |
| "result": f"VERIFIED polynomial: {str(poly_exp)}", |
| "latex": sp.latex(poly_exp) |
| } |
|
|
| |
| |
| |
| elif any(k in p for k in ["newton divided", "divided difference"]): |
| pts = re.findall(r"\(\s*([-\d\.]+)\s*,\s*([-\d\.]+)\s*\)", p) |
| if pts: |
| xs_v = [float(px) for px, py in pts] |
| ys_v = [float(py) for px, py in pts] |
| n_p = len(xs_v) |
| dd = [[0.0]*n_p for _ in range(n_p)] |
| for i in range(n_p): dd[i][0] = ys_v[i] |
| for j in range(1, n_p): |
| for i in range(n_p - j): |
| dd[i][j] = (dd[i+1][j-1]-dd[i][j-1])/(xs_v[i+j]-xs_v[i]) |
| coeffs = [round(dd[0][j], 8) for j in range(n_p)] |
| |
| poly_s = sp.interpolate(list(zip(xs_v, ys_v)), x) |
| return { |
| "type": "NewtonDividedDiff", |
| "result": (f"VERIFIED divided differences: {coeffs}\n" |
| f"Polynomial: {str(sp.expand(poly_s))}"), |
| "latex": sp.latex(sp.expand(poly_s)) |
| } |
|
|
| |
| |
| |
| elif any(k in p for k in ["trapezoidal", "trapezoid rule"]): |
| expr_t = get_expr() |
| ab_m2 = re.search(r"\[\s*([-\d\.]+)\s*,\s*([-\d\.]+)\s*\]", p) |
| n_m = re.search(r"n\s*[=:]\s*(\d+)", p) |
| if expr_t is not None and ab_m2 and n_m: |
| a_v = float(ab_m2.group(1)) |
| b_v = float(ab_m2.group(2)) |
| n_v = int(n_m.group(1)) |
| f_t = sp.lambdify(x, expr_t, modules="math") |
| h = (b_v - a_v) / n_v |
| s = f_t(a_v) + f_t(b_v) |
| pts_str = [f"f({round(a_v,4)})={round(f_t(a_v),6)}", ] |
| for i in range(1, n_v): |
| xi = a_v + i*h |
| pts_str.append(f"f({round(xi,4)})={round(f_t(xi),6)}") |
| pts_str.append(f"f({round(b_v,4)})={round(f_t(b_v),6)}") |
| result_val = round(h/2 * (f_t(a_v)+f_t(b_v) + 2*sum(f_t(a_v+i*h) for i in range(1,n_v))), 8) |
| return { |
| "type": "Trapezoidal", |
| "result": (f"f(x)={str(expr_t)}, [{a_v},{b_v}], n={n_v}, h={round(h,6)}\n" |
| f"Function values: {', '.join(pts_str)}\n" |
| f"VERIFIED result: {result_val}"), |
| "latex": f"\\int_{{{a_v}}}^{{{b_v}}} \\approx {result_val}" |
| } |
|
|
| |
| |
| |
| elif any(k in p for k in ["simpson"]): |
| expr_si = get_expr() |
| ab_m3 = re.search(r"\[\s*([-\d\.]+)\s*,\s*([-\d\.]+)\s*\]", p) |
| n_m2 = re.search(r"n\s*[=:]\s*(\d+)", p) |
| if expr_si is not None and ab_m3 and n_m2: |
| a_v = float(ab_m3.group(1)) |
| b_v = float(ab_m3.group(2)) |
| n_v = int(n_m2.group(1)) |
| if n_v % 2 != 0: n_v += 1 |
| f_si = sp.lambdify(x, expr_si, modules="math") |
| h = (b_v - a_v) / n_v |
| s = f_si(a_v) + f_si(b_v) |
| for i in range(1, n_v): |
| s += (4 if i % 2 != 0 else 2) * f_si(a_v + i*h) |
| result_val = round(h/3 * s, 8) |
| return { |
| "type": "Simpsons", |
| "result": (f"f(x)={str(expr_si)}, [{a_v},{b_v}], n={n_v}, h={round(h,6)}\n" |
| f"VERIFIED result: {result_val}"), |
| "latex": f"\\int_{{{a_v}}}^{{{b_v}}} \\approx {result_val}" |
| } |
|
|
| |
| |
| |
| elif any(k in p for k in ["euler method", "euler's method"]): |
| rhs_str = get_ode_rhs() |
| x0_em = re.search(r"x\s*0?\s*[=:]\s*([-\d\.]+)", p) |
| y0_em = re.search(r"y\s*[=\(]\s*0?\s*\)?\s*[=:]\s*([-\d\.]+)", p) |
| h_val = get_h() |
| n_steps = get_iters(default=5) |
| if rhs_str and x0_em and y0_em: |
| x_s, y_s = sp.symbols('x y') |
| rhs_expr_ode = parse_expr(clean(rhs_str), transformations=tfms, |
| local_dict={**ld, "y": y_s}) |
| f_ode = sp.lambdify((x_s, y_s), rhs_expr_ode, modules="math") |
| xn_e, yn_e = float(x0_em.group(1)), float(y0_em.group(1)) |
| steps = [] |
| for i in range(n_steps): |
| yn1 = yn_e + h_val * f_ode(xn_e, yn_e) |
| xn_e += h_val |
| steps.append({"n": i+1, "x": round(xn_e,6), "y": round(yn1,8)}) |
| yn_e = yn1 |
| step_str = "\n".join([f" Step {s['n']}: x={s['x']}, y={s['y']}" for s in steps]) |
| final_y_e = steps[-1]['y'] |
| return { |
| "type": "EulersMethod", |
| "result": (f"dy/dx = {rhs_str}, h={h_val}, {n_steps} steps\n" |
| f"VERIFIED ITERATIONS (USE THESE EXACT VALUES):\n{step_str}\n" |
| f"FINAL ANSWER: y({steps[-1]['x']}) = {final_y_e} β USE THIS EXACTLY"), |
| "latex": f"y_{{{n_steps}}} = {final_y_e}" |
| } |
|
|
| |
| |
| |
| elif any(k in p for k in ["runge-kutta", "runge kutta", "rk4"]): |
| rhs_str = get_ode_rhs() |
| x0_rk = re.search(r"x\s*0?\s*[=:]\s*([-\d\.]+)", p) |
| y0_rk = re.search(r"y\s*[=\(]\s*0?\s*\)?\s*[=:]\s*([-\d\.]+)", p) |
| h_val = get_h() |
| n_steps = get_iters(default=3) |
| if rhs_str and x0_rk and y0_rk: |
| x_s, y_s = sp.symbols('x y') |
| rhs_expr_rk = parse_expr(clean(rhs_str), transformations=tfms, |
| local_dict={**ld, "y": y_s}) |
| f_rk = sp.lambdify((x_s, y_s), rhs_expr_rk, modules="math") |
| xn_r, yn_r = float(x0_rk.group(1)), float(y0_rk.group(1)) |
| steps = [] |
| for i in range(n_steps): |
| k1 = h_val * f_rk(xn_r, yn_r) |
| k2 = h_val * f_rk(xn_r+h_val/2, yn_r+k1/2) |
| k3 = h_val * f_rk(xn_r+h_val/2, yn_r+k2/2) |
| k4 = h_val * f_rk(xn_r+h_val, yn_r+k3) |
| yn1 = yn_r + (k1+2*k2+2*k3+k4)/6 |
| xn_r += h_val |
| steps.append({"n": i+1, "x": round(xn_r,6), |
| "k1": round(k1,8), "k2": round(k2,8), |
| "k3": round(k3,8), "k4": round(k4,8), |
| "y": round(yn1,8)}) |
| yn_r = yn1 |
| step_str = "\n".join([ |
| f" Step {s['n']}: x={s['x']}, k1={s['k1']}, k2={s['k2']}, k3={s['k3']}, k4={s['k4']}, y={s['y']}" |
| for s in steps]) |
| final_y = steps[-1]['y'] |
| return { |
| "type": "RungeKutta4", |
| "result": (f"dy/dx={rhs_str}, h={h_val}, {n_steps} steps\n" |
| f"VERIFIED ITERATIONS (USE THESE EXACT k VALUES):\n{step_str}\n" |
| f"FINAL ANSWER: y({round(xn_r,4)}) = {final_y} β USE THIS EXACTLY"), |
| "latex": f"y_{{{n_steps}}} = {final_y}" |
| } |
|
|
| |
| elif any(k in p for k in [ |
| "gcd", "greatest common divisor", "hcf", |
| "lcm", "least common multiple", |
| "prime factor", "factoriz", "factori", |
| "is prime", "isprime", "prime or not", "check prime", |
| "totient", "euler's totient", |
| "number of divisor", "sum of divisor", "divisors of", |
| "mobius", "mΓΆbius", |
| "diophantine", |
| "chinese remainder", "crt", |
| "fermat", "wilson", |
| "quadratic residu", "legendre", |
| "primitive root", |
| "linear congruence", "congruence", "β‘", |
| "euler's theorem", "euler theorem", |
| ]) or re.search(r'\bis\s+\d+\s+prime\b', p): |
| import math as _math |
|
|
| def _nums(text): |
| return [int(n) for n in re.findall(r'\b\d+\b', text)] |
|
|
| x_d, y_d = sp.symbols('x y') |
|
|
| try: |
| |
| if any(k in p for k in ["gcd","greatest common divisor","hcf"]): |
| nums = _nums(p) |
| if len(nums) >= 2: |
| a,b = nums[0],nums[1] |
| g = int(sp.gcd(a,b)) |
| |
| old_r,r = a,b; old_s,s = 1,0; old_t,t2 = 0,1 |
| while r: |
| q=old_r//r; old_r,r=r,old_r-q*r |
| old_s,s=s,old_s-q*s; old_t,t2=t2,old_t-q*t2 |
| result_str = (f"gcd({a},{b}) = {old_r}\n" |
| f"Extended Euclidean: {a}Γ({old_s}) + {b}Γ({old_t}) = {old_r}\n" |
| f"Verify: {a*old_s + b*old_t} = {old_r} β
") |
| return {"type":"GCD","result":result_str, |
| "latex":f"\\gcd({a},{b})={old_r}"} |
|
|
| |
| elif any(k in p for k in ["lcm","least common multiple"]): |
| nums = _nums(p) |
| if len(nums) >= 2: |
| l = int(sp.lcm(nums[0],nums[1])) |
| g = int(sp.gcd(nums[0],nums[1])) |
| return {"type":"LCM", |
| "result":f"lcm({nums[0]},{nums[1]}) = {l}, gcd = {g}", |
| "latex":f"\\text{{lcm}}({nums[0]},{nums[1]})={l}"} |
|
|
| |
| elif any(k in p for k in ["prime factor","factoriz","factori"]): |
| nums = _nums(p) |
| if nums: |
| f_dict = sp.factorint(nums[0]) |
| f_str = " Γ ".join([f"{pp}^{e}" if e>1 else str(pp) for pp,e in f_dict.items()]) |
| return {"type":"PrimeFactorization", |
| "result":f"{nums[0]} = {f_str}", |
| "latex":f"{nums[0]} = {f_str}"} |
|
|
| |
| elif any(k in p for k in ["is prime","isprime","prime or not","check prime"]) or re.search(r'\bis\s+\d+\s+prime\b',p): |
| nums = _nums(p) |
| if nums: |
| n_val = nums[0] |
| is_p = sp.isprime(n_val) |
| ans = "PRIME" if is_p else "COMPOSITE (NOT PRIME)" |
| return {"type":"PrimeCheck", |
| "result":f"{n_val} is {ans}", |
| "latex":f"{n_val}\\text{{ is }}{ans}"} |
|
|
| |
| elif any(k in p for k in ["totient","euler's totient"]): |
| nums = _nums(p) |
| if nums: |
| phi = int(sp.totient(nums[0])) |
| f_dict = sp.factorint(nums[0]) |
| return {"type":"EulerTotient", |
| "result":f"Ο({nums[0]}) = {phi}, factorization = {f_dict}", |
| "latex":f"\\phi({nums[0]})={phi}"} |
|
|
| |
| elif any(k in p for k in ["number of divisor","sum of divisor","divisors of","tau","sigma"]): |
| nums = _nums(p) |
| if nums: |
| divs = sp.divisors(nums[0]) |
| return {"type":"DivisorFunctions", |
| "result":f"divisors({nums[0]}) = {divs}, Ο = {len(divs)}, Ο = {sum(divs)}", |
| "latex":f"\\tau({nums[0]})={len(divs)}, \\sigma({nums[0]})={sum(divs)}"} |
|
|
| |
| elif any(k in p for k in ["mobius","mΓΆbius"]): |
| nums = _nums(p) |
| if nums: |
| mu = sp.mobius(nums[0]) |
| return {"type":"Mobius", |
| "result":f"ΞΌ({nums[0]}) = {mu}", |
| "latex":f"\\mu({nums[0]})={mu}"} |
|
|
| |
| elif "diophantine" in p: |
| m = re.search(r"(\d+)\s*x\s*[+\-]\s*(\d+)\s*y\s*=\s*(\d+)",p) |
| if m: |
| a_d,b_d,c_d = int(m.group(1)),int(m.group(2)),int(m.group(3)) |
| g = int(sp.gcd(a_d,b_d)) |
| if c_d%g == 0: |
| sol = sp.diophantine(sp.Eq(a_d*x_d+b_d*y_d, c_d)) |
| return {"type":"Diophantine", |
| "result":f"{a_d}x+{b_d}y={c_d}: general solution={sol}, gcd={g}", |
| "latex":str(sol)} |
| else: |
| return {"type":"Diophantine", |
| "result":f"No integer solution: gcd({a_d},{b_d})={g} does not divide {c_d}", |
| "latex":"\\text{No solution}"} |
|
|
| |
| elif any(k in p for k in ["chinese remainder","crt"]): |
| pairs = re.findall(r'x\s*[β‘=]\s*(\d+)\s*(?:mod|modulo|\(mod)\s*(\d+)',p) |
| if len(pairs) >= 2: |
| remainders = [int(r) for r,m in pairs] |
| moduli = [int(m) for r,m in pairs] |
| sol = sp.ntheory.modular.crt(moduli, remainders) |
| verify = [f"{sol[0]}%{m}={sol[0]%m}" for m in moduli] |
| return {"type":"CRT", |
| "result":f"x β‘ {sol[0]} (mod {sol[1]}), verify: {verify}", |
| "latex":f"x\\equiv {sol[0]}\\pmod{{{sol[1]}}}"} |
|
|
| |
| elif "fermat" in p: |
| nums = _nums(p) |
| if len(nums) >= 2: |
| a_f,p_f = nums[0],nums[1] |
| if sp.isprime(p_f): |
| r = pow(a_f,p_f-1,p_f) |
| return {"type":"FermatTheorem", |
| "result":f"{a_f}^({p_f}-1) mod {p_f} = {r} β‘ 1 (mod {p_f})", |
| "latex":f"{a_f}^{{{p_f-1}}}\\equiv 1\\pmod{{{p_f}}}"} |
|
|
| |
| elif "euler" in p and ("theorem" in p or "theorem" in p): |
| nums = _nums(p) |
| if len(nums) >= 2: |
| a_e,n_e = nums[0],nums[1] |
| phi = int(sp.totient(n_e)) |
| r = pow(a_e,phi,n_e) |
| return {"type":"EulerTheorem", |
| "result":f"Ο({n_e})={phi}, {a_e}^{phi} mod {n_e} = {r} β‘ 1 (mod {n_e})", |
| "latex":f"{a_e}^{{\\phi({n_e})}}\\equiv 1\\pmod{{{n_e}}}"} |
|
|
| |
| elif "wilson" in p: |
| nums = _nums(p) |
| if nums: |
| p_w = nums[0] |
| val = _math.factorial(p_w-1)%p_w |
| return {"type":"WilsonTheorem", |
| "result":f"({p_w}-1)! mod {p_w} = {val} β‘ -1 (mod {p_w})", |
| "latex":f"({p_w}-1)!\\equiv -1\\pmod{{{p_w}}}"} |
|
|
| |
| elif any(k in p for k in ["congruence","linear congruence"]) or re.search(r'\d+\s*x\s*[β‘=]',p): |
| m = re.search(r"(\d+)\s*x\s*[β‘=]\s*(\d+)\s*(?:\(mod|mod|modulo)\s*(\d+)",p) |
| if m: |
| a_c,b_c,n_c = int(m.group(1)),int(m.group(2)),int(m.group(3)) |
| g = int(sp.gcd(a_c,n_c)) |
| if b_c%g != 0: |
| return {"type":"LinearCongruence", |
| "result":f"No solution: gcd({a_c},{n_c})={g} β€ {b_c}", |
| "latex":"\\text{No solution}"} |
| sols = [i for i in range(n_c) if (a_c*i)%n_c==b_c%n_c] |
| return {"type":"LinearCongruence", |
| "result":f"{a_c}x β‘ {b_c} (mod {n_c}): x β‘ {sols} (mod {n_c}), {g} solution(s)", |
| "latex":f"x\\equiv {sols[0]}\\pmod{{{n_c//g}}}"} |
|
|
| |
| elif any(k in p for k in ["quadratic residu","quadratic non"]): |
| nums = _nums(p) |
| if nums: |
| p_q = nums[0] |
| qr = sorted(set([pow(i,2,p_q) for i in range(1,p_q)])) |
| qnr = [i for i in range(1,p_q) if i not in qr] |
| return {"type":"QuadraticResidues", |
| "result":f"QR mod {p_q} = {qr}, QNR mod {p_q} = {qnr}", |
| "latex":f"QR\\pmod{{{p_q}}}={qr}"} |
|
|
| |
| elif "legendre" in p: |
| m = re.search(r"\(\s*(\d+)\s*/\s*(\d+)\s*\)",p) |
| if m: |
| a_l,p_l = int(m.group(1)),int(m.group(2)) |
| val = 1 if pow(a_l,(p_l-1)//2,p_l)==1 else (-1 if a_l%p_l!=0 else 0) |
| meaning = "QR (quadratic residue)" if val==1 else ("QNR (non-residue)" if val==-1 else "0 (divisible)") |
| return {"type":"LegendreSymbol", |
| "result":f"({a_l}/{p_l}) = {val} β {a_l} is {meaning} mod {p_l}", |
| "latex":f"\\left(\\frac{{{a_l}}}{{{p_l}}}\\right)={val}"} |
|
|
| |
| elif "primitive root" in p: |
| nums = _nums(p) |
| if nums: |
| pr = sp.ntheory.primitive_root(nums[0]) |
| return {"type":"PrimitiveRoot", |
| "result":f"primitive_root({nums[0]}) = {pr}", |
| "latex":f"g={pr}"} |
|
|
| except Exception: |
| pass |
|
|
| |
| elif any(k in p for k in ["solve", "roots", "find x"]): |
| raw = re.sub(r"(solve|find x|roots of|roots|the equation)", "", p) |
| raw = raw.strip().strip(":").strip() |
| if "=" in raw: |
| lhs_s, rhs_s = raw.split("=", 1) |
| lhs_e = parse_expr(clean(lhs_s), transformations=tfms, local_dict=ld) |
| rhs_e = parse_expr(clean(rhs_s), transformations=tfms, local_dict=ld) |
| expr = lhs_e - rhs_e |
| else: |
| expr = parse_expr(clean(raw), transformations=tfms, local_dict=ld) |
| if x in expr.free_symbols: |
| sol = sp.solve(expr, x) |
| sol_latex = ", ".join([sp.latex(s) for s in sol]) |
| return { |
| "type": "Equation", |
| "result": str(sol), |
| "latex": r"x \in \{" + sol_latex + r"\}" |
| } |
|
|
| |
| elif any(k in p for k in [ |
| |
| "supremum", "infimum", "least upper bound", "greatest lower bound", |
| "lub", "glb", "archimedean", "bounded set", "completeness", |
| "cartesian product", "density of rational", "real number system", |
| "field propert", "order propert", |
| |
| "sequence", "cauchy sequence", "bounded sequence", |
| "monotone sequence", "subsequence", "bolzano", "weierstrass", |
| |
| "ratio test", "root test", "integral test", "comparison test", |
| "alternating series", "leibniz test", "absolute convergence", |
| "conditional convergence", "cauchy criterion", |
| "pointwise convergence", "uniform convergence", |
| "weierstrass m-test", "m-test", |
| |
| "epsilon delta", "epsilon-delta", "uniform continuity", |
| "intermediate value", "extreme value theorem", |
| |
| "mean value theorem", "rolle", "taylor's theorem", |
| "lhopital", "l'hopital", |
| |
| "riemann sum", "riemann integral", "upper sum", "lower sum", |
| "darboux", "integrability", "fundamental theorem of calculus", |
| ]): |
| try: |
| n_s = sp.Symbol('n', positive=True) |
|
|
| |
| if any(k in p for k in ["sequence","limit of sequence"]): |
| |
| m = re.search(r"(?:of|for|lim)\s+(.+?)\s*(?:as|when|$)", p) |
| if m: |
| raw = clean(m.group(1)) |
| try: |
| expr_s = parse_expr(raw, transformations=tfms, |
| local_dict={**ld, "n": n_s}) |
| lim_val = sp.limit(expr_s, n_s, sp.oo) |
| return { |
| "type": "SequenceLimit", |
| "result": f"lim({m.group(1)}) as nββ = {lim_val}", |
| "latex": f"\\lim_{{n\\to\\infty}} = {sp.latex(lim_val)}" |
| } |
| except Exception: |
| pass |
|
|
| |
| elif any(k in p for k in ["series","sum of"]): |
| m = re.search(r"(?:sum\s+of|series\s+(?:of\s+)?|convergence\s+of)\s*(.+?)(?:\s+from|\s+using|\s+by|$)", p) |
| if m: |
| raw = m.group(1).strip() |
| raw = re.sub(r"^series\s+sum\s+of\s+", "", raw) |
| raw = re.sub(r"^series\s+of\s+", "", raw) |
| raw = re.sub(r"^sum\s+of\s+", "", raw) |
| raw = re.sub(r"^of\s+", "", raw) |
| raw = clean(raw) |
| try: |
| expr_ser = parse_expr(raw, transformations=tfms, |
| local_dict={**ld, "n": n_s}) |
| s_val = sp.summation(expr_ser, (n_s, 1, sp.oo)) |
| converges = s_val.is_finite |
| return { |
| "type": "SeriesConvergence", |
| "result": (f"Series sum = {s_val}, " |
| f"Converges: {converges}"), |
| "latex": f"\\sum_{{n=1}}^{{\\infty}} = {sp.latex(s_val)}" |
| } |
| except Exception: |
| pass |
|
|
| |
| elif any(k in p for k in ["taylor", "maclaurin"]): |
| funcs = { |
| "sin": sp.sin(x), "cos": sp.cos(x), |
| "exp": sp.exp(x), "e^x": sp.exp(x), |
| "ln": sp.log(1+x), "log": sp.log(1+x), |
| "tan": sp.tan(x) |
| } |
| for fname, fexpr in funcs.items(): |
| if fname in p: |
| n_terms = 6 |
| ts = sp.series(fexpr, x, 0, n_terms) |
| return { |
| "type": "TaylorSeries", |
| "result": f"Taylor series of {fname}: {ts}", |
| "latex": sp.latex(ts) |
| } |
|
|
| |
| elif any(k in p for k in ["lhopital","l'hopital"]): |
| m = re.search(r"(?:of|for)\s+(.+?)\s*(?:as|at|when)\s*x\s*[ββ=]\s*([\d\.]+|inf)", p) |
| if m: |
| raw = clean(m.group(1)) |
| pt_str = m.group(2) |
| pt = sp.oo if pt_str in ("inf","infinity") else sp.sympify(pt_str) |
| try: |
| expr_lh = parse_expr(raw, transformations=tfms, local_dict=ld) |
| lim_val = sp.limit(expr_lh, x, pt) |
| return { |
| "type": "LHopital", |
| "result": f"lim({m.group(1)}) as xβ{pt_str} = {lim_val}", |
| "latex": f"\\lim_{{x\\to {pt_str}}} = {sp.latex(lim_val)}" |
| } |
| except Exception: |
| pass |
|
|
| |
| elif any(k in p for k in ["riemann","riemann integral","riemann sum"]): |
| |
| m = re.search(r"(?:of|for)\s+(.+?)\s+(?:from|on)\s+([\d\.]+)\s+to\s+([\d\.]+)", p) |
| if m: |
| raw = clean(m.group(1)) |
| a_v = sp.sympify(m.group(2)) |
| b_v = sp.sympify(m.group(3)) |
| try: |
| expr_r = parse_expr(raw, transformations=tfms, local_dict=ld) |
| result_r = sp.integrate(expr_r, (x, a_v, b_v)) |
| return { |
| "type": "RiemannIntegral", |
| "result": f"β«({m.group(1)}) from {a_v} to {b_v} = {result_r}", |
| "latex": f"\\int_{{{a_v}}}^{{{b_v}}} = {sp.latex(result_r)}" |
| } |
| except Exception: |
| pass |
|
|
| except Exception: |
| pass |
|
|
| |
| elif any(k in p for k in [ |
| "curvature", "torsion", "tangent vector", "normal vector", |
| "binormal", "serret-frenet", "frenet", "osculating", |
| "arc length", "space curve", "plane curve", "helix", "helices", |
| "evolute", "involute", "rectifying plane", |
| "first fundamental form", "second fundamental form", |
| "fundamental form", "gaussian curvature", "mean curvature", |
| "principal curvature", "geodesic", |
| "parametric surface", "christoffel", "covariant derivative", |
| "contravariant", "metric tensor", |
| ]): |
| t_s = sp.Symbol('t') |
| u_s, v_s = sp.symbols('u v') |
| try: |
|
|
| |
| if "curvature" in p and not any(k in p for k in ["gaussian","mean","space","torsion"]): |
| |
| m = re.search(r"(?:of|for)\s+y\s*=\s*(.+?)(?:\s+at|\s*$)", p) |
| pt_m = re.search(r"at\s+x\s*[=:]\s*([-\d\.]+)", p) |
| if m: |
| raw = clean(m.group(1).strip()) |
| expr_c = parse_expr(raw, transformations=tfms, local_dict=ld) |
| dy = sp.diff(expr_c, x) |
| d2y = sp.diff(expr_c, x, 2) |
| kappa_expr = sp.Abs(d2y) / (1 + dy**2)**sp.Rational(3,2) |
| if pt_m: |
| pt_val = float(pt_m.group(1)) |
| kappa_val = sp.simplify(kappa_expr.subs(x, pt_val)) |
| return { |
| "type": "Curvature", |
| "result": f"ΞΊ at x={pt_val}: y'={dy.subs(x,pt_val)}, y''={d2y.subs(x,pt_val)}, ΞΊ={kappa_val}", |
| "latex": f"\\kappa = {sp.latex(kappa_val)}" |
| } |
| else: |
| return { |
| "type": "Curvature", |
| "result": f"ΞΊ(x) = {sp.simplify(kappa_expr)}", |
| "latex": f"\\kappa = {sp.latex(sp.simplify(kappa_expr))}" |
| } |
|
|
| |
| elif "arc length" in p: |
| m = re.search(r"(?:of|for)\s+y\s*=\s*(.+?)\s+from\s+([-\d\.]+)\s+to\s+([-\d\.]+)", p) |
| if m: |
| raw = clean(m.group(1).strip()) |
| a_v = sp.sympify(m.group(2)) |
| b_v = sp.sympify(m.group(3)) |
| expr_al = parse_expr(raw, transformations=tfms, local_dict=ld) |
| dy = sp.diff(expr_al, x) |
| integrand = sp.sqrt(1 + dy**2) |
| L = sp.integrate(integrand, (x, a_v, b_v)) |
| L_simplified = sp.simplify(L) |
| return { |
| "type": "ArcLength", |
| "result": f"L = β«β(1+y'Β²)dx from {a_v} to {b_v} = {L_simplified}", |
| "latex": f"L = {sp.latex(L_simplified)}" |
| } |
|
|
| |
| elif any(k in p for k in ["space curve","torsion","frenet","serret"]): |
| |
| pts = re.findall(r"\(\s*(.+?)\s*,\s*(.+?)\s*,\s*(.+?)\s*\)", p) |
| pt_m = re.search(r"at\s+t\s*[=:]\s*([-\d\.]+)", p) |
| if pts: |
| rx = parse_expr(clean(pts[0][0]), transformations=tfms, local_dict={**ld, "t": t_s}) |
| ry = parse_expr(clean(pts[0][1]), transformations=tfms, local_dict={**ld, "t": t_s}) |
| rz = parse_expr(clean(pts[0][2]), transformations=tfms, local_dict={**ld, "t": t_s}) |
| r_vec = sp.Matrix([rx, ry, rz]) |
| dr = r_vec.diff(t_s) |
| d2r = dr.diff(t_s) |
| d3r = d2r.diff(t_s) |
| speed = sp.sqrt(dr.dot(dr)) |
| cross = dr.cross(d2r) |
| kappa = sp.simplify(sp.sqrt(cross.dot(cross)) / speed**3) |
| torsion_val = sp.simplify(cross.dot(d3r) / cross.dot(cross)) |
| t_val = float(pt_m.group(1)) if pt_m else 0 |
| k_at = sp.simplify(kappa.subs(t_s, t_val)) |
| tau_at = sp.simplify(torsion_val.subs(t_s, t_val)) |
| T_vec = sp.simplify(dr / speed) |
| return { |
| "type": "FrenetSerret", |
| "result": (f"r(t)={pts[0]}, at t={t_val}:\n" |
| f"ΞΊ = {k_at}, Ο = {tau_at}\n" |
| f"T = {T_vec.subs(t_s,t_val).T}"), |
| "latex": f"\\kappa={sp.latex(k_at)}, \\tau={sp.latex(tau_at)}" |
| } |
|
|
| |
| elif "first fundamental form" in p: |
| pts = re.findall(r"\(\s*(.+?)\s*,\s*(.+?)\s*,\s*(.+?)\s*\)", p) |
| if pts: |
| rx = parse_expr(clean(pts[0][0]), transformations=tfms, local_dict={**ld, "u": u_s, "v": v_s}) |
| ry = parse_expr(clean(pts[0][1]), transformations=tfms, local_dict={**ld, "u": u_s, "v": v_s}) |
| rz = parse_expr(clean(pts[0][2]), transformations=tfms, local_dict={**ld, "u": u_s, "v": v_s}) |
| r_vec = sp.Matrix([rx, ry, rz]) |
| ru = r_vec.diff(u_s) |
| rv = r_vec.diff(v_s) |
| E = sp.simplify(ru.dot(ru)) |
| F = sp.simplify(ru.dot(rv)) |
| G = sp.simplify(rv.dot(rv)) |
| return { |
| "type": "FirstFundamentalForm", |
| "result": f"E={E}, F={F}, G={G}, dsΒ²={E}duΒ²+{2*F}dudv+{G}dvΒ²", |
| "latex": f"E={sp.latex(E)}, F={sp.latex(F)}, G={sp.latex(G)}" |
| } |
|
|
| |
| elif any(k in p for k in ["gaussian curvature","mean curvature"]): |
| pts = re.findall(r"\(\s*(.+?)\s*,\s*(.+?)\s*,\s*(.+?)\s*\)", p) |
| if pts: |
| rx = parse_expr(clean(pts[0][0]), transformations=tfms, local_dict={**ld, "u": u_s, "v": v_s}) |
| ry = parse_expr(clean(pts[0][1]), transformations=tfms, local_dict={**ld, "u": u_s, "v": v_s}) |
| rz = parse_expr(clean(pts[0][2]), transformations=tfms, local_dict={**ld, "u": u_s, "v": v_s}) |
| r_vec = sp.Matrix([rx, ry, rz]) |
| ru = r_vec.diff(u_s); rv = r_vec.diff(v_s) |
| E = sp.simplify(ru.dot(ru)); F = sp.simplify(ru.dot(rv)); G = sp.simplify(rv.dot(rv)) |
| n = ru.cross(rv); N = sp.simplify(n / sp.sqrt(n.dot(n))) |
| L = sp.simplify(N.dot(ru.diff(u_s))) |
| M = sp.simplify(N.dot(ru.diff(v_s))) |
| Nv = sp.simplify(N.dot(rv.diff(v_s))) |
| K = sp.simplify((L*Nv - M**2)/(E*G - F**2)) |
| H = sp.simplify((E*Nv - 2*F*M + G*L)/(2*(E*G - F**2))) |
| return { |
| "type": "GaussianCurvature", |
| "result": f"K (Gaussian) = {K}, H (Mean) = {H}", |
| "latex": f"K={sp.latex(K)}, H={sp.latex(H)}" |
| } |
|
|
| except Exception: |
| pass |
|
|
| |
| elif any(k in p for k in [ |
| "continuity equation", "equation of continuity", |
| "streamline", "stream function", "stream line", |
| "velocity potential", "irrotational", "rotational motion", |
| "lagrangian", "eulerian", "vortex", "vorticity", |
| "path line", "streak line", |
| "bernoulli", "euler's equation", "euler equation of motion", |
| "torricelli", "flow rate", "discharge", |
| "reynolds number", "reynolds", |
| "hydrostatic pressure", "pressure at depth", |
| "hydrostatic", "buoyancy", "archimedes", |
| "laminar flow", "turbulent flow", "viscous flow", |
| "incompressible fluid", "steady flow", |
| "navier-stokes", "navier stokes", |
| "stokes stream function", "complex velocity potential", |
| "source", "sink", "doublet", |
| "milne thomson", "blasius theorem", |
| "dimensional analysis", "buckingham pi", |
| ]): |
| try: |
| x_h, y_h = sp.symbols('x y') |
| g_val = sp.Rational(981, 100) |
|
|
| |
| if any(k in p for k in ["continuity equation","equation of continuity"]): |
| nums = [float(n) for n in re.findall(r"[-]?\d+\.?\d*", p)] |
| if len(nums) >= 3: |
| A1_v,v1_v,A2_v = nums[0],nums[1],nums[2] |
| v2_v = round(A1_v*v1_v/A2_v, 6) |
| Q_v = round(A1_v*v1_v, 6) |
| return { |
| "type": "ContinuityEq", |
| "result": (f"A1={A1_v}, v1={v1_v}, A2={A2_v}\n" |
| f"v2 = A1*v1/A2 = {v2_v} m/s\n" |
| f"Flow rate Q = A1*v1 = {Q_v} mΒ³/s"), |
| "latex": f"v_2 = {v2_v}\\text{{ m/s}}" |
| } |
|
|
| |
| elif any(k in p for k in ["reynolds number","reynolds"]): |
| nums = [float(n) for n in re.findall(r"[-]?\d+\.?\d*", p)] |
| if len(nums) >= 4: |
| rho_v,v_v,D_v,mu_v = nums[0],nums[1],nums[2],nums[3] |
| Re = round(rho_v*v_v*D_v/mu_v, 2) |
| flow = "Turbulent (Re>4000)" if Re>4000 else ("Transitional (2300<Re<4000)" if Re>2300 else "Laminar (Re<2300)") |
| return { |
| "type": "ReynoldsNumber", |
| "result": f"Re = ΟvD/ΞΌ = {rho_v}Γ{v_v}Γ{D_v}/{mu_v} = {Re} β {flow}", |
| "latex": f"Re = {Re}" |
| } |
|
|
| |
| elif "bernoulli" in p: |
| nums = [float(n) for n in re.findall(r"[-]?\d+\.?\d*", p)] |
| if len(nums) >= 5: |
| P1_v,v1_v,h1_v,v2_v,h2_v = nums[0],nums[1],nums[2],nums[3],nums[4] |
| rho_v = 1000 |
| P2_v = round(P1_v + 0.5*rho_v*(v1_v**2-v2_v**2) + rho_v*9.81*(h1_v-h2_v), 4) |
| return { |
| "type": "Bernoulli", |
| "result": (f"P1+Β½Οv1Β²+Οgh1 = P2+Β½Οv2Β²+Οgh2\n" |
| f"P2 = {P2_v} Pa"), |
| "latex": f"P_2 = {P2_v}\\text{{ Pa}}" |
| } |
|
|
| |
| elif "torricelli" in p: |
| nums = [float(n) for n in re.findall(r"[-]?\d+\.?\d*", p)] |
| if nums: |
| h_v = nums[0] |
| v_torr = round((2*9.81*h_v)**0.5, 6) |
| return { |
| "type": "Torricelli", |
| "result": f"v = β(2gh) = β(2Γ9.81Γ{h_v}) = {v_torr} m/s", |
| "latex": f"v = {v_torr}\\text{{ m/s}}" |
| } |
|
|
| |
| elif any(k in p for k in ["hydrostatic pressure","pressure at depth"]): |
| nums = [float(n) for n in re.findall(r"[-]?\d+\.?\d*", p)] |
| if nums: |
| h_v = nums[0] |
| rho_v = 1000 |
| P_gauge = round(rho_v*9.81*h_v, 4) |
| P_abs = round(101325 + P_gauge, 4) |
| return { |
| "type": "HydrostaticPressure", |
| "result": (f"At depth h={h_v}m:\n" |
| f"Gauge pressure = Οgh = {P_gauge} Pa\n" |
| f"Absolute pressure = P0+Οgh = {P_abs} Pa"), |
| "latex": f"P = P_0 + \\rho g h = {P_abs}\\text{{ Pa}}" |
| } |
|
|
| |
| elif any(k in p for k in ["flow rate","discharge"]): |
| nums = [float(n) for n in re.findall(r"[-]?\d+\.?\d*", p)] |
| if len(nums) >= 2: |
| A_v, v_v = nums[0], nums[1] |
| Q_v = round(A_v*v_v, 8) |
| return { |
| "type": "FlowRate", |
| "result": f"Q = AΓv = {A_v}Γ{v_v} = {Q_v} mΒ³/s", |
| "latex": f"Q = {Q_v}\\text{{ mΒ³/s}}" |
| } |
|
|
| |
| elif "velocity potential" in p: |
| m = re.search(r"(?:phi|Ο|potential)\s*=\s*(.+?)(?:\s|$)", p) |
| if m: |
| raw = clean(m.group(1)) |
| phi_expr = parse_expr(raw, transformations=tfms, local_dict={**ld,"x":x_h,"y":y_h}) |
| u_comp = sp.diff(phi_expr, x_h) |
| v_comp = sp.diff(phi_expr, y_h) |
| lap = sp.diff(phi_expr,x_h,2) + sp.diff(phi_expr,y_h,2) |
| return { |
| "type": "VelocityPotential", |
| "result": (f"Ο={str(phi_expr)}, u=βΟ/βx={u_comp}, v=βΟ/βy={v_comp}\n" |
| f"βΒ²Ο={sp.simplify(lap)} (irrotational: {sp.simplify(lap)==0})"), |
| "latex": f"\\nabla^2\\phi = {sp.latex(sp.simplify(lap))}" |
| } |
|
|
| except Exception: |
| pass |
|
|
| |
| elif any(k in p for k in ["matrix", "determinant", "eigenvalue", |
| "eigenvector", "det(", "inverse matrix", "rank"]): |
| rows = re.findall(r"\[([^\[\]]+)\]", p) |
| if rows: |
| try: |
| matrix_data = [ |
| [sp.Rational(value.strip()) for value in row.split(",")] |
| for row in rows |
| ] |
| if len({len(row) for row in matrix_data}) != 1: |
| raise ValueError("Matrix rows have different lengths") |
| matrix = sp.Matrix(matrix_data) |
|
|
| if "determinant" in p or "det(" in p: |
| value = sp.factor(matrix.det()) |
| return {"type": "MatrixDeterminant", "result": f"det(A) = {value}", "latex": f"\\det(A)={sp.latex(value)}"} |
| if "eigenvector" in p: |
| value = matrix.eigenvects() |
| return {"type": "Eigenvectors", "result": f"Eigenvectors: {value}", "latex": sp.latex(value)} |
| if "eigenvalue" in p: |
| value = matrix.eigenvals() |
| return {"type": "Eigenvalues", "result": f"Eigenvalues: {value}", "latex": sp.latex(value)} |
| if "inverse" in p: |
| value = matrix.inv() |
| return {"type": "MatrixInverse", "result": f"A^(-1) = {value}", "latex": sp.latex(value)} |
| if "transpose" in p: |
| value = matrix.T |
| return {"type": "MatrixTranspose", "result": f"A^T = {value}", "latex": sp.latex(value)} |
| if "rank" in p: |
| value = matrix.rank() |
| return {"type": "MatrixRank", "result": f"rank(A) = {value}", "latex": f"\\operatorname{{rank}}(A)={value}"} |
| return {"type": "Matrix", "result": f"A = {matrix}", "latex": sp.latex(matrix)} |
| except Exception: |
| pass |
|
|
| |
| elif "mod" in p or "congruence" in p: |
| congruence = re.search( |
| r"([+-]?\d+)\s*x\s*(?:β‘|=)\s*([+-]?\d+)\s*\(?(?:mod|modulo)\s*([+-]?\d+)\)?", |
| p, |
| ) |
| if congruence: |
| a_val, b_val, modulus = (int(value) for value in congruence.groups()) |
| gcd_value = math.gcd(a_val, modulus) |
| if b_val % gcd_value != 0: |
| return { |
| "type": "LinearCongruence", |
| "result": f"No solution because gcd({a_val},{modulus})={gcd_value} does not divide {b_val}.", |
| "latex": "\\text{No solution}", |
| } |
| solutions = [x_val for x_val in range(modulus) if (a_val * x_val - b_val) % modulus == 0] |
| return { |
| "type": "LinearCongruence", |
| "result": f"{a_val}x β‘ {b_val} (mod {modulus}); solutions: {solutions}", |
| "latex": "x \\equiv " + ", \\".join(str(x_val) for x_val in solutions) + f" \\pmod{{{modulus}}}", |
| } |
|
|
| remainder = re.search(r"([+-]?\d+)\s+mod\s+([+-]?\d+)", p) |
| if remainder: |
| left, right = (int(value) for value in remainder.groups()) |
| value = left % right |
| return {"type": "Modulo", "result": f"{left} mod {right} = {value}", "latex": f"{left} \\bmod {right} = {value}"} |
|
|
| except Exception: |
| pass |
|
|
| return {"type": "general", "result": None, "latex": ""} |
|
|
|
|