File size: 14,476 Bytes
67d287e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
"""
Mathematical computation tools for the GAIA Agent.
Includes symbolic math, matrix operations, calculator, and statistics.
"""

import json
from langchain_core.tools import tool


@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)}"


@tool
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)}"


@tool
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)}"


@tool
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)}"