Compare commits
No commits in common. "master" and "looking_for_big_signature" have entirely different histories.
master
...
looking_fo
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,4 +0,0 @@
|
|||||||
*~
|
|
||||||
*.pyc
|
|
||||||
__pycache__/
|
|
||||||
.ipynb_checkpoints
|
|
@ -1,5 +1,3 @@
|
|||||||
This project allows calculating knot invariants for linear combinations of iterated torus knots.
|
This script calculates signature functions for knots (cable sums).
|
||||||
It was created as part of proof for the main lemma from a paper "On the slice genus of generalized algebraic knots" (Maria Marchwicka and Wojciech Politarczyk).
|
The script can be run as a sage script from the terminal or used in interactive mode.
|
||||||
|
A knot (cable sum) is encoded as a list where each element (also a list) corresponds to a cable knot.
|
||||||
To recreate calculations that were done for the proof see lemma.ipynb in notebooks.
|
|
||||||
For a more detailed description see package documentation.
|
|
||||||
|
637
cable_signature.sage
Normal file
637
cable_signature.sage
Normal file
@ -0,0 +1,637 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
import numpy as np
|
||||||
|
import itertools as it
|
||||||
|
from typing import Iterable
|
||||||
|
from collections import Counter
|
||||||
|
from sage.arith.functions import LCM_list
|
||||||
|
import warnings
|
||||||
|
import re
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
# 9.11 (9.8)
|
||||||
|
# 9.15 (9.9)
|
||||||
|
PLOTS_DIR = "plots"
|
||||||
|
|
||||||
|
class CableSummand():
|
||||||
|
|
||||||
|
def __init__(self, knot_as_k_values):
|
||||||
|
self.knot_as_k_values = knot_as_k_values
|
||||||
|
|
||||||
|
self._knot_description = self.get_summand_descrption(knot_as_k_values)
|
||||||
|
self._signature_as_function_of_theta = None
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_summand_descrption(knot_as_k_values):
|
||||||
|
description = ""
|
||||||
|
if knot_as_k_values[0] < 0:
|
||||||
|
description += "-"
|
||||||
|
description += "T("
|
||||||
|
for k in knot_as_k_values:
|
||||||
|
description += "2, " + str(2 * abs(k) + 1) + "; "
|
||||||
|
return description[:-2] + ")"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def knot_description(self):
|
||||||
|
return self._knot_description
|
||||||
|
|
||||||
|
@property
|
||||||
|
def signature_as_function_of_theta(self):
|
||||||
|
if self._signature_as_function_of_theta is None:
|
||||||
|
self._signature_as_function_of_theta = \
|
||||||
|
self.get_summand_signature_as_theta_function()
|
||||||
|
return self._signature_as_function_of_theta
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_blanchfield_for_pattern(cls, k_n, theta=0):
|
||||||
|
|
||||||
|
msg = "Theorem on which this function is based, assumes " +\
|
||||||
|
"theta < k, where q = 2*k + 1 for pattern knot T(p, q)."
|
||||||
|
if theta == 0:
|
||||||
|
sf = cls.get_untwisted_signature_function(k_n)
|
||||||
|
return sf.square_root() + sf.minus_square_root()
|
||||||
|
|
||||||
|
k = abs(k_n)
|
||||||
|
assert theta <= k, msg
|
||||||
|
results = []
|
||||||
|
|
||||||
|
ksi = 1/(2 * k + 1)
|
||||||
|
|
||||||
|
counter = Counter()
|
||||||
|
# print("lambda_odd, i.e. (theta + e) % 2 != 0")
|
||||||
|
for e in range(1, k + 1):
|
||||||
|
if (theta + e) % 2 != 0:
|
||||||
|
counter[e * ksi] = 1 * sgn(k_n)
|
||||||
|
counter[1 - e * ksi] = -1 * sgn(k_n)
|
||||||
|
|
||||||
|
results.append((e * ksi, 1 * sgn(k_n)))
|
||||||
|
results.append((1 - e * ksi, -1 * sgn(k_n)))
|
||||||
|
|
||||||
|
# for example for k = 9 (q = 19) from this part we get
|
||||||
|
# for even theta
|
||||||
|
# 2/19: 1
|
||||||
|
# 4/19: 1
|
||||||
|
# 6/19: 1
|
||||||
|
# 8/19: 1
|
||||||
|
# 11/19: -1
|
||||||
|
# 13/19: -1
|
||||||
|
# 15/19: -1
|
||||||
|
# 17/19: -1
|
||||||
|
#
|
||||||
|
# for odd theta
|
||||||
|
# 1/19: 1
|
||||||
|
# 3/19: 1
|
||||||
|
# 5/19: 1
|
||||||
|
# 7/19: 1
|
||||||
|
# 9/19: 1
|
||||||
|
# 10/19: -1
|
||||||
|
# 12/19: -1
|
||||||
|
# 14/19: -1
|
||||||
|
# 16/19: -1
|
||||||
|
# 18/19: -1
|
||||||
|
|
||||||
|
# print("lambda_even")
|
||||||
|
# print("normal")
|
||||||
|
for e in range(1, theta):
|
||||||
|
if (theta + e) % 2 == 0:
|
||||||
|
results.append((e * ksi, 1 * sgn(k_n)))
|
||||||
|
results.append((1 - e * ksi, -1 * sgn(k_n)))
|
||||||
|
# print("reversed")
|
||||||
|
for e in range(theta + 1, k + 1):
|
||||||
|
if (theta + e) % 2 == 0:
|
||||||
|
results.append((e * ksi, -1 * sgn(k_n)))
|
||||||
|
results.append((1 - e * ksi, 1 * sgn(k_n)))
|
||||||
|
|
||||||
|
return SignatureFunction(values=results)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_satellite_part(cls, *knot_as_k_values, theta=0):
|
||||||
|
patt_k = knot_as_k_values[-1]
|
||||||
|
ksi = 1/(2 * abs(patt_k) + 1)
|
||||||
|
|
||||||
|
satellite_part = SignatureFunction()
|
||||||
|
# For each knot summand consider k values in reversed order,
|
||||||
|
# ommit k value for pattern.
|
||||||
|
for layer_num, k in enumerate(knot_as_k_values[:-1][::-1]):
|
||||||
|
sf = cls.get_untwisted_signature_function(k)
|
||||||
|
shift = theta * ksi * 2^layer_num
|
||||||
|
right_shift = sf >> shift
|
||||||
|
left__shift = sf << shift
|
||||||
|
for _ in range(layer_num):
|
||||||
|
right_shift = right_shift.double_cover()
|
||||||
|
left__shift = left__shift.double_cover()
|
||||||
|
satellite_part += right_shift + left__shift
|
||||||
|
return satellite_part
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_untwisted_signature_function(j):
|
||||||
|
# return the signature function of the T_{2, 2k+1} torus knot
|
||||||
|
k = abs(j)
|
||||||
|
q = 2 * k + 1
|
||||||
|
counter = Counter({(2 * a + 1)/(2 * q) : -sgn(j)
|
||||||
|
for a in range(k)})
|
||||||
|
counter.update(Counter({(2 * a + 1)/(2 * q) : sgn(j)
|
||||||
|
for a in range(k + 1, q)}))
|
||||||
|
return SignatureFunction(counter=counter)
|
||||||
|
|
||||||
|
|
||||||
|
def get_summand_signature_as_theta_function(self):
|
||||||
|
knot_as_k_values = self.knot_as_k_values
|
||||||
|
def get_summand_signture_function(theta):
|
||||||
|
|
||||||
|
patt_k = knot_as_k_values[-1]
|
||||||
|
|
||||||
|
# theta should not be larger than k for the pattern.
|
||||||
|
theta %= (2 * abs(patt_k) + 1)
|
||||||
|
theta = min(theta, 2 * abs(patt_k) + 1 - theta)
|
||||||
|
|
||||||
|
pattern_part = self.get_blanchfield_for_pattern(patt_k, theta)
|
||||||
|
satellite_part = self.get_satellite_part(*knot_as_k_values,
|
||||||
|
theta=theta)
|
||||||
|
return pattern_part, satellite_part
|
||||||
|
get_summand_signture_function.__doc__ = \
|
||||||
|
get_summand_signture_function_docsting
|
||||||
|
|
||||||
|
return get_summand_signture_function
|
||||||
|
|
||||||
|
def get_file_name_for_summand_plot(self, theta=0):
|
||||||
|
if self.knot_as_k_values[0] < 0:
|
||||||
|
name = "inv_T_"
|
||||||
|
else:
|
||||||
|
name = "T_"
|
||||||
|
for k in self.knot_as_k_values:
|
||||||
|
name += str(abs(k)) + "_"
|
||||||
|
name += "_theta_" + str(theta)
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
def plot_summand_for_theta(self, theta, save_path=None):
|
||||||
|
pp, sp = self.signature_as_function_of_theta(theta)
|
||||||
|
title = self.knot_description + ", theta = " + str(theta)
|
||||||
|
if save_path is not None:
|
||||||
|
file_name = self.get_file_name_for_summand_plot(theta)
|
||||||
|
save_path = os.path.join(save_path, file_name)
|
||||||
|
pp.plot_sum_with_other(sp, title=title, save_path=save_path)
|
||||||
|
|
||||||
|
|
||||||
|
def plot_summand(self):
|
||||||
|
range_limit = min(self.knot_as_k_values[-1] + 1, 3)
|
||||||
|
for theta in range(range_limit):
|
||||||
|
self.plot_summand_for_theta(theta)
|
||||||
|
|
||||||
|
class CableSum():
|
||||||
|
def __init__(self, knot_sum):
|
||||||
|
self.knot_sum_as_k_valus = knot_sum
|
||||||
|
self.knot_summands = [CableSummand(k) for k in knot_sum]
|
||||||
|
self.signature_as_function_of_theta = \
|
||||||
|
self.get_signature_as_function_of_theta()
|
||||||
|
|
||||||
|
def __call__(self, *thetas):
|
||||||
|
return self.signature_as_function_of_theta(*thetas)
|
||||||
|
|
||||||
|
def get_dir_name_for_plots(self, dir=None):
|
||||||
|
dir_name = ''
|
||||||
|
for knot in self.knot_summands:
|
||||||
|
if knot.knot_as_k_values[0] < 0:
|
||||||
|
dir_name += "inv_"
|
||||||
|
dir_name += "T_"
|
||||||
|
for k in knot.knot_as_k_values:
|
||||||
|
k = 2 * abs (k) + 1
|
||||||
|
dir_name += str(k) + "_"
|
||||||
|
dir_name = dir_name[:-1]
|
||||||
|
print(dir_name)
|
||||||
|
dir_path = os.getcwd()
|
||||||
|
if dir is not None:
|
||||||
|
dir_path = os.path.join(dir_path, dir)
|
||||||
|
dir_path = os.path.join(dir_path, dir_name)
|
||||||
|
|
||||||
|
if not os.path.isdir(dir_path):
|
||||||
|
os.mkdir(dir_path)
|
||||||
|
return dir_name
|
||||||
|
|
||||||
|
def plot_sum_for_theta_vector(self, thetas, save_to_dir=False):
|
||||||
|
if save_to_dir:
|
||||||
|
if not os.path.isdir(PLOTS_DIR):
|
||||||
|
os.mkdir(PLOTS_DIR)
|
||||||
|
dir_name = self.get_dir_name_for_plots(dir=PLOTS_DIR)
|
||||||
|
save_path = os.path.join(os.getcwd(), PLOTS_DIR)
|
||||||
|
save_path = os.path.join(save_path, dir_name)
|
||||||
|
else:
|
||||||
|
save_path = None
|
||||||
|
for i, knot in enumerate(self.knot_summands):
|
||||||
|
knot.plot_summand_for_theta(thetas[i], save_path=save_path)
|
||||||
|
|
||||||
|
pp, sp = self.signature_as_function_of_theta(*thetas)
|
||||||
|
title = self.knot_description + ", thetas = " + str(thetas)
|
||||||
|
if save_path is not None:
|
||||||
|
file_name = re.sub(r', ', '_', str(thetas))
|
||||||
|
file_name = re.sub(r'[\[\]]', '', str(file_name))
|
||||||
|
file_path = os.path.join(save_path, file_name)
|
||||||
|
pp.plot_sum_with_other(sp, title=title, save_path=file_path)
|
||||||
|
|
||||||
|
|
||||||
|
if save_path is not None:
|
||||||
|
file_path = os.path.join(save_path, "all_" + file_name)
|
||||||
|
sf_list = [knot.signature_as_function_of_theta(thetas[i])
|
||||||
|
for i, knot in enumerate(self.knot_summands)]
|
||||||
|
# pp, sp = knot.signature_as_function_of_theta(thetas[i])
|
||||||
|
# (pp + sp) = sp.plot
|
||||||
|
#
|
||||||
|
# pp.plot_sum_with_other(sp, title=title, save_path=file_path)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return dir_name
|
||||||
|
|
||||||
|
def plot_all_summands(self):
|
||||||
|
for knot in self.knot_summands:
|
||||||
|
knot.plot_summand()
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def knot_description(self):
|
||||||
|
return self._knot_description
|
||||||
|
|
||||||
|
@property
|
||||||
|
def patt_k_list(self):
|
||||||
|
return self._patt_k_list
|
||||||
|
|
||||||
|
@property
|
||||||
|
def patt_q_list(self):
|
||||||
|
return self._patt_q_list
|
||||||
|
|
||||||
|
# q_order is LCM of all q values for pattern knots
|
||||||
|
@property
|
||||||
|
def q_order(self):
|
||||||
|
return self._q_order
|
||||||
|
@q_order.setter
|
||||||
|
def q_order(self, val):
|
||||||
|
self._q_order = val
|
||||||
|
|
||||||
|
@property
|
||||||
|
def knot_sum_as_k_valus(self):
|
||||||
|
return self._knot_sum_as_k_valus
|
||||||
|
@knot_sum_as_k_valus.setter
|
||||||
|
def knot_sum_as_k_valus(self, knot_sum):
|
||||||
|
self._knot_sum_as_k_valus = knot_sum
|
||||||
|
self._knot_description = self.get_knot_descrption(knot_sum)
|
||||||
|
self._patt_k_list = [abs(i[-1]) for i in knot_sum]
|
||||||
|
self._patt_q_list = [2 * i + 1 for i in self._patt_k_list]
|
||||||
|
if any(n not in Primes() for n in self._patt_q_list):
|
||||||
|
msg = "Incorrect q-vector. This implementation assumes that" + \
|
||||||
|
" all last q values are prime numbers.\n" + \
|
||||||
|
str(self._patt_q_list)
|
||||||
|
raise ValueError(msg)
|
||||||
|
self.q_order = LCM_list(self._patt_q_list)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_thetas(self, *thetas):
|
||||||
|
summands_num = len(self.knot_sum_as_k_valus)
|
||||||
|
if not thetas:
|
||||||
|
thetas = summands_num * (0,)
|
||||||
|
elif len(thetas) == 1 and summands_num > 1:
|
||||||
|
if isinstance(thetas[0], Iterable):
|
||||||
|
if len(thetas[0]) >= summands_num:
|
||||||
|
thetas = thetas[0]
|
||||||
|
elif not thetas[0]:
|
||||||
|
thetas = summands_num * (0,)
|
||||||
|
elif thetas[0] == 0:
|
||||||
|
thetas = summands_num * (0,)
|
||||||
|
else:
|
||||||
|
msg = "This function takes at least " + str(summands_num) + \
|
||||||
|
" arguments or no argument at all (" + str(len(thetas)) \
|
||||||
|
+ " given)."
|
||||||
|
raise TypeError(msg)
|
||||||
|
return tuple(thetas)
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_knot_descrption(knot_sum):
|
||||||
|
description = ""
|
||||||
|
for knot in 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]
|
||||||
|
|
||||||
|
def get_signature_as_function_of_theta(self, **key_args):
|
||||||
|
if 'verbose' in key_args:
|
||||||
|
verbose_default = key_args['verbose']
|
||||||
|
else:
|
||||||
|
verbose_default = False
|
||||||
|
knot_desc = self.knot_description
|
||||||
|
|
||||||
|
def signature_as_function_of_theta(*thetas, **kwargs):
|
||||||
|
# print("\n\nsignature_as_function_of_theta " + knot_desc)
|
||||||
|
verbose = verbose_default
|
||||||
|
if 'verbose' in kwargs:
|
||||||
|
verbose = kwargs['verbose']
|
||||||
|
thetas = self.parse_thetas(*thetas)
|
||||||
|
|
||||||
|
satellite_part = SignatureFunction()
|
||||||
|
pattern_part = SignatureFunction()
|
||||||
|
|
||||||
|
# for each cable knot (summand) in cable sum apply theta
|
||||||
|
for i, knot in enumerate(self.knot_summands):
|
||||||
|
sfth = knot.signature_as_function_of_theta
|
||||||
|
pp, sp = sfth(thetas[i])
|
||||||
|
pattern_part += pp
|
||||||
|
satellite_part += sp
|
||||||
|
sf = pattern_part + satellite_part
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
print()
|
||||||
|
print(str(thetas))
|
||||||
|
print(sf)
|
||||||
|
assert sf.total_sign_jump() == 0
|
||||||
|
return pattern_part, satellite_part
|
||||||
|
|
||||||
|
signature_as_function_of_theta.__doc__ =\
|
||||||
|
signature_as_function_of_theta_docstring
|
||||||
|
return signature_as_function_of_theta
|
||||||
|
|
||||||
|
def is_metabolizer(self, theta):
|
||||||
|
# Check if square alternating difference
|
||||||
|
# divided by last q value is integer.
|
||||||
|
result = sum(el^2 / self.patt_q_list[idx] * (-1)^idx
|
||||||
|
for idx, el in enumerate(theta))
|
||||||
|
# for idx, el in enumerate(theta):
|
||||||
|
# old_sum += (el^2 / self.patt_q_list[idx] * (-1)^idx)
|
||||||
|
return result.is_integer()
|
||||||
|
|
||||||
|
def is_signature_big_in_ranges(self, ranges_list):
|
||||||
|
|
||||||
|
for thetas in it.product(*ranges_list):
|
||||||
|
|
||||||
|
# Check only non-zero metabolizers.
|
||||||
|
if not self.is_metabolizer(thetas) or not any(thetas):
|
||||||
|
continue
|
||||||
|
|
||||||
|
signature_is_small = True
|
||||||
|
# Check if any element generated by thetas vector
|
||||||
|
# has a large signature.
|
||||||
|
for shift in range(1, self.q_order):
|
||||||
|
shifted_thetas = [shift * th for th in thetas]
|
||||||
|
pp, sp = self.signature_as_function_of_theta(*shifted_thetas)
|
||||||
|
sf = pp + sp
|
||||||
|
limit = 5 + np.count_nonzero(shifted_thetas)
|
||||||
|
extremum = abs(sf.extremum(limit=limit))
|
||||||
|
if shift > 1:
|
||||||
|
print(shifted_thetas, end=" ")
|
||||||
|
print(extremum)
|
||||||
|
if extremum > limit:
|
||||||
|
signature_is_small = False
|
||||||
|
break
|
||||||
|
elif shift == 1:
|
||||||
|
print("*" * 10)
|
||||||
|
print(shifted_thetas, end=" ")
|
||||||
|
print(extremum)
|
||||||
|
if signature_is_small:
|
||||||
|
print("\n" * 10 + "!" * 1000)
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def is_signature_big_for_all_metabolizers(self):
|
||||||
|
num_of_summands = len(self.knot_sum_as_k_valus)
|
||||||
|
if num_of_summands % 4:
|
||||||
|
f_name = self.is_signature_big_for_all_metabolizers.__name__
|
||||||
|
msg = "Function {}".format(f_name) + " is implemented only for " +\
|
||||||
|
"knots that are direct sums of 4n direct summands."
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
for shift in range(0, num_of_summands, 4):
|
||||||
|
ranges_list = num_of_summands * [range(0, 1)]
|
||||||
|
ranges_list[shift : shift + 3] = \
|
||||||
|
[range(0, i + 1) for i in self.patt_k_list[shift: shift + 3]]
|
||||||
|
ranges_list[shift + 3] = range(0, 2)
|
||||||
|
if not self.is_signature_big_in_ranges(ranges_list):
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print("\nOK")
|
||||||
|
return True
|
||||||
|
|
||||||
|
class CableTemplate():
|
||||||
|
|
||||||
|
def __init__(self, knot_formula, q_vector=None, k_vector=None,
|
||||||
|
generate_q_vector=True, slice_candidate=True):
|
||||||
|
self._knot_formula = knot_formula
|
||||||
|
# q_i = 2 * k_i + 1
|
||||||
|
if k_vector is not None:
|
||||||
|
self.k_vector = k_vector
|
||||||
|
elif q_vector is not None:
|
||||||
|
self.q_vector = q_vector
|
||||||
|
elif generate_q_vector:
|
||||||
|
self.q_vector = self.get_q_vector(knot_formula, slice_candidate)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cable(self):
|
||||||
|
if self._cable is None:
|
||||||
|
msg = "q_vector for cable instance has not been set explicit. " + \
|
||||||
|
"The variable is assigned a default value."
|
||||||
|
warnings.warn(msg)
|
||||||
|
self.fill_q_vector()
|
||||||
|
return self._cable
|
||||||
|
|
||||||
|
def fill_q_vector(self, q_vector=None, slice=True):
|
||||||
|
if q_vector is None:
|
||||||
|
q_vector = self.get_q_vector(self.knot_formula)
|
||||||
|
self.q_vector = q_vector
|
||||||
|
|
||||||
|
@property
|
||||||
|
def knot_formula(self):
|
||||||
|
return self._knot_formula
|
||||||
|
|
||||||
|
@property
|
||||||
|
def k_vector(self):
|
||||||
|
return self._k_vector
|
||||||
|
@k_vector.setter
|
||||||
|
def k_vector(self, k):
|
||||||
|
self._k_vector = k
|
||||||
|
if self.extract_max(self.knot_formula) > len(k) - 1:
|
||||||
|
msg = "The vector for knot_formula evaluation is to short!"
|
||||||
|
msg += "\nk_vector " + str(k) + " \nknot_formula " \
|
||||||
|
+ str(self.knot_formula)
|
||||||
|
raise IndexError(msg)
|
||||||
|
|
||||||
|
self.knot_sum_as_k_valus = eval(self.knot_formula)
|
||||||
|
self._cable = CableSum(self.knot_sum_as_k_valus)
|
||||||
|
|
||||||
|
self._q_vector = [2 * k_val + 1 for k_val in k]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def q_vector(self):
|
||||||
|
return self._q_vector
|
||||||
|
@q_vector.setter
|
||||||
|
def q_vector(self, new_q_vector):
|
||||||
|
self.k_vector = [(q - 1)/2 for q in new_q_vector]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def extract_max(string):
|
||||||
|
numbers = re.findall(r'\d+', string)
|
||||||
|
numbers = map(int, numbers)
|
||||||
|
return max(numbers)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_q_vector(cls, knot_formula, slice=True):
|
||||||
|
lowest_number = 2
|
||||||
|
q_vector = [0] * (cls.extract_max(knot_formula) + 1)
|
||||||
|
P = Primes()
|
||||||
|
for layer in cls.get_layers_from_formula(knot_formula)[::-1]:
|
||||||
|
for el in layer:
|
||||||
|
q_vector[el] = P.next(lowest_number)
|
||||||
|
lowest_number = q_vector[el]
|
||||||
|
lowest_number *= 4
|
||||||
|
return q_vector
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_layers_from_formula(knot_formula):
|
||||||
|
k_indices = re.sub(r'[k-]', '', knot_formula)
|
||||||
|
k_indices = re.sub(r'\[\d+\]', lambda x: x.group()[1:-1], k_indices)
|
||||||
|
k_indices = eval(k_indices)
|
||||||
|
number_of_layers = max(len(lst) for lst in k_indices)
|
||||||
|
layers = []
|
||||||
|
for i in range(1, number_of_layers + 1):
|
||||||
|
layer = set()
|
||||||
|
for lst in k_indices:
|
||||||
|
if len(lst) >= i:
|
||||||
|
layer.add(lst[-i])
|
||||||
|
layers.append(layer)
|
||||||
|
return layers
|
||||||
|
|
||||||
|
def add_with_shift(self, other):
|
||||||
|
shift = self.extract_max(self.knot_formula) + 1
|
||||||
|
o_formula = re.sub(r'\d+', lambda x: str(int(x.group()) + shift),
|
||||||
|
other.knot_formula)
|
||||||
|
return self + CableTemplate(o_formula)
|
||||||
|
|
||||||
|
|
||||||
|
def __add__(self, other):
|
||||||
|
s_formula = self.knot_formula
|
||||||
|
o_formula = other.knot_formula
|
||||||
|
knot_formula = s_formula[:-1] + ",\n" + o_formula[1:]
|
||||||
|
cable_template = CableTemplate(knot_formula)
|
||||||
|
return cable_template
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def mod_one(n):
|
||||||
|
return n - floor(n)
|
||||||
|
|
||||||
|
|
||||||
|
# CableSum.get_knot_descrption.__doc__ = \
|
||||||
|
# """
|
||||||
|
# Arguments:
|
||||||
|
# arbitrary number of lists of numbers, each list encodes a single cable.
|
||||||
|
# Examples:
|
||||||
|
# sage: get_knot_descrption([1, 3], [2], [-1, -2], [-3])
|
||||||
|
# 'T(2, 3; 2, 7) # T(2, 5) # -T(2, 3; 2, 5) # -T(2, 7)'
|
||||||
|
# """
|
||||||
|
|
||||||
|
CableSum.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.
|
||||||
|
Accept arbitrary number of arguments (depending on number of cables in
|
||||||
|
connected sum).
|
||||||
|
Each argument should be given as list of integer representing
|
||||||
|
k - parameters for a cable: parameters k_i (i=1,.., n-1) for satelit knots
|
||||||
|
T(2, 2k_i + 1) and - the last one - k_n for a pattern knot T(2, 2k_n + 1).
|
||||||
|
Returns a function that will take theta vector as an argument and return
|
||||||
|
an object SignatureFunction.
|
||||||
|
|
||||||
|
To calculate signature function for a cable sum and a theta values vector,
|
||||||
|
use as below.
|
||||||
|
|
||||||
|
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)
|
||||||
|
0: 0
|
||||||
|
5/42: 1
|
||||||
|
1/7: 0
|
||||||
|
1/5: -1
|
||||||
|
7/30: -1
|
||||||
|
2/5: 1
|
||||||
|
3/7: 0
|
||||||
|
13/30: -1
|
||||||
|
19/42: -1
|
||||||
|
23/42: 1
|
||||||
|
17/30: 1
|
||||||
|
4/7: 0
|
||||||
|
3/5: -1
|
||||||
|
23/30: 1
|
||||||
|
4/5: 1
|
||||||
|
6/7: 0
|
||||||
|
37/42: -1
|
||||||
|
|
||||||
|
Or like below.
|
||||||
|
sage: print(get_signature_as_function_of_theta([1, 3], [2], [-1, -2], [-3]
|
||||||
|
)(2, 1, 2, 2))
|
||||||
|
0: 0
|
||||||
|
1/7: 0
|
||||||
|
1/6: 0
|
||||||
|
1/5: -1
|
||||||
|
2/5: 1
|
||||||
|
3/7: 0
|
||||||
|
1/2: 0
|
||||||
|
4/7: 0
|
||||||
|
3/5: -1
|
||||||
|
4/5: 1
|
||||||
|
5/6: 0
|
||||||
|
6/7: 0
|
||||||
|
"""
|
||||||
|
|
||||||
|
get_summand_signture_function_docsting = \
|
||||||
|
"""
|
||||||
|
This function returns SignatureFunction for previously defined single
|
||||||
|
cable T_(2, q) and a theta given as an argument.
|
||||||
|
The cable was defined by calling function
|
||||||
|
get_summand_signature_as_theta_function(*arg)
|
||||||
|
with the cable description as an argument.
|
||||||
|
It is an implementaion of the formula:
|
||||||
|
Bl_theta(K'_(2, d)) =
|
||||||
|
Bl_theta(T_2, d) + Bl(K')(ksi_l^(-theta) * t)
|
||||||
|
+ Bl(K')(ksi_l^theta * t)
|
||||||
|
"""
|
||||||
|
|
||||||
|
signature_as_function_of_theta_docstring = \
|
||||||
|
"""
|
||||||
|
Arguments:
|
||||||
|
|
||||||
|
Returns object of SignatureFunction class for a previously defined
|
||||||
|
connected sum of len(arg) cables.
|
||||||
|
Accept len(arg) arguments: for each cable one theta parameter.
|
||||||
|
If call with no arguments, all theta parameters are set to be 0.
|
||||||
|
"""
|
||||||
|
#
|
||||||
|
# CableSummand.get_blanchfield_for_pattern.__doc__ = \
|
||||||
|
# """
|
||||||
|
# Arguments:
|
||||||
|
# k_n: a number s.t. q_n = 2 * k_n + 1, where
|
||||||
|
# T(2, q_n) is a pattern knot for a single cable from a cable sum
|
||||||
|
# theta: twist/character for the cable (value form v vector)
|
||||||
|
# Return:
|
||||||
|
# SignatureFunction created for pattern signature function
|
||||||
|
# for a given cable and theta/character
|
||||||
|
# Based on:
|
||||||
|
# Proposition 9.8. in Twisted Blanchfield Pairing
|
||||||
|
# (https://arxiv.org/pdf/1809.08791.pdf)
|
||||||
|
# """
|
||||||
|
|
||||||
|
# CableSummand.get_summand_signature_as_theta_function.__doc__ = \
|
||||||
|
# """
|
||||||
|
# Argument:
|
||||||
|
# n integers that encode a single cable, i.e.
|
||||||
|
# values of q_i for T(2,q_0; 2,q_1; ... 2, q_n)
|
||||||
|
# Return:
|
||||||
|
# a function that returns SignatureFunction for this single cable
|
||||||
|
# and a theta given as an argument
|
||||||
|
# """
|
@ -1,64 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
r"""calculations of signature function and sigma invariant of generalized algebraic knots (GA-knots)
|
|
||||||
|
|
||||||
|
|
||||||
The package was used to prove Lemma 3.2 from a paper
|
|
||||||
'On the slice genus of generalized algebraic knots' Maria Marchwicka and Wojciech Politarczyk).
|
|
||||||
It contains the following submodules.
|
|
||||||
1) main.sage - with function prove_lemma
|
|
||||||
2) signature.sage - contains SignatureFunction class;
|
|
||||||
it encodes twisted and untwisted signature functions
|
|
||||||
of knots and allows to perform algebraic operations on them.
|
|
||||||
3) cable_signature.sage - contains the following classes:
|
|
||||||
a) CableSummand - it represents a single cable knot,
|
|
||||||
b) CableSum - it represents a cable sum, i. e. linear combination of single cable knots;
|
|
||||||
since the signature function and sigma invariant are additive under connected sum,
|
|
||||||
the class use calculations from CableSummand objects,
|
|
||||||
c) CableTemplate - it represents a scheme for a cable sums.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
from .utility import import_sage
|
|
||||||
import os
|
|
||||||
|
|
||||||
package = __name__.split('.')[0]
|
|
||||||
dirname = os.path.dirname
|
|
||||||
path = dirname(dirname(__file__))
|
|
||||||
import_sage('signature', package=package, path=path)
|
|
||||||
import_sage('cable_signature', package=package, path=path)
|
|
||||||
import_sage('main', package=package, path=path)
|
|
||||||
|
|
||||||
from .main import prove_lemma
|
|
||||||
|
|
||||||
|
|
||||||
# EXAMPLES::
|
|
||||||
#
|
|
||||||
# sage: eval_cable_for_null_signature([[1, 3], [2], [-1, -2], [-3]])
|
|
||||||
#
|
|
||||||
# T(2, 3; 2, 7) # T(2, 5) # -T(2, 3; 2, 5) # -T(2, 7)
|
|
||||||
# Zero cases: 1
|
|
||||||
# All cases: 1225
|
|
||||||
# Zero theta combinations:
|
|
||||||
# (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.
|
|
||||||
#
|
|
||||||
# To calculate signature function for a knot and a theta value, use function
|
|
||||||
# get_signature_as_function_of_theta (see help/docstring for details).
|
|
||||||
#
|
|
||||||
# About notation:
|
|
||||||
# Cables that we work with follow a schema:
|
|
||||||
# T(2, q_1; 2, q_2; 2, q_4) # -T(2, q_2; 2, q_4) #
|
|
||||||
# # T(2, q_3; 2, q_4) # -T(2, q_1; 2, q_3; 2, q_4)
|
|
||||||
# In knot_formula each k[i] is related with some q_i value, where
|
|
||||||
# q_i = 2*k[i] + 1.
|
|
||||||
# So we can work in the following steps:
|
|
||||||
# 1) choose a schema/formula by changing the value of knot_formula
|
|
||||||
# 2) set each q_i all or choose range in which q_i should varry
|
|
||||||
# 3) choose vector v / theta vector.
|
|
||||||
#
|
|
@ -1,863 +0,0 @@
|
|||||||
#!/usr/bin/env sage -python
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
import itertools as it
|
|
||||||
import warnings
|
|
||||||
import logging
|
|
||||||
import re
|
|
||||||
import ast
|
|
||||||
from typing import Iterable
|
|
||||||
from collections import Counter
|
|
||||||
from sage.arith.functions import LCM_list
|
|
||||||
# import importlib
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# preparsing sage script and import as module
|
|
||||||
if __name__ == '__main__': # TBD - check is this is optimal
|
|
||||||
from utility import import_sage
|
|
||||||
package = None
|
|
||||||
path = ''
|
|
||||||
else: # called from package
|
|
||||||
from .utility import import_sage
|
|
||||||
package = os.path.join( __name__.split('.')[0])
|
|
||||||
path = '../'
|
|
||||||
sg = import_sage('signature', package=package, path=path)
|
|
||||||
|
|
||||||
# constants - which invariants should be calculate
|
|
||||||
SIGMA = 0
|
|
||||||
SIGNATURE = 1
|
|
||||||
|
|
||||||
|
|
||||||
# #############################################################################
|
|
||||||
# 9.11 (9.8)
|
|
||||||
# 9.15 (9.9)
|
|
||||||
PLOTS_DIR = "../plots"
|
|
||||||
|
|
||||||
|
|
||||||
class CableSummand:
|
|
||||||
|
|
||||||
def __init__(self, knot_as_k_values, verbose=False):
|
|
||||||
|
|
||||||
self.verbose = verbose
|
|
||||||
self.knot_as_k_values = knot_as_k_values
|
|
||||||
self.knot_description = self.get_summand_descrption(knot_as_k_values)
|
|
||||||
self.signature_as_function_of_theta = \
|
|
||||||
self.get_summand_signature_as_theta_function()
|
|
||||||
self.sigma_as_function_of_theta = self.get_sigma_as_function_of_theta()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_summand_descrption(knot_as_k_values):
|
|
||||||
description = ""
|
|
||||||
if knot_as_k_values[0] < 0:
|
|
||||||
description += "-"
|
|
||||||
description += "T("
|
|
||||||
for k in knot_as_k_values:
|
|
||||||
description += "2, " + str(2 * abs(k) + 1) + "; "
|
|
||||||
return description[:-2] + ")"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_blanchfield_for_pattern(cls, k_n, theta=0):
|
|
||||||
|
|
||||||
msg = "Theorem on which this function is based, assumes " +\
|
|
||||||
"theta < k, where q = 2*k + 1 for pattern knot T(p, q)."
|
|
||||||
if theta == 0:
|
|
||||||
sf = cls.get_untwisted_signature_function(k_n)
|
|
||||||
return sf.square_root() + sf.minus_square_root()
|
|
||||||
|
|
||||||
k = abs(k_n)
|
|
||||||
assert theta <= k, msg
|
|
||||||
|
|
||||||
results = []
|
|
||||||
ksi = 1/(2 * k + 1)
|
|
||||||
|
|
||||||
# print("lambda_odd, i.e. (theta + e) % 2 != 0")
|
|
||||||
for e in range(1, k + 1):
|
|
||||||
if (theta + e) % 2 != 0:
|
|
||||||
results.append((e * ksi, 1 * sgn(k_n)))
|
|
||||||
results.append((1 - e * ksi, -1 * sgn(k_n)))
|
|
||||||
|
|
||||||
# for example for k = 9 (q = 19) from this part we get
|
|
||||||
# for even theta
|
|
||||||
# 2/19: 1
|
|
||||||
# 4/19: 1
|
|
||||||
# 6/19: 1
|
|
||||||
# 8/19: 1
|
|
||||||
# 11/19: -1
|
|
||||||
# 13/19: -1
|
|
||||||
# 15/19: -1
|
|
||||||
# 17/19: -1
|
|
||||||
#
|
|
||||||
# for odd theta
|
|
||||||
# 1/19: 1
|
|
||||||
# 3/19: 1
|
|
||||||
# 5/19: 1
|
|
||||||
# 7/19: 1
|
|
||||||
# 9/19: 1
|
|
||||||
# 10/19: -1
|
|
||||||
# 12/19: -1
|
|
||||||
# 14/19: -1
|
|
||||||
# 16/19: -1
|
|
||||||
# 18/19: -1
|
|
||||||
|
|
||||||
# print("lambda_even")
|
|
||||||
# print("normal")
|
|
||||||
for e in range(1, theta):
|
|
||||||
if (theta + e) % 2 == 0:
|
|
||||||
results.append((e * ksi, 1 * sgn(k_n)))
|
|
||||||
results.append((1 - e * ksi, -1 * sgn(k_n)))
|
|
||||||
# print("reversed")
|
|
||||||
for e in range(theta + 1, k + 1):
|
|
||||||
if (theta + e) % 2 == 0:
|
|
||||||
results.append((e * ksi, -1 * sgn(k_n)))
|
|
||||||
results.append((1 - e * ksi, 1 * sgn(k_n)))
|
|
||||||
|
|
||||||
return sg.SignatureFunction(values=results)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_satellite_part(cls, *knot_as_k_values, theta=0):
|
|
||||||
patt_k = knot_as_k_values[-1]
|
|
||||||
ksi = 1/(2 * abs(patt_k) + 1)
|
|
||||||
|
|
||||||
satellite_part = sg.SignatureFunction()
|
|
||||||
# For each knot summand consider k values in reversed order,
|
|
||||||
# ommit k value for pattern.
|
|
||||||
for layer_num, k in enumerate(knot_as_k_values[:-1][::-1]):
|
|
||||||
sf = cls.get_untwisted_signature_function(k)
|
|
||||||
shift = theta * ksi * 2^layer_num
|
|
||||||
right_shift = sf >> shift
|
|
||||||
left__shift = sf << shift
|
|
||||||
for _ in range(layer_num):
|
|
||||||
right_shift = right_shift.double_cover()
|
|
||||||
left__shift = left__shift.double_cover()
|
|
||||||
satellite_part += right_shift + left__shift
|
|
||||||
return satellite_part
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_untwisted_signature_function(k=None, q=None):
|
|
||||||
# return the signature function of the T_{2, 2k+1} torus knot
|
|
||||||
|
|
||||||
if q is not None:
|
|
||||||
signum = sign(q)
|
|
||||||
q = abs(q)
|
|
||||||
k = (q - 1)/2
|
|
||||||
elif k is not None:
|
|
||||||
signum = sign(k)
|
|
||||||
k = abs(k)
|
|
||||||
q = 2 * k + 1
|
|
||||||
else:
|
|
||||||
raise ValueError('k or q value must be given')
|
|
||||||
|
|
||||||
counter = Counter({(2 * a + 1)/(2 * q): -signum
|
|
||||||
for a in range(k)})
|
|
||||||
counter.update(Counter({(2 * a + 1)/(2 * q): signum
|
|
||||||
for a in range(k + 1, q)}))
|
|
||||||
return sg.SignatureFunction(counter=counter)
|
|
||||||
|
|
||||||
def get_summand_signature_as_theta_function(self):
|
|
||||||
# knot_as_k_values = self.knot_as_k_values
|
|
||||||
def get_summand_signture_function(theta):
|
|
||||||
|
|
||||||
patt_k = self.knot_as_k_values[-1]
|
|
||||||
|
|
||||||
# theta should not be larger than k for the pattern.
|
|
||||||
theta %= (2 * abs(patt_k) + 1)
|
|
||||||
theta = min(theta, 2 * abs(patt_k) + 1 - theta)
|
|
||||||
|
|
||||||
pattern_part = self.get_blanchfield_for_pattern(patt_k, theta)
|
|
||||||
satellite_part = self.get_satellite_part(*self.knot_as_k_values,
|
|
||||||
theta=theta)
|
|
||||||
sf = satellite_part + pattern_part
|
|
||||||
|
|
||||||
satellite_part.plot_title = self.knot_description + \
|
|
||||||
", theta = " + str(theta) + \
|
|
||||||
", satellite part."
|
|
||||||
pattern_part.plot_title = self.knot_description + \
|
|
||||||
", theta = " + str(theta) + \
|
|
||||||
", pattern part."
|
|
||||||
sf.plot_title = self.knot_description +\
|
|
||||||
", theta = " + str(theta)
|
|
||||||
|
|
||||||
return pattern_part, satellite_part, sf
|
|
||||||
get_summand_signture_function.__doc__ = \
|
|
||||||
get_summand_signture_function_docsting
|
|
||||||
|
|
||||||
return get_summand_signture_function
|
|
||||||
|
|
||||||
def get_file_name_for_summand_plot(self, theta=0):
|
|
||||||
if self.knot_as_k_values[0] < 0:
|
|
||||||
name = "inv_T_"
|
|
||||||
else:
|
|
||||||
name = "T_"
|
|
||||||
for k in self.knot_as_k_values:
|
|
||||||
name += str(abs(k)) + "_"
|
|
||||||
name += "_theta_" + str(theta)
|
|
||||||
return name
|
|
||||||
|
|
||||||
def plot_summand_for_theta(self, theta, save_path=None):
|
|
||||||
pp, sp, sf = self.signature_as_function_of_theta(theta)
|
|
||||||
title = self.knot_description + ", theta = " + str(theta)
|
|
||||||
if save_path is not None:
|
|
||||||
file_name = self.get_file_name_for_summand_plot(theta)
|
|
||||||
save_path = os.path.join(save_path, file_name)
|
|
||||||
sg.SignaturePloter.plot_sum_of_two(pp, sp, title=title,
|
|
||||||
save_path=save_path)
|
|
||||||
|
|
||||||
def plot_summand_sigma(self):
|
|
||||||
sigma = self.sigma_as_function_of_theta
|
|
||||||
# pattern part
|
|
||||||
th_values = list(range(abs(self.knot_as_k_values[-1]) + 1))
|
|
||||||
y = [sigma(th)[0] for th in th_values]
|
|
||||||
print("plot_summand_sigma")
|
|
||||||
print(th_values)
|
|
||||||
print(y)
|
|
||||||
|
|
||||||
# satellite_part
|
|
||||||
patt_k = self.knot_as_k_values[-1]
|
|
||||||
patt_q = 2 * abs(patt_k) + 1
|
|
||||||
ksi = 1/patt_q
|
|
||||||
x = []
|
|
||||||
s = self.get_untwisted_signature_function
|
|
||||||
list_of_signatue_functions = [s(k) for k in self.knot_as_k_values[:-1]]
|
|
||||||
for i, k in enumerate(self.knot_as_k_values[:-1][::-1]):
|
|
||||||
layer_num = i + 1
|
|
||||||
x.append(ksi * layer_num)
|
|
||||||
print("\nx")
|
|
||||||
print(x)
|
|
||||||
print(th_values)
|
|
||||||
print("\nx product")
|
|
||||||
x = list(set(it.product(x, th_values)))
|
|
||||||
x = [(a * b) for (a, b) in x]
|
|
||||||
print(x)
|
|
||||||
|
|
||||||
|
|
||||||
def print_sigma_as_function_of_theta(self, theta):
|
|
||||||
if not theta:
|
|
||||||
return
|
|
||||||
|
|
||||||
# theta should not be larger than q for the pattern.
|
|
||||||
patt_k = self.knot_as_k_values[-1]
|
|
||||||
|
|
||||||
patt_q = 2 * abs(patt_k) + 1
|
|
||||||
theta %= patt_q
|
|
||||||
|
|
||||||
ksi = 1/patt_q
|
|
||||||
|
|
||||||
# satellite part (Levine-Tristram signatures)
|
|
||||||
print(3 * "\n" + 10 * "#" + " " + self.knot_description +
|
|
||||||
" " + 10 * "#" + "\n")
|
|
||||||
|
|
||||||
satellite_part = 0
|
|
||||||
for layer_num, k in enumerate(self.knot_as_k_values[::-1]):
|
|
||||||
|
|
||||||
sigma_q = self.get_untwisted_signature_function(k)
|
|
||||||
arg = ksi * theta * layer_num
|
|
||||||
sp = sigma_q(arg)
|
|
||||||
satellite_part += 2 * sp
|
|
||||||
|
|
||||||
if details and arg:
|
|
||||||
label = "ksi * theta * layer_num = " + str(arg)
|
|
||||||
title = self.knot_description + ", layer " + str(layer_num)
|
|
||||||
title += ", theta = " + str(theta)
|
|
||||||
sigma_q.plot(special_point=(mod_one(arg), sp),
|
|
||||||
special_label=label,
|
|
||||||
title=title,)
|
|
||||||
|
|
||||||
pp = (-patt_q + 2 * theta - 2 * (theta^2/patt_q)) * sign(patt_k)
|
|
||||||
sigma = pp + satellite_part
|
|
||||||
print(self.knot_description + ", theta = " + str(theta))
|
|
||||||
print("pp = " + str(pp), end=', ')
|
|
||||||
print("satellite_part = " + str(satellite_part) + "\n")
|
|
||||||
|
|
||||||
def get_sigma_as_function_of_theta(self):
|
|
||||||
|
|
||||||
patt_k = self.knot_as_k_values[-1]
|
|
||||||
patt_q = 2 * abs(patt_k) + 1
|
|
||||||
ksi = 1/patt_q
|
|
||||||
|
|
||||||
def sigma_as_function_of_theta(theta):
|
|
||||||
if theta == 0:
|
|
||||||
return 0, 0, 0
|
|
||||||
|
|
||||||
# theta should not be larger than q for the pattern.
|
|
||||||
patt_k = self.knot_as_k_values[-1]
|
|
||||||
theta %= (2 * abs(patt_k) + 1)
|
|
||||||
|
|
||||||
satellite_part = 0
|
|
||||||
for i, k in enumerate(self.knot_as_k_values[:-1][::-1]):
|
|
||||||
layer_num = i + 1
|
|
||||||
sigma_q = self.get_untwisted_signature_function(k)
|
|
||||||
sp = 2 * sigma_q(ksi * theta * layer_num)
|
|
||||||
satellite_part += sp
|
|
||||||
if theta:
|
|
||||||
pp = (-patt_q + 2 * theta - 2 * (theta^2/patt_q)) * sign(patt_k)
|
|
||||||
else:
|
|
||||||
pp = 0
|
|
||||||
return pp, satellite_part, pp + satellite_part
|
|
||||||
return sigma_as_function_of_theta
|
|
||||||
|
|
||||||
|
|
||||||
class CableSum:
|
|
||||||
|
|
||||||
def __init__(self, knot_sum, verbose=False):
|
|
||||||
|
|
||||||
self.verbose = verbose
|
|
||||||
self.knot_sum_as_k_valus = knot_sum
|
|
||||||
self.knot_description = self.get_knot_descrption(knot_sum)
|
|
||||||
self.patt_k_list = [abs(i[-1]) for i in knot_sum]
|
|
||||||
self.patt_q_list = [2 * i + 1 for i in self.patt_k_list]
|
|
||||||
|
|
||||||
if any(n not in Primes() for n in self.patt_q_list):
|
|
||||||
msg = "Incorrect k- or q-vector. This implementation assumes that"\
|
|
||||||
+ " all last q values are prime numbers.\n" + \
|
|
||||||
str(self.patt_q_list)
|
|
||||||
raise ValueError(msg)
|
|
||||||
self.q_order = LCM_list(self.patt_q_list)
|
|
||||||
|
|
||||||
self.knot_summands = [CableSummand(k, verbose) for k in knot_sum]
|
|
||||||
self.signature_as_function_of_theta = \
|
|
||||||
self.get_signature_as_function_of_theta()
|
|
||||||
self.sigma_as_function_of_theta = \
|
|
||||||
self.get_sigma_as_function_of_theta()
|
|
||||||
|
|
||||||
|
|
||||||
def __call__(self, *thetas):
|
|
||||||
return self.signature_as_function_of_theta(*thetas)
|
|
||||||
|
|
||||||
def get_dir_name_for_plots(self, dir=None):
|
|
||||||
dir_name = ''
|
|
||||||
for knot in self.knot_summands:
|
|
||||||
if knot.knot_as_k_values[0] < 0:
|
|
||||||
dir_name += "inv_"
|
|
||||||
dir_name += "T_"
|
|
||||||
for k in knot.knot_as_k_values:
|
|
||||||
k = 2 * abs (k) + 1
|
|
||||||
dir_name += str(k) + "_"
|
|
||||||
dir_name = dir_name[:-1]
|
|
||||||
print(dir_name)
|
|
||||||
dir_path = os.getcwd()
|
|
||||||
if dir is not None:
|
|
||||||
dir_path = os.path.join(dir_path, dir)
|
|
||||||
dir_path = os.path.join(dir_path, dir_name)
|
|
||||||
|
|
||||||
if not os.path.isdir(dir_path):
|
|
||||||
os.mkdir(dir_path)
|
|
||||||
return dir_name
|
|
||||||
|
|
||||||
def plot_sum_for_theta_vector(self, thetas, save_to_dir=False):
|
|
||||||
if save_to_dir:
|
|
||||||
if not os.path.isdir(PLOTS_DIR):
|
|
||||||
os.mkdir(PLOTS_DIR)
|
|
||||||
dir_name = self.get_dir_name_for_plots(dir=PLOTS_DIR)
|
|
||||||
save_path = os.path.join(os.getcwd(), PLOTS_DIR)
|
|
||||||
save_path = os.path.join(save_path, dir_name)
|
|
||||||
else:
|
|
||||||
save_path = None
|
|
||||||
|
|
||||||
# for theta, knot in zip(thetas, self.knot_summands):
|
|
||||||
# knot.plot_summand_for_theta(thetas, save_path=save_path)
|
|
||||||
|
|
||||||
# pp, sp, sf = self.signature_as_function_of_theta(*thetas)
|
|
||||||
# title = self.knot_description + ", thetas = " + str(thetas)
|
|
||||||
# if save_path is not None:
|
|
||||||
# file_name = re.sub(r', ', '_', str(thetas))
|
|
||||||
# file_name = re.sub(r'[\[\]]', '', str(file_name))
|
|
||||||
# file_path = os.path.join(save_path, file_name)
|
|
||||||
# sg.SignaturePloter.plot_sum_of_two(pp, sp, title=title,
|
|
||||||
# save_path=file_path)
|
|
||||||
#
|
|
||||||
# if save_path is not None:
|
|
||||||
# file_path = os.path.join(save_path, "all_" + file_name)
|
|
||||||
# sf_list = [knot.signature_as_function_of_theta(thetas[i])[2]
|
|
||||||
# for i, knot in enumerate(self.knot_summands)]
|
|
||||||
# sg.SignaturePloter.plot_many(*sf_list, cols=2)
|
|
||||||
# pp, sp, sf = knot.signature_as_function_of_theta(thetas[i])
|
|
||||||
# (pp + sp) = sp.plot
|
|
||||||
#
|
|
||||||
# sg.SignatureFunction.plot_sum_of_two(pp, sp, title=title,
|
|
||||||
# save_path=file_path)
|
|
||||||
|
|
||||||
|
|
||||||
return dir_name
|
|
||||||
|
|
||||||
def plot_sigma_for_summands(self):
|
|
||||||
for knot in self.knot_summands:
|
|
||||||
knot.plot_summand_sigma()
|
|
||||||
|
|
||||||
def parse_thetas(self, *thetas):
|
|
||||||
summands_num = len(self.knot_sum_as_k_valus)
|
|
||||||
if not thetas:
|
|
||||||
thetas = summands_num * (0,)
|
|
||||||
elif len(thetas) == 1 and summands_num > 1:
|
|
||||||
if isinstance(thetas[0], Iterable):
|
|
||||||
if len(thetas[0]) >= summands_num:
|
|
||||||
thetas = thetas[0]
|
|
||||||
elif not thetas[0]:
|
|
||||||
thetas = summands_num * (0,)
|
|
||||||
elif thetas[0] == 0:
|
|
||||||
thetas = summands_num * (0,)
|
|
||||||
else:
|
|
||||||
msg = "This function takes at least " + str(summands_num) + \
|
|
||||||
" arguments or no argument at all (" + str(len(thetas)) \
|
|
||||||
+ " given)."
|
|
||||||
raise TypeError(msg)
|
|
||||||
return tuple(thetas)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_knot_descrption(knot_sum):
|
|
||||||
|
|
||||||
"""
|
|
||||||
Arguments:
|
|
||||||
arbitrary number of lists of numbers,
|
|
||||||
each list encodes a single cable.
|
|
||||||
Examples:
|
|
||||||
sage: get_knot_descrption([1, 3], [2], [-1, -2], [-3])
|
|
||||||
'T(2, 3; 2, 7) # T(2, 5) # -T(2, 3; 2, 5) # -T(2, 7)'
|
|
||||||
"""
|
|
||||||
|
|
||||||
description = ""
|
|
||||||
for knot in 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]
|
|
||||||
|
|
||||||
def get_sigma_as_function_of_theta(self, verbose=None):
|
|
||||||
default_verbose = verbose or self.verbose
|
|
||||||
|
|
||||||
def sigma_as_function_of_theta(*thetas, verbose=None, **kwargs):
|
|
||||||
|
|
||||||
verbose = verbose or default_verbose
|
|
||||||
thetas = self.parse_thetas(*thetas)
|
|
||||||
sigma = 0
|
|
||||||
for th, knot in zip(thetas, self.knot_summands):
|
|
||||||
_, _, s = knot.sigma_as_function_of_theta(th)
|
|
||||||
sigma += s
|
|
||||||
return sigma
|
|
||||||
|
|
||||||
return sigma_as_function_of_theta
|
|
||||||
|
|
||||||
def get_signature_as_function_of_theta(self, **key_args):
|
|
||||||
if 'verbose' in key_args:
|
|
||||||
verbose_default = key_args['verbose']
|
|
||||||
else:
|
|
||||||
verbose_default = False
|
|
||||||
knot_desc = self.knot_description
|
|
||||||
|
|
||||||
def signature_as_function_of_theta(*thetas, **kwargs):
|
|
||||||
# print("\n\nsignature_as_function_of_theta " + knot_desc)
|
|
||||||
verbose = verbose_default
|
|
||||||
if 'verbose' in kwargs:
|
|
||||||
verbose = kwargs['verbose']
|
|
||||||
thetas = self.parse_thetas(*thetas)
|
|
||||||
|
|
||||||
satellite_part = sg.SignatureFunction()
|
|
||||||
pattern_part = sg.SignatureFunction()
|
|
||||||
|
|
||||||
# for each cable knot (summand) in cable sum apply theta
|
|
||||||
for th, knot in zip(thetas, self.knot_summands):
|
|
||||||
pp, sp, _ = knot.signature_as_function_of_theta(th)
|
|
||||||
pattern_part += pp
|
|
||||||
satellite_part += sp
|
|
||||||
|
|
||||||
|
|
||||||
sf = pattern_part + satellite_part
|
|
||||||
|
|
||||||
if verbose:
|
|
||||||
print()
|
|
||||||
print(str(thetas))
|
|
||||||
print(sf)
|
|
||||||
assert sf.total_sign_jump() == 0
|
|
||||||
return pattern_part, satellite_part, sf
|
|
||||||
|
|
||||||
signature_as_function_of_theta.__doc__ =\
|
|
||||||
signature_as_function_of_theta_docstring
|
|
||||||
return signature_as_function_of_theta
|
|
||||||
|
|
||||||
def get_sign_ext_for_theta(self, thetas, limit):
|
|
||||||
_, _, sf = self.signature_as_function_of_theta(*thetas)
|
|
||||||
return sf.extremum(limit=limit)[1]
|
|
||||||
|
|
||||||
def is_metabolizer(self, theta):
|
|
||||||
# Check if square alternating difference
|
|
||||||
# divided by last q value is integer.
|
|
||||||
result = sum(el^2 / self.patt_q_list[idx] * (-1)^idx
|
|
||||||
for idx, el in enumerate(theta))
|
|
||||||
return result.is_integer()
|
|
||||||
|
|
||||||
def is_function_big_in_ranges(self, ranges_list, invariant=SIGMA,
|
|
||||||
verbose=None, details=False,
|
|
||||||
p_part_order=None):
|
|
||||||
verbose = verbose or self.verbose
|
|
||||||
p_part_order = p_part_order or self.q_order
|
|
||||||
|
|
||||||
if invariant == SIGNATURE:
|
|
||||||
get_invariant = self.get_sign_ext_for_theta
|
|
||||||
name = "signature (extremum)"
|
|
||||||
else:
|
|
||||||
get_invariant = self.sigma_as_function_of_theta
|
|
||||||
name = "sigma value"
|
|
||||||
|
|
||||||
if verbose:
|
|
||||||
msg = "\nCalculating {}-primary part.".format(p_part_order)
|
|
||||||
print(msg)
|
|
||||||
|
|
||||||
logging.info(str(ranges_list))
|
|
||||||
|
|
||||||
|
|
||||||
for thetas in it.product(*ranges_list):
|
|
||||||
|
|
||||||
# Check only non-zero metabolizers.
|
|
||||||
if not self.is_metabolizer(thetas) or not any(thetas):
|
|
||||||
continue
|
|
||||||
|
|
||||||
function_is_small = True
|
|
||||||
# Check if any element generated by thetas vector
|
|
||||||
# has a large signature or sigma.
|
|
||||||
for shift in range(1, p_part_order):
|
|
||||||
shifted_thetas = \
|
|
||||||
[(shift * th) % p_part_order for th in thetas]
|
|
||||||
limit = 5 + np.count_nonzero(shifted_thetas)
|
|
||||||
inv_value = get_invariant(shifted_thetas, limit=limit)
|
|
||||||
abs_value = abs(inv_value)
|
|
||||||
|
|
||||||
if verbose:
|
|
||||||
if shift == 1:
|
|
||||||
print("\n" + "*" * 10)
|
|
||||||
print("[ character ] " + name)
|
|
||||||
print(shifted_thetas, end=" ")
|
|
||||||
print(inv_value)
|
|
||||||
|
|
||||||
if abs_value > limit:
|
|
||||||
function_is_small = False
|
|
||||||
if details:
|
|
||||||
self.print_calculations_for_sigma(*shifted_thetas)
|
|
||||||
break
|
|
||||||
if function_is_small:
|
|
||||||
if verbose and invariant == SIGMA:
|
|
||||||
msg = "For an element x = " + str(thetas)
|
|
||||||
msg += " there does not exist any shift such that "
|
|
||||||
msg += "|sigma(K, shift * x)| > {}.\n".format(limit)
|
|
||||||
msg += "We can not give any lower bound for 4-genus."
|
|
||||||
print(msg)
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def print_calculations_for_sigma(self, *thetas):
|
|
||||||
|
|
||||||
print("Calculation details for a cable sum:\n" +
|
|
||||||
self.knot_description + "\nand theta vector: " +
|
|
||||||
str(thetas) + "\n")
|
|
||||||
|
|
||||||
for i, (th, knot) in enumerate(zip(thetas, self.knot_summands)):
|
|
||||||
print("{}. {}, theta = {}".format(i + 1, knot.knot_description, th))
|
|
||||||
if not th:
|
|
||||||
continue
|
|
||||||
patt_k = knot.knot_as_k_values[-1]
|
|
||||||
q = 2 * abs(patt_k) + 1
|
|
||||||
th %= q
|
|
||||||
if patt_k > 0:
|
|
||||||
print("Pattern part = pp")
|
|
||||||
else:
|
|
||||||
print("Pattern part = -pp")
|
|
||||||
|
|
||||||
print("pp = -q + 2 * theta * (q - theta)/q =")
|
|
||||||
print(" = -{} + 2 * {} * ({} - {} )/{} =".format(
|
|
||||||
q, th, q, th, q))
|
|
||||||
print(" = -{} + {} * ({} )/{} =".format(
|
|
||||||
q, 2 * th, q - th, q))
|
|
||||||
print(" = -{} + {} * {} = ".format(
|
|
||||||
q, 2 * th, (q - th)/ q))
|
|
||||||
print(" = -{} + {} = ".format(
|
|
||||||
q, 2 * th * (q - th)/ q))
|
|
||||||
print(" = {} ".format(
|
|
||||||
-q + (2 * th * (q - th)/ q)))
|
|
||||||
|
|
||||||
pp = (-q + 2 * th - 2 * (th^2/q)) * sign(patt_k)
|
|
||||||
sigma = knot.sigma_as_function_of_theta(th)
|
|
||||||
print("Pattern part = {} ~ {}".format(sigma[0],int(sigma[0])))
|
|
||||||
print("Satellite part = {}".format(sigma[1]))
|
|
||||||
print("Sigma = {} ~ {}\n".format(sigma[2], int(sigma[2])))
|
|
||||||
|
|
||||||
# function that proves the main lemma
|
|
||||||
def is_function_big_for_all_metabolizers(self, invariant=SIGMA,
|
|
||||||
verbose=False, details=False):
|
|
||||||
logging.info("start of is_function_big_for_all_metabolizers")
|
|
||||||
if invariant == SIGNATURE:
|
|
||||||
name = "signature (extremum)"
|
|
||||||
else:
|
|
||||||
name = "sigma value"
|
|
||||||
|
|
||||||
num_of_summands = len(self.knot_sum_as_k_valus)
|
|
||||||
if num_of_summands % 4:
|
|
||||||
f_name = self.is_signature_big_for_all_metabolizers.__name__
|
|
||||||
msg = "Function {}".format(f_name) + " is implemented only for " +\
|
|
||||||
"knots that are direct sums of 4n direct summands."
|
|
||||||
raise ValueError(msg)
|
|
||||||
|
|
||||||
# check each p-primary part separately
|
|
||||||
logging.info("number of summands is {}".format(num_of_summands))
|
|
||||||
for shift in range(0, num_of_summands, 4):
|
|
||||||
|
|
||||||
logging.info("shift is {}".format(shift))
|
|
||||||
p_part_order = 2 * self.patt_k_list[shift] + 1
|
|
||||||
|
|
||||||
logging.info("set character (twist) to be zero for all summands")
|
|
||||||
ranges_list = num_of_summands * [range(1)]
|
|
||||||
logging.info(str(ranges_list))
|
|
||||||
|
|
||||||
|
|
||||||
# change ranges for all but one character for current p-primary part
|
|
||||||
ranges_list[shift + 1 : shift + 4] = 3 * [range(p_part_order)]
|
|
||||||
|
|
||||||
# change range for first character in current p-primary part
|
|
||||||
# this one is consider to be 0 or 1
|
|
||||||
# For any characters combinations (vectors) [a_1, a_2, a_3, a_4]
|
|
||||||
# where a_4 != 0 exists such a k < p that k * a_1 % p == 1.
|
|
||||||
ranges_list[shift] = range(0, 2)
|
|
||||||
logging.info("\n\ncall is_function_big_in_ranges with values")
|
|
||||||
logging.info(str(ranges_list))
|
|
||||||
|
|
||||||
if not self.is_function_big_in_ranges(ranges_list, invariant,
|
|
||||||
p_part_order=p_part_order,
|
|
||||||
verbose=verbose,
|
|
||||||
details=details):
|
|
||||||
logging.info("Not proven.")
|
|
||||||
return False
|
|
||||||
if verbose and invariant == SIGMA:
|
|
||||||
msg = "For each p-primery part for each vector x there exist "
|
|
||||||
msg += "a number 0 < shift < p such that "
|
|
||||||
msg += "sigma(K, shift * x) > 5 + eta(K, shift * x)."
|
|
||||||
print(msg)
|
|
||||||
print("q.e.d.")
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class CableTemplate:
|
|
||||||
|
|
||||||
def __init__(self, knot_formula, q_vector=None, k_vector=None,
|
|
||||||
generate_q_vector=True, algebraic=True, verbose=False):
|
|
||||||
self.verbose = verbose
|
|
||||||
self._knot_formula = knot_formula
|
|
||||||
# q_i = 2 * k_i + 1
|
|
||||||
if k_vector is not None:
|
|
||||||
self.k_vector = k_vector
|
|
||||||
elif q_vector is not None:
|
|
||||||
self.q_vector = q_vector
|
|
||||||
elif generate_q_vector:
|
|
||||||
self.q_vector = self.get_q_vector(algebraic=slice)
|
|
||||||
self.templete_description = self.get_template_descrption()
|
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.templete_description
|
|
||||||
|
|
||||||
def get_template_descrption(self):
|
|
||||||
k_indices = re.sub(r'[k ]', '', self.knot_formula)
|
|
||||||
k_indices = re.sub(r'\[\d+\]', lambda x: x.group()[1:-1], k_indices)
|
|
||||||
k_indices = ast.literal_eval(k_indices)
|
|
||||||
description = ""
|
|
||||||
for summand in k_indices :
|
|
||||||
part = ""
|
|
||||||
if summand[0] < 0:
|
|
||||||
part += "-"
|
|
||||||
part += "T("
|
|
||||||
for k in summand:
|
|
||||||
part += "2, q_" + str(abs(k)) + "; "
|
|
||||||
description += part[:-2] + ") # "
|
|
||||||
return description[:-3]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def cable(self):
|
|
||||||
if self._cable is None:
|
|
||||||
msg = "q_vector for cable instance has not been set explicit. " + \
|
|
||||||
"The variable is assigned a default value."
|
|
||||||
warnings.warn(msg)
|
|
||||||
self.fill_q_vector()
|
|
||||||
return self._cable
|
|
||||||
|
|
||||||
def fill_q_vector(self, q_vector=None, algebraic=True, lowest_number=2):
|
|
||||||
self.q_vector = q_vector or self.get_q_vector(slice, lowest_number)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def knot_formula(self):
|
|
||||||
return self._knot_formula
|
|
||||||
|
|
||||||
@property
|
|
||||||
def k_vector(self):
|
|
||||||
return self._k_vector
|
|
||||||
@k_vector.setter
|
|
||||||
def k_vector(self, k):
|
|
||||||
self._k_vector = k
|
|
||||||
if self.extract_max(self.knot_formula) > len(k) - 1:
|
|
||||||
msg = "The vector for knot_formula evaluation is to short!"
|
|
||||||
msg += "Note that we count from 0 (not 1)."
|
|
||||||
msg += "\nk_vector " + str(k) + " \nknot_formula " \
|
|
||||||
+ str(self.knot_formula)
|
|
||||||
raise IndexError(msg)
|
|
||||||
|
|
||||||
self.knot_sum_as_k_valus = eval(self.knot_formula)
|
|
||||||
self._cable = CableSum(self.knot_sum_as_k_valus, verbose=self.verbose)
|
|
||||||
self._q_vector = [2 * k_val + 1 for k_val in k]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def q_vector(self):
|
|
||||||
return self._q_vector
|
|
||||||
@q_vector.setter
|
|
||||||
def q_vector(self, new_q_vector):
|
|
||||||
self.k_vector = [(q - 1)/2 for q in new_q_vector]
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def extract_max(string):
|
|
||||||
numbers = re.findall(r'\d+', string)
|
|
||||||
numbers = map(int, numbers)
|
|
||||||
return max(numbers)
|
|
||||||
|
|
||||||
def get_q_vector(self, algebraic=True, lowest_number=2):
|
|
||||||
r"""
|
|
||||||
Returns q-vector with certain properties.
|
|
||||||
|
|
||||||
If slice a specific relation for each cabling-level is preserved.
|
|
||||||
Consider a cable T(2, q_0; 2, q_1; ...; 2, q_n).
|
|
||||||
Then for every q_i, q_(i + 1): q_(i + 1) > q_i * 4
|
|
||||||
"""
|
|
||||||
knot_formula = self.knot_formula
|
|
||||||
q_vector = [0] * (self.extract_max(knot_formula) + 1)
|
|
||||||
P = Primes()
|
|
||||||
for layer in self._get_layers_from_formula(knot_formula)[::-1]:
|
|
||||||
for el in layer:
|
|
||||||
q_vector[el] = P.next(lowest_number)
|
|
||||||
lowest_number = q_vector[el]
|
|
||||||
if slice:
|
|
||||||
lowest_number *= 4
|
|
||||||
return q_vector
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_layers_from_formula(knot_formula):
|
|
||||||
r"""helper method for get_q_vector"""
|
|
||||||
k_indices = re.sub(r'[k-]', '', knot_formula)
|
|
||||||
k_indices = re.sub(r'\[\d+\]', lambda x: x.group()[1:-1], k_indices)
|
|
||||||
k_indices = eval(k_indices)
|
|
||||||
number_of_layers = max(len(lst) for lst in k_indices)
|
|
||||||
layers = []
|
|
||||||
for i in range(1, number_of_layers + 1):
|
|
||||||
layer = [lst[-i] for lst in k_indices if len(lst)>= i]
|
|
||||||
layers.append(layer)
|
|
||||||
return layers
|
|
||||||
|
|
||||||
def add_with_shift(self, other):
|
|
||||||
shift = self.extract_max(self.knot_formula) + 1
|
|
||||||
o_formula = re.sub(r'\d+', lambda x: str(int(x.group()) + shift),
|
|
||||||
other.knot_formula)
|
|
||||||
return self + CableTemplate(o_formula)
|
|
||||||
|
|
||||||
def __add__(self, other):
|
|
||||||
knot_formula = self.knot_formula[:-1] + ",\n" + other.knot_formula[1:]
|
|
||||||
return CableTemplate(knot_formula)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CableSum.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.
|
|
||||||
Accept arbitrary number of arguments (depending on number of cables in
|
|
||||||
connected sum).
|
|
||||||
Each argument should be given as list of integer representing
|
|
||||||
k - parameters for a cable: parameters k_i (i=1,.., n-1) for satelit knots
|
|
||||||
T(2, 2k_i + 1) and - the last one - k_n for a pattern knot T(2, 2k_n + 1).
|
|
||||||
Returns a function that will take theta vector as an argument and return
|
|
||||||
an object sg.SignatureFunction.
|
|
||||||
|
|
||||||
To calculate signature function for a cable sum and a theta values vector,
|
|
||||||
use as below.
|
|
||||||
|
|
||||||
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)
|
|
||||||
0: 0
|
|
||||||
5/42: 1
|
|
||||||
1/7: 0
|
|
||||||
1/5: -1
|
|
||||||
7/30: -1
|
|
||||||
2/5: 1
|
|
||||||
3/7: 0
|
|
||||||
13/30: -1
|
|
||||||
19/42: -1
|
|
||||||
23/42: 1
|
|
||||||
17/30: 1
|
|
||||||
4/7: 0
|
|
||||||
3/5: -1
|
|
||||||
23/30: 1
|
|
||||||
4/5: 1
|
|
||||||
6/7: 0
|
|
||||||
37/42: -1
|
|
||||||
|
|
||||||
Or like below.
|
|
||||||
sage: print(get_signature_as_function_of_theta([1, 3], [2], [-1, -2], [-3]
|
|
||||||
)(2, 1, 2, 2))
|
|
||||||
0: 0
|
|
||||||
1/7: 0
|
|
||||||
1/6: 0
|
|
||||||
1/5: -1
|
|
||||||
2/5: 1
|
|
||||||
3/7: 0
|
|
||||||
1/2: 0
|
|
||||||
4/7: 0
|
|
||||||
3/5: -1
|
|
||||||
4/5: 1
|
|
||||||
5/6: 0
|
|
||||||
6/7: 0
|
|
||||||
"""
|
|
||||||
|
|
||||||
get_summand_signture_function_docsting = \
|
|
||||||
"""
|
|
||||||
This function returns sg.SignatureFunction for previously defined single
|
|
||||||
cable T_(2, q) and a theta given as an argument.
|
|
||||||
The cable was defined by calling function
|
|
||||||
get_summand_signature_as_theta_function(*arg)
|
|
||||||
with the cable description as an argument.
|
|
||||||
It is an implementaion of the formula:
|
|
||||||
Bl_theta(K'_(2, d)) =
|
|
||||||
Bl_theta(T_2, d) + Bl(K')(ksi_l^(-theta) * t)
|
|
||||||
+ Bl(K')(ksi_l^theta * t)
|
|
||||||
"""
|
|
||||||
|
|
||||||
signature_as_function_of_theta_docstring = \
|
|
||||||
"""
|
|
||||||
Arguments:
|
|
||||||
|
|
||||||
Returns object of sg.SignatureFunction class for a previously defined
|
|
||||||
connected sum of len(arg) cables.
|
|
||||||
Accept len(arg) arguments: for each cable one theta parameter.
|
|
||||||
If call with no arguments, all theta parameters are set to be 0.
|
|
||||||
"""
|
|
||||||
#
|
|
||||||
# CableSummand.get_blanchfield_for_pattern.__doc__ = \
|
|
||||||
# """
|
|
||||||
# Arguments:
|
|
||||||
# k_n: a number s.t. q_n = 2 * k_n + 1, where
|
|
||||||
# T(2, q_n) is a pattern knot for a single cable from a cable sum
|
|
||||||
# theta: twist/character for the cable (value form v vector)
|
|
||||||
# Return:
|
|
||||||
# sg.SignatureFunction created for pattern signature function
|
|
||||||
# for a given cable and theta/character
|
|
||||||
# Based on:
|
|
||||||
# Proposition 9.8. in Twisted Blanchfield Pairing
|
|
||||||
# (https://arxiv.org/pdf/1809.08791.pdf)
|
|
||||||
# """
|
|
||||||
|
|
||||||
# CableSummand.get_summand_signature_as_theta_function.__doc__ = \
|
|
||||||
# """
|
|
||||||
# Argument:
|
|
||||||
# n integers that encode a single cable, i.e.
|
|
||||||
# values of q_i for T(2,q_0; 2,q_1; ... 2, q_n)
|
|
||||||
# Return:
|
|
||||||
# a function that returns sg.SignatureFunction for this single cable
|
|
||||||
# and a theta given as an argument
|
|
||||||
# """
|
|
@ -1,5 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
rm cable_signature.py
|
|
||||||
rm signature.py
|
|
||||||
rm main.py
|
|
325
gaknot/main.sage
325
gaknot/main.sage
@ -1,325 +0,0 @@
|
|||||||
#!/usr/bin/env sage -python
|
|
||||||
|
|
||||||
|
|
||||||
# TBD
|
|
||||||
# print scheme and knot nicely
|
|
||||||
# read about Factory Method, variable in docstring, sage documentation,
|
|
||||||
# print calc. to output file
|
|
||||||
# decide about printing option
|
|
||||||
# make __main__?
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import itertools as it
|
|
||||||
import re
|
|
||||||
import numpy as np
|
|
||||||
import importlib
|
|
||||||
|
|
||||||
# constants - which invariants should be calculate
|
|
||||||
SIGMA = 0
|
|
||||||
SIGNATURE = 1
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
from utility import import_sage
|
|
||||||
package = None
|
|
||||||
path = ''
|
|
||||||
|
|
||||||
else:
|
|
||||||
from .utility import import_sage
|
|
||||||
package = os.path.join( __name__.split('.')[0])
|
|
||||||
path = '../'
|
|
||||||
sg = import_sage('signature', package=package, path=path)
|
|
||||||
cs = import_sage('cable_signature', package=package, path=path)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# class Config:
|
|
||||||
# def __init__(self):
|
|
||||||
# self.f_results = os.path.join(os.getcwd(), "results.out")
|
|
||||||
|
|
||||||
class Schema:
|
|
||||||
r"""This class stores interesting schema of cable sums.
|
|
||||||
|
|
||||||
Cable knots sum can be given as a scheme, e.g. a scheme from the paper:
|
|
||||||
K(p_1 , p_2 , q_1 , q_2 , q_3 ) =
|
|
||||||
T(2, q_1; 2, p_1) # -T(2, q_2; 2, p_1) # T(2, p_1) # -T(2, q_3; 2, p_1) +
|
|
||||||
T(2, q_2; 2, p_2) # -T(2, p_2) # T(2, q_3; 2, p_2) # -T(2, q_1; 2, p_2).
|
|
||||||
We can represent it as nested list:
|
|
||||||
lemma_scheme = "[[ k[5], k[3]], " + \
|
|
||||||
"[ -k[1], -k[3]], " + \
|
|
||||||
"[ k[3]], " + \
|
|
||||||
"[ -k[6], -k[3]], " + \
|
|
||||||
"[ k[1], k[7]], " + \
|
|
||||||
"[ -k[7]], " + \
|
|
||||||
"[ k[6], k[7]], " + \
|
|
||||||
"[ -k[5], -k[7]]]",
|
|
||||||
where each k[i] corresponds to some q_i or p_i.
|
|
||||||
This expression will be later evaluated with k_vector.
|
|
||||||
See k_vector setter in class CableTemplate in cable_signature.sage module.
|
|
||||||
|
|
||||||
Remark 1
|
|
||||||
In the paper, we used p_i and q_i to describe torus knots and cables.
|
|
||||||
It was convenient for writing, but in all the code and documentation
|
|
||||||
only 'q' letter is used to encode torus knots or cables.
|
|
||||||
|
|
||||||
Remark 2
|
|
||||||
There are two ways to set k[i] values for a scheme:
|
|
||||||
via q_vector or k_vector.
|
|
||||||
Both should be lists and the relation is q[i] = 2 * k[i] + 1,
|
|
||||||
i.e. q should be an odd prime and k should be an even number such that
|
|
||||||
2 * k + 1 is prime.
|
|
||||||
To fill the scheme listed above we should use a list of length 8,
|
|
||||||
and k[0] will be omitted as it is not used in the scheme.
|
|
||||||
|
|
||||||
Remark 3
|
|
||||||
Except for development purposes, q_vector was computed with
|
|
||||||
a method CableTemplate.get_q_vector and flag slice=True.
|
|
||||||
The reason for that is that we were interested only in cases
|
|
||||||
where a specific relation for each cabling level is preserved.
|
|
||||||
Consider a cable T(2, q_0; 2, q_1; ...; 2, q_n).
|
|
||||||
Then for every q_i, q_(i + 1): q_(i + 1) > q_i * 4.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# scheme that is used in the paper
|
|
||||||
lemma_scheme_a = "[ [k[5], k[3]], " + \
|
|
||||||
"[ -k[1], -k[3]], " + \
|
|
||||||
"[ k[3]], " + \
|
|
||||||
"[ -k[6], -k[3]]]"
|
|
||||||
|
|
||||||
lemma_scheme_b = "[[ k[1], k[7]], " + \
|
|
||||||
"[ -k[7]], " + \
|
|
||||||
"[ k[6], k[7]], " + \
|
|
||||||
"[ -k[5], -k[7]]]"
|
|
||||||
|
|
||||||
lemma_scheme = "[[ k[5], k[3]], " + \
|
|
||||||
"[ -k[1], -k[3]], " + \
|
|
||||||
"[ k[3]], " + \
|
|
||||||
"[ -k[6], -k[3]], " + \
|
|
||||||
"[ k[1], k[7]], " + \
|
|
||||||
"[ -k[7]], " + \
|
|
||||||
"[ k[6], k[7]], " + \
|
|
||||||
"[ -k[5], -k[7]]]"
|
|
||||||
|
|
||||||
#
|
|
||||||
# formula_long = "[[k[0], k[5], k[3]], " + \
|
|
||||||
# "[ -k[5], -k[3]], " + \
|
|
||||||
# "[ k[2], k[3]], " + \
|
|
||||||
# "[-k[4], -k[2], -k[3]]" + \
|
|
||||||
# "[ k[4], k[1], k[7]], " + \
|
|
||||||
# "[ -k[1], -k[7]], " + \
|
|
||||||
# "[ k[6], k[7]], " + \
|
|
||||||
# "[-k[0], -k[6], -k[7]]]"
|
|
||||||
#
|
|
||||||
# formula_a = "[[k[0], k[5], k[3]], " + \
|
|
||||||
# "[ -k[1], -k[3]], " + \
|
|
||||||
# "[ k[3]], " + \
|
|
||||||
# "[-k[4], -k[6], -k[3]]]"
|
|
||||||
#
|
|
||||||
# formula_b = "[[k[4], k[1], k[7]], " + \
|
|
||||||
# "[ -k[7]], " + \
|
|
||||||
# "[ k[6], k[7]], " + \
|
|
||||||
# "[-k[0], -k[5], -k[7]]]"
|
|
||||||
#
|
|
||||||
# formula_a = "[[ k[0], k[5], k[3]], " + \
|
|
||||||
# "[ -k[1], -k[3]], " + \
|
|
||||||
# "[ k[2], k[3]], " + \
|
|
||||||
# "[ -k[0], -k[2], -k[3]]]"
|
|
||||||
#
|
|
||||||
# formula_b = "[[ k[4], k[1], k[7]], " + \
|
|
||||||
# "[ -k[5], -k[7]], " + \
|
|
||||||
# "[ k[6], k[7]], " + \
|
|
||||||
# "[ -k[4], -k[6], -k[7]]]"
|
|
||||||
#
|
|
||||||
# formula_a = "[[ k[0], k[5], k[3]], " + \
|
|
||||||
# "[ -k[5], -k[3]], " + \
|
|
||||||
# "[ k[2], k[3]], " + \
|
|
||||||
# "[-k[4], -k[2], -k[3]]]"
|
|
||||||
#
|
|
||||||
# formula_b = "[[ k[4], k[1], k[7]], " + \
|
|
||||||
# "[ -k[1], -k[7]], " + \
|
|
||||||
# "[ k[6], k[7]], " + \
|
|
||||||
# "[-k[0], -k[6], -k[7]]]"
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# three_layers_formula_a = "[[k[0], k[1], k[2]],\
|
|
||||||
# [ k[3], k[4]],\
|
|
||||||
# [-k[0], -k[3], -k[4]],\
|
|
||||||
# [ -k[1], -k[2]]]"
|
|
||||||
#
|
|
||||||
# three_layers_formula_b = "[[k[0], k[1], k[2]],\
|
|
||||||
# [ k[3]],\
|
|
||||||
# [-k[0], -k[1], -k[3]],\
|
|
||||||
# [ -k[2]]]"
|
|
||||||
#
|
|
||||||
# short_3_layers_b = "[[ k[5], k[3]], " + \
|
|
||||||
# "[ -k[1], -k[3]], " + \
|
|
||||||
# "[ k[3]], " + \
|
|
||||||
# "[ -k[4], -k[6], -k[3]]]"
|
|
||||||
#
|
|
||||||
# short_3_layers_b = "[[k[4], k[1], k[7]], " + \
|
|
||||||
# "[ -k[7]], " + \
|
|
||||||
# "[ k[6], k[7]], " + \
|
|
||||||
# "[ -k[5], -k[7]]]"
|
|
||||||
#
|
|
||||||
# four_summands_scheme = "[[ k[0], k[1], k[3]]," + \
|
|
||||||
# "[ -k[1], -k[3]]," + \
|
|
||||||
# "[ k[2], k[3]]," + \
|
|
||||||
# "[ -k[0], -k[2], -k[3]]]"
|
|
||||||
#
|
|
||||||
# two_summands_scheme = "[ [k[0], k[1], k[4]], [-k[1], -k[3]],\
|
|
||||||
# [k[2], k[3]], [-k[0], -k[2], -k[4]] ]"
|
|
||||||
# two_small_summands_scheme = "[[k[3]], [-k[3]],\
|
|
||||||
# [k[3]], [-k[3]] ]"
|
|
||||||
|
|
||||||
|
|
||||||
def main(arg=None):
|
|
||||||
try:
|
|
||||||
limit = int(arg[1])
|
|
||||||
except (IndexError, TypeError):
|
|
||||||
limit = None
|
|
||||||
conf = Config()
|
|
||||||
cable_loop_with_details(conf)
|
|
||||||
|
|
||||||
def prove_lemma(verbose=True, details=False):
|
|
||||||
|
|
||||||
if verbose:
|
|
||||||
msg = "CALCULATIONS OF THE SIGMA INVARIANT\n"
|
|
||||||
msg += "Proof of main lemma from "
|
|
||||||
msg += "ON THE SLICE GENUS OF GENERALIZED ALGEBRAIC KNOTS\n\n"
|
|
||||||
print(msg)
|
|
||||||
|
|
||||||
lemma_scheme = Schema.lemma_scheme
|
|
||||||
|
|
||||||
cable_template = cs.CableTemplate(knot_formula=lemma_scheme,
|
|
||||||
verbose=verbose)
|
|
||||||
cable_template.fill_q_vector()
|
|
||||||
q_v = cable_template.q_vector
|
|
||||||
cable = cable_template.cable
|
|
||||||
if verbose:
|
|
||||||
msg = "Let us consider a cable knot: \nK = "
|
|
||||||
msg += cable.knot_description + ".\n"
|
|
||||||
msg += "It is an example of cable knots of a scheme:\n"
|
|
||||||
msg += str(cable_template) + "."
|
|
||||||
print(msg)
|
|
||||||
|
|
||||||
cable.is_function_big_for_all_metabolizers(invariant=SIGMA,
|
|
||||||
verbose=verbose,
|
|
||||||
details=details)
|
|
||||||
|
|
||||||
|
|
||||||
def print_sigma_for_cable(verbose=True):
|
|
||||||
|
|
||||||
lemma_scheme_a = Schema.lemma_scheme_a
|
|
||||||
lemma_scheme_b = Schema.lemma_scheme_b
|
|
||||||
lemma_scheme = Schema.lemma_scheme
|
|
||||||
scheme_four = Schema.four_summands_scheme
|
|
||||||
|
|
||||||
cable_template = cs.CableTemplate(knot_formula=lemma_scheme)
|
|
||||||
cable_template.fill_q_vector()
|
|
||||||
q_v = cable_template.q_vector
|
|
||||||
print(q_v)
|
|
||||||
print(cable_template.cable.knot_description)
|
|
||||||
cable_a = cs.CableTemplate(knot_formula=lemma_scheme_a,
|
|
||||||
verbose=verbose,
|
|
||||||
q_vector=q_v
|
|
||||||
).cable
|
|
||||||
cable_b = cs.CableTemplate(knot_formula=lemma_scheme_b,
|
|
||||||
verbose=verbose,
|
|
||||||
q_vector=q_v
|
|
||||||
).cable
|
|
||||||
cable = cs.CableTemplate(knot_formula=lemma_scheme_a,
|
|
||||||
verbose=verbose,
|
|
||||||
q_vector=q_v
|
|
||||||
).cable
|
|
||||||
|
|
||||||
cable.plot_sigma_for_summands()
|
|
||||||
# cable_a.plot_sigma_for_summands()
|
|
||||||
# cable_b.plot_sigma_for_summands()
|
|
||||||
|
|
||||||
|
|
||||||
def cable_loop_with_details(verbose=True):
|
|
||||||
# verbose = False
|
|
||||||
lemma_scheme_a = Schema.lemma_scheme_a
|
|
||||||
lemma_scheme_b = Schema.lemma_scheme_b
|
|
||||||
lemma_scheme = Schema.lemma_scheme
|
|
||||||
cable_template = cs.CableTemplate(knot_formula=lemma_scheme)
|
|
||||||
|
|
||||||
list_of_q_vectors = []
|
|
||||||
# for el in [2, 3, 5, 7, 11, 13]:
|
|
||||||
for el in [2]:
|
|
||||||
cable_template.fill_q_vector(lowest_number=el)
|
|
||||||
q_v = cable_template.q_vector
|
|
||||||
print(q_v)
|
|
||||||
print(cable_template.cable.knot_description)
|
|
||||||
cable_a = cs.CableTemplate(knot_formula=lemma_scheme_a,
|
|
||||||
verbose=verbose,
|
|
||||||
q_vector=q_v
|
|
||||||
).cable
|
|
||||||
cable_b = cs.CableTemplate(knot_formula=lemma_scheme_b,
|
|
||||||
verbose=verbose,
|
|
||||||
q_vector=q_v
|
|
||||||
).cable
|
|
||||||
# print("\n")
|
|
||||||
# print(cable_a.knot_description)
|
|
||||||
is_a = cable_a.is_function_big_for_all_metabolizers(invariant=cs.SIGMA,
|
|
||||||
verbose=True,
|
|
||||||
details=True)
|
|
||||||
is_b = cable_b.is_function_big_for_all_metabolizers(invariant=cs.SIGMA,
|
|
||||||
verbose=True,
|
|
||||||
details=True)
|
|
||||||
if is_a and is_b:
|
|
||||||
print("sigma is big for all metabolizers")
|
|
||||||
else:
|
|
||||||
print("sigma is not big for all metabolizers")
|
|
||||||
print("\n" * 3)
|
|
||||||
|
|
||||||
|
|
||||||
def few_cable_without_calc(verbose=False):
|
|
||||||
|
|
||||||
lemma_scheme_a = Schema.lemma_scheme_a
|
|
||||||
lemma_scheme_b = Schema.lemma_scheme_b
|
|
||||||
lemma_scheme = Schema.lemma_scheme
|
|
||||||
|
|
||||||
cable_template = cs.CableTemplate(knot_formula=lemma_scheme)
|
|
||||||
|
|
||||||
list_of_q_vectors = []
|
|
||||||
for el in [2, 3, 5, 7, 11, 13]:
|
|
||||||
cable_template.fill_q_vector(lowest_number=el)
|
|
||||||
q_v = cable_template.q_vector
|
|
||||||
print(q_v)
|
|
||||||
print(cable_template.cable.knot_description)
|
|
||||||
cable_a = cs.CableTemplate(knot_formula=lemma_scheme_a,
|
|
||||||
verbose=verbose,
|
|
||||||
q_vector=q_v
|
|
||||||
).cable
|
|
||||||
cable_b = cs.CableTemplate(knot_formula=lemma_scheme_b,
|
|
||||||
verbose=verbose,
|
|
||||||
q_vector=q_v
|
|
||||||
).cable
|
|
||||||
is_a = cable_a.is_function_big_for_all_metabolizers(invariant=sigma)
|
|
||||||
is_b = cable_b.is_function_big_for_all_metabolizers(invariant=sigma)
|
|
||||||
if is_a and is_b:
|
|
||||||
print("sigma is big for all metabolizers")
|
|
||||||
else:
|
|
||||||
print("sigma is not big for all metabolizers")
|
|
||||||
print("\n" * 3)
|
|
||||||
|
|
||||||
|
|
||||||
def plot_many_untwisted_signature_functions(range_tuple=(1, 10)):
|
|
||||||
P = Primes()
|
|
||||||
for i in range(*range_tuple):
|
|
||||||
q = P.unrank(i)
|
|
||||||
a = cs.CableSummand.get_untwisted_signature_function(q=q)
|
|
||||||
a.plot()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
if '__file__' in globals():
|
|
||||||
# skiped in interactive mode as __file__ is not defined
|
|
||||||
main(sys.argv)
|
|
||||||
else:
|
|
||||||
pass
|
|
||||||
# main()
|
|
@ -1,90 +0,0 @@
|
|||||||
import importlib
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import re
|
|
||||||
import math
|
|
||||||
import logging
|
|
||||||
|
|
||||||
def mod_one(n):
|
|
||||||
r"""calculates the fractional part of the argument
|
|
||||||
|
|
||||||
Argument:
|
|
||||||
a number
|
|
||||||
Return:
|
|
||||||
the fractional part of the argument
|
|
||||||
Examples:
|
|
||||||
sage: mod_one(9 + 3/4)
|
|
||||||
3/4
|
|
||||||
sage: mod_one(-9 + 3/4)
|
|
||||||
3/4
|
|
||||||
sage: mod_one(-3/4)
|
|
||||||
1/4
|
|
||||||
"""
|
|
||||||
return n - math.floor(n)
|
|
||||||
|
|
||||||
|
|
||||||
def import_sage(module_name, package=None, path=''):
|
|
||||||
r"""Import or reload SageMath modules with preparse if the sage file exist.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
module_name - name of the module (without file extension!)
|
|
||||||
package - use only if module is used as a part of a package
|
|
||||||
Return:
|
|
||||||
module
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
from utility import import_sage
|
|
||||||
|
|
||||||
# equivalent to import module_name as my_prefered_shortcut}
|
|
||||||
my_prefered_shortcut = import_sage('module_name')
|
|
||||||
"""
|
|
||||||
sage_name = module_name + ".sage"
|
|
||||||
python_name = module_name + ".sage.py"
|
|
||||||
|
|
||||||
logging.info("\n\nimport_sage called with arguments:" +
|
|
||||||
"\n\tmodule_name: " + module_name +
|
|
||||||
"\n\tpackage: " + str(package) +
|
|
||||||
"\n\tpath: " + path)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if package is not None:
|
|
||||||
|
|
||||||
path_from_package_name = re.sub(r'\.', r'\\', package)
|
|
||||||
path = os.path.join(path, path_from_package_name)
|
|
||||||
|
|
||||||
logging.info("path with package name: " + str(path))
|
|
||||||
|
|
||||||
|
|
||||||
sage_path = os.path.join(path, sage_name)
|
|
||||||
python_path = os.path.join(path, python_name)
|
|
||||||
module_path = os.path.join(path, module_name)
|
|
||||||
|
|
||||||
if os.path.isfile(sage_path):
|
|
||||||
logging.info("\nPreparsing sage file " + sage_name + ".")
|
|
||||||
os.system('sage --preparse {}'.format(sage_path));
|
|
||||||
os.system('mv {} {}.py'.format(python_path, module_path))
|
|
||||||
else:
|
|
||||||
logging.info("sage file not found: " + str(sage_path))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if package is not None:
|
|
||||||
module_name = package + "." + module_name
|
|
||||||
|
|
||||||
if module_name in sys.modules:
|
|
||||||
logging.info("\nmodule " + module_name + " was found.")
|
|
||||||
return importlib.reload(sys.modules[module_name])
|
|
||||||
return importlib.import_module(module_name, package=package)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_sage(module_name):
|
|
||||||
|
|
||||||
dir = os.path.dirname(__file__)
|
|
||||||
|
|
||||||
sage_name = os.path.join(dir, module_name + ".sage")
|
|
||||||
python_name = os.path.join(dir, module_name + ".sage.py")
|
|
||||||
module_name = os.path.join(dir, module_name + ".py")
|
|
||||||
|
|
||||||
os.system('sage --preparse {}'.format(sage_name))
|
|
||||||
os.system('mv {} {}'.format(python_name, module_name))
|
|
173
main.sage
Normal file
173
main.sage
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# TBD: read about Factory Method, variable in docstring, sage documentation,
|
||||||
|
# print calc. to output file
|
||||||
|
# delete separation for twisted_part and untwisted_part
|
||||||
|
# decide about printing option
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import itertools as it
|
||||||
|
import re
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
attach("signature.sage")
|
||||||
|
attach("cable_signature.sage")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Config(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.f_results = os.path.join(os.getcwd(), "results.out")
|
||||||
|
|
||||||
|
# knot_formula is a schema for knots which signature function
|
||||||
|
# will be calculated
|
||||||
|
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[0], k[1], k[4]], [-k[1], -k[3]], \
|
||||||
|
# [k[2], k[3]], [-k[0], -k[2], -k[4]]]"
|
||||||
|
#
|
||||||
|
# self.knot_formula = "[[k[3]], [-k[3]], \
|
||||||
|
# [k[3]], [-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
|
||||||
|
|
||||||
|
self.verbose = True
|
||||||
|
# self.verbose = False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main(arg=None):
|
||||||
|
try:
|
||||||
|
limit = int(arg[1])
|
||||||
|
except (IndexError, TypeError):
|
||||||
|
limit = None
|
||||||
|
|
||||||
|
# global cable_template , cable_template_2, cable_template_1
|
||||||
|
|
||||||
|
knot_formula = "[[k[0], k[1], k[3]], " + \
|
||||||
|
"[-k[1], -k[3]], " + \
|
||||||
|
"[k[2], k[3]], " + \
|
||||||
|
"[-k[0], -k[2], -k[3]]]"
|
||||||
|
template = CableTemplate(knot_formula, q_vector=[3, 5, 7, 11])
|
||||||
|
cab = template.cable
|
||||||
|
# cab.plot_all_summands()
|
||||||
|
cab.plot_sum_for_theta_vector([0,4,0,4], save_to_dir=True)
|
||||||
|
# knot_formula = config.knot_formula
|
||||||
|
# q_vector = (3, 5, 7, 13)
|
||||||
|
# q_vector = (3, 5, 7, 11)
|
||||||
|
return
|
||||||
|
|
||||||
|
formula_1 = "[[k[0], k[5], k[3]], " + \
|
||||||
|
"[-k[1], -k[3]], " + \
|
||||||
|
"[k[2], k[3]], " + \
|
||||||
|
"[-k[0], -k[2], -k[3]]]"
|
||||||
|
formula_2 = "[[k[4], k[1], k[7]], " + \
|
||||||
|
"[-k[5], -k[7]], " + \
|
||||||
|
"[k[6], k[7]], " + \
|
||||||
|
"[-k[4], -k[6], -k[7]]]"
|
||||||
|
q_vector = (5, 13, 19, 41,\
|
||||||
|
7, 17, 23, 43)
|
||||||
|
q_vector_small = (3, 7, 13, 19,\
|
||||||
|
5, 11, 17, 23)
|
||||||
|
|
||||||
|
cable_template_1 = CableTemplate(knot_formula=formula_1)
|
||||||
|
cable_template_2 = CableTemplate(knot_formula=formula_2)
|
||||||
|
cable_template = cable_template_1 + cable_template_2
|
||||||
|
cable_with_shift = cable_template_1.add_with_shift(cable_template_2)
|
||||||
|
print(cable_with_shift.knot_formula)
|
||||||
|
cable_template.fill_q_vector()
|
||||||
|
cable = cable_template.cable
|
||||||
|
|
||||||
|
sf = cable(4,4,4,4,0,0,0,0)
|
||||||
|
writer = SignatureWriter(sf)
|
||||||
|
writer.plot(title="hoho")
|
||||||
|
|
||||||
|
sf = cable_template.cable.signature_as_function_of_theta(4,1,1,4,0,0,0,0)
|
||||||
|
writer = SignatureWriter(sf)
|
||||||
|
writer.plot(title="hoho", color='red')
|
||||||
|
|
||||||
|
|
||||||
|
cable_template.cable.is_signature_big_for_all_metabolizers()
|
||||||
|
|
||||||
|
|
||||||
|
cable_template_1 = CableTemplate(knot_formula=formula_1)
|
||||||
|
cable_template_2 = CableTemplate(knot_formula=formula_2)
|
||||||
|
cable_template = cable_template_1 + cable_template_2
|
||||||
|
cable_template.cable.is_signature_big_for_all_metabolizers()
|
||||||
|
sf = cable_template.cable.signature_as_function_of_theta(4,4,4,4,0,0,0,0)
|
||||||
|
writer = SignatureWriter(sf)
|
||||||
|
writer.plot(title="hoho")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
global config
|
||||||
|
config = Config()
|
||||||
|
if '__file__' in globals():
|
||||||
|
# skiped in interactive mode as __file__ is not defined
|
||||||
|
main(sys.argv)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
# main()
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
This script calculates signature functions for knots (cable sums).
|
||||||
|
|
||||||
|
The script can be run as a sage script from the terminal
|
||||||
|
or used in interactive mode.
|
||||||
|
|
||||||
|
A knot (cable sum) is encoded as a list where each element (also a list)
|
||||||
|
corresponds to a cable knot, e.g. a list
|
||||||
|
[[1, 3], [2], [-1, -2], [-3]] encodes
|
||||||
|
T(2, 3; 2, 7) # T(2, 5) # -T(2, 3; 2, 5) # -T(2, 7).
|
||||||
|
|
||||||
|
To calculate the number of characters for which signature function vanish use
|
||||||
|
the function eval_cable_for_null_signature as shown below.
|
||||||
|
|
||||||
|
sage: eval_cable_for_null_signature([[1, 3], [2], [-1, -2], [-3]])
|
||||||
|
|
||||||
|
T(2, 3; 2, 7) # T(2, 5) # -T(2, 3; 2, 5) # -T(2, 7)
|
||||||
|
Zero cases: 1
|
||||||
|
All cases: 1225
|
||||||
|
Zero theta combinations:
|
||||||
|
(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.
|
||||||
|
|
||||||
|
To calculate signature function for a knot and a theta value, use function
|
||||||
|
get_signature_as_function_of_theta (see help/docstring for details).
|
||||||
|
|
||||||
|
About notation:
|
||||||
|
Cables that we work with follow a schema:
|
||||||
|
T(2, q_1; 2, q_2; 2, q_4) # -T(2, q_2; 2, q_4) #
|
||||||
|
# T(2, q_3; 2, q_4) # -T(2, q_1; 2, q_3; 2, q_4)
|
||||||
|
In knot_formula each k[i] is related with some q_i value, where
|
||||||
|
q_i = 2*k[i] + 1.
|
||||||
|
So we can work in the following steps:
|
||||||
|
1) choose a schema/formula by changing the value of knot_formula
|
||||||
|
2) set each q_i all or choose range in which q_i should varry
|
||||||
|
3) choose vector v / theata vector.
|
||||||
|
"""
|
@ -1,99 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import path\n",
|
|
||||||
"import logging\n",
|
|
||||||
"from contextlib import redirect_stdout\n",
|
|
||||||
"# logging.basicConfig(level=logging.INFO)\n",
|
|
||||||
"import gaknot"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Lemma "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"scrolled": false
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"gaknot.prove_lemma()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Details to file"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"with open('very_detailed_calculations.txt', 'w') as f:\n",
|
|
||||||
" with redirect_stdout(f):\n",
|
|
||||||
" gaknot.prove_lemma(details=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Calculations to file"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"with open('calculations.txt', 'w') as f:\n",
|
|
||||||
" with redirect_stdout(f):\n",
|
|
||||||
" gaknot.prove_lemma(details=False)\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "SageMath 9.0",
|
|
||||||
"language": "sage",
|
|
||||||
"name": "sagemath"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.8.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
module_path = os.path.abspath(os.pardir)
|
|
||||||
if module_path not in sys.path:
|
|
||||||
sys.path.append(module_path)
|
|
@ -1,580 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%matplotlib inline\n",
|
|
||||||
"%load_ext pycodestyle_magic\n",
|
|
||||||
"\n",
|
|
||||||
"# display full output, not only last result, except ended with semicolon\n",
|
|
||||||
"from IPython.core.interactiveshell import InteractiveShell\n",
|
|
||||||
"InteractiveShell.ast_node_interactivity = 'all';\n",
|
|
||||||
"from IPython.display import Image, SVG\n",
|
|
||||||
"import logging\n",
|
|
||||||
"logging.basicConfig(level=logging.INFO)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import path\n",
|
|
||||||
"from gaknot import import_sage\n",
|
|
||||||
"cs = import_sage('cable_signature', package='gaknot', path=path.module_path)\n",
|
|
||||||
"sg = import_sage('signature', package='gaknot', path=path.module_path)\n",
|
|
||||||
"m = import_sage('main', package='gaknot', path=path.module_path)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"scrolled": false
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"m.prove_lemma(verbose=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Other cables"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"scrolled": false
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# knot_formula = \"[[k[0], k[1], k[3]],\" + \\\n",
|
|
||||||
"# \" [-k[1], -k[3]],\" + \\\n",
|
|
||||||
"# \" [k[2], k[3]],\" + \\\n",
|
|
||||||
"# \" [-k[0], -k[2], -k[3]]]\"\n",
|
|
||||||
"# # q_vector = (3, 5, 7, 13)\n",
|
|
||||||
"# q_vector = (3, 5, 7, 11)\n",
|
|
||||||
"\n",
|
|
||||||
"# template = cs.CableTemplate(knot_formula, q_vector=q_vector, verbose=True)\n",
|
|
||||||
"# cable = template.cable\n",
|
|
||||||
"# # cable.plot_all_summands()\n",
|
|
||||||
"# cable.is_function_big_for_all_metabolizers(invariant=cs.SIGMA)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Cables with 8 direct summands "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"formula_1 = \"[[k[0], k[5], k[3]], \" + \\\n",
|
|
||||||
" \"[-k[1], -k[3]], \" + \\\n",
|
|
||||||
" \"[k[2], k[3]], \" + \\\n",
|
|
||||||
" \"[-k[0], -k[2], -k[3]]]\"\n",
|
|
||||||
"formula_2 = \"[[k[4], k[1], k[7]], \" + \\\n",
|
|
||||||
" \"[-k[5], -k[7]], \" + \\\n",
|
|
||||||
" \"[k[6], k[7]], \" + \\\n",
|
|
||||||
" \"[-k[4], -k[6], -k[7]]]\"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# cable_template_1 = cs.CableTemplate(knot_formula=formula_1)\n",
|
|
||||||
"# cable_template_2 = cs.CableTemplate(knot_formula=formula_2)\n",
|
|
||||||
"# cable_template = cable_template_1 + cable_template_2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# cable_template.knot_formula"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Relatively small cables "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# q_vector = (5, 13, 19, 41,\\\n",
|
|
||||||
"# 7, 17, 23, 43)\n",
|
|
||||||
"# cable_template.fill_q_vector(q_vector=q_vector)\n",
|
|
||||||
"# cable = cable_template.cable\n",
|
|
||||||
"# print(cable.knot_description)\n",
|
|
||||||
"\n",
|
|
||||||
"# q_vector_small = (3, 7, 13, 19,\\\n",
|
|
||||||
"# 5, 11, 17, 23)\n",
|
|
||||||
"# cable_template.fill_q_vector(q_vector=q_vector)\n",
|
|
||||||
"# cable = cable_template.cable\n",
|
|
||||||
"# print(cable.knot_description)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"scrolled": true
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# cable.is_signature_big_for_all_metabolizers()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Slice candidate"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"\n",
|
|
||||||
"# cable_template.fill_q_vector()\n",
|
|
||||||
"# # print(cable_template.q_vector)\n",
|
|
||||||
"# # print(cable_template.knot_formula)\n",
|
|
||||||
"\n",
|
|
||||||
"# slice_canidate = cable_template.cable\n",
|
|
||||||
"# print(slice_canidate.knot_description)\n",
|
|
||||||
"# sf = slice_canidate(4,4,4,4,0,0,0,0)\n",
|
|
||||||
"# sf = slice_canidate(4,1,1,4,0,0,0,0)\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# cable.is_signature_big_for_all_metabolizers()\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# knot_formula = \"[[k[0], k[1], k[4]], [-k[1], -k[3]],\\\n",
|
|
||||||
"# [k[2], k[3]], [-k[0], -k[2], -k[4]]]\"\n",
|
|
||||||
"\n",
|
|
||||||
"# knot_formula = \"[[k[3]], [-k[3]],\\\n",
|
|
||||||
"# [k[3]], [-k[3]] ]\"\n",
|
|
||||||
"\n",
|
|
||||||
"# knot_formula = \"[[k[3], k[2], k[0]], [-k[2], -k[0]],\\\n",
|
|
||||||
"# [k[1], k[0]], [-k[3], -k[1], -k[0]]]\"\n",
|
|
||||||
"\n",
|
|
||||||
"# knot_formula = \"[[k[0], k[1], k[2]], [k[3], k[4]],\\\n",
|
|
||||||
"# [-k[0], -k[3], -k[4]], [-k[1], -k[2]]]\"\n",
|
|
||||||
"\n",
|
|
||||||
"# knot_formula = \"[[k[0], k[1], k[2]], [k[3]],\\\n",
|
|
||||||
"# [-k[0], -k[1], -k[3]], [-k[2]]]\""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"formula_1 = \"[[k[0], k[5], k[3]], \" + \\\n",
|
|
||||||
" \"[-k[1], -k[3]], \" + \\\n",
|
|
||||||
" \"[k[2], k[3]], \" + \\\n",
|
|
||||||
" \"[-k[0], -k[2], -k[3]]]\"\n",
|
|
||||||
"formula_2 = \"[[k[4], k[1], k[7]], \" + \\\n",
|
|
||||||
" \"[-k[5], -k[7]], \" + \\\n",
|
|
||||||
" \"[k[6], k[7]], \" + \\\n",
|
|
||||||
" \"[-k[4], -k[6], -k[7]]]\"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# cable_template_1 = cs.CableTemplate(knot_formula=formula_1)\n",
|
|
||||||
"# cable_template_2 = cs.CableTemplate(knot_formula=formula_2)\n",
|
|
||||||
"# cable_template = cable_template_1 + cable_template_2\n",
|
|
||||||
"\n",
|
|
||||||
"# cable_template.fill_q_vector()\n",
|
|
||||||
"# # print(cable_template.q_vector)\n",
|
|
||||||
"# # print(cable_template.knot_formula)\n",
|
|
||||||
"\n",
|
|
||||||
"# slice_canidate = cable_template.cable\n",
|
|
||||||
"# print(slice_canidate.knot_description)\n",
|
|
||||||
"# sf = slice_canidate(4,4,4,4,0,0,0,0)\n",
|
|
||||||
"# sf = slice_canidate(4,1,1,4,0,0,0,0)\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# slice_canidate.q_order\n",
|
|
||||||
"# # slice_canidate.is_signature_big_for_all_metabolizers()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"formula_1 = \"[[k[0], k[5], k[3]], \" + \\\n",
|
|
||||||
" \"[-k[5], -k[3]], \" + \\\n",
|
|
||||||
" \"[k[2], k[3]], \" + \\\n",
|
|
||||||
" \"[-k[4], -k[2], -k[3]]]\"\n",
|
|
||||||
"formula_2 = \"[[k[4], k[1], k[7]], \" + \\\n",
|
|
||||||
" \"[-k[1], -k[7]], \" + \\\n",
|
|
||||||
" \"[k[6], k[7]], \" + \\\n",
|
|
||||||
" \"[-k[0], -k[6], -k[7]]]\"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# cable_template_1 = cs.CableTemplate(knot_formula=formula_1)\n",
|
|
||||||
"# cable_template_2 = cs.CableTemplate(knot_formula=formula_2)\n",
|
|
||||||
"# cable_template = cable_template_1 + cable_template_2\n",
|
|
||||||
"# cable_template.fill_q_vector()\n",
|
|
||||||
"\n",
|
|
||||||
"# slice_canidate = cable_template.cable\n",
|
|
||||||
"# print(slice_canidate.knot_description)\n",
|
|
||||||
"\n",
|
|
||||||
"# slice_canidate.q_order\n",
|
|
||||||
"# # slice_canidate.is_signature_big_for_all_metabolizers()\n",
|
|
||||||
"# sigma = slice_canidate.get_sigma_as_function_of_theta()\n",
|
|
||||||
"# # sigma((0, 6, 6, 0, 0,0,0,0))\n",
|
|
||||||
"# # 13450/83\n",
|
|
||||||
"# sigma((9, 9, 9, 9, 0,0,0,0))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"scrolled": false
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"formula_1 = \"[[k[0], k[5], k[3]], \" + \\\n",
|
|
||||||
" \"[-k[1], -k[3]], \" + \\\n",
|
|
||||||
" \"[ k[3]], \" + \\\n",
|
|
||||||
" \"[-k[4], -k[6], -k[3]]]\"\n",
|
|
||||||
"\n",
|
|
||||||
"formula_2 = \"[[k[4], k[1], k[7]], \" + \\\n",
|
|
||||||
" \"[ -k[7]], \" + \\\n",
|
|
||||||
" \"[k[6], k[7]], \" + \\\n",
|
|
||||||
" \"[-k[0], -k[5], -k[7]]]\"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# cable_template_1 = cs.CableTemplate(knot_formula=formula_1)\n",
|
|
||||||
"# cable_template_2 = cs.CableTemplate(knot_formula=formula_2)\n",
|
|
||||||
"# cable_template = cable_template_1 + cable_template_2\n",
|
|
||||||
"\n",
|
|
||||||
"# cable_template.fill_q_vector()\n",
|
|
||||||
"# # print(cable_template.q_vector)\n",
|
|
||||||
"# # print(cable_template.knot_formula)\n",
|
|
||||||
"\n",
|
|
||||||
"# slice_canidate = cable_template.cable\n",
|
|
||||||
"# print(slice_canidate.knot_description)\n",
|
|
||||||
"# sf = slice_canidate(4,4,4,4,0,0,0,0)\n",
|
|
||||||
"# sf = slice_canidate(4,1,1,4,0,0,0,0)\n",
|
|
||||||
"# slice_canidate.is_signature_big_for_all_metabolizers()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"scrolled": false
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"formula_1 = \" [ [k[5], k[3]], \" + \\\n",
|
|
||||||
" \" [ -k[1], -k[3]], \" + \\\n",
|
|
||||||
" \" [ k[3]], \" + \\\n",
|
|
||||||
" \"[-k[4], -k[6], -k[3]]]\"\n",
|
|
||||||
"\n",
|
|
||||||
"formula_2 = \"[[k[4], k[1], k[7]], \" + \\\n",
|
|
||||||
" \"[ -k[7]], \" + \\\n",
|
|
||||||
" \"[k[6], k[7]], \" + \\\n",
|
|
||||||
" \"[-k[5], -k[7]]]\"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# cable_template_1 = cs.CableTemplate(knot_formula=formula_1)\n",
|
|
||||||
"# cable_template_2 = cs.CableTemplate(knot_formula=formula_2)\n",
|
|
||||||
"# cable_template = cable_template_1 + cable_template_2\n",
|
|
||||||
"\n",
|
|
||||||
"# cable_template.fill_q_vector()\n",
|
|
||||||
"# # print(cable_template.q_vector)\n",
|
|
||||||
"# # print(cable_template.knot_formula)\n",
|
|
||||||
"\n",
|
|
||||||
"# slice_canidate = cable_template.cable\n",
|
|
||||||
"# print(slice_canidate.knot_description)\n",
|
|
||||||
"# sf = slice_canidate(4,4,4,4,0,0,0,0)\n",
|
|
||||||
"# sf = slice_canidate(4,1,1,4,0,0,0,0)\n",
|
|
||||||
"# slice_canidate.q_order\n",
|
|
||||||
"# # slice_canidate.is_signature_big_for_all_metabolizers()\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# sf = slice_canidate()\n",
|
|
||||||
"# sf = sf[2]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# sf.plot()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"formula_1 = \"[ [k[5], k[3]], \" + \\\n",
|
|
||||||
" \"[ -k[1], -k[3]], \" + \\\n",
|
|
||||||
" \"[ k[3]], \" + \\\n",
|
|
||||||
" \"[ -k[6], -k[3]]]\"\n",
|
|
||||||
"\n",
|
|
||||||
"formula_2 = \"[[ k[1], k[7]], \" + \\\n",
|
|
||||||
" \"[ -k[7]], \" + \\\n",
|
|
||||||
" \"[ k[6], k[7]], \" + \\\n",
|
|
||||||
" \"[ -k[5], -k[7]]]\""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# cable_template_1 = cs.CableTemplate(knot_formula=formula_1)\n",
|
|
||||||
"# cable_template_2 = cs.CableTemplate(knot_formula=formula_2)\n",
|
|
||||||
"# cable_template = cable_template_1 + cable_template_2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# cable_template.knot_formula"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# cable_template.fill_q_vector()\n",
|
|
||||||
"# print(cable_template.q_vector)\n",
|
|
||||||
"# print(cable_template.knot_formula)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# cable_template.fill_q_vector()\n",
|
|
||||||
"# print(cable_template.q_vector)\n",
|
|
||||||
"# print(cable_template.knot_formula)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# slice_canidate = cable_template.cable\n",
|
|
||||||
"# print(slice_canidate.knot_description)\n",
|
|
||||||
"# sf = slice_canidate(4,4,4,4,0,0,0,0)\n",
|
|
||||||
"# sf = slice_canidate(4,1,1,4,0,0,0,0)\n",
|
|
||||||
"# slice_canidate.q_order"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# slice_canidate.is_sigma_big_for_all_metabolizers()\n",
|
|
||||||
"# slice_canidate.is_signature_big_for_all_metabolizers()\n",
|
|
||||||
"# slice_canidate.is_function_big_for_all_metabolizers()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"scrolled": true
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# slice_canidate.is_function_big_for_all_metabolizers(invariant=cs.SIGMA)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"scrolled": true
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# slice_canidate.is_function_big_for_all_metabolizers(invariant=cs.SIGNATURE)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# sigma = slice_canidate.get_sigma_as_function_of_theta()\n",
|
|
||||||
"# sigma((0, 6, 6, 0, 0,0,0,0))\n",
|
|
||||||
"# # 13450/83\n",
|
|
||||||
"# sigma((9, 0, 0, 9, 0,0,0,0))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# _, _, sf = slice_canidate((1, 1, 0, 0, 0,0,0,0))\n",
|
|
||||||
"# sf"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# sg.SignaturePloter.plot(sf)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"scrolled": true
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"\n",
|
|
||||||
"# slice_canidate.plot_sum_for_theta_vector([0r,4r,0r,4r,0r,0r,0r,0r], save_to_dir=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# sf.plot()\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# help(cs.CableTemplate.get_q_vector)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "SageMath 9.0",
|
|
||||||
"language": "sage",
|
|
||||||
"name": "sagemath"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.8.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
@ -1,51 +1,28 @@
|
|||||||
#!/usr/bin/env sage -python
|
#!/usr/bin/python
|
||||||
|
import numpy as np
|
||||||
import sys
|
import itertools as it
|
||||||
# import os
|
from typing import Iterable
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
from sage.arith.functions import LCM_list
|
||||||
|
import warnings
|
||||||
|
import re
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import inspect
|
import inspect
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import warnings
|
|
||||||
from .utility import mod_one
|
|
||||||
|
|
||||||
|
|
||||||
# check if used in Jupyter Notebook to show plots in proper way
|
|
||||||
JUPYTER = 'ipykernel'
|
|
||||||
IPy_TERMINAL = 'IPython'
|
|
||||||
|
|
||||||
def get_ipython_info():
|
|
||||||
if JUPYTER in sys.modules:
|
|
||||||
return JUPYTER
|
|
||||||
elif IPy_TERMINAL in sys.modules:
|
|
||||||
return IPy_TERMINAL
|
|
||||||
return False
|
|
||||||
|
|
||||||
global ipython_info
|
|
||||||
ipython_info = get_ipython_info()
|
|
||||||
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# 9.11 (9.8)
|
# 9.11 (9.8)
|
||||||
# 9.15 (9.9)
|
# 9.15 (9.9)
|
||||||
|
|
||||||
|
|
||||||
class SignatureFunction:
|
class SignatureFunction():
|
||||||
r"""signature function is entirely encoded by its signature
|
|
||||||
jump, the class stores only information about signature jumps
|
def __init__(self, values=None, counter=None):
|
||||||
in a dictionary self.jumps_counter
|
|
||||||
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
|
|
||||||
signature functions as defined on the interval \[0,1).
|
|
||||||
"""
|
|
||||||
def __init__(self, values=None, counter=None, plot_title=''):
|
|
||||||
|
|
||||||
# counter of signature jumps
|
# counter of signature jumps
|
||||||
if counter is None:
|
if counter is None:
|
||||||
counter = Counter()
|
counter = Counter()
|
||||||
values = values or []
|
if values is None:
|
||||||
|
values = []
|
||||||
for k, v in values:
|
for k, v in values:
|
||||||
counter[k] += v
|
counter[k] += v
|
||||||
|
|
||||||
@ -57,7 +34,6 @@ class SignatureFunction:
|
|||||||
counter[0] += 0
|
counter[0] += 0
|
||||||
counter[1] += 0
|
counter[1] += 0
|
||||||
self.jumps_counter = counter
|
self.jumps_counter = counter
|
||||||
self.plot_title = plot_title
|
|
||||||
|
|
||||||
def __rshift__(self, shift):
|
def __rshift__(self, shift):
|
||||||
# A shift of the signature functions corresponds to the rotation.
|
# A shift of the signature functions corresponds to the rotation.
|
||||||
@ -76,26 +52,13 @@ class SignatureFunction:
|
|||||||
def __add__(self, other):
|
def __add__(self, other):
|
||||||
counter = copy(self.jumps_counter)
|
counter = copy(self.jumps_counter)
|
||||||
counter.update(other.jumps_counter)
|
counter.update(other.jumps_counter)
|
||||||
if self.plot_title and other.plot_title:
|
return SignatureFunction(counter=counter)
|
||||||
title = self.plot_title + " + " + other.plot_title
|
|
||||||
else:
|
|
||||||
title = self.plot_title or other.plot_title
|
|
||||||
return SignatureFunction(counter=counter, plot_title=title)
|
|
||||||
|
|
||||||
def __sub__(self, other):
|
def __sub__(self, other):
|
||||||
counter = copy(self.jumps_counter)
|
counter = copy(self.jumps_counter)
|
||||||
counter.subtract(other.jumps_counter)
|
counter.subtract(other.jumps_counter)
|
||||||
return SignatureFunction(counter=counter)
|
return SignatureFunction(counter=counter)
|
||||||
|
|
||||||
def __mul__(self, number):
|
|
||||||
# scalar multiplication
|
|
||||||
counter = Counter({k : number * v \
|
|
||||||
for k, v in self.jumps_counter.items()})
|
|
||||||
return SignatureFunction(counter=counter)
|
|
||||||
|
|
||||||
def __rmul__(self, number):
|
|
||||||
return(self.__mul__(number))
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return self.jumps_counter == other.jumps_counter
|
return self.jumps_counter == other.jumps_counter
|
||||||
|
|
||||||
@ -116,6 +79,9 @@ class SignatureFunction:
|
|||||||
result = [jump for jump_arg, jump in items if jump_arg < mod_one(arg)]
|
result = [jump for jump_arg, jump in items if jump_arg < mod_one(arg)]
|
||||||
return 2 * sum(result) + self.jumps_counter[arg]
|
return 2 * sum(result) + self.jumps_counter[arg]
|
||||||
|
|
||||||
|
def is_zero_everywhere(self):
|
||||||
|
return not any(self.jumps_counter.values())
|
||||||
|
|
||||||
def double_cover(self):
|
def double_cover(self):
|
||||||
# to read values for t^2
|
# to read values for t^2
|
||||||
items = self.jumps_counter.items()
|
items = self.jumps_counter.items()
|
||||||
@ -137,74 +103,75 @@ class SignatureFunction:
|
|||||||
counter = Counter({mod_one(2 * k) : v for k, v in items if k >= 1/2})
|
counter = Counter({mod_one(2 * k) : v for k, v in items if k >= 1/2})
|
||||||
return SignatureFunction(counter=counter)
|
return SignatureFunction(counter=counter)
|
||||||
|
|
||||||
def is_zero_everywhere(self):
|
def extremum(self, limit=None):
|
||||||
return not any(self.jumps_counter.values())
|
max = 0
|
||||||
|
|
||||||
def extremum(self, limit=math.inf):
|
|
||||||
max_point = (0, 0)
|
|
||||||
current = 0
|
current = 0
|
||||||
items = sorted(self.jumps_counter.items())
|
items = sorted(self.jumps_counter.items())
|
||||||
for arg, jump in items:
|
for arg, jump in items:
|
||||||
current += 2 * jump
|
current += 2 * jump
|
||||||
assert current == self(arg) + jump
|
assert current == self(arg) + jump
|
||||||
if abs(current) > abs(max_point[1]):
|
if abs(current) > abs(max):
|
||||||
max_point = (arg, current)
|
max = current
|
||||||
if abs(current) > limit:
|
if limit is not None:
|
||||||
|
if abs(max) > limit:
|
||||||
break
|
break
|
||||||
return max_point
|
return max
|
||||||
|
|
||||||
def total_sign_jump(self):
|
def total_sign_jump(self):
|
||||||
# Total signature jump is the sum of all jumps.
|
# Total signature jump is the sum of all jumps.
|
||||||
return sum([j[1] for j in sorted(self.jumps_counter.items())])
|
return sum([j[1] for j in sorted(self.jumps_counter.items())])
|
||||||
|
|
||||||
def plot(self, *args, **kargs):
|
def plot_four(self, sf1, sf2, sf3, save_path=None, title=''):
|
||||||
SignaturePloter.plot(self, *args, **kargs)
|
|
||||||
|
|
||||||
|
fig, axes_matrix = plt.subplots(2, 2, sharey=True,
|
||||||
class SignaturePloter:
|
figsize=(10,5))
|
||||||
|
sf0 = self
|
||||||
@classmethod
|
|
||||||
def plot_many(cls, *sf_list, save_path=None, title='', cols=None):
|
|
||||||
|
|
||||||
axes_num = len(sf_list)
|
|
||||||
if axes_num > 36:
|
|
||||||
sf_list = sf_list[36]
|
|
||||||
axes_num = 36
|
|
||||||
msg = "To many functions for the plot were given. "
|
|
||||||
msg += "Only 36 can be plotted "
|
|
||||||
warnings.warn(msg)
|
|
||||||
|
|
||||||
# print war, set val in conf
|
|
||||||
cols = cols or ceil(sqrt(axes_num))
|
|
||||||
rows = ceil(axes_num/cols)
|
|
||||||
fig, axes_matrix = plt.subplots(rows, cols,
|
|
||||||
sharex='col', sharey='row',
|
|
||||||
gridspec_kw={'hspace': 0, 'wspace': 0},
|
|
||||||
# sharey=True,
|
|
||||||
# sharex=True,
|
|
||||||
)
|
|
||||||
for i, sf in enumerate(sf_list):
|
|
||||||
col = i % cols
|
|
||||||
row = (i - col)/cols
|
|
||||||
sf.plot(subplot=True,
|
sf.plot(subplot=True,
|
||||||
ax=axes_matrix[row][col],
|
|
||||||
title=sf.plot_title)
|
|
||||||
|
|
||||||
fig.suptitle(title)
|
|
||||||
plt.tight_layout()
|
|
||||||
|
|
||||||
cls.show_and_save(save_path)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def plot_sum_of_two(cls, sf1, sf2, save_path=None, title=''):
|
|
||||||
|
|
||||||
sf = sf1 + sf2
|
|
||||||
fig, axes_matrix = plt.subplots(2, 2, sharey=True, figsize=(10,5))
|
|
||||||
|
|
||||||
sf1.plot(subplot=True,
|
|
||||||
ax=axes_matrix[0][1])
|
ax=axes_matrix[0][1])
|
||||||
|
|
||||||
|
sf1.plot(subplot=True,
|
||||||
|
ax=axes_matrix[1][0],
|
||||||
|
color='red',
|
||||||
|
linestyle='dotted')
|
||||||
|
|
||||||
sf2.plot(subplot=True,
|
sf2.plot(subplot=True,
|
||||||
|
ax=axes_matrix[0][0],
|
||||||
|
color='black')
|
||||||
|
|
||||||
|
sf3.plot(subplot=True,
|
||||||
|
ax=axes_matrix[1][1],
|
||||||
|
alpha=0.3)
|
||||||
|
|
||||||
|
fig.suptitle(title)
|
||||||
|
|
||||||
|
plt.tight_layout()
|
||||||
|
if save_path is None:
|
||||||
|
save_path = os.path.join(os.getcwd(),"tmp.png")
|
||||||
|
save_path = Path(save_path)
|
||||||
|
save_path = save_path.with_suffix('.png')
|
||||||
|
|
||||||
|
plt.savefig(save_path)
|
||||||
|
plt.close()
|
||||||
|
image = Image.open(save_path)
|
||||||
|
image.show()
|
||||||
|
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def plot_sum_with_other(self, other,
|
||||||
|
save_path=None, title=''):
|
||||||
|
tp = self
|
||||||
|
up = other
|
||||||
|
sf = tp + up
|
||||||
|
|
||||||
|
fig, axes_matrix = plt.subplots(2, 2, sharey=True,
|
||||||
|
figsize=(10,5))
|
||||||
|
|
||||||
|
tp.plot(subplot=True,
|
||||||
|
ax=axes_matrix[0][1])
|
||||||
|
|
||||||
|
up.plot(subplot=True,
|
||||||
ax=axes_matrix[1][0],
|
ax=axes_matrix[1][0],
|
||||||
color='red',
|
color='red',
|
||||||
linestyle='dotted')
|
linestyle='dotted')
|
||||||
@ -213,11 +180,11 @@ class SignaturePloter:
|
|||||||
ax=axes_matrix[0][0],
|
ax=axes_matrix[0][0],
|
||||||
color='black')
|
color='black')
|
||||||
|
|
||||||
sf1.plot(subplot=True,
|
tp.plot(subplot=True,
|
||||||
ax=axes_matrix[1][1],
|
ax=axes_matrix[1][1],
|
||||||
alpha=0.3)
|
alpha=0.3)
|
||||||
|
|
||||||
sf2.plot(subplot=True,
|
up.plot(subplot=True,
|
||||||
ax=axes_matrix[1][1],
|
ax=axes_matrix[1][1],
|
||||||
color='red', alpha=0.3,
|
color='red', alpha=0.3,
|
||||||
linestyle='dotted')
|
linestyle='dotted')
|
||||||
@ -228,78 +195,63 @@ class SignaturePloter:
|
|||||||
alpha=0.7,)
|
alpha=0.7,)
|
||||||
|
|
||||||
fig.suptitle(title)
|
fig.suptitle(title)
|
||||||
|
|
||||||
plt.tight_layout()
|
plt.tight_layout()
|
||||||
|
if save_path is None:
|
||||||
|
save_path = os.path.join(os.getcwd(),"tmp.png")
|
||||||
|
save_path = Path(save_path)
|
||||||
|
save_path = save_path.with_suffix('.png')
|
||||||
|
|
||||||
cls.show_and_save(save_path)
|
|
||||||
|
|
||||||
@classmethod
|
# print(save_as)
|
||||||
def plot(cls, sf, subplot=False, ax=None,
|
|
||||||
save_path=None,
|
plt.savefig(save_path)
|
||||||
title='',
|
plt.close()
|
||||||
|
image = Image.open(save_path)
|
||||||
|
image.show()
|
||||||
|
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def plot(self, subplot=False, ax=None, save_as='sf',
|
||||||
|
title="",
|
||||||
alpha=1,
|
alpha=1,
|
||||||
color='blue',
|
color='blue',
|
||||||
linestyle='solid',
|
linestyle='solid',
|
||||||
special_point=None,
|
|
||||||
special_label='',
|
|
||||||
extraticks=None,
|
|
||||||
ylabel=''):
|
ylabel=''):
|
||||||
|
|
||||||
if ax is None:
|
if ax is None:
|
||||||
fig, ax = plt.subplots(1, 1)
|
fig, ax = plt.subplots(1, 1)
|
||||||
|
|
||||||
keys = sorted(sf.jumps_counter.keys())
|
keys = sorted(self.jumps_counter.keys())
|
||||||
y = [(sf(k) + sf.jumps_counter[k]) for k in keys[:-1]]
|
y = [self(k) + self.jumps_counter[k] for k in keys]
|
||||||
xmax = keys[1:]
|
xmax = keys[1:]
|
||||||
xmin = keys[:-1]
|
xmin = keys[:-1]
|
||||||
|
|
||||||
ax.set(ylabel=ylabel)
|
ax.set(ylabel=ylabel)
|
||||||
ax.set(title=title)
|
ax.set(title=title)
|
||||||
ax.hlines(y, xmin, xmax, color=color, linestyle=linestyle, alpha=alpha)
|
ax.hlines(y, xmin, xmax, color=color, linestyle=linestyle, alpha=alpha)
|
||||||
if special_point is not None:
|
|
||||||
arg, val = special_point
|
|
||||||
extraticks = extraticks or []
|
|
||||||
plt.xticks(list(plt.xticks()[0]) + extraticks)
|
|
||||||
ext = sf.extremum()[1]
|
|
||||||
ytext = ext/2 + 1/2
|
|
||||||
xtext = arg + 1/5
|
|
||||||
|
|
||||||
ax.annotate(special_label, xy=(arg, val), xytext=(xtext, ytext),
|
|
||||||
arrowprops=dict(facecolor='black', shrink=0.05,
|
|
||||||
alpha=0.7, width=2),)
|
|
||||||
if subplot:
|
if subplot:
|
||||||
return ax
|
return ax
|
||||||
|
|
||||||
cls.show_and_save(save_path)
|
save_as += ".png"
|
||||||
|
plt.savefig(save_as)
|
||||||
@staticmethod
|
|
||||||
def show_and_save(save_path):
|
|
||||||
|
|
||||||
if save_path is not None:
|
|
||||||
save_path = Path(save_path)
|
|
||||||
save_path = save_path.with_suffix('.png')
|
|
||||||
plt.savefig(save_path)
|
|
||||||
|
|
||||||
if ipython_info == JUPYTER:
|
|
||||||
plt.show()
|
|
||||||
|
|
||||||
elif True: # save_path is None:
|
|
||||||
plt.savefig('tmp.png')
|
|
||||||
plt.close()
|
plt.close()
|
||||||
image = Image.open('tmp.png')
|
image = Image.open(save_as)
|
||||||
image.show()
|
image.show()
|
||||||
# msg = "For interactive shell set save_path."
|
|
||||||
# warnings.warn(msg)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def step_function_data(sf):
|
|
||||||
|
def step_function_data(self):
|
||||||
# Transform the signature jump data to a format understandable
|
# Transform the signature jump data to a format understandable
|
||||||
# by the plot function.
|
# by the plot function.
|
||||||
result = [(k, sf.sf(k) + sf.jumps_counter[k])
|
result = [(k, self.sf(k) + self.jumps_counter[k])
|
||||||
for k in sorted(sf.jumps_counter.keys())]
|
for k in sorted(self.jumps_counter.keys())]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@staticmethod
|
def tikz_plot(self, save_as):
|
||||||
def tikz_plot(sf, save_as):
|
|
||||||
plt_sin = plot(sin(x), (x, 0, 2*pi))
|
plt_sin = plot(sin(x), (x, 0, 2*pi))
|
||||||
# plt_sin.show()
|
# plt_sin.show()
|
||||||
plt_sin.save("MyPic.pdf")
|
plt_sin.save("MyPic.pdf")
|
||||||
@ -374,3 +326,34 @@ class SignaturePloter:
|
|||||||
\end{document}
|
\end{document}
|
||||||
"""
|
"""
|
||||||
f.write(tail)
|
f.write(tail)
|
||||||
|
|
||||||
|
def mod_one(n):
|
||||||
|
return n - floor(n)
|
||||||
|
|
||||||
|
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.jumps_counter.
|
||||||
|
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
|
||||||
|
signature functions as defined on the interval [0,1).
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
mod_one.__doc__ = \
|
||||||
|
"""
|
||||||
|
Argument:
|
||||||
|
a number
|
||||||
|
Return:
|
||||||
|
the fractional part of the argument
|
||||||
|
Examples:
|
||||||
|
sage: mod_one(9 + 3/4)
|
||||||
|
3/4
|
||||||
|
sage: mod_one(-9 + 3/4)
|
||||||
|
3/4
|
||||||
|
sage: mod_one(-3/4)
|
||||||
|
1/4
|
||||||
|
"""
|
Loading…
Reference in New Issue
Block a user