mathai 0.6.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/factor.py ADDED
@@ -0,0 +1,304 @@
1
+ import itertools
2
+ from .trig import trig0
3
+ from .parser import parse
4
+ from .structure import transform_formula
5
+ from .base import *
6
+ from .simplify import simplify
7
+ from .expand import expand
8
+ import math
9
+ from .tool import poly
10
+ from .fraction import fraction
11
+ from .printeq import printeq
12
+ from collections import Counter
13
+ def multiset_intersection(*lists):
14
+ counters = list(map(Counter, lists))
15
+ common = counters[0]
16
+ for c in counters[1:]:
17
+ common = common & c
18
+ return list(common.elements())
19
+ def subtract_sublist(full_list, sublist):
20
+ c_full = Counter(full_list)
21
+ c_sub = Counter(sublist)
22
+ result = c_full - c_sub
23
+ tmp = list(result.elements())
24
+ if tmp == []:
25
+ return [tree_form("d_1")]
26
+ return tmp
27
+ def term_common2(eq):
28
+ if eq.name != "f_add":
29
+ return eq
30
+ s = []
31
+ arr = [factor_generation(child) for child in eq.children]
32
+ s = multiset_intersection(*arr)
33
+ return product(s)*summation([product(subtract_sublist(factor_generation(child), s)) for child in eq.children])
34
+ def term_common(eq):
35
+ if eq.name == "f_add":
36
+ return simplify(term_common2(eq))
37
+ return simplify(product([term_common2(item) for item in factor_generation(eq)]))
38
+ def take_common(eq):
39
+ if eq.name == "f_add":
40
+ eq = term_common(eq)
41
+ if eq.name == "f_add":
42
+ for i in range(len(eq.children)-1,1,-1):
43
+ for item in itertools.combinations(range(len(eq.children)), i):
44
+ eq2 = summation([item2 for index, item2 in enumerate(eq.children) if index in item])
45
+ eq2 = term_common(eq2)
46
+ if eq2.name == "f_mul":
47
+ return take_common(simplify(summation([item2 for index, item2 in enumerate(eq.children) if index not in item]) + eq2))
48
+ break
49
+ return eq
50
+ return term_common(eq)
51
+ def take_common2(eq):
52
+ eq = take_common(eq)
53
+ return TreeNode(eq.name, [take_common2(child) for child in eq.children])
54
+
55
+ def _factorconst(eq):
56
+ def hcf_list(numbers):
57
+ if not numbers:
58
+ return None # empty list
59
+ n = 1
60
+ if math.prod(numbers) < 0:
61
+ n = -1
62
+ hcf = numbers[0]
63
+ for num in numbers[1:]:
64
+ hcf = math.gcd(hcf, abs(num))
65
+ return hcf*n
66
+ def extractnum(eq):
67
+ lst = factor_generation(eq)
68
+ for item in lst:
69
+ if item.name[:2] == "d_":
70
+ return int(item.name[2:])
71
+ return 1
72
+ n = 1
73
+ if eq.name == "f_add":
74
+ n = hcf_list([extractnum(child) for child in eq.children])
75
+ eq = TreeNode(eq.name, [child/tree_form("d_"+str(n)) for child in eq.children])
76
+ if n != 1:
77
+ return tree_form("d_"+str(n))*eq
78
+ return TreeNode(eq.name, [factorconst(child) for child in eq.children])
79
+
80
+ def _merge_sqrt(eq):
81
+ lst= []
82
+ eq2 = []
83
+ for child in factor_generation(eq):
84
+ if frac(child) is not None and frac(child).denominator==1:
85
+ if frac(child)>0:
86
+ eq2.append(child**2)
87
+ elif frac(child)!=-1:
88
+ eq2.append((-child)**2)
89
+ lst.append(tree_form("d_-1"))
90
+ else:
91
+ lst.append(tree_form("d_-1"))
92
+ elif child.name == "f_pow" and frac(child.children[1]) == Fraction(1,2):
93
+ eq2.append(child.children[0])
94
+ else:
95
+ lst.append(child)
96
+
97
+ if len(eq2)>1:
98
+ if lst == []:
99
+ lst= [tree_form("d_1")]
100
+ return simplify(product(eq2)**(tree_form("d_2")**-1)*product(lst))
101
+ return TreeNode(eq.name, [_merge_sqrt(child) for child in eq.children])
102
+ def sqrt_to_a_sqrt_b(n):
103
+ if n == 0:
104
+ return 0, 0
105
+ sign = 1
106
+ if n < 0:
107
+ sign = -1
108
+ m = -n
109
+ else:
110
+ m = n
111
+
112
+ a = 1
113
+ b = 1
114
+ p = 2
115
+ while p * p <= m:
116
+ exp = 0
117
+ while m % p == 0:
118
+ m //= p
119
+ exp += 1
120
+ if exp:
121
+ a *= p ** (exp // 2)
122
+ if exp % 2 == 1:
123
+ b *= p
124
+ p += 1 if p == 2 else 2
125
+
126
+ if m > 1:
127
+ b *= m
128
+
129
+ return sign * a, b
130
+ def merge_sqrt(eq):
131
+ def helper(eq):
132
+ if eq.name == "f_pow" and frac(eq.children[1]) == Fraction(1,2):
133
+ if eq.children[0].name[:2] == "d_":
134
+ n = int(eq.children[0].name[2:])
135
+ a, b =sqrt_to_a_sqrt_b(n)
136
+ return tree_form("d_"+str(b))**(tree_form("d_2")**-1)*tree_form("d_"+str(a))
137
+ return TreeNode(eq.name, [helper(child) for child in eq.children])
138
+ return helper(_merge_sqrt(eq))
139
+ def rationalize_sqrt(eq):
140
+ if eq.name== "f_pow" and frac(eq.children[1]) == Fraction(-1,2):
141
+ eq = eq.children[0]**(tree_form("d_2")**-1)/eq.children[0]
142
+ def term(eq):
143
+ if eq.name == "f_add":
144
+ output = []
145
+ for child in eq.children:
146
+ if any(child2.name == "f_pow" and frac(child2.children[1]) == Fraction(1,2) for child2 in factor_generation(child)):
147
+ output.append(simplify(-child))
148
+ else:
149
+ output.append(child)
150
+ return summation(output)
151
+ return None
152
+ n, d=num_dem(eq)
153
+ n,d=simplify(n), simplify(d)
154
+
155
+ if d != 1:
156
+ t = term(d)
157
+ if t is not None and t!=1:
158
+
159
+ n,d=simplify(expand(simplify(n*t))),simplify(expand(simplify(d*t)))
160
+ tmp= simplify(n/d)
161
+
162
+ tmp = _merge_sqrt(tmp)
163
+
164
+ return tmp
165
+ return TreeNode(eq.name, [rationalize_sqrt(child) for child in eq.children])
166
+ def factorconst(eq):
167
+ return simplify(_factorconst(eq))
168
+
169
+ def factor_quar_formula_init():
170
+ var = ""
171
+ formula_list = [(f"(A^4+B*A^2+C)", f"(A^2 + sqrt(2*sqrt(C) - B)*A + sqrt(C))*(A^2 - sqrt(2*sqrt(C) - B)*A + sqrt(C))")]
172
+ formula_list = [[simplify(parse(y)) for y in x] for x in formula_list]
173
+ expr = [[parse("A")], [parse("B"), parse("0"), parse("1")], [parse("C"), parse("0")]]
174
+ return [formula_list, var, expr]
175
+
176
+ formula_gen9 = factor_quar_formula_init()
177
+ def factor_helper(equation, complexnum, power=2):
178
+ global formula_gen9
179
+ if equation.name in ["f_or", "f_and", "f_not", "f_eq", "f_gt", "f_lt", "f_ge", "f_le"]:
180
+ return TreeNode(equation.name, [factor_helper(child, complexnum, power) for child in equation.children])
181
+ maxnum=1
182
+ alloclst = []
183
+ for i in range(0,26):
184
+ if "v_"+str(i) not in vlist(equation):
185
+ alloclst.append("v_"+str(i))
186
+ r = alloclst.pop(0)
187
+ fx = None
188
+ curr = None
189
+ def high(eq):
190
+ nonlocal maxnum
191
+ if eq.name == "f_pow" and eq.children[1].name[:2] == "d_":
192
+ n = int(eq.children[1].name[2:])
193
+ if abs(n)>power and abs(n) % power == 0:
194
+ if abs(n)>abs(maxnum):
195
+ maxnum = n
196
+ for child in eq.children:
197
+ high(child)
198
+ def helper(eq):
199
+ nonlocal maxnum, fx, r
200
+ if eq.name == "f_pow" and eq.children[1].name[:2] == "d_" and eq.children[0] == curr:
201
+ n = int(eq.children[1].name[2:])
202
+ if maxnum !=1 and n % maxnum == 0:
203
+ fx = lambda x: replace(x, tree_form(r), curr**tree_form("d_"+str(maxnum)))
204
+ out= tree_form(r)**tree_form("d_"+str(int(n/maxnum)))
205
+ return out
206
+ return TreeNode(eq.name, [helper(child) for child in eq.children])
207
+ out = None
208
+
209
+ for i in range(2,4):
210
+ if power == i:
211
+ for curr in vlist(equation):
212
+ curr = tree_form(curr)
213
+ fx = None
214
+ maxnum = 1
215
+ high(equation.copy_tree())
216
+
217
+ if maxnum != 1:
218
+ maxnum= maxnum/power
219
+ maxnum = round(maxnum)
220
+ eq2 = helper(equation.copy_tree())
221
+ if not contain(eq2, tree_form(r)) or (contain(eq2, tree_form(r)) and not contain(eq2,curr)):
222
+ if not contain(eq2, tree_form(r)):
223
+ r = curr.name
224
+ fx = lambda x: x
225
+
226
+ lst = poly(eq2.copy_tree(), r)
227
+ if lst is not None and len(lst)==i+1:
228
+
229
+ success = True
230
+ if i == 2:
231
+ a, b, c = lst
232
+ x1 = (-b+(b**2 - 4*a*c)**(tree_form("d_2")**-1))/(2*a)
233
+ x2 = (-b-(b**2 - 4*a*c)**(tree_form("d_2")**-1))/(2*a)
234
+ x1 = expand(simplify(x1))
235
+ x2 = expand(simplify(x2))
236
+ eq2 = a*(tree_form(r)-x1)*(tree_form(r)-x2)
237
+ if not complexnum and (contain(x1, tree_form("s_i")) or contain(x2, tree_form("s_i"))):
238
+ success = False
239
+ else:
240
+ a, b, c, d = lst
241
+ B, C, D = b/a, c/a, d/a
242
+ p = C-(B**2)/3
243
+ q = 2*B**3/27-B*C/3+D
244
+ t = q**2/4+ p**3/27
245
+
246
+ if compute(t) > 0:
247
+ u = (-q/2+t**(tree_form("d_2")**-1))**(tree_form("d_3")**-1)
248
+ v = (-q/2-t**(tree_form("d_2")**-1))**(tree_form("d_3")**-1)
249
+ y1 = u+v
250
+ three = 3**(tree_form("d_2")**-1)
251
+ y2 = -(u+v)/2+tree_form("s_i")*three*(u-v)/2
252
+ y3 = -(u+v)/2-tree_form("s_i")*three*(u-v)/2
253
+
254
+ else:
255
+ ar = 2*(-p/3)**(tree_form("d_2")**-1)
256
+ phi = ((3*q/(2*p))*(-3/p)**(tree_form("d_2")**-1)).fx("arccos")
257
+ y1 = ar*(phi/3).fx("cos")
258
+ y2 = ar*((phi+2*tree_form("s_pi"))/3).fx("cos")
259
+ y3 = ar*((phi+4*tree_form("s_pi"))/3).fx("cos")
260
+
261
+ x1,x2,x3 = y1-B/3 , y2-B/3, y3-B/3
262
+ x1 = simplify(trig0(simplify(x1)))
263
+ x2 = simplify(trig0(simplify(x2)))
264
+ x3 = simplify(trig0(simplify(x3)))
265
+
266
+ out2 = None
267
+ if not complexnum:
268
+ for item in itertools.combinations([x1,x2,x3],2):
269
+ if all(contain(item2,tree_form("s_i")) for item2 in list(item)):
270
+ out2 = (tree_form(r)-item[0])*(tree_form(r)-item[1])
271
+ break
272
+ if out2 is not None:
273
+ out2 = simplify(fraction(expand(simplify(out2))))
274
+ out3 = None
275
+ for item in [x1, x2, x3]:
276
+ if not contain(item,tree_form("s_i")):
277
+ out3 = item
278
+ break
279
+ eq2 = a*(tree_form(r)-out3)*out2
280
+
281
+ else:
282
+ eq2 = a*(tree_form(r)-x1)*(tree_form(r)-x2)*(tree_form(r)-x3)
283
+ if success:
284
+ equation = fx(eq2)
285
+ break
286
+
287
+ if False and power == 4:
288
+
289
+ out = transform_formula(helper(equation), "v_0", formula_gen9[0], formula_gen9[1], formula_gen9[2])
290
+
291
+ if out is not None:
292
+ out = simplify(out)
293
+ if out is not None and (complexnum or (not complexnum and not contain(out, tree_form("s_i")))):
294
+ return out
295
+
296
+ return TreeNode(equation.name, [factor_helper(child, complexnum, power) for child in equation.children])
297
+ def factor(equation):
298
+ return simplify(take_common2(simplify(equation)))
299
+
300
+ def factor2(equation, complexnum=False):
301
+ return simplify(factor_helper(simplify(equation), complexnum, 2))
302
+
303
+ def factor3(equation, complexnum=False):
304
+ return simplify(factor_helper(simplify(factor_helper(simplify(equation), complexnum, 2)), complexnum, 3))
mathai/fraction.py ADDED
@@ -0,0 +1,103 @@
1
+ from .base import *
2
+ from .simplify import simplify
3
+ from .expand import expand
4
+
5
+ def fraction(eq):
6
+ stack = [(eq, None)] # (current_node, parent_processed_children)
7
+ result_map = {} # Map original nodes to their processed TreeNode
8
+
9
+ while stack:
10
+ node, parent_info = stack.pop()
11
+
12
+ # If node already processed, continue
13
+ if node in result_map:
14
+ continue
15
+
16
+ # Base case: leaf node
17
+ if not node.children:
18
+ result_map[node] = TreeNode(node.name, [])
19
+ continue
20
+
21
+ # Check if all children are processed
22
+ all_children_done = all(child in result_map for child in node.children)
23
+ if not all_children_done:
24
+ # Push current node back to stack after children
25
+ stack.append((node, parent_info))
26
+ for child in reversed(node.children):
27
+ if child not in result_map:
28
+ stack.append((child, (node, node.children)))
29
+ continue
30
+
31
+ # Now all children are processed, handle this node
32
+ if node.name == "f_eq":
33
+ left = result_map[node.children[0]]
34
+ right = result_map[node.children[1]]
35
+ result_map[node] = TreeNode("f_eq", [left, right])
36
+ continue
37
+
38
+ elif node.name == "f_add":
39
+ con = []
40
+ for child in node.children:
41
+ child_processed = result_map[child]
42
+ if child_processed.name == "f_pow" and child_processed.children[1].name[:2] == "d_" and int(child_processed.children[1].name[2:]) < 0:
43
+ den = []
44
+ n = int(child_processed.children[1].name[2:])
45
+ if n == -1:
46
+ den.append(child_processed.children[0])
47
+ else:
48
+ den.append(TreeNode("f_pow", [child_processed.children[0], tree_form("d_" + str(-n))]))
49
+ con.append([[], den])
50
+ elif child_processed.name == "f_mul":
51
+ num = []
52
+ den = []
53
+ for child2 in child_processed.children:
54
+ if child2.name == "f_pow" and child2.children[1].name[:2] == "d_" and int(child2.children[1].name[2:]) < 0:
55
+ n = int(child2.children[1].name[2:])
56
+ if n == -1:
57
+ den.append(child2.children[0])
58
+ else:
59
+ den.append(TreeNode("f_pow", [child2.children[0], tree_form("d_" + str(-n))]))
60
+ else:
61
+ num.append(child2)
62
+ con.append([num, den])
63
+ else:
64
+ con.append([[child_processed], []])
65
+
66
+ if len(con) > 1 and any(x[1] != [] for x in con):
67
+ # Construct numerator
68
+ a_children = []
69
+ for i in range(len(con)):
70
+ b_children = con[i][0].copy()
71
+ for j in range(len(con)):
72
+ if i == j:
73
+ continue
74
+ b_children += con[j][1]
75
+ if len(b_children) == 0:
76
+ b_children = [tree_form("d_1")]
77
+ elif len(b_children) == 1:
78
+ b_children = b_children
79
+ else:
80
+ b_children = [TreeNode("f_mul", b_children)]
81
+ a_children += b_children if isinstance(b_children, list) else [b_children]
82
+
83
+ a = TreeNode("f_add", a_children)
84
+
85
+ # Construct denominator
86
+ c_children = []
87
+ for i in range(len(con)):
88
+ c_children += con[i][1]
89
+ if len(c_children) == 1:
90
+ c = c_children[0]
91
+ else:
92
+ c = TreeNode("f_mul", c_children)
93
+ c = TreeNode("f_pow", [c, tree_form("d_-1")])
94
+
95
+ result_map[node] = TreeNode("f_mul", [simplify(expand(a)), c])
96
+ continue
97
+
98
+ # Default: just reconstruct node
99
+ children_processed = [result_map[child] for child in node.children]
100
+ result_map[node] = TreeNode(node.name, children_processed)
101
+
102
+ # Final return
103
+ return simplify(result_map[eq])