mathai 0.4.9__py3-none-any.whl → 0.5.1__py3-none-any.whl

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.
mathai/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from .ode import diffsolve as ode_solve
2
2
  from .ode import diffsolve_sep as ode_shift_term
3
3
 
4
- from .linear import linear_solve
4
+ from .linear import linear_solve, linear_or
5
5
 
6
6
  from .expand import expand
7
7
 
@@ -42,6 +42,7 @@ from .apart import apart, apart2
42
42
  from .limit import limit
43
43
 
44
44
  from .univariate_inequality import wavycurvy, absolute, domain, handle_sqrt
45
+ from .bivariate_inequality import inequality_solve
45
46
 
46
47
  from .base import *
47
48
 
mathai/base.py CHANGED
@@ -204,11 +204,9 @@ def compute(eq):
204
204
 
205
205
  # Recursive case: compute child values
206
206
  values = [compute(child) for child in eq.children]
207
-
208
-
209
207
  if None in values:
210
208
  return None
211
-
209
+ # Evaluate based on node type
212
210
  if eq.name == "f_add":
213
211
  return sum(values)
214
212
  elif eq.name == "f_sub":
@@ -0,0 +1,317 @@
1
+ import math
2
+ from .linear import linear_or
3
+ from functools import reduce
4
+ import operator
5
+ from .base import *
6
+ from .simplify import simplify
7
+ from .expand import expand
8
+ from .logic import logic0
9
+
10
+ def shoelace_area(vertices):
11
+ n = len(vertices)
12
+ area = 0.0
13
+ for i in range(n):
14
+ j = (i + 1) % n
15
+ area += vertices[i][0] * vertices[j][1]
16
+ area -= vertices[j][0] * vertices[i][1]
17
+ return abs(area) / 2.0
18
+
19
+ def triangle_area(p1, p2, p3):
20
+ area = 0.0
21
+ area += p1[0] * (p2[1] - p3[1])
22
+ area += p2[0] * (p3[1] - p1[1])
23
+ area += p3[0] * (p1[1] - p2[1])
24
+ return abs(area) / 2.0
25
+
26
+ def is_point_inside_polygon(point, vertices):
27
+ if len(vertices) < 3:
28
+ return False
29
+
30
+ polygon_area = shoelace_area(vertices)
31
+
32
+ total_triangle_area = 0.0
33
+ n = len(vertices)
34
+ for i in range(n):
35
+ j = (i + 1) % n
36
+ total_triangle_area += triangle_area(point, vertices[i], vertices[j])
37
+
38
+ tolerance = 1e-5
39
+ return abs(total_triangle_area - polygon_area) < tolerance
40
+
41
+ def distance_point_to_segment(px, py, x1, y1, x2, y2):
42
+ dx, dy = x2 - x1, y2 - y1
43
+ if dx == dy == 0:
44
+ return ((px - x1)**2 + (py - y1)**2)**0.5
45
+ t = max(0, min(1, ((px - x1) * dx + (py - y1) * dy) / (dx*dx + dy*dy)))
46
+ proj_x = x1 + t * dx
47
+ proj_y = y1 + t * dy
48
+ return ((px - proj_x)**2 + (py - proj_y)**2)**0.5
49
+
50
+ def deterministic_middle_point(vertices, grid_resolution=100):
51
+ xs = [v[0] for v in vertices]
52
+ ys = [v[1] for v in vertices]
53
+ xmin, xmax = min(xs), max(xs)
54
+ ymin, ymax = min(ys), max(ys)
55
+
56
+ best_point = None
57
+ max_dist = -1
58
+
59
+ for i in range(grid_resolution + 1):
60
+ for j in range(grid_resolution + 1):
61
+ px = xmin + (xmax - xmin) * i / grid_resolution
62
+ py = ymin + (ymax - ymin) * j / grid_resolution
63
+ if not is_point_inside_polygon((px, py), vertices):
64
+ continue
65
+ min_edge_dist = float('inf')
66
+ n = len(vertices)
67
+ for k in range(n):
68
+ x1, y1 = vertices[k]
69
+ x2, y2 = vertices[(k + 1) % n]
70
+ d = distance_point_to_segment(px, py, x1, y1, x2, y2)
71
+ min_edge_dist = min(min_edge_dist, d)
72
+ if min_edge_dist > max_dist:
73
+ max_dist = min_edge_dist
74
+ best_point = (px, py)
75
+
76
+ return best_point
77
+
78
+ def build(eq):
79
+ eq = TreeNode("f_or", eq)
80
+ eq = flatten_tree(eq)
81
+ orig = eq.copy_tree()
82
+ def fxhelper3(eq):
83
+ if eq.name[2:] in "le ge lt gt".split(" "):
84
+ return TreeNode("f_eq", [child.copy_tree() for child in eq.children])
85
+ return TreeNode(eq.name, [fxhelper3(child) for child in eq.children])
86
+ eq = fxhelper3(eq)
87
+
88
+ result = linear_or(eq)
89
+
90
+ if result is None:
91
+ return None
92
+
93
+ maxnum = tree_form("d_2")
94
+ if len(result[1]) != 0:
95
+ maxnum = max([max([simplify(item2.fx("abs")) for item2 in item], key=lambda x: compute(x)) for item in result[1]], key=lambda x: compute(x))
96
+ maxnum += 1
97
+ maxnum = simplify(maxnum)
98
+ eq = flatten_tree(eq | simplify(TreeNode("f_or", [TreeNode("f_eq", [tree_form(item)+maxnum, tree_form("d_0")])|\
99
+ TreeNode("f_eq", [tree_form(item)-maxnum, tree_form("d_0")]) for item in ["v_0","v_1"]])))
100
+ result2 = linear_or(eq)
101
+ if result2 is None:
102
+ return None
103
+
104
+ point_lst = result2[2]
105
+
106
+ def gen(point):
107
+ nonlocal point_lst
108
+ out = []
109
+ for item in point_lst:
110
+ p = None
111
+ if point in item:
112
+ p = item.index(point)
113
+ else:
114
+ continue
115
+ if p < len(item)-1:
116
+ out.append(item[p+1])
117
+ if p > 0:
118
+ out.append(item[p-1])
119
+ return list(set(out))
120
+ start = list(range(len(result2[1])))
121
+ graph= {}
122
+ for item in start:
123
+ graph[item] = gen(item)
124
+
125
+ points = {}
126
+ for index, item in enumerate(result2[1]):
127
+ points[index] = [compute(item2) for item2 in item]
128
+
129
+ res = []
130
+ for index, item in enumerate(result2[1]):
131
+ if any(simplify(item2.fx("abs")-maxnum)!=0 and abs(compute(item2))>compute(maxnum) for item2 in item):
132
+ res.append(index)
133
+
134
+ graph = {k: sorted(v) for k, v in graph.items()}
135
+
136
+ def dfs(current, parent, path, visited, cycles):
137
+ path.append(current)
138
+ visited.add(current)
139
+ for neighbor in graph[current]:
140
+ if neighbor == parent:
141
+ continue
142
+ if neighbor in visited:
143
+ idx = path.index(neighbor)
144
+ cycle = path[idx:]
145
+ cycles.append(cycle)
146
+ else:
147
+ dfs(neighbor, current, path, visited, cycles)
148
+ path.pop()
149
+ visited.remove(current)
150
+
151
+ cycles = []
152
+ for start in sorted(graph.keys()):
153
+ path = []
154
+ visited = set()
155
+ dfs(start, -1, path, visited, cycles)
156
+
157
+ def normalize(cycle):
158
+ k = len(cycle)
159
+ if k < 3:
160
+ return None
161
+ candidates = []
162
+ for direction in [cycle, list(reversed(cycle))]:
163
+ doubled = direction + direction[:-1]
164
+ for i in range(k):
165
+ rot = tuple(doubled[i:i + k])
166
+ candidates.append(rot)
167
+ return min(candidates)
168
+
169
+ unique = set()
170
+ for c in cycles:
171
+ norm = normalize(c)
172
+ if norm:
173
+ unique.add(norm)
174
+
175
+ cycles = sorted(list(unique), key=lambda x: (len(x), x))
176
+
177
+ start = list(range(len(result2[1])))
178
+ for i in range(len(cycles)-1,-1,-1):
179
+ if any(item in cycles[i] for item in res) or\
180
+ any(is_point_inside_polygon([compute(item2) for item2 in list(result2[1][p])], [[compute(item2) for item2 in result2[1][item]] for item in cycles[i]]) for p in list(set(start) - set(cycles[i]))) or\
181
+ any(len(set(graph[item]) & set(cycles[i]))>2 for item in cycles[i]):
182
+ cycles.pop(i)
183
+
184
+ point_lst = [index for index, item in enumerate(result2[1]) if item in result[1]]
185
+
186
+ border = []
187
+ for item in start:
188
+ for item2 in graph[item]:
189
+ a = result2[1][item]
190
+ b = result2[1][item2]
191
+
192
+ if a[0] == b[0] and simplify(a[0].fx("abs") - maxnum) == 0:
193
+ continue
194
+ if a[1] == b[1] and simplify(a[1].fx("abs") - maxnum) == 0:
195
+ continue
196
+
197
+ border.append(tuple(sorted([item, item2])))
198
+
199
+ line = []
200
+ for key in graph.keys():
201
+ for item in list(set(point_lst)&set(graph[key])):
202
+ line.append(tuple(sorted([item, key])))
203
+ line = list(set(line+border))
204
+ point_in = [deterministic_middle_point([[compute(item3) for item3 in result2[1][item2]] for item2 in item]) for item in cycles]
205
+ def work(eq, point):
206
+ nonlocal result2
207
+ if eq.name[:2] == "d_":
208
+ return float(eq.name[2:])
209
+ if eq.name in result2[0]:
210
+ return point[result2[0].index(eq.name)]
211
+ if eq.name == "f_add":
212
+ return sum(work(item, point) for item in eq.children)
213
+ if eq.name == "f_mul":
214
+ return math.prod(work(item, point) for item in eq.children)
215
+ if eq.name == "f_sub":
216
+ return work(eq.children[0], point) - work(eq.children[1], point)
217
+ return {"eq": lambda a,b: abs(a-b)<0.001, "gt":lambda a,b: False if abs(a-b)<0.001 else a>b, "lt":lambda a,b: False if abs(a-b)<0.001 else a<b}[eq.name[2:]](work(eq.children[0], point), work(eq.children[1], point))
218
+
219
+ data = []
220
+ for index, item in enumerate(result2[2][:-4]):
221
+ a = tuple([item for item in point_lst if work(orig.children[index], [compute(item2) for item2 in result2[1][item]])])
222
+ #a = tuple(set(item) & set(point_lst))
223
+ #b = tuple(set([tuple(sorted([item[i], item[i+1]])) for i in range(len(item)-1)]) & set(line))
224
+ b = None
225
+ if orig.children[index] == "f_eq":
226
+ b = tuple([tuple(item) for item in line if work(orig.children[index], [compute(item2) for item2 in result2[1][item[1]]]) and work(orig.children[index], [compute(item2) for item2 in result2[1][item[0]]])])
227
+ else:
228
+ b = tuple([tuple(item) for item in line if work(orig.children[index], [compute(item2) for item2 in result2[1][item[1]]]) or work(orig.children[index], [compute(item2) for item2 in result2[1][item[0]]])])
229
+ c = tuple([tuple(item) for index2, item in enumerate(cycles) if work(orig.children[index], point_in[index2])])
230
+ data.append((a,b,c))
231
+
232
+ total = tuple([tuple(point_lst), tuple(line), tuple(cycles)])
233
+ final = {}
234
+ for index, item in enumerate(orig.children):
235
+ final[item] = tuple(data[index])
236
+ return final, total, result2[1]
237
+
238
+ def inequality_solve(eq):
239
+
240
+ eq = logic0(eq)
241
+ element = []
242
+ def helper(eq):
243
+ nonlocal element
244
+
245
+ if eq.name[2:] in "le ge lt gt eq".split(" ") and "v_" in str_form(eq):
246
+ element.append(eq)
247
+ return TreeNode(eq.name, [helper(child) for child in eq.children])
248
+ helper(eq)
249
+
250
+ out = build(list(set(element)))
251
+
252
+ if out is None:
253
+ return eq
254
+
255
+ def helper2(eq):
256
+ nonlocal out
257
+ if eq == tree_form("s_true"):
258
+ return [set(item) for item in out[1]]
259
+ if eq == tree_form("s_false"):
260
+ return [set(), set(), set()]
261
+ if eq in out[0].keys():
262
+ return [set(item) for item in out[0][eq]]
263
+ if eq.name == "f_or":
264
+ result = [helper2(child) for child in eq.children]
265
+ a = []
266
+ b = []
267
+ c = []
268
+ for item in result:
269
+ a += [item[0]]
270
+ b += [item[1]]
271
+ c += [item[2]]
272
+ x = a[0]
273
+ for item in a[1:]:
274
+ x |= item
275
+ y = b[0]
276
+ for item in b[1:]:
277
+ y |= item
278
+ z = c[0]
279
+ for item in c[1:]:
280
+ z |= item
281
+ return [x, y, z]
282
+ if eq.name == "f_and":
283
+ result = [helper2(child) for child in eq.children]
284
+ a = []
285
+ b = []
286
+ c = []
287
+ for item in result:
288
+ a += [item[0]]
289
+ b += [item[1]]
290
+ c += [item[2]]
291
+ x = a[0]
292
+ for item in a[1:]:
293
+ x &= item
294
+ y = b[0]
295
+ for item in b[1:]:
296
+ y &= item
297
+ z = c[0]
298
+ for item in c[1:]:
299
+ z &= item
300
+ return [x, y, z]
301
+ if eq.name == "f_not":
302
+ eq2 = helper2(eq.children[0])
303
+ a,b,c= eq2
304
+ d,e,f= [set(item) for item in out[1]]
305
+ return [d-a,e-b,f-c]
306
+ return helper2(dowhile(eq, lambda x: logic0(expand(simplify(eq)))))
307
+ out2 = helper2(eq)
308
+
309
+ out = list(out)
310
+ out[1] = [set(item) for item in out[1]]
311
+ if tuple(out[1]) == (set(), set(), set()):
312
+ return eq
313
+ if tuple(out[1]) == tuple(out2):
314
+ return tree_form("s_true")
315
+ if tuple(out2) == (set(), set(), set()):
316
+ return tree_form("s_false")
317
+ return eq
mathai/console.py ADDED
@@ -0,0 +1,84 @@
1
+ import copy
2
+ from .expand import expand
3
+ from .parser import parse
4
+ from .printeq import printeq, printeq_log
5
+ from .simplify import solve, simplify
6
+
7
+ from .diff import diff
8
+ from .base import *
9
+ from .factor import _factorconst, factor
10
+ from .fraction import fraction
11
+ from .inverse import inverse
12
+ from .trig import trig0, trig1, trig2, trig3, trig4
13
+ from .logic import logic0, logic1, logic2, logic3
14
+ from .apart import apart
15
+
16
+ def console():
17
+ eq = None
18
+ orig = None
19
+ while True:
20
+ command = input(">>> ")
21
+ try:
22
+ orig = copy.deepcopy(eq)
23
+ if command == "expand":
24
+ eq = expand(eq)
25
+ elif command.split(" ")[0] == "inverse":
26
+ eq=simplify(eq)
27
+ if eq.name == "f_eq":
28
+ eq3 = eq.children[0]-eq.children[1]
29
+ eq2 = parse(command.split(" ")[1])
30
+ out = inverse(eq3, str_form(eq2))
31
+ eq = TreeNode(eq.name, [eq2,out])
32
+ elif command == "apart":
33
+ eq = apart(eq, vlist(eq)[0])
34
+ elif command == "rawprint":
35
+ print(eq)
36
+ elif command == "logic0":
37
+ eq = logic0(eq)
38
+ elif command == "logic1":
39
+ eq = logic1(eq)
40
+ elif command == "logic2":
41
+ eq = logic2(eq)
42
+ elif command == "logic3":
43
+ eq = logic3(eq)
44
+ elif command == "trig0":
45
+ eq = trig0(eq)
46
+ elif command == "trig1":
47
+ eq = trig1(eq)
48
+ elif command == "factor":
49
+ eq = factor(eq)
50
+ elif command == "trig2":
51
+ eq = trig2(eq)
52
+ elif command == "trig3":
53
+ eq = trig3(eq)
54
+ elif command == "trig4":
55
+ eq = trig4(eq)
56
+ elif command == "simplify":
57
+ eq = _factorconst(eq)
58
+ eq = simplify(eq)
59
+ elif command == "fraction":
60
+ eq = fraction(eq)
61
+ elif command.split(" ")[0] in ["integrate", "sqint", "byparts"]:
62
+ if command.split(" ")[0] == "sqint":
63
+ typesqint()
64
+ elif command.split(" ")[0] == "byparts":
65
+ typebyparts()
66
+ elif command.split(" ")[0] == "integrate":
67
+ typeintegrate()
68
+ out = integrate(eq, parse(command.split(" ")[1]).name)
69
+ if out is None:
70
+ print("failed to integrate")
71
+ else:
72
+ eq, logs = out
73
+ eq = simplify(eq)
74
+ printeq_log(logs)
75
+ print()
76
+ elif command.split(" ")[0] == "diff":
77
+ eq = diff(eq, parse(command.split(" ")[1]).name)
78
+ else:
79
+ eq = parse(command)
80
+ eq = copy.deepcopy(eq)
81
+ printeq(eq)
82
+ except:
83
+ eq = copy.deepcopy(orig)
84
+ print("error")
mathai/factor.py CHANGED
@@ -171,8 +171,7 @@ def factor_quar_formula_init():
171
171
  formula_gen9 = factor_quar_formula_init()
172
172
  def factor_helper(equation, complexnum, power=2):
173
173
  global formula_gen9
174
- if equation.name[2:] in "and or not eq le ge lt gt".split(" "):
175
- return TreeNode(equation.name, [factor_helper(child, complexnum, power) for child in equation.children])
174
+
176
175
  maxnum=1
177
176
  alloclst = []
178
177
  for i in range(0,26):
mathai/linear.py CHANGED
@@ -1,9 +1,12 @@
1
+ from .inverse import inverse
2
+ import itertools
1
3
  from .diff import diff
2
4
  from .simplify import simplify, solve
3
5
  from .fraction import fraction
4
6
  from .expand import expand
5
7
  from .base import *
6
8
  from .factor import factorconst
9
+ from .tool import poly
7
10
  def ss(eq):
8
11
  return dowhile(eq, lambda x: fraction(expand(simplify(x))))
9
12
  def rref(matrix):
@@ -31,38 +34,16 @@ def rref(matrix):
31
34
  return matrix
32
35
  def islinear(eq, fxconst):
33
36
  eq =simplify(eq)
34
- if eq.name == "f_pow" and fxconst(eq):#"v_" in str_form(eq):
35
- return False
36
- for child in eq.children:
37
- out = islinear(child, fxconst)
38
- if not out:
39
- return out
40
- return True
37
+ if all(fxconst(tree_form(item)) and poly(eq, item) is not None and len(poly(eq, item)) <= 2 for item in vlist(eq)):
38
+ return True
39
+ return False
41
40
  def linear(eqlist, fxconst):
42
- final = []
43
- extra = []
44
- for i in range(len(eqlist)-1,-1,-1):
45
- if eqlist[i].name == "f_mul" and not islinear(expand2(eqlist[i]), fxconst):
46
- if "v_" in str_form(eqlist[i]):
47
- eqlist[i] = TreeNode("f_mul", [child for child in eqlist[i].children if fxconst(child)])
48
- if all(islinear(child, fxconst) for child in eqlist[i].children):
49
- for child in eqlist[i].children:
50
- extra.append(TreeNode("f_eq", [child, tree_form("d_0")]))
51
- eqlist.pop(i)
52
- else:
53
- final.append(TreeNode("f_eq", [eqlist[i], tree_form("d_0")]))
54
- eqlist.pop(i)
41
+ orig = [item.copy_tree() for item in eqlist]
42
+ #eqlist = [eq for eq in eqlist if fxconst(eq)]
55
43
 
56
- if extra != []:
57
- final.append(TreeNode("f_or", extra))
58
- if eqlist == []:
59
- if len(final)==1:
60
-
61
- return final[0]
62
- return TreeNode("f_and", final)
63
- eqlist = [eq for eq in eqlist if fxconst(eq)]
64
- if not all(islinear(eq, fxconst) for eq in eqlist):
65
- return TreeNode("f_and", copy.deepcopy(final+eqlist))
44
+ if eqlist == [] or not all(islinear(eq, fxconst) for eq in eqlist):
45
+ return None
46
+ #return TreeNode("f_and", [TreeNode("f_eq", [x, tree_form("d_0")]) for x in orig])
66
47
  vl = []
67
48
  def varlist(eq, fxconst):
68
49
  nonlocal vl
@@ -75,7 +56,7 @@ def linear(eqlist, fxconst):
75
56
  vl = list(set(vl))
76
57
 
77
58
  if len(vl) > len(eqlist):
78
- return TreeNode("f_and", final+[TreeNode("f_eq", [x, tree_form("d_0")]) for x in eqlist])
59
+ return TreeNode("f_and", [TreeNode("f_eq", [x, tree_form("d_0")]) for x in eqlist])
79
60
  m = []
80
61
  for eq in eqlist:
81
62
  s = copy.deepcopy(eq)
@@ -94,63 +75,91 @@ def linear(eqlist, fxconst):
94
75
  for i in range(len(m)):
95
76
  for j in range(len(m[i])):
96
77
  m[i][j] = fraction(m[i][j])
97
-
98
- for item in m:
99
- if all(item2==tree_form("d_0") for item2 in item[:-1]) and item[-1] != tree_form("d_0"):
100
- return tree_form("s_false")
101
78
 
102
79
  output = []
103
80
  for index, row in enumerate(m):
104
- count = 0
105
- for item in row[:-1]:
106
- if item == tree_form("d_1"):
107
- count += 1
108
- if count == 2:
109
- break
110
- elif item == tree_form("d_0") and count == 1:
111
- break
112
- if count == 0:
113
- continue
114
- output.append(tree_form(vl[index])+row[-1])
115
- if len(output) == 1 and len(final)==0:
81
+ if not all(item == 0 for item in row[:-1]):
82
+ output.append(summation([tree_form(vl[index2])*coeff for index2, coeff in enumerate(row[:-1])])+row[-1])
83
+ elif row[-1] != 0:
84
+ return tree_form("s_false")
85
+ if len(output) == 1:
116
86
  return TreeNode("f_eq", [output[0], tree_form("d_0")])
117
- return TreeNode("f_and", final+[TreeNode("f_eq", [x, tree_form("d_0")]) for x in output])
87
+ if len(output) == 0:
88
+ return tree_form("s_false")
89
+ return TreeNode("f_and", [TreeNode("f_eq", [x, tree_form("d_0")]) for x in output])
90
+ def order_collinear_indices(points, idx):
91
+ """
92
+ Arrange a subset of collinear points (given by indices) along their line.
93
+
94
+ points: list of (x, y) tuples
95
+ idx: list of indices referring to points
96
+ Returns: list of indices sorted along the line
97
+ """
98
+ if len(idx) <= 1:
99
+ return idx[:]
100
+
101
+ # Take first two points from the subset to define the line
102
+ p0, p1 = points[idx[0]], points[idx[1]]
103
+ dx, dy = p1[0] - p0[0], p1[1] - p0[1]
104
+
105
+ # Projection factor for sorting
106
+ def projection_factor(i):
107
+ vx, vy = points[i][0] - p0[0], points[i][1] - p0[1]
108
+ return compute((vx * dx + vy * dy) / (dx**2 + dy**2))
109
+
110
+ # Sort indices by projection
111
+ sorted_idx = sorted(idx, key=projection_factor)
112
+ return list(sorted_idx)
113
+ def linear_or(eq):
114
+ eqlst =[]
115
+ if eq.name != "f_or":
116
+ eqlst = [eq]
117
+ else:
118
+ eqlst = eq.children
119
+ v = vlist(eq)
120
+ p = []
121
+ line = {}
122
+ for i in range(len(eqlst)):
123
+ line[i] = []
124
+ for item in itertools.combinations(enumerate(eqlst), 2):
125
+ x, y = item[0][0], item[1][0]
126
+ item = [item[0][1], item[1][1]]
127
+
128
+ out = linear_solve(TreeNode("f_and", list(item)))
118
129
 
119
- def rmeq(eq):
120
- if eq.name == "f_eq":
121
- return rmeq(eq.children[0])
122
- return TreeNode(eq.name, [rmeq(child) for child in eq.children])
130
+ if out is None:
131
+ return None
132
+
133
+ if out.name == "f_and" and all(len(vlist(child)) == 1 for child in out.children) and set(vlist(out)) == set(v) and all(len(vlist(simplify(child))) >0 for child in out.children):
134
+ t = {}
135
+ for child in out.children:
136
+ t[v.index(vlist(child)[0])] = simplify(inverse(child.children[0], vlist(child)[0]))
137
+ t2 = []
138
+ for key in sorted(t.keys()):
139
+ t2.append(t[key])
140
+ t2 = tuple(t2)
141
+ if t2 not in p:
142
+ p.append(t2)
143
+ line[x] += [p.index(t2)]
144
+ line[y] += [p.index(t2)]
145
+ line2 = []
146
+ for key in sorted(line.keys()):
147
+ line2.append(order_collinear_indices(p, list(set(line[key]))))
123
148
 
124
- def mat0(eq, lst=None):
125
- def findeq(eq):
126
- out = []
127
- if "f_list" not in str_form(eq) and "f_eq" not in str_form(eq):
128
- return [str_form(eq)]
129
- else:
130
- for child in eq.children:
131
- out += findeq(child)
132
- return out
133
- eqlist = findeq(eq)
134
- eqlist = [tree_form(x) for x in eqlist]
135
- eqlist = [rmeq(x) for x in eqlist]
136
- eqlist = [TreeNode("f_mul", factor_generation(x)) for x in eqlist if x != tree_form("d_0")]
137
- eqlist = [x.children[0] if len(x.children) == 1 else x for x in eqlist]
149
+ return v, p, line2, eqlst
150
+ def linear_solve(eq, lst=None):
151
+ eq = simplify(eq)
152
+ eqlist = []
153
+ if eq.name =="f_and" and all(child.name == "f_eq" and child.children[1] == 0 for child in eq.children):
154
+
155
+ eqlist = [child.children[0] for child in eq.children]
156
+ else:
157
+ return eq
138
158
  out = None
139
-
140
159
  if lst is None:
141
160
  out = linear(copy.deepcopy(eqlist), lambda x: "v_" in str_form(x))
142
161
  else:
143
162
  out = linear(copy.deepcopy(eqlist), lambda x: any(contain(x, item) for item in lst))
144
- def rms(eq):
145
- if eq.name in ["f_and", "f_or"] and len(eq.children) == 1:
146
- return eq.children[0]
147
- return TreeNode(eq.name, [rms(child) for child in eq.children])
148
- return rms(out)
149
- def linear_solve(eq, lst=None):
150
- if eq.name == "f_and":
151
- eq2 = copy.deepcopy(eq)
152
- eq2.name = "f_list"
153
- return mat0(eq2, lst)
154
- elif eq.name == "f_eq":
155
- return mat0(eq, lst)
156
- return TreeNode(eq.name, [linear_solve(child, lst) for child in eq.children])
163
+ if out is None:
164
+ return None
165
+ return simplify(out)
mathai/parser.py CHANGED
@@ -73,9 +73,15 @@ CNUMBER: /c[0-9]+/
73
73
  %ignore WS_INLINE
74
74
  """
75
75
 
76
- def parse(equation):
76
+ def parse(equation, funclist=None):
77
77
  equation = copy.copy(equation.replace(" ", ""))
78
78
  grammar2 = copy.deepcopy(grammar)
79
+ if funclist is not None:
80
+ output = grammar2.split("\n")
81
+ for i in range(len(output)):
82
+ if "FUNC_NAME:" in output[i]:
83
+ output[i] = output[i].replace("FUNC_NAME: ", "FUNC_NAME: " + " | ".join(['"' + x + '"' for x in funclist]) + " | ")
84
+ grammar2 = "\n".join(output)
79
85
 
80
86
  parser_main = Lark(grammar2, start='start', parser='lalr')
81
87
  parse_tree = parser_main.parse(equation)
@@ -112,42 +118,21 @@ def parse(equation):
112
118
 
113
119
  # Convert function names and constants
114
120
  def fxchange(tree_node):
115
- tmp3 = []
116
-
117
- # Handle negation
121
+ tmp3 = funclist if funclist is not None else []
118
122
  if tree_node.name == "neg":
119
123
  child = fxchange(tree_node.children[0])
124
+ # if the child is a number, make it negative
120
125
  if child.name.startswith("d_") and re.match(r"d_\d+(\.\d+)?$", child.name):
121
126
  return TreeNode("d_" + str(-int(child.name[2:])))
122
127
  else:
128
+ # otherwise subtract from zero
123
129
  return TreeNode("f_sub", [tree_form("d_0"), child])
124
-
125
- # Pass through node
126
130
  if tree_node.name == "pass_through":
127
131
  return fxchange(tree_node.children[0])
128
-
129
- # Define function name categories
130
- builtin_funcs = tmp3 + [
131
- "try","ref","sqrt","imply","forall","exist","exclude","union","intersection","len",
132
- "index","angle","charge","sum2","electricfield","line","point","sum","transpose",
133
- "equationrhs","equationlhs","equation","covariance","variance","expect","error",
134
- "laplace","dot","curl","pdif","diverge","gradient","rad","ge","le","gt","lt",
135
- "eqtri","linesegment","midpoint","mag","point1","point2","point3","line1","line2",
136
- "line3","log10","arcsin","arccos","arctan","list","cosec","sec","cot","equiv",
137
- "or","not","and","circumcenter","eq","sub","add","sin","cos","tan","mul",
138
- "integrate","dif","pow","div","log","abs"
139
- ]
140
-
141
- # --- NEW: detect F + digits ---
142
- if re.match(r"F\d+$", tree_node.name):
143
- new_name = "f_" + tree_node.name # e.g., F12 → f_F12
144
- elif tree_node.name in builtin_funcs:
145
- new_name = "f_" + tree_node.name
146
- else:
147
- new_name = "d_" + tree_node.name
148
-
149
- return TreeNode(new_name, [fxchange(child) for child in tree_node.children])
150
-
132
+ return TreeNode(
133
+ "f_" + tree_node.name if tree_node.name in tmp3 + ["try", "ref", "sqrt","imply","forall","exist","exclude","union","intersection","len","index","angle","charge","sum2","electricfield","line","point","sum","transpose","equationrhs","equationlhs","equation","covariance","variance","expect","error","laplace","dot","curl","pdif","diverge","gradient","rad","ge","le","gt","lt","eqtri","linesegment","midpoint","mag","point1","point2","point3","line1","line2","line3","log10","arcsin","arccos","arctan","list","cosec","sec","cot","equiv","or","not","and","circumcenter","eq","sub","add","sin","cos","tan","mul","integrate","dif","pow","div","log","abs"] else "d_" + tree_node.name,
134
+ [fxchange(child) for child in tree_node.children]
135
+ )
151
136
 
152
137
  tree_node = fxchange(tree_node)
153
138
 
mathai/tool.py CHANGED
@@ -4,7 +4,6 @@ from .simplify import simplify, solve
4
4
  from .base import *
5
5
  import math
6
6
 
7
-
8
7
  def poly_div(dividend_coeffs, divisor_coeffs):
9
8
  """
10
9
  Perform polynomial division using coefficients with symbolic simplification.
@@ -9,71 +9,7 @@ from .expand import expand
9
9
  from .fraction import fraction
10
10
  import copy
11
11
  from .diff import diff
12
-
13
- from .factor import merge_sqrt
14
- from .factor import rationalize_sqrt as rationalize
15
-
16
- from functools import cmp_to_key
17
-
18
-
19
- def arithmetic(eq):
20
- eq = dowhile(eq, lambda x: handle_sqrt(simplify(merge_sqrt(rationalize(x)))))
21
- def helper(eq):
22
- if eq.name[2:] in "le ge gt lt eq".split(" "):
23
- a, b = frac(eq.children[0]), frac(eq.children[1])
24
-
25
- if a is not None and b is not None:
26
- out = {"le": lambda x, y: x <= y, "ge":lambda x, y: x >= y, "lt":lambda x, y: x < y,\
27
- "gt":lambda x, y: x > y, "eq":lambda x, y: x == y}[eq.name[2:]](a, b)
28
- if out:
29
- return tree_form("s_true")
30
- else:
31
- return tree_form("s_false")
32
- return TreeNode(eq.name, [helper(child) for child in eq.children])
33
- def helper2(eq):
34
- if eq.children == []:
35
- if eq == tree_form("s_true"):
36
- return True
37
- elif eq == tree_form("s_false"):
38
- return False
39
- else:
40
- return None
41
- if eq.name == "f_or":
42
- out = [helper2(child) for child in eq.children]
43
- if None in out:
44
- return None
45
- return any(out)
46
- if eq.name == "f_and":
47
- out = [helper2(child) for child in eq.children]
48
- if None in out:
49
- return None
50
- return all(out)
51
- if eq.name == "f_not":
52
- out = [helper2(child) for child in eq.children]
53
- if None in out:
54
- return None
55
- return not out[0]
56
- return None
57
-
58
- return helper2(eq)
59
-
60
- def less_than(eq1, eq2):
61
- return arithmetic(TreeNode("f_le", [eq1,eq2]))
62
- def equal_to(eq1, eq2):
63
- return arithmetic(TreeNode("f_eq", [eq1,eq2]))
64
- def custom_compare(a, b):
65
-
66
- y = equal_to(a, b)
67
- if y is not None:
68
- if y:
69
- return -1
70
- x = less_than(a, b)
71
- if x is not None:
72
- if x:
73
- return -1
74
- else:
75
- return 1
76
- return 0
12
+ from .logic import logic0
77
13
  def intersection2(domain, lst):
78
14
  domain = copy.deepcopy(domain)
79
15
  if domain == [True]:
@@ -87,14 +23,14 @@ def intersection2(domain, lst):
87
23
 
88
24
  if isinstance(domain[index], bool) and domain[index]:
89
25
 
90
- if index == 0 and less_than(item2, domain[index+1]):
26
+ if index == 0 and compute(item2) < compute(domain[index+1]):
91
27
 
92
28
  out.append(item2)
93
29
  break
94
- elif index == len(domain)-1 and less_than(domain[index-1], item2):
30
+ elif index == len(domain)-1 and compute(domain[index-1]) < compute(item2):
95
31
  out.append(item2)
96
32
  break
97
- elif index != 0 and index != len(domain)-1 and less_than(domain[index-1], item2) and less_than(item2, domain[index+1]):
33
+ elif index != 0 and index != len(domain)-1 and compute(domain[index-1]) < compute(item2) and compute(item2) < compute(domain[index+1]):
98
34
 
99
35
  out.append(item2)
100
36
  break
@@ -128,8 +64,7 @@ def intersection(domain_1, domain_2):
128
64
  result = domain_1 + domain_2
129
65
  result = [item for item in result if not isinstance(item, bool)]
130
66
  result = list(set(result))
131
-
132
- result = sorted(result, key=cmp_to_key(custom_compare))
67
+ result = sorted(result, key=lambda x: compute(x))
133
68
  i = len(result)
134
69
  while i>=0:
135
70
  result.insert(i, True)
@@ -281,7 +216,7 @@ def helper(eq, var="v_0"):
281
216
  item = simplify(expand(item))
282
217
 
283
218
  if len(vlist(item)) == 0:
284
- if less_than(item, tree_form("d_0")):
219
+ if compute(item) <0:
285
220
  sign = not sign
286
221
  continue
287
222
  v = vlist(item)[0]
@@ -295,12 +230,12 @@ def helper(eq, var="v_0"):
295
230
  a = replace(diff(diff(item, v), v), tree_form(v), tree_form("d_0"))/tree_form("d_2")
296
231
  if "v_" in str_form(a):
297
232
  return None
298
- if less_than(a, tree_form("d_0")):
233
+ if compute(a) < 0:
299
234
  sign = not sign
300
235
  continue
301
236
  else:
302
237
  tmp2 = diff(copy.deepcopy(item))
303
- if less_than(tmp2, tree_form("d_0")):
238
+ if compute(tmp2)<0:
304
239
  sign = not sign
305
240
  item = simplify(item * tree_form("d_-1"))
306
241
  out = inverse(item, vlist(item)[0])
@@ -312,12 +247,12 @@ def helper(eq, var="v_0"):
312
247
  a = replace(diff(diff(item, v), v), tree_form(v), tree_form("d_0"))/tree_form("d_2")
313
248
  if "v_" in str_form(a):
314
249
  return None
315
- if less_than(a, tree_form("d_0")):
250
+ if compute(a) < 0:
316
251
  sign = not sign
317
252
  continue
318
253
  else:
319
254
  tmp2 = diff(copy.deepcopy(item))
320
- if less_than(tmp2, tree_form("d_0")):
255
+ if compute(tmp2)<0:
321
256
  sign = not sign
322
257
  item = simplify(item * tree_form("d_-1"))
323
258
  out = inverse(item, vlist(item)[0])
@@ -329,7 +264,7 @@ def helper(eq, var="v_0"):
329
264
  critical = [simplify(item) for item in critical]
330
265
  critical = Counter(critical)
331
266
 
332
- critical = sorted(critical.items(), key=cmp_to_key(lambda a,b: custom_compare(a[0], b[0])))
267
+ critical = sorted(critical.items(), key=lambda x: compute(x[0]))
333
268
 
334
269
  i = len(critical)
335
270
  element = sign
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mathai
3
- Version: 0.4.9
3
+ Version: 0.5.1
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
@@ -1,24 +1,26 @@
1
- mathai/__init__.py,sha256=_cw5FqfRBxoeFYc-9EDbRuZ7ZGTSBslgNcMO4zR31Bs,1418
1
+ mathai/__init__.py,sha256=O3P2_Q64gwo1CmgD4cwhl3fGUQc3wGa0-b9z8MBtFaI,1481
2
2
  mathai/apart.py,sha256=VSS3khE9PNuxiRvdU5JDl4IN-KJBSIFjwR17pkhviXI,4197
3
- mathai/base.py,sha256=Di775V_upyhrel4--cNhG3Zskj5BKan0cAcjjFHjSzA,12721
3
+ mathai/base.py,sha256=Ma1oCRbaZP0bp0Qnt_ZjKAh3rt9nZXQ_rmJL0sAoz5c,12730
4
+ mathai/bivariate_inequality.py,sha256=FJOC2zKU5zWCMybCrhEQ7nVDgRO_w19Zko8WPTaDTSo,11411
5
+ mathai/console.py,sha256=Sn58iwYE79MLEh67s8X3q6vZjw6g7f9XM1T8_dBBR2o,3048
4
6
  mathai/diff.py,sha256=YUBpRsz0qmBkq5vGxeGnvR4nMKjdOQiIXlNMxpij2ns,3051
5
7
  mathai/expand.py,sha256=SnBltkpIENMGkP0AYmbMlSc4H-CF5RslO2PcBEkn1BQ,3359
6
- mathai/factor.py,sha256=6iXnm-TB4HRjzCki5dLi_NNhFIiRYE3h7_c4111zta8,11509
8
+ mathai/factor.py,sha256=Xkx2_lxq-Z-t55dA9F2W4EH-3Uc1CFXj_6oESQdWAHM,11332
7
9
  mathai/fraction.py,sha256=Q2ztsh5Bpz6YhML2QU0tfufbAs0Q6J319AhlzKephIY,4396
8
10
  mathai/integrate.py,sha256=ewV46QDD0-oiTWpSkmcpcZhBz9StcntbTV1tBLCo1Wo,16502
9
11
  mathai/inverse.py,sha256=QCvDrzKquWsZv-BDAzZd9HnU0c3gZvcc44UztHVO5LQ,2919
10
12
  mathai/limit.py,sha256=bn7eofIOJv4AIh0-FmLppZ3DKnGfbwOzXks2XOPTOs0,4932
11
- mathai/linear.py,sha256=BzSnm941Zlod_l6hON4Rs6J4pdAA3MGpRVqr6-66ZBk,5524
13
+ mathai/linear.py,sha256=Mmmnn4IdnADRMuv6crB0a_Ba2drGUFXOh7eqIIkirYA,5709
12
14
  mathai/logic.py,sha256=UvHzRmKcO9AD51tRzHmpNSEhgW5gmaf4XPaQKFjGfC4,9653
13
15
  mathai/ode.py,sha256=zxxTXAOpt7oSsfpgI4vHsCWKXevmM96ZOBZWWs-vj8Y,4801
14
- mathai/parser.py,sha256=XEeWgfqRinTAXWKFg5NtkTQWvFgMgtr0BfrJmvyuPQM,6970
16
+ mathai/parser.py,sha256=f7bemieFmp0sbup1NlraMLvZDVFvqKGFknEVtlFRMVk,6979
15
17
  mathai/printeq.py,sha256=gIes-pstFOa6FcnpVIVvkjVKuWdsVdo11LlEnmHhakU,1303
16
18
  mathai/simplify.py,sha256=nR5IReewrJ7HbxEUzQ2zg9xoFcwI1R5lGjWnX1pBKko,16885
17
19
  mathai/structure.py,sha256=4Ww2IAx62RcQSO7_17TZES-DjMWBpcFQtL939FBIHwY,4103
18
- mathai/tool.py,sha256=ivU4urQ9QxvfIO6bXqNtOvza4HnuZZfaO2m-bCuHaWc,6068
20
+ mathai/tool.py,sha256=r8ejBY4Bnk_t8USYQCuxwmmJ4M-5H5OR6A3VbV7W-5w,6066
19
21
  mathai/trig.py,sha256=BQd_Gl_u0g5ZuZIwKozuXKbMinqb6K-OYicrtftn7eg,11174
20
- mathai/univariate_inequality.py,sha256=4Uwzneoofb-q8hFg6TsqK1SZTBCnGHbYUU9XoyspA5M,16996
21
- mathai-0.4.9.dist-info/METADATA,sha256=C4r7cP1Tp2SpN22TaTyobAKHaSGdW2FeyJ4ie3A9X54,7103
22
- mathai-0.4.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
- mathai-0.4.9.dist-info/top_level.txt,sha256=ROP4l3OhGYw3ihkQGASr18xM9GsK4z3_6whV5AyXLwE,7
24
- mathai-0.4.9.dist-info/RECORD,,
22
+ mathai/univariate_inequality.py,sha256=_r-kkiS4Hr-jRN7f-EL_E4svAMFWJP1Ea50HJKKbjfk,14778
23
+ mathai-0.5.1.dist-info/METADATA,sha256=zPDi8RasVepSv0JP4bBx_LszViwltoRJSgR3HOvLNkQ,7103
24
+ mathai-0.5.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
25
+ mathai-0.5.1.dist-info/top_level.txt,sha256=ROP4l3OhGYw3ihkQGASr18xM9GsK4z3_6whV5AyXLwE,7
26
+ mathai-0.5.1.dist-info/RECORD,,
File without changes