2
2
# 2021/3/8 @ tongshiwei
3
3
4
4
from pprint import pformat
5
- from typing import List
5
+ from typing import List , Dict
6
6
import networkx as nx
7
7
from copy import deepcopy
8
8
9
- from .ast import str2ast , get_edges , ast , link_variable
9
+ from .ast import str2ast , get_edges , link_variable
10
10
11
11
CONST_MATHORD = {r"\pi" }
12
12
13
- __all__ = ["Formula" , "FormulaGroup" , "CONST_MATHORD" ]
13
+ __all__ = ["Formula" , "FormulaGroup" , "CONST_MATHORD" , "link_formulas" ]
14
14
15
15
16
16
class Formula (object ):
17
- def __init__ (self , formula , is_str = True , variable_standardization = False , const_mathord = None ):
18
- self ._formula = formula
19
- self ._ast = str2ast (formula ) if is_str else formula
20
- if variable_standardization :
21
- const_mathord = CONST_MATHORD if const_mathord is None else const_mathord
22
- self .variable_standardization (inplace = True , const_mathord = const_mathord )
17
+ """
18
+ Examples
19
+ --------
20
+ >>> f = Formula("x")
21
+ >>> f
22
+ <Formula: x>
23
+ >>> f.ast
24
+ [{'val': {'id': 0, 'type': 'mathord', 'text': 'x', 'role': None}, \
25
+ 'structure': {'bro': [None, None], 'child': None, 'father': None, 'forest': None}}]
26
+ >>> f.elements
27
+ [{'id': 0, 'type': 'mathord', 'text': 'x', 'role': None}]
28
+ >>> f.variable_standardization(inplace=True)
29
+ <Formula: x>
30
+ >>> f.elements
31
+ [{'id': 0, 'type': 'mathord', 'text': 'x', 'role': None, 'var': 0}]
32
+ """
33
+
34
+ def __init__ (self , formula : (str , List [Dict ]), variable_standardization = False , const_mathord = None ,
35
+ * args , ** kwargs ):
36
+ """
23
37
24
- def variable_standardization (self , inplace = False , const_mathord = None ):
38
+ Parameters
39
+ ----------
40
+ formula: str or List[Dict]
41
+ latex formula string or the parsed abstracted syntax tree
42
+ variable_standardization
43
+ const_mathord
44
+ args
45
+ kwargs
46
+ """
47
+ self ._formula = formula
48
+ self ._ast = None
49
+ self .reset_ast (
50
+ formula_ensure_str = False ,
51
+ variable_standardization = variable_standardization ,
52
+ const_mathord = const_mathord , * args , ** kwargs
53
+ )
54
+
55
+ def variable_standardization (self , inplace = False , const_mathord = None , variable_connect_dict = None ):
25
56
const_mathord = const_mathord if const_mathord is not None else CONST_MATHORD
26
57
ast_tree = self ._ast if inplace else deepcopy (self ._ast )
27
- variables = {}
28
- index = 0
58
+ var_code = variable_connect_dict ["var_code" ] if variable_connect_dict is not None else {}
29
59
for node in ast_tree :
30
60
if node ["val" ]["type" ] == "mathord" :
31
61
var = node ["val" ]["text" ]
32
62
if var in const_mathord :
33
63
continue
34
64
else :
35
- if var not in variables :
36
- variables [var ], index = index , index + 1
37
- node ["val" ]["var" ] = variables [var ]
65
+ if var not in var_code :
66
+ var_code [var ] = len ( var_code )
67
+ node ["val" ]["var" ] = var_code [var ]
38
68
if inplace :
39
69
return self
40
70
else :
41
71
return Formula (ast_tree , is_str = False )
42
72
43
73
@property
44
- def element (self ):
74
+ def ast (self ):
45
75
return self ._ast
46
76
47
77
@property
48
- def ast (self ) -> (nx .Graph , nx .DiGraph ):
78
+ def elements (self ):
79
+ return [self .ast_graph .nodes [node ] for node in self .ast_graph .nodes ]
80
+
81
+ @property
82
+ def ast_graph (self ) -> (nx .Graph , nx .DiGraph ):
49
83
edges = [(edge [0 ], edge [1 ]) for edge in get_edges (self ._ast ) if edge [2 ] == 3 ]
50
84
tree = nx .DiGraph ()
51
85
for node in self ._ast :
@@ -60,38 +94,85 @@ def to_str(self):
60
94
return pformat (self ._ast )
61
95
62
96
def __repr__ (self ):
63
- return "<Formula: %s>" % self ._formula
97
+ if isinstance (self ._formula , str ):
98
+ return "<Formula: %s>" % self ._formula
99
+ else :
100
+ return super (Formula , self ).__repr__ ()
64
101
102
+ def reset_ast (self , formula_ensure_str : bool = True , variable_standardization = False , const_mathord = None , * args ,
103
+ ** kwargs ):
104
+ if formula_ensure_str is True and self .resetable is False :
105
+ raise TypeError ("formula must be str, now is %s" % type (self ._formula ))
106
+ self ._ast = str2ast (self ._formula , * args , ** kwargs ) if isinstance (self ._formula , str ) else self ._formula
107
+ if variable_standardization :
108
+ const_mathord = CONST_MATHORD if const_mathord is None else const_mathord
109
+ self .variable_standardization (inplace = True , const_mathord = const_mathord )
110
+ return self ._ast
65
111
66
- class FormulaGroup ( object ):
67
- def __init__ (self , formula_list : List [ str ], variable_standardization = False , const_mathord = None ):
68
- """
112
+ @ property
113
+ def resetable (self ):
114
+ return isinstance ( self . _formula , str )
69
115
70
- Parameters
71
- ----------
72
- formula_list: List[str]
73
- """
74
- forest_begin = 0
116
+
117
+ class FormulaGroup (object ):
118
+ """
119
+ Examples
120
+ ---------
121
+ >>> fg = FormulaGroup(["x + y", "y + x", "z + x"])
122
+ >>> fg
123
+ <FormulaGroup: <Formula: x + y>;<Formula: y + x>;<Formula: z + x>>
124
+ >>> fg = FormulaGroup(["x + y", Formula("y + x"), "z + x"])
125
+ >>> fg
126
+ <FormulaGroup: <Formula: x + y>;<Formula: y + x>;<Formula: z + x>>
127
+ >>> fg = FormulaGroup(["x", Formula("y"), "x"])
128
+ >>> fg.elements
129
+ [{'id': 0, 'type': 'mathord', 'text': 'x', 'role': None}, {'id': 1, 'type': 'mathord', 'text': 'y', 'role': None},\
130
+ {'id': 2, 'type': 'mathord', 'text': 'x', 'role': None}]
131
+ >>> fg = FormulaGroup(["x", Formula("y"), "x"], variable_standardization=True)
132
+ >>> fg.elements
133
+ [{'id': 0, 'type': 'mathord', 'text': 'x', 'role': None, 'var': 0}, \
134
+ {'id': 1, 'type': 'mathord', 'text': 'y', 'role': None, 'var': 1}, \
135
+ {'id': 2, 'type': 'mathord', 'text': 'x', 'role': None, 'var': 0}]
136
+ """
137
+
138
+ def __init__ (self ,
139
+ formula_list : (list , List [str ], List [Formula ]),
140
+ variable_standardization = False ,
141
+ const_mathord = None ,
142
+ detach = True
143
+ ):
75
144
forest = []
76
- formula_sep_index = []
77
- for index in range (0 , len (formula_list )):
78
- formula_sep_index .append (forest_begin )
79
- tree = ast (
80
- formula_list [index ],
81
- forest_begin = forest_begin ,
82
- is_str = True
83
- )
84
- forest_begin += len (tree )
145
+ self ._formulas = []
146
+ for formula in formula_list :
147
+ if isinstance (formula , str ):
148
+ formula = Formula (
149
+ formula ,
150
+ forest_begin = len (forest ),
151
+ )
152
+ self ._formulas .append (formula )
153
+ tree = formula .ast
154
+ elif isinstance (formula , Formula ):
155
+ if detach :
156
+ formula = deepcopy (formula )
157
+ tree = formula .reset_ast (
158
+ formula_ensure_str = True ,
159
+ variable_standardization = False ,
160
+ forest_begin = len (forest ),
161
+ )
162
+ self ._formulas .append (formula )
163
+ else :
164
+ raise TypeError (
165
+ "the element in formula_list should be either str or Formula, now is %s" % type (Formula )
166
+ )
85
167
forest += tree
86
- else :
87
- formula_sep_index .append (len (forest ))
88
- forest = link_variable (forest )
168
+ variable_connect_dict = link_variable (forest )
89
169
self ._forest = forest
90
- self ._formulas = []
91
- for i , sep in enumerate (formula_sep_index [:- 1 ]):
92
- self ._formulas .append (Formula (forest [sep : formula_sep_index [i + 1 ]], is_str = False ))
93
170
if variable_standardization :
94
- self .variable_standardization (inplace = True , const_mathord = const_mathord )
171
+ self .variable_standardization (
172
+ inplace = True ,
173
+ const_mathord = const_mathord ,
174
+ variable_connect_dict = variable_connect_dict
175
+ )
95
176
96
177
def __iter__ (self ):
97
178
return iter (self ._formulas )
@@ -102,14 +183,47 @@ def __getitem__(self, item) -> Formula:
102
183
def __contains__ (self , item ) -> bool :
103
184
return item in self ._formulas
104
185
105
- def variable_standardization (self , inplace = False , const_mathord = None ):
186
+ def variable_standardization (self , inplace = False , const_mathord = None , variable_connect_dict = None ):
106
187
ret = []
107
188
for formula in self ._formulas :
108
- ret .append (formula .variable_standardization (inplace = inplace , const_mathord = const_mathord ))
189
+ ret .append (formula .variable_standardization (inplace = inplace , const_mathord = const_mathord ,
190
+ variable_connect_dict = variable_connect_dict ))
109
191
return ret
110
192
111
193
def to_str (self ):
112
- return pformat (self ._formulas )
194
+ return pformat (self ._forest )
113
195
114
196
def __repr__ (self ):
115
197
return "<FormulaGroup: %s>" % ";" .join ([repr (_formula ) for _formula in self ._formulas ])
198
+
199
+ @property
200
+ def ast (self ):
201
+ return self ._forest
202
+
203
+ @property
204
+ def elements (self ):
205
+ return [self .ast_graph .nodes [node ] for node in self .ast_graph .nodes ]
206
+
207
+ @property
208
+ def ast_graph (self ) -> (nx .Graph , nx .DiGraph ):
209
+ edges = [(edge [0 ], edge [1 ]) for edge in get_edges (self ._forest ) if edge [2 ] == 3 ]
210
+ tree = nx .DiGraph ()
211
+ for node in self ._forest :
212
+ tree .add_node (
213
+ node ["val" ]["id" ],
214
+ ** node ["val" ]
215
+ )
216
+ tree .add_edges_from (edges )
217
+ return tree
218
+
219
+
220
+ def link_formulas (* formula : Formula , ** kwargs ):
221
+ forest = []
222
+ for form in formula :
223
+ forest += form .reset_ast (
224
+ forest_begin = len (forest ),
225
+ ** kwargs
226
+ )
227
+ variable_connect_dict = link_variable (forest )
228
+ for form in formula :
229
+ form .variable_standardization (inplace = True , variable_connect_dict = variable_connect_dict , ** kwargs )
0 commit comments