-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathparsefg.py
209 lines (144 loc) · 5.85 KB
/
parsefg.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
""" parsefg.py: This file is part of the feyncop/feyngen package.
Implements the Graph parsing. """
# See also: https://github.com/michibo/feyncop
# Author: Michael Borinsky
# Python3 port: Frédéric Chapoton
# Bugreports, comments, or suggestions are always welcome.
# For instance, via github or email
import re
import sys
from fractions import Fraction
import collections
from hopf_graph import HopfGraph
var_name_ptrn = re.compile(r"^(\S+)\s*:=\s*")
def parse_var_name(string):
"""Parses the name of a input graph sum."""
m = var_name_ptrn.search(string)
if m:
return m.group(1), m.end(1), m.end()
return "", 0, 0
fraction_pattern = re.compile(r"^(\d*)(/?)(\d*)$")
def parse_fraction(s):
"""Parses a fraction encoded in a string s."""
if not s:
return Fraction(1, 1)
m = fraction_pattern.match(s)
n = 1
try:
n = int(m.group(1))
except ValueError:
pass
d = 1
try:
d = int(m.group(3))
except ValueError:
pass
return Fraction(n, d)
edge_pattern = re.compile(r"\[\s*(\d+)\s*,\s*(\d+)\s*(,?)\s*(-?\s*[Afc]+|)\s*\]")
graph_pattern = re.compile(r"\s*(\+?-?)\s*(\d*/?\d*)\s*\*?\s*G\[([0-9,\[\]\sAfc]*)\]\*?(\d*/?\d*)?\s*")
graph_pattern_pow = re.compile(r"\s*\(?(G\[[0-9,\[\]\sAfc]*\])\s*\)?\^?(\d*)")
tensor_product_pattern = re.compile(r"\s*(\+?-?)\s*(\d*/?\d*)\s*\*?\s*T\[\s*((?:\(?G\[[0-9,\[\]\sAfc]*\]\)?\^?(\d*)\s*\*?\s*)+),\s*(G\[[0-9,\[\]\sAfc]*\])\s*\]\s*")
graph_with_tp_pattern = re.compile(r"\s*(\+?-?)\s*(\d*/?\d*)\s*\*?\s*(G\[[0-9,\[\]\sAfc]*\])\s*\*\s*\(((?:\s*\+?-?\s*\d*/?\d*\s*\*?\s*T\[\s*(?:\(?(?:G\[[0-9,\[\]\sAfc]*\])\)?\^?\d*\s*\*?\s*)+\s*,\s*G\[[0-9,\[\]\sAfc]*\]\s*\])*)\s*\)\s*")
def get_graph_from_match(m):
"""Helper function: Parses a graph from a match."""
edges_string = m.group(3)
dict_W = {'A': 2, 'f': 1, 'c': 3}
global ym
ym = False
def gen_edges():
for m_e in edge_pattern.finditer(edges_string):
v1 = int(m_e.group(1))
v2 = int(m_e.group(2))
w = dict_W[m_e.group(4)] if m_e.group(3) == "," else 2
if m_e.group(3) == ",":
global ym
ym = True
yield (v1, v2, w)
edges_weights = tuple(gen_edges())
edges = [(v1, v2) for v1, v2, w in edges_weights]
weights = [w for v1, v2, w in edges_weights]
f1 = parse_fraction(m.group(2))
f2 = parse_fraction(m.group(4))
sign = -1 if "-" in m.group(1) else 1
return HopfGraph(edges, weights, 0), sign * f1 * f2, ym
def get_tensor_product_from_match(m):
"""Helper function: Parses a tensor product from a match."""
gprs = m.groups()
f1 = parse_fraction(gprs[1])
res_str = gprs[-1]
res_graph, res_fac, res_ym = get_graph_from_match(graph_pattern.match(res_str))
if res_fac != 1:
print(f"Warning strange input: {m.group(0)}", file=sys.stderr)
return None
def gen_sgs():
sbgrs_str = gprs[2]
for sg_m in graph_pattern_pow.finditer(sbgrs_str):
sg_str = sg_m.group(1)
exp_str = sg_m.group(2)
sg, sg_fac, sg_ym = get_graph_from_match(graph_pattern.match(sg_str))
if sg_fac != 1 or sg_ym != res_ym:
print(f"Warning strange input: {m.group(0)}", file=sys.stderr)
continue
p = 1 if not exp_str else int(exp_str)
yield sg, p
sgs = collections.Counter(dict(gen_sgs()))
return (tuple(sorted(sgs.items())), res_graph), f1, ym
def get_graph_with_tp_from_match(m):
gprs = m.groups()
f1 = parse_fraction(gprs[1])
g, g_fac, g_ym = get_graph_from_match(graph_pattern.match(gprs[2]))
if g_fac != 1:
print(f"Warning strange input: {m.group(0)}", file=sys.stderr)
tps_str = gprs[3]
def gen_tps():
for tp_m in tensor_product_pattern.finditer(tps_str):
if not tp_m:
print(f"Warning strange input: {m.group(0)}", file=sys.stderr)
continue
tp, fac, ym = get_tensor_product_from_match(tp_m)
if ym != g_ym:
print(f"Warning strange input: {m.group(0)}", file=sys.stderr)
continue
yield tp, fac
tp_sum = collections.Counter(dict(gen_tps()) if tps_str != (None,) else {})
return g, tp_sum, f1, g_ym
def parse_sum_of_graphs(string):
"""Parses a graph sum."""
for m in graph_pattern.finditer(string):
yield get_graph_from_match(m), m.start(), m.end()
def parse_sum_of_tensor_products(string):
"""Parses a tensor product sum."""
for m in tensor_product_pattern.finditer(string):
yield get_tensor_product_from_match(m), m.start(), m.end()
def parse_sum_of_graph_with_tp(string):
"""Parses a graph with tensor product sum."""
for m in graph_with_tp_pattern.finditer(string):
yield get_graph_with_tp_from_match(m), m.start(), m.end()
def not_parsable_check(s):
if s:
print("\n********************************", file=sys.stderr)
print(f"Warning: Could not parse this: {s}", file=sys.stderr)
print("********************************", file=sys.stderr)
end_pattern = re.compile(r"0?;\s*(.*)$")
def parse_input_lines(instream, outstream, string, parser_fun=parse_sum_of_graphs):
"""Parses a stream of input."""
for line in instream:
string += line
oldend = 0
for g_fac, strbeg, strend in parser_fun(string):
not_parsable_check(string[oldend:strbeg])
oldend = strend
yield g_fac
string = string[oldend:]
oldend = 0
for g_fac, strbeg, strend in parser_fun(string):
not_parsable_check(string[oldend:strbeg])
oldend = strend
yield g_fac
string = string[oldend:]
if string:
m = end_pattern.match(string)
if not m:
not_parsable_check(string)
else:
not_parsable_check(m.group(1))