Spaces:
Sleeping
Sleeping
| """ | |
| Mathematical computation tools for the GAIA Agent. | |
| Includes symbolic math, matrix operations, calculator, and statistics. | |
| """ | |
| import json | |
| from langchain_core.tools import tool | |
| def symbolic_math(expression: str, operation: str = "simplify", variable: str = "x") -> str: | |
| """Perform symbolic mathematics operations using SymPy. | |
| Operations available: | |
| - simplify: Simplify an expression | |
| - expand: Expand an expression | |
| - factor: Factor an expression | |
| - solve: Solve an equation (set equal to 0) | |
| - differentiate: Compute derivative with respect to variable | |
| - integrate: Compute indefinite integral with respect to variable | |
| - limit: Compute limit as variable approaches 0 (use expression like "sin(x)/x") | |
| - series: Compute Taylor series expansion | |
| Args: | |
| expression: Mathematical expression (use ** for power, e.g., "x**2 + 2*x + 1") | |
| operation: One of: simplify, expand, factor, solve, differentiate, integrate, limit, series | |
| variable: Variable to use for calculus operations (default: "x") | |
| """ | |
| try: | |
| import sympy as sp | |
| from sympy.parsing.sympy_parser import parse_expr, standard_transformations, implicit_multiplication_application | |
| # Define common symbols | |
| x, y, z, t, n, a, b, c = sp.symbols('x y z t n a b c') | |
| symbol_map = {'x': x, 'y': y, 'z': z, 't': t, 'n': n, 'a': a, 'b': b, 'c': c} | |
| # Get the main variable | |
| var = symbol_map.get(variable, sp.Symbol(variable)) | |
| # Parse the expression with implicit multiplication support | |
| transformations = standard_transformations + (implicit_multiplication_application,) | |
| expr = parse_expr(expression, local_dict=symbol_map, transformations=transformations) | |
| operation = operation.lower().strip() | |
| if operation == "simplify": | |
| result = sp.simplify(expr) | |
| elif operation == "expand": | |
| result = sp.expand(expr) | |
| elif operation == "factor": | |
| result = sp.factor(expr) | |
| elif operation == "solve": | |
| result = sp.solve(expr, var) | |
| elif operation in ("differentiate", "diff", "derivative"): | |
| result = sp.diff(expr, var) | |
| elif operation in ("integrate", "integral"): | |
| result = sp.integrate(expr, var) | |
| elif operation == "limit": | |
| result = sp.limit(expr, var, 0) | |
| elif operation == "series": | |
| result = sp.series(expr, var, 0, 6) | |
| else: | |
| return f"Unknown operation: {operation}. Available: simplify, expand, factor, solve, differentiate, integrate, limit, series" | |
| return f"Input: {expression}\nOperation: {operation}\nResult: {result}" | |
| except ImportError: | |
| return "Error: SymPy is not installed. Please install it with: pip install sympy" | |
| except Exception as e: | |
| return f"Symbolic math error: {str(e)}" | |
| def matrix_operations(matrix_a: str, operation: str = "determinant", matrix_b: str = "") -> str: | |
| """Perform matrix operations using NumPy. | |
| Operations available: | |
| - determinant: Compute determinant of matrix_a | |
| - inverse: Compute inverse of matrix_a | |
| - transpose: Compute transpose of matrix_a | |
| - eigenvalues: Compute eigenvalues of matrix_a | |
| - eigenvectors: Compute eigenvectors of matrix_a | |
| - rank: Compute rank of matrix_a | |
| - trace: Compute trace of matrix_a | |
| - multiply: Matrix multiplication of matrix_a @ matrix_b | |
| - add: Element-wise addition of matrix_a + matrix_b | |
| - solve: Solve linear system Ax = b (matrix_a is A, matrix_b is b vector) | |
| Args: | |
| matrix_a: Matrix as JSON array, e.g., "[[1,2],[3,4]]" | |
| operation: One of: determinant, inverse, transpose, eigenvalues, eigenvectors, rank, trace, multiply, add, solve | |
| matrix_b: Second matrix for binary operations (as JSON array) | |
| """ | |
| try: | |
| import numpy as np | |
| # Parse matrix_a | |
| try: | |
| a = np.array(json.loads(matrix_a), dtype=float) | |
| except json.JSONDecodeError: | |
| return f"Error parsing matrix_a: {matrix_a}. Use JSON format like [[1,2],[3,4]]" | |
| operation = operation.lower().strip() | |
| # Parse matrix_b if needed | |
| b = None | |
| if matrix_b and operation in ("multiply", "add", "solve"): | |
| try: | |
| b = np.array(json.loads(matrix_b), dtype=float) | |
| except json.JSONDecodeError: | |
| return f"Error parsing matrix_b: {matrix_b}. Use JSON format like [[1,2],[3,4]]" | |
| if operation == "determinant": | |
| if a.shape[0] != a.shape[1]: | |
| return "Error: Determinant requires a square matrix" | |
| result = np.linalg.det(a) | |
| elif operation == "inverse": | |
| if a.shape[0] != a.shape[1]: | |
| return "Error: Inverse requires a square matrix" | |
| result = np.linalg.inv(a) | |
| elif operation == "transpose": | |
| result = a.T | |
| elif operation == "eigenvalues": | |
| if a.shape[0] != a.shape[1]: | |
| return "Error: Eigenvalues require a square matrix" | |
| result = np.linalg.eigvals(a) | |
| elif operation == "eigenvectors": | |
| if a.shape[0] != a.shape[1]: | |
| return "Error: Eigenvectors require a square matrix" | |
| eigenvalues, eigenvectors = np.linalg.eig(a) | |
| result = {"eigenvalues": eigenvalues.tolist(), "eigenvectors": eigenvectors.tolist()} | |
| elif operation == "rank": | |
| result = np.linalg.matrix_rank(a) | |
| elif operation == "trace": | |
| result = np.trace(a) | |
| elif operation == "multiply": | |
| if b is None: | |
| return "Error: multiply operation requires matrix_b" | |
| result = a @ b | |
| elif operation == "add": | |
| if b is None: | |
| return "Error: add operation requires matrix_b" | |
| result = a + b | |
| elif operation == "solve": | |
| if b is None: | |
| return "Error: solve operation requires matrix_b (the b vector)" | |
| result = np.linalg.solve(a, b) | |
| else: | |
| return f"Unknown operation: {operation}. Available: determinant, inverse, transpose, eigenvalues, eigenvectors, rank, trace, multiply, add, solve" | |
| # Format result | |
| if isinstance(result, np.ndarray): | |
| result_str = np.array2string(result, precision=6, suppress_small=True) | |
| elif isinstance(result, dict): | |
| result_str = json.dumps(result, indent=2) | |
| else: | |
| result_str = str(result) | |
| return f"Matrix A:\n{np.array2string(a)}\nOperation: {operation}\nResult:\n{result_str}" | |
| except ImportError: | |
| return "Error: NumPy is not installed. Please install it with: pip install numpy" | |
| except np.linalg.LinAlgError as e: | |
| return f"Linear algebra error: {str(e)}" | |
| except Exception as e: | |
| return f"Matrix operation error: {str(e)}" | |
| def calculator(expression: str) -> str: | |
| """Evaluate a mathematical expression with high precision. | |
| Supports standard math operations: +, -, *, /, ** (power), % (modulo) | |
| Also supports functions: sqrt, sin, cos, tan, log, log10, exp, abs, ceil, floor, round | |
| Constants: pi, e | |
| Args: | |
| expression: Mathematical expression to evaluate, e.g., "sqrt(2) * pi" or "2**10 + 5" | |
| """ | |
| try: | |
| import math | |
| from decimal import Decimal, getcontext | |
| # Set high precision | |
| getcontext().prec = 50 | |
| # Safe evaluation context with math functions | |
| safe_dict = { | |
| 'sqrt': math.sqrt, | |
| 'sin': math.sin, | |
| 'cos': math.cos, | |
| 'tan': math.tan, | |
| 'asin': math.asin, | |
| 'acos': math.acos, | |
| 'atan': math.atan, | |
| 'atan2': math.atan2, | |
| 'log': math.log, | |
| 'log10': math.log10, | |
| 'log2': math.log2, | |
| 'exp': math.exp, | |
| 'pow': pow, | |
| 'abs': abs, | |
| 'ceil': math.ceil, | |
| 'floor': math.floor, | |
| 'round': round, | |
| 'pi': math.pi, | |
| 'e': math.e, | |
| 'inf': math.inf, | |
| 'factorial': math.factorial, | |
| 'gcd': math.gcd, | |
| 'lcm': math.lcm, | |
| 'degrees': math.degrees, | |
| 'radians': math.radians, | |
| } | |
| # Basic security check - only allow safe characters | |
| allowed_chars = set('0123456789+-*/.()%, abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_') | |
| if not all(c in allowed_chars for c in expression): | |
| return f"Error: Expression contains invalid characters. Only math operations and functions are allowed." | |
| # Evaluate the expression | |
| result = eval(expression, {"__builtins__": {}}, safe_dict) | |
| # Format the result | |
| if isinstance(result, float): | |
| # Check if it's close to an integer | |
| if result == int(result): | |
| result_str = str(int(result)) | |
| else: | |
| result_str = f"{result:.15g}" # High precision but remove trailing zeros | |
| else: | |
| result_str = str(result) | |
| return f"Expression: {expression}\nResult: {result_str}" | |
| except ZeroDivisionError: | |
| return "Error: Division by zero" | |
| except ValueError as e: | |
| return f"Math error: {str(e)}" | |
| except Exception as e: | |
| return f"Calculator error: {str(e)}" | |
| def statistical_analysis(data: str, operation: str = "describe") -> str: | |
| """Perform statistical analysis on numerical data. | |
| Operations available: | |
| - describe: Full statistical summary (mean, median, std, min, max, quartiles) | |
| - mean: Arithmetic mean | |
| - median: Median value | |
| - mode: Most frequent value | |
| - std: Standard deviation | |
| - var: Variance | |
| - correlation: Correlation coefficient (requires 2D data like [[x1,y1],[x2,y2],...]) | |
| - regression: Linear regression (requires 2D data) | |
| - percentile: Compute 25th, 50th, 75th percentiles | |
| - zscore: Compute z-scores for each value | |
| Args: | |
| data: Numerical data as JSON array, e.g., "[1, 2, 3, 4, 5]" or "[[1,2],[3,4]]" for 2D | |
| operation: One of: describe, mean, median, mode, std, var, correlation, regression, percentile, zscore | |
| """ | |
| try: | |
| import numpy as np | |
| from scipy import stats as sp_stats | |
| # Parse data | |
| try: | |
| arr = np.array(json.loads(data), dtype=float) | |
| except json.JSONDecodeError: | |
| return f"Error parsing data: {data}. Use JSON format like [1, 2, 3, 4, 5]" | |
| operation = operation.lower().strip() | |
| if operation == "describe": | |
| if arr.ndim == 1: | |
| result = { | |
| "count": len(arr), | |
| "mean": float(np.mean(arr)), | |
| "median": float(np.median(arr)), | |
| "std": float(np.std(arr)), | |
| "variance": float(np.var(arr)), | |
| "min": float(np.min(arr)), | |
| "max": float(np.max(arr)), | |
| "25th_percentile": float(np.percentile(arr, 25)), | |
| "50th_percentile": float(np.percentile(arr, 50)), | |
| "75th_percentile": float(np.percentile(arr, 75)), | |
| "sum": float(np.sum(arr)), | |
| } | |
| else: | |
| result = { | |
| "shape": arr.shape, | |
| "mean_per_column": np.mean(arr, axis=0).tolist(), | |
| "std_per_column": np.std(arr, axis=0).tolist(), | |
| } | |
| elif operation == "mean": | |
| result = float(np.mean(arr)) | |
| elif operation == "median": | |
| result = float(np.median(arr)) | |
| elif operation == "mode": | |
| mode_result = sp_stats.mode(arr.flatten(), keepdims=False) | |
| result = {"mode": float(mode_result.mode), "count": int(mode_result.count)} | |
| elif operation == "std": | |
| result = float(np.std(arr)) | |
| elif operation == "var": | |
| result = float(np.var(arr)) | |
| elif operation == "correlation": | |
| if arr.ndim != 2 or arr.shape[1] != 2: | |
| return "Error: correlation requires 2D data with 2 columns, e.g., [[x1,y1],[x2,y2],...]" | |
| result = float(np.corrcoef(arr[:, 0], arr[:, 1])[0, 1]) | |
| elif operation == "regression": | |
| if arr.ndim != 2 or arr.shape[1] != 2: | |
| return "Error: regression requires 2D data with 2 columns, e.g., [[x1,y1],[x2,y2],...]" | |
| slope, intercept, r_value, p_value, std_err = sp_stats.linregress(arr[:, 0], arr[:, 1]) | |
| result = { | |
| "slope": float(slope), | |
| "intercept": float(intercept), | |
| "r_squared": float(r_value**2), | |
| "p_value": float(p_value), | |
| "std_error": float(std_err), | |
| "equation": f"y = {slope:.6f}x + {intercept:.6f}" | |
| } | |
| elif operation == "percentile": | |
| result = { | |
| "25th": float(np.percentile(arr, 25)), | |
| "50th": float(np.percentile(arr, 50)), | |
| "75th": float(np.percentile(arr, 75)), | |
| "90th": float(np.percentile(arr, 90)), | |
| "95th": float(np.percentile(arr, 95)), | |
| "99th": float(np.percentile(arr, 99)), | |
| } | |
| elif operation == "zscore": | |
| zscores = sp_stats.zscore(arr.flatten()) | |
| result = zscores.tolist() | |
| else: | |
| return f"Unknown operation: {operation}. Available: describe, mean, median, mode, std, var, correlation, regression, percentile, zscore" | |
| # Format result | |
| if isinstance(result, dict): | |
| result_str = json.dumps(result, indent=2) | |
| elif isinstance(result, list): | |
| result_str = json.dumps(result) | |
| else: | |
| result_str = str(result) | |
| return f"Data: {len(arr.flatten())} values\nOperation: {operation}\nResult:\n{result_str}" | |
| except ImportError as e: | |
| missing = "scipy" if "scipy" in str(e) else "numpy" | |
| return f"Error: {missing} is not installed. Please install it with: pip install {missing}" | |
| except Exception as e: | |
| return f"Statistical analysis error: {str(e)}" | |