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/__init__.py +53 -0
- mathai/apart.py +142 -0
- mathai/base.py +419 -0
- mathai/bivariate_inequality.py +317 -0
- mathai/console.py +84 -0
- mathai/diff.py +68 -0
- mathai/expand.py +124 -0
- mathai/factor.py +304 -0
- mathai/fraction.py +103 -0
- mathai/integrate.py +459 -0
- mathai/inverse.py +65 -0
- mathai/limit.py +156 -0
- mathai/linear.py +165 -0
- mathai/logic.py +230 -0
- mathai/matrix.py +22 -0
- mathai/ode.py +124 -0
- mathai/parser.py +158 -0
- mathai/printeq.py +34 -0
- mathai/simplify.py +521 -0
- mathai/structure.py +103 -0
- mathai/tool.py +163 -0
- mathai/trig.py +276 -0
- mathai/univariate_inequality.py +458 -0
- mathai-0.6.0.dist-info/METADATA +234 -0
- mathai-0.6.0.dist-info/RECORD +27 -0
- mathai-0.6.0.dist-info/WHEEL +5 -0
- mathai-0.6.0.dist-info/top_level.txt +1 -0
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])
|