mathai 0.4.0__py3-none-any.whl → 0.6.9__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/simplify.py CHANGED
@@ -1,362 +1,540 @@
1
1
  import math
2
2
  from .base import *
3
3
  from fractions import Fraction
4
- nolog = False
5
- def set_nolog(val):
6
- global nolog
7
- nolog = val
8
- def _solve(eq):
9
- def solve_add(eq):
10
- def multiplied(eq):
11
- if eq.name[:2] == "d_":
12
- return int(eq.name[2:]), "const"
13
- if eq.name == "f_mul":
14
- arth = 1
15
- for i in range(len(eq.children)-1,-1,-1):
16
- if eq.children[i].name[:2] == "d_":
17
- arth *= int(eq.children[i].name[2:])
18
- eq.children.pop(i)
19
- if eq.children == []:
20
- eq = "const"
21
- elif len(eq.children) == 1:
22
- eq = eq.children[0]
23
- return arth, eq
24
- return 1, eq
25
- if eq.name != "f_add":
26
- return eq
27
- dic = {"const":0}
28
- for child in eq.children:
29
- a, b = multiplied(child)
30
- if b == "const":
31
- dic[b] += a
32
- elif b in dic.keys():
33
- dic[b] += a
34
- else:
35
- dic[b] = a
36
- summation = TreeNode("f_add", [])
37
- for key in sorted(dic.keys(), key=lambda x: str_form(x)):
38
- n = dic[key]
39
- if n == 0:
40
- continue
41
- if key == "const":
42
- summation.children.append(tree_form("d_"+str(n)))
4
+ from collections import Counter
5
+ def convert_to_basic(node):
6
+ if not node.name.startswith("f_"):
7
+ return node
8
+ node.children = [convert_to_basic(c) for c in node.children]
9
+ if node.name == "f_sub":
10
+ node = node.children[0]-node.children[1]
11
+ if node.name == "f_div":
12
+ node = node.children[0]/node.children[1]
13
+ if node.name == "f_sqrt":
14
+ node = node.children[0]**(tree_form("d_2")**tree_form("d_-1"))
15
+ return node
16
+
17
+ def clear_div(eq, denom):
18
+
19
+ lst = factor_generation(eq)
20
+
21
+ if tree_form("d_0") in lst:
22
+ return tree_form("d_0"), True
23
+
24
+ lst3 = []
25
+ for item in lst:
26
+ if "v_" not in str_form(item) and compute(item) < 0:
27
+ lst3.append(item)
28
+ sign = denom
29
+ if len(lst3) % 2 == 1:
30
+ sign = False
31
+ if denom:
32
+ eq2 = []
33
+ eq3 = []
34
+ for item in lst:
35
+ if frac(item) is not None:#"v_" not in str_form(item):
36
+ eq2.append(item)
43
37
  else:
44
- if n == 1:
45
- summation.children.append(key)
46
- else:
47
- if key.name == "f_mul":
48
- key.children.append(tree_form("d_"+str(n)))
49
- else:
50
- key = tree_form("d_"+str(n))*key
51
- summation.children.append(key)
38
+ eq3.append(item)
52
39
 
53
- if len(summation.children)==1:
54
- summation = summation.children[0]
40
+ if eq3 == []:
41
+ return product(eq2), True
42
+ return product(eq3), sign
43
+ lst4 = []
44
+
45
+ for item in lst:
46
+ if item.name == "f_pow":
47
+ tmp = frac(item.children[1])
48
+ if tmp is None or tmp != -1:
49
+ lst4.append(item)
50
+ else:
51
+ lst4.append(item)
52
+
53
+ lst2 = []
54
+ for item in lst4:
55
+ if frac(item) is None:#"v_" in str_form(item):
56
+ lst2.append(item)
55
57
 
56
- if summation.name[:2] == "f_" and len(summation.children)==0:
57
- summation = tree_form("d_0")
58
- return summation
59
-
60
- def solve_mul(eq):
61
- def multiplied(eq):
62
- if eq.name[:2] == "d_":
63
- return int(eq.name[2:]), "const"
64
- if eq.name != "f_pow" or eq.children[1].name[:2] != "d_":
65
- return 1, eq
58
+ if lst2 == []:
59
+ return product(lst4), sign
60
+ return product(lst2), sign
61
+ '''
62
+ def multiply_node(eq):
63
+ if not eq.name.startswith("f_"):
64
+ return eq
65
+ if eq.name == "f_mul":
66
+ con = 1
67
+ eq2 = TreeNode("f_mul", [])
68
+ for i in range(len(eq.children)-1,-1,-1):
69
+ if frac(eq.children[i]) is not None:
70
+ con = con * frac(eq.children[i])
66
71
  else:
67
- return int(eq.children[1].name[2:]), eq.children[0]
68
- if eq.name == "f_pow":
69
- if eq.children[1] == 1:
70
- return eq.children[0]
71
- return eq
72
- if eq.name != "f_mul":
73
- return eq
74
-
75
- dic = {"const":1}
72
+ eq2.children.append(eq.children[i])
73
+ if con == 0:
74
+ return tree_form("d_0")
75
+ eq2.name = eq.name
76
+ eq = eq2
77
+
78
+ lst = {}
76
79
  for child in eq.children:
77
-
78
- a, b = multiplied(child)
79
- if b == "const":
80
- dic[b] *= a
81
- elif b in dic.keys():
82
- dic[b] += a
80
+ power = tree_form("d_1")
81
+ con2 = ""
82
+ if child.name == "f_pow":
83
+ con2 = child.children[0]
84
+ power = child.children[1]
83
85
  else:
84
- dic[b] = a
85
-
86
- summation = TreeNode("f_mul", [])
87
- if dic["const"] == 0:
88
- return tree_form("d_0")
89
- for key in sorted(dic.keys(), key=lambda x: str_form(x)):
90
- n = dic[key]
91
- if n == 0:
92
-
86
+ con2 = child
87
+ if con2 in lst.keys():
88
+ lst[con2] = lst[con2] + power
89
+ else:
90
+ lst[con2] = power
91
+ eq3 = TreeNode("f_mul", [])
92
+
93
+ for kv in lst.keys():
94
+ tmp3 = lst[kv]
95
+ if tmp3 == tree_form("d_1"):
96
+ eq3.children.append(kv)
97
+ elif tmp3 == tree_form("d_0"):
93
98
  continue
94
- if key == "const":
95
- if n != 1:
96
- summation.children.append(tree_form("d_"+str(n)))
97
99
  else:
98
- if n== 1:
99
- summation.children.append(key)
100
- else:
101
- summation.children.append(key**tree_form("d_"+str(n)))
100
+ eq3.children.append(kv ** tmp3)
102
101
 
103
- if len(summation.children)==1:
104
- summation = summation.children[0]
105
-
106
- if summation.name[:2] == "f_" and len(summation.children)==0:
107
- summation = tree_form("d_1")
108
-
109
- return summation
110
- def solve_u(eq):
111
- if eq.name in ["f_pow", "f_mul"]:
112
- return solve_mul(eq)
113
- return solve_add(eq)
114
- def recur_solve(eq):
115
- eq = solve_u(eq)
102
+ tmp3 = frac_to_tree(con)
103
+ if tmp3 != tree_form("d_1"):
104
+ eq3.children.append(tmp3)
105
+ eq = eq3
106
+ eq4 = TreeNode(eq.name, [])
116
107
  if eq.children == []:
117
- pass
108
+ return tree_form("d_1")
109
+ if len(eq.children) == 1:
110
+ eq4 = eq.children[0]
111
+ eq = eq4
112
+ return TreeNode(eq.name, [multiply_node(child) for child in eq.children])
113
+ '''
114
+ def multiply_node(equation):
115
+ """
116
+ Iterative version of multiply_node without using TreeNode as dict key.
117
+ """
118
+ # Stack: (node, child_index, partially_processed_children)
119
+ if equation is None:
120
+ return None
121
+ stack = [(equation, 0, [])]
122
+
123
+ while stack:
124
+ node, child_index, processed_children = stack.pop()
125
+
126
+ # If all children processed
127
+ if child_index >= len(node.children):
128
+ node.children = processed_children
118
129
 
119
- elif eq.name in ("f_add", "f_mul"):
120
- merged_children = []
121
- for child in eq.children:
122
- if child.name == eq.name:
123
- merged_children.extend(child.children)
130
+ # Only process multiplication nodes
131
+ if node.name == "f_mul":
132
+ # Step 1: combine numeric constants
133
+ con = 1
134
+ new_children = []
135
+ for child in reversed(node.children):
136
+ val = frac(child)
137
+ if val is not None:
138
+ con *= val
139
+ else:
140
+ new_children.append(child)
141
+
142
+ if con == 0:
143
+ node = tree_form("d_0")
144
+ # Return to parent
145
+ if stack:
146
+ parent, idx, parent_children = stack.pop()
147
+ parent_children.append(node)
148
+ stack.append((parent, idx + 1, parent_children))
149
+ continue
150
+ else:
151
+ return node
152
+
153
+ node.children = new_children
154
+
155
+ # Step 2: combine powers of same base iteratively
156
+ # Instead of using dict, we collect (base, exponent) in a list
157
+ base_powers = []
158
+ for child in node.children:
159
+ if child.name == "f_pow":
160
+ base, power = child.children
161
+ else:
162
+ base = child
163
+ power = tree_form("d_1")
164
+
165
+ # Look for existing base in base_powers (by structural equality)
166
+ found = False
167
+ for i, (b, p) in enumerate(base_powers):
168
+ if b == base: # structural equality check
169
+ base_powers[i] = (b, p + power)
170
+ found = True
171
+ break
172
+ if not found:
173
+ base_powers.append((base, power))
174
+
175
+ # Step 3: rebuild multiplication node
176
+ new_mul = TreeNode("f_mul", [])
177
+ for base, power in base_powers:
178
+ if power == tree_form("d_1"):
179
+ new_mul.children.append(base)
180
+ elif power == tree_form("d_0"):
181
+ continue
182
+ else:
183
+ new_mul.children.append(TreeNode("f_pow", [base, power]))
184
+
185
+ # Step 4: add numeric constant
186
+ con_tree = frac_to_tree(con)
187
+ if con_tree != tree_form("d_1"):
188
+ new_mul.children.append(con_tree)
189
+
190
+ # Step 5: simplify trivial cases
191
+ if not new_mul.children:
192
+ node = tree_form("d_1")
193
+ elif len(new_mul.children) == 1:
194
+ node = new_mul.children[0]
124
195
  else:
125
- merged_children.append(child)
126
-
127
- eq = TreeNode(eq.name, merged_children)
128
- return TreeNode(eq.name, [recur_solve(child) for child in eq.children])
129
-
130
- return recur_solve(eq)
131
- def _convert_sub2neg(eq):
132
- if eq.name == "f_neg":
133
- return -_convert_sub2neg(eq.children[0])
134
- elif eq.name == "f_sub":
135
- return _convert_sub2neg(eq.children[0]) - _convert_sub2neg(eq.children[1])
136
- elif eq.name == "f_sqrt":
137
- return _convert_sub2neg(eq.children[0])**(tree_form("d_2")**-1)
138
- elif eq.name == "f_div":
139
- if eq.children[0] == 0:
140
- return tree_form("d_0")
141
- return _convert_sub2neg(eq.children[0])*_convert_sub2neg(eq.children[1])**-1
142
- return TreeNode(eq.name, [_convert_sub2neg(child) for child in eq.children])
143
- def solve(eq, specialfx=False):
144
- if specialfx:
145
- eq = _convert_sub2neg(eq)
146
-
147
- eq = flatten_tree(eq)
148
-
149
- return dowhile(eq, _solve)
150
- def solve2(eq):
151
- return solve(eq, True)
152
- def clear_div(eq, denom=False):
153
- lst = factor_generation(eq)
154
- if tree_form("d_0") in lst:
155
- return tree_form("d_0"), True
156
- lst3 = [item for item in lst if "v_" not in str_form(item) and compute(item) < 0]
157
-
158
- sign = True
159
- if len(lst3) % 2 == 1:
160
- sign = False
161
- if denom:
162
- return eq if sign else -eq, sign
163
- lst = [item for item in lst if not(item.name == "f_pow" and frac(item.children[1]) is not None and frac(item.children[1]) == -1)]
196
+ node = new_mul
164
197
 
165
- lst2 = [item for item in lst if "v_" in str_form(item)]
166
- if lst2 == []:
167
- return solve(product(lst)),sign
168
- return solve(product(lst2)),sign
198
+ # Return node to parent
199
+ if stack:
200
+ parent, idx, parent_children = stack.pop()
201
+ parent_children.append(node)
202
+ stack.append((parent, idx + 1, parent_children))
203
+ else:
204
+ return node # fully processed root
169
205
 
170
- def simplify(eq):
171
- error = False
172
- eq = flatten_tree(eq)
173
- if eq.name in ["f_and", "f_or", "f_not"]:
174
- return TreeNode(eq.name, [simplify(child) for child in eq.children])
175
-
176
- if eq.name in ["f_lt", "f_gt", "f_le", "f_ge", "f_eq"]:
177
- tmp, sign = clear_div(simplify(eq.children[0]-eq.children[1]), eq.name != "f_eq")
178
- name2 = eq.name
179
- if not sign:
180
- name2 = {"f_lt":"f_gt", "f_gt":"f_lt", "f_eq":"f_eq", "f_le":"f_ge", "f_ge":"f_le"}[name2]
206
+ else:
207
+ # Push current node back to continue with next child
208
+ stack.append((node, child_index, processed_children))
209
+ # Push next child to stack
210
+ child = node.children[child_index]
211
+ stack.append((child, 0, []))
212
+ '''
213
+ def addition_node(eq):
214
+ if not eq.name.startswith("f_"):
215
+ return eq
216
+ if eq.name == "f_add":
217
+ con = 0
218
+ eq2 = TreeNode("f_add", [])
219
+ for i in range(len(eq.children)-1,-1,-1):
220
+ n = frac(eq.children[i])
221
+ if n is not None:
222
+ con = con + n
223
+ else:
224
+ eq2.children.append(eq.children[i])
225
+ eq2.name = eq.name
226
+ eq = eq2
181
227
 
182
- return TreeNode(name2, [tmp, tree_form("d_0")])
228
+ lst = {}
229
+ for child in eq.children:
230
+ power = TreeNode("f_mul", [])
231
+ con2 = None
232
+ con3 = TreeNode("f_mul", [])
233
+ power2 = None
183
234
 
184
- eq = solve(eq, True)
185
- def helper(eq):
186
-
187
- if eq.name == "f_pow" and eq.children[0].name[:2] == "d_" and eq.children[1].name[:2] == "d_":
188
-
189
- a, b = int(eq.children[0].name[2:]), int(eq.children[1].name[2:])
190
- a = a**abs(b)
191
- if b == 0 and a == 0:
192
- error= True
193
- return eq
194
- if b == 0:
195
- b = 1
196
- b = int(b/abs(b))
197
- if b == 1:
198
- eq = tree_form("d_"+str(a))
235
+ if child.name == "f_mul":
236
+ for i in range(len(child.children)):
237
+ if "v_" not in str_form(child.children[i]):
238
+ if child.children[i] != tree_form("d_0"):
239
+ power.children.append(child.children[i])
240
+ else:
241
+ if child.children[i] != tree_form("d_1"):
242
+ con3.children.append(child.children[i])
243
+ if len(con3.children) == 0:
244
+ con2 = tree_form("d_1")
245
+ elif len(con3.children) == 1:
246
+ con2 = con3.children[0]
247
+ else:
248
+ con2 = con3
199
249
  else:
200
- eq = tree_form("d_"+str(a))**-1
201
- return TreeNode(eq.name, [helper(child) for child in eq.children])
202
- def helper2(eq):
203
-
204
- def even(eq):
205
- return eq.name[:2] == "d_" and int(eq.name[2:])%2==0
206
- def even2(eq):
207
- return any(even(item) for item in factor_generation(eq))
208
- if eq.name == "f_pow" and eq.children[0].name == "f_pow":
209
- if even2(eq.children[0].children[1]) or even2(eq.children[1]) and not even2(solve(eq.children[0].children[1] * eq.children[1])):
210
- return eq.children[0].children[0].fx("abs") ** solve(eq.children[0].children[1] * eq.children[1])
250
+ con2 = child
251
+
252
+ if power.children == []:
253
+ power2 = tree_form("d_1")
254
+ elif len(power.children) == 1:
255
+ power2 = power.children[0]
211
256
  else:
212
- return eq.children[0].children[0] ** solve(eq.children[0].children[1] * eq.children[1])
213
- return TreeNode(eq.name, [helper2(child) for child in eq.children])
214
- def helper3(eq):
215
-
216
- if eq.name == "f_mul":
217
- n = Fraction(1)
218
- for i in range(len(eq.children)-1,-1,-1):
219
- child= eq.children[i]
220
- if child.name == "f_pow" and child.children[0].name[:2] == "d_" and child.children[1] == -1:
221
- if int(child.children[0].name[2:]) == 0:
222
- error = True
223
- return eq
224
- n = n*Fraction(1,int(child.children[0].name[2:]))
225
- eq.children.pop(i)
226
- elif child.name[:2] == "d_":
227
- n = n*int(child.name[2:])
228
- eq.children.pop(i)
229
- if n.denominator == 1:
230
- eq.children.append(tree_form("d_"+str(n.numerator)))
257
+ power2 = power
258
+
259
+ if con2 in lst.keys():
260
+ lst[con2] = lst[con2] + power2
231
261
  else:
232
- eq.children.append(tree_form("d_"+str(n.numerator))*tree_form("d_"+str(n.denominator))**-1)
233
-
234
- if len(eq.children) == 1:
235
- eq = eq.children[0]
236
- return TreeNode(eq.name, [helper3(child) for child in eq.children])
237
- def helper4(eq):
238
- nonlocal error
239
- if eq == tree_form("d_-1")**tree_form("d_-1"):
240
- return tree_form("d_-1")
241
- def perfect_nth_root_value(x, n):
242
- """Return integer y if x is a perfect n-th power (y**n == x), else None."""
243
- if x < 0 and n % 2 == 0:
244
- return None # even root of negative number not real
245
-
246
- sign = -1 if x < 0 else 1
247
- x = abs(x)
262
+ lst[con2] = power2
263
+ eq3 = TreeNode("f_add", [])
248
264
 
249
- # approximate integer root
250
- y = round(x ** (1.0 / n))
251
-
252
- if y ** n == x:
253
- return sign * y
254
- return None
255
- def pp(eq, n):
256
- if n == 1:
257
- return eq
258
- return eq**tree_form("d_"+str(n))
259
- if eq.name == "f_pow" and eq.children[0].name[:2] == "d_" and frac(eq.children[1]) is not None:
260
- f = frac(eq.children[1])
261
- r = f.denominator
262
- f = frac(eq.children[1]).numerator
263
- if r > 1:
264
- n = int(eq.children[0].name[2:])
265
- if n < 0 and r==2:
266
- out = perfect_nth_root_value(-n, 2)
267
- if out is not None:
268
- return pp( tree_form("d_"+str(out))*tree_form("s_i") , f)
265
+ for kv in lst.keys():
266
+ tmp3 = lst[kv]
267
+ if tmp3 == tree_form("d_1"):
268
+ eq3.children.append(kv)
269
+ elif tmp3 == tree_form("d_0"):
270
+ continue
271
+ else:
272
+ eq3.children.append(kv * tmp3)
273
+
274
+ eq = eq3
275
+ eq4 = None
276
+ tmp3 = frac_to_tree(con)
277
+ if tmp3 != tree_form("d_0"):
278
+ eq.children.append(tmp3)
279
+ if eq.children == []:
280
+ return tree_form("d_0")
281
+ if len(eq.children) == 1:
282
+ eq4 = eq.children[0]
283
+ eq = eq4
284
+ return TreeNode(eq.name, [addition_node(child) for child in eq.children])
285
+ '''
286
+ def addition_node(equation):
287
+ """
288
+ Iterative version of addition_node.
289
+ Combines constants and like terms in addition nodes.
290
+ """
291
+ # Stack: (node, child_index, partially_processed_children)
292
+ if equation is None:
293
+ return None
294
+ stack = [(equation, 0, [])]
295
+
296
+ while stack:
297
+ node, child_index, processed_children = stack.pop()
298
+
299
+ # If all children are processed
300
+ if child_index >= len(node.children):
301
+ node.children = processed_children
302
+
303
+ # Only process addition nodes
304
+ if node.name == "f_add":
305
+ # Step 1: combine numeric constants
306
+ con = 0
307
+ new_children = []
308
+ for child in reversed(node.children):
309
+ val = frac(child)
310
+ if val is not None:
311
+ con += val
312
+ else:
313
+ new_children.append(child)
314
+
315
+ node.children = new_children
316
+
317
+ # Step 2: combine like terms iteratively
318
+ # We store (base, power) pairs in a list (avoid dict/hash)
319
+ base_terms = []
320
+ for child in node.children:
321
+ # Decompose child into base and multiplier
322
+ power_node = TreeNode("f_mul", [])
323
+ base_node = None
324
+ mul_node = TreeNode("f_mul", [])
325
+ multiplier_node = None
326
+
327
+ if child.name == "f_mul":
328
+ for c in child.children:
329
+ if frac(c) is not None: # constant part
330
+ if c != tree_form("d_0"):
331
+ power_node.children.append(c)
332
+ else: # variable part
333
+ if c != tree_form("d_1"):
334
+ mul_node.children.append(c)
335
+ if len(mul_node.children) == 0:
336
+ base_node = tree_form("d_1")
337
+ elif len(mul_node.children) == 1:
338
+ base_node = mul_node.children[0]
339
+ else:
340
+ base_node = mul_node
341
+ else:
342
+ base_node = child
343
+
344
+ if not power_node.children:
345
+ multiplier_node = tree_form("d_1")
346
+ elif len(power_node.children) == 1:
347
+ multiplier_node = power_node.children[0]
348
+ else:
349
+ multiplier_node = power_node
350
+
351
+ # Combine like terms structurally
352
+ found = False
353
+ for i, (b, m) in enumerate(base_terms):
354
+ if b == base_node:
355
+ base_terms[i] = (b, m + multiplier_node)
356
+ found = True
357
+ break
358
+ if not found:
359
+ base_terms.append((base_node, multiplier_node))
360
+
361
+ # Step 3: rebuild addition node
362
+ new_add = TreeNode("f_add", [])
363
+ for base, multiplier in base_terms:
364
+ if multiplier == tree_form("d_1"):
365
+ new_add.children.append(base)
366
+ elif multiplier == tree_form("d_0"):
367
+ continue
269
368
  else:
270
- return pp( (tree_form("d_"+str(-n))**(tree_form("d_2")**-1))*tree_form("s_i"), f)
369
+ new_add.children.append(base * multiplier)
370
+
371
+ # Step 4: add numeric constant
372
+ con_tree = frac_to_tree(con)
373
+ if con_tree != tree_form("d_0"):
374
+ new_add.children.append(con_tree)
375
+
376
+ # Step 5: simplify trivial cases
377
+ if not new_add.children:
378
+ node = tree_form("d_0")
379
+ elif len(new_add.children) == 1:
380
+ node = new_add.children[0]
271
381
  else:
272
- out = perfect_nth_root_value(n, r)
273
- if out is not None:
274
- return pp( tree_form("d_"+str(out)), f)
275
- if not nolog:
276
- if eq.name == "f_mul" and len(eq.children)== 2:
277
- for i in range(2):
278
- if eq.children[i].name[:2] == "d_" and eq.children[1-i].name == "f_log":
279
- return (eq.children[1-i].children[0]**eq.children[i]).fx("log")
280
- if eq.name == "f_pow" and eq.children[0] == tree_form("s_e") and eq.children[1].name == "f_log":
281
- return eq.children[1].children[0]
282
- if eq.name == "f_pow" and eq.children[0] == tree_form("d_1"):
283
- eq = tree_form("d_1")
284
- if eq.name == "f_pow" and eq.children[0] == tree_form("d_0"):
285
- if frac(eq.children[1]) is not None and frac(eq.children[1]) <= 0:
286
- error = True
382
+ node = new_add
383
+
384
+ # Return node to parent
385
+ if stack:
386
+ parent, idx, parent_children = stack.pop()
387
+ parent_children.append(node)
388
+ stack.append((parent, idx + 1, parent_children))
287
389
  else:
288
- eq = tree_form("d_0")
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"):
290
- eq = eq.children[0].children[0]
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"):
292
- eq = eq.children[0].children[0]
293
- if (eq.name == "f_cos" and eq.children[0].name == "f_arcsin") or (eq.name == "f_sin" and eq.children[0].name == "f_arccos"):
294
- eq2 = eq.children[0].children[0]
295
- eq2 = (tree_form("d_1") - eq2*eq2)**(tree_form("d_1")/tree_form("d_2"))
296
- eq = eq2
297
- if (eq.name == "f_arcsin" and eq.children[0].name == "f_sin") or (eq.name == "f_arccos" and eq.children[0].name == "f_cos") or (eq.name == "f_arctan" and eq.children[0].name == "f_tan"):
298
- eq = eq.children[0].children[0]
299
- if eq.name == "f_abs" and eq.children[0].name[:2] == "d_":
300
- eq = tree_form("d_"+str(abs(int(eq.children[0].name[2:]))))
301
-
302
- if eq.name == "f_pow" and eq.children[0].name[:2] == "d_" and frac(eq.children[1]) is not None:
303
- f = frac(eq.children[1])
304
- if f.denominator != 1:
305
- return helper(eq.children[0]**tree_form("d_"+str(f.numerator)))**(tree_form("d_"+str(f.denominator))**-1)
390
+ # Root node fully processed
391
+ return node
392
+
393
+ else:
394
+ # Push current node back for next child
395
+ stack.append((node, child_index, processed_children))
396
+ # Push next child to stack
397
+ child = node.children[child_index]
398
+ stack.append((child, 0, []))
399
+
400
+ def other_node(eq):
401
+ if eq is None:
402
+ return None
403
+ if eq.name == "f_log":
404
+ if len(eq.children) == 1:
405
+ if eq.children[0].name == "d_1":
406
+ return tree_form("d_0")
407
+ if eq.children[0].name == "s_e":
408
+ return tree_form("d_1")
409
+ if eq.name == "f_mul":
410
+ if tree_form("d_1") in eq.children:
411
+ return product([remove_extra(child) for child in eq.children if child != tree_form("d_1")])
412
+ if eq.name == "f_pow" and len(eq.children) == 2:
413
+ a, b = frac(eq.children[0]), frac(eq.children[1])
414
+ if a is not None and b is not None and a == 0 and b < 0:
415
+ return None
416
+ if eq.children[1].name == "d_0":
417
+ return tree_form("d_1")
418
+ if eq.children[1].name == "d_1":
419
+ return eq.children[0]
420
+ if eq.children[0].name == "d_1":
421
+ return tree_form("d_1")
422
+ if eq.children[0].name == "f_abs" and eq.children[1].name.startswith("d_")\
423
+ and int(eq.children[1].name[2:]) % 2 == 0:
424
+ return eq.children[0].children[0] ** eq.children[1]
306
425
 
307
- return TreeNode(eq.name, [helper4(child) for child in eq.children])
308
-
309
- def helper7(eq):
426
+ if eq.children[0].name == "f_mul":
427
+ n = frac(eq.children[1])
428
+ if n is not None and n < 0 and n.numerator % 2 == 1 and n.denominator == 1:
429
+ n2 = frac_to_tree(-n)
430
+ if n2 == tree_form("d_1"):
431
+ return product([child**-1 for child in eq.children[0].children])
432
+ return product([child**-1 for child in eq.children[0].children]) ** n2
433
+ if frac(eq.children[1]) == Fraction(1,2):
434
+ d = frac(eq.children[0])
435
+ if d is not None and d < 0:
436
+ return tree_form("s_i")*(frac_to_tree(-d)**eq.children[1])
437
+ if eq.children[0].name == "f_pow":
438
+ b = eq.children[0].children[1]
439
+ c = eq.children[1]
440
+ out = frac(b*c)
441
+ if out is not None:
442
+ out2 = frac(b)
443
+ if out.numerator % 2 == 0 or (out2 is not None and out2.numerator % 2 != 0):
444
+ return eq.children[0].children[0] ** (b*c)
445
+ else:
446
+ return eq.children[0].children[0].fx("abs") ** (b*c)
447
+ else:
448
+ tmp = compute(eq.children[0].children[0])
449
+ if (tmp is not None and tmp > 0) or eq.children[0].children[0].name == "f_abs":
450
+ return eq.children[0].children[0] ** (b*c)
451
+ c = frac(eq)
452
+ if c is not None:
453
+ c = frac_to_tree(c)
454
+ if c != eq:
455
+ return c
456
+ if eq.name == "f_pow" and eq.children[0] == tree_form("s_i") and eq.children[1].name.startswith("d_"):
457
+ n = int(eq.children[1].name[2:])
458
+ if n % 4 == 0:
459
+ return tree_form("d_1")
460
+ if n % 4 == 1:
461
+ return tree_form("s_i")
462
+ if n % 4 == 2:
463
+ return tree_form("d_-1")
464
+ if n % 4 == 3:
465
+ return -tree_form("s_i")
466
+ if eq.name == "f_pow" and eq.children[0].name == "s_e":
467
+ if eq.children[1].name == "f_log":
468
+ return eq.children[1].children[0]
469
+ if eq.children[1].name == "f_mul":
470
+ lst = factor_generation(eq.children[1])
471
+ log = None
472
+ for i in range(len(lst)-1,-1,-1):
473
+ if lst[i].name == "f_log":
474
+ log = lst[i]
475
+ lst.pop(i)
476
+ break
477
+ if log is not None:
478
+ return log.children[0] ** product(lst)
479
+ for index, child in enumerate(eq.children):
480
+ out = other_node(child)
481
+ if out is None:
482
+ return None
483
+ eq.children[index] = out
484
+ return TreeNode(eq.name, eq.children)
485
+ def cancel(eq):
486
+ n, d = num_dem(eq)
487
+ d = simplify(d)
488
+ if d != tree_form("d_1"):
489
+ n = simplify(n)
490
+ a = Counter(factor_generation(n))
491
+ b = Counter(factor_generation(d))
492
+ c = a & b
493
+ a = simplify(product(list(a-c)))
494
+ b = simplify(product(list(b-c)))
495
+ if b == tree_form("d_1"):
496
+ return a
497
+ if a == tree_form("d_1"):
498
+ return b ** -1
499
+ return a/b
500
+ return TreeNode(eq.name, [cancel(child) for child in eq.children])
501
+ def solve3(eq):
502
+ a = lambda x: multiply_node(x)
503
+ b = lambda x: addition_node(x)
504
+ c = lambda x: other_node(x)
505
+ return dowhile(eq, lambda x: flatten_tree(c(b(a(x)))))
506
+
507
+ def simplify(eq, basic=True):
508
+ if eq is None:
509
+ return None
510
+ orig = TreeNode.matmul
511
+ if TreeNode.matmul == True:
512
+ TreeNode.matmul = False
513
+ if TreeNode.matmul == False:
514
+ eq = use(tree_form(str_form(eq).replace("f_w","f_")))
310
515
 
311
- if eq.name == "f_pow" and eq.children[0].name == "f_mul":
312
- return product([child**eq.children[1] for child in eq.children[0].children])
313
- return TreeNode(eq.name, [helper7(child) for child in eq.children])
314
-
315
- def helper6(eq):
316
- if eq.name == "f_mul":
317
- lst = factor_generation(eq)
318
- rm = []
319
- for i in range(len(lst)):
320
- if i in rm:
321
- continue
322
- for j in range(len(lst)):
323
- if i ==j or j in rm:
324
- continue
325
- if solve(helper2(lst[i]**-1)) == lst[j]:
326
- rm += [i,j]
327
- break
328
- if rm != []:
329
- for item in sorted(rm)[::-1]:
330
- lst.pop(item)
331
- return product(lst)
332
- return TreeNode(eq.name, [helper6(child) for child in eq.children])
333
- def helper5(eq):
516
+ if eq.name == "f_and" or eq.name == "f_not" or eq.name == "f_or":
517
+ new_children = []
518
+ for child in eq.children:
519
+ new_children.append(simplify(child))
520
+ TreeNode.matmul = orig
521
+ return TreeNode(eq.name, new_children)
522
+ if eq.name[2:] in "gt ge lt le eq".split(" "):
523
+ denom = eq.name != "f_eq"
524
+ tmp2 = simplify(eq.children[0] - eq.children[1])
525
+ tmp, denom = clear_div(tmp2, denom)
526
+ tmp = simplify(tmp)
334
527
 
335
- if eq.name == "f_pow" and eq.children[1].name[:2] == "d_" and abs(int(eq.children[1].name[2:]))%2==0 and eq.children[0].name == "f_abs":
336
- return eq.children[0].children[0]**eq.children[1]
337
- return TreeNode(eq.name, [helper5(child) for child in eq.children])
338
- def helper8(eq):
339
- if eq.name == "f_pow" and eq.children[0].name == "f_abs" and frac(eq.children[1]) is not None and frac(eq.children[1]).numerator % 2==0:
340
- return eq.children[0].children[0] ** eq.children[1]
341
- if eq.name == "f_abs" and eq.children[0].name == "f_abs":
342
- return eq.children[0]
343
- if eq.name == "f_cos" and eq.children[0].name == "f_abs":
344
- return eq.children[0].children[0].fx("cos")
345
- return TreeNode(eq.name, [helper8(child) for child in eq.children])
346
- def fx1(eq):
347
- for item in [helper, helper3, helper4, helper6,solve,helper2,helper5]:
348
- eq = dowhile(eq, item)
349
- return eq
350
- def fx2(eq):
351
- for item in [helper, helper3, helper4, helper6,helper7,helper2,helper5]:
352
- eq = dowhile(eq, item)
353
- return eq
354
- def fx3(eq):
355
- for item in [fx1, fx2]:
356
- eq = dowhile(eq, item)
357
- return eq
358
- eq = dowhile(eq, fx3)
359
- eq = dowhile(eq, helper8)
360
- if error:
361
- return None
362
- return solve(eq)
528
+ value2 = eq.name[2:]
529
+ if denom is False:
530
+ value2 = {"ge":"le", "le":"ge", "gt":"lt", "lt":"gt", "eq":"eq"}[value2]
531
+ value2 = "f_"+value2
532
+ out = TreeNode(value2, [tmp, tree_form("d_0")])
533
+ TreeNode.matmul = orig
534
+ return out
535
+ eq = flatten_tree(eq)
536
+ if basic:
537
+ eq = convert_to_basic(eq)
538
+ eq = solve3(eq)
539
+ TreeNode.matmul = orig
540
+ return eq