mathai 0.3.7__tar.gz → 0.3.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.3.7 → mathai-0.3.9}/PKG-INFO +1 -1
- {mathai-0.3.7 → mathai-0.3.9}/mathai/__init__.py +0 -2
- {mathai-0.3.7 → mathai-0.3.9}/mathai/apart.py +19 -9
- {mathai-0.3.7 → mathai-0.3.9}/mathai/base.py +4 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai/integrate.py +1 -1
- {mathai-0.3.7 → mathai-0.3.9}/mathai/linear.py +7 -4
- {mathai-0.3.7 → mathai-0.3.9}/mathai/simplify.py +17 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai/trig.py +29 -8
- {mathai-0.3.7 → mathai-0.3.9}/mathai.egg-info/PKG-INFO +1 -1
- {mathai-0.3.7 → mathai-0.3.9}/mathai.egg-info/SOURCES.txt +0 -1
- {mathai-0.3.7 → mathai-0.3.9}/setup.py +1 -1
- mathai-0.3.7/mathai/search.py +0 -117
- {mathai-0.3.7 → mathai-0.3.9}/README.md +0 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai/console.py +0 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai/diff.py +0 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai/expand.py +0 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai/factor.py +0 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai/fraction.py +0 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai/inverse.py +0 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai/limit.py +0 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai/logic.py +0 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai/parser.py +0 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai/printeq.py +0 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai/structure.py +0 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai/tool.py +0 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai/univariate_inequality.py +0 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai.egg-info/dependency_links.txt +0 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai.egg-info/requires.txt +0 -0
- {mathai-0.3.7 → mathai-0.3.9}/mathai.egg-info/top_level.txt +0 -0
- {mathai-0.3.7 → mathai-0.3.9}/setup.cfg +0 -0
@@ -1,14 +1,18 @@
|
|
1
1
|
from .linear import linear_solve
|
2
2
|
from .expand import expand
|
3
3
|
from .simplify import simplify
|
4
|
+
|
4
5
|
from .diff import diff
|
5
6
|
from .inverse import inverse
|
6
7
|
from .base import *
|
7
8
|
import math
|
8
9
|
from .tool import poly, enclose_const
|
9
10
|
|
10
|
-
def _apart(eq, v=
|
11
|
-
|
11
|
+
def _apart(eq, v=None):
|
12
|
+
if v is None:
|
13
|
+
if len(vlist(eq)) == 0:
|
14
|
+
return eq
|
15
|
+
v = vlist(eq)[0]
|
12
16
|
origv = vlist(eq)
|
13
17
|
eq = simplify(eq)
|
14
18
|
if eq.name != "f_mul":
|
@@ -42,8 +46,9 @@ def _apart(eq, v="v_0"):
|
|
42
46
|
s = []
|
43
47
|
facd = [simplify(x) for x in factor_generation(simplify(d))]
|
44
48
|
|
45
|
-
|
46
|
-
facd2 = remove_duplicates_custom(facd, lambda m, n: simplify(m-n) == tree_form("d_0"))
|
49
|
+
|
50
|
+
facd2 = remove_duplicates_custom(facd, lambda m, n: simplify(expand(simplify(m-n))) == tree_form("d_0"))
|
51
|
+
|
47
52
|
if len(facd2) == 1:
|
48
53
|
return eq
|
49
54
|
x = tree_form(v)
|
@@ -58,6 +63,7 @@ def _apart(eq, v="v_0"):
|
|
58
63
|
if n > 2:
|
59
64
|
return eq
|
60
65
|
n = tree_form("d_"+str(n))
|
66
|
+
|
61
67
|
l = len(poly(item, v))
|
62
68
|
if l == 3:
|
63
69
|
a = alloclst.pop(0)
|
@@ -93,14 +99,15 @@ def _apart(eq, v="v_0"):
|
|
93
99
|
final = summation(final2)
|
94
100
|
|
95
101
|
s = simplify(TreeNode("f_eq", [final-eq2, tree_form("d_0")]))
|
96
|
-
|
102
|
+
|
97
103
|
lst = poly(s.children[0], v)
|
98
|
-
|
104
|
+
|
99
105
|
lst = [TreeNode("f_eq", [item, tree_form("d_0")]) for item in lst if "v_" in str_form(item)]
|
100
106
|
lst2 = []
|
101
107
|
for item in lst:
|
102
108
|
lst2+=vlist(item)
|
103
109
|
origv = list(set(lst2)-set(origv))
|
110
|
+
|
104
111
|
out = linear_solve(TreeNode("f_and", lst), [tree_form(item) for item in origv])
|
105
112
|
for item in out.children:
|
106
113
|
|
@@ -108,6 +115,9 @@ def _apart(eq, v="v_0"):
|
|
108
115
|
return simplify(final3)
|
109
116
|
def apart(eq):
|
110
117
|
eq, fx = enclose_const(eq)
|
111
|
-
|
112
|
-
|
113
|
-
|
118
|
+
def helper(eq):
|
119
|
+
eq2 = _apart(eq)
|
120
|
+
if eq != eq2:
|
121
|
+
return eq2
|
122
|
+
return TreeNode(eq.name, [helper(child) for child in eq.children])
|
123
|
+
return fx(helper(eq))
|
@@ -131,6 +131,8 @@ def frac(eq):
|
|
131
131
|
return Fraction(int(eq.name[2:]))
|
132
132
|
if eq.name == "f_add":
|
133
133
|
p = frac(eq.children[0])
|
134
|
+
if p is None:
|
135
|
+
return None
|
134
136
|
for child in eq.children[1:]:
|
135
137
|
tmp = frac(child)
|
136
138
|
if isinstance(tmp, Fraction):
|
@@ -140,6 +142,8 @@ def frac(eq):
|
|
140
142
|
return p
|
141
143
|
if eq.name == "f_mul":
|
142
144
|
p = frac(eq.children[0])
|
145
|
+
if p is None:
|
146
|
+
return None
|
143
147
|
for child in eq.children[1:]:
|
144
148
|
tmp = frac(child)
|
145
149
|
if isinstance(tmp, Fraction):
|
@@ -170,7 +170,7 @@ def integrate_subs(equation, term, v1, v2):
|
|
170
170
|
|
171
171
|
return none
|
172
172
|
|
173
|
-
return TreeNode("f_subs", [TreeNode("f_integrate", [simplify(expand(simplify(equation))), tree_form(origv2)]),tree_form(origv2) ,g])
|
173
|
+
return TreeNode("f_subs", [TreeNode("f_integrate", [simplify(fraction(expand(simplify(equation)))), tree_form(origv2)]),tree_form(origv2) ,g])
|
174
174
|
|
175
175
|
def integrate_subs_main(equation):
|
176
176
|
if equation.name == "f_ref":
|
@@ -3,6 +3,9 @@ from .simplify import simplify, solve
|
|
3
3
|
from .fraction import fraction
|
4
4
|
from .expand import expand
|
5
5
|
from .base import *
|
6
|
+
from .factor import factorconst
|
7
|
+
def ss(eq):
|
8
|
+
return dowhile(eq, lambda x: fraction(expand(simplify(x))))
|
6
9
|
def rref(matrix):
|
7
10
|
rows, cols = len(matrix), len(matrix[0])
|
8
11
|
lead = 0
|
@@ -10,7 +13,7 @@ def rref(matrix):
|
|
10
13
|
if lead >= cols:
|
11
14
|
return matrix
|
12
15
|
i = r
|
13
|
-
while
|
16
|
+
while ss(matrix[i][lead]) == tree_form("d_0"):
|
14
17
|
i += 1
|
15
18
|
if i == rows:
|
16
19
|
i = r
|
@@ -19,11 +22,11 @@ def rref(matrix):
|
|
19
22
|
return matrix
|
20
23
|
matrix[i], matrix[r] = matrix[r], matrix[i]
|
21
24
|
lv = matrix[r][lead]
|
22
|
-
matrix[r] = [
|
25
|
+
matrix[r] = [ss(m / lv) for m in matrix[r]]
|
23
26
|
for i in range(rows):
|
24
27
|
if i != r:
|
25
28
|
lv = matrix[i][lead]
|
26
|
-
matrix[i] = [
|
29
|
+
matrix[i] = [ss(m - lv * n) for m, n in zip(matrix[i], matrix[r])]
|
27
30
|
lead += 1
|
28
31
|
return matrix
|
29
32
|
def islinear(eq, fxconst):
|
@@ -91,7 +94,7 @@ def linear(eqlist, fxconst):
|
|
91
94
|
for i in range(len(m)):
|
92
95
|
for j in range(len(m[i])):
|
93
96
|
m[i][j] = fraction(m[i][j])
|
94
|
-
|
97
|
+
|
95
98
|
for item in m:
|
96
99
|
if all(item2==tree_form("d_0") for item2 in item[:-1]) and item[-1] != tree_form("d_0"):
|
97
100
|
return tree_form("s_false")
|
@@ -286,6 +286,23 @@ def simplify(eq):
|
|
286
286
|
error = True
|
287
287
|
else:
|
288
288
|
eq = tree_form("d_0")
|
289
|
+
|
290
|
+
if eq.name == "f_mul" and str_form(eq).count("f_pow")>1:
|
291
|
+
dic = {}
|
292
|
+
for child in eq.children:
|
293
|
+
head = child
|
294
|
+
tail = None
|
295
|
+
if child.name == "f_pow":
|
296
|
+
head = child.children[0]
|
297
|
+
tail = child.children[1]
|
298
|
+
if tail is None:
|
299
|
+
tail = tree_form("d_1")
|
300
|
+
if head not in dic.keys():
|
301
|
+
dic[head] = tail
|
302
|
+
else:
|
303
|
+
dic[head] += tail
|
304
|
+
if len(eq.children) != len(dic.keys()):
|
305
|
+
eq = product([key if dic[key] == 1 else key**dic[key] for key in dic.keys()])
|
289
306
|
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"):
|
290
307
|
eq = eq.children[0].children[0]
|
291
308
|
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"):
|
@@ -199,16 +199,37 @@ def trig4(eq, numer=True):
|
|
199
199
|
return tree_form("d_1")/(1+a**2)**(tree_form("d_2")**-1)
|
200
200
|
|
201
201
|
return TreeNode(eq.name, [trig4(child, False) if not numer or (eq.name == "f_pow" and frac(eq.children[1]) is not None and frac(eq.children[1]) < 0) else trig4(child, True) for child in eq.children])
|
202
|
+
|
202
203
|
def trig2(eq):
|
203
204
|
if eq.name == "f_add":
|
204
205
|
for item in itertools.combinations(range(len(eq.children)), 2):
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
206
|
+
child1, child2 = eq.children[item[0]], eq.children[item[1]]
|
207
|
+
|
208
|
+
# Check if both are sin or cos
|
209
|
+
if child1.name in ["f_sin", "f_cos"] and child2.name in ["f_sin", "f_cos"]:
|
210
|
+
a, b = child1.children[0], child2.children[0]
|
211
|
+
|
212
|
+
# Compute the rest of the sum
|
213
|
+
rest = [eq.children[i] for i in range(len(eq.children)) if i not in item]
|
214
|
+
if len(rest) == 0:
|
215
|
+
rest_tree = tree_form("d_0")
|
216
|
+
else:
|
217
|
+
rest_tree = summation(rest)
|
218
|
+
|
219
|
+
# Now handle the sin/cos combination formula
|
220
|
+
if child1.name == "f_sin" and child2.name == "f_sin":
|
221
|
+
# sin A + sin B = 2 sin((A+B)/2) cos((A-B)/2)
|
222
|
+
two = tree_form("d_2")
|
223
|
+
combined = two * ((a + b) / two).fx("sin") * ((a - b) / two).fx("cos")
|
224
|
+
elif child1.name == "f_cos" and child2.name == "f_cos":
|
225
|
+
# cos A + cos B = 2 cos((A+B)/2) cos((A-B)/2)
|
226
|
+
two = tree_form("d_2")
|
227
|
+
combined = two * ((a + b) / two).fx("cos") * ((a - b) / two).fx("cos")
|
210
228
|
else:
|
211
|
-
|
212
|
-
|
213
|
-
|
229
|
+
# sin A + cos B = sin A + cos B (leave unchanged, or implement formula if desired)
|
230
|
+
continue # skip for now, keep original
|
231
|
+
|
232
|
+
return rest_tree + combined
|
233
|
+
|
234
|
+
# Recurse for other nodes
|
214
235
|
return TreeNode(eq.name, [trig2(child) for child in eq.children])
|
mathai-0.3.7/mathai/search.py
DELETED
@@ -1,117 +0,0 @@
|
|
1
|
-
from mathai import *
|
2
|
-
import copy
|
3
|
-
from concurrent.futures import ThreadPoolExecutor, TimeoutError
|
4
|
-
|
5
|
-
def dfs_simplify(equation, functions, true_expr, false_expr,
|
6
|
-
max_timeout=25, max_small=4,
|
7
|
-
base_timeout=1, time_per_char=0.1, timeout_increase=0.5):
|
8
|
-
"""
|
9
|
-
Perform DFS simplification on a given equation using provided functions.
|
10
|
-
|
11
|
-
Args:
|
12
|
-
equation: The starting expression (TreeNode or parsed equation)
|
13
|
-
functions: List of simplification functions
|
14
|
-
true_expr: Expression representing True (immediate termination)
|
15
|
-
false_expr: Expression representing False (immediate termination)
|
16
|
-
max_timeout: Maximum timeout allowed for any function
|
17
|
-
max_small: Number of smallest expressions to track
|
18
|
-
base_timeout: Base timeout in seconds
|
19
|
-
time_per_char: Additional timeout per character of expression
|
20
|
-
timeout_increase: Factor to increase timeout for consecutive timeouts
|
21
|
-
|
22
|
-
Returns:
|
23
|
-
tuple(found_boolean, boolean_path, smallest_expressions)
|
24
|
-
"""
|
25
|
-
original_eq = simplify(equation)
|
26
|
-
smallest_four = []
|
27
|
-
|
28
|
-
stack = [(copy.deepcopy(original_eq), [copy.deepcopy(original_eq)])]
|
29
|
-
visited = set()
|
30
|
-
|
31
|
-
found_boolean = False
|
32
|
-
boolean_path = None
|
33
|
-
boolean_expr = None
|
34
|
-
|
35
|
-
executor = ThreadPoolExecutor(max_workers=3)
|
36
|
-
consecutive_timeouts = 0
|
37
|
-
|
38
|
-
while stack and not found_boolean:
|
39
|
-
current_eq, path = stack.pop()
|
40
|
-
expr_str = str(current_eq)
|
41
|
-
|
42
|
-
if expr_str in visited:
|
43
|
-
continue
|
44
|
-
visited.add(expr_str)
|
45
|
-
|
46
|
-
# Thinking message
|
47
|
-
printeq(current_eq)
|
48
|
-
|
49
|
-
# Immediate termination using predicate functions
|
50
|
-
if true_expr(current_eq):
|
51
|
-
found_boolean = True
|
52
|
-
boolean_path = path
|
53
|
-
boolean_expr = current_eq
|
54
|
-
break
|
55
|
-
if false_expr(current_eq):
|
56
|
-
found_boolean = True
|
57
|
-
boolean_path = path
|
58
|
-
boolean_expr = current_eq
|
59
|
-
break
|
60
|
-
|
61
|
-
|
62
|
-
# Insert into smallest_four if qualifies
|
63
|
-
inserted = False
|
64
|
-
for j in range(len(smallest_four)):
|
65
|
-
if len(expr_str) < len(str(smallest_four[j][0])):
|
66
|
-
smallest_four.insert(j, (copy.deepcopy(current_eq), copy.deepcopy(path)))
|
67
|
-
inserted = True
|
68
|
-
break
|
69
|
-
if not inserted and len(smallest_four) < max_small:
|
70
|
-
smallest_four.append((copy.deepcopy(current_eq), copy.deepcopy(path)))
|
71
|
-
if len(smallest_four) > max_small:
|
72
|
-
smallest_four = smallest_four[:max_small]
|
73
|
-
|
74
|
-
# Calculate adaptive timeout with cap
|
75
|
-
timeout = (base_timeout + time_per_char * len(expr_str)) * (1 + timeout_increase * consecutive_timeouts)
|
76
|
-
if timeout > max_timeout:
|
77
|
-
timeout = max_timeout
|
78
|
-
|
79
|
-
# Try functions that reduce length first
|
80
|
-
reduced_any = False
|
81
|
-
for fx in functions:
|
82
|
-
print(f"[Thinking] Executing {fx.__name__} on current expression (timeout={timeout:.2f}s):")
|
83
|
-
printeq(current_eq)
|
84
|
-
future = executor.submit(fx, current_eq)
|
85
|
-
try:
|
86
|
-
new_expr = future.result(timeout=timeout)
|
87
|
-
new_expr_str = str(new_expr)
|
88
|
-
if len(new_expr_str) <= len(expr_str) and new_expr_str != expr_str:
|
89
|
-
reduced_any = True
|
90
|
-
stack.append((new_expr, path + [copy.deepcopy(new_expr)]))
|
91
|
-
consecutive_timeouts = 0 # reset after success
|
92
|
-
except TimeoutError:
|
93
|
-
print(f"[Thinking] {fx.__name__} timed out, skipping.")
|
94
|
-
consecutive_timeouts += 1
|
95
|
-
continue
|
96
|
-
|
97
|
-
# If no reducing function worked, try growing functions
|
98
|
-
if not reduced_any:
|
99
|
-
for fx in functions:
|
100
|
-
print(f"[Thinking] Trying growing {fx.__name__} on current expression (timeout={timeout:.2f}s):")
|
101
|
-
printeq(current_eq)
|
102
|
-
future = executor.submit(fx, current_eq)
|
103
|
-
try:
|
104
|
-
new_expr = future.result(timeout=timeout)
|
105
|
-
new_expr_str = str(new_expr)
|
106
|
-
if new_expr_str != expr_str:
|
107
|
-
stack.append((new_expr, path + [copy.deepcopy(new_expr)]))
|
108
|
-
consecutive_timeouts = 0
|
109
|
-
break # only take one growing function
|
110
|
-
except TimeoutError:
|
111
|
-
print(f"[Thinking] {fx.__name__} (growing) timed out, skipping.")
|
112
|
-
consecutive_timeouts += 1
|
113
|
-
continue
|
114
|
-
|
115
|
-
executor.shutdown(wait=True)
|
116
|
-
|
117
|
-
return found_boolean, boolean_path, smallest_four
|
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
|