mathai 0.7.7__tar.gz → 0.7.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.
Files changed (39) hide show
  1. {mathai-0.7.7 → mathai-0.7.9}/PKG-INFO +1 -1
  2. {mathai-0.7.7 → mathai-0.7.9}/mathai/__init__.py +2 -2
  3. {mathai-0.7.7 → mathai-0.7.9}/mathai/base.py +0 -1
  4. mathai-0.7.9/mathai/diff.py +156 -0
  5. mathai-0.7.9/mathai/fraction.py +106 -0
  6. {mathai-0.7.7 → mathai-0.7.9}/mathai/integrate.py +11 -5
  7. mathai-0.7.9/mathai/ode.py +326 -0
  8. {mathai-0.7.7 → mathai-0.7.9}/mathai/parser.py +2 -3
  9. mathai-0.7.9/mathai/pde.py +100 -0
  10. {mathai-0.7.7 → mathai-0.7.9}/mathai/structure.py +3 -3
  11. {mathai-0.7.7 → mathai-0.7.9}/mathai.egg-info/PKG-INFO +1 -1
  12. {mathai-0.7.7 → mathai-0.7.9}/setup.py +1 -1
  13. mathai-0.7.7/mathai/diff.py +0 -74
  14. mathai-0.7.7/mathai/fraction.py +0 -103
  15. mathai-0.7.7/mathai/ode.py +0 -189
  16. mathai-0.7.7/mathai/pde.py +0 -139
  17. {mathai-0.7.7 → mathai-0.7.9}/README.md +0 -0
  18. {mathai-0.7.7 → mathai-0.7.9}/mathai/apart.py +0 -0
  19. {mathai-0.7.7 → mathai-0.7.9}/mathai/bivariate_inequality.py +0 -0
  20. {mathai-0.7.7 → mathai-0.7.9}/mathai/console.py +0 -0
  21. {mathai-0.7.7 → mathai-0.7.9}/mathai/expand.py +0 -0
  22. {mathai-0.7.7 → mathai-0.7.9}/mathai/factor.py +0 -0
  23. {mathai-0.7.7 → mathai-0.7.9}/mathai/inverse.py +0 -0
  24. {mathai-0.7.7 → mathai-0.7.9}/mathai/limit.py +0 -0
  25. {mathai-0.7.7 → mathai-0.7.9}/mathai/linear.py +0 -0
  26. {mathai-0.7.7 → mathai-0.7.9}/mathai/logic.py +0 -0
  27. {mathai-0.7.7 → mathai-0.7.9}/mathai/matrix.py +0 -0
  28. {mathai-0.7.7 → mathai-0.7.9}/mathai/parsetab.py +0 -0
  29. {mathai-0.7.7 → mathai-0.7.9}/mathai/printeq.py +0 -0
  30. {mathai-0.7.7 → mathai-0.7.9}/mathai/simplify.py +0 -0
  31. {mathai-0.7.7 → mathai-0.7.9}/mathai/statistics.py +0 -0
  32. {mathai-0.7.7 → mathai-0.7.9}/mathai/tool.py +0 -0
  33. {mathai-0.7.7 → mathai-0.7.9}/mathai/trig.py +0 -0
  34. {mathai-0.7.7 → mathai-0.7.9}/mathai/univariate_inequality.py +0 -0
  35. {mathai-0.7.7 → mathai-0.7.9}/mathai.egg-info/SOURCES.txt +0 -0
  36. {mathai-0.7.7 → mathai-0.7.9}/mathai.egg-info/dependency_links.txt +0 -0
  37. {mathai-0.7.7 → mathai-0.7.9}/mathai.egg-info/requires.txt +0 -0
  38. {mathai-0.7.7 → mathai-0.7.9}/mathai.egg-info/top_level.txt +0 -0
  39. {mathai-0.7.7 → mathai-0.7.9}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mathai
3
- Version: 0.7.7
3
+ Version: 0.7.9
4
4
  Summary: Mathematics solving Ai tailored to NCERT
5
5
  Home-page: https://github.com/infinity390/mathai4
6
6
  Requires-Python: >=3.7
@@ -1,7 +1,7 @@
1
1
  from .ode import diffsolve as ode_solve
2
2
  from .ode import diffsolve_sep as ode_shift_term
3
3
 
4
- from .pde import pde_sep, want
4
+ from .pde import pde_sep, want, absorb
5
5
 
6
6
  from .linear import linear_solve, linear_or
7
7
 
@@ -21,7 +21,7 @@ from .integrate import rm_const as integrate_const
21
21
  from .integrate import solve_integrate as integrate_clean
22
22
  from .integrate import integrate_formula
23
23
 
24
- from .diff import diff
24
+ from .diff import diff, diff2
25
25
 
26
26
  from .factor import factor as factor1
27
27
  from .factor import factor2, factor3
@@ -14,7 +14,6 @@ def contains_list_or_neg(node):
14
14
  return False
15
15
 
16
16
  class TreeNode:
17
- matmul = None
18
17
 
19
18
  def __init__(self, name, children=None):
20
19
  if children is None:
@@ -0,0 +1,156 @@
1
+ from .trig import trig0
2
+ from .simplify import simplify
3
+ from .base import *
4
+
5
+ def helper(eq):
6
+ name = eq.name
7
+ if name in ["f_dif", "f_pdif"]:
8
+ if eq.children[0].name == "f_add":
9
+ return summation([TreeNode(name, [child, eq.children[1]]) for child in eq.children[0].children])
10
+
11
+ if eq.children[0].name == "f_mul":
12
+ return summation([product([TreeNode(name, [child, eq.children[1]]) if index==index2 else child for index2, child in enumerate(eq.children[0].children)])\
13
+ for index in range(len(eq.children[0].children))])
14
+ if eq.children[0].name == "f_pow" and "v_" not in str_form(eq.children[0].children[1]):
15
+ base, power = eq.children[0].children
16
+ dbase = TreeNode(name, [base, eq.children[1]])
17
+ b1 = power - tree_form("d_1")
18
+ bab1 = TreeNode("f_pow", [base, b1])
19
+ return power * bab1 * dbase
20
+
21
+ if eq.children[0].name == "f_pow":
22
+ a, b = eq.children
23
+ return a**b * ((b/a) * TreeNode(name, [a, eq.children[1]]) + a.fx("log") * TreeNode(name, [b, eq.children[1]]))
24
+
25
+ if "v_" not in str_form(eq.children[0]):
26
+ return tree_form("d_0")
27
+
28
+ if eq.children[0] == eq.children[1]:
29
+ return tree_form("d_1")
30
+
31
+ if name == "f_pdif" and not contain(eq.children[0], eq.children[1]):
32
+ return tree_form("d_0")
33
+ if eq.children[0].name == "f_sin":
34
+ eq.children[0].name = "f_cos"
35
+ d = TreeNode(name, [eq.children[0].children[0], eq.children[1]])
36
+ return d*eq.children[0]
37
+ if eq.children[0].name == "f_cos":
38
+ eq.children[0].name = "f_sin"
39
+ d = TreeNode(name, [eq.children[0].children[0], eq.children[1]])
40
+ return tree_form("d_-1")*d*eq.children[0]
41
+ if eq.children[0].name == "f_tan":
42
+ d = TreeNode(name, [eq.children[0].children[0], eq.children[1]])
43
+ return d/(eq.children[0].children[0].fx("cos")*eq.children[0].children[0].fx("cos"))
44
+ if eq.children[0].name == "f_log":
45
+ d = TreeNode(name, [eq.children[0].children[0], eq.children[1]])
46
+ return d*(tree_form("d_1")/eq.children[0].children[0])
47
+ if eq.children[0].name == "f_arcsin":
48
+ d = TreeNode(name, [eq.children[0].children[0], eq.children[1]])
49
+ return d/(tree_form("d_1")-eq.children[0].children[0]*eq.children[0].children[0])**(tree_form("d_2")**-1)
50
+ if eq.children[0].name == "f_arccos":
51
+ d = TreeNode(name, [eq.children[0].children[0], eq.children[1]])
52
+ return tree_form("d_-1")*d/(tree_form("d_1")-eq.children[0].children[0]*eq.children[0].children[0])**(tree_form("d_2")**-1)
53
+ if eq.children[0].name == "f_arctan":
54
+ d = TreeNode(name, [eq.children[0].children[0], eq.children[1]])
55
+ return d/(tree_form("d_1")+eq.children[0].children[0]*eq.children[0].children[0])
56
+
57
+ return eq
58
+
59
+ def diff3(eq):
60
+ eq = simplify(eq)
61
+
62
+ stack = [(eq, False)]
63
+ out = {}
64
+
65
+ while stack:
66
+ node, visited = stack.pop()
67
+
68
+ if not visited:
69
+ stack.append((node, True))
70
+ for c in node.children:
71
+ stack.append((c, False))
72
+ continue
73
+
74
+ new_children = [out[c] for c in node.children]
75
+ rebuilt = TreeNode(node.name, new_children)
76
+ rebuilt = helper(rebuilt)
77
+ rebuilt = simplify(rebuilt)
78
+
79
+ out[node] = rebuilt
80
+
81
+ return out[eq]
82
+
83
+ def diff2(eq):
84
+ return dowhile(eq, diff3)
85
+ def diff(equation, var="v_0"):
86
+ def diffeq(eq):
87
+ eq = simplify(eq)
88
+ if "v_" not in str_form(eq):
89
+ return tree_form("d_0")
90
+ if eq.name == "f_add":
91
+ add = tree_form("d_0")
92
+ for child in eq.children:
93
+ add += diffeq(child)
94
+ return add
95
+ elif eq.name == "f_abs":
96
+ return diffeq(eq.children[0])*eq.children[0]/eq
97
+ elif eq.name == "f_pow" and eq.children[0].name == "s_e":
98
+ return diffeq(eq.children[1])*eq
99
+ elif eq.name == "f_tan":
100
+ return diffeq(eq.children[0])/(eq.children[0].fx("cos")*eq.children[0].fx("cos"))
101
+ elif eq.name == "f_log":
102
+ return diffeq(eq.children[0])*(tree_form("d_1")/eq.children[0])
103
+ elif eq.name == "f_arcsin":
104
+ return diffeq(eq.children[0])/(tree_form("d_1")-eq.children[0]*eq.children[0])**(tree_form("d_2")**-1)
105
+ elif eq.name == "f_arccos":
106
+ return tree_form("d_-1")*diffeq(eq.children[0])/(tree_form("d_1")-eq.children[0]*eq.children[0])**(tree_form("d_2")**-1)
107
+ elif eq.name == "f_arctan":
108
+ return diffeq(eq.children[0])/(tree_form("d_1")+eq.children[0]*eq.children[0])
109
+ elif eq.name == "f_pow" and "v_" in str_form(eq.children[1]):
110
+ a, b = eq.children
111
+ return a**b * ((b/a) * diffeq(a) + a.fx("log") * diffeq(b))
112
+ elif eq.name == "f_mul":
113
+ add = tree_form("d_0")
114
+ for i in range(len(eq.children)):
115
+ tmp = eq.children.pop(i)
116
+ if len(eq.children)==1:
117
+ eq2 = eq.children[0]
118
+ else:
119
+ eq2 = eq
120
+ add += diffeq(tmp)*eq2
121
+ eq.children.insert(i, tmp)
122
+ return add
123
+ elif eq.name == "f_sin":
124
+ eq.name = "f_cos"
125
+ return diffeq(eq.children[0])*eq
126
+ elif eq.name == "f_cos":
127
+ eq.name = "f_sin"
128
+ return tree_form("d_-1")*diffeq(eq.children[0])*eq
129
+ elif eq.name[:2] == "v_":
130
+ return TreeNode("f_dif", [eq])
131
+ elif eq.name == "f_pow" and "v_" not in str_form(eq.children[1]):
132
+ base, power = eq.children
133
+ dbase = diffeq(base)
134
+ b1 = power - tree_form("d_1")
135
+ bab1 = TreeNode("f_pow", [base, b1])
136
+ return power * bab1 * dbase
137
+ return TreeNode("f_dif", [eq, tree_form(var)])
138
+ def helper2(equation, var="v_0"):
139
+ if equation.name == "f_dif":
140
+ if equation.children[0].name == var:
141
+ return tree_form("d_1")
142
+ if var not in str_form(equation.children[0]):
143
+ return tree_form("d_0")
144
+ else:
145
+ return equation
146
+ return TreeNode(equation.name, [helper2(child, var) for child in equation.children])
147
+ def calc(eq):
148
+ if eq.name == "f_dif":
149
+ return diffeq(trig0(eq.children[0]))
150
+ return TreeNode(eq.name, [calc(child) for child in eq.children])
151
+ if var is None:
152
+ return simplify(calc(equation))
153
+ equation = diffeq(trig0(equation))
154
+ equation = helper2(equation, var)
155
+ return simplify(equation)
156
+
@@ -0,0 +1,106 @@
1
+ from .base import *
2
+ from .simplify import simplify
3
+ from .expand import expand
4
+
5
+
6
+ def fraction(expr):
7
+ if expr is None:
8
+ return None
9
+
10
+ expr = simplify(expr)
11
+
12
+ # -----------------------------
13
+ # leaf
14
+ # -----------------------------
15
+ if expr.children == []:
16
+ return expr
17
+
18
+ # recurse first (inner-most first)
19
+ children = [fraction(c) for c in expr.children]
20
+
21
+ # -----------------------------
22
+ # ADDITION: collect denominators
23
+ # -----------------------------
24
+ if expr.name == "f_add":
25
+ terms = []
26
+
27
+ for c in children:
28
+ # term is a multiplication
29
+ if c.name == "f_mul":
30
+ num = []
31
+ den = []
32
+ for f in c.children:
33
+ if (
34
+ f.name == "f_pow"
35
+ and f.children[1].name.startswith("d_")
36
+ and int(f.children[1].name[2:]) < 0
37
+ ):
38
+ n = int(f.children[1].name[2:])
39
+ den.append(
40
+ f.children[0]
41
+ if n == -1
42
+ else TreeNode("f_pow", [f.children[0], tree_form(f"d_{-n}")])
43
+ )
44
+ else:
45
+ num.append(f)
46
+ terms.append((num, den))
47
+
48
+ # pure reciprocal
49
+ elif (
50
+ c.name == "f_pow"
51
+ and c.children[1].name.startswith("d_")
52
+ and int(c.children[1].name[2:]) < 0
53
+ ):
54
+ n = int(c.children[1].name[2:])
55
+ terms.append(([], [
56
+ c.children[0]
57
+ if n == -1
58
+ else TreeNode("f_pow", [c.children[0], tree_form(f"d_{-n}")])
59
+ ]))
60
+
61
+ # normal term
62
+ else:
63
+ terms.append(([c], []))
64
+
65
+ # if no denominators → rebuild normally
66
+ if not any(den for _, den in terms):
67
+ return TreeNode("f_add", children)
68
+
69
+ # -----------------------------
70
+ # build numerator
71
+ # -----------------------------
72
+ num_terms = []
73
+ for i, (num_i, _) in enumerate(terms):
74
+ acc = list(num_i)
75
+ for j, (_, den_j) in enumerate(terms):
76
+ if i != j:
77
+ acc += den_j
78
+ if not acc:
79
+ acc = [tree_form("d_1")]
80
+ num_terms.append(
81
+ acc[0] if len(acc) == 1 else TreeNode("f_mul", acc)
82
+ )
83
+
84
+ numerator = TreeNode("f_add", num_terms)
85
+
86
+ # -----------------------------
87
+ # build denominator
88
+ # -----------------------------
89
+ den_all = []
90
+ for _, den in terms:
91
+ den_all += den
92
+
93
+ denom = den_all[0] if len(den_all) == 1 else TreeNode("f_mul", den_all)
94
+ denom = TreeNode("f_pow", [denom, tree_form("d_-1")])
95
+
96
+ return simplify(
97
+ TreeNode(
98
+ "f_mul",
99
+ [simplify(expand(numerator)), denom],
100
+ )
101
+ )
102
+
103
+ # -----------------------------
104
+ # default reconstruction
105
+ # -----------------------------
106
+ return TreeNode(expr.name, children)
@@ -97,6 +97,8 @@ def place_try2(eq):
97
97
  return eq.children[try_lst.pop(0)]
98
98
  return TreeNode(eq.name, [place_try2(child) for child in eq.children])
99
99
  def _solve_integrate(eq):
100
+ if eq is None:
101
+ return None
100
102
  if eq.name == "f_ref":
101
103
  return eq
102
104
  if eq.name == "f_subs":
@@ -153,14 +155,18 @@ def inteq(eq):
153
155
  else:
154
156
  return TreeNode(eq.name, [inteq(child) for child in eq.children])
155
157
  def rm(eq):
158
+ if eq is None:
159
+ return None
156
160
  if eq.name == "f_try":
157
161
  eq = TreeNode(eq.name, list(set(eq.children)))
158
162
  return TreeNode(eq.name, [rm(child) for child in eq.children if child is not None])
159
163
  def solve_integrate(eq):
160
164
 
161
165
  eq2 = dowhile(eq, _solve_integrate)
162
- eq2 = dowhile(eq2, handle_try)
166
+ #eq2 = dowhile(eq2, handle_try)
163
167
  eq2 = rm(eq2)
168
+ if eq2 is None:
169
+ return None
164
170
  if eq2.name == "f_try":
165
171
  eq2.children = list(set(eq2.children))
166
172
  return eq2
@@ -409,8 +415,8 @@ def integration_formula_ex():
409
415
 
410
416
  formula_gen11 = integration_formula_ex()
411
417
  def rm_const(equation):
412
- if equation.name == "f_ref":
413
- return equation
418
+ if equation is None:
419
+ return None
414
420
  eq2 = equation
415
421
  if eq2.name == "f_integrate" and contain(eq2.children[0], eq2.children[1]):
416
422
  equation = eq2.children[0]
@@ -436,8 +442,8 @@ def shorten(eq):
436
442
  return tree_form("d_0")
437
443
  return TreeNode(eq.name, [shorten(child) for child in eq.children])
438
444
  def integrate_formula(equation):
439
- if equation.name == "f_ref":
440
- return equation.copy_tree()
445
+ if equation is None:
446
+ return None
441
447
  eq2 = equation.copy_tree()
442
448
  if eq2.name == "f_integrate":
443
449
  integrand = eq2.children[0]
@@ -0,0 +1,326 @@
1
+ import itertools
2
+ from collections import Counter
3
+ from .diff import diff, diff2
4
+ from .factor import factor, factor2, term_common2
5
+ from .expand import expand
6
+ from .base import *
7
+ from .fraction import fraction
8
+ from .simplify import simplify
9
+ import copy
10
+ from .inverse import inverse
11
+ from .parser import parse
12
+
13
+ def rev(eq):
14
+ tmp = factor_generation(eq)
15
+ if tree_form("v_0").fx("dif")**-1 in tmp or tree_form("v_1").fx("dif")**-1 in tmp:
16
+ return False
17
+ for child in eq.children:
18
+ if not rev(child):
19
+ return False
20
+ return True
21
+ node_count = 100
22
+ def kkk(lhs, rhs, depth=5):
23
+ global node_count
24
+ lst = [simplify(lhs), simplify(rhs)]
25
+ orig = copy.deepcopy(lst)
26
+ if not contain(lst[0], tree_form("v_1")) and not contain(lst[1], tree_form("v_0")):
27
+ if not contain(lst[0], tree_form("v_0")) and not contain(lst[1], tree_form("v_1")):
28
+ return lst, False
29
+ return lst, True
30
+ node_count -= 1
31
+
32
+ if depth < 0 or node_count < 0:
33
+ return lst, False
34
+ for j in range(2):
35
+ for i in range(2):
36
+ if lst[i].name in ["f_mul", "f_add"]:
37
+ for child in lst[i].children:
38
+ out = child
39
+ if j == 0:
40
+ if contain(out, tree_form(f"v_{i}")) or not contain(out, tree_form(f"v_{1-i}")):
41
+ continue
42
+ if contain(out, tree_form(f"v_{i}")) and not contain(out, tree_form(f"v_{1-i}")):
43
+ continue
44
+
45
+ if lst[i].name == "f_add":
46
+ lst[i] = lst[i] - out
47
+ lst[1-i] = lst[1-i] - out
48
+ elif lst[i].name == "f_mul":
49
+ lst[i] = lst[i] / out
50
+ lst[1-i] = lst[1-i] / out
51
+ else:
52
+ continue
53
+
54
+ output = kkk(lst[0], lst[1], depth-1)
55
+ lst = orig
56
+
57
+ if output[1]:
58
+ return output
59
+
60
+ return lst, False
61
+ def clr(eq):
62
+ return simplify(product([item for item in factor_generation(eq) if "f_add" in str_form(item)]))
63
+ def inversediff(lhs, rhs):
64
+ global node_count
65
+ eq = simplify(fraction(TreeNode("f_eq", [lhs-rhs, tree_form("d_0")]))).children[0]
66
+ eq = simplify(term_common2(eq))
67
+ eq = clr(eq)
68
+
69
+ out= None
70
+ if eq.name == "f_add":
71
+ h = {}
72
+ n = [eq]
73
+ for i in range(len(eq.children)-2,1,-1):
74
+ for item in itertools.combinations(list(range(len(eq.children))), i):
75
+ item = tuple(sorted(list(item)))
76
+ tmp = simplify(term_common2(simplify(summation([eq.children[x] for x in item]))))
77
+ if tmp.name == "f_mul":
78
+ h[item] = tmp
79
+
80
+ for item in itertools.combinations(list(h.keys()),2):
81
+
82
+ g = []
83
+ for x in item:
84
+ g += x
85
+ if sum([len(x) for x in item]) == len(set(g)):
86
+ pass
87
+ else:
88
+ continue
89
+
90
+ item2 = summation([eq.children[x] for x in list(set(range(len(eq.children)))-set(g))])
91
+ n.append(simplify(term_common2(simplify(h[item[0]] + h[item[1]]))+item2))
92
+
93
+
94
+ for item in list(set(n)):
95
+
96
+ item = clr(item)
97
+ node_count = 100
98
+
99
+ tmp = kkk(item, tree_form("d_0"))
100
+
101
+ if tmp[1]:
102
+ out = tmp[0]
103
+ break
104
+ else:
105
+ node_count = 100
106
+ tmp = kkk(eq, tree_form("d_0"))
107
+ if tmp[1]:
108
+ out = tmp[0]
109
+ if out is None:
110
+ return None
111
+ out = [simplify(fraction(item)) for item in out]
112
+
113
+ if not rev(out[0]) and not rev(out[1]):
114
+
115
+ out[0] = fraction(1/out[0])
116
+ out[1] = fraction(1/out[1])
117
+ return simplify(e0(out[0]-out[1]))
118
+
119
+ def allocvar():
120
+ return tree_form("v_101")
121
+
122
+ def epowersplit(eq):
123
+ if eq.name == "f_pow" and eq.children[1].name == "f_add":
124
+ return product([eq.children[0]**child for child in eq.children[1].children])
125
+ return TreeNode(eq.name, [epowersplit(child) for child in eq.children])
126
+ def esolve(s):
127
+ if s.name == "f_add" and "f_log" in str_form(s):
128
+ return product([tree_form("s_e")**child for child in s.children]) - tree_form("d_1")
129
+ return TreeNode(s.name, [esolve(child) for child in s.children])
130
+ def diffsolve_sep2(eq):
131
+ lst = None
132
+ if eq is None:
133
+ return None
134
+ eq = eq.children[0]
135
+ if eq.name == "f_add":
136
+ lst = list(eq.children)
137
+ else:
138
+ lst = [eq]
139
+ s = [allocvar()]
140
+
141
+ for item in lst:
142
+ item = simplify(item)
143
+ tmp = factor_generation(item)
144
+
145
+ tmp2 = product([k for k in tmp if k.name != "f_dif"])
146
+
147
+ if tree_form("v_0").fx("dif") in tmp:
148
+ s.append(TreeNode("f_integrate", [tmp2, tree_form("v_0")]))
149
+ elif tree_form("v_1").fx("dif") in tmp:
150
+ s.append(TreeNode("f_integrate", [tmp2, tree_form("v_1")]))
151
+
152
+ return TreeNode("f_eq", [summation(s), tree_form("d_0")])
153
+ def e0(eq):
154
+ return TreeNode("f_eq", [eq, tree_form("d_0")])
155
+ def e1(eq):
156
+ if eq.name == "f_eq":
157
+ eq = eq.children[0]
158
+ return eq
159
+ def groupe(eq):
160
+ eq = esolve(eq)
161
+ eq = simplify(eq)
162
+ eq = fraction(eq)
163
+ eq = simplify(eq)
164
+ eq = epowersplit(eq)
165
+ return eq
166
+
167
+ def diffsolve_sep(eq):
168
+ eq = epowersplit(eq)
169
+
170
+ eq = inversediff(tree_form("d_0"), eq.children[0].copy_tree())
171
+
172
+ return eq
173
+
174
+ def diffsolve(eq):
175
+ orig = eq.copy_tree()
176
+ eq = diff2(eq)
177
+ eq = subs2(eq, order(eq))
178
+ eq = fraction(simplify(fraction(eq)))
179
+
180
+ if order(eq) == 2:
181
+ for i in range(2):
182
+ out = second_order_dif(eq, tree_form(f"v_{i}"), tree_form(f"v_{1-i}"))
183
+ if out is not None:
184
+ return out
185
+ return orig
186
+
187
+ eq = diffsolve_sep2(diffsolve_sep(eq))
188
+
189
+ if eq is None:
190
+ for i in range(2):
191
+ a = tree_form(f"v_{i}")
192
+ b = tree_form(f"v_{1-i}")
193
+ c = tree_form("v_2")
194
+ eq2 = orig
195
+
196
+ eq2 = subs2(eq2, 1)
197
+ eq2 = replace(eq2, b, b*a)
198
+ eq2 = subs3(eq2)
199
+
200
+ eq2 = simplify(fraction(simplify(eq2)))
201
+
202
+ eq2 = diffsolve_sep(eq2)
203
+
204
+ eq2 = diffsolve_sep2(eq2)
205
+ if eq2 is not None:
206
+ return e0(TreeNode("f_subs", [replace(eq2.children[0],b,c), c,b/a]).fx("try"))
207
+ eq = orig
208
+ eq = simplify(eq)
209
+ eq = subs2(eq, 1)
210
+ eq = fraction(eq)
211
+ for i in range(2):
212
+
213
+ out = linear_dif(eq, tree_form(f"v_{i}"), tree_form(f"v_{1-i}"))
214
+ if out is not None:
215
+ return out
216
+ return orig
217
+ else:
218
+ return eq
219
+
220
+ def clist(x):
221
+ return list(x.elements())
222
+ def collect_term(eq, term_lst):
223
+
224
+ lst = None
225
+ if eq.name == "f_add":
226
+ lst = copy.deepcopy(eq.children)
227
+ else:
228
+ lst = [eq]
229
+
230
+ other = []
231
+ dic = {}
232
+ term_lst = list(sorted(term_lst, key=lambda x: -len(factor_generation(x))))
233
+ for item in term_lst:
234
+ dic[item] = tree_form("d_0")
235
+ for item2 in lst:
236
+ done = True
237
+ tmp2 = Counter(factor_generation(item2))
238
+ for index, item in enumerate(term_lst):
239
+
240
+ tmp = Counter(factor_generation(item))
241
+
242
+ if (tmp2&tmp) == tmp:
243
+ if item in dic.keys():
244
+
245
+ dic[item] += product(clist(tmp2-tmp))
246
+ else:
247
+
248
+ dic[item] = product(clist(tmp2-tmp))
249
+ done = False
250
+ break
251
+ if done:
252
+ other.append(item2)
253
+ other = summation(other)
254
+
255
+ for key in dic.keys():
256
+ dic[key] = simplify(dic[key])
257
+ return [dic, simplify(other)]
258
+ def order(eq,m=0):
259
+ best = m
260
+ if eq.name in ["f_pdif", "f_dif"]:
261
+ out = order(eq.children[0], m+1)
262
+ best = max(out, best)
263
+ else:
264
+ for child in eq.children:
265
+ out = order(child, m)
266
+ best = max(out, best)
267
+ return best
268
+ def subs2(eq, orde):
269
+ if eq.name in ["f_dif", "f_pdif"] and len(eq.children) == 2:
270
+ if orde == 1:
271
+ return eq.children[0].fx("dif")/eq.children[1].fx("dif")
272
+ else:
273
+ return subs2(TreeNode("f_dif", eq.children), orde)
274
+ return TreeNode(eq.name, [subs2(child, orde) for child in eq.children])
275
+ def subs3(eq):
276
+ if eq.name == "f_dif" and eq.children[0].name == "f_add":
277
+ return summation([subs3(child.fx("dif")) for child in eq.children[0].children])
278
+ if eq.name == "f_dif" and eq.children[0].name == "f_mul":
279
+ return summation([product([subs3(child.fx("dif")) if index==index2 else child for index2, child in enumerate(eq.children[0].children)]) for index in range(len(eq.children[0].children))])
280
+ return TreeNode(eq.name, [subs3(child) for child in eq.children])
281
+ def second_order_dif(eq, a, b):
282
+ eq = simplify(eq)
283
+ nn = [TreeNode("f_dif", [TreeNode("f_dif", [b,a]),a]), TreeNode("f_dif", [b,a]), b]
284
+ out = collect_term(eq.children[0], nn)
285
+ if out[1] == tree_form("d_0"):
286
+ tmp = out[0][nn[0]]
287
+ if tmp != tree_form("d_0"):
288
+ for key in out[0].keys():
289
+ out[0][key] = simplify(out[0][key]/tmp)
290
+
291
+ B = out[0][nn[1]]
292
+ C = out[0][nn[2]]
293
+
294
+ if all(all(not contain(item, item2) for item2 in [a,b]) for item in [B, C]):
295
+ r = parse("r")
296
+ s = simplify(factor2(simplify(TreeNode("f_eq", [r**2 + B*r + C, tree_form("d_0")])), True))
297
+ r1, r2 = [inverse(item, r.name) for item in s.children[0].children]
298
+ out = None
299
+ if contain(r1, tree_form("s_i")):
300
+ real = simplify(fraction((r1+r2)/tree_form("d_2")))
301
+ imagine = simplify((r1-real)/tree_form("s_i"))
302
+ out = tree_form("s_e")**(real*a)*(tree_form("v_101")*(imagine*a).fx("cos")+tree_form("v_102")*(imagine*a).fx("sin"))
303
+ elif fraction(simplify(r1-r2)) == tree_form("d_0"):
304
+ out =(tree_form("v_101")+tree_form("v_102")*a)*tree_form("s_e")**(r1*a)
305
+ else:
306
+ out = tree_form("v_101")*tree_form("s_e")**(r1*a) + tree_form("v_102")*tree_form("s_e")**(r2*a)
307
+ return TreeNode("f_eq", [b, out])
308
+ return None
309
+
310
+ def linear_dif(eq, a, b):
311
+ eq = simplify(eq)
312
+
313
+ out = collect_term(eq.children[0], [b.fx("dif"), b*a.fx("dif"), a.fx("dif")])
314
+
315
+ if out[1] == tree_form("d_0"):
316
+ tmp = out[0][b.fx("dif")]
317
+ if tmp != tree_form("d_0"):
318
+
319
+ for key in out[0].keys():
320
+ out[0][key] = simplify(out[0][key]/tmp)
321
+ p, q = out[0][b*a.fx("dif")], -out[0][a.fx("dif")]
322
+ if contain(p, b) or contain(q, b):
323
+ return None
324
+ f = tree_form("s_e") ** TreeNode("f_integrate", [p, a])
325
+ return simplify(TreeNode("f_eq", [b*f, TreeNode("f_integrate", [q*f, a])+allocvar()]))
326
+ return None