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