KingOfThoughtFleuren commited on
Commit
7a36c05
·
verified ·
1 Parent(s): b4487f5

Update services/math_kernel.py

Browse files
Files changed (1) hide show
  1. services/math_kernel.py +44 -132
services/math_kernel.py CHANGED
@@ -1,146 +1,58 @@
1
  # services/math_kernel.py
2
- from typing import Any, Dict, Optional
3
- from dataclasses import dataclass
4
- from sympy import symbols, Eq, sympify, solve, diff, integrate, sqrt, series
5
- from sympy import Matrix
6
- from sympy.parsing.sympy_parser import standard_transformations, convert_xor, implicit_multiplication_application
7
- from sympy.parsing.sympy_parser import parse_expr
8
- from sympy.physics.units import G, c
9
- from sympy import S
10
- import mpmath as mp
11
-
12
- # Optional: small map of physical constants one might use
13
- CONSTS = {
14
- "G": G, # gravitational constant
15
- "c": c, # speed of light
16
- }
17
-
18
- SAFE_NAMES = {
19
- "sqrt": sqrt,
20
- "Eq": Eq,
21
- # add more SymPy callables if needed
22
  }
23
 
24
- TRANSFORMS = (standard_transformations + (convert_xor, implicit_multiplication_application))
25
-
26
- @dataclass
27
- class MathPayload:
28
- task: str # "symbolic" | "numeric"
29
- expr: Optional[str] = None # sympy-string expression, e.g. "Eq(1/sqrt(1-2*G*M/(c**2*r)), 1+z)"
30
- solve_for: Optional[list] = None
31
- subs: Optional[Dict[str, Any]] = None # e.g. {"M":"10","r":"4*rs"}; you can keep this symbolic too
32
- series_var: Optional[str] = None # e.g. "x"
33
- series_point: Optional[Any] = None # e.g. 0
34
- series_order: int = 3
35
-
36
  def _parse(s: str):
37
- # parse a sympy string safely with limited names
38
- local_dict = {**SAFE_NAMES, **CONSTS}
39
- return parse_expr(s, local_dict=local_dict, transformations=TRANSFORMS)
40
-
41
- def _sym(v):
42
- return symbols(v)
43
 
44
- def compute(payload: Dict[str, Any]) -> Dict[str, Any]:
45
  """
46
- payload:
47
- task: "symbolic" | "numeric"
48
- expr: sympy-string expression (equation or expression)
49
- solve_for: [list of symbol names]
50
- subs: dict of substitutions (numbers or sympy-strings)
51
- series_var, series_point, series_order: optional series expansion controls
52
-
53
- returns:
54
- {
55
- "steps": [str, ...],
56
- "symbolic": str, # final sympy string
57
- "numeric": {"value": float, "note": str} | null,
58
- "interpretation": str
59
- }
60
  """
61
- steps = []
62
- try:
63
- mp.mp.dps = 50 # high precision numeric eval
64
- task = payload.get("task", "symbolic")
65
- expr_s = payload.get("expr", "")
66
- solve_for = payload.get("solve_for") or []
67
- subs_in = payload.get("subs") or {}
68
- series_var = payload.get("series_var")
69
- series_point = payload.get("series_point", 0)
70
- series_order = int(payload.get("series_order", 3))
71
 
72
- if not expr_s:
73
- return {"steps": steps, "symbolic": "", "numeric": None, "interpretation": "No expression provided."}
74
-
75
- # parse the main expression
76
- expr = _parse(expr_s)
77
- steps.append(f"Parsed expression: {expr!s}")
78
-
79
- # normalize substitutions into SymPy objects
80
- subs = {}
81
- for k, v in subs_in.items():
82
- if isinstance(v, (int, float)):
83
- subs[k] = S(v)
84
- elif isinstance(v, str):
85
- subs[k] = _parse(v)
86
- else:
87
- subs[k] = v
88
-
89
- # If it's an equation and we have solve_for
90
- result_sym = expr
91
- if solve_for:
92
- syms = [symbols(n) for n in solve_for]
93
- steps.append(f"Solving for: {', '.join(solve_for)}")
94
- sol = solve(expr, *syms, dict=True)
95
- steps.append(f"Raw solution: {sol!r}")
96
- result_sym = sol
97
 
98
- # Apply substitutions (symbolic)
99
  if subs:
100
- steps.append(f"Applying substitutions: { {k:str(v) for k,v in subs.items()} }")
101
- if isinstance(result_sym, list):
102
- result_sym = [{k: (vv.subs(subs) if hasattr(vv, 'subs') else vv) for k, vv in d.items()} for d in result_sym]
103
- else:
104
- result_sym = result_sym.subs(subs)
105
-
106
- # Optional series expansion (for expressions, not solution dicts)
107
- if series_var and not isinstance(result_sym, list):
108
- x = symbols(series_var)
109
- steps.append(f"Series expansion in {series_var} around {series_point} to order {series_order}")
110
- try:
111
- result_sym = series(result_sym, x, series_point, series_order).removeO()
112
- except Exception as _:
113
- steps.append("Series expansion failed; leaving symbolic result unchanged.")
114
-
115
- # Optional numeric evaluation
116
- numeric_out = None
117
- try:
118
- to_eval = None
119
- if isinstance(result_sym, list):
120
- # try numeric evaluation of the first solution if it’s a scalar
121
- if result_sym and isinstance(result_sym[0], dict):
122
- first = list(result_sym[0].values())[0]
123
- to_eval = first
124
  else:
125
- to_eval = result_sym
 
126
 
127
- if to_eval is not None and hasattr(to_eval, 'evalf'):
128
- val = float(to_eval.evalf())
129
- numeric_out = {"value": val, "note": "evalf() with high precision"}
130
- except Exception as _:
131
- pass
132
 
133
- return {
134
- "steps": steps,
135
- "symbolic": str(result_sym),
136
- "numeric": numeric_out,
137
- "interpretation": "Mathematical computation completed."
138
- }
139
 
140
- except Exception as e:
141
- return {
142
- "steps": steps + [f"ERROR: {e}"],
143
- "symbolic": "",
144
- "numeric": None,
145
- "interpretation": f"Computation failed: {e}"
146
- }
 
1
  # services/math_kernel.py
2
+ from typing import Dict, Any, List, Optional
3
+ import sympy as sp
4
+ from sympy.parsing.sympy_parser import (
5
+ parse_expr, standard_transformations, convert_xor, implicit_multiplication_application
6
+ )
7
+
8
+ TRANSFORMS = standard_transformations + (convert_xor, implicit_multiplication_application)
9
+
10
+ SAFE_FUNCS = {
11
+ "sin": sp.sin, "cos": sp.cos, "tan": sp.tan, "exp": sp.exp, "log": sp.log,
12
+ "sqrt": sp.sqrt, "Eq": sp.Eq, "diff": sp.diff, "integrate": sp.integrate,
13
+ "Symbol": sp.Symbol
 
 
 
 
 
 
 
 
14
  }
15
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  def _parse(s: str):
17
+ return parse_expr(s, local_dict=SAFE_FUNCS, transformations=TRANSFORMS)
 
 
 
 
 
18
 
19
+ def compute(task: str, expr: str, solve_for: Optional[List[str]] = None, subs: Optional[Dict[str, Any]] = None):
20
  """
21
+ task: 'symbolic' | 'numeric'
22
+ expr: SymPy string or Eq(...)
23
+ solve_for: symbols to solve for
24
+ subs: dict like {"M":"1.0", "r":"4"} (strings parsed via SymPy)
 
 
 
 
 
 
 
 
 
 
25
  """
26
+ out = {"steps": [], "symbolic": None, "numeric": None, "interpretation": ""}
 
 
 
 
 
 
 
 
 
27
 
28
+ try:
29
+ e = _parse(expr)
30
+ out["steps"].append(f"Parsed: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
 
32
  if subs:
33
+ sdict = {sp.Symbol(k): (_parse(v) if isinstance(v, str) else v) for k, v in subs.items()}
34
+ e = e.subs(sdict)
35
+ out["steps"].append(f"Substitutions: {sdict}")
36
+
37
+ if task == "symbolic":
38
+ if solve_for:
39
+ syms = [sp.Symbol(n) for n in solve_for]
40
+ sol = sp.solve(e, *syms, dict=True)
41
+ out["symbolic"] = str(sol)
42
+ out["interpretation"] = "Solved symbolically."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  else:
44
+ out["symbolic"] = str(sp.simplify(e))
45
+ out["interpretation"] = "Simplified symbolically."
46
 
47
+ elif task == "numeric":
48
+ val = float(e.evalf())
49
+ out["numeric"] = {"value": val}
50
+ out["interpretation"] = "Numeric evaluation complete."
 
51
 
52
+ else:
53
+ out["interpretation"] = "Unknown task."
 
 
 
 
54
 
55
+ return out
56
+ except Exception as err:
57
+ out["interpretation"] = f"Error: {err}"
58
+ return out