2013-03-25 21:39:15 +01:00
|
|
|
#include <knotkit.h>
|
2016-11-19 21:01:10 +01:00
|
|
|
#include <periodicity.h>
|
|
|
|
#include <fstream>
|
|
|
|
#include <vector>
|
|
|
|
#include <utility>
|
2017-01-13 11:51:49 +01:00
|
|
|
#include <cctype>
|
2013-03-25 21:39:15 +01:00
|
|
|
|
|
|
|
const char *program_name;
|
|
|
|
|
|
|
|
void
|
|
|
|
usage ()
|
|
|
|
{
|
2016-11-29 17:45:16 +01:00
|
|
|
std::cout << "usage: %s <invariant> [options...] <link>\n" << program_name << "\n"
|
|
|
|
<< " compute <invariant> for knot or link <link>\n"
|
|
|
|
<< "<invariant> can be one of:\n"
|
|
|
|
<< " kh: Khovanov homology\n"
|
|
|
|
<< " gss: Szabo's geometric spectral sequence\n"
|
|
|
|
<< " lsss: Batson-Seed link splitting spectral sequence\n"
|
|
|
|
<< " component weights are 0, 1, ..., m\n"
|
|
|
|
<< " sq2: Lipshitz-Sarkar Steenrod square on Z/2 Kh\n"
|
|
|
|
<< " output suitable for Sage\n"
|
|
|
|
<< " leess: spectral sequence coming from Bar-Natan analogue of Lee's\n"
|
|
|
|
<< " deformation of Khovanov's complex (whew!)\n"
|
|
|
|
<< " s: Rasmussen's s-invariant coming from lee\n"
|
|
|
|
<< " khp: computes Khovanov polynomial of a link\n"
|
|
|
|
<< " jones: computes Jones polynomial of a link\n"
|
|
|
|
<< " periodicity: uses periodicity criterion of Przytycki and\n"
|
|
|
|
<< " the criterion in terms of Khovanov polynomial\n"
|
|
|
|
<< "output:\n"
|
|
|
|
<< " kh, gss, lsss, leess: .tex file\n"
|
|
|
|
<< " sq2: text in Sage format\n"
|
|
|
|
<< " s, khp, jones, periodicity: text\n"
|
|
|
|
<< "options:\n"
|
|
|
|
<< " -r : compute reduced theory\n"
|
|
|
|
<< " -h : print this message\n"
|
|
|
|
<< " -o <file> : write output to <file>\n"
|
|
|
|
<< " (stdout is the default)\n"
|
|
|
|
<< " -f <field> : ground field (if applicable)\n"
|
|
|
|
<< " (Z2 is the default)\n"
|
|
|
|
<< " -v : verbose: report progress as the computation proceeds\n"
|
|
|
|
<< " -p : period when verifying periodicity, can be equal to\n"
|
|
|
|
<< " 5,7,11,13,17 or 19\n"
|
|
|
|
<< " -t : type of periodicity test:\n"
|
|
|
|
<< " - Przytycki - Przytycki's periodicity test\n"
|
|
|
|
<< " - Kh - periodicity criterion in terms of Khovanov homology\n"
|
|
|
|
<< " - all - uses both criteria and tests for all prime\n"
|
|
|
|
<< " periods between 5 and 19\n"
|
|
|
|
<< "<field> can be one of:\n"
|
|
|
|
<< " Z2, Z3, Q\n"
|
|
|
|
<< "<link> can be one of:\n"
|
|
|
|
<< " - the unknot, e.g. U or unknot\n"
|
|
|
|
<< " - a torus knot, e.g. T(2,3)\n"
|
|
|
|
<< " - a Rolfsen table knot, e.g. 10_124\n"
|
|
|
|
<< " - a Hoste-Thistlethwaite-Weeks knot, e.g. 11a12 or 12n214\n"
|
|
|
|
<< " - a Morwen Thistlethwaite link, e.g. L8n9 or L13n8862\n"
|
|
|
|
<< " - a planar diagram, e.g.\n"
|
|
|
|
<< " PD[X[1, 4, 2, 5], X[3, 6, 4, 1], X[5, 2, 6, 3]] or\n"
|
|
|
|
<< " PD[[1, 4, 2, 5], [3, 6, 4, 1], [5, 2, 6, 3]]\n"
|
|
|
|
<< " - a Dowker-Thistlethwaite code, e.g.\n"
|
|
|
|
<< " DTCode[6,8,2,4],\n"
|
|
|
|
<< " DT[dadbcda] or\n"
|
|
|
|
<< " DT[{6, -8}, {-10, 12, -14, 2, -4}]\n"
|
|
|
|
<< " - a braid, e.g. BR[2, {-1, -1, -1}]\n"
|
|
|
|
<< " - disjoint union (juxtaposition), e.g. T(2,3) U\n";
|
2013-03-25 21:39:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
FILE *outfp = stdout;
|
|
|
|
|
|
|
|
void tex_header ()
|
|
|
|
{
|
|
|
|
fprintf (outfp, "\\documentclass{article}\n\
|
|
|
|
\\usepackage{amsmath, tikz, hyperref}\n\
|
|
|
|
\\DeclareMathOperator{\\rank}{rank}\n\
|
|
|
|
\\setlength{\\parindent}{0pt}\n\
|
|
|
|
\n\
|
|
|
|
\\begin{document}\n\
|
|
|
|
\\pagestyle{empty}\n\
|
|
|
|
\\sloppy\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void tex_footer ()
|
|
|
|
{
|
|
|
|
fprintf (outfp, "\\end{document}\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *knot = 0;
|
|
|
|
const char *invariant = 0;
|
|
|
|
const char *field = "Z2";
|
2016-11-19 21:01:10 +01:00
|
|
|
std::string periodicity_test = "Przytycki";
|
|
|
|
int period = 5;
|
2013-03-25 21:39:15 +01:00
|
|
|
|
|
|
|
knot_diagram kd;
|
|
|
|
bool reduced = 0;
|
|
|
|
|
|
|
|
class hg_grading_mapper
|
|
|
|
{
|
|
|
|
unsigned m;
|
|
|
|
|
|
|
|
public:
|
|
|
|
hg_grading_mapper (unsigned m_) : m(m_) { }
|
|
|
|
|
|
|
|
grading operator () (grading hq) const
|
|
|
|
{
|
|
|
|
int t = hq.q - (int)m;
|
|
|
|
if (reduced)
|
|
|
|
t --;
|
|
|
|
|
|
|
|
assert (is_even (t));
|
|
|
|
return grading (hq.h, t / 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
grading map_delta (grading d_hq) const
|
|
|
|
{
|
|
|
|
assert (is_even (d_hq.q));
|
|
|
|
return grading (d_hq.h, d_hq.q / 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void x_label (FILE *fp, int h) const
|
|
|
|
{
|
|
|
|
fprintf (fp, "%d", h);
|
|
|
|
}
|
|
|
|
void y_label (FILE *fp, int g) const
|
|
|
|
{
|
|
|
|
unsigned q = 2*g + (int)m;
|
|
|
|
if (reduced)
|
|
|
|
q ++;
|
|
|
|
|
|
|
|
fprintf (fp, "%d", q);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class R> mod_map<R>
|
|
|
|
compute_link_splitting_d (knot_diagram &kd,
|
|
|
|
cube<R> &c,
|
|
|
|
basedvector<R, 1> comp_weight)
|
|
|
|
{
|
|
|
|
unsigned n = kd.num_components ();
|
|
|
|
|
|
|
|
unionfind<1> u (kd.num_edges ());
|
|
|
|
for (unsigned i = 1; i <= kd.n_crossings; i ++)
|
|
|
|
{
|
|
|
|
u.join (kd.ept_edge (kd.crossings[i][1]),
|
|
|
|
kd.ept_edge (kd.crossings[i][3]));
|
|
|
|
u.join (kd.ept_edge (kd.crossings[i][2]),
|
|
|
|
kd.ept_edge (kd.crossings[i][4]));
|
|
|
|
}
|
|
|
|
|
|
|
|
map<unsigned, unsigned> root_comp;
|
|
|
|
unsigned t = 0;
|
|
|
|
for (unsigned i = 1; i <= kd.num_edges (); i ++)
|
|
|
|
{
|
|
|
|
if (u.find (i) == i)
|
|
|
|
{
|
|
|
|
++ t;
|
|
|
|
root_comp.push (i, t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert (t == n);
|
|
|
|
|
|
|
|
assert (comp_weight.size () == n);
|
|
|
|
|
|
|
|
map<unsigned, R> crossing_over_sign;
|
|
|
|
|
|
|
|
// crossings
|
|
|
|
set<unsigned> pending;
|
|
|
|
set<unsigned> finished;
|
|
|
|
|
|
|
|
crossing_over_sign.push (1, R (1));
|
|
|
|
pending.push (1);
|
|
|
|
|
|
|
|
while (pending.card () > 0)
|
|
|
|
{
|
|
|
|
unsigned x = pending.pop ();
|
|
|
|
finished.push (x);
|
|
|
|
|
|
|
|
R s = crossing_over_sign(x);
|
|
|
|
|
|
|
|
for (unsigned j = 1; j <= 4; j ++)
|
|
|
|
{
|
|
|
|
unsigned p = kd.crossings[x][j];
|
|
|
|
R t = kd.is_over_ept (p) ? s : -s; // sign of (x, p)
|
|
|
|
|
|
|
|
unsigned q = kd.edge_other_ept (p);
|
|
|
|
unsigned x2 = kd.ept_crossing[q];
|
|
|
|
|
|
|
|
R u = kd.is_over_ept (q) ? -t : t;
|
|
|
|
|
|
|
|
if (crossing_over_sign % x2)
|
|
|
|
assert (crossing_over_sign(x2) == u);
|
|
|
|
else
|
|
|
|
crossing_over_sign.push (x2, u);
|
|
|
|
|
|
|
|
if (! (finished % x2))
|
|
|
|
pending += x2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert (finished.card () == kd.n_crossings);
|
|
|
|
|
|
|
|
mod_map<R> untwisted_d = c.compute_d (1, 0, 0, 0, 0);
|
|
|
|
assert (untwisted_d.compose (untwisted_d) == 0);
|
|
|
|
|
|
|
|
mod_map<R> d = untwisted_d;
|
|
|
|
for (unsigned x = 1; x <= kd.n_crossings; x ++)
|
|
|
|
{
|
|
|
|
unsigned p1 = kd.crossings[x][1],
|
|
|
|
p2 = kd.crossings[x][2];
|
|
|
|
assert (kd.is_over_ept (p2));
|
|
|
|
|
|
|
|
unsigned r1 = u.find (kd.ept_edge (p1)),
|
|
|
|
r2 = u.find (kd.ept_edge (p2));
|
|
|
|
|
|
|
|
unsigned c1 = root_comp(r1),
|
|
|
|
c2 = root_comp(r2);
|
|
|
|
|
|
|
|
if (c1 != c2)
|
|
|
|
{
|
|
|
|
R s = crossing_over_sign(x);
|
|
|
|
|
|
|
|
R w_under = comp_weight[c1];
|
|
|
|
R w_over = comp_weight[c2];
|
|
|
|
|
|
|
|
d = d + c.compute_dinv (x)*(s*(w_over - w_under));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert (d.compose (d) == 0);
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
compute_gss ()
|
|
|
|
{
|
|
|
|
cube<Z2> c (kd, reduced);
|
|
|
|
ptr<const module<Z2> > C = c.khC;
|
|
|
|
mod_map<Z2> d = c.compute_d (0, 0, 0, 0, 0);
|
|
|
|
|
|
|
|
unsigned m = kd.num_components ();
|
|
|
|
hg_grading_mapper mapper (m);
|
|
|
|
|
|
|
|
sseq_bounds b (C, mapper);
|
|
|
|
basedvector<sseq_page, 1> pages;
|
|
|
|
|
|
|
|
unsigned k = 1;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
chain_complex_simplifier<Z2> s (C, d,
|
|
|
|
maybe<int> (k), maybe<int> (2*k - 2));
|
|
|
|
C = s.new_C;
|
|
|
|
d = s.new_d;
|
|
|
|
k ++;
|
|
|
|
|
|
|
|
grading dk_gr (k, 2*k - 2);
|
|
|
|
pages.append (sseq_page (b, k, dk_gr, d.graded_piece (dk_gr), mapper));
|
|
|
|
if (d == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
sseq ss (b, pages);
|
|
|
|
|
|
|
|
tex_header ();
|
|
|
|
fprintf (outfp, "$E_k = %s^{Sz}_k(\\verb~%s~; \\verb~%s~)$:\\\\\n",
|
|
|
|
(reduced
|
|
|
|
? "\\widetilde{E}"
|
|
|
|
: "E"),
|
|
|
|
knot, field);
|
|
|
|
ss.texshow (outfp, mapper);
|
|
|
|
tex_footer ();
|
|
|
|
}
|
|
|
|
|
2016-11-19 21:01:10 +01:00
|
|
|
template<class R>
|
|
|
|
multivariate_laurentpoly<Z> compute_khp(const knot_diagram& k, bool reduced = false) {
|
|
|
|
cube<R> c (kd, reduced);
|
|
|
|
ptr<const module<R> > C = c.khC;
|
|
|
|
mod_map<R> d = c.compute_d (1, 0, 0, 0, 0);
|
|
|
|
|
|
|
|
unsigned m = kd.num_components ();
|
|
|
|
hg_grading_mapper mapper (m);
|
|
|
|
|
|
|
|
chain_complex_simplifier<R> s (C, d,
|
|
|
|
maybe<int> (1), maybe<int> (0));
|
2016-11-19 20:46:39 +01:00
|
|
|
C = s.new_C;
|
|
|
|
d = s.new_d;
|
2016-11-19 21:01:10 +01:00
|
|
|
return C->free_poincare_polynomial();
|
|
|
|
}
|
|
|
|
|
|
|
|
multivariate_laurentpoly<Z> compute_jones(const knot_diagram& k, bool reduced = false) {
|
2017-01-13 11:51:49 +01:00
|
|
|
return compute_khp<Z2>(k, reduced).evaluate(-1, 1);
|
2016-11-19 20:53:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template<class R>
|
2016-11-19 21:01:10 +01:00
|
|
|
int compute_s_inv(knot_diagram& kd) {
|
|
|
|
unsigned m = kd.num_components ();
|
|
|
|
if (m != 1) {
|
|
|
|
fprintf (stderr, "error: s-invariant only defined for knots\n");
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
cube<R> c (kd, 0);
|
2016-11-19 20:53:18 +01:00
|
|
|
ptr<const module<R> > C = c.khC;
|
2016-11-19 21:01:10 +01:00
|
|
|
|
|
|
|
mod_map<R> d = c.compute_d (1, 0, 0, 0, 0);
|
|
|
|
for (unsigned i = 1; i <= kd.n_crossings; i ++)
|
|
|
|
d = d + c.H_i (i);
|
|
|
|
assert (d.compose (d) == 0);
|
|
|
|
|
|
|
|
int k = 0;
|
|
|
|
for (;;) {
|
|
|
|
chain_complex_simplifier<R> s (C, d,
|
|
|
|
maybe<int> (1),
|
|
|
|
maybe<int> (2*k));
|
|
|
|
C = s.new_C;
|
|
|
|
d = s.new_d;
|
|
|
|
k ++;
|
|
|
|
|
|
|
|
if (d == 0)
|
|
|
|
break;
|
2016-11-19 20:53:18 +01:00
|
|
|
}
|
2016-11-19 21:01:10 +01:00
|
|
|
|
|
|
|
assert (C->dim () == 2);
|
|
|
|
grading gr1 = C->generator_grading (1),
|
|
|
|
gr2 = C->generator_grading (2);
|
|
|
|
C->free_poincare_polynomial().display_self();
|
|
|
|
int qmin = gr1.q,
|
|
|
|
qmax = gr2.q;
|
|
|
|
if (qmax < qmin)
|
|
|
|
std::swap (qmin, qmax);
|
|
|
|
|
|
|
|
assert (qmax == qmin + 2);
|
|
|
|
return qmin + 1;
|
2016-11-19 20:46:39 +01:00
|
|
|
}
|
|
|
|
|
2016-11-19 21:01:10 +01:00
|
|
|
void check_periodicity(std::string out_file) {
|
2016-11-28 09:26:41 +01:00
|
|
|
if(periodicity_test == "all") {
|
2017-01-13 11:51:49 +01:00
|
|
|
Kh_periodicity_checker Kh_pc(kd, std::string(knot));
|
2016-11-28 09:26:41 +01:00
|
|
|
for(auto& p : primes_list) {
|
2017-01-13 11:51:49 +01:00
|
|
|
std::cout << "Kh criterion: "
|
|
|
|
<< Kh_pc(p) << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(periodicity_test == "all_seq") {
|
|
|
|
std::string k(knot);
|
|
|
|
// first check whether the number of crossings is bigger or lower than 10
|
|
|
|
if(isdigit(k[1])) {
|
|
|
|
// at least 10 crossings
|
|
|
|
if(k[1] == '0') {
|
|
|
|
// ten crossings
|
|
|
|
int num_cr = 10;
|
|
|
|
int knot_index = stoi(k.substr(3));
|
2017-01-26 11:33:27 +01:00
|
|
|
for(unsigned i = knot_index; i < rolfsen_crossing_knots(num_cr); i++) {
|
2017-01-13 11:51:49 +01:00
|
|
|
std::string knot_name = std::to_string(num_cr) + "_" + std::to_string(i);
|
|
|
|
knot_diagram kd_temp = parse_knot(knot_name.c_str());
|
|
|
|
kd.marked_edge = 1;
|
|
|
|
Kh_periodicity_checker Kh_pc(kd_temp, knot_name);
|
|
|
|
for(auto& p : primes_list) {
|
|
|
|
std::cout << "Kh criterion: "
|
|
|
|
<< Kh_pc(p) << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int num_cr = stoi(k.substr(0,2));
|
|
|
|
int knot_index = stoi(k.substr(3));
|
|
|
|
char alt = k[2];
|
|
|
|
bool alternating = (alt == 'a' ? true : false);
|
2017-01-26 11:33:27 +01:00
|
|
|
for(unsigned i = knot_index; i <= htw_knots(num_cr, alternating); i++) {
|
2017-01-13 11:51:49 +01:00
|
|
|
std::string knot_name = std::to_string(num_cr) + alt + std::to_string(i);
|
|
|
|
knot_diagram kd_temp = parse_knot(knot_name.c_str());
|
|
|
|
kd.marked_edge = 1;
|
|
|
|
Kh_periodicity_checker Kh_pc(kd_temp, knot_name);
|
|
|
|
for(auto& p : primes_list) {
|
|
|
|
std::cout << "Kh criterion: "
|
|
|
|
<< Kh_pc(p) << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// at most nine crossings
|
|
|
|
int num_cr = stoi(k.substr(0, 1));
|
|
|
|
int knot_index = stoi(k.substr(2));
|
2017-01-26 11:33:27 +01:00
|
|
|
for(unsigned i = knot_index; i <= rolfsen_crossing_knots(num_cr); i++) {
|
2017-01-13 11:51:49 +01:00
|
|
|
std::string knot_name = std::to_string(num_cr) + "_" + std::to_string(i);
|
|
|
|
knot_diagram kd_temp = parse_knot(knot_name.c_str());
|
|
|
|
kd.marked_edge = 1;
|
|
|
|
Kh_periodicity_checker Kh_pc(kd_temp, knot_name);
|
|
|
|
for(auto& p : primes_list) {
|
|
|
|
std::cout << "Kh criterion: "
|
|
|
|
<< Kh_pc(p) << std::endl;
|
|
|
|
}
|
|
|
|
}
|
2016-11-28 09:26:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2016-11-19 21:01:10 +01:00
|
|
|
if(period == 2 || period == 3) {
|
|
|
|
std::cout << "Sorry, the criteria don't work for period "
|
|
|
|
<< period << "...\n";
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
auto result = std::find(primes_list.begin(), primes_list.end(), period);
|
|
|
|
if(result == primes_list.end()) {
|
2016-11-29 17:45:16 +01:00
|
|
|
std::cout << "For now you can only check periodicity for primes up to 19..." << "\n";
|
2016-11-19 21:01:10 +01:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2016-11-28 09:26:41 +01:00
|
|
|
std::ofstream out(out_file, std::ios_base::app);
|
2016-11-19 21:01:10 +01:00
|
|
|
|
2016-11-28 09:26:41 +01:00
|
|
|
if(periodicity_test == "Przytycki") {
|
|
|
|
Przytycki_periodicity_checker P_pc(compute_jones(kd));
|
|
|
|
if(out_file.size() != 0)
|
|
|
|
out << P_pc(period) << std::endl;
|
|
|
|
else
|
|
|
|
std::cout << P_pc(period) << std::endl;
|
2016-11-19 21:01:10 +01:00
|
|
|
}
|
|
|
|
else if(periodicity_test == "Kh") {
|
2017-01-13 11:51:49 +01:00
|
|
|
Kh_periodicity_checker Kh_pc(kd, std::string(knot));
|
2016-11-19 21:01:10 +01:00
|
|
|
if(out_file.size() != 0)
|
2016-11-28 09:26:41 +01:00
|
|
|
out << Kh_pc(period) << std::endl;
|
2016-11-19 21:01:10 +01:00
|
|
|
else
|
2016-11-28 09:26:41 +01:00
|
|
|
std::cout << Kh_pc(period) << std::endl;
|
2016-11-19 21:01:10 +01:00
|
|
|
}
|
|
|
|
else {
|
2016-11-28 09:26:41 +01:00
|
|
|
std::cout << "Sorry, I don't recognize this option..." << "\n";
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2016-11-19 21:01:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-25 21:39:15 +01:00
|
|
|
template<class R> void
|
|
|
|
compute_invariant ()
|
|
|
|
{
|
|
|
|
if (!strcmp (invariant, "kh"))
|
|
|
|
{
|
|
|
|
cube<R> c (kd, reduced);
|
|
|
|
ptr<const module<R> > C = c.khC;
|
|
|
|
mod_map<R> d = c.compute_d (1, 0, 0, 0, 0);
|
|
|
|
|
|
|
|
unsigned m = kd.num_components ();
|
|
|
|
hg_grading_mapper mapper (m);
|
|
|
|
|
|
|
|
chain_complex_simplifier<R> s (C, d,
|
|
|
|
maybe<int> (1), maybe<int> (0));
|
|
|
|
C = s.new_C;
|
|
|
|
d = s.new_d;
|
|
|
|
|
|
|
|
sseq_bounds b (C, mapper);
|
|
|
|
sseq_page pg (b, 2, grading (0, 0), mod_map<R> (C), mapper);
|
|
|
|
|
|
|
|
tex_header ();
|
|
|
|
|
|
|
|
fprintf (outfp, "Kh = $%s(\\verb~%s~; \\verb~%s~)$:\\\\\n",
|
|
|
|
(reduced
|
|
|
|
? "\\widetilde{Kh}"
|
|
|
|
: "Kh"),
|
|
|
|
knot,
|
|
|
|
field);
|
|
|
|
fprintf (outfp, "$\\rank Kh = %d$\\\\\n", C->dim ());
|
|
|
|
|
|
|
|
char buf[1000];
|
|
|
|
sprintf (buf, "$Kh$");
|
|
|
|
pg.texshow (outfp, b, buf, mapper);
|
|
|
|
|
|
|
|
tex_footer ();
|
|
|
|
}
|
|
|
|
else if (!strcmp (invariant, "lsss"))
|
|
|
|
{
|
|
|
|
cube<R> c (kd, reduced);
|
|
|
|
ptr<const module<R> > C = c.khC;
|
|
|
|
|
|
|
|
unsigned m = kd.num_components ();
|
|
|
|
basedvector<R, 1> comp_weight (m);
|
|
|
|
for (unsigned i = 1; i <= m; i ++)
|
|
|
|
comp_weight[i] = R ((int)(i - 1));
|
|
|
|
|
|
|
|
mod_map<R> d = compute_link_splitting_d (kd, c, comp_weight);
|
|
|
|
|
|
|
|
hg_grading_mapper mapper (m);
|
|
|
|
|
|
|
|
sseq_bounds b (C, mapper);
|
|
|
|
basedvector<sseq_page, 1> pages;
|
|
|
|
|
|
|
|
int k = 0;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
chain_complex_simplifier<R> s (C, d,
|
|
|
|
maybe<int> (1 - 2*k), maybe<int> (-2*k));
|
|
|
|
C = s.new_C;
|
|
|
|
d = s.new_d;
|
|
|
|
k ++;
|
|
|
|
|
|
|
|
grading dk_gr (1 - 2*k, -2*k);
|
|
|
|
pages.append (sseq_page (b, k, dk_gr, d.graded_piece (dk_gr), mapper));
|
|
|
|
if (d == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
sseq ss (b, pages);
|
|
|
|
|
|
|
|
tex_header ();
|
2013-03-26 17:44:40 +01:00
|
|
|
fprintf (outfp, "$E_k = %s^{BS}_k({}^{%d}\\verb~%s~; \\verb~%s~)$:\\\\\n",
|
2013-03-25 21:39:15 +01:00
|
|
|
(reduced
|
|
|
|
? "\\widetilde{E}"
|
|
|
|
: "E"),
|
2013-03-26 17:44:40 +01:00
|
|
|
m,
|
2013-03-25 21:39:15 +01:00
|
|
|
knot,
|
|
|
|
field);
|
|
|
|
ss.texshow (outfp, mapper);
|
|
|
|
tex_footer ();
|
|
|
|
}
|
|
|
|
else if (!strcmp (invariant, "leess"))
|
|
|
|
{
|
|
|
|
cube<R> c (kd, reduced);
|
|
|
|
ptr<const module<R> > C = c.khC;
|
|
|
|
|
|
|
|
mod_map<R> d = c.compute_d (1, 0, 0, 0, 0);
|
|
|
|
for (unsigned i = 1; i <= kd.n_crossings; i ++)
|
|
|
|
d = d + c.H_i (i);
|
|
|
|
assert (d.compose (d) == 0);
|
|
|
|
|
|
|
|
unsigned m = kd.num_components ();
|
|
|
|
hg_grading_mapper mapper (m);
|
|
|
|
|
|
|
|
sseq_bounds b (C, mapper);
|
|
|
|
basedvector<sseq_page, 1> pages;
|
|
|
|
|
|
|
|
int k = 0;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
chain_complex_simplifier<R> s (C, d,
|
|
|
|
maybe<int> (1), maybe<int> (2*k));
|
|
|
|
C = s.new_C;
|
|
|
|
d = s.new_d;
|
|
|
|
k ++;
|
|
|
|
|
|
|
|
grading dk_gr (1, 2*k);
|
|
|
|
pages.append (sseq_page (b, k, dk_gr, d.graded_piece (dk_gr), mapper));
|
|
|
|
if (d == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
sseq ss (b, pages);
|
|
|
|
|
|
|
|
tex_header ();
|
|
|
|
fprintf (outfp, "$E_k = %s^{BN}_k(\\verb~%s~; \\verb~%s~)$:\\\\\n",
|
|
|
|
(reduced
|
|
|
|
? "\\widetilde{E}"
|
|
|
|
: "E"),
|
|
|
|
knot, field);
|
|
|
|
ss.texshow (outfp, mapper);
|
|
|
|
tex_footer ();
|
|
|
|
}
|
|
|
|
else if (!strcmp (invariant, "s"))
|
2016-11-19 21:01:10 +01:00
|
|
|
{
|
|
|
|
int s = compute_s_inv<R>(kd);
|
|
|
|
fprintf (outfp, "s(%s; %s) = %d\n", knot, field, s);
|
|
|
|
}
|
2013-03-25 21:39:15 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf (stderr, "error: unknown invariant %s\n", invariant);
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sage_show (FILE *fp,
|
|
|
|
map<grading, basedvector<unsigned, 1> > hq_gens,
|
|
|
|
ptr<const module<Z2> > H)
|
|
|
|
{
|
|
|
|
fprintf (fp, "hom={");
|
|
|
|
bool first = 1;
|
|
|
|
for (map<grading, basedvector<unsigned, 1> >::const_iter i = hq_gens; i; i ++)
|
|
|
|
{
|
|
|
|
if (first)
|
|
|
|
first = 0;
|
|
|
|
else
|
|
|
|
fprintf (fp, ", ");
|
|
|
|
fprintf (fp, "(%d, %d): %d", i.key ().h, i.key ().q, i.val ().size ());
|
|
|
|
}
|
|
|
|
fprintf (fp, "}\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sage_show (FILE *fp,
|
|
|
|
map<grading, basedvector<unsigned, 1> > hq_gens,
|
|
|
|
std::string name,
|
|
|
|
grading delta,
|
|
|
|
mod_map<Z2> f)
|
|
|
|
{
|
|
|
|
fprintf (fp, "%s={", name.c_str ());
|
|
|
|
|
|
|
|
bool first = 1;
|
|
|
|
for (map<grading, basedvector<unsigned, 1> >::const_iter i = hq_gens; i; i ++)
|
|
|
|
{
|
|
|
|
grading from_hq = i.key ();
|
|
|
|
basedvector<unsigned, 1> from_gens = i.val ();
|
|
|
|
|
|
|
|
grading to_hq = from_hq + delta;
|
|
|
|
if (hq_gens % to_hq)
|
|
|
|
{
|
|
|
|
basedvector<unsigned, 1> to_gens = hq_gens(to_hq);
|
|
|
|
|
|
|
|
if (first)
|
|
|
|
first = 0;
|
|
|
|
else
|
|
|
|
fprintf (fp, ", ");
|
|
|
|
fprintf (fp, "(%d, %d): [", from_hq.h, from_hq.q);
|
|
|
|
bool first2 = 1;
|
|
|
|
for (unsigned j = 1; j <= from_gens.size (); j ++)
|
|
|
|
{
|
|
|
|
unsigned gj = from_gens[j];
|
|
|
|
|
|
|
|
if (first2)
|
|
|
|
first2 = 0;
|
|
|
|
else
|
|
|
|
fprintf (fp, ", ");
|
|
|
|
fprintf (fp, "(");
|
|
|
|
for (unsigned k = 1; k <= to_gens.size (); k ++)
|
|
|
|
{
|
|
|
|
unsigned gk = to_gens[k];
|
|
|
|
|
|
|
|
if (k > 1)
|
|
|
|
fprintf (fp, ", ");
|
|
|
|
if (f[gj](gk) == 1)
|
|
|
|
fprintf (fp, "1");
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert (f[gj](gk) == 0);
|
|
|
|
fprintf (fp, "0");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fprintf (fp, ")");
|
|
|
|
}
|
|
|
|
fprintf (fp, "]");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fprintf (fp, "}\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sage_show_khsq (FILE *fp,
|
|
|
|
ptr<const module<Z2> > H,
|
|
|
|
mod_map<Z2> sq1,
|
|
|
|
mod_map<Z2> sq2)
|
|
|
|
{
|
|
|
|
unsigned n = H->dim ();
|
|
|
|
|
|
|
|
map<grading, basedvector<unsigned, 1> > hq_gens;
|
|
|
|
for (unsigned i = 1; i <= H->dim (); i ++)
|
|
|
|
hq_gens[H->generator_grading (i)].append (i);
|
|
|
|
|
|
|
|
unsigned t = 0;
|
|
|
|
for (map<grading, basedvector<unsigned, 1> >::const_iter i = hq_gens; i; i ++)
|
|
|
|
t += i.val ().size ();
|
|
|
|
assert (t == n);
|
|
|
|
|
|
|
|
sage_show (fp, hq_gens, H);
|
|
|
|
sage_show (fp, hq_gens, "sq1", grading (1, 0), sq1);
|
|
|
|
sage_show (fp, hq_gens, "sq2", grading (2, 0), sq2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
compute_sq2 ()
|
|
|
|
{
|
|
|
|
cube<Z2> c (kd);
|
|
|
|
mod_map<Z2> d = c.compute_d (1, 0, 0, 0, 0);
|
|
|
|
|
|
|
|
chain_complex_simplifier<Z2> s (c.khC, d, maybe<int> (1), maybe<int> (0));
|
|
|
|
assert (s.new_d == 0);
|
|
|
|
|
|
|
|
steenrod_square sq (c, d, s);
|
|
|
|
mod_map<Z2> sq1 = sq.sq1 ();
|
|
|
|
mod_map<Z2> sq2 = sq.sq2 ();
|
|
|
|
|
|
|
|
ptr<const module<Z2> > H = sq1.domain ();
|
|
|
|
|
|
|
|
sage_show_khsq (outfp, H, sq1, sq2);
|
|
|
|
}
|
|
|
|
|
2014-04-07 05:09:45 +02:00
|
|
|
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
kh_rk (knot_diagram kd)
|
|
|
|
{
|
|
|
|
cube<Z2> c (kd);
|
|
|
|
mod_map<Z2> d = c.compute_d (1, 0, 0, 0, 0);
|
|
|
|
|
|
|
|
chain_complex_simplifier<Z2> s (c.khC, d, maybe<int> (1), maybe<int> (0));
|
|
|
|
assert (s.new_d == 0);
|
|
|
|
return s.new_C->free_rank();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
run_demo ()
|
|
|
|
{
|
|
|
|
printf ("Link \t\t L1 \t L2 \t L \n");
|
|
|
|
for (unsigned i = 10; i <= 11; i ++)
|
|
|
|
{
|
|
|
|
for (unsigned j = 90; j <= fmin(mt_links (i, 0), 230); j ++)
|
|
|
|
{
|
|
|
|
|
|
|
|
knot_diagram kd (mt_link (i, 0, j));
|
|
|
|
if (kd.num_components () != 2)
|
|
|
|
continue;
|
|
|
|
knot_diagram L1 (SUBLINK, smallbitset (2, 1), kd);
|
|
|
|
knot_diagram L2 (SUBLINK, smallbitset (2, 2), kd);
|
|
|
|
|
|
|
|
printf ("%s \t %d \t %d \t %d \n", kd.name.c_str(), kh_rk(L1), kh_rk(L2), kh_rk(kd));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-25 21:39:15 +01:00
|
|
|
int
|
|
|
|
main (int argc, char **argv)
|
|
|
|
{
|
|
|
|
program_name = argv[0];
|
|
|
|
|
|
|
|
const char *file = 0;
|
|
|
|
|
2016-11-19 21:01:10 +01:00
|
|
|
for (int i = 1; i < argc; i ++) {
|
|
|
|
if (argv[i][0] == '-') {
|
|
|
|
if (strcmp (argv[i], "-r") == 0)
|
|
|
|
reduced = 1;
|
|
|
|
else if (strcmp (argv[i], "-h") == 0) {
|
|
|
|
usage ();
|
|
|
|
exit (EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
else if (strcmp (argv[i], "-demo") == 0) {
|
|
|
|
run_demo();
|
|
|
|
exit (EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
else if (!strcmp (argv[i], "-v"))
|
|
|
|
verbose = 1;
|
|
|
|
else if (!strcmp (argv[i], "-f")) {
|
|
|
|
i ++;
|
|
|
|
if (i == argc) {
|
|
|
|
fprintf (stderr, "error: missing argument to option `-f'\n");
|
|
|
|
exit (EXIT_FAILURE);
|
2013-03-25 21:39:15 +01:00
|
|
|
}
|
2016-11-19 21:01:10 +01:00
|
|
|
field = argv[i];
|
|
|
|
}
|
|
|
|
else if (!strcmp (argv[i], "-o")) {
|
|
|
|
i ++;
|
|
|
|
if (i == argc) {
|
|
|
|
fprintf (stderr, "error: missing argument to option `-o'\n");
|
|
|
|
exit (EXIT_FAILURE);
|
2013-03-25 21:39:15 +01:00
|
|
|
}
|
2016-11-19 21:01:10 +01:00
|
|
|
file = argv[i];
|
|
|
|
}
|
|
|
|
else if(!strcmp (argv[i], "-p")) {
|
|
|
|
i++;
|
|
|
|
if(i == argc) {
|
2016-11-28 09:26:41 +01:00
|
|
|
fprintf (stderr, "error: missing argument to option `-p'\n");
|
2016-11-19 21:01:10 +01:00
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
period = std::stoi(argv[i]);
|
|
|
|
}
|
|
|
|
else if (!strcmp(argv[i], "-t")) {
|
|
|
|
i++;
|
|
|
|
if(i == argc) {
|
2016-11-28 09:26:41 +01:00
|
|
|
fprintf (stderr, "error: missing argument to option `-t'\n");
|
2016-11-19 21:01:10 +01:00
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
periodicity_test = argv[i];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fprintf (stderr, "error: unknown argument `%s'\n", argv[1]);
|
|
|
|
fprintf (stderr, " use -h for usage\n");
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
2013-03-25 21:39:15 +01:00
|
|
|
}
|
2016-11-19 21:01:10 +01:00
|
|
|
else {
|
|
|
|
if (knot) {
|
|
|
|
fprintf (stderr, "error: too many arguments\n");
|
|
|
|
fprintf (stderr, " use -h for usage\n");
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
else if (invariant)
|
|
|
|
knot = argv[i];
|
|
|
|
else {
|
|
|
|
assert (invariant == 0);
|
|
|
|
invariant = argv[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-25 21:39:15 +01:00
|
|
|
if (!knot)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "error: too few arguments, <invariant> or <knot> missing\n");
|
|
|
|
fprintf (stderr, " use -h for usage\n");
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2016-11-19 21:01:10 +01:00
|
|
|
if (file) {
|
|
|
|
outfp = fopen (file, "w");
|
|
|
|
if (!outfp) {
|
|
|
|
stderror ("fopen: %s", file);
|
|
|
|
exit (EXIT_FAILURE);
|
2013-03-25 21:39:15 +01:00
|
|
|
}
|
2016-11-19 21:01:10 +01:00
|
|
|
}
|
2013-03-25 21:39:15 +01:00
|
|
|
else
|
|
|
|
outfp = stdout;
|
|
|
|
|
|
|
|
kd = parse_knot (knot);
|
|
|
|
kd.marked_edge = 1;
|
2016-11-19 20:46:39 +01:00
|
|
|
|
|
|
|
if (!strcmp (invariant, "gauss"))
|
|
|
|
{
|
|
|
|
basedvector<basedvector<int, 1>, 1> gc = kd.as_gauss_code ();
|
|
|
|
for (unsigned i = 1; i <= gc.size (); i ++)
|
|
|
|
{
|
2014-04-07 05:09:45 +02:00
|
|
|
if (i > 1)
|
|
|
|
printf (":");
|
|
|
|
for (unsigned j = 1; j <= gc[i].size (); j ++)
|
|
|
|
{
|
|
|
|
if (j > 1)
|
|
|
|
printf (",");
|
|
|
|
printf ("%d", gc[i][j]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
newline ();
|
|
|
|
}
|
|
|
|
|
2013-03-25 21:39:15 +01:00
|
|
|
if (!strcmp (invariant, "sq2"))
|
|
|
|
{
|
|
|
|
if (strcmp (field, "Z2"))
|
|
|
|
{
|
|
|
|
fprintf (stderr, "warning: sq2 only defined over Z2, ignoring -f %s\n", field);
|
|
|
|
field = "Z2";
|
|
|
|
}
|
|
|
|
|
|
|
|
compute_sq2 ();
|
|
|
|
}
|
|
|
|
else if (!strcmp (invariant, "gss"))
|
|
|
|
{
|
|
|
|
if (strcmp (field, "Z2"))
|
|
|
|
{
|
|
|
|
fprintf (stderr, "warning: gss only defined over Z2, ignoring -f %s\n", field);
|
|
|
|
field = "Z2";
|
|
|
|
}
|
|
|
|
|
|
|
|
compute_gss ();
|
|
|
|
}
|
2016-11-19 20:46:39 +01:00
|
|
|
else if(!strcmp(invariant, "jones")) {
|
2016-11-19 21:01:10 +01:00
|
|
|
std::cout << "Jones polynomial of " << knot << " = " << compute_jones(kd, reduced) << "\n";
|
2016-11-19 20:46:39 +01:00
|
|
|
}
|
2016-11-19 21:01:10 +01:00
|
|
|
else if(!strcmp(invariant, "periodicity")) {
|
|
|
|
check_periodicity((file ? std::string(file) : std::string()));
|
2016-11-19 20:46:39 +01:00
|
|
|
}
|
|
|
|
else if(!strcmp(invariant, "khp")) {
|
2016-11-19 20:53:18 +01:00
|
|
|
multivariate_laurentpoly<Z> khp;
|
|
|
|
if(!strcmp(field, "Z2"))
|
|
|
|
khp = compute_khp<Z2>(kd, reduced);
|
|
|
|
else if(!strcmp(field, "Z3"))
|
2016-11-19 21:01:10 +01:00
|
|
|
khp = compute_khp<Zp<3>>(kd, reduced);
|
|
|
|
else if(!strcmp(field, "Z5"))
|
|
|
|
khp = compute_khp<Zp<5>>(kd, reduced);
|
|
|
|
else if (!strcmp(field, "Z7"))
|
|
|
|
khp = compute_khp<Zp<7>>(kd,reduced);
|
2016-11-19 20:53:18 +01:00
|
|
|
else if(!strcmp(field, "Q"))
|
|
|
|
khp = compute_khp<Q>(kd, reduced);
|
|
|
|
else
|
|
|
|
{
|
2016-11-19 21:01:10 +01:00
|
|
|
std::cerr << "Unknown field: " << field << std::endl;
|
2016-11-19 20:53:18 +01:00
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
2016-11-19 21:01:10 +01:00
|
|
|
std::cout << "Khovanov polynomial (coefficients in " << field
|
|
|
|
<< ") of " << knot << " = " << std::endl
|
|
|
|
<< khp << std::endl;
|
2016-11-19 20:46:39 +01:00
|
|
|
}
|
2013-03-25 21:39:15 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!strcmp (field, "Z2"))
|
|
|
|
compute_invariant<Z2> ();
|
|
|
|
else if (!strcmp (field, "Z3"))
|
|
|
|
compute_invariant<Zp<3> > ();
|
|
|
|
else if (!strcmp (field, "Q"))
|
|
|
|
compute_invariant<Q> ();
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf (stderr, "error: unknown field %s\n", field);
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (file)
|
|
|
|
fclose (outfp);
|
|
|
|
}
|