mathai 0.2.7__py3-none-any.whl → 0.2.9__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 +16 -16
- mathai/apart.py +103 -103
- mathai/base.py +355 -354
- mathai/console.py +84 -84
- mathai/diff.py +65 -65
- mathai/expand.py +58 -58
- mathai/factor.py +125 -125
- mathai/fraction.py +59 -59
- mathai/integrate.py +346 -346
- mathai/inverse.py +65 -65
- mathai/limit.py +130 -130
- mathai/linear.py +152 -152
- mathai/logic.py +224 -224
- mathai/parser.py +154 -154
- mathai/printeq.py +34 -34
- mathai/simplify.py +358 -358
- mathai/structure.py +103 -103
- mathai/tool.py +35 -35
- mathai/trig.py +169 -169
- mathai/univariate_inequality.py +410 -414
- {mathai-0.2.7.dist-info → mathai-0.2.9.dist-info}/METADATA +231 -231
- mathai-0.2.9.dist-info/RECORD +24 -0
- {mathai-0.2.7.dist-info → mathai-0.2.9.dist-info}/WHEEL +1 -1
- mathai-0.2.7.dist-info/RECORD +0 -24
- {mathai-0.2.7.dist-info → mathai-0.2.9.dist-info}/top_level.txt +0 -0
mathai/parser.py
CHANGED
@@ -1,154 +1,154 @@
|
|
1
|
-
import copy
|
2
|
-
from lark import Lark, Tree
|
3
|
-
from .base import *
|
4
|
-
import re
|
5
|
-
|
6
|
-
grammar = """
|
7
|
-
?start: expr
|
8
|
-
|
9
|
-
?expr: logic_equiv
|
10
|
-
|
11
|
-
?logic_equiv: logic_imply
|
12
|
-
| logic_equiv "<->" logic_imply -> equiv
|
13
|
-
|
14
|
-
?logic_imply: logic_or
|
15
|
-
| logic_or "->" logic_imply -> imply
|
16
|
-
|
17
|
-
?logic_or: logic_and
|
18
|
-
| logic_or "|" logic_and -> or
|
19
|
-
| logic_or "||" logic_and -> or
|
20
|
-
|
21
|
-
?logic_and: comparison
|
22
|
-
| logic_and "&" comparison -> and
|
23
|
-
| logic_and "&&" comparison -> and
|
24
|
-
|
25
|
-
?comparison: arithmetic
|
26
|
-
| comparison "=" arithmetic -> eq
|
27
|
-
| comparison "<" arithmetic -> lt
|
28
|
-
| comparison ">" arithmetic -> gt
|
29
|
-
| comparison "<=" arithmetic -> le
|
30
|
-
| comparison ">=" arithmetic -> ge
|
31
|
-
|
32
|
-
?arithmetic: arithmetic "+" term -> add
|
33
|
-
| arithmetic "-" term -> sub
|
34
|
-
| term
|
35
|
-
|
36
|
-
?term: term "*" power -> mul
|
37
|
-
| term "/" power -> div
|
38
|
-
| term "." power -> dot
|
39
|
-
| power
|
40
|
-
|
41
|
-
?power: power "^" factor -> pow
|
42
|
-
| power "**" factor -> pow
|
43
|
-
| factor
|
44
|
-
|
45
|
-
?factor: "-" factor -> neg
|
46
|
-
| "+" factor -> pass_through
|
47
|
-
| atom
|
48
|
-
|
49
|
-
?atom: NUMBER -> number
|
50
|
-
| VARIABLE -> variable
|
51
|
-
| FUNC_NAME "(" [expr ("," expr)*] ")" -> func
|
52
|
-
| "[" [expr ("," expr)*] "]" -> list
|
53
|
-
| "(" expr ")" -> paren
|
54
|
-
| CNUMBER -> cnumber
|
55
|
-
| ESCAPED_STRING -> string
|
56
|
-
| CAPITAL_ID -> matrix
|
57
|
-
|
58
|
-
FUNC_NAME: "midpoint" | "forall" | "imply" | "exist" | "len" | "sum" | "angle" | "line" | "sum2" | "charge" | "electricfield" | "perm" | "point" | "equationrhs" | "transpose" | "equationlhs" | "equation" | "error" | "covariance" | "variance" | "expect" | "mag" | "rad" | "laplace" | "diverge" | "pdif" | "gradient" | "curl" | "point1" | "point2" | "dot" | "point3" | "line1" | "line2" | "line3" | "sin" | "circumcenter" | "eqtri" | "linesegment" | "cos" | "tan" | "log" | "sqrt" | "integrate" | "dif" | "abs" | "cosec" | "sec" | "cot" | "arctan" | "arcsin" | "arccos" | "log10"
|
59
|
-
|
60
|
-
VARIABLE: /[a-z]/ | "nabla" | "pi" | "kc" | "hbar" | "em" | "ec" | "anot" | "false" | "true"
|
61
|
-
|
62
|
-
CAPITAL_ID: /[A-Z]/
|
63
|
-
|
64
|
-
CNUMBER: /c[0-9]+/
|
65
|
-
|
66
|
-
%import common.NUMBER
|
67
|
-
%import common.ESCAPED_STRING
|
68
|
-
%import common.WS_INLINE
|
69
|
-
%ignore WS_INLINE
|
70
|
-
"""
|
71
|
-
|
72
|
-
def parse(equation, funclist=None):
|
73
|
-
equation = copy.copy(equation.replace(" ", ""))
|
74
|
-
grammar2 = copy.deepcopy(grammar)
|
75
|
-
if funclist is not None:
|
76
|
-
output = grammar2.split("\n")
|
77
|
-
for i in range(len(output)):
|
78
|
-
if "FUNC_NAME:" in output[i]:
|
79
|
-
output[i] = output[i].replace("FUNC_NAME: ", "FUNC_NAME: " + " | ".join(['"' + x + '"' for x in funclist]) + " | ")
|
80
|
-
grammar2 = "\n".join(output)
|
81
|
-
|
82
|
-
parser_main = Lark(grammar2, start='start', parser='lalr')
|
83
|
-
parse_tree = parser_main.parse(equation)
|
84
|
-
|
85
|
-
# Convert Lark tree to TreeNode
|
86
|
-
def convert_to_treenode(parse_tree):
|
87
|
-
if isinstance(parse_tree, Tree):
|
88
|
-
node = TreeNode(parse_tree.data)
|
89
|
-
node.children = [convert_to_treenode(child) for child in parse_tree.children]
|
90
|
-
return node
|
91
|
-
else:
|
92
|
-
return TreeNode(str(parse_tree))
|
93
|
-
|
94
|
-
# Flatten unnecessary nodes like pass_through
|
95
|
-
def remove_past(equation):
|
96
|
-
if equation.name in {"number", "paren", "func", "variable", "pass_through", "cnumber", "string", "matrix"}:
|
97
|
-
if len(equation.children) == 1:
|
98
|
-
return remove_past(equation.children[0])
|
99
|
-
else:
|
100
|
-
equation.children = [remove_past(child) for child in equation.children]
|
101
|
-
return TreeNode(equation.children[0].name, equation.children[1:])
|
102
|
-
equation.children = [remove_past(child) for child in equation.children]
|
103
|
-
return equation
|
104
|
-
|
105
|
-
# Handle indices if any
|
106
|
-
def prefixindex(equation):
|
107
|
-
if equation.name == "base" and len(equation.children) > 1:
|
108
|
-
return TreeNode("index", [equation.children[0]] + equation.children[1].children)
|
109
|
-
return TreeNode(equation.name, [prefixindex(child) for child in equation.children])
|
110
|
-
|
111
|
-
tree_node = convert_to_treenode(parse_tree)
|
112
|
-
tree_node = remove_past(tree_node)
|
113
|
-
tree_node = prefixindex(tree_node)
|
114
|
-
|
115
|
-
# Convert function names and constants
|
116
|
-
def fxchange(tree_node):
|
117
|
-
tmp3 = funclist if funclist is not None else []
|
118
|
-
if tree_node.name == "neg":
|
119
|
-
child = fxchange(tree_node.children[0])
|
120
|
-
# if the child is a number, make it negative
|
121
|
-
if child.name.startswith("d_") and re.match(r"d_\d+(\.\d+)?$", child.name):
|
122
|
-
return TreeNode("d_" + str(-int(child.name[2:])))
|
123
|
-
else:
|
124
|
-
# otherwise subtract from zero
|
125
|
-
return TreeNode("f_sub", [tree_form("d_0"), child])
|
126
|
-
if tree_node.name == "pass_through":
|
127
|
-
return fxchange(tree_node.children[0])
|
128
|
-
return TreeNode(
|
129
|
-
"f_" + tree_node.name if tree_node.name in tmp3 + ["sqrt","imply","forall","exist","exclude","union","intersection","len","index","angle","charge","sum2","electricfield","line","point","sum","transpose","equationrhs","equationlhs","equation","covariance","variance","expect","error","laplace","dot","curl","pdif","diverge","gradient","rad","ge","le","gt","lt","eqtri","linesegment","midpoint","mag","point1","point2","point3","line1","line2","line3","log10","arcsin","arccos","arctan","list","cosec","sec","cot","equiv","or","not","and","circumcenter","eq","sub","add","sin","cos","tan","mul","integrate","dif","pow","div","log","abs"] else "d_" + tree_node.name,
|
130
|
-
[fxchange(child) for child in tree_node.children]
|
131
|
-
)
|
132
|
-
|
133
|
-
tree_node = fxchange(tree_node)
|
134
|
-
|
135
|
-
# Replace common constants
|
136
|
-
for const in ["e","pi","kc","em","ec","anot","hbar","false","true","i","nabla"]:
|
137
|
-
tree_node = replace(tree_node, tree_form("d_"+const), tree_form("s_"+const))
|
138
|
-
|
139
|
-
# Map letters to variables
|
140
|
-
for i, c in enumerate(["x","y","z"] + [chr(x+ord("a")) for x in range(0,23)]):
|
141
|
-
tree_node = replace(tree_node, tree_form("d_"+c), tree_form("v_"+str(i)))
|
142
|
-
for i, c in enumerate([chr(x+ord("A")) for x in range(0,26)]):
|
143
|
-
tree_node = replace(tree_node, tree_form("d_"+c), tree_form("v_-"+str(i+1)))
|
144
|
-
tree_node = replace(tree_node, tree_form("f_"+c), tree_form("v_-"+str(i+1)))
|
145
|
-
|
146
|
-
# Final recursive replacements
|
147
|
-
def rfx(tree_node):
|
148
|
-
if tree_node.name[:3] == "d_c":
|
149
|
-
return tree_form("v_" + str(int(tree_node.name[3:])+100))
|
150
|
-
tree_node.children = [rfx(child) for child in tree_node.children]
|
151
|
-
return tree_node
|
152
|
-
|
153
|
-
tree_node = rfx(tree_node)
|
154
|
-
return tree_node
|
1
|
+
import copy
|
2
|
+
from lark import Lark, Tree
|
3
|
+
from .base import *
|
4
|
+
import re
|
5
|
+
|
6
|
+
grammar = """
|
7
|
+
?start: expr
|
8
|
+
|
9
|
+
?expr: logic_equiv
|
10
|
+
|
11
|
+
?logic_equiv: logic_imply
|
12
|
+
| logic_equiv "<->" logic_imply -> equiv
|
13
|
+
|
14
|
+
?logic_imply: logic_or
|
15
|
+
| logic_or "->" logic_imply -> imply
|
16
|
+
|
17
|
+
?logic_or: logic_and
|
18
|
+
| logic_or "|" logic_and -> or
|
19
|
+
| logic_or "||" logic_and -> or
|
20
|
+
|
21
|
+
?logic_and: comparison
|
22
|
+
| logic_and "&" comparison -> and
|
23
|
+
| logic_and "&&" comparison -> and
|
24
|
+
|
25
|
+
?comparison: arithmetic
|
26
|
+
| comparison "=" arithmetic -> eq
|
27
|
+
| comparison "<" arithmetic -> lt
|
28
|
+
| comparison ">" arithmetic -> gt
|
29
|
+
| comparison "<=" arithmetic -> le
|
30
|
+
| comparison ">=" arithmetic -> ge
|
31
|
+
|
32
|
+
?arithmetic: arithmetic "+" term -> add
|
33
|
+
| arithmetic "-" term -> sub
|
34
|
+
| term
|
35
|
+
|
36
|
+
?term: term "*" power -> mul
|
37
|
+
| term "/" power -> div
|
38
|
+
| term "." power -> dot
|
39
|
+
| power
|
40
|
+
|
41
|
+
?power: power "^" factor -> pow
|
42
|
+
| power "**" factor -> pow
|
43
|
+
| factor
|
44
|
+
|
45
|
+
?factor: "-" factor -> neg
|
46
|
+
| "+" factor -> pass_through
|
47
|
+
| atom
|
48
|
+
|
49
|
+
?atom: NUMBER -> number
|
50
|
+
| VARIABLE -> variable
|
51
|
+
| FUNC_NAME "(" [expr ("," expr)*] ")" -> func
|
52
|
+
| "[" [expr ("," expr)*] "]" -> list
|
53
|
+
| "(" expr ")" -> paren
|
54
|
+
| CNUMBER -> cnumber
|
55
|
+
| ESCAPED_STRING -> string
|
56
|
+
| CAPITAL_ID -> matrix
|
57
|
+
|
58
|
+
FUNC_NAME: "midpoint" | "forall" | "imply" | "exist" | "len" | "sum" | "angle" | "line" | "sum2" | "charge" | "electricfield" | "perm" | "point" | "equationrhs" | "transpose" | "equationlhs" | "equation" | "error" | "covariance" | "variance" | "expect" | "mag" | "rad" | "laplace" | "diverge" | "pdif" | "gradient" | "curl" | "point1" | "point2" | "dot" | "point3" | "line1" | "line2" | "line3" | "sin" | "circumcenter" | "eqtri" | "linesegment" | "cos" | "tan" | "log" | "sqrt" | "integrate" | "dif" | "abs" | "cosec" | "sec" | "cot" | "arctan" | "arcsin" | "arccos" | "log10"
|
59
|
+
|
60
|
+
VARIABLE: /[a-z]/ | "nabla" | "pi" | "kc" | "hbar" | "em" | "ec" | "anot" | "false" | "true"
|
61
|
+
|
62
|
+
CAPITAL_ID: /[A-Z]/
|
63
|
+
|
64
|
+
CNUMBER: /c[0-9]+/
|
65
|
+
|
66
|
+
%import common.NUMBER
|
67
|
+
%import common.ESCAPED_STRING
|
68
|
+
%import common.WS_INLINE
|
69
|
+
%ignore WS_INLINE
|
70
|
+
"""
|
71
|
+
|
72
|
+
def parse(equation, funclist=None):
|
73
|
+
equation = copy.copy(equation.replace(" ", ""))
|
74
|
+
grammar2 = copy.deepcopy(grammar)
|
75
|
+
if funclist is not None:
|
76
|
+
output = grammar2.split("\n")
|
77
|
+
for i in range(len(output)):
|
78
|
+
if "FUNC_NAME:" in output[i]:
|
79
|
+
output[i] = output[i].replace("FUNC_NAME: ", "FUNC_NAME: " + " | ".join(['"' + x + '"' for x in funclist]) + " | ")
|
80
|
+
grammar2 = "\n".join(output)
|
81
|
+
|
82
|
+
parser_main = Lark(grammar2, start='start', parser='lalr')
|
83
|
+
parse_tree = parser_main.parse(equation)
|
84
|
+
|
85
|
+
# Convert Lark tree to TreeNode
|
86
|
+
def convert_to_treenode(parse_tree):
|
87
|
+
if isinstance(parse_tree, Tree):
|
88
|
+
node = TreeNode(parse_tree.data)
|
89
|
+
node.children = [convert_to_treenode(child) for child in parse_tree.children]
|
90
|
+
return node
|
91
|
+
else:
|
92
|
+
return TreeNode(str(parse_tree))
|
93
|
+
|
94
|
+
# Flatten unnecessary nodes like pass_through
|
95
|
+
def remove_past(equation):
|
96
|
+
if equation.name in {"number", "paren", "func", "variable", "pass_through", "cnumber", "string", "matrix"}:
|
97
|
+
if len(equation.children) == 1:
|
98
|
+
return remove_past(equation.children[0])
|
99
|
+
else:
|
100
|
+
equation.children = [remove_past(child) for child in equation.children]
|
101
|
+
return TreeNode(equation.children[0].name, equation.children[1:])
|
102
|
+
equation.children = [remove_past(child) for child in equation.children]
|
103
|
+
return equation
|
104
|
+
|
105
|
+
# Handle indices if any
|
106
|
+
def prefixindex(equation):
|
107
|
+
if equation.name == "base" and len(equation.children) > 1:
|
108
|
+
return TreeNode("index", [equation.children[0]] + equation.children[1].children)
|
109
|
+
return TreeNode(equation.name, [prefixindex(child) for child in equation.children])
|
110
|
+
|
111
|
+
tree_node = convert_to_treenode(parse_tree)
|
112
|
+
tree_node = remove_past(tree_node)
|
113
|
+
tree_node = prefixindex(tree_node)
|
114
|
+
|
115
|
+
# Convert function names and constants
|
116
|
+
def fxchange(tree_node):
|
117
|
+
tmp3 = funclist if funclist is not None else []
|
118
|
+
if tree_node.name == "neg":
|
119
|
+
child = fxchange(tree_node.children[0])
|
120
|
+
# if the child is a number, make it negative
|
121
|
+
if child.name.startswith("d_") and re.match(r"d_\d+(\.\d+)?$", child.name):
|
122
|
+
return TreeNode("d_" + str(-int(child.name[2:])))
|
123
|
+
else:
|
124
|
+
# otherwise subtract from zero
|
125
|
+
return TreeNode("f_sub", [tree_form("d_0"), child])
|
126
|
+
if tree_node.name == "pass_through":
|
127
|
+
return fxchange(tree_node.children[0])
|
128
|
+
return TreeNode(
|
129
|
+
"f_" + tree_node.name if tree_node.name in tmp3 + ["sqrt","imply","forall","exist","exclude","union","intersection","len","index","angle","charge","sum2","electricfield","line","point","sum","transpose","equationrhs","equationlhs","equation","covariance","variance","expect","error","laplace","dot","curl","pdif","diverge","gradient","rad","ge","le","gt","lt","eqtri","linesegment","midpoint","mag","point1","point2","point3","line1","line2","line3","log10","arcsin","arccos","arctan","list","cosec","sec","cot","equiv","or","not","and","circumcenter","eq","sub","add","sin","cos","tan","mul","integrate","dif","pow","div","log","abs"] else "d_" + tree_node.name,
|
130
|
+
[fxchange(child) for child in tree_node.children]
|
131
|
+
)
|
132
|
+
|
133
|
+
tree_node = fxchange(tree_node)
|
134
|
+
|
135
|
+
# Replace common constants
|
136
|
+
for const in ["e","pi","kc","em","ec","anot","hbar","false","true","i","nabla"]:
|
137
|
+
tree_node = replace(tree_node, tree_form("d_"+const), tree_form("s_"+const))
|
138
|
+
|
139
|
+
# Map letters to variables
|
140
|
+
for i, c in enumerate(["x","y","z"] + [chr(x+ord("a")) for x in range(0,23)]):
|
141
|
+
tree_node = replace(tree_node, tree_form("d_"+c), tree_form("v_"+str(i)))
|
142
|
+
for i, c in enumerate([chr(x+ord("A")) for x in range(0,26)]):
|
143
|
+
tree_node = replace(tree_node, tree_form("d_"+c), tree_form("v_-"+str(i+1)))
|
144
|
+
tree_node = replace(tree_node, tree_form("f_"+c), tree_form("v_-"+str(i+1)))
|
145
|
+
|
146
|
+
# Final recursive replacements
|
147
|
+
def rfx(tree_node):
|
148
|
+
if tree_node.name[:3] == "d_c":
|
149
|
+
return tree_form("v_" + str(int(tree_node.name[3:])+100))
|
150
|
+
tree_node.children = [rfx(child) for child in tree_node.children]
|
151
|
+
return tree_node
|
152
|
+
|
153
|
+
tree_node = rfx(tree_node)
|
154
|
+
return tree_node
|
mathai/printeq.py
CHANGED
@@ -1,34 +1,34 @@
|
|
1
|
-
from .base import *
|
2
|
-
from .simplify import solve
|
3
|
-
import copy
|
4
|
-
from fractions import Fraction
|
5
|
-
def abstractexpr(eq):
|
6
|
-
if eq.name == "f_pow" and frac(eq.children[1])==Fraction(1,2):
|
7
|
-
eq = eq.children[0].fx("sqrt")
|
8
|
-
if eq.name == "f_pow" and frac(eq.children[1])==Fraction(-1,2):
|
9
|
-
eq = eq.children[0].fx("sqrt")**-1
|
10
|
-
if eq.name in ["f_mul", "f_pow"]:
|
11
|
-
|
12
|
-
lst = factor_generation(eq)
|
13
|
-
deno = [item.children[0]**int(item.children[1].name[3:]) for item in lst if item.name == "f_pow" and item.children[1].name[:3] == "d_-"]
|
14
|
-
if eq.name == "f_mul" and any(item.name[:2] == "d_" and int(item.name[2:]) < 0 for item in lst):
|
15
|
-
return solve(-eq).fx("neg")
|
16
|
-
if deno != []:
|
17
|
-
|
18
|
-
num = [item for item in lst if item.name != "f_pow" or item.children[1].name[:3] != "d_-"]
|
19
|
-
if num == []:
|
20
|
-
num = [tree_form("d_1")]
|
21
|
-
return TreeNode("f_div", [solve(product(num)), solve(product(deno))])
|
22
|
-
|
23
|
-
|
24
|
-
return TreeNode(eq.name, [abstractexpr(child) for child in eq.children])
|
25
|
-
|
26
|
-
def printeq_str(eq):
|
27
|
-
return str(dowhile(copy.deepcopy(eq), abstractexpr))
|
28
|
-
|
29
|
-
def printeq(eq):
|
30
|
-
print(printeq_str(eq))
|
31
|
-
|
32
|
-
def printeq_log(lst):
|
33
|
-
for item in lst:
|
34
|
-
print(" "*item[0] + item[1])
|
1
|
+
from .base import *
|
2
|
+
from .simplify import solve
|
3
|
+
import copy
|
4
|
+
from fractions import Fraction
|
5
|
+
def abstractexpr(eq):
|
6
|
+
if eq.name == "f_pow" and frac(eq.children[1])==Fraction(1,2):
|
7
|
+
eq = eq.children[0].fx("sqrt")
|
8
|
+
if eq.name == "f_pow" and frac(eq.children[1])==Fraction(-1,2):
|
9
|
+
eq = eq.children[0].fx("sqrt")**-1
|
10
|
+
if eq.name in ["f_mul", "f_pow"]:
|
11
|
+
|
12
|
+
lst = factor_generation(eq)
|
13
|
+
deno = [item.children[0]**int(item.children[1].name[3:]) for item in lst if item.name == "f_pow" and item.children[1].name[:3] == "d_-"]
|
14
|
+
if eq.name == "f_mul" and any(item.name[:2] == "d_" and int(item.name[2:]) < 0 for item in lst):
|
15
|
+
return solve(-eq).fx("neg")
|
16
|
+
if deno != []:
|
17
|
+
|
18
|
+
num = [item for item in lst if item.name != "f_pow" or item.children[1].name[:3] != "d_-"]
|
19
|
+
if num == []:
|
20
|
+
num = [tree_form("d_1")]
|
21
|
+
return TreeNode("f_div", [solve(product(num)), solve(product(deno))])
|
22
|
+
|
23
|
+
|
24
|
+
return TreeNode(eq.name, [abstractexpr(child) for child in eq.children])
|
25
|
+
|
26
|
+
def printeq_str(eq):
|
27
|
+
return str(dowhile(copy.deepcopy(eq), abstractexpr))
|
28
|
+
|
29
|
+
def printeq(eq):
|
30
|
+
print(printeq_str(eq))
|
31
|
+
|
32
|
+
def printeq_log(lst):
|
33
|
+
for item in lst:
|
34
|
+
print(" "*item[0] + item[1])
|