mathai 0.3.9__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {mathai-0.3.9 → mathai-0.4.0}/PKG-INFO +1 -1
  2. {mathai-0.3.9 → mathai-0.4.0}/mathai/__init__.py +2 -0
  3. {mathai-0.3.9 → mathai-0.4.0}/mathai/apart.py +9 -19
  4. {mathai-0.3.9 → mathai-0.4.0}/mathai/base.py +0 -4
  5. {mathai-0.3.9 → mathai-0.4.0}/mathai/integrate.py +8 -15
  6. {mathai-0.3.9 → mathai-0.4.0}/mathai/linear.py +4 -7
  7. mathai-0.4.0/mathai/search.py +117 -0
  8. {mathai-0.3.9 → mathai-0.4.0}/mathai/simplify.py +0 -17
  9. {mathai-0.3.9 → mathai-0.4.0}/mathai/trig.py +8 -29
  10. {mathai-0.3.9 → mathai-0.4.0}/mathai.egg-info/PKG-INFO +1 -1
  11. {mathai-0.3.9 → mathai-0.4.0}/mathai.egg-info/SOURCES.txt +1 -0
  12. {mathai-0.3.9 → mathai-0.4.0}/setup.py +1 -1
  13. {mathai-0.3.9 → mathai-0.4.0}/README.md +0 -0
  14. {mathai-0.3.9 → mathai-0.4.0}/mathai/console.py +0 -0
  15. {mathai-0.3.9 → mathai-0.4.0}/mathai/diff.py +0 -0
  16. {mathai-0.3.9 → mathai-0.4.0}/mathai/expand.py +0 -0
  17. {mathai-0.3.9 → mathai-0.4.0}/mathai/factor.py +0 -0
  18. {mathai-0.3.9 → mathai-0.4.0}/mathai/fraction.py +0 -0
  19. {mathai-0.3.9 → mathai-0.4.0}/mathai/inverse.py +0 -0
  20. {mathai-0.3.9 → mathai-0.4.0}/mathai/limit.py +0 -0
  21. {mathai-0.3.9 → mathai-0.4.0}/mathai/logic.py +0 -0
  22. {mathai-0.3.9 → mathai-0.4.0}/mathai/parser.py +0 -0
  23. {mathai-0.3.9 → mathai-0.4.0}/mathai/printeq.py +0 -0
  24. {mathai-0.3.9 → mathai-0.4.0}/mathai/structure.py +0 -0
  25. {mathai-0.3.9 → mathai-0.4.0}/mathai/tool.py +0 -0
  26. {mathai-0.3.9 → mathai-0.4.0}/mathai/univariate_inequality.py +0 -0
  27. {mathai-0.3.9 → mathai-0.4.0}/mathai.egg-info/dependency_links.txt +0 -0
  28. {mathai-0.3.9 → mathai-0.4.0}/mathai.egg-info/requires.txt +0 -0
  29. {mathai-0.3.9 → mathai-0.4.0}/mathai.egg-info/top_level.txt +0 -0
  30. {mathai-0.3.9 → mathai-0.4.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mathai
3
- Version: 0.3.9
3
+ Version: 0.4.0
4
4
  Summary: Mathematics solving Ai tailored to NCERT
5
5
  Home-page: https://github.com/infinity390/mathai4
6
6
  Author: educated indians are having a low iq and are good for nothing
@@ -36,6 +36,8 @@ from .console import console
36
36
 
37
37
  from .limit import limit
38
38
 
39
+ from .search import dfs_simplify as search0
40
+
39
41
  from .univariate_inequality import wavycurvy, absolute, domain, handle_sqrt
40
42
 
41
43
  from .base import *
@@ -1,18 +1,14 @@
1
1
  from .linear import linear_solve
2
2
  from .expand import expand
3
3
  from .simplify import simplify
4
-
5
4
  from .diff import diff
6
5
  from .inverse import inverse
7
6
  from .base import *
8
7
  import math
9
8
  from .tool import poly, enclose_const
10
9
 
11
- def _apart(eq, v=None):
12
- if v is None:
13
- if len(vlist(eq)) == 0:
14
- return eq
15
- v = vlist(eq)[0]
10
+ def _apart(eq, v="v_0"):
11
+
16
12
  origv = vlist(eq)
17
13
  eq = simplify(eq)
18
14
  if eq.name != "f_mul":
@@ -46,9 +42,8 @@ def _apart(eq, v=None):
46
42
  s = []
47
43
  facd = [simplify(x) for x in factor_generation(simplify(d))]
48
44
 
49
-
50
- facd2 = remove_duplicates_custom(facd, lambda m, n: simplify(expand(simplify(m-n))) == tree_form("d_0"))
51
-
45
+
46
+ facd2 = remove_duplicates_custom(facd, lambda m, n: simplify(m-n) == tree_form("d_0"))
52
47
  if len(facd2) == 1:
53
48
  return eq
54
49
  x = tree_form(v)
@@ -63,7 +58,6 @@ def _apart(eq, v=None):
63
58
  if n > 2:
64
59
  return eq
65
60
  n = tree_form("d_"+str(n))
66
-
67
61
  l = len(poly(item, v))
68
62
  if l == 3:
69
63
  a = alloclst.pop(0)
@@ -99,15 +93,14 @@ def _apart(eq, v=None):
99
93
  final = summation(final2)
100
94
 
101
95
  s = simplify(TreeNode("f_eq", [final-eq2, tree_form("d_0")]))
102
-
96
+
103
97
  lst = poly(s.children[0], v)
104
-
98
+
105
99
  lst = [TreeNode("f_eq", [item, tree_form("d_0")]) for item in lst if "v_" in str_form(item)]
106
100
  lst2 = []
107
101
  for item in lst:
108
102
  lst2+=vlist(item)
109
103
  origv = list(set(lst2)-set(origv))
110
-
111
104
  out = linear_solve(TreeNode("f_and", lst), [tree_form(item) for item in origv])
112
105
  for item in out.children:
113
106
 
@@ -115,9 +108,6 @@ def _apart(eq, v=None):
115
108
  return simplify(final3)
116
109
  def apart(eq):
117
110
  eq, fx = enclose_const(eq)
118
- def helper(eq):
119
- eq2 = _apart(eq)
120
- if eq != eq2:
121
- return eq2
122
- return TreeNode(eq.name, [helper(child) for child in eq.children])
123
- return fx(helper(eq))
111
+
112
+ eq = _apart(eq)
113
+ return fx(eq)
@@ -131,8 +131,6 @@ def frac(eq):
131
131
  return Fraction(int(eq.name[2:]))
132
132
  if eq.name == "f_add":
133
133
  p = frac(eq.children[0])
134
- if p is None:
135
- return None
136
134
  for child in eq.children[1:]:
137
135
  tmp = frac(child)
138
136
  if isinstance(tmp, Fraction):
@@ -142,8 +140,6 @@ def frac(eq):
142
140
  return p
143
141
  if eq.name == "f_mul":
144
142
  p = frac(eq.children[0])
145
- if p is None:
146
- return None
147
143
  for child in eq.children[1:]:
148
144
  tmp = frac(child)
149
145
  if isinstance(tmp, Fraction):
@@ -104,6 +104,8 @@ def handle_try(eq):
104
104
  else:
105
105
  return TreeNode(eq.name, [handle_try(child) for child in eq.children])
106
106
  def inteq(eq):
107
+ if "f_ref" not in str_form(eq):
108
+ return eq
107
109
  if eq.name == "f_try":
108
110
  eq2 = None
109
111
  output = []
@@ -111,19 +113,13 @@ def inteq(eq):
111
113
  if child.name == "f_ref":
112
114
  eq2 = child.children[0]
113
115
  break
114
- if eq2 is None:
115
- return eq
116
116
  for child in eq.children:
117
117
  if child.name == "f_ref":
118
118
  output.append(child)
119
119
  else:
120
120
  eq3 = simplify(expand(simplify(eq2 - child)))
121
121
  if contain(eq3, eq2):
122
- out = inverse(eq3, str_form(eq2))
123
- if out is None:
124
- output.append(child)
125
- else:
126
- output.append(out)
122
+ output.append(inverse(eq3, str_form(eq2)))
127
123
  else:
128
124
  output.append(child)
129
125
  return TreeNode("f_try", output)
@@ -138,8 +134,7 @@ def solve_integrate(eq):
138
134
  eq2 = dowhile(eq, _solve_integrate)
139
135
  eq2 = dowhile(eq2, handle_try)
140
136
  eq2 = rm(eq2)
141
- if eq2.name == "f_try":
142
- eq2.children = list(set(eq2.children))
137
+ eq2.children = list(set(eq2.children))
143
138
  return eq2
144
139
  def integrate_subs(equation, term, v1, v2):
145
140
  output = []
@@ -170,7 +165,7 @@ def integrate_subs(equation, term, v1, v2):
170
165
 
171
166
  return none
172
167
 
173
- return TreeNode("f_subs", [TreeNode("f_integrate", [simplify(fraction(expand(simplify(equation)))), tree_form(origv2)]),tree_form(origv2) ,g])
168
+ return TreeNode("f_subs", [TreeNode("f_integrate", [simplify(expand(simplify(equation))), tree_form(origv2)]),tree_form(origv2) ,g])
174
169
 
175
170
  def integrate_subs_main(equation):
176
171
  if equation.name == "f_ref":
@@ -381,7 +376,6 @@ def rm_const(equation):
381
376
  return rm_const(TreeNode("f_integrate",[equation, wrt])) *const
382
377
  equation = eq2
383
378
  return TreeNode(equation.name, [rm_const(child) for child in equation.children])
384
-
385
379
  def integrate_formula(equation):
386
380
  if equation.name == "f_ref":
387
381
  return equation.copy_tree()
@@ -390,18 +384,17 @@ def integrate_formula(equation):
390
384
  integrand = eq2.children[0]
391
385
  wrt = eq2.children[1]
392
386
  if integrand == wrt:
393
- return wrt**2/2 # x^2/2
387
+ return TreeNode("f_add", [TreeNode("f_power", [wrt.copy_tree(), TreeNode("2")]), TreeNode("f_div", [TreeNode("1"), TreeNode("2")])]) # x^2/2
394
388
  if not contain(integrand, wrt):
395
- return integrand*wrt
389
+ return TreeNode("f_mul", [wrt.copy_tree(), integrand.copy_tree()]) # constant * dx
396
390
  out = transform_formula(simplify(trig0(integrand)), wrt.name, formula_gen[0], formula_gen[1], formula_gen[2])
397
391
  if out is not None:
398
-
399
392
  return out
400
393
  expr_str = str_form(integrand)
401
394
  if expr_str.count("f_sin") + expr_str.count("f_cos") > 2:
402
395
  out = transform_formula(integrand, wrt.name, formula_gen4[0], formula_gen4[1], formula_gen4[2])
403
396
  if out is not None:
404
-
397
+ print(out, 111)
405
398
  return out
406
399
  return TreeNode(eq2.name, [integrate_formula(child) for child in eq2.children])
407
400
 
@@ -3,9 +3,6 @@ from .simplify import simplify, solve
3
3
  from .fraction import fraction
4
4
  from .expand import expand
5
5
  from .base import *
6
- from .factor import factorconst
7
- def ss(eq):
8
- return dowhile(eq, lambda x: fraction(expand(simplify(x))))
9
6
  def rref(matrix):
10
7
  rows, cols = len(matrix), len(matrix[0])
11
8
  lead = 0
@@ -13,7 +10,7 @@ def rref(matrix):
13
10
  if lead >= cols:
14
11
  return matrix
15
12
  i = r
16
- while ss(matrix[i][lead]) == tree_form("d_0"):
13
+ while fraction(simplify(matrix[i][lead])) == tree_form("d_0"):
17
14
  i += 1
18
15
  if i == rows:
19
16
  i = r
@@ -22,11 +19,11 @@ def rref(matrix):
22
19
  return matrix
23
20
  matrix[i], matrix[r] = matrix[r], matrix[i]
24
21
  lv = matrix[r][lead]
25
- matrix[r] = [ss(m / lv) for m in matrix[r]]
22
+ matrix[r] = [fraction(simplify(m / lv)) for m in matrix[r]]
26
23
  for i in range(rows):
27
24
  if i != r:
28
25
  lv = matrix[i][lead]
29
- matrix[i] = [ss(m - lv * n) for m, n in zip(matrix[i], matrix[r])]
26
+ matrix[i] = [fraction(simplify(m - lv * n)) for m, n in zip(matrix[i], matrix[r])]
30
27
  lead += 1
31
28
  return matrix
32
29
  def islinear(eq, fxconst):
@@ -94,7 +91,7 @@ def linear(eqlist, fxconst):
94
91
  for i in range(len(m)):
95
92
  for j in range(len(m[i])):
96
93
  m[i][j] = fraction(m[i][j])
97
-
94
+ #print(m)
98
95
  for item in m:
99
96
  if all(item2==tree_form("d_0") for item2 in item[:-1]) and item[-1] != tree_form("d_0"):
100
97
  return tree_form("s_false")
@@ -0,0 +1,117 @@
1
+ from mathai import *
2
+ import copy
3
+ from concurrent.futures import ThreadPoolExecutor, TimeoutError
4
+
5
+ def dfs_simplify(equation, functions, true_expr, false_expr,
6
+ max_timeout=25, max_small=4,
7
+ base_timeout=1, time_per_char=0.1, timeout_increase=0.5):
8
+ """
9
+ Perform DFS simplification on a given equation using provided functions.
10
+
11
+ Args:
12
+ equation: The starting expression (TreeNode or parsed equation)
13
+ functions: List of simplification functions
14
+ true_expr: Expression representing True (immediate termination)
15
+ false_expr: Expression representing False (immediate termination)
16
+ max_timeout: Maximum timeout allowed for any function
17
+ max_small: Number of smallest expressions to track
18
+ base_timeout: Base timeout in seconds
19
+ time_per_char: Additional timeout per character of expression
20
+ timeout_increase: Factor to increase timeout for consecutive timeouts
21
+
22
+ Returns:
23
+ tuple(found_boolean, boolean_path, smallest_expressions)
24
+ """
25
+ original_eq = simplify(equation)
26
+ smallest_four = []
27
+
28
+ stack = [(copy.deepcopy(original_eq), [copy.deepcopy(original_eq)])]
29
+ visited = set()
30
+
31
+ found_boolean = False
32
+ boolean_path = None
33
+ boolean_expr = None
34
+
35
+ executor = ThreadPoolExecutor(max_workers=3)
36
+ consecutive_timeouts = 0
37
+
38
+ while stack and not found_boolean:
39
+ current_eq, path = stack.pop()
40
+ expr_str = str(current_eq)
41
+
42
+ if expr_str in visited:
43
+ continue
44
+ visited.add(expr_str)
45
+
46
+ # Thinking message
47
+ printeq(current_eq)
48
+
49
+ # Immediate termination using predicate functions
50
+ if true_expr(current_eq):
51
+ found_boolean = True
52
+ boolean_path = path
53
+ boolean_expr = current_eq
54
+ break
55
+ if false_expr(current_eq):
56
+ found_boolean = True
57
+ boolean_path = path
58
+ boolean_expr = current_eq
59
+ break
60
+
61
+
62
+ # Insert into smallest_four if qualifies
63
+ inserted = False
64
+ for j in range(len(smallest_four)):
65
+ if len(expr_str) < len(str(smallest_four[j][0])):
66
+ smallest_four.insert(j, (copy.deepcopy(current_eq), copy.deepcopy(path)))
67
+ inserted = True
68
+ break
69
+ if not inserted and len(smallest_four) < max_small:
70
+ smallest_four.append((copy.deepcopy(current_eq), copy.deepcopy(path)))
71
+ if len(smallest_four) > max_small:
72
+ smallest_four = smallest_four[:max_small]
73
+
74
+ # Calculate adaptive timeout with cap
75
+ timeout = (base_timeout + time_per_char * len(expr_str)) * (1 + timeout_increase * consecutive_timeouts)
76
+ if timeout > max_timeout:
77
+ timeout = max_timeout
78
+
79
+ # Try functions that reduce length first
80
+ reduced_any = False
81
+ for fx in functions:
82
+ print(f"[Thinking] Executing {fx.__name__} on current expression (timeout={timeout:.2f}s):")
83
+ printeq(current_eq)
84
+ future = executor.submit(fx, current_eq)
85
+ try:
86
+ new_expr = future.result(timeout=timeout)
87
+ new_expr_str = str(new_expr)
88
+ if len(new_expr_str) <= len(expr_str) and new_expr_str != expr_str:
89
+ reduced_any = True
90
+ stack.append((new_expr, path + [copy.deepcopy(new_expr)]))
91
+ consecutive_timeouts = 0 # reset after success
92
+ except TimeoutError:
93
+ print(f"[Thinking] {fx.__name__} timed out, skipping.")
94
+ consecutive_timeouts += 1
95
+ continue
96
+
97
+ # If no reducing function worked, try growing functions
98
+ if not reduced_any:
99
+ for fx in functions:
100
+ print(f"[Thinking] Trying growing {fx.__name__} on current expression (timeout={timeout:.2f}s):")
101
+ printeq(current_eq)
102
+ future = executor.submit(fx, current_eq)
103
+ try:
104
+ new_expr = future.result(timeout=timeout)
105
+ new_expr_str = str(new_expr)
106
+ if new_expr_str != expr_str:
107
+ stack.append((new_expr, path + [copy.deepcopy(new_expr)]))
108
+ consecutive_timeouts = 0
109
+ break # only take one growing function
110
+ except TimeoutError:
111
+ print(f"[Thinking] {fx.__name__} (growing) timed out, skipping.")
112
+ consecutive_timeouts += 1
113
+ continue
114
+
115
+ executor.shutdown(wait=True)
116
+
117
+ return found_boolean, boolean_path, smallest_four
@@ -286,23 +286,6 @@ def simplify(eq):
286
286
  error = True
287
287
  else:
288
288
  eq = tree_form("d_0")
289
-
290
- if eq.name == "f_mul" and str_form(eq).count("f_pow")>1:
291
- dic = {}
292
- for child in eq.children:
293
- head = child
294
- tail = None
295
- if child.name == "f_pow":
296
- head = child.children[0]
297
- tail = child.children[1]
298
- if tail is None:
299
- tail = tree_form("d_1")
300
- if head not in dic.keys():
301
- dic[head] = tail
302
- else:
303
- dic[head] += tail
304
- if len(eq.children) != len(dic.keys()):
305
- eq = product([key if dic[key] == 1 else key**dic[key] for key in dic.keys()])
306
289
  if eq.name == "f_pow" and eq.children[0].name == "f_pow" and eq.children[0].children[1] == tree_form("d_2")**-1 and eq.children[1] == tree_form("d_2"):
307
290
  eq = eq.children[0].children[0]
308
291
  if (eq.name == "f_sin" and eq.children[0].name == "f_arcsin") or (eq.name == "f_cos" and eq.children[0].name == "f_arccos") or (eq.name == "f_tan" and eq.children[0].name == "f_arctan"):
@@ -199,37 +199,16 @@ def trig4(eq, numer=True):
199
199
  return tree_form("d_1")/(1+a**2)**(tree_form("d_2")**-1)
200
200
 
201
201
  return TreeNode(eq.name, [trig4(child, False) if not numer or (eq.name == "f_pow" and frac(eq.children[1]) is not None and frac(eq.children[1]) < 0) else trig4(child, True) for child in eq.children])
202
-
203
202
  def trig2(eq):
204
203
  if eq.name == "f_add":
205
204
  for item in itertools.combinations(range(len(eq.children)), 2):
206
- child1, child2 = eq.children[item[0]], eq.children[item[1]]
207
-
208
- # Check if both are sin or cos
209
- if child1.name in ["f_sin", "f_cos"] and child2.name in ["f_sin", "f_cos"]:
210
- a, b = child1.children[0], child2.children[0]
211
-
212
- # Compute the rest of the sum
213
- rest = [eq.children[i] for i in range(len(eq.children)) if i not in item]
214
- if len(rest) == 0:
215
- rest_tree = tree_form("d_0")
216
- else:
217
- rest_tree = summation(rest)
218
-
219
- # Now handle the sin/cos combination formula
220
- if child1.name == "f_sin" and child2.name == "f_sin":
221
- # sin A + sin B = 2 sin((A+B)/2) cos((A-B)/2)
222
- two = tree_form("d_2")
223
- combined = two * ((a + b) / two).fx("sin") * ((a - b) / two).fx("cos")
224
- elif child1.name == "f_cos" and child2.name == "f_cos":
225
- # cos A + cos B = 2 cos((A+B)/2) cos((A-B)/2)
226
- two = tree_form("d_2")
227
- combined = two * ((a + b) / two).fx("cos") * ((a - b) / two).fx("cos")
205
+ if all(eq.children[item2].name == "f_sin" for item2 in item):
206
+ a, b = eq.children[item[0]].children[0], eq.children[item[1]].children[0]
207
+ rest = [item2 for index, item2 in enumerate(eq.children) if index not in item]
208
+ if len(rest)==0:
209
+ rest = tree_form("d_0")
228
210
  else:
229
- # sin A + cos B = sin A + cos B (leave unchanged, or implement formula if desired)
230
- continue # skip for now, keep original
231
-
232
- return rest_tree + combined
233
-
234
- # Recurse for other nodes
211
+ rest = summation(rest)
212
+ two = tree_form("d_2")
213
+ return rest + two*((a+b)/two).fx("sin")*((a-b)/two).fx("cos")
235
214
  return TreeNode(eq.name, [trig2(child) for child in eq.children])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mathai
3
- Version: 0.3.9
3
+ Version: 0.4.0
4
4
  Summary: Mathematics solving Ai tailored to NCERT
5
5
  Home-page: https://github.com/infinity390/mathai4
6
6
  Author: educated indians are having a low iq and are good for nothing
@@ -15,6 +15,7 @@ mathai/linear.py
15
15
  mathai/logic.py
16
16
  mathai/parser.py
17
17
  mathai/printeq.py
18
+ mathai/search.py
18
19
  mathai/simplify.py
19
20
  mathai/structure.py
20
21
  mathai/tool.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="mathai",
5
- version="0.3.9",
5
+ version="0.4.0",
6
6
  description="Mathematics solving Ai tailored to NCERT",
7
7
  long_description=open("README.md").read(),
8
8
  long_description_content_type="text/markdown",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes