mathai 0.3.0__py3-none-any.whl → 0.3.2__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 CHANGED
@@ -1,16 +1,46 @@
1
1
  from .expand import expand
2
+
2
3
  from .parser import parse
4
+
3
5
  from .printeq import printeq, printeq_log, printeq_str
6
+
4
7
  from .simplify import solve, simplify, solve2
5
- from .integrate import integrate, sqint, byparts
8
+
9
+ from .integrate import ref as integrate_save
10
+ from .integrate import integrate_subs_main as integrate_subs
11
+ from .integrate import byparts as integrate_byparts
12
+ from .integrate import sqint as integrate_fraction
13
+ from .integrate import integrate_summation
14
+ from .integrate import rm_const as integrate_const
15
+ from .integrate import solve_integrate as integrate_clean
16
+ from .integrate import inteq as integrate_recursive
17
+ from .integrate import integrate_formula
18
+
6
19
  from .diff import diff
7
- from .factor import factor, factor2
20
+
21
+ from .factor import factor as factor1
22
+ from .factor import factor2
23
+ from .factor import factorconst as factor0
24
+
8
25
  from .fraction import fraction
26
+
9
27
  from .inverse import inverse
28
+
10
29
  from .trig import trig0, trig1, trig2, trig3, trig4
30
+
11
31
  from .logic import logic0, logic1, logic2, logic3
32
+
12
33
  from .apart import apart
34
+
13
35
  from .console import console
36
+
14
37
  from .limit import limit
38
+
39
+ from .search import dfs_simplify as search0
40
+
15
41
  from .univariate_inequality import wavycurvy, absolute, domain, handle_sqrt
42
+
16
43
  from .base import *
44
+
45
+ from .tool import enclose_const
46
+
mathai/apart.py CHANGED
@@ -5,16 +5,18 @@ from .diff import diff
5
5
  from .inverse import inverse
6
6
  from .base import *
7
7
  import math
8
- from .tool import poly
8
+ from .tool import poly, enclose_const
9
9
 
10
- def apart(eq, v="v_0"):
10
+ def _apart(eq, v="v_0"):
11
+
12
+ origv = vlist(eq)
11
13
  eq = simplify(eq)
12
14
  if eq.name != "f_mul":
13
15
  return eq
14
16
  if any("f_"+item in str_form(eq) for item in "sin cos tan log".split(" ")):
15
17
  return eq
16
18
  def exclude(eq):
17
- if eq.name == "f_pow" and eq.children[1].name[:2] != "d_":
19
+ if eq.name == "f_pow" and frac(eq.children[1]) is not None and frac(eq.children[1]).denominator != 1:
18
20
  return False
19
21
  if any(not exclude(child) for child in eq.children):
20
22
  return False
@@ -47,6 +49,7 @@ def apart(eq, v="v_0"):
47
49
  x = tree_form(v)
48
50
  num = []
49
51
  dem = []
52
+
50
53
  for item in facd2:
51
54
 
52
55
  g = countfac(facd, item)
@@ -94,10 +97,17 @@ def apart(eq, v="v_0"):
94
97
  lst = poly(s.children[0], v)
95
98
 
96
99
  lst = [TreeNode("f_eq", [item, tree_form("d_0")]) for item in lst if "v_" in str_form(item)]
97
-
98
- out = linear_solve(TreeNode("f_and", lst))
99
-
100
+ lst2 = []
101
+ for item in lst:
102
+ lst2+=vlist(item)
103
+ origv = list(set(lst2)-set(origv))
104
+ out = linear_solve(TreeNode("f_and", lst), [tree_form(item) for item in origv])
100
105
  for item in out.children:
101
106
 
102
- final3 = replace(final3, tree_form(vlist(item)[0]), inverse(item.children[0], vlist(item)[0]))
107
+ final3 = replace(final3, tree_form(list(set(vlist(item))&set(origv))[0]), inverse(item.children[0], list(set(vlist(item))&set(origv))[0]))
103
108
  return simplify(final3)
109
+ def apart(eq):
110
+ eq, fx = enclose_const(eq)
111
+
112
+ eq = _apart(eq)
113
+ return fx(eq)
mathai/base.py CHANGED
@@ -3,7 +3,8 @@ from fractions import Fraction
3
3
 
4
4
  class TreeNode:
5
5
  def __init__(self, name, children=[]):
6
- children = copy.deepcopy(children)
6
+
7
+ children = [child.copy_tree() for child in children]
7
8
  self.name = name
8
9
  if name in ["f_add", "f_mul"]:
9
10
  self.children = sorted(children, key=lambda x: str_form(x))
@@ -12,6 +13,11 @@ class TreeNode:
12
13
 
13
14
  def fx(self, fxname):
14
15
  return TreeNode("f_" + fxname, [self])
16
+ def copy_tree(node):
17
+ if node is None:
18
+ return None
19
+
20
+ return tree_form(str_form(node))
15
21
 
16
22
  def __repr__(self):
17
23
  return string_equation(str_form(self))
@@ -281,10 +287,11 @@ def flatten_tree(node):
281
287
  return node
282
288
  def dowhile(eq, fx):
283
289
  while True:
284
- orig = copy.deepcopy(eq)
285
- eq = copy.deepcopy(fx(eq))
286
- if eq is None:
290
+ orig = eq.copy_tree()
291
+ eq2 = fx(eq)
292
+ if eq2 is None:
287
293
  return None
294
+ eq = eq2.copy_tree()
288
295
  if eq == orig:
289
296
  return orig
290
297
  def tree_form(tabbed_strings):
@@ -318,7 +325,7 @@ def string_equation_helper(equation_tree):
318
325
  if equation_tree.name == "f_index":
319
326
  return string_equation_helper(equation_tree.children[0])+"["+",".join([string_equation_helper(child) for child in equation_tree.children[1:]])+"]"
320
327
  s = "("
321
- if len(equation_tree.children) == 1 or equation_tree.name[2:] in [chr(ord("A")+i) for i in range(26)]+["exist", "forall", "sum2", "int", "pdif", "dif", "A", "B", "C", "covariance", "sum"]:
328
+ if len(equation_tree.children) == 1 or equation_tree.name[2:] in [chr(ord("A")+i) for i in range(26)]+["subs", "try", "ref", "integrate", "exist", "forall", "sum2", "int", "pdif", "dif", "A", "B", "C", "covariance", "sum"]:
322
329
  s = equation_tree.name[2:] + s
323
330
  sign = {"f_not":"~", "f_addw":"+", "f_mulw":"*", "f_intersection":"&", "f_union":"|", "f_sum2":",", "f_exist":",", "f_forall":",", "f_sum":",","f_covariance": ",", "f_B":",", "f_imply":"->", "f_ge":">=", "f_le":"<=", "f_gt":">", "f_lt":"<", "f_cosec":"?" , "f_equiv": "<->", "f_sec":"?", "f_cot": "?", "f_dot": ".", "f_circumcenter":"?", "f_transpose":"?", "f_exp":"?", "f_abs":"?", "f_log":"?", "f_and":"&", "f_or":"|", "f_sub":"-", "f_neg":"?", "f_inv":"?", "f_add": "+", "f_mul": "*", "f_pow": "^", "f_poly": ",", "f_div": "/", "f_sub": "-", "f_dif": ",", "f_sin": "?", "f_cos": "?", "f_tan": "?", "f_eq": "=", "f_sqrt": "?"}
324
331
  arr = []
@@ -328,7 +335,7 @@ def string_equation_helper(equation_tree):
328
335
  else:
329
336
  k = sign[equation_tree.name]
330
337
  for child in equation_tree.children:
331
- arr.append(string_equation_helper(copy.deepcopy(child)))
338
+ arr.append(string_equation_helper(child.copy_tree()))
332
339
  outfinal = s + k.join(arr) + ")"+extra
333
340
 
334
341
  return outfinal.replace("+-", "-")
mathai/console.py CHANGED
@@ -3,7 +3,7 @@ from .expand import expand
3
3
  from .parser import parse
4
4
  from .printeq import printeq, printeq_log
5
5
  from .simplify import solve, simplify
6
- from .integrate import integrate, typesqint, typebyparts, typeintegrate
6
+
7
7
  from .diff import diff
8
8
  from .base import *
9
9
  from .factor import _factorconst, factor
mathai/diff.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from .simplify import solve
2
2
  from .base import *
3
-
3
+ from .trig import trig0
4
4
  def diff(equation, var="v_0"):
5
5
  def diffeq(eq):
6
6
  eq = solve(eq)
@@ -53,13 +53,16 @@ def diff(equation, var="v_0"):
53
53
  b1 = power - tree_form("d_1")
54
54
  bab1 = TreeNode("f_pow", [base, b1])
55
55
  return power * bab1 * dbase
56
- return eq.fx("dif")
56
+ return TreeNode("f_dif", [eq, tree_form(var)])
57
57
  def helper(equation, var="v_0"):
58
58
  if equation.name == "f_dif":
59
59
  if equation.children[0].name == var:
60
60
  return tree_form("d_1")
61
- return tree_form("d_0")
61
+ if var not in str_form(equation.children[0]):
62
+ return tree_form("d_0")
63
+ else:
64
+ return equation
62
65
  return TreeNode(equation.name, [helper(child, var) for child in equation.children])
63
- equation = diffeq(equation)
66
+ equation = diffeq(trig0(equation))
64
67
  equation = helper(equation, var)
65
68
  return solve(equation)
mathai/expand.py CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  import itertools
3
2
  from .base import *
4
3
  from .simplify import solve, simplify
@@ -6,53 +5,92 @@ from .simplify import solve, simplify
6
5
  def expand(eq):
7
6
  if eq is None:
8
7
  return None
9
- if eq.name == "f_mul" or eq.name == "f_pow":
10
- if eq.name == "f_pow":
11
- eq = TreeNode("f_pow", [eq])
12
- ac = []
13
- addchild = []
14
- for child in eq.children:
15
- tmp5 = [solve(x) for x in factor_generation(child)]
16
- ac += tmp5
17
- tmp3 = []
18
- for child in ac:
19
- tmp2 = []
20
- if child.name == "f_add":
21
- if child.children != []:
22
- for child2 in child.children:
23
- tmp2.append(child2)
8
+
9
+ stack = [(eq, 0)] # (node, stage)
10
+ result_map = {} # id(node) -> expanded TreeNode
11
+
12
+ while stack:
13
+ node, stage = stack.pop()
14
+ node_id = id(node)
15
+
16
+ # Leaf node
17
+ if not node.children and stage == 0:
18
+ result_map[node_id] = TreeNode(node.name, [])
19
+ continue
20
+
21
+ if stage == 0:
22
+ # Stage 0: push node back for stage 1 after children
23
+ stack.append((node, 1))
24
+ # Push children to stack
25
+ for child in reversed(node.children):
26
+ if id(child) not in result_map:
27
+ stack.append((child, 0))
28
+ else:
29
+ # Stage 1: all children processed
30
+ children_expanded = [result_map[id(child)] for child in node.children]
31
+
32
+ # Only f_mul or f_pow need special expansion
33
+ if node.name in ["f_mul", "f_pow"]:
34
+ current_eq = TreeNode(node.name, children_expanded)
35
+
36
+ if node.name == "f_pow":
37
+ current_eq = TreeNode("f_pow", [current_eq])
38
+
39
+ ac = []
40
+ addchild = []
41
+
42
+ for child in current_eq.children:
43
+ tmp5 = [solve(x) for x in factor_generation(child)]
44
+ ac += tmp5
45
+
46
+ tmp3 = []
47
+ for child in ac:
48
+ tmp2 = []
49
+ if child.name == "f_add":
50
+ if child.children != []:
51
+ tmp2.extend(child.children)
52
+ else:
53
+ tmp2 = [child]
54
+ else:
55
+ tmp3.append(child)
56
+ if tmp2 != []:
57
+ addchild.append(tmp2)
58
+
59
+ tmp4 = 1
60
+ for item in tmp3:
61
+ tmp4 = tmp4 * item
62
+ addchild.append([tmp4])
63
+
64
+ def flatten(lst):
65
+ flat_list = []
66
+ for item in lst:
67
+ if isinstance(item, list) and item == []:
68
+ continue
69
+ if isinstance(item, list):
70
+ flat_list.extend(flatten(item))
71
+ else:
72
+ flat_list.append(item)
73
+ return flat_list
74
+
75
+ if len(flatten(addchild)) > 0:
76
+ add = 0
77
+ for prod_items in itertools.product(*addchild):
78
+ mul = 1
79
+ for item2 in prod_items:
80
+ mul = mul * item2
81
+ mul = simplify(mul)
82
+ add = add + mul
83
+ add = simplify(add)
84
+ current_eq = simplify(add)
24
85
  else:
25
- tmp2 = [child]
86
+ current_eq = simplify(current_eq)
87
+
88
+ # Store expanded result
89
+ result_map[node_id] = current_eq
26
90
  else:
27
- tmp3.append(child)
28
- if tmp2 != []:
29
- addchild.append(tmp2)
30
- tmp4 = 1
31
- for item in tmp3:
32
- tmp4 = tmp4 * item
33
- addchild.append([tmp4])
34
- def flatten(lst):
35
- flat_list = []
36
- for item in lst:
37
- if isinstance(item, list) and item == []:
38
- continue
39
- if isinstance(item, list):
40
- flat_list.extend(flatten(item))
41
- else:
42
- flat_list.append(item)
43
- return flat_list
44
-
45
- if isinstance(addchild, list) and len(flatten(addchild))>0:
46
- add= 0
47
- for item in itertools.product(*addchild):
48
- mul = 1
49
- for item2 in item:
50
- mul = mul * item2
51
- mul = simplify(mul)
52
- add = add + mul
53
- add = simplify(add)
54
- eq = add
55
- eq = simplify(eq)
56
-
57
- return TreeNode(eq.name, [expand(child) for child in eq.children])
91
+ # Default: reconstruct node with children
92
+ result_map[node_id] = TreeNode(node.name, children_expanded)
93
+
94
+ # Return final expanded eq
95
+ return result_map[id(eq)]
58
96
 
mathai/factor.py CHANGED
@@ -77,7 +77,12 @@ def factor_quad_formula_init():
77
77
  formula_list = [[simplify(parse(y)) for y in x] for x in formula_list]
78
78
  expr = [[parse("A"), parse("1")], [parse("B"), parse("0"), parse("1")], [parse("C"), parse("0")]]
79
79
  return [formula_list, var, expr]
80
-
80
+ def factor_quar_formula_init():
81
+ var = ""
82
+ 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))")]
83
+ formula_list = [[simplify(parse(y)) for y in x] for x in formula_list]
84
+ expr = [[parse("A")], [parse("B"), parse("0"), parse("1")], [parse("C"), parse("0")]]
85
+ return [formula_list, var, expr]
81
86
  def factor_cube_formula_init():
82
87
  var = ""
83
88
  formula_list = [(f"D^3+E", f"(D+E^(1/3))*(D^2-D*E^(1/3)+E^(2/3))"), (f"D^3-E", f"(D-E^(1/3))*(D^2+D*E^(1/3)+E^(2/3))"),\
@@ -87,8 +92,9 @@ def factor_cube_formula_init():
87
92
  return [formula_list, var, expr]
88
93
  formula_gen2 = factor_quad_formula_init()
89
94
  formula_gen3 = factor_cube_formula_init()
95
+ formula_gen9 = factor_quar_formula_init()
90
96
  def factor_helper(equation, complexnum, power=2):
91
- global formula_gen2, formula_gen3
97
+ global formula_gen2, formula_gen3, formula_gen9
92
98
  maxnum = 1
93
99
  def high(eq):
94
100
  nonlocal maxnum
@@ -114,6 +120,8 @@ def factor_helper(equation, complexnum, power=2):
114
120
  out = transform_formula(helper(equation), "v_0", formula_gen2[0], formula_gen2[1], formula_gen2[2])
115
121
  elif power == 3:
116
122
  out = transform_formula(helper(equation), "v_0", formula_gen3[0], formula_gen3[1], formula_gen3[2])
123
+ elif power == 4:
124
+ out = transform_formula(helper(equation), "v_0", formula_gen9[0], formula_gen9[1], formula_gen9[2])
117
125
  if out is not None:
118
126
  out = simplify(solve(out))
119
127
  if out is not None and (complexnum or (not complexnum and not contain(out, tree_form("s_i")))):
@@ -122,4 +130,4 @@ def factor_helper(equation, complexnum, power=2):
122
130
  def factor(equation, complexnum=False):
123
131
  return solve(take_common2(simplify(factor_helper(simplify(equation), complexnum, 2))))
124
132
  def factor2(equation, complexnum=False):
125
- return solve(factor_helper(simplify(factor_helper(simplify(equation), complexnum, 2)), complexnum, 3))
133
+ return solve(factor_helper(solve(factor_helper(simplify(factor_helper(simplify(equation), complexnum, 2)), complexnum, 3)), complexnum, 4))
mathai/fraction.py CHANGED
@@ -1,59 +1,103 @@
1
1
  from .base import *
2
- from .simplify import solve
2
+ from .simplify import solve, simplify
3
3
  from .expand import expand
4
+
4
5
  def fraction(eq):
5
- if eq.name == "f_eq":
6
- return TreeNode(eq.name, [fraction(eq.children[0]), fraction(eq.children[1])])
7
- if eq.name == "f_add":
8
- con = []
9
- for child in eq.children:
10
- if child.name == "f_pow" and child.children[1].name[:2] == "d_" and int(child.children[1].name[2:])<0:
11
- den = []
12
- n = int(child.children[1].name[2:])
13
- if n == -1:
14
- den.append(child.children[0])
15
- else:
16
- den.append(TreeNode("f_pow", [child.children[0], tree_form("d_"+str(-n))]))
17
- con.append([[], den])
18
- elif child.name == "f_mul":
19
- num = []
20
- den = []
21
- for child2 in child.children:
22
- if child2.name == "f_pow" and child2.children[1].name[:2] == "d_" and int(child2.children[1].name[2:])<0:
23
- n = int(child2.children[1].name[2:])
24
- if n == -1:
25
- den.append(child2.children[0])
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))]))
26
60
  else:
27
- den.append(TreeNode("f_pow", [child2.children[0], tree_form("d_"+str(-n))]))
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
28
79
  else:
29
- num.append(child2)
30
- con.append([num, den])
31
- else:
32
- con.append([[child], []])
33
- if len(con)>1 and any(x[1] != [] for x in con):
34
- a = TreeNode("f_add", [])
35
- for i in range(len(con)):
36
- b = TreeNode("f_mul", [])
37
- if con[i][0] != []:
38
- b.children += con[i][0]
39
- for j in range(len(con)):
40
- if i ==j:
41
- continue
42
- b.children += con[j][1]
43
- if len(b.children) == 1:
44
- a.children.append(b.children[0])
45
- elif len(b.children) > 1:
46
- a.children.append(b)
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]
47
91
  else:
48
- a.children.append(tree_form("d_1"))
49
- c = TreeNode("f_mul", [])
50
- for i in range(len(con)):
51
- c.children += con[i][1]
52
- if len(c.children)==1:
53
- c = c.children[0]
54
- c = TreeNode("f_pow", [c, tree_form("d_-1")])
55
- return TreeNode("f_mul", [expand(a),c])
56
- arr = TreeNode(eq.name, [])
57
- for child in eq.children:
58
- arr.children.append(fraction(child))
59
- return solve(arr)
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 solve(result_map[eq])