mathai 0.6.8__tar.gz → 0.7.0__tar.gz
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-0.6.8 → mathai-0.7.0}/PKG-INFO +1 -1
- {mathai-0.6.8 → mathai-0.7.0}/mathai/__init__.py +1 -1
- {mathai-0.6.8 → mathai-0.7.0}/mathai/base.py +12 -5
- mathai-0.7.0/mathai/expand.py +95 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai/factor.py +1 -1
- {mathai-0.6.8 → mathai-0.7.0}/mathai/matrix.py +2 -3
- {mathai-0.6.8 → mathai-0.7.0}/mathai/parser.py +1 -1
- {mathai-0.6.8 → mathai-0.7.0}/mathai/printeq.py +8 -5
- {mathai-0.6.8 → mathai-0.7.0}/mathai/simplify.py +13 -1
- {mathai-0.6.8 → mathai-0.7.0}/mathai.egg-info/PKG-INFO +1 -1
- {mathai-0.6.8 → mathai-0.7.0}/setup.py +1 -1
- mathai-0.6.8/mathai/expand.py +0 -129
- {mathai-0.6.8 → mathai-0.7.0}/README.md +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai/apart.py +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai/bivariate_inequality.py +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai/console.py +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai/diff.py +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai/fraction.py +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai/integrate.py +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai/inverse.py +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai/limit.py +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai/linear.py +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai/logic.py +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai/ode.py +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai/parsetab.py +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai/structure.py +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai/tool.py +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai/trig.py +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai/univariate_inequality.py +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai.egg-info/SOURCES.txt +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai.egg-info/dependency_links.txt +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai.egg-info/requires.txt +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/mathai.egg-info/top_level.txt +0 -0
- {mathai-0.6.8 → mathai-0.7.0}/setup.cfg +0 -0
|
@@ -2,6 +2,8 @@ import copy
|
|
|
2
2
|
from fractions import Fraction
|
|
3
3
|
def use(eq):
|
|
4
4
|
return TreeNode(eq.name, [use(child) for child in eq.children])
|
|
5
|
+
def use2(eq):
|
|
6
|
+
return use(tree_form(str_form(eq).replace("f_wmul", "f_mul")))
|
|
5
7
|
def contains_list_or_neg(node):
|
|
6
8
|
stack = [node]
|
|
7
9
|
while stack:
|
|
@@ -10,9 +12,10 @@ def contains_list_or_neg(node):
|
|
|
10
12
|
return True
|
|
11
13
|
stack.extend(n.children)
|
|
12
14
|
return False
|
|
15
|
+
|
|
13
16
|
class TreeNode:
|
|
14
17
|
matmul = None
|
|
15
|
-
|
|
18
|
+
|
|
16
19
|
def __init__(self, name, children=None):
|
|
17
20
|
if children is None:
|
|
18
21
|
children = []
|
|
@@ -247,7 +250,9 @@ def frac(eq):
|
|
|
247
250
|
def factor_generation(eq):
|
|
248
251
|
output = []
|
|
249
252
|
if eq.name != "f_mul":
|
|
250
|
-
|
|
253
|
+
tmp = TreeNode("f_mul", [])
|
|
254
|
+
tmp.children.append(eq)
|
|
255
|
+
eq = tmp
|
|
251
256
|
if eq.name == "f_mul":
|
|
252
257
|
for child in eq.children:
|
|
253
258
|
if child.name == "f_pow":
|
|
@@ -365,21 +370,23 @@ def product(lst):
|
|
|
365
370
|
for item in lst[1:]:
|
|
366
371
|
s *= item
|
|
367
372
|
return s
|
|
368
|
-
def flatten_tree(node
|
|
373
|
+
def flatten_tree(node):
|
|
374
|
+
if node is None:
|
|
375
|
+
return None
|
|
369
376
|
if not node.children:
|
|
370
377
|
return node
|
|
371
378
|
ad = []
|
|
372
379
|
if node.name in ["f_add", "f_mul", "f_and", "f_or", "f_wmul"]:
|
|
373
380
|
merged_children = []
|
|
374
381
|
for child in node.children:
|
|
375
|
-
flattened_child = flatten_tree(child
|
|
382
|
+
flattened_child = flatten_tree(child)
|
|
376
383
|
if flattened_child.name == node.name:
|
|
377
384
|
merged_children.extend(flattened_child.children)
|
|
378
385
|
else:
|
|
379
386
|
merged_children.append(flattened_child)
|
|
380
387
|
return TreeNode(node.name, merged_children)
|
|
381
388
|
else:
|
|
382
|
-
node.children = [flatten_tree(child
|
|
389
|
+
node.children = [flatten_tree(child) for child in node.children]
|
|
383
390
|
return node
|
|
384
391
|
def dowhile(eq, fx):
|
|
385
392
|
if eq is None:
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
from .base import *
|
|
2
|
+
from .simplify import simplify
|
|
3
|
+
import itertools
|
|
4
|
+
|
|
5
|
+
def eliminate_powers(node):
|
|
6
|
+
if not node.children:
|
|
7
|
+
return node
|
|
8
|
+
|
|
9
|
+
node.children = [eliminate_powers(c) for c in node.children]
|
|
10
|
+
|
|
11
|
+
if node.name == "f_pow":
|
|
12
|
+
base, exp = node.children
|
|
13
|
+
n = frac(exp)
|
|
14
|
+
|
|
15
|
+
# Only expand positive integer powers
|
|
16
|
+
if not (n and n.denominator == 1 and n.numerator > 1):
|
|
17
|
+
return node
|
|
18
|
+
|
|
19
|
+
n = n.numerator
|
|
20
|
+
|
|
21
|
+
# ---- Multinomial expansion ----
|
|
22
|
+
if base.name == "f_add":
|
|
23
|
+
terms = []
|
|
24
|
+
for combo in itertools.product(base.children, repeat=n):
|
|
25
|
+
prod = combo[0]
|
|
26
|
+
for c in combo[1:]:
|
|
27
|
+
prod = prod * c
|
|
28
|
+
terms.append(prod)
|
|
29
|
+
return simplify(TreeNode("f_add", terms))
|
|
30
|
+
|
|
31
|
+
# ---- Fallback: simple power ----
|
|
32
|
+
return TreeNode("f_mul", [base] * n)
|
|
33
|
+
|
|
34
|
+
return node
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# =====================================================
|
|
39
|
+
# Phase 2: Single distributive rewrite (DEEPEST FIRST)
|
|
40
|
+
# =====================================================
|
|
41
|
+
|
|
42
|
+
def expand_once(node):
|
|
43
|
+
"""
|
|
44
|
+
Performs exactly ONE distributive expansion.
|
|
45
|
+
Deepest-first (post-order).
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
# ---- recurse FIRST (this is the fix) ----
|
|
49
|
+
for i, c in enumerate(node.children):
|
|
50
|
+
new, changed = expand_once(c)
|
|
51
|
+
if changed:
|
|
52
|
+
node.children[i] = new
|
|
53
|
+
return node, True
|
|
54
|
+
|
|
55
|
+
# ---- now try expanding at this node ----
|
|
56
|
+
if node.name == "f_mul":
|
|
57
|
+
for i, child in enumerate(node.children):
|
|
58
|
+
if child.name == "f_add":
|
|
59
|
+
left = node.children[:i]
|
|
60
|
+
right = node.children[i+1:]
|
|
61
|
+
|
|
62
|
+
terms = []
|
|
63
|
+
for t in child.children:
|
|
64
|
+
prod = t
|
|
65
|
+
for r in right:
|
|
66
|
+
prod = prod * r
|
|
67
|
+
for l in reversed(left):
|
|
68
|
+
prod = l * prod
|
|
69
|
+
terms.append(prod)
|
|
70
|
+
|
|
71
|
+
return TreeNode("f_add", terms), True
|
|
72
|
+
|
|
73
|
+
return node, False
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# =====================================================
|
|
77
|
+
# Phase 3: Global fixed-point driver
|
|
78
|
+
# =====================================================
|
|
79
|
+
|
|
80
|
+
def expand(eq):
|
|
81
|
+
orig = TreeNode.matmul
|
|
82
|
+
eq = simplify(eq)
|
|
83
|
+
if TreeNode.matmul is not None:
|
|
84
|
+
TreeNode.matmul = True
|
|
85
|
+
eq = tree_form(str_form(eq).replace("f_wmul", "f_mul"))
|
|
86
|
+
eq = flatten_tree(eq)
|
|
87
|
+
eq = eliminate_powers(eq)
|
|
88
|
+
while True:
|
|
89
|
+
eq = flatten_tree(eq)
|
|
90
|
+
eq, changed = expand_once(eq)
|
|
91
|
+
if not changed:
|
|
92
|
+
break
|
|
93
|
+
eq =simplify(eq)
|
|
94
|
+
TreeNode.matmul = orig
|
|
95
|
+
return eq
|
|
@@ -215,14 +215,13 @@ def fold_wmul(root):
|
|
|
215
215
|
return newnode[root]
|
|
216
216
|
|
|
217
217
|
def flat(eq):
|
|
218
|
-
return flatten_tree(eq
|
|
218
|
+
return flatten_tree(eq)
|
|
219
219
|
def use(eq):
|
|
220
220
|
return TreeNode(eq.name, [use(child) for child in eq.children])
|
|
221
221
|
def _matrix_solve(eq):
|
|
222
222
|
if TreeNode.matmul == True:
|
|
223
223
|
TreeNode.matmul = False
|
|
224
|
-
eq = use(
|
|
225
|
-
eq = dowhile(eq, lambda x: fold_wmul(flat(x)))
|
|
224
|
+
eq = dowhile(eq, lambda x: fold_wmul(use(flat(x))))
|
|
226
225
|
TreeNode.matmul = True
|
|
227
226
|
return eq
|
|
228
227
|
def matrix_solve(eq):
|
|
@@ -154,7 +154,7 @@ def parse(equation, funclist=None):
|
|
|
154
154
|
return tree_node
|
|
155
155
|
|
|
156
156
|
tree_node = rfx(tree_node)
|
|
157
|
-
tree_node = flatten_tree(tree_node
|
|
157
|
+
tree_node = flatten_tree(tree_node)
|
|
158
158
|
if TreeNode.matmul == True:
|
|
159
159
|
TreeNode.matmul = False
|
|
160
160
|
tree_node = use(tree_form(str_form(tree_node).replace("f_w","f_")))
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from .base import *
|
|
2
|
+
from .factor import merge_sqrt
|
|
2
3
|
from .simplify import simplify
|
|
3
4
|
import copy
|
|
4
5
|
from fractions import Fraction
|
|
@@ -24,11 +25,13 @@ def abstractexpr(eq):
|
|
|
24
25
|
return TreeNode(eq.name, [abstractexpr(child) for child in eq.children])
|
|
25
26
|
|
|
26
27
|
def printeq_str(eq):
|
|
27
|
-
|
|
28
|
+
if eq is None:
|
|
29
|
+
return None
|
|
30
|
+
eq = merge_sqrt(eq)
|
|
31
|
+
return string_equation(str_form(dowhile(eq, abstractexpr)))
|
|
32
|
+
def printeq_obj(self):
|
|
33
|
+
return printeq_str(self)
|
|
28
34
|
|
|
29
35
|
def printeq(eq):
|
|
30
36
|
print(printeq_str(eq))
|
|
31
|
-
|
|
32
|
-
def printeq_log(lst):
|
|
33
|
-
for item in lst:
|
|
34
|
-
print(" "*item[0] + item[1])
|
|
37
|
+
TreeNode.__repr__ = printeq_obj
|
|
@@ -15,9 +15,12 @@ def convert_to_basic(node):
|
|
|
15
15
|
return node
|
|
16
16
|
|
|
17
17
|
def clear_div(eq, denom):
|
|
18
|
+
|
|
18
19
|
lst = factor_generation(eq)
|
|
20
|
+
|
|
19
21
|
if tree_form("d_0") in lst:
|
|
20
22
|
return tree_form("d_0"), True
|
|
23
|
+
|
|
21
24
|
lst3 = []
|
|
22
25
|
for item in lst:
|
|
23
26
|
if "v_" not in str_form(item) and compute(item) < 0:
|
|
@@ -33,10 +36,12 @@ def clear_div(eq, denom):
|
|
|
33
36
|
eq2.append(item)
|
|
34
37
|
else:
|
|
35
38
|
eq3.append(item)
|
|
39
|
+
|
|
36
40
|
if eq3 == []:
|
|
37
41
|
return product(eq2), True
|
|
38
42
|
return product(eq3), sign
|
|
39
43
|
lst4 = []
|
|
44
|
+
|
|
40
45
|
for item in lst:
|
|
41
46
|
if item.name == "f_pow":
|
|
42
47
|
tmp = frac(item.children[1])
|
|
@@ -44,10 +49,12 @@ def clear_div(eq, denom):
|
|
|
44
49
|
lst4.append(item)
|
|
45
50
|
else:
|
|
46
51
|
lst4.append(item)
|
|
52
|
+
|
|
47
53
|
lst2 = []
|
|
48
54
|
for item in lst4:
|
|
49
55
|
if frac(item) is None:#"v_" in str_form(item):
|
|
50
56
|
lst2.append(item)
|
|
57
|
+
|
|
51
58
|
if lst2 == []:
|
|
52
59
|
return product(lst4), sign
|
|
53
60
|
return product(lst2), sign
|
|
@@ -503,23 +510,28 @@ def simplify(eq, basic=True):
|
|
|
503
510
|
orig = TreeNode.matmul
|
|
504
511
|
if TreeNode.matmul == True:
|
|
505
512
|
TreeNode.matmul = False
|
|
513
|
+
if TreeNode.matmul == False:
|
|
506
514
|
eq = use(tree_form(str_form(eq).replace("f_w","f_")))
|
|
507
515
|
|
|
508
516
|
if eq.name == "f_and" or eq.name == "f_not" or eq.name == "f_or":
|
|
509
517
|
new_children = []
|
|
510
518
|
for child in eq.children:
|
|
511
519
|
new_children.append(simplify(child))
|
|
520
|
+
TreeNode.matmul = orig
|
|
512
521
|
return TreeNode(eq.name, new_children)
|
|
513
522
|
if eq.name[2:] in "gt ge lt le eq".split(" "):
|
|
514
523
|
denom = eq.name != "f_eq"
|
|
515
524
|
tmp2 = simplify(eq.children[0] - eq.children[1])
|
|
516
525
|
tmp, denom = clear_div(tmp2, denom)
|
|
517
526
|
tmp = simplify(tmp)
|
|
527
|
+
|
|
518
528
|
value2 = eq.name[2:]
|
|
519
529
|
if denom is False:
|
|
520
530
|
value2 = {"ge":"le", "le":"ge", "gt":"lt", "lt":"gt", "eq":"eq"}[value2]
|
|
521
531
|
value2 = "f_"+value2
|
|
522
|
-
|
|
532
|
+
out = TreeNode(value2, [tmp, tree_form("d_0")])
|
|
533
|
+
TreeNode.matmul = orig
|
|
534
|
+
return out
|
|
523
535
|
eq = flatten_tree(eq)
|
|
524
536
|
if basic:
|
|
525
537
|
eq = convert_to_basic(eq)
|
mathai-0.6.8/mathai/expand.py
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import itertools
|
|
2
|
-
from .base import *
|
|
3
|
-
from .simplify import simplify
|
|
4
|
-
'''
|
|
5
|
-
def _expand(equation):
|
|
6
|
-
eq = equation
|
|
7
|
-
eq.children = [_expand(flatten_tree(child)) for child in eq.children]
|
|
8
|
-
if eq.name == "f_pow":
|
|
9
|
-
n = frac(eq.children[1])
|
|
10
|
-
if n is not None and n.denominator == 1 and n.numerator > 1:
|
|
11
|
-
power_children = []
|
|
12
|
-
for i in range(n.numerator):
|
|
13
|
-
power_children.append(eq.children[0])
|
|
14
|
-
return _expand(flatten_tree(TreeNode("f_mul", power_children)))
|
|
15
|
-
if eq.name == "f_mul":
|
|
16
|
-
lone_children = tree_form("d_1")
|
|
17
|
-
bracket_children = []
|
|
18
|
-
for i in range(len(eq.children)-1,-1,-1):
|
|
19
|
-
if eq.children[i].name == "f_add":
|
|
20
|
-
bracket_children.append(eq.children[i])
|
|
21
|
-
elif eq.children[i].name == "f_pow" and eq.children[i].children[0].name == "f_add":
|
|
22
|
-
n = frac(eq.children[i].children[1])
|
|
23
|
-
if n is not None and n.denominator == 1 and n.numerator > 1:
|
|
24
|
-
for j in range(n.numerator):
|
|
25
|
-
bracket_children.append(eq.children[i].children[0])
|
|
26
|
-
else:
|
|
27
|
-
lone_children = lone_children * eq.children[i]
|
|
28
|
-
else:
|
|
29
|
-
lone_children = lone_children * eq.children[i]
|
|
30
|
-
lone_children = simplify(lone_children)
|
|
31
|
-
while bracket_children != []:
|
|
32
|
-
tmp = tree_form("d_0")
|
|
33
|
-
for i in range(len(bracket_children[0].children)):
|
|
34
|
-
if lone_children.name == "f_add":
|
|
35
|
-
for j in range(len(lone_children.children)):
|
|
36
|
-
tmp = tmp + bracket_children[0].children[i] * lone_children.children[j]
|
|
37
|
-
else:
|
|
38
|
-
tmp = tmp + lone_children * bracket_children[0].children[i]
|
|
39
|
-
lone_children = flatten_tree(simplify(tmp))
|
|
40
|
-
bracket_children.pop(0)
|
|
41
|
-
return lone_children
|
|
42
|
-
return eq
|
|
43
|
-
'''
|
|
44
|
-
def is_expandable(child):
|
|
45
|
-
if child.name == "f_add":
|
|
46
|
-
return True
|
|
47
|
-
if child.name == "f_pow" and child.children[0].name == "f_add":
|
|
48
|
-
n = frac(child.children[1])
|
|
49
|
-
return n is not None and n.denominator == 1 and n.numerator > 1
|
|
50
|
-
return False
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def expand_terms(child):
|
|
54
|
-
if child.name == "f_add":
|
|
55
|
-
return child.children
|
|
56
|
-
n = frac(child.children[1]).numerator
|
|
57
|
-
return child.children[0].children * n
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def _expand(equation):
|
|
61
|
-
stack = [(equation, 0, [])]
|
|
62
|
-
|
|
63
|
-
while stack:
|
|
64
|
-
node, idx, done = stack.pop()
|
|
65
|
-
|
|
66
|
-
if idx >= len(node.children):
|
|
67
|
-
node.children = done
|
|
68
|
-
|
|
69
|
-
# ===== f_pow =====
|
|
70
|
-
if node.name == "f_pow":
|
|
71
|
-
n = frac(node.children[1])
|
|
72
|
-
if n and n.denominator == 1 and n.numerator > 1:
|
|
73
|
-
node = flatten_tree(
|
|
74
|
-
TreeNode("f_mul", [node.children[0]] * n.numerator)
|
|
75
|
-
)
|
|
76
|
-
stack.append((node, 0, []))
|
|
77
|
-
continue
|
|
78
|
-
|
|
79
|
-
# ===== f_mul =====
|
|
80
|
-
elif node.name == "f_mul":
|
|
81
|
-
children = node.children
|
|
82
|
-
k = len(children)
|
|
83
|
-
|
|
84
|
-
# ---- find expandable index (L→R, then R→L) ----
|
|
85
|
-
idxs = list(range(k)) + list(reversed(range(k)))
|
|
86
|
-
seen = set()
|
|
87
|
-
expand_i = None
|
|
88
|
-
|
|
89
|
-
for i in idxs:
|
|
90
|
-
if i in seen:
|
|
91
|
-
continue
|
|
92
|
-
seen.add(i)
|
|
93
|
-
if is_expandable(children[i]):
|
|
94
|
-
expand_i = i
|
|
95
|
-
break
|
|
96
|
-
|
|
97
|
-
if expand_i is not None:
|
|
98
|
-
left = children[:expand_i]
|
|
99
|
-
right = children[expand_i + 1:]
|
|
100
|
-
expandable = children[expand_i]
|
|
101
|
-
|
|
102
|
-
out = tree_form("d_0")
|
|
103
|
-
for term in expand_terms(expandable):
|
|
104
|
-
prod = term
|
|
105
|
-
for r in right:
|
|
106
|
-
prod = prod * r
|
|
107
|
-
for l in reversed(left):
|
|
108
|
-
prod = l * prod
|
|
109
|
-
out = out + prod
|
|
110
|
-
|
|
111
|
-
node = flatten_tree(simplify(out))
|
|
112
|
-
|
|
113
|
-
# ===== return =====
|
|
114
|
-
if stack:
|
|
115
|
-
parent, pidx, acc = stack.pop()
|
|
116
|
-
acc.append(node)
|
|
117
|
-
stack.append((parent, pidx + 1, acc))
|
|
118
|
-
else:
|
|
119
|
-
return node
|
|
120
|
-
|
|
121
|
-
else:
|
|
122
|
-
stack.append((node, idx, done))
|
|
123
|
-
child = flatten_tree(node.children[idx])
|
|
124
|
-
stack.append((child, 0, []))
|
|
125
|
-
|
|
126
|
-
def expand(eq):
|
|
127
|
-
if TreeNode.matmul == True:
|
|
128
|
-
eq = tree_form(str_form(eq).replace("f_wmul", "f_mul"))
|
|
129
|
-
return _expand(eq)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|