mathai 2.5.0__tar.gz → 2.5.2__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-2.5.0 → mathai-2.5.2}/PKG-INFO +1 -1
- {mathai-2.5.0 → mathai-2.5.2}/mathai/__init__.py +1 -5
- {mathai-2.5.0 → mathai-2.5.2}/mathai/benchmark.py +1 -1
- {mathai-2.5.0 → mathai-2.5.2}/mathai/decision.py +1 -1
- mathai-2.5.2/mathai/factor.py +66 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/integrate.py +3 -5
- {mathai-2.5.0 → mathai-2.5.2}/mathai/linear.py +1 -1
- {mathai-2.5.0 → mathai-2.5.2}/mathai/logic.py +1 -1
- mathai-2.5.2/mathai/ode.py +302 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/pde.py +1 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/printeq.py +0 -1
- {mathai-2.5.0 → mathai-2.5.2}/mathai/trig.py +0 -1
- {mathai-2.5.0 → mathai-2.5.2}/mathai.egg-info/PKG-INFO +1 -1
- {mathai-2.5.0 → mathai-2.5.2}/setup.py +1 -1
- mathai-2.5.0/mathai/factor.py +0 -187
- mathai-2.5.0/mathai/ode.py +0 -296
- {mathai-2.5.0 → mathai-2.5.2}/README.md +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/apart.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/base.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/diff.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/electronic.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/expand.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/formula_applier.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/formula_compiler.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/fraction.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/graphics.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/inverse.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/lambda_calculus.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/limit.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/matrix.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/ml.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/mlscalar.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/ncert_data.txt +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/ncert_data_optimized.txt +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/parser.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/qm.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/simplify.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/square_root.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/statistics.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/test.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/tool.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai/univariate_inequality.py +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai.egg-info/SOURCES.txt +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai.egg-info/dependency_links.txt +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/mathai.egg-info/top_level.txt +0 -0
- {mathai-2.5.0 → mathai-2.5.2}/setup.cfg +0 -0
|
@@ -44,11 +44,7 @@ from .integrate import normalize as integration_basic
|
|
|
44
44
|
|
|
45
45
|
from .diff import diff, diff2
|
|
46
46
|
|
|
47
|
-
from .factor import
|
|
48
|
-
from .factor import factor2, take_common
|
|
49
|
-
from .factor import rationalize_sqrt as rationalize
|
|
50
|
-
from .factor import merge_sqrt
|
|
51
|
-
from .factor import factorconst as factor0
|
|
47
|
+
from .factor import factor0, factor1, factor2
|
|
52
48
|
|
|
53
49
|
from .fraction import fraction, fraction0
|
|
54
50
|
|
|
@@ -200,7 +200,7 @@ def execute_parallel(tree, equation, terminal_condition=None):
|
|
|
200
200
|
|
|
201
201
|
|
|
202
202
|
def god2(string, parallel=False):
|
|
203
|
-
tree = strategy_tree(load_sequences("
|
|
203
|
+
tree = strategy_tree(load_sequences("ncert_data_optimized"))
|
|
204
204
|
if parallel:
|
|
205
205
|
out = execute_parallel(tree, simplify(parse(string)), _no_integrate_left)
|
|
206
206
|
else:
|
|
@@ -11,7 +11,7 @@ from .univariate_inequality import simple_wavycurvy, wavycurvy, prepare, absolut
|
|
|
11
11
|
from .fraction import fraction
|
|
12
12
|
from .expand import expand
|
|
13
13
|
from .logic import logic0, set_sub, truth_gen, solve_logically
|
|
14
|
-
from .factor import factor2,
|
|
14
|
+
from .factor import factor2, factor1, factor0
|
|
15
15
|
from .limit import limit1, limit5
|
|
16
16
|
from .linear import linear_solve
|
|
17
17
|
from .matrix import matrix_solve, matrix_formula
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
|
|
2
|
+
import math
|
|
3
|
+
|
|
4
|
+
from .base import * # tree_form, TreeNode, str_form, factor_generation, product, summation, partitions ...
|
|
5
|
+
from .simplify import simplify
|
|
6
|
+
from .expand import expand # noqa: F401
|
|
7
|
+
from .formula_compiler import formula_list_compiler
|
|
8
|
+
|
|
9
|
+
# Kept so that `from .factor import *` in other modules keeps working.
|
|
10
|
+
from .parser import parse # noqa: F401
|
|
11
|
+
from .simplify import convert_to_basic # noqa: F401
|
|
12
|
+
from .tool import poly # noqa: F401
|
|
13
|
+
from .fraction import fraction
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
factor2 = formula_list_compiler("poly(x,a,b,c) a*(x-(-b+sqrt(b^2-4*a*c))/(2*a))*(x-(-b-sqrt(b^2-4*a*c))/(2*a)) [] _ _ b^2-4*a*c _")
|
|
17
|
+
factor1_s = """x^2-y^2 (x+y)*(x-y) [] _ _ _ _
|
|
18
|
+
x^3-y^3 (x-y)*(x^2+x*y+y^2) [] _ _ _ _
|
|
19
|
+
x^3+y^3 (x+y)*(x^2-x*y+y^2) [] _ _ _ _
|
|
20
|
+
x*y+a*y+x+a (x+a)*(y+1) [[a,1]] _ _ _ _
|
|
21
|
+
a*b+a*c a*(b+c) [[b,1]] _ _ _ _
|
|
22
|
+
a*b*c+a*b*d a*b*(c+d) [] _ _ _ _
|
|
23
|
+
a*x+b*x (a+b)*x [] _ _ _ _
|
|
24
|
+
a*x+a*y a*(x+y) [] _ _ _ _
|
|
25
|
+
a*c+a*d+b*c+b*d (a+b)*(c+d) [] _ _ _ _
|
|
26
|
+
x^2+2*a*x+a^2 (x+a)^2 [] _ _ _ _
|
|
27
|
+
x^2-2*a*x+a^2 (x-a)^2 [] _ _ _ _
|
|
28
|
+
a*b*c+a*d a*(b*c+d) [] _ _ _ _"""
|
|
29
|
+
factor1 = formula_list_compiler(factor1_s)
|
|
30
|
+
|
|
31
|
+
def _coeff(term):
|
|
32
|
+
"""Integer coefficient of a term (1 if none)."""
|
|
33
|
+
for item in factor_generation(term):
|
|
34
|
+
if item.name.startswith("d_"):
|
|
35
|
+
try:
|
|
36
|
+
return int(item.name[2:])
|
|
37
|
+
except ValueError:
|
|
38
|
+
return 1
|
|
39
|
+
return 1
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _hcf(numbers):
|
|
43
|
+
"""gcd of the coefficients; negative only if every coefficient is negative."""
|
|
44
|
+
g = 0
|
|
45
|
+
for x in numbers:
|
|
46
|
+
g = math.gcd(g, x)
|
|
47
|
+
if g == 0:
|
|
48
|
+
return 1
|
|
49
|
+
if numbers and all(x < 0 for x in numbers):
|
|
50
|
+
return -g
|
|
51
|
+
return g
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _factorconst(eq):
|
|
55
|
+
if not eq.children:
|
|
56
|
+
return eq
|
|
57
|
+
if eq.name == "f_add":
|
|
58
|
+
n = _hcf([_coeff(child) for child in eq.children])
|
|
59
|
+
if n != 1:
|
|
60
|
+
const = tree_form("d_" + str(n))
|
|
61
|
+
return const * TreeNode(eq.name, [child / const for child in eq.children])
|
|
62
|
+
return TreeNode(eq.name, [_factorconst(child) for child in eq.children])
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def factor0(eq):
|
|
66
|
+
return simplify(_factorconst(eq))
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
from .factor import factor2
|
|
2
|
-
from .factor import factorconst as factor0
|
|
3
|
-
from .factor import factor as factor1
|
|
1
|
+
from .factor import factor2, factor1, factor0
|
|
4
2
|
from .parser import parse
|
|
5
3
|
import itertools
|
|
6
4
|
from .diff import diff
|
|
@@ -289,14 +287,14 @@ def byparts(eq):
|
|
|
289
287
|
return TreeNode("f_try", output)
|
|
290
288
|
eq = eq2
|
|
291
289
|
return TreeNode(eq.name, [byparts(child) for child in eq.children])
|
|
292
|
-
|
|
293
290
|
integrate_fraction_s = """integrate(1/sqrt(poly(x,a,b,c)),x) 1/sqrt(a)*log(abs(sqrt(a)*x+b/(2*sqrt(a))+sqrt((sqrt(a)*x+b/(2*sqrt(a)))^2+(4*a*c-b^2)/(4*a)))) [] x [a,b,c] [a,4*a*c-b^2] _ [[a,0],[b^2-4*a*c,0]]
|
|
294
291
|
integrate(1/sqrt(poly(x,a,b,c)),x) 1/sqrt(a)*log(abs(sqrt(a)*x+b/(2*sqrt(a))+sqrt((sqrt(a)*x+b/(2*sqrt(a)))^2-(b^2-4*a*c)/(4*a)))) [] x [a,b,c] [a,b^2-4*a*c] _ [[a,0],[4*a*c-b^2,0]]
|
|
295
292
|
integrate(1/sqrt(poly(x,a,b,c)),x) 1/sqrt(-a)*arcsin((sqrt(-a)*x-b/(2*sqrt(-a)))/sqrt((4*a*c-b^2)/(4*a))) [] x [a,b,c] [4*a*c-b^2] a [[a,0],[b^2-4*a*c,0]]
|
|
296
293
|
integrate(1/poly(x,a,b,c),x) 1/(sqrt(a)*sqrt((4*a*c-b^2)/(4*a)))*arctan((sqrt(a)*x+b/(2*sqrt(a)))/sqrt((4*a*c-b^2)/(4*a))) [] x [a,b,c] [a,4*a*c-b^2] _ [[a,0],[b^2-4*a*c,0]]
|
|
297
|
-
integrate(1/poly(x,a,b,c),x) -1/(sqrt(-a)*sqrt((
|
|
294
|
+
integrate(1/poly(x,a,b,c),x) -1/(sqrt(-a)*sqrt((4*a*c-b^2)/(-4*a)))*arctan((sqrt(-a)*x-b/(2*sqrt(-a)))/sqrt((4*a*c-b^2)/(-4*a))) [] x [a,b,c] [4*a*c-b^2] a [[a,0],[b^2-4*a*c,0]]
|
|
298
295
|
integrate(poly(x,p,q)/sqrt(poly(x,a,b,c)),x) (p/a)*sqrt(a*x^2+b*x+c)+(q-p*b/(2*a))*integrate(1/sqrt(a*x^2+b*x+c),x) [] x [p,q,a,b,c] _ _ _ [[a,0]]
|
|
299
296
|
integrate(poly(x,p,q)/poly(x,a,b,c),x) (p/(2*a))*log(abs(a*x^2+b*x+c))+(q-p*b/(2*a))*integrate(1/(a*x^2+b*x+c),x) [] x [p,q,a,b,c] _ _ _ [[a,0]]"""
|
|
297
|
+
|
|
300
298
|
integrate_fraction = formula_list_compiler(integrate_fraction_s)
|
|
301
299
|
|
|
302
300
|
def_integrate_formula_s = """integrate(abs(poly(x,a,b)),x,m,n) ((a*n+b)*abs(a*n+b)-(a*m+b)*abs(a*m+b))/(2*a) [] x [a,b] _ _
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
from collections import Counter
|
|
2
|
+
|
|
3
|
+
from .base import * # tree_form, TreeNode, contain, replace, str_form, factor_generation, product, summation ...
|
|
4
|
+
from .factor import factor1, factor2 # factor1 = formula-list compiler (takes ONE expression, not a list)
|
|
5
|
+
from .fraction import fraction
|
|
6
|
+
from .simplify import simplify
|
|
7
|
+
from .inverse import inverse
|
|
8
|
+
from .parser import parse
|
|
9
|
+
|
|
10
|
+
# --------------------------------------------------------------------------- #
|
|
11
|
+
# Constants (built once)
|
|
12
|
+
# --------------------------------------------------------------------------- #
|
|
13
|
+
ZERO = tree_form("d_0")
|
|
14
|
+
ONE = tree_form("d_1")
|
|
15
|
+
TWO = tree_form("d_2")
|
|
16
|
+
NEG_ONE = tree_form("d_-1")
|
|
17
|
+
E = tree_form("s_e")
|
|
18
|
+
I = tree_form("s_i")
|
|
19
|
+
V0 = tree_form("v_0")
|
|
20
|
+
V1 = tree_form("v_1")
|
|
21
|
+
V2 = tree_form("v_2")
|
|
22
|
+
V = (V0, V1)
|
|
23
|
+
DIF0 = V0.fx("dif")
|
|
24
|
+
DIF1 = V1.fx("dif")
|
|
25
|
+
INV_DIF0 = DIF0 ** -1
|
|
26
|
+
INV_DIF1 = DIF1 ** -1
|
|
27
|
+
|
|
28
|
+
_MAX_DEPTH = 8 # bound on the shift/factor rewriting loop in inversediff
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# --------------------------------------------------------------------------- #
|
|
32
|
+
# Small helpers
|
|
33
|
+
# --------------------------------------------------------------------------- #
|
|
34
|
+
def _has_name(node, name):
|
|
35
|
+
return node.name == name or any(_has_name(c, name) for c in node.children)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _terms(eq):
|
|
39
|
+
return list(eq.children) if eq.name == "f_add" else [eq]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _expr(eq):
|
|
43
|
+
"""The 'expression = 0' side of an equation (or the expression itself)."""
|
|
44
|
+
if eq.name == "f_eq":
|
|
45
|
+
lhs, rhs = eq.children
|
|
46
|
+
return lhs if rhs == ZERO else lhs - rhs
|
|
47
|
+
return eq
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def allocvar():
|
|
51
|
+
return tree_form("v_101")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def clist(x):
|
|
55
|
+
return list(x.elements())
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def e0(eq):
|
|
59
|
+
return TreeNode("f_eq", [eq, ZERO])
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def e1(eq):
|
|
63
|
+
return eq.children[0] if eq.name == "f_eq" else eq
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# --------------------------------------------------------------------------- #
|
|
67
|
+
# Separation of variables
|
|
68
|
+
# --------------------------------------------------------------------------- #
|
|
69
|
+
def rev(eq):
|
|
70
|
+
factors = factor_generation(eq)
|
|
71
|
+
if INV_DIF0 in factors or INV_DIF1 in factors:
|
|
72
|
+
return False
|
|
73
|
+
return all(rev(child) for child in eq.children)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def check(eq):
|
|
77
|
+
"""False if some single factor mixes x and y."""
|
|
78
|
+
return not any(contain(f, V0) and contain(f, V1) for f in factor_generation(eq))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def shift(lhs, rhs):
|
|
82
|
+
"""Rearrange lhs + rhs = 0 into A(x) = B(y)-style sides; returns [new_lhs, new_rhs]."""
|
|
83
|
+
if isinstance(lhs, list):
|
|
84
|
+
lhs = simplify(summation(lhs))
|
|
85
|
+
if isinstance(rhs, list):
|
|
86
|
+
rhs = simplify(summation(rhs))
|
|
87
|
+
rhs = simplify(-rhs)
|
|
88
|
+
sides = [factor_generation(lhs), factor_generation(rhs)]
|
|
89
|
+
moved = [[], []] # moved[k] = factors that must be divided out of side k
|
|
90
|
+
for i in (0, 1):
|
|
91
|
+
stay = []
|
|
92
|
+
for f in sides[i]:
|
|
93
|
+
if contain(f, V[1 - i]) and not contain(f, V[i]):
|
|
94
|
+
moved[1 - i].append(f)
|
|
95
|
+
else:
|
|
96
|
+
stay.append(f)
|
|
97
|
+
sides[i] = stay
|
|
98
|
+
output = [simplify(product(sides[i]) * product(moved[i]) ** NEG_ONE) for i in (0, 1)]
|
|
99
|
+
if any(_has_name(item, "f_dif") for item in output) and DIF0 not in factor_generation(output[0]):
|
|
100
|
+
output = [ONE / item for item in output]
|
|
101
|
+
return output
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def inversediff(lhs, rhs, old=None):
|
|
105
|
+
if lhs is None or rhs is None:
|
|
106
|
+
return None
|
|
107
|
+
old = [] if old is None else old
|
|
108
|
+
if len(old) > _MAX_DEPTH:
|
|
109
|
+
return None
|
|
110
|
+
|
|
111
|
+
eq = factor1(simplify(lhs - rhs))
|
|
112
|
+
if eq in old: # already seen -> rewriting is looping
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
const, xonly, yonly, mixed = [], [], [], []
|
|
116
|
+
for item in _terms(eq):
|
|
117
|
+
cx, cy = contain(item, V0), contain(item, V1)
|
|
118
|
+
if cx and cy:
|
|
119
|
+
mixed.append(item)
|
|
120
|
+
elif cx:
|
|
121
|
+
xonly.append(item)
|
|
122
|
+
elif cy:
|
|
123
|
+
yonly.append(item)
|
|
124
|
+
else:
|
|
125
|
+
const.append(item)
|
|
126
|
+
(yonly if yonly else xonly).extend(const)
|
|
127
|
+
|
|
128
|
+
if not mixed:
|
|
129
|
+
return simplify(lhs - rhs) # already separated (unfactored form, so terms stay iterable)
|
|
130
|
+
|
|
131
|
+
m = factor1(summation(mixed)) # factor1 takes an expression, not a list
|
|
132
|
+
mixed = _terms(m)
|
|
133
|
+
nxt = old + [eq]
|
|
134
|
+
|
|
135
|
+
if xonly and yonly:
|
|
136
|
+
out = inversediff(*shift(mixed + xonly, yonly), nxt)
|
|
137
|
+
if out is None:
|
|
138
|
+
out = inversediff(*shift(xonly, factor1(summation(mixed + yonly))), nxt)
|
|
139
|
+
return out
|
|
140
|
+
if yonly:
|
|
141
|
+
if m.name == "f_add":
|
|
142
|
+
return None
|
|
143
|
+
return inversediff(*shift(m, yonly), nxt)
|
|
144
|
+
if xonly:
|
|
145
|
+
if m.name == "f_add":
|
|
146
|
+
return None
|
|
147
|
+
return inversediff(*shift(xonly, m), nxt)
|
|
148
|
+
if len(mixed) == 2:
|
|
149
|
+
return inversediff(*shift(*mixed), nxt)
|
|
150
|
+
return None
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def epowersplit(eq):
|
|
154
|
+
if not eq.children:
|
|
155
|
+
return eq
|
|
156
|
+
if eq.name == "f_pow" and eq.children[1].name == "f_add":
|
|
157
|
+
return product([eq.children[0] ** child for child in eq.children[1].children])
|
|
158
|
+
return TreeNode(eq.name, [epowersplit(child) for child in eq.children])
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def esolve(s):
|
|
162
|
+
if not s.children:
|
|
163
|
+
return s
|
|
164
|
+
if s.name == "f_add" and _has_name(s, "f_log"):
|
|
165
|
+
return product([E ** child for child in s.children]) - ONE
|
|
166
|
+
return TreeNode(s.name, [esolve(child) for child in s.children])
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def groupe(eq):
|
|
170
|
+
eq = simplify(esolve(eq))
|
|
171
|
+
eq = simplify(fraction(eq))
|
|
172
|
+
return epowersplit(eq)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def diffsolve_sep(eq):
|
|
176
|
+
expr = e1(epowersplit(eq))
|
|
177
|
+
return inversediff(ZERO, expr.copy_tree())
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def diffsolve_sep2(eq):
|
|
181
|
+
"""Integrate a separated form f(x)dx + g(y)dy term by term."""
|
|
182
|
+
if eq is None:
|
|
183
|
+
return None
|
|
184
|
+
parts = [allocvar()]
|
|
185
|
+
for item in _terms(eq):
|
|
186
|
+
factors = factor_generation(simplify(item))
|
|
187
|
+
rest = product([k for k in factors if k.name != "f_dif"])
|
|
188
|
+
if DIF0 in factors:
|
|
189
|
+
parts.append(TreeNode("f_integrate", [rest, V0]))
|
|
190
|
+
elif DIF1 in factors:
|
|
191
|
+
parts.append(TreeNode("f_integrate", [rest, V1]))
|
|
192
|
+
else:
|
|
193
|
+
return None # a term with no differential cannot be integrated (was silently dropped)
|
|
194
|
+
return TreeNode("f_eq", [summation(parts), ZERO])
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
# --------------------------------------------------------------------------- #
|
|
198
|
+
# Derivative bookkeeping
|
|
199
|
+
# --------------------------------------------------------------------------- #
|
|
200
|
+
def order(eq, m=0):
|
|
201
|
+
if eq.name in ("f_pdif", "f_dif"):
|
|
202
|
+
return order(eq.children[0], m + 1)
|
|
203
|
+
return max([m] + [order(child, m) for child in eq.children])
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def subs2(eq, orde):
|
|
207
|
+
if not eq.children:
|
|
208
|
+
return eq
|
|
209
|
+
if eq.name in ("f_dif", "f_pdif") and len(eq.children) == 2:
|
|
210
|
+
if orde == 1:
|
|
211
|
+
return eq.children[0].fx("dif") / eq.children[1].fx("dif")
|
|
212
|
+
return eq
|
|
213
|
+
return TreeNode(eq.name, [subs2(child, orde) for child in eq.children])
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def subs3(eq):
|
|
217
|
+
"""Push dif through sums and products (sum / product rule)."""
|
|
218
|
+
if not eq.children:
|
|
219
|
+
return eq
|
|
220
|
+
if eq.name == "f_dif":
|
|
221
|
+
inner = eq.children[0]
|
|
222
|
+
if inner.name == "f_add":
|
|
223
|
+
return summation([subs3(c.fx("dif")) for c in inner.children])
|
|
224
|
+
if inner.name == "f_mul":
|
|
225
|
+
kids = inner.children
|
|
226
|
+
return summation([
|
|
227
|
+
product([subs3(c.fx("dif")) if i == j else c for j, c in enumerate(kids)])
|
|
228
|
+
for i in range(len(kids))
|
|
229
|
+
])
|
|
230
|
+
return TreeNode(eq.name, [subs3(child) for child in eq.children])
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
# --------------------------------------------------------------------------- #
|
|
234
|
+
# Coefficient collection
|
|
235
|
+
# --------------------------------------------------------------------------- #
|
|
236
|
+
def collect_term(eq, term_lst):
|
|
237
|
+
"""Split eq into sum(coef[t] * t for t in term_lst) + other. Returns [coef_dict, other]."""
|
|
238
|
+
ordered = sorted(term_lst, key=lambda x: -len(factor_generation(x))) # most specific first
|
|
239
|
+
counters = [(t, Counter(factor_generation(t))) for t in ordered] # built once, not per term
|
|
240
|
+
parts = {t: [] for t, _ in counters}
|
|
241
|
+
other = []
|
|
242
|
+
for term in _terms(eq):
|
|
243
|
+
tc = Counter(factor_generation(term))
|
|
244
|
+
for t, c in counters:
|
|
245
|
+
if (tc & c) == c:
|
|
246
|
+
parts[t].append(product(clist(tc - c)))
|
|
247
|
+
break
|
|
248
|
+
else:
|
|
249
|
+
other.append(term)
|
|
250
|
+
coef = {t: (simplify(summation(p)) if p else ZERO) for t, p in parts.items()}
|
|
251
|
+
return [coef, simplify(summation(other)) if other else ZERO]
|
|
252
|
+
|
|
253
|
+
def linear_dif(eq, a, b):
|
|
254
|
+
"""db + p*b*da - q*da = 0 -> integrating-factor solution."""
|
|
255
|
+
eq = simplify(eq)
|
|
256
|
+
db, da = b.fx("dif"), a.fx("dif")
|
|
257
|
+
bda = b * da
|
|
258
|
+
coef, other = collect_term(_expr(eq), [db, bda, da])
|
|
259
|
+
if other != ZERO:
|
|
260
|
+
return None
|
|
261
|
+
lead = coef[db]
|
|
262
|
+
if lead == ZERO:
|
|
263
|
+
return None
|
|
264
|
+
p = simplify(coef[bda] / lead)
|
|
265
|
+
q = simplify(-(coef[da] / lead))
|
|
266
|
+
if contain(p, b) or contain(q, b):
|
|
267
|
+
return None
|
|
268
|
+
f = E ** TreeNode("f_integrate", [p, a])
|
|
269
|
+
return simplify(TreeNode("f_eq", [b * f, TreeNode("f_integrate", [q * f, a]) + allocvar()]))
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def diffsolve(eq):
|
|
273
|
+
orig = eq.copy_tree()
|
|
274
|
+
eq = subs2(eq, order(eq))
|
|
275
|
+
eq = fraction(simplify(fraction(eq)))
|
|
276
|
+
n = order(eq)
|
|
277
|
+
|
|
278
|
+
if n != 1: # only first order are handled
|
|
279
|
+
return orig
|
|
280
|
+
|
|
281
|
+
# 1) directly separable
|
|
282
|
+
sol = diffsolve_sep2(diffsolve_sep(eq))
|
|
283
|
+
if sol is not None:
|
|
284
|
+
return sol
|
|
285
|
+
|
|
286
|
+
# 2) homogeneous: substitute b = b*a, separate, substitute back
|
|
287
|
+
first = subs2(orig, 1) # same for both loop iterations
|
|
288
|
+
for i in (0, 1):
|
|
289
|
+
a, b = V[i], V[1 - i]
|
|
290
|
+
eq2 = subs3(replace(first, b, b * a))
|
|
291
|
+
eq2 = simplify(fraction(simplify(eq2)))
|
|
292
|
+
eq2 = diffsolve_sep2(diffsolve_sep(eq2))
|
|
293
|
+
if eq2 is not None:
|
|
294
|
+
return e0(TreeNode("f_subs", [replace(eq2.children[0], b, V2), V2, b / a]).fx("try"))
|
|
295
|
+
|
|
296
|
+
# 3) linear first order
|
|
297
|
+
eq = fraction(subs2(simplify(orig), 1))
|
|
298
|
+
for i in (0, 1):
|
|
299
|
+
out = linear_dif(eq, V[i], V[1 - i])
|
|
300
|
+
if out is not None:
|
|
301
|
+
return out
|
|
302
|
+
return orig
|
|
@@ -4,6 +4,7 @@ from .ode import diffsolve as ode_solve
|
|
|
4
4
|
from .integrate import integrate_formula
|
|
5
5
|
from .simplify import simplify
|
|
6
6
|
from .formula_applier import formula_applier
|
|
7
|
+
from .formula_compiler import formula_list_compiler
|
|
7
8
|
|
|
8
9
|
pde_character_s = """a*pdif(u,x)+b*pdif(u,y)+c=0 list(dif(x,y)=a/b,dif(u,x)=-c/a,dif(u,y)=-c/b,u) [[c,0],[a,1],[b,1]] [u,x,y] _ _ _"""
|
|
9
10
|
pde_character = lambda x: formula_applier(x, pde_character_s)
|
|
@@ -7,7 +7,6 @@ from .base import *
|
|
|
7
7
|
from .expand import expand
|
|
8
8
|
from .parser import parse
|
|
9
9
|
from .fraction import fraction
|
|
10
|
-
from .factor import rationalize_sqrt
|
|
11
10
|
from .inverse import inverse
|
|
12
11
|
from .formula_compiler import formula_list_compiler
|
|
13
12
|
from .univariate_inequality import simple_wavycurvy, eq2range, Range, range2eq2
|
|
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
|
|
|
3
3
|
|
|
4
4
|
setup(
|
|
5
5
|
name="mathai",
|
|
6
|
-
version="2.5.
|
|
6
|
+
version="2.5.2",
|
|
7
7
|
description="Mathematics solving Ai tailored to NCERT",
|
|
8
8
|
long_description=Path("README.md").read_text(encoding="utf-8"),
|
|
9
9
|
long_description_content_type="text/markdown",
|
mathai-2.5.0/mathai/factor.py
DELETED
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import itertools
|
|
2
|
-
from .parser import parse
|
|
3
|
-
from .base import *
|
|
4
|
-
from .simplify import simplify, convert_to_basic
|
|
5
|
-
from .expand import expand
|
|
6
|
-
import math
|
|
7
|
-
from .tool import poly
|
|
8
|
-
from .fraction import fraction
|
|
9
|
-
from collections import Counter
|
|
10
|
-
from .formula_compiler import formula_list_compiler
|
|
11
|
-
|
|
12
|
-
factor2 = formula_list_compiler("poly(x,a,b,c) a*(x-(-b+sqrt(b^2-4*a*c))/(2*a))*(x-(-b-sqrt(b^2-4*a*c))/(2*a)) [] _ _ b^2-4*a*c _")
|
|
13
|
-
def multiset_intersection(*lists):
|
|
14
|
-
counters = list(map(Counter, lists))
|
|
15
|
-
common = counters[0]
|
|
16
|
-
for c in counters[1:]:
|
|
17
|
-
common = common & c
|
|
18
|
-
return list(common.elements())
|
|
19
|
-
def subtract_sublist(full_list, sublist):
|
|
20
|
-
c_full = Counter(full_list)
|
|
21
|
-
c_sub = Counter(sublist)
|
|
22
|
-
result = c_full - c_sub
|
|
23
|
-
tmp = list(result.elements())
|
|
24
|
-
if tmp == []:
|
|
25
|
-
return [tree_form("d_1")]
|
|
26
|
-
return tmp
|
|
27
|
-
def term_common2(lst, take_neg_common=False):
|
|
28
|
-
s = []
|
|
29
|
-
arr = [factor_generation(child,True) for child in lst]
|
|
30
|
-
if take_neg_common and not all(tree_form("d_-1") not in item for item in arr):
|
|
31
|
-
arr = [item+[tree_form("d_-1"), tree_form("d_-1")] if tree_form("d_-1") not in item else item for item in arr]
|
|
32
|
-
s = multiset_intersection(*arr)
|
|
33
|
-
if s == []:
|
|
34
|
-
return simplify(summation(lst))
|
|
35
|
-
arr = [subtract_sublist(item, s) for item in arr]
|
|
36
|
-
return simplify(product(s)*summation([product(item) for item in arr]))
|
|
37
|
-
def take_common(eq):
|
|
38
|
-
score = []
|
|
39
|
-
output = []
|
|
40
|
-
def helper(eq, depth=0):
|
|
41
|
-
nonlocal score
|
|
42
|
-
nonlocal output
|
|
43
|
-
key = tuple(sorted(eq,key=lambda x: str_form(x)))
|
|
44
|
-
if key in output:
|
|
45
|
-
return
|
|
46
|
-
else:
|
|
47
|
-
score.append(depth)
|
|
48
|
-
output.append(key)
|
|
49
|
-
for item3 in partitions(eq):
|
|
50
|
-
for option in [False, True]:
|
|
51
|
-
item = [term_common2(item2, option) for item2 in item3]
|
|
52
|
-
helper(item, depth+1)
|
|
53
|
-
if eq.name == "f_add":
|
|
54
|
-
helper(eq.children)
|
|
55
|
-
else:
|
|
56
|
-
return [eq]
|
|
57
|
-
sc = {}
|
|
58
|
-
for i in range(len(output)):
|
|
59
|
-
output[i] = simplify(summation(list(output[i])))
|
|
60
|
-
sc[output[i]] = score[i]
|
|
61
|
-
output = list(set(output))
|
|
62
|
-
return list(sorted(output, key=lambda x: -sc[x]))
|
|
63
|
-
def _factorconst(eq):
|
|
64
|
-
def hcf_list(numbers):
|
|
65
|
-
if not numbers:
|
|
66
|
-
return None
|
|
67
|
-
n = 1
|
|
68
|
-
if math.prod(numbers) < 0:
|
|
69
|
-
n = -1
|
|
70
|
-
hcf = numbers[0]
|
|
71
|
-
for num in numbers[1:]:
|
|
72
|
-
hcf = math.gcd(hcf, abs(num))
|
|
73
|
-
return hcf*n
|
|
74
|
-
def extractnum(eq):
|
|
75
|
-
lst = factor_generation(eq)
|
|
76
|
-
for item in lst:
|
|
77
|
-
if item.name[:2] == "d_":
|
|
78
|
-
return int(item.name[2:])
|
|
79
|
-
return 1
|
|
80
|
-
n = 1
|
|
81
|
-
if eq.name == "f_add":
|
|
82
|
-
n = hcf_list([extractnum(child) for child in eq.children])
|
|
83
|
-
eq = TreeNode(eq.name, [child/tree_form("d_"+str(n)) for child in eq.children])
|
|
84
|
-
if n != 1:
|
|
85
|
-
return tree_form("d_"+str(n))*eq
|
|
86
|
-
return TreeNode(eq.name, [factorconst(child) for child in eq.children])
|
|
87
|
-
def _merge_sqrt(eq):
|
|
88
|
-
lst= []
|
|
89
|
-
eq2 = []
|
|
90
|
-
for child in factor_generation(eq):
|
|
91
|
-
if frac(child) is not None and frac(child).denominator==1:
|
|
92
|
-
if frac(child)>0:
|
|
93
|
-
eq2.append(child**2)
|
|
94
|
-
elif frac(child)!=-1:
|
|
95
|
-
eq2.append((-child)**2)
|
|
96
|
-
lst.append(tree_form("d_-1"))
|
|
97
|
-
else:
|
|
98
|
-
lst.append(tree_form("d_-1"))
|
|
99
|
-
elif child.name == "f_pow" and frac(child.children[1]) == Fraction(1,2):
|
|
100
|
-
eq2.append(child.children[0])
|
|
101
|
-
else:
|
|
102
|
-
lst.append(child)
|
|
103
|
-
if len(eq2)>1:
|
|
104
|
-
if lst == []:
|
|
105
|
-
lst= [tree_form("d_1")]
|
|
106
|
-
return simplify(product(eq2)**(tree_form("d_2")**-1)*product(lst))
|
|
107
|
-
return TreeNode(eq.name, [_merge_sqrt(child) for child in eq.children])
|
|
108
|
-
def sqrt_to_a_sqrt_b(n):
|
|
109
|
-
if n == 0:
|
|
110
|
-
return 0, 0
|
|
111
|
-
sign = 1
|
|
112
|
-
if n < 0:
|
|
113
|
-
sign = -1
|
|
114
|
-
m = -n
|
|
115
|
-
else:
|
|
116
|
-
m = n
|
|
117
|
-
a = 1
|
|
118
|
-
b = 1
|
|
119
|
-
p = 2
|
|
120
|
-
while p * p <= m:
|
|
121
|
-
exp = 0
|
|
122
|
-
while m % p == 0:
|
|
123
|
-
m //= p
|
|
124
|
-
exp += 1
|
|
125
|
-
if exp:
|
|
126
|
-
a *= p ** (exp // 2)
|
|
127
|
-
if exp % 2 == 1:
|
|
128
|
-
b *= p
|
|
129
|
-
p += 1 if p == 2 else 2
|
|
130
|
-
if m > 1:
|
|
131
|
-
b *= m
|
|
132
|
-
return sign * a, b
|
|
133
|
-
def merge_sqrt(eq):
|
|
134
|
-
def helper(eq):
|
|
135
|
-
if eq.name == "f_pow" and frac(eq.children[1]) == Fraction(1,2):
|
|
136
|
-
if eq.children[0].name[:2] == "d_":
|
|
137
|
-
n = int(eq.children[0].name[2:])
|
|
138
|
-
a, b =sqrt_to_a_sqrt_b(n)
|
|
139
|
-
return tree_form("d_"+str(b))**(tree_form("d_2")**-1)*tree_form("d_"+str(a))
|
|
140
|
-
if eq.name == "f_pow" and frac(eq.children[1]) == Fraction(-1,2):
|
|
141
|
-
if frac(eq.children[0]) is not None:
|
|
142
|
-
out = frac(eq.children[0])
|
|
143
|
-
b, a = [tree_form("d_"+str(x)) for x in [out.numerator, out.denominator]]
|
|
144
|
-
return a**(tree_form("d_2")**-1)/b**(tree_form("d_2")**-1)
|
|
145
|
-
return TreeNode(eq.name, [helper(child) for child in eq.children])
|
|
146
|
-
return helper(_merge_sqrt(eq))
|
|
147
|
-
def rationalize_sqrt(eq):
|
|
148
|
-
if eq.name== "f_pow" and frac(eq.children[1]) == Fraction(-1,2):
|
|
149
|
-
eq = eq.children[0]**(tree_form("d_2")**-1)/eq.children[0]
|
|
150
|
-
def term(eq):
|
|
151
|
-
if eq.name == "f_add":
|
|
152
|
-
output = []
|
|
153
|
-
for child in eq.children:
|
|
154
|
-
if any(child2.name == "f_pow" and frac(child2.children[1]) == Fraction(1,2) for child2 in factor_generation(child)):
|
|
155
|
-
output.append(simplify(-child))
|
|
156
|
-
else:
|
|
157
|
-
output.append(child)
|
|
158
|
-
return summation(output)
|
|
159
|
-
return None
|
|
160
|
-
n, d=num_dem(eq)
|
|
161
|
-
n,d=simplify(n), simplify(d)
|
|
162
|
-
if d != 1:
|
|
163
|
-
t = term(d)
|
|
164
|
-
if t is not None and t!=1:
|
|
165
|
-
n,d=simplify(expand(simplify(n*t))),simplify(expand(simplify(d*t)))
|
|
166
|
-
tmp= simplify(n/d)
|
|
167
|
-
tmp = _merge_sqrt(tmp)
|
|
168
|
-
return tmp
|
|
169
|
-
return TreeNode(eq.name, [rationalize_sqrt(child) for child in eq.children])
|
|
170
|
-
def factorconst(eq):
|
|
171
|
-
return simplify(_factorconst(eq))
|
|
172
|
-
def max_depth(node):
|
|
173
|
-
if node is None:
|
|
174
|
-
return 0
|
|
175
|
-
if not node.children:
|
|
176
|
-
return 1
|
|
177
|
-
return 1 + max(max_depth(child) for child in node.children)
|
|
178
|
-
def factor(equation):
|
|
179
|
-
if equation.name == "f_add":
|
|
180
|
-
lst = take_common(equation)
|
|
181
|
-
lst3 = lst
|
|
182
|
-
mx = min([len(item.children) for item in lst3])
|
|
183
|
-
lst3 = [item for item in lst3 if len(item.children)==mx]
|
|
184
|
-
tmp = max(lst3, key=lambda x: -max_depth(x))
|
|
185
|
-
if equation != tmp:
|
|
186
|
-
return tmp
|
|
187
|
-
return TreeNode(equation.name, [factor(child) for child in equation.children])
|
mathai-2.5.0/mathai/ode.py
DELETED
|
@@ -1,296 +0,0 @@
|
|
|
1
|
-
import itertools
|
|
2
|
-
from collections import Counter
|
|
3
|
-
from .diff import diff
|
|
4
|
-
from .factor import factor, factor2, take_common, 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
|
-
def rev(eq):
|
|
13
|
-
tmp = factor_generation(eq)
|
|
14
|
-
if tree_form("v_0").fx("dif")**-1 in tmp or tree_form("v_1").fx("dif")**-1 in tmp:
|
|
15
|
-
return False
|
|
16
|
-
for child in eq.children:
|
|
17
|
-
if not rev(child):
|
|
18
|
-
return False
|
|
19
|
-
return True
|
|
20
|
-
def clr(eq):
|
|
21
|
-
return simplify(product([item for item in factor_generation(eq) if "f_add" in str_form(item)]))
|
|
22
|
-
def tt(eq):
|
|
23
|
-
if eq.name == "f_add":
|
|
24
|
-
return term_common2(eq.children)
|
|
25
|
-
return eq
|
|
26
|
-
def shift(lhs, rhs):
|
|
27
|
-
if isinstance(lhs, list):
|
|
28
|
-
lhs = simplify(summation(lhs))
|
|
29
|
-
if isinstance(rhs, list):
|
|
30
|
-
rhs = simplify(summation(rhs))
|
|
31
|
-
rhs = simplify(-rhs)
|
|
32
|
-
out2 = [factor_generation(lhs), factor_generation(rhs)]
|
|
33
|
-
out = [[], []]
|
|
34
|
-
for i in range(2):
|
|
35
|
-
for j in range(len(out2[i])-1,-1,-1):
|
|
36
|
-
if contain(out2[i][j], tree_form(f"v_{1-i}")) and not contain(out2[i][j], tree_form(f"v_{i}")):
|
|
37
|
-
out[1-i].append(out2[i].pop(j))
|
|
38
|
-
output = [simplify(product(out2[i])*product(out[i])**tree_form("d_-1")) for i in range(2)]
|
|
39
|
-
if ("f_dif" in str_form(output[0]) or "f_dif" in str_form(output[1])) and tree_form("v_0").fx("dif") not in factor_generation(output[0]):
|
|
40
|
-
output = [tree_form("d_1")/item for item in output]
|
|
41
|
-
return output
|
|
42
|
-
def check(eq):
|
|
43
|
-
for item in factor_generation(eq):
|
|
44
|
-
if contain(item, tree_form("v_0")) and contain(item, tree_form("v_1")) :
|
|
45
|
-
return False
|
|
46
|
-
return True
|
|
47
|
-
def t(eq):
|
|
48
|
-
eq2 = simplify(summation(eq))
|
|
49
|
-
lst = take_common(eq2)
|
|
50
|
-
for item in lst:
|
|
51
|
-
if item.name == "f_add" and len(item.children) == 2:
|
|
52
|
-
if all(check(child) for child in item.children):
|
|
53
|
-
return item
|
|
54
|
-
elif check(item):
|
|
55
|
-
return item
|
|
56
|
-
return eq2
|
|
57
|
-
def inversediff(lhs, rhs, old=None):
|
|
58
|
-
if old is None:
|
|
59
|
-
old = []
|
|
60
|
-
if lhs is None or rhs is None:
|
|
61
|
-
return None
|
|
62
|
-
eq = simplify(lhs - rhs)
|
|
63
|
-
eq = tt(eq)
|
|
64
|
-
eq = clr(eq)
|
|
65
|
-
eq = t(eq.children)
|
|
66
|
-
xonly = []
|
|
67
|
-
yonly = []
|
|
68
|
-
mixed = []
|
|
69
|
-
const = []
|
|
70
|
-
lst = []
|
|
71
|
-
if eq.name != "f_add":
|
|
72
|
-
lst.append(eq)
|
|
73
|
-
else:
|
|
74
|
-
lst = eq.children
|
|
75
|
-
for item in lst:
|
|
76
|
-
con_x = contain(item, tree_form("v_0"))
|
|
77
|
-
con_y = contain(item, tree_form("v_1"))
|
|
78
|
-
if not con_x and not con_y:
|
|
79
|
-
const.append(item)
|
|
80
|
-
elif con_x and con_y:
|
|
81
|
-
mixed.append(item)
|
|
82
|
-
elif con_x:
|
|
83
|
-
xonly.append(item)
|
|
84
|
-
elif con_y:
|
|
85
|
-
yonly.append(item)
|
|
86
|
-
if len(const) > 0:
|
|
87
|
-
if len(yonly) > 0:
|
|
88
|
-
yonly += const
|
|
89
|
-
else:
|
|
90
|
-
xonly += const
|
|
91
|
-
if eq in old:
|
|
92
|
-
return None
|
|
93
|
-
if len(mixed) == 0:
|
|
94
|
-
tmp = shift(lhs, -rhs)
|
|
95
|
-
return simplify(lhs-rhs)
|
|
96
|
-
elif len(mixed) > 0:
|
|
97
|
-
m = t(mixed)
|
|
98
|
-
if m.name == "f_add":
|
|
99
|
-
mixed = m.children
|
|
100
|
-
else:
|
|
101
|
-
mixed = [m]
|
|
102
|
-
if len(yonly) > 0 and len(xonly) > 0:
|
|
103
|
-
tmp = inversediff(*(shift(t(mixed + xonly), yonly)+[old+[eq]]))
|
|
104
|
-
if tmp is None:
|
|
105
|
-
tmp = inversediff(*(shift(xonly, t(mixed + yonly))+[old+[eq]]))
|
|
106
|
-
if tmp is None:
|
|
107
|
-
return None
|
|
108
|
-
return tmp
|
|
109
|
-
elif len(yonly) > 0:
|
|
110
|
-
if m.name == "f_add":
|
|
111
|
-
return None
|
|
112
|
-
return inversediff(*(shift(m, yonly)+[old+[eq]]))
|
|
113
|
-
elif len(xonly) > 0:
|
|
114
|
-
if m.name == "f_add":
|
|
115
|
-
return None
|
|
116
|
-
return inversediff(*(shift(xonly, m)+[old+[eq]]))
|
|
117
|
-
else:
|
|
118
|
-
if len(mixed) == 2:
|
|
119
|
-
return inversediff(*(shift(*mixed)+[old+[eq]]))
|
|
120
|
-
return None
|
|
121
|
-
def allocvar():
|
|
122
|
-
return tree_form("v_101")
|
|
123
|
-
def epowersplit(eq):
|
|
124
|
-
if eq.name == "f_pow" and eq.children[1].name == "f_add":
|
|
125
|
-
return product([eq.children[0]**child for child in eq.children[1].children])
|
|
126
|
-
return TreeNode(eq.name, [epowersplit(child) for child in eq.children])
|
|
127
|
-
def esolve(s):
|
|
128
|
-
if s.name == "f_add" and "f_log" in str_form(s):
|
|
129
|
-
return product([tree_form("s_e")**child for child in s.children]) - tree_form("d_1")
|
|
130
|
-
return TreeNode(s.name, [esolve(child) for child in s.children])
|
|
131
|
-
def diffsolve_sep2(eq):
|
|
132
|
-
lst = None
|
|
133
|
-
if eq is None:
|
|
134
|
-
return None
|
|
135
|
-
if eq.name == "f_add":
|
|
136
|
-
lst = list(eq.children)
|
|
137
|
-
else:
|
|
138
|
-
lst = [eq]
|
|
139
|
-
s = [allocvar()]
|
|
140
|
-
for item in lst:
|
|
141
|
-
item = simplify(item)
|
|
142
|
-
tmp = factor_generation(item)
|
|
143
|
-
tmp2 = product([k for k in tmp if k.name != "f_dif"])
|
|
144
|
-
if tree_form("v_0").fx("dif") in tmp:
|
|
145
|
-
s.append(TreeNode("f_integrate", [tmp2, tree_form("v_0")]))
|
|
146
|
-
elif tree_form("v_1").fx("dif") in tmp:
|
|
147
|
-
s.append(TreeNode("f_integrate", [tmp2, tree_form("v_1")]))
|
|
148
|
-
return TreeNode("f_eq", [summation(s), tree_form("d_0")])
|
|
149
|
-
def e0(eq):
|
|
150
|
-
return TreeNode("f_eq", [eq, tree_form("d_0")])
|
|
151
|
-
def e1(eq):
|
|
152
|
-
if eq.name == "f_eq":
|
|
153
|
-
eq = eq.children[0]
|
|
154
|
-
return eq
|
|
155
|
-
def groupe(eq):
|
|
156
|
-
eq = esolve(eq)
|
|
157
|
-
eq = simplify(eq)
|
|
158
|
-
eq = fraction(eq)
|
|
159
|
-
eq = simplify(eq)
|
|
160
|
-
eq = epowersplit(eq)
|
|
161
|
-
return eq
|
|
162
|
-
def diffsolve_sep(eq):
|
|
163
|
-
eq = epowersplit(eq)
|
|
164
|
-
eq = inversediff(tree_form("d_0"), eq.children[0].copy_tree())
|
|
165
|
-
return eq
|
|
166
|
-
def diffsolve(eq):
|
|
167
|
-
orig = eq.copy_tree()
|
|
168
|
-
# eq = diff2(eq)
|
|
169
|
-
eq = subs2(eq, order(eq))
|
|
170
|
-
eq = fraction(simplify(fraction(eq)))
|
|
171
|
-
if order(eq) == 2:
|
|
172
|
-
for i in range(2):
|
|
173
|
-
out = second_order_dif(eq, tree_form(f"v_{i}"), tree_form(f"v_{1-i}"))
|
|
174
|
-
if out is not None:
|
|
175
|
-
return out
|
|
176
|
-
return orig
|
|
177
|
-
eq = diffsolve_sep2(diffsolve_sep(eq))
|
|
178
|
-
if eq is None:
|
|
179
|
-
for i in range(2):
|
|
180
|
-
a = tree_form(f"v_{i}")
|
|
181
|
-
b = tree_form(f"v_{1-i}")
|
|
182
|
-
c = tree_form("v_2")
|
|
183
|
-
eq2 = orig
|
|
184
|
-
eq2 = subs2(eq2, 1)
|
|
185
|
-
eq2 = replace(eq2, b, b*a)
|
|
186
|
-
eq2 = subs3(eq2)
|
|
187
|
-
eq2 = simplify(fraction(simplify(eq2)))
|
|
188
|
-
eq2 = diffsolve_sep(eq2)
|
|
189
|
-
eq2 = diffsolve_sep2(eq2)
|
|
190
|
-
if eq2 is not None:
|
|
191
|
-
return e0(TreeNode("f_subs", [replace(eq2.children[0],b,c), c,b/a]).fx("try"))
|
|
192
|
-
eq = orig
|
|
193
|
-
eq = simplify(eq)
|
|
194
|
-
eq = subs2(eq, 1)
|
|
195
|
-
eq = fraction(eq)
|
|
196
|
-
for i in range(2):
|
|
197
|
-
out = linear_dif(eq, tree_form(f"v_{i}"), tree_form(f"v_{1-i}"))
|
|
198
|
-
if out is not None:
|
|
199
|
-
return out
|
|
200
|
-
return orig
|
|
201
|
-
else:
|
|
202
|
-
return eq
|
|
203
|
-
def clist(x):
|
|
204
|
-
return list(x.elements())
|
|
205
|
-
def collect_term(eq, term_lst):
|
|
206
|
-
lst = None
|
|
207
|
-
if eq.name == "f_add":
|
|
208
|
-
lst = copy.deepcopy(eq.children)
|
|
209
|
-
else:
|
|
210
|
-
lst = [eq]
|
|
211
|
-
other = []
|
|
212
|
-
dic = {}
|
|
213
|
-
term_lst = list(sorted(term_lst, key=lambda x: -len(factor_generation(x))))
|
|
214
|
-
for item in term_lst:
|
|
215
|
-
dic[item] = tree_form("d_0")
|
|
216
|
-
for item2 in lst:
|
|
217
|
-
done = True
|
|
218
|
-
tmp2 = Counter(factor_generation(item2))
|
|
219
|
-
for index, item in enumerate(term_lst):
|
|
220
|
-
tmp = Counter(factor_generation(item))
|
|
221
|
-
if (tmp2&tmp) == tmp:
|
|
222
|
-
if item in dic.keys():
|
|
223
|
-
dic[item] += product(clist(tmp2-tmp))
|
|
224
|
-
else:
|
|
225
|
-
dic[item] = product(clist(tmp2-tmp))
|
|
226
|
-
done = False
|
|
227
|
-
break
|
|
228
|
-
if done:
|
|
229
|
-
other.append(item2)
|
|
230
|
-
other = summation(other)
|
|
231
|
-
for key in dic.keys():
|
|
232
|
-
dic[key] = simplify(dic[key])
|
|
233
|
-
return [dic, simplify(other)]
|
|
234
|
-
def order(eq,m=0):
|
|
235
|
-
best = m
|
|
236
|
-
if eq.name in ["f_pdif", "f_dif"]:
|
|
237
|
-
out = order(eq.children[0], m+1)
|
|
238
|
-
best = max(out, best)
|
|
239
|
-
else:
|
|
240
|
-
for child in eq.children:
|
|
241
|
-
out = order(child, m)
|
|
242
|
-
best = max(out, best)
|
|
243
|
-
return best
|
|
244
|
-
def subs2(eq, orde):
|
|
245
|
-
if eq.name in ["f_dif", "f_pdif"] and len(eq.children) == 2:
|
|
246
|
-
if orde == 1:
|
|
247
|
-
return eq.children[0].fx("dif")/eq.children[1].fx("dif")
|
|
248
|
-
else:
|
|
249
|
-
return eq
|
|
250
|
-
return TreeNode(eq.name, [subs2(child, orde) for child in eq.children])
|
|
251
|
-
def subs3(eq):
|
|
252
|
-
if eq.name == "f_dif" and eq.children[0].name == "f_add":
|
|
253
|
-
return summation([subs3(child.fx("dif")) for child in eq.children[0].children])
|
|
254
|
-
if eq.name == "f_dif" and eq.children[0].name == "f_mul":
|
|
255
|
-
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))])
|
|
256
|
-
return TreeNode(eq.name, [subs3(child) for child in eq.children])
|
|
257
|
-
def second_order_dif(eq, a, b):
|
|
258
|
-
eq = simplify(eq)
|
|
259
|
-
nn = [TreeNode("f_dif", [TreeNode("f_dif", [b,a]),a]), TreeNode("f_dif", [b,a]), b]
|
|
260
|
-
out = collect_term(eq.children[0], nn)
|
|
261
|
-
if out[1] == tree_form("d_0"):
|
|
262
|
-
tmp = out[0][nn[0]]
|
|
263
|
-
if tmp != tree_form("d_0"):
|
|
264
|
-
for key in out[0].keys():
|
|
265
|
-
out[0][key] = simplify(out[0][key]/tmp)
|
|
266
|
-
B = out[0][nn[1]]
|
|
267
|
-
C = out[0][nn[2]]
|
|
268
|
-
if all(all(not contain(item, item2) for item2 in [a,b]) for item in [B, C]):
|
|
269
|
-
r = parse("r")
|
|
270
|
-
s = simplify(factor2(simplify(TreeNode("f_eq", [r**2 + B*r + C, tree_form("d_0")])), True))
|
|
271
|
-
r1, r2 = [inverse(item, r.name) for item in s.children[0].children]
|
|
272
|
-
out = None
|
|
273
|
-
if contain(r1, tree_form("s_i")):
|
|
274
|
-
real = simplify(fraction((r1+r2)/tree_form("d_2")))
|
|
275
|
-
imagine = simplify((r1-real)/tree_form("s_i"))
|
|
276
|
-
out = tree_form("s_e")**(real*a)*(tree_form("v_101")*(imagine*a).fx("cos")+tree_form("v_102")*(imagine*a).fx("sin"))
|
|
277
|
-
elif fraction(simplify(r1-r2)) == tree_form("d_0"):
|
|
278
|
-
out =(tree_form("v_101")+tree_form("v_102")*a)*tree_form("s_e")**(r1*a)
|
|
279
|
-
else:
|
|
280
|
-
out = tree_form("v_101")*tree_form("s_e")**(r1*a) + tree_form("v_102")*tree_form("s_e")**(r2*a)
|
|
281
|
-
return TreeNode("f_eq", [b, out])
|
|
282
|
-
return None
|
|
283
|
-
def linear_dif(eq, a, b):
|
|
284
|
-
eq = simplify(eq)
|
|
285
|
-
out = collect_term(eq.children[0], [b.fx("dif"), b*a.fx("dif"), a.fx("dif")])
|
|
286
|
-
if out[1] == tree_form("d_0"):
|
|
287
|
-
tmp = out[0][b.fx("dif")]
|
|
288
|
-
if tmp != tree_form("d_0"):
|
|
289
|
-
for key in out[0].keys():
|
|
290
|
-
out[0][key] = simplify(out[0][key]/tmp)
|
|
291
|
-
p, q = out[0][b*a.fx("dif")], -out[0][a.fx("dif")]
|
|
292
|
-
if contain(p, b) or contain(q, b):
|
|
293
|
-
return None
|
|
294
|
-
f = tree_form("s_e") ** TreeNode("f_integrate", [p, a])
|
|
295
|
-
return simplify(TreeNode("f_eq", [b*f, TreeNode("f_integrate", [q*f, a])+allocvar()]))
|
|
296
|
-
return None
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|