Periodicity congruences

This commit is contained in:
Wojciech Politarczyk 2016-11-19 21:01:10 +01:00
parent 66813d4a15
commit 297e02dc05
17 changed files with 596 additions and 190 deletions

1
.gitignore vendored
View File

@ -11,3 +11,4 @@ GTAGS
/parallel.cmd.[eo]*
/save
*/save
/org

View File

@ -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)

View File

@ -13,47 +13,8 @@ class Q
using linear_combination_const_iter = ::linear_combination_const_iter<Q>;
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<Q_impl> impl;
std::shared_ptr<mpq_class> 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

View File

@ -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

View File

@ -1,5 +1,6 @@
#ifndef KNOTKIT_ALGEBRA_Z2_H
#define KNOTKIT_ALGEBRA_Z2_H
#include <algebra/Z.h>
#include <iostream>
#include <tuple>
#include <cassert>
@ -8,7 +9,6 @@ class Z2
{
public:
using linear_combination = ::linear_combination<Z2>;
// typedef linear_combination_iter<Z2> linear_combination_iter;
using linear_combination_const_iter = ::linear_combination_const_iter<Z2>;
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

View File

@ -1,6 +1,6 @@
#ifndef KNOTKIT_ALGEBRA_ZP_H
#define KNOTKIT_ALGEBRA_ZP_H
#include <algebra/Z.h>
#include <iostream>
#include <tuple>
#include <cassert>
@ -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

View File

@ -1,3 +1,5 @@
#ifndef _KNOTKIT_ALGEBRA_H
#define _KNOTKIT_ALGEBRA_H
#include <lib/lib.h>
#ifdef DEBUG_ALGEBRA
@ -73,3 +75,5 @@ enum variable { VARIABLE };
#include <algebra/module.h>
#include <algebra/linear_combination.h>
#endif // _KNOTKIT_ALGEBRA_H

View File

@ -1,3 +1,5 @@
#ifndef _KNOTKIT_ALGEBRA_FRACTION_FIELD_H
#define _KNOTKIT_ALGEBRA_FRACTION_FIELD_H
template<class T> class fraction_field
{
@ -243,3 +245,5 @@ fraction_field<T>::show_self () const
printf (")");
}
}
#endif // _KNOTKIT_ALGEBRA_FRACTION_FIELD_H

View File

@ -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

View File

@ -1,4 +1,5 @@
#ifndef _KNOTKIT_ALGEBRA_LINEAR_COMBINATIONS_H
#define _KNOTKIT_ALGEBRA_LINEAR_COMBINATIONS_H
template<class R> class linear_combination_const_iter;
template<class R>
@ -512,3 +513,5 @@ class linear_combination_const_iter<Z2>
unsigned key () const { return i.val (); }
Z2 val () { return Z2 (1); }
};
#endif // _KNOTKIT_ALGEBRA_LINEAR_COMBINATIONS_H

View File

@ -1,4 +1,5 @@
#ifndef _KNOTKIT_ALGEBRA_MODULE_H
#define _KNOTKIT_ALGEBRA_MODULE_H
template<class R> class mod_map;
template<class R> class mod_span;
@ -85,8 +86,10 @@ class module : public refcounted
ptr<const quotient_module<R> > quotient (ptr<const free_submodule<R> > m) const;
ptr<const free_submodule<R> > submodule (const mod_span<R> &span) const;
multivariate_laurentpoly<Z> free_poincare_polynomial () const;
template<unsigned p>
multivariate_laurentpoly<Zp<p>> free_poincare_polynomial () const;
multivariate_laurentpoly<Z> free_delta_poincare_polynomial () const;
multivariate_laurentpoly<Z> free_ell_poincare_polynomial () const;
@ -1476,6 +1479,20 @@ module<R>::free_poincare_polynomial () const
return r;
}
template<class R> template <unsigned p> multivariate_laurentpoly<Zp<p>>
module<R>::free_poincare_polynomial() const {
multivariate_laurentpoly<Zp<p>> 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<class R> multivariate_laurentpoly<Z>
module<R>::free_delta_poincare_polynomial () const
{
@ -2130,3 +2147,5 @@ reader::read_mod ()
return module<R>::reader_id_module(id);
}
}
#endif // _KNOTKIT_ALGEBRA_MODULE_H

View File

@ -1,4 +1,7 @@
#ifndef _KNOTKIT_ALGEBRA_MULTIVARIATE_LAURENPOLY_H
#define _KNOTKIT_ALGEBRA_MULTIVARIATE_LAURENPOLY_H
#include <sstream>
#include <string>
/* 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<unsigned, int>::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<unsigned, int>::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 T>
class multivariate_laurentpoly
{
public:
typedef ::linear_combination<multivariate_laurentpoly<T> > linear_combination;
typedef ::linear_combination_const_iter<multivariate_laurentpoly<T> >
linear_combination_const_iter;
using linear_combination = ::linear_combination<multivariate_laurentpoly<T>>;
using linear_combination_const_iter = ::linear_combination_const_iter<multivariate_laurentpoly<T> >;
public:
typedef multivariate_laurent_monomial monomial;
using monomial = multivariate_laurent_monomial;
map<monomial, T> coeffs;
@ -294,6 +310,7 @@ class multivariate_laurentpoly
unsigned card () const { return coeffs.card (); }
pair<monomial, T> head () const { return coeffs.head (); }
pair<monomial, T> 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<T>::check () const
}
#endif
template<class T> void
multivariate_laurentpoly<T>::show_self () const
{
template<class T>
std::string multivariate_laurentpoly<T>::to_string() const {
std::ostringstream res;
unsigned first = 1;
for (typename map<monomial, T>::const_iter i = coeffs; i; i ++)
{
monomial m = i.key ();
T c = i.val ();
for (typename map<monomial, T>::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<class T>
std::ostream& operator << (std::ostream& os, const multivariate_laurentpoly<T>& pol) {
return os << pol.to_string();
}
// functions below were added to verify several periodicity criteria
@ -506,30 +527,4 @@ multivariate_laurentpoly<T> invert_variable(const multivariate_laurentpoly<T>& p
return result;
}
template<class T>
bool check_przytycki_cong(const multivariate_laurentpoly<T>& pol, const int prime,
const int exponent = 1, const unsigned index = 1) {
multivariate_laurentpoly<T> result;
for(typename map<multivariate_laurent_monomial, T>::const_iter i = pol.coeffs; i; i++) {
multivariate_laurent_monomial mon = i.key();
T c = i.val();
multivariate_laurent_monomial mon2;
for(typename map<unsigned, int>::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<T>(c, mon2);
}
result.display_self();
return true;
}
#endif // _KNOTKIT_ALGEBRA_MULTIVARIATE_LAURENPOLY_H

View File

@ -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<T, n>::show_self () const
if (first)
printf ("0");
}
#endif // _KNOTKIT_ALGEBRA_MULTIVARIATE_POLYNOMIAL_H

View File

@ -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<Z2>
void display_self () const { show_self (); newline (); }
void show_self () const;
};
#endif // _KNOTKIT_ALGEBRA_POLYNOMIAL_H

193
kk.cpp
View File

@ -1,4 +1,7 @@
#include <knotkit.h>
#include <vector>
#include <utility>
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<Z> compute_jones(const knot_diagram& k, bool reduced) {
multivariate_laurentpoly<Z> compute_jones(const knot_diagram& k, bool reduced = false) {
using polynomial = multivariate_laurentpoly<Z>;
cube<Z2> c(kd, reduced);
ptr<const module<Z2> > C = c.khC;
mod_map<Z2> d = c.compute_d(1, 0, 0, 0, 0);
chain_complex_simplifier<Z2> s(C, d, maybe<int>(1), maybe<int>(0));
C = s.new_C;
d = s.new_d;
multivariate_laurentpoly<Z> 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<Z>(1, VARIABLE, 1, gr.q);
jones += polynomial(1, VARIABLE, 1, gr.q);
}
else {
jones += multivariate_laurentpoly<Z>(-1, VARIABLE, 1, gr.q);
jones += polynomial(-1, VARIABLE, 1, gr.q);
}
}
return jones;
}
template<class R>
multivariate_laurentpoly<Z> compute_khp(const knot_diagram& k, bool reduced) {
cube<R> c(kd,reduced);
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);
chain_complex_simplifier<R> s(C, d, maybe<int>(1), maybe<int>(0));
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;
multivariate_laurentpoly<Z> khp;
for(uint i = 1; i <= C->dim(); ++i) {
grading gr = C->generator_grading(i);
multivariate_laurentpoly<Z> p1 = multivariate_laurentpoly<Z>(1, VARIABLE, 0, gr.h);
multivariate_laurentpoly<Z> p2 = multivariate_laurentpoly<Z>(1, VARIABLE, 1, gr.q);
multivariate_laurentpoly<Z> p3 = p1 * p2;
khp += p3;
return C->free_poincare_polynomial();
}
template<class R>
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<R> c (kd, 0);
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);
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;
}
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<class R>
void check_periodicity_criterion(knot_diagram kd, int prime = 5){
using monomial = multivariate_laurent_monomial;
using polynomial = multivariate_laurentpoly<Z>;
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<R> c(kd,0);
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);
// computing Khovanov homology
if(verbose)
std::cout << "Computing Khovanov polynomial..." << "\n";
chain_complex_simplifier<R> s(C, d, maybe<int>(1), maybe<int>(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<R> s1(C, d, maybe<int>(1), maybe<int>(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<class R> 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<R> c (kd, 0);
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);
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;
}
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<R>(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<Z> diff = jones_pol - inv_jones_pol;
diff.display_self();
check_przytycki_cong(diff, 3);
check_przytycki_cong<Z,Zp<5>>(diff, 5);
}
else if(!strcmp(invariant, "khp")) {
multivariate_laurentpoly<Z> khp;
if(!strcmp(field, "Z2"))
khp = compute_khp<Z2>(kd, reduced);
else if(!strcmp(field, "Z3"))
khp = compute_khp<Zp<3> >(kd, reduced);
khp = compute_khp<Zp<3>>(kd, reduced);
else if(!strcmp(field, "Q"))
khp = compute_khp<Q>(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<Z2>(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"))

169
periodicity.cpp Normal file
View File

@ -0,0 +1,169 @@
#include <periodicity.h>
using polynomial = multivariate_laurentpoly;
using monomial = multivariate_laurent_monomial;
template<class T>
bool congruence_checker::reduce(const polynomial<T>& pol) const {
polynomial res;
for(typename map<monomial, T>::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<Z> periodicity_checker::divide(const polynomial<Z> kh,
const polynomial<Z> lee) const {
polynomial <Z> diff = kh - lee;
polynomial <Z> quotient;
while(diff != 0) {
pair<monomial, Z> m = diff.head();
if(m.first.m[1] == 1) {
pair<monomial, Z> 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<Z>, polynomial<Z>>
periodicity_checker::divide_p(const polynomial& q) const {
polynomial quotient, remainder = 0;
for(map<monomial, Z>::iter i = q.coeffs; i; i++) {
std::tuple<Z,Z> 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<Z>& lee,
const multivariate_laurentpoly<Z>& remainder,
const multivariate_laurentpoly<Z>& quotient,
int prime) {
using polynomial = multivariate_laurentpoly<Z>;
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<std::pair<monomial,Z>> v;
Z number_of_cases = 1;
for(map<monomial,Z>::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.";
}
}
}

135
periodicity.h Normal file
View File

@ -0,0 +1,135 @@
#ifndef _KNOTKIT_PERIODICITY_H
#define _KNOTKIT_PERIODICITY_H
#include <algebra/algebra.h>
#include <vector>
extern bool verbose;
extern const char* knot;
int period = 5;
std::vector<int> primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31};
template<class T>
class congruence_checker {
using polynomial = multivariate_laurentpoly<T>;
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<Z> khp;
polynomial<Z> leep;
polynomial<Z> quotient;
polynomial<Z> remainder;
polynomial<Z> 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<Z> divide(const polynomial<Z>& kh, const polynomial<Z>& lee) const;
std::pair<polynomial<Z>, polynomial<Z>>
divide_p(const polynomial<Z>& q) const;
public:
periodicity_checker(polynomial<Z> kh,
polynomial<Z> 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<Z>, polynomial<Z>>
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