-
Notifications
You must be signed in to change notification settings - Fork 10
/
compat_autoboot.py
184 lines (174 loc) · 8.21 KB
/
compat_autoboot.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
def admissible_min(x, y):
"""
Returns the minimum of the set obtained by taking the two arguments and
discarding those that are negative.
Parameters
----------
x: The first number.
y: The second number.
"""
if x < 0:
return y
if y < 0:
return x
return min(x, y)
def find_table(tab_list, symmetric, delta_12, delta_34):
"""
Searches a list of `ConvolvedBlockTable` instances for criteria given by the
last three arguments and returns the index of the first match or -1 if absent.
Parameters
----------
tab_list: The list to be searched.
symmetric: Whether the desired table should involve the sum of blocks in two
channels as opposed to the difference.
delta_12: The `delta_12` attribute of the desired table.
delta_34: The `delta_34` attribute of the desired table.
"""
for i in range(0, len(tab_list)):
if abs(delta_12 - tab_list[i].delta_12) > tiny:
continue
if abs(delta_34 - tab_list[i].delta_34) > tiny:
continue
if (symmetric == True and tab_list[i].m_order[0] % 2 == 0) or (symmetric == False and tab_list[i].m_order[0] % 2 == 1):
return i
return -1
def autoboot_sdp(dim, k_max, l_max, m_max, n_max, operators, equations):
"""
Returns an `SDP` generated by parsing strings which encode crossing equations.
These are assumed to be in the format of the Mathematica package autoboot by
Mocho Go and Yuji Tachikawa. Single blocks not part of a sum are currently
skipped and must be put into the `SDP` with `add_point`.
Parameters
----------
dim: The spatial dimension for the crossing equations.
k_max: Accuracy parameter for each `ConvolvedBlockTable` to be generated.
l_max: Maximum spin to include in each generated `ConvolvedBlockTable`.
m_max: First derivative cutoff parameter for each table.
n_max: Second derivative cutoff parameter for each table.
operators: A dictionary whose keys are the strings which have been used to
represent external operators in autoboot. The corresponding values
should be their scaling dimensions.
equations: A crossing equation string encoding the output of autoboot's
`bootAll` function. It must be expressed in input form and not
contain any new lines.
"""
vector_names = []
vector_types = []
possible_opes = []
conv_table_list = []
dim_list = list(operators.values())
# Hopefully this works in python2 as well
ope_symbol = "β"
depth = 0
marker = 5
eq_list = []
for i in range(5, len(equations) - 2):
if equations[i] == '[':
depth += 1
elif equations[i] == ']':
depth -= 1
elif equations[i] == ',' and depth == 0:
eq_list.append(equations[marker:i])
marker = i + 2
eq_list.append(equations[marker:-2])
# Get all types of exchanged operators
for eq in eq_list:
data = eq[:]
while ope_symbol in data:
m = re.search(r'\]\[[0-9]*\]\^2, |\]\[[0-9]*\], ', data)
pos0 = m.start()
pos1 = m.end()
pos2 = data.index("]]", pos1)
current_name = data[pos1:pos2 + 1]
ind1 = get_index(vector_names, current_name)
if ind1 == -1:
vector_names.append(current_name)
possible_opes.append([])
if "^2" in data[pos0:pos1]:
ind2 = data.rindex(ope_symbol, 0, pos0)
first = data[ind2:pos1 - 4]
second = first
else:
ind2 = data.rindex(ope_symbol, 0, pos0)
first = data[ind2:pos1 - 2]
ind3 = data.rindex(ope_symbol, 0, ind2 - 1)
second = data[ind3:ind2 - 1]
# This assumes autoboot sticks to a single convention for how the three operators are ordered
if first not in possible_opes[ind1]:
possible_opes[ind1].append(first)
if second not in possible_opes[ind1]:
possible_opes[ind1].append(second)
data = data[pos2 + 1:]
# Convert them to the format we use
for i in range(0, len(vector_names)):
name = vector_names[i]
size = len(possible_opes[i])
if "-1]" in name:
vector_types.append([[], 1, name])
else:
vector_types.append([[], 0, name])
for j in range(0, len(eq_list)):
outer_list = []
for r in range(0, size):
inner_list = []
for s in range(0, size):
inner_list.append([0, 0, 0, 0])
outer_list.append(inner_list)
vector_types[-1][0].append(outer_list)
for i in range(0, len(vector_types)):
for j in range(0, len(possible_opes[i])):
for k in range(j, len(possible_opes[i])):
for l in range(0, len(eq_list)):
# This assumes like terms have already been collected
if j == k:
ind = eq_list[l].find(possible_opes[i][j] + "^2")
else:
ind1 = eq_list[l].find(possible_opes[i][j] + "*" + possible_opes[i][k])
ind2 = eq_list[l].find(possible_opes[i][k] + "*" + possible_opes[i][j])
ind = admissible_min(ind1, ind2)
if ind == -1:
continue
if eq_list[l].index("]") >= ind - 2:
pos0 = eq_list[l].index("sum")
coeff = eq_list[l][:pos0].replace('*', '').replace(' ', '')
else:
data = eq_list[l][ind:0:-1]
m = re.search(r"mus[*]?[0-9]* [\+|\-]", data)
coeff = m.group()[-1:3:-1]
coeff = coeff.replace('*', '').replace(' ', '')
if '/' in coeff:
parts = coeff.split('/')
coeff = Rational(parts[0], parts[1])
#coeff = float(parts[0]) / float(parts[1])
elif coeff == '' or coeff == '+':
coeff = 1
elif coeff == '-':
coeff = -1
else:
coeff = float(coeff)
vector_types[i][0][l][j][k][0] += 0.5 * coeff
vector_types[i][0][l][k][j][0] += 0.5 * coeff
pos1 = eq_list[l].rindex('[', 0, ind)
block_string = eq_list[l][pos1 + 1:ind - 2].replace(' ', '')
parts = block_string.split(',')
vector_types[i][0][l][j][k][2] = get_index_approx(dim_list, operators[parts[1]])
vector_types[i][0][l][k][j][2] = get_index_approx(dim_list, operators[parts[1]])
vector_types[i][0][l][j][k][3] = get_index_approx(dim_list, operators[parts[2]])
vector_types[i][0][l][k][j][3] = get_index_approx(dim_list, operators[parts[2]])
delta_12 = operators[parts[0]] - operators[parts[1]]
delta_34 = operators[parts[2]] - operators[parts[3]]
if eq_list[l][pos1 - 1] == 'H':
symmetric = True
else:
symmetric = False
pos2 = find_table(conv_table_list, symmetric, delta_12, delta_34)
if pos2 == -1:
# This is slightly wasteful because a few tables will only be used for even spins
# Also because not every table appears with both symmetric and antisymmetric versions
tab = ConformalBlockTable(dim, k_max, l_max, m_max, n_max, delta_12, delta_34, True)
conv_table_list.append(ConvolvedBlockTable(tab, symmetric = False))
conv_table_list.append(ConvolvedBlockTable(tab, symmetric = True))
pos2 = find_table(conv_table_list, symmetric, delta_12, delta_34)
vector_types[i][0][l][j][k][1] = pos2
vector_types[i][0][l][k][j][1] = pos2
return SDP(dim_list, conv_table_list, vector_types)