mathai 0.4.9__py3-none-any.whl → 0.5.0__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,296 @@
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
+ def shoelace_area(vertices):
8
+ n = len(vertices)
9
+ area = 0.0
10
+ for i in range(n):
11
+ j = (i + 1) % n
12
+ area += vertices[i][0] * vertices[j][1]
13
+ area -= vertices[j][0] * vertices[i][1]
14
+ return abs(area) / 2.0
15
+
16
+ def triangle_area(p1, p2, p3):
17
+ area = 0.0
18
+ area += p1[0] * (p2[1] - p3[1])
19
+ area += p2[0] * (p3[1] - p1[1])
20
+ area += p3[0] * (p1[1] - p2[1])
21
+ return abs(area) / 2.0
22
+
23
+ def is_point_inside_polygon(point, vertices):
24
+ if len(vertices) < 3:
25
+ return False
26
+
27
+ polygon_area = shoelace_area(vertices)
28
+
29
+ total_triangle_area = 0.0
30
+ n = len(vertices)
31
+ for i in range(n):
32
+ j = (i + 1) % n
33
+ total_triangle_area += triangle_area(point, vertices[i], vertices[j])
34
+
35
+ tolerance = 1e-5
36
+ return abs(total_triangle_area - polygon_area) < tolerance
37
+
38
+ def distance_point_to_segment(px, py, x1, y1, x2, y2):
39
+ dx, dy = x2 - x1, y2 - y1
40
+ if dx == dy == 0:
41
+ return ((px - x1)**2 + (py - y1)**2)**0.5
42
+ t = max(0, min(1, ((px - x1) * dx + (py - y1) * dy) / (dx*dx + dy*dy)))
43
+ proj_x = x1 + t * dx
44
+ proj_y = y1 + t * dy
45
+ return ((px - proj_x)**2 + (py - proj_y)**2)**0.5
46
+
47
+ def deterministic_middle_point(vertices, grid_resolution=100):
48
+ xs = [v[0] for v in vertices]
49
+ ys = [v[1] for v in vertices]
50
+ xmin, xmax = min(xs), max(xs)
51
+ ymin, ymax = min(ys), max(ys)
52
+
53
+ best_point = None
54
+ max_dist = -1
55
+
56
+ for i in range(grid_resolution + 1):
57
+ for j in range(grid_resolution + 1):
58
+ px = xmin + (xmax - xmin) * i / grid_resolution
59
+ py = ymin + (ymax - ymin) * j / grid_resolution
60
+ if not is_point_inside_polygon((px, py), vertices):
61
+ continue
62
+ min_edge_dist = float('inf')
63
+ n = len(vertices)
64
+ for k in range(n):
65
+ x1, y1 = vertices[k]
66
+ x2, y2 = vertices[(k + 1) % n]
67
+ d = distance_point_to_segment(px, py, x1, y1, x2, y2)
68
+ min_edge_dist = min(min_edge_dist, d)
69
+ if min_edge_dist > max_dist:
70
+ max_dist = min_edge_dist
71
+ best_point = (px, py)
72
+
73
+ return best_point
74
+
75
+ def build(eq):
76
+ if len(eq) <= 1:
77
+ return None
78
+ eq = TreeNode("f_or", eq)
79
+ eq = flatten_tree(eq)
80
+ orig = eq.copy_tree()
81
+ def fxhelper3(eq):
82
+ if eq.name[2:] in "le ge lt gt".split(" "):
83
+ return TreeNode("f_eq", [child.copy_tree() for child in eq.children])
84
+ return TreeNode(eq.name, [fxhelper3(child) for child in eq.children])
85
+ eq = fxhelper3(eq)
86
+
87
+ result = linear_or(eq)
88
+ maxnum = tree_form("d_2")
89
+ if len(result[1]) != 0:
90
+ 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))
91
+ maxnum += 1
92
+ maxnum = simplify(maxnum)
93
+ eq = flatten_tree(eq | simplify(TreeNode("f_or", [TreeNode("f_eq", [tree_form(item)+maxnum, tree_form("d_0")])|\
94
+ TreeNode("f_eq", [tree_form(item)-maxnum, tree_form("d_0")]) for item in vlist(eq)])))
95
+ result2 = linear_or(eq)
96
+
97
+ point_lst = result2[2]
98
+
99
+ def gen(point):
100
+ nonlocal point_lst
101
+ out = []
102
+ for item in point_lst:
103
+ p = None
104
+ if point in item:
105
+ p = item.index(point)
106
+ else:
107
+ continue
108
+ if p < len(item)-1:
109
+ out.append(item[p+1])
110
+ if p > 0:
111
+ out.append(item[p-1])
112
+ return list(set(out))
113
+ start = list(range(len(result2[1])))
114
+ graph= {}
115
+ for item in start:
116
+ graph[item] = gen(item)
117
+
118
+ points = {}
119
+ for index, item in enumerate(result2[1]):
120
+ points[index] = [compute(item2) for item2 in item]
121
+
122
+ res = []
123
+ for index, item in enumerate(result2[1]):
124
+ if any(simplify(item2.fx("abs")-maxnum)!=0 and abs(compute(item2))>compute(maxnum) for item2 in item):
125
+ res.append(index)
126
+
127
+ graph = {k: sorted(v) for k, v in graph.items()}
128
+
129
+ def dfs(current, parent, path, visited, cycles):
130
+ path.append(current)
131
+ visited.add(current)
132
+ for neighbor in graph[current]:
133
+ if neighbor == parent:
134
+ continue
135
+ if neighbor in visited:
136
+ idx = path.index(neighbor)
137
+ cycle = path[idx:]
138
+ cycles.append(cycle)
139
+ else:
140
+ dfs(neighbor, current, path, visited, cycles)
141
+ path.pop()
142
+ visited.remove(current)
143
+
144
+ cycles = []
145
+ for start in sorted(graph.keys()):
146
+ path = []
147
+ visited = set()
148
+ dfs(start, -1, path, visited, cycles)
149
+
150
+ def normalize(cycle):
151
+ k = len(cycle)
152
+ if k < 3:
153
+ return None
154
+ candidates = []
155
+ for direction in [cycle, list(reversed(cycle))]:
156
+ doubled = direction + direction[:-1]
157
+ for i in range(k):
158
+ rot = tuple(doubled[i:i + k])
159
+ candidates.append(rot)
160
+ return min(candidates)
161
+
162
+ unique = set()
163
+ for c in cycles:
164
+ norm = normalize(c)
165
+ if norm:
166
+ unique.add(norm)
167
+
168
+ cycles = sorted(list(unique), key=lambda x: (len(x), x))
169
+
170
+ start = list(range(len(result2[1])))
171
+ for i in range(len(cycles)-1,-1,-1):
172
+ if any(item in cycles[i] for item in res) or\
173
+ 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\
174
+ any(len(set(graph[item]) & set(cycles[i]))>2 for item in cycles[i]):
175
+ cycles.pop(i)
176
+
177
+ point_lst = [index for index, item in enumerate(result2[1]) if item in result[1]]
178
+ border = []
179
+ for item in start:
180
+ for item2 in graph[item]:
181
+ a = result2[1][item]
182
+ b = result2[1][item2]
183
+
184
+ if a[0] == b[0] and simplify(a[0].fx("abs") - maxnum) == 0:
185
+ continue
186
+ if a[1] == b[1] and simplify(a[1].fx("abs") - maxnum) == 0:
187
+ continue
188
+ border.append(tuple(sorted([item, item2])))
189
+ line = []
190
+ for key in graph.keys():
191
+ for item in list(set(point_lst)&set(graph[key])):
192
+ line.append(tuple(sorted([item, key])))
193
+ line = list(set(line+border))
194
+ point_in = [deterministic_middle_point([[compute(item3) for item3 in result2[1][item2]] for item2 in item]) for item in cycles]
195
+ def work(eq, point):
196
+ if "f_eq" in str_form(eq):
197
+ return False
198
+ nonlocal result2
199
+ if eq.name[:2] == "d_":
200
+ return float(eq.name[2:])
201
+ if eq.name in result2[0]:
202
+ return point[result2[0].index(eq.name)]
203
+ if eq.name == "f_add":
204
+ return sum(work(item, point) for item in eq.children)
205
+ if eq.name == "f_mul":
206
+ return math.prod(work(item, point) for item in eq.children)
207
+ return {"gt":lambda a,b: a>b, "lt":lambda a,b: a<b}[eq.name[2:]](work(eq.children[0], point), work(eq.children[1], point))
208
+
209
+ data = []
210
+ for index, item in enumerate(result2[2][:-4]):
211
+ a = tuple(set(item) & set(point_lst))
212
+ b = tuple(set([tuple(sorted([item[i], item[i+1]])) for i in range(len(item)-1)]) & set(line))
213
+ c = tuple([tuple(item) for index2, item in enumerate(cycles) if work(orig.children[index], point_in[index2])])
214
+ data.append((a,b,c))
215
+
216
+ total = tuple([tuple(point_lst), tuple(line), tuple(cycles)])
217
+ final = {}
218
+ for index, item in enumerate(orig.children):
219
+ final[item] = tuple(data[index])
220
+ return final, total, result2[1]
221
+
222
+ def inequality_solve(eq):
223
+ element = []
224
+ def helper(eq):
225
+ nonlocal element
226
+ if eq.name[2:] in "le ge lt gt eq".split(" ") and "v_" in str_form(eq):
227
+ element.append(eq)
228
+ return TreeNode(eq.name, [helper(child) for child in eq.children])
229
+ helper(eq)
230
+
231
+ out = build(list(set(element)))
232
+
233
+ if out is None:
234
+ return eq
235
+
236
+ def helper2(eq):
237
+ nonlocal out
238
+ if eq == tree_form("s_true"):
239
+ return [set(item) for item in out[1]]
240
+ if eq == tree_form("s_false"):
241
+ return [set(), set(), set()]
242
+ if eq in out[0].keys():
243
+ return [set(item) for item in out[0][eq]]
244
+ if eq.name == "f_or":
245
+ result = [helper2(child) for child in eq.children]
246
+ a = []
247
+ b = []
248
+ c = []
249
+ for item in result:
250
+ a += [item[0]]
251
+ b += [item[1]]
252
+ c += [item[2]]
253
+ x = a[0]
254
+ for item in a[1:]:
255
+ x |= item
256
+ y = b[0]
257
+ for item in b[1:]:
258
+ y |= item
259
+ z = c[0]
260
+ for item in c[1:]:
261
+ z |= item
262
+ return [x, y, z]
263
+ if eq.name == "f_and":
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_not":
283
+ eq2 = helper2(eq.children[0])
284
+ a,b,c= eq2
285
+ d,e,f= [set(item) for item in out[1]]
286
+ return [d-a,e-b,f-c]
287
+ out2 = helper2(eq)
288
+
289
+ out = list(out)
290
+ out[1] = [set(item) for item in out[1]]
291
+
292
+ if tuple(out[1]) == tuple(out2):
293
+ return tree_form("s_true")
294
+ if tuple(out2) == (set(), set(), set()):
295
+ return tree_form("s_false")
296
+ 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,3 +1,5 @@
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
@@ -39,30 +41,9 @@ def islinear(eq, fxconst):
39
41
  return out
40
42
  return True
41
43
  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)
55
-
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
44
  eqlist = [eq for eq in eqlist if fxconst(eq)]
64
45
  if not all(islinear(eq, fxconst) for eq in eqlist):
65
- return TreeNode("f_and", copy.deepcopy(final+eqlist))
46
+ return TreeNode("f_and", copy.deepcopy(eqlist))
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,83 @@ 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])
118
-
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])
123
-
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]
138
- out = None
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[:]
139
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
+ eq = simplify(eq)
115
+ eqlst =[]
116
+ if eq.name != "f_or":
117
+ eqlst = [eq]
118
+ else:
119
+ eqlst = eq.children
120
+ v = vlist(eq)
121
+ p = []
122
+ line = {}
123
+ for i in range(len(eqlst)):
124
+ line[i] = []
125
+ for item in itertools.combinations(enumerate(eqlst), 2):
126
+ x, y = item[0][0], item[1][0]
127
+ item = [item[0][1], item[1][1]]
128
+ out = linear_solve(TreeNode("f_and", list(item)))
129
+ if out.name == "f_and" and all(len(vlist(child)) == 1 for child in out.children) and set(vlist(out)) == set(v):
130
+ t = {}
131
+ for child in out.children:
132
+ t[v.index(vlist(child)[0])] = simplify(inverse(child.children[0], vlist(child)[0]))
133
+ t2 = []
134
+ for key in sorted(t.keys()):
135
+ t2.append(t[key])
136
+ t2 = tuple(t2)
137
+ if t2 not in p:
138
+ p.append(t2)
139
+ line[x] += [p.index(t2)]
140
+ line[y] += [p.index(t2)]
141
+ line2 = []
142
+ for key in sorted(line.keys()):
143
+ line2.append(order_collinear_indices(p, list(set(line[key]))))
144
+ return v, p, line2, eqlst
145
+ def linear_solve(eq, lst=None):
146
+ eq = simplify(eq)
147
+ eqlist = []
148
+ if eq.name =="f_and" and all(child.name == "f_eq" and child.children[1] == 0 for child in eq.children):
149
+ eqlist = [child.children[0] for child in eq.children]
150
+ else:
151
+ return eq
152
+ out = None
140
153
  if lst is None:
141
154
  out = linear(copy.deepcopy(eqlist), lambda x: "v_" in str_form(x))
142
155
  else:
143
156
  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])
157
+ 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.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
@@ -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=zZlLrs1fywCWyB0L0Ww1G6hh9yltUrQ0Z4DTi4WMWsM,10316
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=53sAEbCHlQUYhhjoUJfhay6x-PuXXPsheFeI9EYxDgc,5448
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.0.dist-info/METADATA,sha256=KeObHgS2oretRbmW0yO37o4AIkliWpBN01nO435awO8,7103
24
+ mathai-0.5.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
25
+ mathai-0.5.0.dist-info/top_level.txt,sha256=ROP4l3OhGYw3ihkQGASr18xM9GsK4z3_6whV5AyXLwE,7
26
+ mathai-0.5.0.dist-info/RECORD,,
File without changes