mathai 0.6.7__tar.gz → 0.6.9__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.7 → mathai-0.6.9}/PKG-INFO +1 -1
- {mathai-0.6.7 → mathai-0.6.9}/mathai/__init__.py +1 -1
- {mathai-0.6.7 → mathai-0.6.9}/mathai/base.py +9 -2
- mathai-0.6.9/mathai/expand.py +95 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai/factor.py +1 -1
- {mathai-0.6.7 → mathai-0.6.9}/mathai/matrix.py +5 -1
- {mathai-0.6.7 → mathai-0.6.9}/mathai/parser.py +1 -2
- {mathai-0.6.7 → mathai-0.6.9}/mathai/printeq.py +8 -5
- {mathai-0.6.7 → mathai-0.6.9}/mathai/simplify.py +19 -1
- {mathai-0.6.7 → mathai-0.6.9}/mathai.egg-info/PKG-INFO +1 -1
- {mathai-0.6.7 → mathai-0.6.9}/setup.py +1 -1
- mathai-0.6.7/mathai/expand.py +0 -124
- {mathai-0.6.7 → mathai-0.6.9}/README.md +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai/apart.py +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai/bivariate_inequality.py +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai/console.py +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai/diff.py +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai/fraction.py +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai/integrate.py +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai/inverse.py +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai/limit.py +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai/linear.py +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai/logic.py +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai/ode.py +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai/parsetab.py +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai/structure.py +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai/tool.py +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai/trig.py +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai/univariate_inequality.py +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai.egg-info/SOURCES.txt +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai.egg-info/dependency_links.txt +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai.egg-info/requires.txt +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/mathai.egg-info/top_level.txt +0 -0
- {mathai-0.6.7 → mathai-0.6.9}/setup.cfg +0 -0
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import copy
|
|
2
2
|
from fractions import Fraction
|
|
3
|
+
def use(eq):
|
|
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")))
|
|
3
7
|
def contains_list_or_neg(node):
|
|
4
8
|
stack = [node]
|
|
5
9
|
while stack:
|
|
@@ -8,9 +12,10 @@ def contains_list_or_neg(node):
|
|
|
8
12
|
return True
|
|
9
13
|
stack.extend(n.children)
|
|
10
14
|
return False
|
|
15
|
+
|
|
11
16
|
class TreeNode:
|
|
12
17
|
matmul = None
|
|
13
|
-
|
|
18
|
+
|
|
14
19
|
def __init__(self, name, children=None):
|
|
15
20
|
if children is None:
|
|
16
21
|
children = []
|
|
@@ -245,7 +250,9 @@ def frac(eq):
|
|
|
245
250
|
def factor_generation(eq):
|
|
246
251
|
output = []
|
|
247
252
|
if eq.name != "f_mul":
|
|
248
|
-
|
|
253
|
+
tmp = TreeNode("f_mul", [])
|
|
254
|
+
tmp.children.append(eq)
|
|
255
|
+
eq = tmp
|
|
249
256
|
if eq.name == "f_mul":
|
|
250
257
|
for child in eq.children:
|
|
251
258
|
if child.name == "f_pow":
|
|
@@ -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
|
|
@@ -70,6 +70,10 @@ def contains_neg(node):
|
|
|
70
70
|
return True
|
|
71
71
|
# ---------- multiplication (fully simplified) ----------
|
|
72
72
|
def multiply(left,right):
|
|
73
|
+
if left == tree_form("d_1"):
|
|
74
|
+
return right
|
|
75
|
+
if right == tree_form("d_1"):
|
|
76
|
+
return left
|
|
73
77
|
left2, right2 = left, right
|
|
74
78
|
if left2.name != "f_pow":
|
|
75
79
|
left2 = left2 ** 1
|
|
@@ -217,7 +221,7 @@ def use(eq):
|
|
|
217
221
|
def _matrix_solve(eq):
|
|
218
222
|
if TreeNode.matmul == True:
|
|
219
223
|
TreeNode.matmul = False
|
|
220
|
-
eq = dowhile(eq, lambda x: fold_wmul(flat(x)))
|
|
224
|
+
eq = dowhile(eq, lambda x: fold_wmul(use(flat(x))))
|
|
221
225
|
TreeNode.matmul = True
|
|
222
226
|
return eq
|
|
223
227
|
def matrix_solve(eq):
|
|
@@ -152,8 +152,7 @@ def parse(equation, funclist=None):
|
|
|
152
152
|
return tree_form("v_" + str(int(tree_node.name[3:])+100))
|
|
153
153
|
tree_node.children = [rfx(child) for child in tree_node.children]
|
|
154
154
|
return tree_node
|
|
155
|
-
|
|
156
|
-
return TreeNode(eq.name, [use(child) for child in eq.children])
|
|
155
|
+
|
|
157
156
|
tree_node = rfx(tree_node)
|
|
158
157
|
tree_node = flatten_tree(tree_node, ["f_wmul"])
|
|
159
158
|
if TreeNode.matmul == True:
|
|
@@ -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
|
|
@@ -500,23 +507,34 @@ def solve3(eq):
|
|
|
500
507
|
def simplify(eq, basic=True):
|
|
501
508
|
if eq is None:
|
|
502
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_")))
|
|
515
|
+
|
|
503
516
|
if eq.name == "f_and" or eq.name == "f_not" or eq.name == "f_or":
|
|
504
517
|
new_children = []
|
|
505
518
|
for child in eq.children:
|
|
506
519
|
new_children.append(simplify(child))
|
|
520
|
+
TreeNode.matmul = orig
|
|
507
521
|
return TreeNode(eq.name, new_children)
|
|
508
522
|
if eq.name[2:] in "gt ge lt le eq".split(" "):
|
|
509
523
|
denom = eq.name != "f_eq"
|
|
510
524
|
tmp2 = simplify(eq.children[0] - eq.children[1])
|
|
511
525
|
tmp, denom = clear_div(tmp2, denom)
|
|
512
526
|
tmp = simplify(tmp)
|
|
527
|
+
|
|
513
528
|
value2 = eq.name[2:]
|
|
514
529
|
if denom is False:
|
|
515
530
|
value2 = {"ge":"le", "le":"ge", "gt":"lt", "lt":"gt", "eq":"eq"}[value2]
|
|
516
531
|
value2 = "f_"+value2
|
|
517
|
-
|
|
532
|
+
out = TreeNode(value2, [tmp, tree_form("d_0")])
|
|
533
|
+
TreeNode.matmul = orig
|
|
534
|
+
return out
|
|
518
535
|
eq = flatten_tree(eq)
|
|
519
536
|
if basic:
|
|
520
537
|
eq = convert_to_basic(eq)
|
|
521
538
|
eq = solve3(eq)
|
|
539
|
+
TreeNode.matmul = orig
|
|
522
540
|
return eq
|
mathai-0.6.7/mathai/expand.py
DELETED
|
@@ -1,124 +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 _expand(equation):
|
|
45
|
-
"""Iterative version of _expand without recursion."""
|
|
46
|
-
# Stack: (node, child_index, partially_processed_children)
|
|
47
|
-
stack = [(equation, 0, [])]
|
|
48
|
-
|
|
49
|
-
while stack:
|
|
50
|
-
node, child_index, processed_children = stack.pop()
|
|
51
|
-
|
|
52
|
-
# If all children are processed
|
|
53
|
-
if child_index >= len(node.children):
|
|
54
|
-
# Replace children with processed versions
|
|
55
|
-
node.children = processed_children
|
|
56
|
-
|
|
57
|
-
# === Handle f_pow ===
|
|
58
|
-
if node.name == "f_pow":
|
|
59
|
-
n = frac(node.children[1])
|
|
60
|
-
if n is not None and n.denominator == 1 and n.numerator > 1:
|
|
61
|
-
# Convert power to repeated multiplication
|
|
62
|
-
power_children = [node.children[0] for _ in range(n.numerator)]
|
|
63
|
-
new_node = TreeNode("f_mul", power_children)
|
|
64
|
-
# Flatten tree
|
|
65
|
-
node = flatten_tree(new_node)
|
|
66
|
-
# Push it back for further processing
|
|
67
|
-
stack.append((node, 0, []))
|
|
68
|
-
continue
|
|
69
|
-
|
|
70
|
-
# === Handle f_mul ===
|
|
71
|
-
elif node.name == "f_mul":
|
|
72
|
-
# Separate lone children and bracket children
|
|
73
|
-
lone_children = tree_form("d_1")
|
|
74
|
-
bracket_children = []
|
|
75
|
-
|
|
76
|
-
# Iterate in reverse (like original)
|
|
77
|
-
for child in reversed(node.children):
|
|
78
|
-
if child.name == "f_add":
|
|
79
|
-
bracket_children.append(child)
|
|
80
|
-
elif child.name == "f_pow" and child.children[0].name == "f_add":
|
|
81
|
-
n = frac(child.children[1])
|
|
82
|
-
if n is not None and n.denominator == 1 and n.numerator > 1:
|
|
83
|
-
for _ in range(n.numerator):
|
|
84
|
-
bracket_children.append(child.children[0])
|
|
85
|
-
else:
|
|
86
|
-
lone_children = lone_children * child
|
|
87
|
-
else:
|
|
88
|
-
lone_children = lone_children * child
|
|
89
|
-
|
|
90
|
-
lone_children = simplify(lone_children)
|
|
91
|
-
|
|
92
|
-
# Distribute bracket children over lone children iteratively
|
|
93
|
-
while bracket_children:
|
|
94
|
-
tmp = tree_form("d_0")
|
|
95
|
-
bracket = bracket_children.pop(0)
|
|
96
|
-
for bc in bracket.children:
|
|
97
|
-
if lone_children.name == "f_add":
|
|
98
|
-
for lc in lone_children.children:
|
|
99
|
-
tmp = tmp + bc * lc
|
|
100
|
-
else:
|
|
101
|
-
tmp = tmp + bc * lone_children
|
|
102
|
-
# Simplify after each distribution
|
|
103
|
-
lone_children = flatten_tree(simplify(tmp))
|
|
104
|
-
|
|
105
|
-
node = lone_children
|
|
106
|
-
|
|
107
|
-
# === Return node to parent ===
|
|
108
|
-
if stack:
|
|
109
|
-
parent, idx, parent_children = stack.pop()
|
|
110
|
-
parent_children.append(node)
|
|
111
|
-
stack.append((parent, idx + 1, parent_children))
|
|
112
|
-
else:
|
|
113
|
-
# Root node fully expanded
|
|
114
|
-
return node
|
|
115
|
-
|
|
116
|
-
else:
|
|
117
|
-
# Push current node back for next child
|
|
118
|
-
stack.append((node, child_index, processed_children))
|
|
119
|
-
# Push the child to process next
|
|
120
|
-
child = flatten_tree(node.children[child_index])
|
|
121
|
-
stack.append((child, 0, []))
|
|
122
|
-
|
|
123
|
-
def expand(eq):
|
|
124
|
-
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
|