From 297e02dc05d79c4546d04aeb720680a9c231284e Mon Sep 17 00:00:00 2001 From: Wojciech Politarczyk Date: Sat, 19 Nov 2016 21:01:10 +0100 Subject: [PATCH] Periodicity congruences --- .gitignore | 1 + Makefile | 4 +- algebra/Q.h | 48 ++----- algebra/Z.h | 23 +++- algebra/Z2.h | 4 +- algebra/Zp.h | 4 +- algebra/algebra.h | 4 + algebra/fraction_field.h | 4 + algebra/grading.h | 14 ++- algebra/linear_combination.h | 5 +- algebra/module.h | 23 +++- algebra/multivariate_laurentpoly.h | 145 +++++++++++----------- algebra/multivariate_polynomial.h | 5 +- algebra/polynomial.h | 5 +- kk.cpp | 193 ++++++++++++++++++++--------- periodicity.cpp | 169 +++++++++++++++++++++++++ periodicity.h | 135 ++++++++++++++++++++ 17 files changed, 596 insertions(+), 190 deletions(-) create mode 100644 periodicity.cpp create mode 100644 periodicity.h diff --git a/.gitignore b/.gitignore index 093d3f1..62f5ee3 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ GTAGS /parallel.cmd.[eo]* /save */save +/org diff --git a/Makefile b/Makefile index 18109a1..7d0b603 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ CXX = g++ -std=c++11 INCLUDES = -I. -I/opt/local/include # OPTFLAGS = -g -OPTFLAGS = -O2 -g +OPTFLAGS = -O2 -g -pg # OPTFLAGS = -O2 -g -DNDEBUG LDFLAGS = -L/opt/local/lib @@ -55,7 +55,7 @@ all: kk $(CXX) -c $(CXXFLAGS) $< -o $@ kk: kk.o $(COMMON_OBJS) - $(CXX) $(LDFLAGS) -o kk $^ $(LIBS) + $(CXX) $(LDFLAGS) -pg -o kk $^ $(LIBS) main: main.o $(COMMON_OBJS) $(CXX) $(LDFLAGS) -o main $^ $(LIBS) diff --git a/algebra/Q.h b/algebra/Q.h index 24c8509..b8f2510 100644 --- a/algebra/Q.h +++ b/algebra/Q.h @@ -13,47 +13,8 @@ class Q using linear_combination_const_iter = ::linear_combination_const_iter; private: - // enum steal { STEAL }; - // enum copy { COPY }; - // class Q_impl : public refcounted - // { - // public: - // mpq_t x; - - // public: - // Q_impl () { mpq_init (x); } - // Q_impl (int init) - // { - // mpq_init (x); - // mpq_set_si (x, init, 1); - // } - - // Q_impl (copy, mpq_srcptr init) - // { - // mpq_init (x); - // mpq_set (x, init); - // } - - // Q_impl (steal, mpq_srcptr init) { x[0] = *init; } - // Q_impl (reader &r) - // { - // mpq_init (x); - // r.read_mpz (mpq_numref (x)); - // r.read_mpz (mpq_denref (x)); - // } - - // ~Q_impl () { mpq_clear (x); } - - // void write_self (writer &w) const - // { - // w.write_mpz (mpq_numref (x)); - // w.write_mpz (mpq_denref (x)); - // } - // }; - - // ptr impl; std::shared_ptr impl; - void write_state() const { + void write_state() const { std::cout << "I store the following value " << *this << "\n"; std::cout << "Number of objects pointing to the same value " << impl.use_count() << "\n"; /* std::cout << "I point to " << impl.get() << "\n"; */ @@ -246,6 +207,11 @@ class Q int get_count() const { return impl.use_count(); } + Z get_num() const { + return Z(impl.get()->get_num()); + } + Z get_den() const { + return Z(impl.get()->get_den()); + } }; - #endif // _KNOTKIT_ALGEBRA_Q_H diff --git a/algebra/Z.h b/algebra/Z.h index b15856a..db61310 100644 --- a/algebra/Z.h +++ b/algebra/Z.h @@ -145,6 +145,24 @@ class Z } } + Z operator % (const Z& z) const { + if(Z(0) < z) { + // return Z(*impl.get() % *z.impl.get()); + mpz_class r; + mpz_fdiv_r(r.get_mpz_t(), impl.get()->get_mpz_t(), z.impl.get()->get_mpz_t()); + return Z(r); + } + else + return *this; + } + + Z operator % (unsigned p) const { + if(p != 0) + return operator % (Z(p)); + else + return *this; + } + Z recip () const { assert(is_unit()); return *this; @@ -234,6 +252,9 @@ class Z int get_count() const { return impl.use_count(); } -}; + unsigned get_ui() const { + return impl.get()->get_ui(); + } +}; #endif // _KNOTKIT_ALGEBRA_Z_H diff --git a/algebra/Z2.h b/algebra/Z2.h index 8cb5df5..c5c2ba6 100644 --- a/algebra/Z2.h +++ b/algebra/Z2.h @@ -1,5 +1,6 @@ #ifndef KNOTKIT_ALGEBRA_Z2_H #define KNOTKIT_ALGEBRA_Z2_H +#include #include #include #include @@ -8,7 +9,6 @@ class Z2 { public: using linear_combination = ::linear_combination; - // typedef linear_combination_iter linear_combination_iter; using linear_combination_const_iter = ::linear_combination_const_iter; private: @@ -24,6 +24,7 @@ class Z2 x.v = 0; } Z2 (reader &r) { v = r.read_bool (); } + Z2 (const Z& z) : v((z % 2).get_ui()) {} ~Z2 () { } Z2& operator = (const Z2& x) { v = x.v; return *this; } @@ -88,5 +89,4 @@ class Z2 void show_self () const { std::cout << *this; } void display_self () const { std::cout << *this << "\n"; } }; - #endif //KNOTKIT_ALGEBRA_Z2_H diff --git a/algebra/Zp.h b/algebra/Zp.h index 80414a0..3de8b6d 100644 --- a/algebra/Zp.h +++ b/algebra/Zp.h @@ -1,6 +1,6 @@ #ifndef KNOTKIT_ALGEBRA_ZP_H #define KNOTKIT_ALGEBRA_ZP_H - +#include #include #include #include @@ -32,6 +32,7 @@ class Zp Zp (Zp&& x) : v(std::move(x.v)) { x.v = 0; } + Zp (const Z& z) : v((z % p).get_ui()) {} ~Zp () { } Zp& operator = (const Zp& x) { v = x.v; return *this; } @@ -123,5 +124,4 @@ class Zp void show_self () const { std::cout << v << "(" << p << ")"; } void display_self () const { std::cout << *this << "\n"; } }; - #endif //KNOTKIT_ALGEBRA_ZP_H diff --git a/algebra/algebra.h b/algebra/algebra.h index b23bd79..325e0ba 100644 --- a/algebra/algebra.h +++ b/algebra/algebra.h @@ -1,3 +1,5 @@ +#ifndef _KNOTKIT_ALGEBRA_H +#define _KNOTKIT_ALGEBRA_H #include #ifdef DEBUG_ALGEBRA @@ -73,3 +75,5 @@ enum variable { VARIABLE }; #include #include + +#endif // _KNOTKIT_ALGEBRA_H diff --git a/algebra/fraction_field.h b/algebra/fraction_field.h index 3f648b6..ea3a6d2 100644 --- a/algebra/fraction_field.h +++ b/algebra/fraction_field.h @@ -1,3 +1,5 @@ +#ifndef _KNOTKIT_ALGEBRA_FRACTION_FIELD_H +#define _KNOTKIT_ALGEBRA_FRACTION_FIELD_H template class fraction_field { @@ -243,3 +245,5 @@ fraction_field::show_self () const printf (")"); } } + +#endif // _KNOTKIT_ALGEBRA_FRACTION_FIELD_H diff --git a/algebra/grading.h b/algebra/grading.h index cbd3972..4310657 100644 --- a/algebra/grading.h +++ b/algebra/grading.h @@ -1,4 +1,5 @@ - +#ifndef _KNOTKIT_ALGEBRA_GRADINGS_H +#define _KNOTKIT_ALGEBRA_GRADINGS_H class grading { public: @@ -8,6 +9,9 @@ class grading grading () : h(0), q(0) { } grading (int h_, int q_) : h(h_), q(q_) { } grading (const grading &gr) : h(gr.h), q(gr.q) { } + grading (grading&& gr) : h(std::move(gr.h)), q(std::move(gr.q)) { + gr.h = gr.q = 0; + } grading (reader &r) { h = r.read_int (); @@ -17,6 +21,12 @@ class grading ~grading () { } grading &operator = (const grading &gr) { h = gr.h; q = gr.q; return *this; } + grading& operator = (grading&& gr) { + h = std::move(gr.h); + q = std::move(gr.q); + gr.h = gr.q = 0; + return *this; + } grading operator + (const grading &gr) const { @@ -61,3 +71,5 @@ class grading void show_self () const; void display_self () const; }; + +#endif // _KNOTKIT_ALGEBRA_GRADINGS_H diff --git a/algebra/linear_combination.h b/algebra/linear_combination.h index 373a0b8..b9af52b 100644 --- a/algebra/linear_combination.h +++ b/algebra/linear_combination.h @@ -1,4 +1,5 @@ - +#ifndef _KNOTKIT_ALGEBRA_LINEAR_COMBINATIONS_H +#define _KNOTKIT_ALGEBRA_LINEAR_COMBINATIONS_H template class linear_combination_const_iter; template @@ -512,3 +513,5 @@ class linear_combination_const_iter unsigned key () const { return i.val (); } Z2 val () { return Z2 (1); } }; + +#endif // _KNOTKIT_ALGEBRA_LINEAR_COMBINATIONS_H diff --git a/algebra/module.h b/algebra/module.h index acd217b..e824ab9 100644 --- a/algebra/module.h +++ b/algebra/module.h @@ -1,4 +1,5 @@ - +#ifndef _KNOTKIT_ALGEBRA_MODULE_H +#define _KNOTKIT_ALGEBRA_MODULE_H template class mod_map; template class mod_span; @@ -85,8 +86,10 @@ class module : public refcounted ptr > quotient (ptr > m) const; ptr > submodule (const mod_span &span) const; - + multivariate_laurentpoly free_poincare_polynomial () const; + template + multivariate_laurentpoly> free_poincare_polynomial () const; multivariate_laurentpoly free_delta_poincare_polynomial () const; multivariate_laurentpoly free_ell_poincare_polynomial () const; @@ -1476,6 +1479,20 @@ module::free_poincare_polynomial () const return r; } +template template multivariate_laurentpoly> +module::free_poincare_polynomial() const { + multivariate_laurentpoly> r; + for (unsigned i = 1; i <= free_rank (); i ++) + { + grading hq = generator_grading (i); + multivariate_laurent_monomial m; + m.push_exponent (1, hq.h); + m.push_exponent (2, hq.q); + r.muladdeq (1, m); + } + return r; +} + template multivariate_laurentpoly module::free_delta_poincare_polynomial () const { @@ -2130,3 +2147,5 @@ reader::read_mod () return module::reader_id_module(id); } } + +#endif // _KNOTKIT_ALGEBRA_MODULE_H diff --git a/algebra/multivariate_laurentpoly.h b/algebra/multivariate_laurentpoly.h index a26122c..ae6e007 100644 --- a/algebra/multivariate_laurentpoly.h +++ b/algebra/multivariate_laurentpoly.h @@ -1,4 +1,7 @@ - +#ifndef _KNOTKIT_ALGEBRA_MULTIVARIATE_LAURENPOLY_H +#define _KNOTKIT_ALGEBRA_MULTIVARIATE_LAURENPOLY_H +#include +#include /* multivariate polynomial in a (vector) variable x with coefficients in T. */ @@ -133,17 +136,31 @@ class multivariate_laurent_monomial if (e != 0) m.push (j, e); } - + + std::string to_string() const { + std::ostringstream res; + for (map::const_iter i = m; i; i ++) { + assert (i.val () != 0); + if (i.val () == 1) { + res << "x" << std::to_string(i.key()); + } + else { + res << "x" + << std::to_string(i.key()) + << "^" + << std::to_string(i.val()); + } + } + return res.str(); + } + + friend std::ostream& operator << (std::ostream& os, const multivariate_laurent_monomial& m) { + return os << m.to_string(); + } + void show_self () const { - for (map::const_iter i = m; i; i ++) - { - assert (i.val () != 0); - if (i.val () == 1) - printf ("x%d", i.key ()); - else - printf ("x%d^%d", i.key (), i.val ()); - } + std::cout << *this; } void write_self (writer &w) const { write (w, m); } @@ -161,12 +178,11 @@ template class multivariate_laurentpoly { public: - typedef ::linear_combination > linear_combination; - typedef ::linear_combination_const_iter > - linear_combination_const_iter; + using linear_combination = ::linear_combination>; + using linear_combination_const_iter = ::linear_combination_const_iter >; public: - typedef multivariate_laurent_monomial monomial; + using monomial = multivariate_laurent_monomial; map coeffs; @@ -294,6 +310,7 @@ class multivariate_laurentpoly unsigned card () const { return coeffs.card (); } pair head () const { return coeffs.head (); } + pair tail() const { return coeffs.tail(); } multivariate_laurentpoly &operator += (const multivariate_laurentpoly &p); multivariate_laurentpoly &operator -= (const multivariate_laurentpoly &p); @@ -351,9 +368,14 @@ class multivariate_laurentpoly T::show_ring (); printf ("[x_1^+/-1, ..., x_n^+/-1]"); } - - void display_self () const { show_self (); newline (); } - void show_self () const; + + std::string to_string() const; + void display_self () const { + std::cout << *this << "\n"; + } + void show_self () const { + std::cout << *this; + } void write_self (writer &w) const { write (w, coeffs); } }; @@ -444,42 +466,41 @@ multivariate_laurentpoly::check () const } #endif -template void -multivariate_laurentpoly::show_self () const -{ +template +std::string multivariate_laurentpoly::to_string() const { + std::ostringstream res; unsigned first = 1; - for (typename map::const_iter i = coeffs; i; i ++) - { - monomial m = i.key (); - T c = i.val (); + for (typename map::const_iter i = coeffs; i; i ++) { + monomial m = i.key (); + T c = i.val (); + assert (c != 0); + + if (first) + first = 0; + else + res << " + "; - assert (c != 0); - - if (first) - first = 0; + if (m == 1) { + if (c == 1) + res << "1"; else - printf (" + "); - - if (m == 1) - { - if (c == 1) - printf ("1"); - else - show (c); - } - else - { - if (c != 1) - { - show (c); - printf ("*"); - } - - show (m); - } + res << c; } + else { + if (c != 1) { + res << c << "*"; + } + res << m; + } + } if (first) - printf ("0"); + res << "0"; + return res.str(); +} + +template +std::ostream& operator << (std::ostream& os, const multivariate_laurentpoly& pol) { + return os << pol.to_string(); } // functions below were added to verify several periodicity criteria @@ -506,30 +527,4 @@ multivariate_laurentpoly invert_variable(const multivariate_laurentpoly& p return result; } -template -bool check_przytycki_cong(const multivariate_laurentpoly& pol, const int prime, - const int exponent = 1, const unsigned index = 1) { - multivariate_laurentpoly result; - for(typename map::const_iter i = pol.coeffs; i; i++) { - multivariate_laurent_monomial mon = i.key(); - T c = i.val(); - multivariate_laurent_monomial mon2; - for(typename map::const_iter i = mon.m; i; i++) { - // still need to handle the coefficient - // i.e. we need to take c % p - if(i.key() == index) { - int v = i.val() % (2 * prime); - if(v < 0) v += (2 * prime); - mon2 *= multivariate_laurent_monomial(VARIABLE, i.key(), v); - c.display_self(); - printf("Old: key = %d, val = %d\n", i.key(), i.val()); - printf("New: key = %d, val = %d\n", i.key(), v); - } - else - mon2 *= multivariate_laurent_monomial(VARIABLE, i.key(), i.val()); - } - result += multivariate_laurentpoly(c, mon2); - } - result.display_self(); - return true; -} +#endif // _KNOTKIT_ALGEBRA_MULTIVARIATE_LAURENPOLY_H diff --git a/algebra/multivariate_polynomial.h b/algebra/multivariate_polynomial.h index c35bd32..a30bc0d 100644 --- a/algebra/multivariate_polynomial.h +++ b/algebra/multivariate_polynomial.h @@ -1,4 +1,5 @@ - +#ifndef _KNOTKIT_ALGEBRA_MULTIVARIATE_POLYNOMIAL_H +#define _KNOTKIT_ALGEBRA_MULTIVARIATE_POLYNOMIAL_H /* multivariate polynomial in a (vector) variable x with coefficients in T. */ @@ -499,3 +500,5 @@ multivariate_polynomial::show_self () const if (first) printf ("0"); } + +#endif // _KNOTKIT_ALGEBRA_MULTIVARIATE_POLYNOMIAL_H diff --git a/algebra/polynomial.h b/algebra/polynomial.h index 4d1771f..c4bae40 100644 --- a/algebra/polynomial.h +++ b/algebra/polynomial.h @@ -1,4 +1,5 @@ - +#ifndef _KNOTKIT_ALGEBRA_POLYNOMIAL_H +#define _KNOTKIT_ALGEBRA_POLYNOMIAL_H /* univariate polynomial in a single variable `x' with coefficients in T. */ @@ -512,3 +513,5 @@ class polynomial void display_self () const { show_self (); newline (); } void show_self () const; }; + +#endif // _KNOTKIT_ALGEBRA_POLYNOMIAL_H diff --git a/kk.cpp b/kk.cpp index 2ddb2a7..06d3668 100644 --- a/kk.cpp +++ b/kk.cpp @@ -1,4 +1,7 @@ + #include +#include +#include const char *program_name; @@ -72,7 +75,6 @@ const char *invariant = 0; const char *field = "Z2"; knot_diagram kd; - bool reduced = 0; class hg_grading_mapper @@ -250,43 +252,131 @@ compute_gss () tex_footer (); } -multivariate_laurentpoly compute_jones(const knot_diagram& k, bool reduced) { +multivariate_laurentpoly compute_jones(const knot_diagram& k, bool reduced = false) { + using polynomial = multivariate_laurentpoly; cube c(kd, reduced); ptr > C = c.khC; mod_map d = c.compute_d(1, 0, 0, 0, 0); chain_complex_simplifier s(C, d, maybe(1), maybe(0)); C = s.new_C; d = s.new_d; - multivariate_laurentpoly jones; + polynomial jones; for(uint i = 1; i <= c.n_generators; ++i) { grading gr = c.compute_generator_grading(i); if(gr.h % 2 == 0) { - jones += multivariate_laurentpoly(1, VARIABLE, 1, gr.q); + jones += polynomial(1, VARIABLE, 1, gr.q); } else { - jones += multivariate_laurentpoly(-1, VARIABLE, 1, gr.q); + jones += polynomial(-1, VARIABLE, 1, gr.q); } } return jones; } template -multivariate_laurentpoly compute_khp(const knot_diagram& k, bool reduced) { - cube c(kd,reduced); +multivariate_laurentpoly compute_khp(const knot_diagram& k, bool reduced = false) { + cube c (kd, reduced); ptr > C = c.khC; - mod_map d = c.compute_d(1, 0, 0, 0, 0); - chain_complex_simplifier s(C, d, maybe(1), maybe(0)); + mod_map d = c.compute_d (1, 0, 0, 0, 0); + + unsigned m = kd.num_components (); + hg_grading_mapper mapper (m); + + chain_complex_simplifier s (C, d, + maybe (1), maybe (0)); C = s.new_C; d = s.new_d; - multivariate_laurentpoly khp; - for(uint i = 1; i <= C->dim(); ++i) { - grading gr = C->generator_grading(i); - multivariate_laurentpoly p1 = multivariate_laurentpoly(1, VARIABLE, 0, gr.h); - multivariate_laurentpoly p2 = multivariate_laurentpoly(1, VARIABLE, 1, gr.q); - multivariate_laurentpoly p3 = p1 * p2; - khp += p3; + return C->free_poincare_polynomial(); +} + +template +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); } - return khp; + + cube c (kd, 0); + ptr > C = c.khC; + + mod_map 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 s (C, d, + maybe (1), + maybe (2*k)); + C = s.new_C; + d = s.new_d; + k ++; + + if (d == 0) + break; + } + + 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; +} + +template +void check_periodicity_criterion(knot_diagram kd, int prime = 5){ + using monomial = multivariate_laurent_monomial; + using polynomial = multivariate_laurentpoly; + unsigned m = kd.num_components(); + Test_type t = Test_type::all; + if(m != 1) { + std::cerr << "Error: for now this only works for knots\n"; + exit(EXIT_FAILURE); + } + polynomial khp, lee_p; + // Adding braces so that the cube can be destroyed + // when its not needed anymore + { + cube c(kd,0); + ptr> C = c.khC; + mod_map 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); + + // computing Khovanov homology + if(verbose) + std::cout << "Computing Khovanov polynomial..." << "\n"; + chain_complex_simplifier s(C, d, maybe(1), maybe(0)); + C = s.new_C; + d = s.new_d; + khp = C->free_poincare_polynomial(); + + // computing Lee homology + if(verbose) + std::cout << "Computing Lee polynomial..." << "\n"; + chain_complex_simplifier s1(C, d, maybe(1), maybe(2)); + C = s1.new_C; + d = s1.new_d; + assert(C->dim() == 2); + lee_p = C->free_poincare_polynomial(); + } + if(verbose) { + std::cout << "Khovanov polynomial = " + << khp << "\n" + << "Lee polynomial = " + << lee_p << "\n"; + } + periodicity_checker pc = periodicity_checker(khp, lee_p, prime, t); + pc(); } template void @@ -413,48 +503,10 @@ compute_invariant () tex_footer (); } else if (!strcmp (invariant, "s")) - { - unsigned m = kd.num_components (); - if (m != 1) - { - fprintf (stderr, "error: s-invariant only defined for knots\n"); - exit (EXIT_FAILURE); - } - - cube c (kd, 0); - ptr > C = c.khC; - - mod_map 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 s (C, d, - maybe (1), maybe (2*k)); - C = s.new_C; - d = s.new_d; - k ++; - - if (d == 0) - break; - } - - assert (C->dim () == 2); - grading gr1 = C->generator_grading (1), - gr2 = C->generator_grading (2); - - int qmin = gr1.q, - qmax = gr2.q; - if (qmax < qmin) - std::swap (qmin, qmax); - - assert (qmax == qmin + 2); - - fprintf (outfp, "s(%s; %s) = %d\n", knot, field, qmin + 1); - } + { + int s = compute_s_inv(kd); + fprintf (outfp, "s(%s; %s) = %d\n", knot, field, s); + } else { fprintf (stderr, "error: unknown invariant %s\n", invariant); @@ -753,14 +805,14 @@ main (int argc, char **argv) inv_jones_pol.display_self(); multivariate_laurentpoly diff = jones_pol - inv_jones_pol; diff.display_self(); - check_przytycki_cong(diff, 3); + check_przytycki_cong>(diff, 5); } else if(!strcmp(invariant, "khp")) { multivariate_laurentpoly khp; if(!strcmp(field, "Z2")) khp = compute_khp(kd, reduced); else if(!strcmp(field, "Z3")) - khp = compute_khp >(kd, reduced); + khp = compute_khp>(kd, reduced); else if(!strcmp(field, "Q")) khp = compute_khp(kd, reduced); else @@ -771,6 +823,25 @@ main (int argc, char **argv) printf("Khovanov polynomial of %s is equal to (coefficients %s):\n", knot, field); khp.display_self(); } + else if(!strcmp(invariant, "periodicity_congruence")) { + if(!strcmp(field, "Z2")) { + // first we check whether period is a prime + if(period == 2 || period == 3) { + std::cerr << "The criterion does not work for period = " << period << "\n"; + exit(EXIT_FAILURE); + } + auto result = find(primes.begin(), primes.end(), period); + if(result == primes.end()) { + std::cerr << "For now it is possible to check periodicity for primes up to 31" << "\n"; + exit(EXIT_FAILURE); + } + check_periodicity_criterion(kd,period); + } + else { + std::cerr << "error: for now this function is only defined for Z2 coefficients..." << "\n"; + exit(EXIT_FAILURE); + } + } else { if (!strcmp (field, "Z2")) diff --git a/periodicity.cpp b/periodicity.cpp new file mode 100644 index 0000000..d3fa7b7 --- /dev/null +++ b/periodicity.cpp @@ -0,0 +1,169 @@ +#include + +using polynomial = multivariate_laurentpoly; +using monomial = multivariate_laurent_monomial; + +template +bool congruence_checker::reduce(const polynomial& pol) const { + polynomial res; + for(typename map::const_iter i = p.coeffs; i; i++) { + int c = i.key().m[index] % (2 * prime); + if(c < 0) + c += (2 * prime); + monomial mon = monomial(VARIABLE, index, c); + res += polynomial(i.val(), mon); + } + if(verbose) + std::cout << "res = " << res << "\n"; + return res == 0; +} + +polynomial periodicity_checker::divide(const polynomial kh, + const polynomial lee) const { + polynomial diff = kh - lee; + polynomial quotient; + while(diff != 0) { + pair m = diff.head(); + if(m.first.m[1] == 1) { + pair m1 = diff.tail(); + while(m1.first.m.card() == 1 && m1.first.m[2]) { + quotient += polynomial(m1.second, m1.first); + polynomial p = polynomial(m1.second, m1.first) * mul; + diff -= p; + m1 = diff.tail(); + } + } + quotient += polynomial(m.second, m.first); + polynomial p = polynomial(m.second, m.first) * mul; + diff -= p; + } + if(verbose) { + std::cout << "Decomposition of the Khovanov polynomial = " + << lee << " + (" + << mul << ") * (" + << quotient << ")\n"; + } + return quotient; +} + +std::pair, polynomial> +periodicity_checker::divide_p(const polynomial& q) const { + polynomial quotient, remainder = 0; + for(map::iter i = q.coeffs; i; i++) { + std::tuple div = i.val().divide_with_remainder(prime - 1); + quotient += polynomial(std::get<0>(div), i.key()); + remainder += polynomial(std::get<1>(div), i.key()); + } + return std::make_pair(quotient, remainder); +} + +////// Functions that verify periodicity of knots and links + +void periodicity_congruence(const multivariate_laurentpoly& lee, + const multivariate_laurentpoly& remainder, + const multivariate_laurentpoly& quotient, + int prime) { + using polynomial = multivariate_laurentpoly; + using monomial = multivariate_laurent_monomial; + // prepare polynomials + polynomial m = (polynomial(1) + polynomial(1, VARIABLE, 1) * polynomial(1, VARIABLE, 2, 2)); + polynomial r = lee + m * (remainder - quotient); + // first check if quotient is zero + if(quotient == 0) { + // only one case to check + if(verbose) + std::cout << "All coefficients of the quotient " + "are smaller than " + << (prime -1) << "...\n"; + if(check_congruence((r - invert_variable(r,2)).evaluate(-1,1), prime)) + std::cout << knot << " may be " << prime << "-periodic...\n"; + else + std::cout << knot << " is not " << prime << "-periodic..." << "\n"; + } + // quotient not zero + else { + if(verbose) + std::cout << "Decomposition of the quotient:" << "\n" + << remainder << " + " + << (prime - 1) << " * (" + << quotient << ")\n"; + //generate and check all cases + std::vector> v; + Z number_of_cases = 1; + for(map::const_iter i = quotient.coeffs; i; i++) { + v.push_back(std::make_pair(i.key(), i.val())); + number_of_cases *= (i.val() + 1); + // std::cout << i.val() << "\n"; + } + if(verbose) { + std::cout << "There are " + << number_of_cases + << " cases to check...\n"; + } + Z counter = 0; + Z candidates = 0; + // std::cout << "v.size() = " << v.size() << "\n"; + for(Z level = 0; level < v.size(); level += 1) { + polynomial pol_temp = m * polynomial(prime, std::get<0>(v[level.get_ui()])); + // std::cout << "level = " << level << " / " + // << (v.size() - 1) << "\n"; + int i = 0; + if(level != Z(0)) + i++; + for( ; Z(i) < std::get<1>(v[level.get_ui()]) + 1; i++) { + // std::cout << "i = " << i << " / " + // << std::get<1>(v[level.get_ui()]) << "\n"; + polynomial p = r + polynomial(i) * pol_temp; + if(level == 0) { + if(check_congruence((p - invert_variable(p, 2)).evaluate(-1,1), prime)) { + candidates += 1; + if(verbose) + std::cout << "Found a candidate..." << "\n"; + } + counter += 1; + if(verbose) { + std::cout << counter + << " / " + << number_of_cases + << " cases checked...\n"; + } + } // level = 0 + else { + for(int level2 = 0; Z(level2) < level; level2++) { + // std::cout << "level2 = " << level2 << " / " + // << level << "\n"; + Z n_temp = std::get<1>(v[level2]); + polynomial mon_temp = m * polynomial(prime, std::get<0>(v[level2])); + for(int j = 0; Z(j) < n_temp + 1; j++) { + p += pol_temp; + // std::cout << "j = " << j << " / " + // << n_temp << "\n"; + if(check_congruence((p - invert_variable(p, 2)).evaluate(-1,1), prime)) { + candidates += 1; + if(verbose) { + std::cout << "Found a candidate..." << "\n"; + } + } + counter += 1; + if(verbose) + std::cout << counter + << " / " + << number_of_cases + << " cases checked...\n"; + } // loop over j + } // loop over level2 + } // level not zero + } // loop over i + } // loop over level + if(candidates == 0) { + std::cout << knot << " is not " + << prime << "-periodic...\n"; + } + else { + std::cout << knot << " may be " + << prime << "-periodic,\n" + << "found " << candidates + << " decompositions of khp."; + } + } +} diff --git a/periodicity.h b/periodicity.h new file mode 100644 index 0000000..454104c --- /dev/null +++ b/periodicity.h @@ -0,0 +1,135 @@ +#ifndef _KNOTKIT_PERIODICITY_H +#define _KNOTKIT_PERIODICITY_H + +#include +#include + +extern bool verbose; +extern const char* knot; + +int period = 5; +std::vector primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}; + +template +class congruence_checker { + using polynomial = multivariate_laurentpoly; + using monomial = multivariate_laurent_monomial; + + int prime; + unsigned index; + unsigend ev_index; + + polynomial prepare_polynomial(const polynomial& pol) const { + return (pol - invert_variable(pol, index)).evaluate(-1, ev_index); + } + + bool reduce (const polynomial& pol) const; + +public: + congruence_checker(int pprime = 5, + unsigned ind = 2, + unsigned ev_ind = 1) : + prime(pprime), index(ind), ev_index(ev_ind) {} + + congruence_checker(const congruence_checker& cc) =default; + congruence_checker(congruence_checker&& cc) =default; + + ~congruence_checker() {}; + + congruence_checker& operator= (const congruence_checker&& cc) =default; + congruence_checker& operator= (congruence_checker&& cc) =default; + + bool operator () (const polynomial& pol) const { + return reduce(prepare_polynomial(pol)); + } +}; + +enum class Test_type { + przytycki_criterion, + BKP_criterion, + all +}; + +class periodicity_checker { + using polynomial = multivariate_laurentpoly; + using monomial = multivariate_laurent_monomial; + + const unsigned ev_index = 1; + const unsigned index = 2; + + int prime; + + polynomial khp; + polynomial leep; + + polynomial quotient; + polynomial remainder; + + polynomial mul; + + Test_type type; + + void write_test_result(bool result) const { + std::cout << knot; + if(result) + std::cout << " may be "; + else + std::cout << " is not "; + std::cout << prime << "-periodic.\n"; + + } + + polynomial divide(const polynomial& kh, const polynomial& lee) const; + + std::pair, polynomial> + divide_p(const polynomial& q) const; + +public: + periodicity_checker(polynomial kh, + polynomial lee, + int p = 5, + Test_type t = Test_type::all) : + khp(kh), + leep(lee), + prime(p), + type(t) { + // check if prime is in primes + + // compute mul + mul = polynomial(Z(1)) + polynomial(1, VARIABLE, ev_index) * polynomial(1, VARIABLE, index, 2); + + // compute quotient and remainder + std::pair, polynomial> + p = divide_p(divide(khp, leep)); + quotient = std::get<0>(p); + remainder = std::get<1>(p); + } + + periodicity_checker(const periodicity_checker& pc) =default; + periodicity_checker(periodicity_checker&& pc) =default; + + periodicity_checker& operator= (const periodicity_checker& pc) =default; + periodicity_checker& operator= (periodicity_checker&& pc) =default; + + void operator () () const { + if(type == Test_type::przytycki_criterion || + type == Test_type::all) { + std::cout << "Przytycki's test: "; + write_test_result(przytycki_test()); + } + if(type == Test_type::BKP_criterion || + type == Test_type::all) { + std::cout << "BKP test: "; + write_test_result(BKP_test); + } + } + + bool przytycki_test() const { + return true; + } + + bool BKP_test() const { + return false; + } +} +#endif // _KNOTKIT_PERIODICITY_H