signature_function/my_signature.sage

309 lines
12 KiB
Python

#!/usr/bin/env python
import collections
import sys
def mod_one(n):
"""This function returns the fractional part of some number."""
if n >= 1:
return mod_one(n - 1)
if n < 0:
return mod_one(n + 1)
return n
class av_signature_function(object):
'''
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.data.
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=[]):
# We will store data of signature jumps here.
self.data = collections.defaultdict(int)
# values contain initial data of singature jumps
for jump_arg, jump in values:
assert 0 <= jump_arg < 1, \
"Signature function is defined on the interval [0, 1)."
self.data[jump_arg] = jump
def value(self, arg):
# Compute the value of the signature function at the point arg.
# This requires summing all signature jumps that occur before arg.
assert 0 <= arg < 1, \
"Signature function is defined on the interval [0, 1)."
val = 0
for jump_arg, jump in self.data.items():
if jump_arg < arg:
val += 2 * jump
elif jump_arg == arg:
val += jump
return val
def total_sign_jump(self):
# Total signature jump is the sum of all jumps.
a = sum([j[1] for j in self.to_list()])
b = sum(self.data.values())
# print b
assert a == b
return sum(self.data.values())
def total_absolute_sign_jump(self):
# Total signature jump is the sum of all jumps.
a = sum([abs(j[1]) for j in self.to_list()])
# b = sum(self.data.values())
# print b
# assert a == b
return a
def double_cover(self):
new_data = []
for jump_arg, jump in self.data.items():
new_data.append((mod_one(jump_arg/2), jump))
new_data.append((mod_one(1/2 + jump_arg/2), jump))
return av_signature_function(new_data)
def to_list(self):
# Return signature jumps formated as a list
return sorted(self.data.items(), key=lambda x: x[0])
def step_function_data(self):
# Transform the signature jump data to a format understandable
# by the plot function.
l = self.to_list()
vals = ([(d[0], sum(2 * j[1] for j in l[:l.index(d)+1])) for d in l] +
[(0, self.data[0]), (1, self.total_sign_jump())])
return vals
def plot(self):
# plot the signture function
plot_step_function(self.step_function_data())
def tikz_plot(self, file_name):
# Draw the graph of the signature and transform it into TiKz.
# header of the LaTeX file
output_file = open(file_name, "w")
output_file.write("\\documentclass[tikz]{standalone}\n")
output_file.write("\\usetikzlibrary{datavisualization,datavisualization.formats.functions}\n")
output_file.write("\\begin{document}\n")
output_file.write("\\begin{tikzpicture}\n")
data = sorted(self.step_function_data())
output_file.write(" \\datavisualization[scientific axes,visualize as smooth line,\n")
output_file.write(" x axis={ticks={none,major={at={")
output_file.write(", " + str(N(data[0][0], digits=4)) + " as \\(" + str(data[0][0]) + "\\)")
for jump_arg, jump in data[1:]:
output_file.write(", " + str(N(jump_arg, digits=4)) + " as \\(" + str(jump_arg) + "\\)")
output_file.write("}}}}\n")
output_file.write(" ]\n")
output_file.write("data [format=function]{\n")
output_file.write("var x : interval [0:1];\n")
output_file.write("func y = \\value x;\n")
output_file.write("};\n")
# close LaTeX enviroments
output_file.write("\\end{tikzpicture}\n")
output_file.write("\\end{document}\n")
output_file.close()
def __lshift__(self, shift):
# Shift of the signature functions correspond to the rotations.
return self.__rshift__(-shift)
def __rshift__(self, shift):
new_data = []
for jump_arg, jump in self.data.items():
new_data.append((mod_one(jump_arg + shift), jump))
return av_signature_function(new_data)
def __sub__(self, other):
# we cn perform arithmetic operations on signature functions.
return self + other.__neg__()
def __neg__(self):
for jump_arg in self.data.keys():
self.data[jump_arg] *= -1
return self
def __add__(self, other):
new_one = av_signature_function()
new_data = collections.defaultdict(int)
for jump_arg, jump in other.data.items():
new_data[jump_arg] = jump + self.data.get(jump_arg, 0)
try:
int(jump_arg)
except:
print jump_arg
for jump_arg, jump in self.data.items():
if jump_arg not in new_data.keys():
new_data[jump_arg] = self.data[jump_arg]
new_one.data = new_data
return new_one
def __str__(self):
return '\n'.join([str(jump_arg) + ": " + str(jump)
for jump_arg, jump in sorted(self.data.items())])
def __repr__(self):
return self.__str__()
# 9.8
# ksi = exp( (2 PI * i) / (2k + 1))
# blanchfield = lambda_even + lambda_odd
def get_twisted_signature_function(k_n, theta):
results = []
k = abs(k_n)
ksi = 1/(2 * k + 1)
# lambda_odd (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)))
# lambda_even
# print "normal"
for e in range(1, theta):
if (theta + e) % 2 == 0:
# print e * ksi, ": 1"
# print 1 - e * ksi, ": -1 "
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:
continue
# print e * ksi, ": -1"
# print 1 - e * ksi, ": 1 "
results.append((e * ksi, -1 * sgn(k_n)))
results.append((1 - e * ksi, 1 * sgn(k_n)))
return av_signature_function(results)
def get_blanchfield(t, k):
p = 2
q = 2 * k + 1
sigma_set = get_sigma_set(p, q)
sigma = len(sigma_set) - 2 * len([z for z in sigma_set if t < z < 1 + t])
return sigma
def get_sigma_set(p, q):
sigma_set = set()
for i in range(1, p):
for j in range(1, q):
sigma_set.add(j/q + i/p)
return sigma_set
# Bl_theta(K'_(2, d) = Bl_theta(T_2, d) + Bl(K')(ksi_l^(-theta) * t) + Bl(K')(ksi_l^theta * t)
def get_cable_signature_as_theta_function(*arg):
if len(arg) < 2:
print "It is not a cable"
return None
def signture_function(theta):
if theta > abs(arg[-1]):
print "k for pattern is " + str(arg[-1])
print "theta shouldn't be larger than this"
return None
if theta == 0:
cable_signature = get_untwisted_signutere_function(arg[-1])
else:
cable_signature = get_twisted_signature_function(arg[-1], theta)
for i, k_i in enumerate(arg[:-1][::-1]):
k = abs(k_i)
ksi = 1/(2 * k + 1)
power = 2^i
a = get_untwisted_signutere_function(k_i)
shift = theta * ksi * power
b = a >> shift
c = a << shift
for _ in range(i):
b = b.double_cover()
c = c.double_cover()
b += c
cable_signature += b
return cable_signature
return signture_function
def get_untwisted_signutere_function(*arg):
signture_function = av_signature_function([(0, 0)])
for k_i in arg:
k = abs(k_i)
# Return the signature function of the T_{2,2k+1} torus knot.
l = ([((2 * a + 1)/(4 * k + 2), -1 * sgn(k_i)) for a in range(k)] +
[((2 * a + 1)/(4 * k + 2), 1 * sgn(k_i)) for a in range(k + 1, 2 * k + 1)])
signture_function += av_signature_function(l)
return signture_function
def get_function_of_theta_for_sum(*arg):
def signture_function_for_sum(*thetas):
if len(thetas) != len(arg) - 1:
print "For each cable one theta value should be given"
return None
signature_function = get_untwisted_signutere_function(*arg[0])
for i, knot in enumerate(arg[1:]):
signature_function += (get_cable_signature_as_theta_function(*knot))(thetas[i])
return signature_function
return signture_function_for_sum
def tmp(limit=None):
if limit is None:
limit = 10
for k_0 in range(1, limit):
for k_1 in range(1, limit):
for k_2 in range(1, limit):
for k_3 in range(1, limit):
F = get_function_of_theta_for_sum([k_3, -k_2], [-k_0, -k_1, -k_3], [k_0, k_1, k_2])
for theta_0 in range(k_3 + 1):
for theta_1 in range(k_2 + 1):
f = F(theta_0, theta_1)
if f.total_absolute_sign_jump() != 0 and theta_1 + theta_0 == 0:
print 4 * "\n"
print "OJOJOJOJJOOJJOJJ!!!!!!!!!!"
print k_0, k_1, k_2, k_3
print theta_0, theta_1
if f.total_absolute_sign_jump() == 0 and theta_1 + theta_0 != 0:
# print "HURA"
# print k_0, k_1, k_2, k_3
# print theta_0, theta_1
if k_2 != k_3 or theta_0 != theta_1:
print 4 * "\n"
print " SUPER!!!!!!!!!!"
print k_0, k_1, k_2, k_3
print theta_0, theta_1
for k_4 in range(1, limit):
F = get_function_of_theta_for_sum([], [k_0, k_1, k_2], [k_3, k_4], [-k_0, -k_3, -k_4], [-k_1, -k_2])
for theta_0 in range(k_2 + 1):
for theta_1 in range(k_4 + 1):
for theta_2 in range(k_4 + 1):
for theta_3 in range(k_2 + 1):
f = F(theta_0, theta_1, theta_2, theta_3)
if f.total_absolute_sign_jump() != 0 and theta_1 + theta_0 + theta_3 + theta_2 == 0:
print 4 * "\n"
print "2 OJOJOJOJJOOJJOJJ!!!!!!!!!!"
print k_0, k_1, k_2, k_3, k_4
print theta_0, theta_1, theta_2, theta_3
if f.total_absolute_sign_jump() == 0 and theta_1 + theta_0 + theta_3 + theta_2 != 0:
# print "HURA"
# print k_0, k_1, k_2, k_3
# print theta_0, theta_1
if k_2 != k_3 or theta_0 != theta_1:
print 4 * "\n"
print "2 SUPER!!!!!!!!!!"
print k_0, k_1, k_2, k_3, k_4
print theta_0, theta_1, theta_2, theta_3