classes as separate module
This commit is contained in:
parent
1cc1de2e04
commit
0110e6161c
516
cable_signature.sage
Normal file
516
cable_signature.sage
Normal file
@ -0,0 +1,516 @@
|
||||
#!/usr/bin/python
|
||||
import collections
|
||||
|
||||
|
||||
class TorusCable(object):
|
||||
def __init__(self, knot_formula, k_vector=None, q_vector=None):
|
||||
# q_i = 2 * k_i + 1
|
||||
|
||||
if k_vector is None:
|
||||
if q_vector is None:
|
||||
# TBD docstring
|
||||
print("Please give a list of k (k_vector) \
|
||||
or q values (q_vector).")
|
||||
return None
|
||||
else:
|
||||
k_vector = [(q - 1)/2 for q in q_vector]
|
||||
elif q_vector is None:
|
||||
q_vector = [2 * k + 1 for k in k_vector]
|
||||
self.knot_formula = knot_formula
|
||||
self.k_vector = k_vector
|
||||
self.q_vector = q_vector
|
||||
k = k_vector
|
||||
self.knot_sum = eval(knot_formula)
|
||||
self.knot_description = self.get_knot_descrption()
|
||||
self.__sigma_function = None
|
||||
self.__signature_as_function_of_theta = None
|
||||
|
||||
def get_knot_descrption(self):
|
||||
description = ""
|
||||
for knot in self.knot_sum:
|
||||
if knot[0] < 0:
|
||||
description += "-"
|
||||
description += "T("
|
||||
for k in knot:
|
||||
description += "2, " + str(2 * abs(k) + 1) + "; "
|
||||
description = description[:-2] + ") # "
|
||||
return description[:-3]
|
||||
|
||||
# searching for signature == 0
|
||||
def get_signature_as_function_of_theta(self, verbose=False):
|
||||
if self.__signature_as_function_of_theta is None:
|
||||
self.__signature_as_function_of_theta = \
|
||||
self.__get_signature_as_function_of_theta(verbose=verbose)
|
||||
return self.__signature_as_function_of_theta
|
||||
|
||||
# searching for signature == 0
|
||||
def __get_signature_as_function_of_theta(self, **key_args):
|
||||
if 'verbose' in key_args:
|
||||
verbose_default = key_args['verbose']
|
||||
else:
|
||||
verbose_default = False
|
||||
def signature_as_function_of_theta(*thetas, **kwargs):
|
||||
verbose = verbose_default
|
||||
if 'verbose' in kwargs:
|
||||
verbose = kwargs['verbose']
|
||||
len_a = len(self.knot_sum)
|
||||
len_t = len(thetas)
|
||||
|
||||
# call with no arguments
|
||||
if len_t == 0:
|
||||
return signature_as_function_of_theta(*(len_a * [0]))
|
||||
|
||||
if len_t != len_a:
|
||||
msg = "This function takes exactly " + str(len_a) + \
|
||||
" arguments or no argument at all (" + str(len_t) + \
|
||||
" given)."
|
||||
raise TypeError(msg)
|
||||
|
||||
sf = SignatureFunction()
|
||||
|
||||
# for each cable knot in cable sum apply theta
|
||||
for i, knot in enumerate(self.knot_sum):
|
||||
try:
|
||||
ssf = get_signature_summand_as_theta_function(*knot)
|
||||
sf += ssf(thetas[i])
|
||||
# in case wrong theata value was given
|
||||
except ValueError as e:
|
||||
print("ValueError: " + str(e.args[0]) +\
|
||||
" Please change " + str(i + 1) + ". parameter.")
|
||||
return None
|
||||
if verbose:
|
||||
print()
|
||||
print(str(thetas))
|
||||
print(sf)
|
||||
return sf
|
||||
signature_as_function_of_theta.__doc__ =\
|
||||
signature_as_function_of_theta_docstring
|
||||
return signature_as_function_of_theta
|
||||
|
||||
# searching for signature == 0
|
||||
def check_for_null_theta_combinations(self, verbose=False):
|
||||
list_of_good_vectors= []
|
||||
number_of_null_comb = 0
|
||||
f = self.get_signature_as_function_of_theta(verbose=verbose)
|
||||
range_list = [range(abs(knot[-1]) + 1) for knot in self.knot_sum]
|
||||
for theta_vector in it.product(*range_list):
|
||||
if f(*theta_vector, verbose=False).is_zero_everywhere():
|
||||
list_of_good_vectors.append(theta_vector)
|
||||
m = len([theta for theta in theta_vector if theta != 0])
|
||||
number_of_null_comb += 2^m
|
||||
return number_of_null_comb, list_of_good_vectors
|
||||
|
||||
# searching for signature == 0
|
||||
def eval_cable_for_null_signature(self, print_results=False, verbose=False):
|
||||
# search for zero combinations
|
||||
number_of_all_comb = self.get_number_of_combinations_of_theta()
|
||||
result = self.check_for_null_theta_combinations(verbose=verbose)
|
||||
number_of_null_comb, list_of_good_vectors = result
|
||||
|
||||
if print_results:
|
||||
print()
|
||||
print(self.knot_description)
|
||||
print("Zero cases: " + str(number_of_null_comb))
|
||||
print("All cases: " + str(number_of_all_comb))
|
||||
print("Zero theta combinations: ")
|
||||
for el in list_of_good_vectors:
|
||||
print(el)
|
||||
if number_of_null_comb^2 >= number_of_all_comb:
|
||||
return number_of_null_comb, number_of_all_comb
|
||||
return None
|
||||
|
||||
# check sigma for all v = s * [a_1, a_2, a_3, a_4] for s in [1, q_4 - 1]
|
||||
def __is_sigma_for_vector_class_big(self, theta_vector):
|
||||
[a_1, a_2, a_3, a_4] = theta_vector
|
||||
q_4 = self.q_vector[3]
|
||||
for shift in range(1, q_4):
|
||||
shifted_theta = [(shift * a) % q_4 for a in
|
||||
[a_1, a_2, a_3, a_4]]
|
||||
sigma_v = self.__sigma_function(shifted_theta)
|
||||
if abs(sigma_v) > 5 + np.count_nonzero(shifted_theta):
|
||||
return True
|
||||
return False
|
||||
|
||||
def __tmp_print_all_sigma_for_vector_class(self, theta_vector):
|
||||
print("\n")
|
||||
print(self.knot_description)
|
||||
print("vector = " + str(theta_vector))
|
||||
[a_1, a_2, a_3, a_4] = theta_vector
|
||||
q_4 = self.q_vector[3]
|
||||
for shift in range(1, q_4):
|
||||
shifted_theta = [(shift * a) % q_4 for a in
|
||||
[a_1, a_2, a_3, a_4]]
|
||||
print(str(shifted_theta) + "\t\t" + \
|
||||
str(self.__sigma_function(shifted_theta)))
|
||||
print("\n")
|
||||
|
||||
def __tmp_get_max_sigma_for_vector_class(self, theta_vector):
|
||||
# print("\n")
|
||||
# print(self.knot_description)
|
||||
# print("vector = " + str(theta_vector))
|
||||
max_sigma = (theta_vector, 0)
|
||||
[a_1, a_2, a_3, a_4] = theta_vector
|
||||
q_4 = self.q_vector[3]
|
||||
for shift in range(1, q_4):
|
||||
shifted_theta = [(shift * a) % q_4 for a in
|
||||
[a_1, a_2, a_3, a_4]]
|
||||
sigma = self.__sigma_function(shifted_theta)
|
||||
if abs(sigma) > abs(max_sigma[1]):
|
||||
max_sigma = (shifted_theta, sigma)
|
||||
assert max_sigma[1] == 0, knot_description
|
||||
# print("\n" + self.knot_description + "\t" + str(max_sigma[0]) +\
|
||||
# "\t" + str(max_sigma[1]))
|
||||
return max_sigma[1]
|
||||
|
||||
|
||||
|
||||
def is_sigma_for_vector_class_big(self, theta_vector):
|
||||
if self.__sigma_function is None:
|
||||
self.__sigma_function = self.__get_sigma_function()
|
||||
return self.__is_sigma_for_vector_class_big(theta_vector)
|
||||
|
||||
def __get_sigma_function(self):
|
||||
k_1, k_2, k_3, k_4 = [abs(k) for k in self.k_vector]
|
||||
q_4 = 2 * k_4 + 1
|
||||
ksi = 1/q_4
|
||||
sigma_q_1 = get_untwisted_signature_function(k_1)
|
||||
sigma_q_2 = get_untwisted_signature_function(k_2)
|
||||
sigma_q_3 = get_untwisted_signature_function(k_3)
|
||||
|
||||
def sigma_function(theta_vector, print_results=False):
|
||||
# "untwisted" part (Levine-Tristram signatures)
|
||||
a_1, a_2, a_3, a_4 = theta_vector
|
||||
untwisted_part = 2 * (sigma_q_2(ksi * a_1) -
|
||||
sigma_q_2(ksi * a_2) +
|
||||
sigma_q_3(ksi * a_3) -
|
||||
sigma_q_3(ksi * a_4) +
|
||||
sigma_q_1(ksi * a_1 * 2) -
|
||||
sigma_q_1(ksi * a_4 * 2))
|
||||
# "twisted" part
|
||||
tp = [0, 0, 0, 0]
|
||||
for i, a in enumerate(theta_vector):
|
||||
if a:
|
||||
tp[i] = -q_4 + 2 * a - 2 * (a^2/q_4)
|
||||
twisted_part = tp[0] - tp[1] + tp[2] - tp[3]
|
||||
# if print_results:
|
||||
# self.print_results_LT(theta_vector, untwisted_part)
|
||||
# self.print_results_LT(theta_vector, twisted_part)
|
||||
|
||||
sigma_v = untwisted_part + twisted_part
|
||||
return sigma_v
|
||||
return sigma_function
|
||||
|
||||
def print_results_LT(self, theta_vector, untwisted_part):
|
||||
knot_description = self.knot_description
|
||||
k_1, k_2, k_3, k_4 = [abs(k) for k in self.k_vector]
|
||||
a_1, a_2, a_3, a_4 = theta_vector
|
||||
q_4 = 2 * k_4 + 1
|
||||
ksi = 1/q_4
|
||||
sigma_q_1 = get_untwisted_signature_function(k_1)
|
||||
sigma_q_2 = get_untwisted_signature_function(k_2)
|
||||
sigma_q_3 = get_untwisted_signature_function(k_3)
|
||||
print("\n\nLevine-Tristram signatures for the cable sum: ")
|
||||
print(knot_description)
|
||||
print("and characters:\n" + str(theta_vector) + ",")
|
||||
print("ksi = " + str(ksi))
|
||||
print("\n\n2 * (sigma_q_2(ksi * a_1) + " + \
|
||||
"sigma_q_1(ksi * a_1 * 2) - " +\
|
||||
"sigma_q_2(ksi * a_2) + " +\
|
||||
"sigma_q_3(ksi * a_3) - " +\
|
||||
"sigma_q_3(ksi * a_4) - " +\
|
||||
"sigma_q_1(ksi * a_4 * 2))" +\
|
||||
\
|
||||
" = \n\n2 * (sigma_q_2(" + \
|
||||
str(ksi) + " * " + str(a_1) + \
|
||||
") + sigma_q_1(" + \
|
||||
str(ksi) + " * " + str(a_1) + " * 2" + \
|
||||
") - sigma_q_2(" + \
|
||||
str(ksi) + " * " + str(a_2) + \
|
||||
") + sigma_q_3(" + \
|
||||
str(ksi) + " * " + str(a_3) + \
|
||||
") - sigma_q_3(" + \
|
||||
str(ksi) + " * " + str(a_4) + \
|
||||
") - sigma_q_1(" + \
|
||||
str(ksi) + " * " + str(a_4) + " * 2)) " + \
|
||||
\
|
||||
" = \n\n2 * (sigma_q_2(" + \
|
||||
str(mod_one(ksi * a_1)) + \
|
||||
") + sigma_q_1(" + \
|
||||
str(mod_one(ksi * a_1 * 2)) + \
|
||||
") - sigma_q_2(" + \
|
||||
str(mod_one(ksi * a_2)) + \
|
||||
") + sigma_q_3(" + \
|
||||
str(mod_one(ksi * a_3)) + \
|
||||
") - sigma_q_3(" + \
|
||||
str(mod_one(ksi * a_4)) + \
|
||||
") - sigma_q_1(" + \
|
||||
str(mod_one(ksi * a_4 * 2)) + \
|
||||
\
|
||||
") = \n\n2 * ((" + \
|
||||
str(sigma_q_2(ksi * a_1)) + \
|
||||
") + (" + \
|
||||
str(sigma_q_1(ksi * a_1 * 2)) + \
|
||||
") - (" + \
|
||||
str(sigma_q_2(ksi * a_2)) + \
|
||||
") + (" + \
|
||||
str(sigma_q_3(ksi * a_3)) + \
|
||||
") - (" + \
|
||||
str(sigma_q_3(ksi * a_4)) + \
|
||||
") - (" + \
|
||||
str(sigma_q_1(ksi * a_4 * 2)) + ")) = " + \
|
||||
"\n\n2 * (" + \
|
||||
str(sigma_q_2(ksi * a_1) +
|
||||
sigma_q_1(ksi * a_1 * 2) -
|
||||
sigma_q_2(ksi * a_2) +
|
||||
sigma_q_3(ksi * a_3) -
|
||||
sigma_q_3(ksi * a_4) -
|
||||
sigma_q_1(ksi * a_4 * 2)) + \
|
||||
") = " + str(untwisted_part))
|
||||
print("\nSignatures:")
|
||||
print("\nq_1 = " + str(2 * k_1 + 1) + ": " + repr(sigma_q_1))
|
||||
print("\nq_2 = " + str(2 * k_2 + 1) + ": " + repr(sigma_q_2))
|
||||
print("\nq_3 = " + str(2 * k_3 + 1) + ": " + repr(sigma_q_3))
|
||||
|
||||
def get_number_of_combinations_of_theta(self):
|
||||
number_of_combinations = 1
|
||||
for knot in self.knot_sum:
|
||||
number_of_combinations *= (2 * abs(knot[-1]) + 1)
|
||||
return number_of_combinations
|
||||
|
||||
def print_results_sigma(self, theta_vector, twisted_part):
|
||||
a_1, a_2, a_3, a_4 = theta_vector
|
||||
knot_description = self.knot_description
|
||||
q_4 = self.q_vector[-1]
|
||||
print("\n\nSigma values for the cable sum: ")
|
||||
print(knot_description)
|
||||
print("and characters: " + str(v_theta))
|
||||
print("\nsigma(T_{2, q_4}, ksi_a) = " + \
|
||||
"-q + (2 * a * (q_4 - a)/q_4) " +\
|
||||
"= -q + 2 * a - 2 * a^2/q_4 if a != 0,\n\t\t\t" +\
|
||||
" = 0 if a == 0.")
|
||||
print("\nsigma(T_{2, q_4}, chi_a_1) = ", end="")
|
||||
if a_1:
|
||||
print("- (" + str(q_4) + ") + 2 * " + str(a_1) + " + " +\
|
||||
"- 2 * " + str(a_1^2) + "/" + str(q_4) + \
|
||||
" = " + str(tp[0]))
|
||||
else:
|
||||
print("0")
|
||||
print("\nsigma(T_{2, q_4}, chi_a_2) = ", end ="")
|
||||
if a_2:
|
||||
print("- (" + str(q_4) + ") + 2 * " + str(a_2) + " + " +\
|
||||
"- 2 * " + str(a_2^2) + "/" + str(q_4) + \
|
||||
" = " + str(tp[1]))
|
||||
else:
|
||||
print("0", end="")
|
||||
print("\nsigma(T_{2, q_4}, chi_a_3) = ", end="")
|
||||
if a_3:
|
||||
print("- (" + str(q_4) + ") + 2 * " + str(a_3) + " + " +\
|
||||
"- 2 * " + str(a_3^2) + "/" + str(q_4) + \
|
||||
" = " + str(tp[2]))
|
||||
else:
|
||||
print("0", end="")
|
||||
print("\nsigma(T_{2, q_4}, chi_a_4) = ", end="")
|
||||
if a_4:
|
||||
print("- (" + str(q_4) + ") + 2 * " + str(a_4) + " + " +\
|
||||
"- 2 * " + str(a_4^2) + "/" + str(q_4) + \
|
||||
" = " + str(tp[3]))
|
||||
else:
|
||||
print("0")
|
||||
|
||||
print("\n\nsigma(T_{2, q_4}, chi_a_1) " + \
|
||||
"- sigma(T_{2, q_4}, chi_a_2) " + \
|
||||
"+ sigma(T_{2, q_4}, chi_a_3) " + \
|
||||
"- sigma(T_{2, q_4}, chi_a_4) =\n" + \
|
||||
"sigma(T_{2, q_4}, " + str(a_1) + \
|
||||
") - sigma(T_{2, q_4}, " + str(a_2) + \
|
||||
") + sigma(T_{2, q_4}, " + str(a_3) + \
|
||||
") - sigma(T_{2, q_4}, " + str(a_4) + ") = " + \
|
||||
str(tp[0] - tp[1] + tp[2] - tp[3]))
|
||||
|
||||
# searching for sigma > 5 + #(v_i != 0)
|
||||
def calculate_sigma(self, theta_vector):
|
||||
if self.__sigma_function is None:
|
||||
self.__sigma_function = self.__get_sigma_function()
|
||||
return self.__sigma_function(theta_vector)
|
||||
|
||||
|
||||
# searching for sigma > 5 + #(v_i != 0)
|
||||
def __check_combinations_in_range(self, range_product):
|
||||
large_sigma_for_all_combinations = True
|
||||
bad_vectors = []
|
||||
good_vectors = []
|
||||
q_4 = self.q_vector[-1]
|
||||
for vector in range_product:
|
||||
a_1, a_2, a_3, a_4 = vector
|
||||
if (a_1^2 - a_2^2 + a_3^2 - a_4^2) % q_4:
|
||||
continue
|
||||
if all(a in [1, q_4 - 1] for a in vector):
|
||||
is_all_one = True
|
||||
else:
|
||||
is_all_one = False
|
||||
if self.__is_sigma_for_vector_class_big(vector):
|
||||
good_vectors.append(vector)
|
||||
# if is_all_one:
|
||||
# print("\nHURA" * 100)
|
||||
# print(self.knot_description)
|
||||
# self.__tmp_print_all_sigma_for_vector_class(vector)
|
||||
# pass
|
||||
else:
|
||||
if is_all_one:
|
||||
self.__tmp_get_max_sigma_for_vector_class(vector)
|
||||
bad_vectors.append(vector)
|
||||
#####################################################
|
||||
if len(bad_vectors) > 8:
|
||||
break
|
||||
####################################################
|
||||
large_sigma_for_all_combinations = False
|
||||
return good_vectors, bad_vectors
|
||||
|
||||
# searching for sigma > 5 + #(v_i != 0)
|
||||
def check_combinations_in_range(self, range_product):
|
||||
if self.__sigma_function is None:
|
||||
self.__sigma_function = self.__get_sigma_function()
|
||||
return self.__check_combinations_in_range(range_product)
|
||||
|
||||
# searching for sigma > 5 + #(v_i != 0)
|
||||
def __check_all_combinations_in_ranges(self, list_of_ranges,
|
||||
print_results=True):
|
||||
all_combinations_pass = True
|
||||
all_bad_vectors = []
|
||||
number_of_all_good_v = 0
|
||||
for i, range_product in enumerate(list_of_ranges):
|
||||
good_v, bad_v = self.__check_combinations_in_range(range_product)
|
||||
number_of_all_good_v += len(good_v)
|
||||
all_bad_vectors = list(it.chain(all_bad_vectors, bad_v))
|
||||
if bad_v:
|
||||
all_combinations_pass = False
|
||||
if len(all_bad_vectors) > 8:
|
||||
break
|
||||
# if print_results:
|
||||
# print("good : bad:\t " + str(len(good_v)) +\
|
||||
# " : " + str(len(bad_v)))
|
||||
# if i in [0, 4,]:
|
||||
# print()
|
||||
# if bad_v:
|
||||
# print(bad_v)
|
||||
|
||||
if print_results:
|
||||
print("good : bad:\t " + str(number_of_all_good_v) +\
|
||||
" : " + str(len(all_bad_vectors)))
|
||||
if len(all_bad_vectors) < 8:
|
||||
print()
|
||||
print(all_bad_vectors)
|
||||
|
||||
|
||||
return all_combinations_pass
|
||||
|
||||
# searching for sigma > 5 + #(v_i != 0)
|
||||
def eval_cable_for_large_sigma(self, list_of_ranges,
|
||||
print_results=False, verbose=False):
|
||||
if self.__sigma_function is None:
|
||||
self.__sigma_function = self.__get_sigma_function()
|
||||
if print_results:
|
||||
# print("\n\n")
|
||||
# print(100 * "*")
|
||||
# print("Searching for a large signature values for the cable sum: ")
|
||||
print(self.knot_description, end="\t\t\t")
|
||||
# print()
|
||||
if self.__check_all_combinations_in_ranges(list_of_ranges,
|
||||
print_results=print_results):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
class SignatureFunction(object):
|
||||
|
||||
def __init__(self, values=None, counter=None):
|
||||
# set values of signature jumps
|
||||
if counter is None:
|
||||
counter = collections.Counter()
|
||||
if values is None:
|
||||
values = []
|
||||
assert all(x < 1 for x, y in values),\
|
||||
"Signature function is defined on the interval [0, 1)."
|
||||
counter = collections.Counter(dict(values))
|
||||
self.cnt_signature_jumps = counter
|
||||
|
||||
def sum_of_absolute_values(self):
|
||||
return sum([abs(i) for i in self.cnt_signature_jumps.values()])
|
||||
|
||||
def is_zero_everywhere(self):
|
||||
return not any(self.cnt_signature_jumps.values())
|
||||
|
||||
def double_cover(self):
|
||||
# to read values for t^2
|
||||
new_data = []
|
||||
for jump_arg, jump in self.cnt_signature_jumps.items():
|
||||
new_data.append((jump_arg/2, jump))
|
||||
new_data.append((1/2 + jump_arg/2, jump))
|
||||
return SignatureFunction(values=new_data)
|
||||
|
||||
def square_root(self):
|
||||
# to read values for t^(1/2)
|
||||
new_data = []
|
||||
for jump_arg, jump in self.cnt_signature_jumps.items():
|
||||
if jump_arg < 1/2:
|
||||
new_data.append((2 * jump_arg, jump))
|
||||
return SignatureFunction(values=new_data)
|
||||
|
||||
def minus_square_root(self):
|
||||
# to read values for t^(1/2)
|
||||
counter = collections.Counter()
|
||||
for jump_arg, jump in self.cnt_signature_jumps.items():
|
||||
if jump_arg >= 1/2:
|
||||
counter[mod_one(2 * jump_arg)] = jump
|
||||
return SignatureFunction(counter=counter)
|
||||
|
||||
def __lshift__(self, shift):
|
||||
# A shift of the signature functions corresponds to the rotation.
|
||||
return self.__rshift__(-shift)
|
||||
|
||||
def __rshift__(self, shift):
|
||||
new_data = []
|
||||
for jump_arg, jump in self.cnt_signature_jumps.items():
|
||||
new_data.append((mod_one(jump_arg + shift), jump))
|
||||
return SignatureFunction(values=new_data)
|
||||
|
||||
def __neg__(self):
|
||||
counter = collections.Counter()
|
||||
counter.subtract(self.cnt_signature_jumps)
|
||||
return SignatureFunction(counter=counter)
|
||||
|
||||
# TBD short
|
||||
def __add__(self, other):
|
||||
counter = copy(self.cnt_signature_jumps)
|
||||
counter.update(other.cnt_signature_jumps)
|
||||
return SignatureFunction(counter=counter)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.cnt_signature_jumps == other.cnt_signature_jumps
|
||||
|
||||
def __sub__(self, other):
|
||||
counter = copy(self.cnt_signature_jumps)
|
||||
counter.subtract(other.cnt_signature_jumps)
|
||||
return SignatureFunction(counter=counter)
|
||||
|
||||
def __str__(self):
|
||||
result = ''.join([str(jump_arg) + ": " + str(jump) + "\n"
|
||||
for jump_arg, jump in sorted(self.cnt_signature_jumps.items())])
|
||||
return result
|
||||
|
||||
def __repr__(self):
|
||||
result = ''.join([str(jump_arg) + ": " + str(jump) + ", "
|
||||
for jump_arg, jump in sorted(self.cnt_signature_jumps.items())])
|
||||
return result[:-2] + "."
|
||||
|
||||
def __call__(self, arg):
|
||||
# Compute the value of the signature function at the point arg.
|
||||
# This requires summing all signature jumps that occur before arg.
|
||||
arg = mod_one(arg)
|
||||
cnt = self.cnt_signature_jumps
|
||||
before_arg = [jump for jump_arg, jump in cnt.items() if jump_arg < arg]
|
||||
return 2 * sum(before_arg) + cnt[arg]
|
||||
|
||||
def mod_one(n):
|
||||
return n - floor(n)
|
@ -11,8 +11,7 @@ import collections
|
||||
import itertools as it
|
||||
import numpy as np
|
||||
import re
|
||||
|
||||
|
||||
from cable_signature import SignatureFunction, TorusCable
|
||||
|
||||
class Config(object):
|
||||
def __init__(self):
|
||||
@ -23,17 +22,25 @@ class Config(object):
|
||||
self.knot_formula = "[[k[0], k[1], k[3]], [-k[1], -k[3]], \
|
||||
[k[2], k[3]], [-k[0], -k[2], -k[3]]]"
|
||||
|
||||
# self.knot_formula = "[[k[3], k[2], k[0]], [-k[2], -k[0]], \
|
||||
# [k[1], k[0]], [-k[3], -k[1], -k[0]]]"
|
||||
|
||||
|
||||
|
||||
# self.knot_formula = "[[k[0], k[1], k[2]], [k[3], k[4]], \
|
||||
# [-k[0], -k[3], -k[4]], [-k[1], -k[2]]]"
|
||||
# self.knot_formula = "[[k[0], k[1], k[2]], [k[3]],\
|
||||
# [-k[0], -k[1], -k[3]], [-k[2]]]"
|
||||
self.limit = 3
|
||||
|
||||
# in search for large sigma, for 1. checked knot q_1 = 3 + start_shift
|
||||
self.start_shift = 0
|
||||
|
||||
self.verbose = True
|
||||
self.verbose = False
|
||||
|
||||
self.print_calculations_for_small_sigma = True
|
||||
self.print_calculations_for_small_sigma = False
|
||||
self.print_results = True
|
||||
# self.print_results = False
|
||||
|
||||
self.print_calculations_for_large_sigma = True
|
||||
self.print_calculations_for_large_sigma = False
|
||||
@ -43,337 +50,61 @@ class Config(object):
|
||||
self.only_slice_candidates = True
|
||||
self.only_slice_candidates = False
|
||||
|
||||
self.stop_after_firts_large_sigma = True
|
||||
self.stop_after_firts_large_sigma = False
|
||||
|
||||
# range for a_i, v = [a_1, a_2, a_3, a_4], for sigma calculations
|
||||
def get_list_of_ranges(self, q):
|
||||
list_of_ranges = [
|
||||
# all characters a_1, a_2, a_3, a_4 != 0
|
||||
it.product(range(1, q), range(1, q), range(1, q), range(1, 2)),
|
||||
|
||||
class SignatureFunction(object):
|
||||
# a_1 == 0, a_2, a_3, a_4 != 0
|
||||
it.product(range(1), range(1, q), range(1, q), range(1, 2)),
|
||||
# a_2 == 0, a_1, a_3, a_4 != 0
|
||||
it.product(range(1, q), range(1), range(1, q), range(1, 2)),
|
||||
# a_3 == 0, a_1, a_2, a_4 != 0
|
||||
it.product(range(1, q), range(1, q), range(1), range(1, 2)),
|
||||
# a_4 == 0, a_1, a_2, a_3 != 0
|
||||
it.product(range(1, q), range(1, q), range(1, 2), range(1)),
|
||||
|
||||
def __init__(self, values=None, counter=None):
|
||||
# set values of signature jumps
|
||||
if counter is None:
|
||||
counter = collections.Counter()
|
||||
if values is None:
|
||||
values = []
|
||||
for jump_arg, jump in values:
|
||||
assert 0 <= jump_arg < 1, \
|
||||
"Signature function is defined on the interval [0, 1)."
|
||||
counter[jump_arg] = jump
|
||||
self.cnt_signature_jumps = counter
|
||||
self.signature_jumps = collections.defaultdict(int, counter)
|
||||
|
||||
def sum_of_absolute_values(self):
|
||||
return sum([abs(i) for i in self.cnt_signature_jumps.values()])
|
||||
|
||||
def is_zero_everywhere(self):
|
||||
return not any(self.signature_jumps.values())
|
||||
|
||||
def double_cover(self):
|
||||
# to read values for t^2
|
||||
new_data = []
|
||||
for jump_arg, jump in self.cnt_signature_jumps.items():
|
||||
new_data.append((jump_arg/2, jump))
|
||||
new_data.append((1/2 + jump_arg/2, jump))
|
||||
|
||||
t_data = []
|
||||
for jump_arg, jump in self.signature_jumps.items():
|
||||
t_data.append((jump_arg/2, jump))
|
||||
t_data.append((1/2 + jump_arg/2, jump))
|
||||
|
||||
sf = SignatureFunction(values=t_data)
|
||||
a = SignatureFunction(values=new_data)
|
||||
assert a == sf
|
||||
return sf
|
||||
|
||||
def square_root(self):
|
||||
# to read values for t^(1/2)
|
||||
new_data = []
|
||||
for jump_arg, jump in self.signature_jumps.items():
|
||||
if jump_arg < 1/2:
|
||||
new_data.append((2 * jump_arg, jump))
|
||||
|
||||
t_data = []
|
||||
for jump_arg, jump in self.cnt_signature_jumps.items():
|
||||
if jump_arg < 1/2:
|
||||
t_data.append((2 * jump_arg, jump))
|
||||
|
||||
sf = SignatureFunction(values=t_data)
|
||||
a = SignatureFunction(values=new_data)
|
||||
assert a == sf
|
||||
return sf
|
||||
|
||||
def minus_square_root(self):
|
||||
# to read values for t^(1/2)
|
||||
counter = collections.Counter()
|
||||
new_data = []
|
||||
for jump_arg, jump in self.cnt_signature_jumps.items():
|
||||
if jump_arg >= 1/2:
|
||||
counter[mod_one(2 * jump_arg)] = jump
|
||||
new_data.append((mod_one(2 * jump_arg), jump))
|
||||
t_data = []
|
||||
for jump_arg, jump in self.signature_jumps.items():
|
||||
if jump_arg >= 1/2:
|
||||
t_data.append((mod_one(2 * jump_arg), jump))
|
||||
print(t_data)
|
||||
a = SignatureFunction(values=t_data)
|
||||
sf = SignatureFunction(values=new_data)
|
||||
sf2 = SignatureFunction(counter=counter)
|
||||
assert a == sf
|
||||
assert a == sf2
|
||||
return sf
|
||||
|
||||
def __lshift__(self, shift):
|
||||
# A shift of the signature functions corresponds to the rotation.
|
||||
return self.__rshift__(-shift)
|
||||
|
||||
def __rshift__(self, shift):
|
||||
t_data = []
|
||||
for jump_arg, jump in self.signature_jumps.items():
|
||||
t_data.append((mod_one(jump_arg + shift), jump))
|
||||
new_data = []
|
||||
for jump_arg, jump in self.cnt_signature_jumps.items():
|
||||
new_data.append((mod_one(jump_arg + shift), jump))
|
||||
sf = SignatureFunction(values=new_data)
|
||||
a = SignatureFunction(values=t_data)
|
||||
assert a == sf
|
||||
return sf
|
||||
|
||||
def __neg__(self):
|
||||
new_data = []
|
||||
for jump_arg, jump in self.signature_jumps.items():
|
||||
new_data.append((jump_arg, -jump))
|
||||
a = SignatureFunction(values=new_data)
|
||||
counter = collections.Counter()
|
||||
counter.subtract(self.cnt_signature_jumps)
|
||||
sf = SignatureFunction(counter=counter)
|
||||
assert a == sf
|
||||
return sf
|
||||
|
||||
# TBD short
|
||||
def __add__(self, other):
|
||||
new_data = collections.defaultdict(int)
|
||||
for jump_arg, jump in other.signature_jumps.items():
|
||||
new_data[jump_arg] = jump + self.signature_jumps.get(jump_arg, 0)
|
||||
for jump_arg, jump in self.signature_jumps.items():
|
||||
if jump_arg not in new_data.keys():
|
||||
new_data[jump_arg] = self.signature_jumps[jump_arg]
|
||||
|
||||
counter = copy(self.cnt_signature_jumps)
|
||||
counter.update(other.cnt_signature_jumps)
|
||||
assert collections.defaultdict(int, counter) == new_data
|
||||
return SignatureFunction(counter=counter)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.cnt_signature_jumps == other.cnt_signature_jumps
|
||||
|
||||
def __sub__(self, other):
|
||||
a = self + other.__neg__()
|
||||
counter = copy(self.cnt_signature_jumps)
|
||||
counter.subtract(other.cnt_signature_jumps)
|
||||
sf = SignatureFunction(counter=counter)
|
||||
assert a == sf
|
||||
return sf
|
||||
|
||||
def __str__(self):
|
||||
result2 = ''.join([str(jump_arg) + ": " + str(jump) + "\n"
|
||||
for jump_arg, jump in sorted(self.signature_jumps.items())])
|
||||
result = ''.join([str(jump_arg) + ": " + str(jump) + "\n"
|
||||
for jump_arg, jump in sorted(self.cnt_signature_jumps.items())])
|
||||
assert result == result2
|
||||
|
||||
return result
|
||||
|
||||
def __repr__(self):
|
||||
result2 = ''.join([str(jump_arg) + ": " + str(jump) + ", "
|
||||
for jump_arg, jump in sorted(self.signature_jumps.items())])
|
||||
result = ''.join([str(jump_arg) + ": " + str(jump) + ", "
|
||||
for jump_arg, jump in sorted(self.cnt_signature_jumps.items())])
|
||||
|
||||
|
||||
assert result == result2
|
||||
|
||||
return result[:-2] + "."
|
||||
|
||||
def __call__(self, arg):
|
||||
# Compute the value of the signature function at the point arg.
|
||||
# This requires summing all signature jumps that occur before arg.
|
||||
arg = mod_one(arg)
|
||||
cnt = self.cnt_signature_jumps
|
||||
before_arg = [jump for jump_arg, jump in cnt.items() if jump_arg < arg]
|
||||
return 2 * sum(before_arg) + cnt[arg]
|
||||
|
||||
|
||||
class TorusCable(object):
|
||||
def __init__(self, knot_formula=None, k_vector=None, q_vector=None):
|
||||
# q_i = 2 * k_i + 1
|
||||
if knot_formula is None:
|
||||
knot_formula = config.knot_formula
|
||||
|
||||
if k_vector is None:
|
||||
if q_vector is None:
|
||||
# TBD docstring
|
||||
print("Please give a list of k (k_vector) or q values (q_vector).")
|
||||
return None
|
||||
else:
|
||||
k_vector = [(q - 1)/2 for q in q_vector]
|
||||
elif q_vector is None:
|
||||
q_vector = [2 * k + 1 for k in k_vector]
|
||||
self.knot_formula = knot_formula
|
||||
self.k_vector = k_vector
|
||||
self.q_vector = q_vector
|
||||
k = k_vector
|
||||
self.knot_sum = eval(knot_formula)
|
||||
self.knot_description = get_knot_descrption(*self.knot_sum)
|
||||
self.sigma_function = None
|
||||
|
||||
# check sigma for all v = s * [a_1, a_2, a_3, a_4] for s in [1, q_4 - 1]
|
||||
def __is_sigma_for_vector_class_big(self, theta_vector):
|
||||
[a_1, a_2, a_3, a_4] = theta_vector
|
||||
q_4 = self.q_vector[3]
|
||||
for shift in range(1, q_4):
|
||||
shifted_theta = [(shift * a) % q_4 for a in
|
||||
[a_1, a_2, a_3, a_4]]
|
||||
sigma_v = self.__calculate_sigma(shifted_theta)
|
||||
if abs(sigma_v) > 5 + np.count_nonzero(shifted_theta):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def is_sigma_for_vector_class_big(self, theta_vector):
|
||||
if self.sigma_function is None:
|
||||
self.sigma_function = self.__get_sigma_function()
|
||||
return self.__is_sigma_for_vector_class_big(theta_vector)
|
||||
|
||||
|
||||
def __get_sigma_function(self):
|
||||
k_1, k_2, k_3, k_4 = [abs(k) for k in self.k_vector]
|
||||
q_4 = 2 * k_4 + 1
|
||||
ksi = 1/q_4
|
||||
sigma_q_1 = get_untwisted_signature_function(k_1)
|
||||
sigma_q_2 = get_untwisted_signature_function(k_2)
|
||||
sigma_q_3 = get_untwisted_signature_function(k_3)
|
||||
|
||||
def sigma_function(theta_vector):
|
||||
# "untwisted" part (Levine-Tristram signatures)
|
||||
a_1, a_2, a_3, a_4 = theta_vector
|
||||
untwisted_part = 2 * (sigma_q_2(ksi * a_1) -
|
||||
sigma_q_2(ksi * a_2) +
|
||||
sigma_q_3(ksi * a_3) -
|
||||
sigma_q_3(ksi * a_4) +
|
||||
sigma_q_1(ksi * a_1 * 2) -
|
||||
sigma_q_1(ksi * a_4 * 2))
|
||||
|
||||
# "twisted" part
|
||||
tp = [0, 0, 0, 0]
|
||||
for i, a in enumerate(theta_vector):
|
||||
if a:
|
||||
tp[i] = -q_4 + 2 * a - 2 * (a^2/q_4)
|
||||
twisted_part = tp[0] - tp[1] + tp[2] - tp[3]
|
||||
sigma_v = untwisted_part + twisted_part
|
||||
return sigma_v
|
||||
return sigma_function
|
||||
|
||||
def calculate_sigma(self, theta_vector):
|
||||
if self.sigma_function is None:
|
||||
self.sigma_function = self.__get_sigma_function()
|
||||
return self.__calculate_sigma(theta_vector)
|
||||
|
||||
def __calculate_sigma(self, theta_vector):
|
||||
return self.sigma_function(theta_vector)
|
||||
|
||||
def check_combinations_in_range(self, range_list):
|
||||
if self.sigma_function is None:
|
||||
self.sigma_function = self.__get_sigma_function()
|
||||
large_sigma_for_all_combinations = True
|
||||
bad_vectors = []
|
||||
good_vectors = []
|
||||
q_4 = self.q_vector[-1]
|
||||
for vector in range_list:
|
||||
a_1, a_2, a_3, a_4 = vector
|
||||
if a_1 == a_2 == a_3 == a_4:
|
||||
continue
|
||||
if (a_1^2 - a_2^2 + a_3^2 - a_4^2) % q_4:
|
||||
continue
|
||||
|
||||
|
||||
if self.__is_sigma_for_vector_class_big(vector):
|
||||
good_vectors.append(vector)
|
||||
pass
|
||||
else:
|
||||
bad_vectors.append(vector)
|
||||
large_sigma_for_all_combinations = False
|
||||
return good_vectors, bad_vectors
|
||||
|
||||
|
||||
|
||||
# def is_condition_for_vector_class_fulfilled(vector):
|
||||
# a_1, a_2, a_3, a_4 = vector
|
||||
# q_4 = self.q_vector[-1]
|
||||
# # check assumption - for results != 0 mod q_4 we stop here
|
||||
# if (a_1^2 - a_2^2 + a_3^2 - a_4^2) % q_4:
|
||||
# return None
|
||||
# if self.sigma_function is None:
|
||||
# self.sigma_function = self.__get_sigma_function()
|
||||
# return self.__is_sigma_for_vector_class_big(theta_vector)
|
||||
|
||||
|
||||
# searching for sigma > 5 + #(v_i != 0)
|
||||
def eval_cable_for_large_sigma(k_vector=None, knot_formula=None,
|
||||
print_results=True, verbose=None,
|
||||
q_vector=None):
|
||||
|
||||
cable = TorusCable(knot_formula=knot_formula, k_vector=k_vector,
|
||||
q_vector=q_vector)
|
||||
|
||||
q = cable.q_vector[-1]
|
||||
|
||||
if verbose:
|
||||
print("\n\n")
|
||||
print(100 * "*")
|
||||
print("Searching for a large signature values for the cable sum: ")
|
||||
print(cable.knot_description)
|
||||
|
||||
list_of_ranges = [
|
||||
# all characters a_1, a_2, a_3, a_4 != 0
|
||||
it.product(range(1, q), range(1, q), range(1, q), range(1, 2)),
|
||||
|
||||
# a_1 == 0, a_2, a_3, a_4 != 0
|
||||
it.product(range(1), range(1, q), range(1, q), range(1, 2)),
|
||||
# a_2 == 0, a_1, a_3, a_4 != 0
|
||||
it.product(range(1, q), range(1), range(1, q), range(1, 2)),
|
||||
# a_3 == 0, a_1, a_2, a_4 != 0
|
||||
it.product(range(1, q), range(1, q), range(1), range(1, 2)),
|
||||
# a_4 == 0, a_1, a_2, a_3 != 0
|
||||
it.product(range(1, q), range(1, q), range(1, 2), range(1)),
|
||||
|
||||
# a_1 == 0, a_2 == 0, a_3, a_4 != 0
|
||||
it.product(range(1), range(1), range(1, q), range(1, 2)),
|
||||
# a_1 == 0, a_3 == 0, a_2, a_4 != 0
|
||||
it.product(range(1), range(1, q), range(1), range(1, 2)),
|
||||
# a_1 == 0, a_4 == 0, a_3, a_2 != 0
|
||||
it.product(range(1), range(1, q), range(1, 2), range(1)),
|
||||
# a_2 == 0, a_3 == 0, a_1, a_4 != 0
|
||||
it.product(range(1, q), range(1), range(1), range(1, 2)),
|
||||
# a_2 == 0, a_4 == 0, a_1, a_3 != 0
|
||||
it.product(range(1, q), range(1), range(1, 2), range(1)),
|
||||
# a_3 == 0, a_4 == 0, a_1, a_2 != 0
|
||||
it.product(range(1, q), range(1, 2), range(1), range(1)),
|
||||
|
||||
]
|
||||
for ranges in list_of_ranges:
|
||||
good_vectors, bad_vectors = cable.check_combinations_in_range(ranges)
|
||||
|
||||
|
||||
print("good_vectors : bad_vectors: " + str(len(good_vectors)) +\
|
||||
" : " + str(len(bad_vectors)))
|
||||
# a_1 == 0, a_2 == 0, a_3, a_4 != 0
|
||||
it.product(range(1), range(1), range(1, q), range(1, 2)),
|
||||
# a_1 == 0, a_3 == 0, a_2, a_4 != 0
|
||||
it.product(range(1), range(1, q), range(1), range(1, 2)),
|
||||
# a_1 == 0, a_4 == 0, a_3, a_2 != 0
|
||||
it.product(range(1), range(1, q), range(1, 2), range(1)),
|
||||
# a_2 == 0, a_3 == 0, a_1, a_4 != 0
|
||||
it.product(range(1, q), range(1), range(1), range(1, 2)),
|
||||
# a_2 == 0, a_4 == 0, a_1, a_3 != 0
|
||||
it.product(range(1, q), range(1), range(1, 2), range(1)),
|
||||
# a_3 == 0, a_4 == 0, a_1, a_2 != 0
|
||||
it.product(range(1, q), range(1, 2), range(1), range(1)),
|
||||
]
|
||||
# list_of_ranges = [
|
||||
# # all characters a_1, a_2, a_3, a_4 != 0
|
||||
# # 1, 1, 1, 1
|
||||
# it.product(range(1, 2), range(1, 2), range(1, 2), range(1, 2)),
|
||||
#
|
||||
# print("\ngood_vectors")
|
||||
# print(len(good_vectors))
|
||||
# print("\nbad_vectors")
|
||||
# print(len(bad_vectors))
|
||||
# print(bad_vectors)
|
||||
# # -1, -1, -1, 1
|
||||
# it.product(range(q - 1, q), range(q - 1, q), range(q - 1, q), range(1, 2)),
|
||||
#
|
||||
# # 1, -1, -1, 1
|
||||
# it.product(range(1, 2), range(q - 1, q), range(q - 1, q), range(1, 2)),
|
||||
# # -1 , -1, 1, 1
|
||||
# it.product(range(q - 1, q), range(q - 1, q), range(1, 2), range(1, 2)),
|
||||
# # -1, 1, -1, 1
|
||||
# it.product(range(q - 1, q), range(1, 2), range(q - 1, q), range(1, 2)),
|
||||
#
|
||||
# # 1, 1, -1, 1
|
||||
# it.product(range(1, 2), range(1, 2), range(q - 1, q), range(1, 2)),
|
||||
# # 1, -1, 1, 1
|
||||
# it.product(range(1, 2), range(q - 1, q), range(1, 2), range(1, 2)),
|
||||
# # -1, 1, 1, 1
|
||||
# it.product(range(q - 1, q), range(1, 2), range(1, 2), range(1, 2)),
|
||||
#
|
||||
# ]
|
||||
|
||||
return list_of_ranges
|
||||
|
||||
return None
|
||||
|
||||
|
||||
|
||||
@ -382,230 +113,94 @@ def main(arg):
|
||||
limit = int(arg[1])
|
||||
else:
|
||||
limit = None
|
||||
search_for_large_signature_value(limit=limit)
|
||||
knots_with_large_sigma = search_for_large_signature_value(limit=limit)
|
||||
# search_for_null_signature_value(limit=limit)
|
||||
|
||||
|
||||
|
||||
# searching for sigma > 5 + #(v_i != 0) over given knot schema
|
||||
def search_for_large_signature_value(knot_formula=None,
|
||||
limit=None,
|
||||
verbose=None):
|
||||
def __search_for_large_signature_value(knot_formula, limit,
|
||||
verbose, print_results):
|
||||
# number of k_i (q_i) variables to substitute
|
||||
k_size = extract_max(knot_formula) + 1
|
||||
combinations = it.combinations_with_replacement(range(0, limit + 1), k_size)
|
||||
P = Primes()
|
||||
good_knots = []
|
||||
# iterate over q-vector
|
||||
for c in combinations:
|
||||
q = list(c)
|
||||
q[0] = P.unrank(q[0] + 1 + config.start_shift)
|
||||
q[1] = P.next(q[0] * 4 + q[1])
|
||||
q[2] = P.next(q[1] * 4 + q[2])
|
||||
q[3] = P.next(q[2] * 4 + q[3])
|
||||
cable = TorusCable(knot_formula=knot_formula, q_vector=q)
|
||||
list_of_ranges = config.get_list_of_ranges(cable.q_vector[-1])
|
||||
if cable.eval_cable_for_large_sigma(list_of_ranges, verbose=verbose,
|
||||
print_results=print_results):
|
||||
good_knots.append(cable)
|
||||
return good_knots
|
||||
|
||||
# searching for sigma > 5 + #(v_i != 0) over given knot schema
|
||||
def search_for_large_signature_value(knot_formula=None, limit=None,
|
||||
verbose=None, print_results=None):
|
||||
if limit is None:
|
||||
limit = config.limit
|
||||
if knot_formula is None:
|
||||
knot_formula = config.knot_formula
|
||||
if verbose is None:
|
||||
vebose = config.verbose
|
||||
if print_results is None:
|
||||
print_results = config.print_results
|
||||
|
||||
k_vector_size = extract_max(knot_formula) + 1
|
||||
limit = max(limit, k_vector_size)
|
||||
if config.only_slice_candidates:
|
||||
return __search_for_large_signature_value(knot_formula, limit, verbose,
|
||||
print_results)
|
||||
|
||||
# number of k_i (q_i) variables to substitute
|
||||
k_vector_size = extract_max(knot_formula) + 1
|
||||
|
||||
limit = max(limit, k_vector_size)
|
||||
combinations = it.combinations(range(1, limit + 1), k_vector_size)
|
||||
P = Primes()
|
||||
good_knots = []
|
||||
# with open(config.f_results, 'w') as f_results:
|
||||
|
||||
# iterate over q-vector
|
||||
for c in combinations:
|
||||
k = [(P.unrank(i + 2) - 1)/2 for i in c]
|
||||
if config.only_slice_candidates:
|
||||
if not (k[3] > 4 * k[2] and
|
||||
k[2] > 4 * k[1] and
|
||||
k[1] > 4 * k[0]):
|
||||
if verbose:
|
||||
print("Ratio-condition does not hold")
|
||||
continue
|
||||
result = eval_cable_for_large_sigma(k_vector=k,
|
||||
knot_formula=knot_formula,
|
||||
print_results=False)
|
||||
good_knots.append(result)
|
||||
k = [(P.unrank(i + config.start_shift) - 1)/2 for i in c]
|
||||
cable = TorusCable(knot_formula=knot_formula, k_vector=k)
|
||||
list_of_ranges = config.get_list_of_ranges(cable.q_vector[-1])
|
||||
if cable.eval_cable_for_large_sigma(list_of_ranges, verbose=verbose,
|
||||
print_results=print_results):
|
||||
good_knots.append(cable)
|
||||
return good_knots
|
||||
|
||||
|
||||
|
||||
def print_results_LT(v_theta, knot_description, ksi, untwisted_part,
|
||||
k, sigma_q_1, sigma_q_2, sigma_q_3):
|
||||
a_1, a_2, a_3, a_4 = v_theta
|
||||
k_1, k_2, k_3, k_4 = [abs(i) for i in k]
|
||||
print("\n\nLevine-Tristram signatures for the cable sum: ")
|
||||
print(knot_description)
|
||||
print("and characters:\n" + str(v_theta) + ",")
|
||||
print("ksi = " + str(ksi))
|
||||
print("\n\n2 * (sigma_q_2(ksi * a_1) + " + \
|
||||
"sigma_q_1(ksi * a_1 * 2) - " +\
|
||||
"sigma_q_2(ksi * a_2) + " +\
|
||||
"sigma_q_3(ksi * a_3) - " +\
|
||||
"sigma_q_3(ksi * a_4) - " +\
|
||||
"sigma_q_1(ksi * a_4 * 2))" +\
|
||||
\
|
||||
" = \n\n2 * (sigma_q_2(" + \
|
||||
str(ksi) + " * " + str(a_1) + \
|
||||
") + sigma_q_1(" + \
|
||||
str(ksi) + " * " + str(a_1) + " * 2" + \
|
||||
") - sigma_q_2(" + \
|
||||
str(ksi) + " * " + str(a_2) + \
|
||||
") + sigma_q_3(" + \
|
||||
str(ksi) + " * " + str(a_3) + \
|
||||
") - sigma_q_3(" + \
|
||||
str(ksi) + " * " + str(a_4) + \
|
||||
") - sigma_q_1(" + \
|
||||
str(ksi) + " * " + str(a_4) + " * 2)) " + \
|
||||
\
|
||||
" = \n\n2 * (sigma_q_2(" + \
|
||||
str(mod_one(ksi * a_1)) + \
|
||||
") + sigma_q_1(" + \
|
||||
str(mod_one(ksi * a_1 * 2)) + \
|
||||
") - sigma_q_2(" + \
|
||||
str(mod_one(ksi * a_2)) + \
|
||||
") + sigma_q_3(" + \
|
||||
str(mod_one(ksi * a_3)) + \
|
||||
") - sigma_q_3(" + \
|
||||
str(mod_one(ksi * a_4)) + \
|
||||
") - sigma_q_1(" + \
|
||||
str(mod_one(ksi * a_4 * 2)) + \
|
||||
\
|
||||
") = \n\n2 * ((" + \
|
||||
str(sigma_q_2(ksi * a_1)) + \
|
||||
") + (" + \
|
||||
str(sigma_q_1(ksi * a_1 * 2)) + \
|
||||
") - (" + \
|
||||
str(sigma_q_2(ksi * a_2)) + \
|
||||
") + (" + \
|
||||
str(sigma_q_3(ksi * a_3)) + \
|
||||
") - (" + \
|
||||
str(sigma_q_3(ksi * a_4)) + \
|
||||
") - (" + \
|
||||
str(sigma_q_1(ksi * a_4 * 2)) + ")) = " + \
|
||||
"\n\n2 * (" + \
|
||||
str(sigma_q_2(ksi * a_1) +
|
||||
sigma_q_1(ksi * a_1 * 2) -
|
||||
sigma_q_2(ksi * a_2) +
|
||||
sigma_q_3(ksi * a_3) -
|
||||
sigma_q_3(ksi * a_4) -
|
||||
sigma_q_1(ksi * a_4 * 2)) + \
|
||||
") = " + str(untwisted_part))
|
||||
print("\nSignatures:")
|
||||
print("\nq_1 = " + str(2 * k_1 + 1) + ": " + repr(sigma_q_1))
|
||||
print("\nq_2 = " + str(2 * k_2 + 1) + ": " + repr(sigma_q_2))
|
||||
print("\nq_3 = " + str(2 * k_3 + 1) + ": " + repr(sigma_q_3))
|
||||
|
||||
|
||||
def print_results_sigma(v_theta, knot_description, tp, q_4):
|
||||
a_1, a_2, a_3, a_4 = v_theta
|
||||
|
||||
print("\n\nSigma values for the cable sum: ")
|
||||
print(knot_description)
|
||||
print("and characters: " + str(v_theta))
|
||||
print("\nsigma(T_{2, q_4}, ksi_a) = " + \
|
||||
"-q + (2 * a * (q_4 - a)/q_4) " +\
|
||||
"= -q + 2 * a - 2 * a^2/q_4 if a != 0,\n\t\t\t" +\
|
||||
" = 0 if a == 0.")
|
||||
print("\nsigma(T_{2, q_4}, chi_a_1) = ", end="")
|
||||
if a_1:
|
||||
print("- (" + str(q_4) + ") + 2 * " + str(a_1) + " + " +\
|
||||
"- 2 * " + str(a_1^2) + "/" + str(q_4) + \
|
||||
" = " + str(tp[0]))
|
||||
else:
|
||||
print("0")
|
||||
print("\nsigma(T_{2, q_4}, chi_a_2) = ", end ="")
|
||||
if a_2:
|
||||
print("- (" + str(q_4) + ") + 2 * " + str(a_2) + " + " +\
|
||||
"- 2 * " + str(a_2^2) + "/" + str(q_4) + \
|
||||
" = " + str(tp[1]))
|
||||
else:
|
||||
print("0", end="")
|
||||
print("\nsigma(T_{2, q_4}, chi_a_3) = ", end="")
|
||||
if a_3:
|
||||
print("- (" + str(q_4) + ") + 2 * " + str(a_3) + " + " +\
|
||||
"- 2 * " + str(a_3^2) + "/" + str(q_4) + \
|
||||
" = " + str(tp[2]))
|
||||
else:
|
||||
print("0", end="")
|
||||
print("\nsigma(T_{2, q_4}, chi_a_4) = ", end="")
|
||||
if a_4:
|
||||
print("- (" + str(q_4) + ") + 2 * " + str(a_4) + " + " +\
|
||||
"- 2 * " + str(a_4^2) + "/" + str(q_4) + \
|
||||
" = " + str(tp[3]))
|
||||
else:
|
||||
print("0")
|
||||
|
||||
print("\n\nsigma(T_{2, q_4}, chi_a_1) " + \
|
||||
"- sigma(T_{2, q_4}, chi_a_2) " + \
|
||||
"+ sigma(T_{2, q_4}, chi_a_3) " + \
|
||||
"- sigma(T_{2, q_4}, chi_a_4) =\n" + \
|
||||
"sigma(T_{2, q_4}, " + str(a_1) + \
|
||||
") - sigma(T_{2, q_4}, " + str(a_2) + \
|
||||
") + sigma(T_{2, q_4}, " + str(a_3) + \
|
||||
") - sigma(T_{2, q_4}, " + str(a_4) + ") = " + \
|
||||
str(tp[0] - tp[1] + tp[2] - tp[3]))
|
||||
|
||||
# searching for signature == 0
|
||||
def search_for_null_signature_value(knot_formula=None, limit=None):
|
||||
if limit is None:
|
||||
limit = config.limit
|
||||
if knot_formula is None:
|
||||
knot_formula = config.knot_formula
|
||||
print_results = config.print_results
|
||||
verbose = config.verbose
|
||||
|
||||
k_vector_size = extract_max(knot_formula) + 1
|
||||
combinations = it.combinations_with_replacement(range(1, limit + 1),
|
||||
k_vector_size)
|
||||
|
||||
with open(config.f_results, 'w') as f_results:
|
||||
|
||||
for k in combinations:
|
||||
if config.only_slice_candidates and k_vector_size == 5:
|
||||
k = get_shifted_combination(k)
|
||||
knot_sum = eval(knot_formula)
|
||||
if is_trivial_combination(knot_sum):
|
||||
print(knot_sum)
|
||||
cable = TorusCable(knot_formula, k_vector=k)
|
||||
if is_trivial_combination(cable.knot_sum):
|
||||
print(cable.knot_sum)
|
||||
continue
|
||||
|
||||
result = eval_cable_for_null_signature(knot_sum)
|
||||
result = cable.eval_cable_for_null_signature(verbose=verbose,
|
||||
print_results=print_results)
|
||||
if result is not None:
|
||||
knot_description, null_comb, all_comb = result
|
||||
null_comb, all_comb = result
|
||||
line = (str(k) + ", " + str(null_comb) + ", " +
|
||||
str(all_comb) + "\n")
|
||||
f_results.write(line)
|
||||
|
||||
# searching for signature == 0
|
||||
def eval_cable_for_null_signature(knot_sum, print_results=False, verbose=None):
|
||||
# search for zero combinations
|
||||
if verbose is None:
|
||||
vebose = config.verbose
|
||||
f = get_signature_as_theta_function(*knot_sum, verbose=False)
|
||||
knot_description = get_knot_descrption(*knot_sum)
|
||||
all_combinations = get_number_of_combinations(*knot_sum)
|
||||
|
||||
null_combinations = 0
|
||||
zero_theta_combinations = []
|
||||
|
||||
range_list = [range(abs(knot[-1]) + 1) for knot in knot_sum]
|
||||
if verbose:
|
||||
print()
|
||||
print(knot_description)
|
||||
for v_theta in it.product(*range_list):
|
||||
if f(*v_theta, verbose=False).is_zero_everywhere():
|
||||
zero_theta_combinations.append(v_theta)
|
||||
m = len([theta for theta in v_theta if theta != 0])
|
||||
null_combinations += 2^m
|
||||
# else:
|
||||
# assert sum(v_theta) != 0
|
||||
|
||||
if print_results:
|
||||
print()
|
||||
print(knot_description)
|
||||
print("Zero cases: " + str(null_combinations))
|
||||
print("All cases: " + str(all_combinations))
|
||||
if zero_theta_combinations:
|
||||
print("Zero theta combinations: ")
|
||||
for el in zero_theta_combinations:
|
||||
print(el)
|
||||
if null_combinations^2 >= all_combinations:
|
||||
return knot_description, null_combinations, all_combinations
|
||||
return None
|
||||
|
||||
|
||||
def is_trivial_combination(knot_sum):
|
||||
# for now is applicable only for schema that are sums of 4 cables
|
||||
if len(knot_sum) == 4:
|
||||
@ -614,7 +209,6 @@ def is_trivial_combination(knot_sum):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def get_shifted_combination(combination):
|
||||
# for now applicable only for schama
|
||||
# "[[k[0], k[1], k[2]], [k[3], k[4]],
|
||||
@ -626,7 +220,6 @@ def get_shifted_combination(combination):
|
||||
4 * (4 * combination[0] + combination[3]) + combination[4]]
|
||||
return combination
|
||||
|
||||
|
||||
def get_blanchfield_for_pattern(k_n, theta):
|
||||
if theta == 0:
|
||||
a = get_untwisted_signature_function(k_n)
|
||||
@ -688,7 +281,6 @@ def get_signature_summand_as_theta_function(*arg):
|
||||
get_signture_function.__doc__ = get_signture_function_docsting
|
||||
return get_signture_function
|
||||
|
||||
|
||||
def get_untwisted_signature_function(j):
|
||||
# return the signature function of the T_{2,2k+1} torus knot
|
||||
k = abs(j)
|
||||
@ -697,77 +289,15 @@ def get_untwisted_signature_function(j):
|
||||
for a in range(k + 1, 2 * k + 1)])
|
||||
return SignatureFunction(values=w)
|
||||
|
||||
|
||||
def get_signature_as_theta_function(*arg, **key_args):
|
||||
if 'verbose' in key_args:
|
||||
verbose_default = key_args['verbose']
|
||||
else:
|
||||
verbose_default = config.verbose
|
||||
def signature_as_theta_function(*thetas, **kwargs):
|
||||
verbose = verbose_default
|
||||
if 'verbose' in kwargs:
|
||||
verbose = kwargs['verbose']
|
||||
la = len(arg)
|
||||
lt = len(thetas)
|
||||
|
||||
# call with no arguments
|
||||
if lt == 0:
|
||||
return signature_as_theta_function(*(la * [0]))
|
||||
|
||||
if lt != la:
|
||||
msg = "This function takes exactly " + str(la) + \
|
||||
" arguments or no argument at all (" + str(lt) + " given)."
|
||||
raise TypeError(msg)
|
||||
|
||||
sf = SignatureFunction()
|
||||
|
||||
# for each cable in cable sum apply theta
|
||||
for i, knot in enumerate(arg):
|
||||
try:
|
||||
sf += get_signature_summand_as_theta_function(*knot)(thetas[i])
|
||||
# in case wrong theata value was given
|
||||
except ValueError as e:
|
||||
print("ValueError: " + str(e.args[0]) +\
|
||||
" Please change " + str(i + 1) + ". parameter.")
|
||||
return None
|
||||
if verbose:
|
||||
print()
|
||||
print(str(thetas))
|
||||
print(sf)
|
||||
return sf
|
||||
signature_as_theta_function.__doc__ = signature_as_theta_function_docstring
|
||||
return signature_as_theta_function
|
||||
|
||||
|
||||
def get_number_of_combinations(*arg):
|
||||
number_of_combinations = 1
|
||||
for knot in arg:
|
||||
number_of_combinations *= (2 * abs(knot[-1]) + 1)
|
||||
return number_of_combinations
|
||||
|
||||
|
||||
def extract_max(string):
|
||||
numbers = re.findall('\d+', string)
|
||||
numbers = map(int, numbers)
|
||||
return max(numbers)
|
||||
|
||||
|
||||
def mod_one(n):
|
||||
return n - floor(n)
|
||||
|
||||
|
||||
def get_knot_descrption(*arg):
|
||||
description = ""
|
||||
for knot in arg:
|
||||
if knot[0] < 0:
|
||||
description += "-"
|
||||
description += "T("
|
||||
for k in knot:
|
||||
description += "2, " + str(2 * abs(k) + 1) + "; "
|
||||
description = description[:-2] + ") # "
|
||||
return description[:-3]
|
||||
|
||||
|
||||
get_blanchfield_for_pattern.__doc__ = \
|
||||
"""
|
||||
Arguments:
|
||||
@ -782,7 +312,7 @@ get_blanchfield_for_pattern.__doc__ = \
|
||||
(https://arxiv.org/pdf/1809.08791.pdf)
|
||||
"""
|
||||
|
||||
get_number_of_combinations.__doc__ = \
|
||||
TorusCable.get_number_of_combinations_of_theta.__doc__ = \
|
||||
"""
|
||||
Arguments:
|
||||
arbitrary number of lists of numbers, each list encodes a single cable
|
||||
@ -794,7 +324,7 @@ get_number_of_combinations.__doc__ = \
|
||||
and q_j is the last q parameter for the component (a single cable)
|
||||
"""
|
||||
|
||||
get_knot_descrption.__doc__ = \
|
||||
TorusCable.get_knot_descrption.__doc__ = \
|
||||
"""
|
||||
Arguments:
|
||||
arbitrary number of lists of numbers, each list encodes a single cable.
|
||||
@ -828,7 +358,8 @@ search_for_null_signature_value.__doc__ = \
|
||||
i.e k[0] value in a cable sum, where q_0 = 2 * k[0] + 1.
|
||||
|
||||
(the number of knots that will be constracted depends on limit value).
|
||||
For each knot/cable sum the function eval_cable_for_null_signature is called.
|
||||
For each knot/cable sum the function eval_cable_for_null_signature
|
||||
is called.
|
||||
eval_cable_for_null_signature calculetes the number of all possible thetas
|
||||
(characters) and the number of combinations for which signature function
|
||||
equeles zero. In case the first number is larger than squere of the second,
|
||||
@ -847,7 +378,7 @@ extract_max.__doc__ = \
|
||||
3300
|
||||
"""
|
||||
|
||||
eval_cable_for_null_signature.__doc__ = \
|
||||
TorusCable.eval_cable_for_null_signature.__doc__ = \
|
||||
"""
|
||||
This function calculates all possible twisted signature functions for
|
||||
a knot that is given as an argument. The knot should be encoded as a list
|
||||
@ -867,11 +398,11 @@ eval_cable_for_null_signature.__doc__ = \
|
||||
(0, 0, 0, 0)
|
||||
|
||||
sage:
|
||||
The numbers given to the function eval_cable_for_null_signature are k-values for each
|
||||
component/cable in a direct sum.
|
||||
The numbers given to the function eval_cable_for_null_signature
|
||||
are k-values for each component/cable in a direct sum.
|
||||
"""
|
||||
|
||||
get_signature_as_theta_function.__doc__ = \
|
||||
TorusCable.get_signature_as_function_of_theta.__doc__ = \
|
||||
"""
|
||||
Function intended to construct signature function for a connected
|
||||
sum of multiple cables with varying theta parameter values.
|
||||
@ -886,7 +417,7 @@ get_signature_as_theta_function.__doc__ = \
|
||||
To calculate signature function for a cable sum and a theta values vector,
|
||||
use as below.
|
||||
|
||||
sage: signature_function_generator = get_signature_as_theta_function(
|
||||
sage: signature_function_generator = get_signature_as_function_of_theta(
|
||||
[1, 3], [2], [-1, -2], [-3])
|
||||
sage: sf = signature_function_generator(2, 1, 2, 2)
|
||||
sage: print(sf)
|
||||
@ -909,7 +440,7 @@ get_signature_as_theta_function.__doc__ = \
|
||||
37/42: -1
|
||||
|
||||
Or like below.
|
||||
sage: print(get_signature_as_theta_function([1, 3], [2], [-1, -2], [-3]
|
||||
sage: print(get_signature_as_function_of_theta([1, 3], [2], [-1, -2], [-3]
|
||||
)(2, 1, 2, 2))
|
||||
0: 0
|
||||
1/7: 0
|
||||
@ -939,7 +470,7 @@ SignatureFunction.__doc__ = \
|
||||
This simple class encodes twisted and untwisted signature functions
|
||||
of knots. Since the signature function is entirely encoded by its signature
|
||||
jump, the class stores only information about signature jumps
|
||||
in a dictionary self.signature_jumps.
|
||||
in a dictionary self.cnt_signature_jumps.
|
||||
The dictionary stores data of the signature jump as a key/values pair,
|
||||
where the key is the argument at which the functions jumps
|
||||
and value encodes the value of the jump. Remember that we treat
|
||||
@ -958,13 +489,13 @@ get_signture_function_docsting = \
|
||||
+ Bl(K')(ksi_l^theta * t)
|
||||
"""
|
||||
|
||||
signature_as_theta_function_docstring = \
|
||||
signature_as_function_of_theta_docstring = \
|
||||
"""
|
||||
Arguments:
|
||||
|
||||
Returns object of SignatureFunction class for a previously defined
|
||||
connected sum of len(arg) cables.
|
||||
Acept len(arg) arguments: for each cable one theta parameter.
|
||||
Accept len(arg) arguments: for each cable one theta parameter.
|
||||
If call with no arguments, all theta parameters are set to be 0.
|
||||
"""
|
||||
|
||||
@ -1009,11 +540,11 @@ Zero theta combinations:
|
||||
|
||||
sage:
|
||||
|
||||
The numbers given to the function eval_cable_for_null_signature are k-values for each
|
||||
component/cable in a direct sum.
|
||||
The numbers given to the function eval_cable_for_null_signature are k-values
|
||||
for each component/cable in a direct sum.
|
||||
|
||||
To calculate signature function for a knot and a theta value, use function
|
||||
get_signature_as_theta_function (see help/docstring for details).
|
||||
get_signature_as_function_of_theta (see help/docstring for details).
|
||||
|
||||
About notation:
|
||||
Cables that we work with follow a schema:
|
||||
|
Loading…
Reference in New Issue
Block a user