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