mathai 0.4.8__py3-none-any.whl → 0.7.2__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,398 +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()
118
125
 
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)
126
+ # If all children processed
127
+ if child_index >= len(node.children):
128
+ node.children = processed_children
129
+
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
169
-
170
- def simplify(eq):
171
- if "v_" not in str_form(eq):
172
- n = frac(eq)
173
- if n is not None:
174
- if n.numerator == 0:
175
- return tree_form("d_0")
176
- if n.denominator != 1:
177
- return tree_form("d_"+str(n.numerator))/tree_form("d_"+str(n.denominator))
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))
178
203
  else:
179
- return tree_form("d_"+str(n.numerator))
180
- error = False
181
- eq = flatten_tree(eq)
182
- if eq.name in ["f_and", "f_or", "f_not"]:
183
- return TreeNode(eq.name, [simplify(child) for child in eq.children])
184
-
185
- if eq.name in ["f_lt", "f_gt", "f_le", "f_ge", "f_eq"]:
186
- tmp, sign = clear_div(simplify(eq.children[0]-eq.children[1]), eq.name != "f_eq")
187
- name2 = eq.name
188
- if not sign:
189
- name2 = {"f_lt":"f_gt", "f_gt":"f_lt", "f_eq":"f_eq", "f_le":"f_ge", "f_ge":"f_le"}[name2]
204
+ return node # fully processed root
190
205
 
191
- return TreeNode(name2, [tmp, tree_form("d_0")])
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
192
227
 
193
- eq = solve(eq, True)
194
- def helper(eq):
195
-
196
- if eq.name == "f_pow" and eq.children[0].name[:2] == "d_" and eq.children[1].name[:2] == "d_":
197
-
198
- a, b = int(eq.children[0].name[2:]), int(eq.children[1].name[2:])
199
- a = a**abs(b)
200
- if b == 0 and a == 0:
201
- error= True
202
- return eq
203
- if b == 0:
204
- b = 1
205
- b = int(b/abs(b))
206
- if b == 1:
207
- eq = tree_form("d_"+str(a))
228
+ lst = {}
229
+ for child in eq.children:
230
+ power = TreeNode("f_mul", [])
231
+ con2 = None
232
+ con3 = TreeNode("f_mul", [])
233
+ power2 = None
234
+
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
208
249
  else:
209
- eq = tree_form("d_"+str(a))**-1
210
- return TreeNode(eq.name, [helper(child) for child in eq.children])
211
- def helper2(eq):
212
-
213
- def even(eq):
214
- return eq.name[:2] == "d_" and int(eq.name[2:])%2==0
215
- def even2(eq):
216
- return any(even(item) for item in factor_generation(eq))
217
- if eq.name == "f_pow" and eq.children[0].name == "f_pow":
218
- if even2(eq.children[0].children[1]) or even2(eq.children[1]) and not even2(solve(eq.children[0].children[1] * eq.children[1])):
219
- 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]
220
256
  else:
221
- return eq.children[0].children[0] ** solve(eq.children[0].children[1] * eq.children[1])
222
- return TreeNode(eq.name, [helper2(child) for child in eq.children])
223
- def helper3(eq):
224
-
225
- if eq.name == "f_mul":
226
- n = Fraction(1)
227
- for i in range(len(eq.children)-1,-1,-1):
228
- child= eq.children[i]
229
- if child.name == "f_pow" and child.children[0].name[:2] == "d_" and child.children[1] == -1:
230
- if int(child.children[0].name[2:]) == 0:
231
- error = True
232
- return eq
233
- n = n*Fraction(1,int(child.children[0].name[2:]))
234
- eq.children.pop(i)
235
- elif child.name[:2] == "d_":
236
- n = n*int(child.name[2:])
237
- eq.children.pop(i)
238
- if n.denominator == 1:
239
- 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
240
261
  else:
241
- eq.children.append(tree_form("d_"+str(n.numerator))*tree_form("d_"+str(n.denominator))**-1)
242
-
243
- if len(eq.children) == 1:
244
- eq = eq.children[0]
245
- return TreeNode(eq.name, [helper3(child) for child in eq.children])
246
- def helper4(eq):
247
- nonlocal error
248
- if eq == tree_form("d_-1")**tree_form("d_-1"):
249
- return tree_form("d_-1")
250
- def perfect_nth_root_value(x, n):
251
- """Return integer y if x is a perfect n-th power (y**n == x), else None."""
252
- if x < 0 and n % 2 == 0:
253
- return None # even root of negative number not real
254
-
255
- sign = -1 if x < 0 else 1
256
- x = abs(x)
262
+ lst[con2] = power2
263
+ eq3 = TreeNode("f_add", [])
257
264
 
258
- # approximate integer root
259
- y = round(x ** (1.0 / n))
260
-
261
- if y ** n == x:
262
- return sign * y
263
- return None
264
- def pp(eq, n):
265
- if n == 1:
266
- return eq
267
- return eq**tree_form("d_"+str(n))
268
- if eq.name == "f_pow" and eq.children[0].name[:2] == "d_" and frac(eq.children[1]) is not None:
269
- f = frac(eq.children[1])
270
- r = f.denominator
271
- f = frac(eq.children[1]).numerator
272
- if r > 1:
273
- n = int(eq.children[0].name[2:])
274
- if n < 0 and r==2:
275
- out = perfect_nth_root_value(-n, 2)
276
- if out is not None:
277
- 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
278
368
  else:
279
- 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]
280
381
  else:
281
- out = perfect_nth_root_value(n, r)
282
- if out is not None:
283
- return pp( tree_form("d_"+str(out)), f)
284
- if not nolog:
285
- if eq.name == "f_mul" and len(eq.children)== 2:
286
- for i in range(2):
287
- if eq.children[i].name[:2] == "d_" and eq.children[1-i].name == "f_log":
288
- return (eq.children[1-i].children[0]**eq.children[i]).fx("log")
289
- if eq.name == "f_pow" and eq.children[0] == tree_form("s_e") and eq.children[1].name == "f_log":
290
- return eq.children[1].children[0]
291
-
292
- if eq.name == "f_pow" and eq.children[0] == tree_form("d_1"):
293
- eq = tree_form("d_1")
294
- if eq.name == "f_pow" and eq.children[0] == tree_form("d_0"):
295
- if frac(eq.children[1]) is not None and frac(eq.children[1]) <= 0:
296
- 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))
297
389
  else:
298
- eq = tree_form("d_0")
299
- 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:
300
- n = frac(eq.children[1]).numerator
301
- eq = {0:tree_form("d_1"), 1:tree_form("s_i"), 2:tree_form("d_-1"), 3:-tree_form("s_i")}[n%4]
302
- if eq.name == "f_mul":
303
- dic = {}
304
- for child in eq.children:
305
- head = child
306
- tail = None
307
- if child.name == "f_pow":
308
- head = child.children[0]
309
- tail = child.children[1]
310
- if tail is None:
311
- tail = tree_form("d_1")
312
- if head not in dic.keys():
313
- dic[head] = tail
314
- else:
315
- dic[head] += tail
316
- if len(eq.children) > len(dic.keys()):
317
- eq = product([key if dic[key] == 1 else key**dic[key] for key in dic.keys()])
318
- if eq.name == "f_abs" and eq.children[0].name == "f_pow" and frac(eq.children[0].children[1]) == Fraction(1,2):
319
- eq = eq.children[0]
320
- 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"):
321
- eq = eq.children[0].children[0]
322
- 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"):
323
- eq = eq.children[0].children[0]
324
- if (eq.name == "f_cos" and eq.children[0].name == "f_arcsin") or (eq.name == "f_sin" and eq.children[0].name == "f_arccos"):
325
- eq2 = eq.children[0].children[0]
326
- eq2 = (tree_form("d_1") - eq2*eq2)**(tree_form("d_1")/tree_form("d_2"))
327
- eq = eq2
328
- 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"):
329
- eq = eq.children[0].children[0]
330
- if eq.name == "f_abs" and eq.children[0].name[:2] == "d_":
331
- eq = tree_form("d_"+str(abs(int(eq.children[0].name[2:]))))
332
- if eq.name == "f_abs" and "v_" not in str_form(eq.children[0]):
333
- if compute(eq.children[0]) > 0.00001:
334
- eq = eq.children[0]
335
- elif compute(eq.children[0]) < 0.00001:
336
- eq = -eq.children[0]
337
- if eq.name == "f_pow" and eq.children[0].name[:2] == "d_" and frac(eq.children[1]) is not None:
338
- f = frac(eq.children[1])
339
- if f.denominator != 1:
340
- 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]
341
425
 
342
- return TreeNode(eq.name, [helper4(child) for child in eq.children])
343
-
344
- 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_")))
345
515
 
346
- if eq.name == "f_pow" and eq.children[0].name == "f_mul":
347
- return product([child**eq.children[1] for child in eq.children[0].children])
348
- return TreeNode(eq.name, [helper7(child) for child in eq.children])
349
-
350
- def helper6(eq):
351
- if eq.name == "f_mul":
352
- lst = factor_generation(eq)
353
- rm = []
354
- for i in range(len(lst)):
355
- if i in rm:
356
- continue
357
- for j in range(len(lst)):
358
- if i ==j or j in rm:
359
- continue
360
- if solve(helper2(lst[i]**-1)) == lst[j]:
361
- rm += [i,j]
362
- break
363
- if rm != []:
364
- for item in sorted(rm)[::-1]:
365
- lst.pop(item)
366
- return product(lst)
367
- return TreeNode(eq.name, [helper6(child) for child in eq.children])
368
- 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)
369
527
 
370
- 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":
371
- return eq.children[0].children[0]**eq.children[1]
372
- return TreeNode(eq.name, [helper5(child) for child in eq.children])
373
- def helper8(eq):
374
- 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:
375
- return eq.children[0].children[0] ** eq.children[1]
376
- if eq.name == "f_abs" and eq.children[0].name == "f_abs":
377
- return eq.children[0]
378
- if eq.name == "f_cos" and eq.children[0].name == "f_abs":
379
- return eq.children[0].children[0].fx("cos")
380
- return TreeNode(eq.name, [helper8(child) for child in eq.children])
381
- def fx1(eq):
382
- for item in [helper, helper3, helper4, helper6,solve,helper2,helper5]:
383
- eq = dowhile(eq, item)
384
- return eq
385
- def fx2(eq):
386
- for item in [helper, helper3, helper4, helper6,helper7,helper2,helper5]:
387
- eq = dowhile(eq, item)
388
- return eq
389
- def fx3(eq):
390
- for item in [fx1, fx2]:
391
- eq = dowhile(eq, item)
392
- return eq
393
- eq = dowhile(eq, fx3)
394
- eq = dowhile(eq, helper8)
395
- if error:
396
- return None
397
- return solve(eq)
398
-
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