computation up to 11 crossing ok, for larger knots the algorithm does not work
This commit is contained in:
parent
7836c158c7
commit
4625bde375
332
blanchfield.sage
Normal file
332
blanchfield.sage
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
class MySettings(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
self.f_pd_knot_11_15 = os.path.join(os.getcwd(), "knots_11_to_15.txt")
|
||||||
|
self.f_knot_up_to_10 = os.path.join(os.getcwd(), "knots_3_to_10.txt")
|
||||||
|
|
||||||
|
|
||||||
|
class Crossing(object):
|
||||||
|
|
||||||
|
def __init__(self, c_idx, paired_ind, complex, previous):
|
||||||
|
|
||||||
|
self.c_idx = c_idx
|
||||||
|
self.paired_ind = paired_ind
|
||||||
|
self.previous = previous
|
||||||
|
|
||||||
|
self.G = complex.knot.fundamental_group()
|
||||||
|
self.F = self.G.free_group()
|
||||||
|
self.pd = complex.pd_code[c_idx]
|
||||||
|
if paired_ind is not None:
|
||||||
|
self.edge = self.pd[paired_ind]
|
||||||
|
else:
|
||||||
|
self.edge = None
|
||||||
|
self.orientation = complex.orientation[c_idx]
|
||||||
|
self.pd_sign = self.get_pd_sign()
|
||||||
|
self.element = self.set_element(complex)
|
||||||
|
|
||||||
|
self.done = False
|
||||||
|
self.path_by_edges = []
|
||||||
|
self.w_i = self.F([])
|
||||||
|
|
||||||
|
def set_w_i(self, complex):
|
||||||
|
w_i = self.F([])
|
||||||
|
path = self.get_path_by_edges(None)
|
||||||
|
for edge in path:
|
||||||
|
arc = complex.get_arc(abs(edge))
|
||||||
|
g = self.F([arc+1])
|
||||||
|
if edge < 0:
|
||||||
|
g = g.inverse()
|
||||||
|
w_i *= g
|
||||||
|
self.path_by_edges = path
|
||||||
|
self.w_i = w_i
|
||||||
|
|
||||||
|
def get_path_by_edges(self, edge):
|
||||||
|
path_by_edges = []
|
||||||
|
if self.previous is not None:
|
||||||
|
path_by_edges.extend(self.previous.get_path_by_edges(self.edge))
|
||||||
|
if edge is not None:
|
||||||
|
idx = self.pd.index(edge)
|
||||||
|
else:
|
||||||
|
idx = None
|
||||||
|
path_by_edges.extend(self.get_correction(idx))
|
||||||
|
return path_by_edges
|
||||||
|
|
||||||
|
def get_correction(self, ind_to_pair):
|
||||||
|
path = []
|
||||||
|
correction_in = self.calculate_correction_in(ind_to_pair)
|
||||||
|
if self.previous is not None:
|
||||||
|
ind_to_pair = self.previous.pd.index(self.edge)
|
||||||
|
p_out = self.previous.calculate_correction_out(ind_to_pair)
|
||||||
|
path.extend(p_out)
|
||||||
|
path.extend(correction_in)
|
||||||
|
return path
|
||||||
|
|
||||||
|
def calculate_correction_in(self, ind_to_pair):
|
||||||
|
path_out = self.calculate_correction_out(ind_to_pair)
|
||||||
|
ind = self.paired_ind
|
||||||
|
if ind is None or ind == 0:
|
||||||
|
return []
|
||||||
|
pd = self.pd_sign
|
||||||
|
if ind == 3:
|
||||||
|
return [pd[3]]
|
||||||
|
if ind == 1 and len(path_out) > 2:
|
||||||
|
return [pd[1], pd[2], pd[3]]
|
||||||
|
if ind == 2 and len(path_out) > 1:
|
||||||
|
return [pd[2], pd[3]]
|
||||||
|
if ind == 1:
|
||||||
|
return [-pd[0]]
|
||||||
|
return [-pd[1], -pd[0]] # ind == 2
|
||||||
|
|
||||||
|
def calculate_correction_out(self, ind_to_pair):
|
||||||
|
path = []
|
||||||
|
if ind_to_pair is not None:
|
||||||
|
if ind_to_pair < 3:
|
||||||
|
path.append(-self.pd_sign[3])
|
||||||
|
if ind_to_pair < 2:
|
||||||
|
path.append(-self.pd_sign[2])
|
||||||
|
if ind_to_pair < 1:
|
||||||
|
path.append(-self.pd_sign[1])
|
||||||
|
return path
|
||||||
|
|
||||||
|
def set_element(self, complex):
|
||||||
|
loop = self.set_loop(complex)
|
||||||
|
relation = self.F([])
|
||||||
|
for element in loop:
|
||||||
|
relation *= element
|
||||||
|
return relation
|
||||||
|
|
||||||
|
def set_loop(self, complex):
|
||||||
|
F = self.F
|
||||||
|
loop = []
|
||||||
|
for edge in self.pd_sign:
|
||||||
|
arc = complex.get_arc(abs(edge))
|
||||||
|
g = F([arc+1])
|
||||||
|
if edge < 0:
|
||||||
|
g = g.inverse()
|
||||||
|
loop.append(g)
|
||||||
|
return loop
|
||||||
|
|
||||||
|
def get_pd_sign(self):
|
||||||
|
pd = []
|
||||||
|
pd.append(self.pd[0])
|
||||||
|
if self.orientation == 1:
|
||||||
|
pd.append(self.pd[1])
|
||||||
|
pd.append(-self.pd[2])
|
||||||
|
pd.append(-self.pd[3])
|
||||||
|
else:
|
||||||
|
pd.append(-self.pd[1])
|
||||||
|
pd.append(-self.pd[2])
|
||||||
|
pd.append(self.pd[3])
|
||||||
|
return pd
|
||||||
|
|
||||||
|
|
||||||
|
class TwistedChainComplex(object):
|
||||||
|
"""
|
||||||
|
This class implements twisted Blanchfield pairing
|
||||||
|
of a zero-surgery of a knot.
|
||||||
|
"""
|
||||||
|
def __init__(self, knot, field=RationalField(), images=None):
|
||||||
|
self.knot = knot
|
||||||
|
self.crossings_list = []
|
||||||
|
|
||||||
|
self.pd_code = self.knot.pd_code()
|
||||||
|
self.visited = [False] * len(self.pd_code)
|
||||||
|
|
||||||
|
self.orientation = self.knot.orientation()
|
||||||
|
# self.field = field
|
||||||
|
# self.ring = LaurentPolynomialRing(self.field, 'T')
|
||||||
|
# self.pol_ring = self.ring.polynomial_ring()
|
||||||
|
# self.T = self.ring.gen()
|
||||||
|
# self.TT = self.pol_ring.gen()
|
||||||
|
self.overcrossing_seq = []
|
||||||
|
self.G = self.get_fundamental_group()
|
||||||
|
assert self.G.abelian_invariants() == (0,)
|
||||||
|
|
||||||
|
def get_fundamental_group(self):
|
||||||
|
G = self.knot.fundamental_group()
|
||||||
|
pd_code = self.pd_code
|
||||||
|
orientation = self.knot.orientation()
|
||||||
|
writhe = self.knot.writhe()
|
||||||
|
arc = self.get_arc(1)
|
||||||
|
overcrossing_seq = [0] * len(pd_code)
|
||||||
|
longitude = G([arc + 1] * abs(writhe))
|
||||||
|
if writhe > 0:
|
||||||
|
longitude = longitude.inverse()
|
||||||
|
for entry in range(1, 2 * len(pd_code) + 1):
|
||||||
|
for idx, pd in enumerate(pd_code):
|
||||||
|
if entry == pd[0]:
|
||||||
|
# print "undercrossing pd[0]"
|
||||||
|
overcrossing_seq[idx] = longitude
|
||||||
|
overcrossing = pd[1]
|
||||||
|
arc = self.get_arc(overcrossing)
|
||||||
|
g = G([arc + 1])
|
||||||
|
if orientation[idx] == -1:
|
||||||
|
g = g.inverse()
|
||||||
|
overcrossing = -overcrossing
|
||||||
|
longitude *= g
|
||||||
|
break
|
||||||
|
elif entry == pd[1] and orientation[idx] == 1:
|
||||||
|
# print "overcrossing pd[1]"
|
||||||
|
break
|
||||||
|
elif entry == pd[3] and orientation[idx] == -1:
|
||||||
|
# print "overcrossing pd[3]"
|
||||||
|
break
|
||||||
|
relations = list(G.relations())
|
||||||
|
relations.append(longitude)
|
||||||
|
F = G.free_group().quotient(relations)
|
||||||
|
self.overcrossing_seq = overcrossing_seq
|
||||||
|
return F
|
||||||
|
|
||||||
|
def get_crossings_list(self):
|
||||||
|
pd_code = self.pd_code
|
||||||
|
pd_ind = 0 # current crossing id
|
||||||
|
paired_ind = None # position for a paired edge
|
||||||
|
crossing = None
|
||||||
|
while not all(self.visited):
|
||||||
|
self.visited[pd_ind] = True
|
||||||
|
crossing = Crossing(pd_ind, paired_ind, self, crossing)
|
||||||
|
self.crossings_list.append(crossing)
|
||||||
|
pd = crossing.pd
|
||||||
|
for i in reversed(range(4)):
|
||||||
|
pd_ind, paired_ind = self.find_next(crossing.c_idx, pd[i])
|
||||||
|
if not self.visited[pd_ind]:
|
||||||
|
break
|
||||||
|
elif self.visited[pd_ind] and i == 0:
|
||||||
|
if all(self.visited):
|
||||||
|
break
|
||||||
|
crossing, pd_ind, paired_ind = self.find_previous()
|
||||||
|
return self.crossings_list
|
||||||
|
|
||||||
|
def compute_wi(self):
|
||||||
|
|
||||||
|
F = self.G.free_group()
|
||||||
|
self.crossings_list = self.get_crossings_list()
|
||||||
|
crossings_list = self.crossings_list
|
||||||
|
null_loop = F([])
|
||||||
|
full_walk = [] # conjugated elements
|
||||||
|
big_lst = [] # elements
|
||||||
|
|
||||||
|
for c in crossings_list:
|
||||||
|
c.set_w_i(self)
|
||||||
|
|
||||||
|
for c in crossings_list[::-1]:
|
||||||
|
lst = []
|
||||||
|
walk = []
|
||||||
|
p = c
|
||||||
|
while p is not None:
|
||||||
|
if not p.done:
|
||||||
|
g = p.w_i * p.element * p.w_i.inverse()
|
||||||
|
walk.append(g)
|
||||||
|
lst.append(p)
|
||||||
|
p.done = True
|
||||||
|
p = p.previous
|
||||||
|
full_walk.extend(walk[::-1])
|
||||||
|
big_lst.extend(lst[::-1])
|
||||||
|
|
||||||
|
for el in full_walk:
|
||||||
|
null_loop *= el
|
||||||
|
|
||||||
|
if null_loop != F([]):
|
||||||
|
n_loop = F([])
|
||||||
|
for c in crossings_list:
|
||||||
|
n_loop *= c.w_i * c.element * c.w_i.inverse()
|
||||||
|
if n_loop == F([]):
|
||||||
|
return -1
|
||||||
|
print "n_loop = " + str(n_loop)
|
||||||
|
return 0
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def find_previous(self):
|
||||||
|
previous = None
|
||||||
|
for c in self.crossings_list:
|
||||||
|
for i in reversed(range(4)):
|
||||||
|
new_ind, paired_ind = self.find_next(c.c_idx, c.pd[i])
|
||||||
|
if not self.visited[new_ind]:
|
||||||
|
previous = c
|
||||||
|
break
|
||||||
|
if previous is not None:
|
||||||
|
break
|
||||||
|
if previous is None:
|
||||||
|
raise ValueError("This knot is to difficult or doesn't exist.")
|
||||||
|
return previous, new_ind, paired_ind
|
||||||
|
|
||||||
|
def find_next(self, pd_ind, edge):
|
||||||
|
pd_code = self.pd_code
|
||||||
|
for ind, pd in enumerate(pd_code):
|
||||||
|
if ind == pd_ind:
|
||||||
|
continue
|
||||||
|
if edge in pd:
|
||||||
|
return ind, pd.index(edge)
|
||||||
|
raise ValueError("The knot.pd_code is incorrect.")
|
||||||
|
|
||||||
|
def get_arc(self, edge):
|
||||||
|
arcs = self.knot.arcs()
|
||||||
|
for idx, arc in enumerate(arcs):
|
||||||
|
if edge in arc:
|
||||||
|
return idx
|
||||||
|
|
||||||
|
|
||||||
|
def parse_pd_code(pd_code_from_file):
|
||||||
|
set = '0987654321[],'
|
||||||
|
pd_code = ''.join([c for c in pd_code_from_file if c in set])
|
||||||
|
return eval(pd_code)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_knot_name(name):
|
||||||
|
data = name[5: -2].split(',')
|
||||||
|
name = data[0].strip() + data[1].strip().lower()[:1] + data[2].strip()
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
def check_11_to_15(f_out=None):
|
||||||
|
with open(settings.f_pd_knot_11_15, 'r') as f:
|
||||||
|
line = f.readline()
|
||||||
|
while line:
|
||||||
|
name = parse_knot_name(line)
|
||||||
|
pd_code = parse_pd_code(f.readline())
|
||||||
|
line = f.readline()
|
||||||
|
knot = Link(pd_code)
|
||||||
|
C = TwistedChainComplex(knot)
|
||||||
|
result = C.compute_wi()
|
||||||
|
if result == 1:
|
||||||
|
# print C.knot.is_alternating()
|
||||||
|
pass
|
||||||
|
# print "ok"
|
||||||
|
# elif result == -1:
|
||||||
|
# print name
|
||||||
|
elif result == 0:
|
||||||
|
print "ERROR while checking " + str(name)
|
||||||
|
|
||||||
|
|
||||||
|
def check_up_to_10(f_out=None):
|
||||||
|
with open(settings.f_knot_up_to_10, 'r') as f:
|
||||||
|
line = f.readline()
|
||||||
|
while line:
|
||||||
|
line = line.split(" = ")
|
||||||
|
name = str(line[0])[5:]
|
||||||
|
pd_code = parse_pd_code(str(line[1]))
|
||||||
|
line = f.readline()
|
||||||
|
knot = Link(pd_code)
|
||||||
|
C = TwistedChainComplex(knot)
|
||||||
|
if C.compute_wi() == 1:
|
||||||
|
# print C.knot.is_alternating()
|
||||||
|
print "ok"
|
||||||
|
else:
|
||||||
|
print "!!!!!!!!!!!!!!"
|
||||||
|
print knot
|
||||||
|
print "!!!!!!!!!!!!!!"
|
||||||
|
|
||||||
|
def perform_test():
|
||||||
|
# check_up_to_10()
|
||||||
|
check_11_to_15()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
settings = MySettings()
|
||||||
|
perform_test()
|
Loading…
Reference in New Issue
Block a user