From f80ac2ce8e97faacff7c97d6af49a040701be82d Mon Sep 17 00:00:00 2001 From: Wojciech Politarczyk Date: Thu, 26 Jan 2017 11:33:27 +0100 Subject: [PATCH] Verification of periodicity criterion works for nonthin knots. --- kk.cpp | 6 +- periodicity.cpp | 354 ++++++++++++++++++++++++++++-------------------- periodicity.h | 65 ++++++--- 3 files changed, 253 insertions(+), 172 deletions(-) diff --git a/kk.cpp b/kk.cpp index 01242dd..fbf8f81 100644 --- a/kk.cpp +++ b/kk.cpp @@ -346,7 +346,7 @@ void check_periodicity(std::string out_file) { // ten crossings int num_cr = 10; int knot_index = stoi(k.substr(3)); - for(int i = knot_index; i < rolfsen_crossing_knots(num_cr); i++) { + for(unsigned i = knot_index; i < rolfsen_crossing_knots(num_cr); i++) { 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; @@ -362,7 +362,7 @@ void check_periodicity(std::string out_file) { int knot_index = stoi(k.substr(3)); char alt = k[2]; bool alternating = (alt == 'a' ? true : false); - for(int i = knot_index; i <= htw_knots(num_cr, alternating); i++) { + for(unsigned i = knot_index; i <= htw_knots(num_cr, alternating); i++) { 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; @@ -378,7 +378,7 @@ void check_periodicity(std::string out_file) { // at most nine crossings int num_cr = stoi(k.substr(0, 1)); int knot_index = stoi(k.substr(2)); - for(int i = knot_index; i <= rolfsen_crossing_knots(num_cr); i++) { + for(unsigned i = knot_index; i <= rolfsen_crossing_knots(num_cr); i++) { 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; diff --git a/periodicity.cpp b/periodicity.cpp index 468a523..40794ae 100644 --- a/periodicity.cpp +++ b/periodicity.cpp @@ -1,5 +1,10 @@ #include #include +#include + +using polynomial_tuple = std::vector, multivariate_laurentpoly, multivariate_laurentpoly>>; + +using bounds_vector = std::map, std::pair>; bool Przytycki_periodicity_checker::check(int period) const { switch(period) { @@ -38,8 +43,46 @@ std::string Przytycki_periodicity_checker::operator () (int period) const { return res.str(); } -void Kh_periodicity_checker::compute_knot_polynomials(knot_diagram& kd) { +bool Kh_bounds_iterator::advance() { + if(level == bv.end()) + return false; + for(auto bv_it = bv.begin(); bv_it != level; ++bv_it) { + if(current_state[bv_it->first] < (bv_it->second).second) { + current_state[bv_it->first] += period; + for(auto bv_it_2 = bv.begin(); bv_it_2 != bv_it; ++bv_it_2) { + current_state[bv_it_2->first] = bv_it_2->second.first; + } + return true; + } + } + if(current_state[level->first] < bv[level->first].second) { + current_state[level->first] += period; + for(auto bv_it = bv.begin(); bv_it != level; ++bv_it) { + current_state[bv_it->first] = bv_it->second.first; + } + return true; + } + ++level; + if(level == bv.end()) + return false; + current_state[level->first] += period; + for(auto bv_it = bv.begin(); bv_it != level; ++bv_it) { + current_state[bv_it->first] = bv_it->second.first; + } + + return true; +} +multivariate_laurentpoly Kh_bounds_iterator::get_polynomial() const { + polynomial p; + for(auto& cs : current_state) { + p += cs.second * cs.first; + } + return p; +} + +std::vector> +Kh_periodicity_checker::compute_knot_polynomials(knot_diagram& kd) { unsigned m = kd.num_components (); if (m != 1) { std::cerr << "warning: this implementation of the criterion works for knots only..."; @@ -56,187 +99,201 @@ void Kh_periodicity_checker::compute_knot_polynomials(knot_diagram& kd) { // computing Khovanov homology if(verbose) - std::cout << "Computing Khovanov homology" << std::endl; - { - chain_complex_simplifier s (C, d, maybe(1), maybe(0)); + std::cerr << "Computing Khovanov homology" << std::endl; + std::vector lee_ss_polynomials; + int k = 0; + for(;;) { + chain_complex_simplifier s(C, d, maybe(1), maybe(2*k)); C = s.new_C; d = s.new_d; - khp = C->free_poincare_polynomial(); - if(verbose) - std::cout << "KhP = " << khp << "\n"; + lee_ss_polynomials.push_back(C->free_poincare_polynomial()); + if(k != 0) + mul.push_back(polynomial(Z(1)) + polynomial(Z(1), VARIABLE, 1, 1) * polynomial(Z(1), VARIABLE, 2, 2 * k)); + if(d == 0) + break; + k++; } - // computing Lee homolgy - if(verbose) - std::cout << "Computing Lee homology" << std::endl; - { - chain_complex_simplifier s(C, d, maybe(1), maybe(2)); - C = s.new_C; - d = s.new_d; - leep = C->free_poincare_polynomial(); - if(d != 0) { - std::cout << "For now, you can only use this criterion on Kh-thin knots." << std::endl; - exit(EXIT_FAILURE); - } - if(verbose) { - std::cout << "LeeP = " << leep << "\n"; - } + khp = *lee_ss_polynomials.begin(); + leep = *lee_ss_polynomials.rbegin(); + + if(verbose) { + std::cerr << "KhP = " << khp << "\n"; + std::cerr << "LeeP = " << leep << "\n"; } + // for(unsigned i = 0; i < lee_ss_polynomials.size(); ++i) { + // std::cerr << "lee_ss_polynomials[" << i << "]= " + // << lee_ss_polynomials[i] << "\n"; + // std::cerr << "mul[" << i << "] = " << mul[i] << "\n"; + // } + return lee_ss_polynomials; } -void Kh_periodicity_checker::compute_quot() { - polynomial diff = khp - leep; - 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]) { - quot += polynomial(m1.second, m1.first); - polynomial p = polynomial(m1.second, m1.first) * mul; - diff -= p; - if(diff != 0) - m1 = diff.tail(); - else break; +void Kh_periodicity_checker::compute_quot(const std::vector& lee_ss_polynomials) { + // quot.push_back(polynomial(Z(0))); + for(unsigned i = 1; i < lee_ss_polynomials.size(); ++i) { + polynomial diff = lee_ss_polynomials[i-1] - lee_ss_polynomials[i]; + polynomial q = 0; + // std::cerr << "diff = " << diff << "\n"; + // std::cerr << "mul = " << mul[i-1] << "\n"; + 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]) { + q += polynomial(m1.second, m1.first); + polynomial p = polynomial(m1.second, m1.first) * mul[i-1]; + diff -= p; + if(diff != 0) + m1 = diff.tail(); + else break; + } + if(diff != 0) + m = diff.head(); + else + break; } - if(diff != 0) - m = diff.head(); - else - break; + q += polynomial(m.second, m.first); + polynomial p = polynomial(m.second, m.first) * mul[i-1]; + diff -= p; } - quot += polynomial(m.second, m.first); - polynomial p = polynomial(m.second, m.first) * mul; - diff -= p; + quot.push_back(q); } + // for(unsigned i = 0; i < quot.size(); ++i) { + // std::cerr << "quot[" << i << "] = " << quot[i] << "\n"; + // } } -std::pair, multivariate_laurentpoly> -Kh_periodicity_checker::compute_quotient_and_remainder(const polynomial& quot, - int period) const { - polynomial quotient, remainder; - for(map::const_iter i = quot.coeffs; i; i++) { - std::tuple div = i.val().divide_with_remainder(period - 1); - quotient += polynomial(std::get<0>(div), i.key()); - remainder += polynomial(std::get<1>(div), i.key()); +polynomial_tuple +Kh_periodicity_checker::compute_quotient_and_remainder(const std::vector& quot, int period) const { + polynomial_tuple decomposed_khp; + for(unsigned i = 0; i < quot.size(); ++i) { + polynomial quotient, remainder; + for(map::const_iter j = quot[i].coeffs; j; j++) { + std::tuple div = j.val().divide_with_remainder(period - 1); + quotient += polynomial(std::get<0>(div), j.key()); + remainder += polynomial(std::get<1>(div), j.key()); + } + decomposed_khp.push_back(std::make_tuple(quotient, remainder, std::move(mul[i]))); } if(verbose) { - std::cout << "Decomposition of Khp = " << std::endl - << leep << " + (" - << mul << ") * (" - << remainder; - if(quotient != 0) { - std::cout << " + " << (period - 1) - << " * (" << quotient - << ")"; + std::cerr << "Decomposition of Khp = " << std::endl + << leep; + for(auto& p: decomposed_khp) { + polynomial quotient, remainder, mul; + tie(quotient, remainder, mul) = p; + std::cerr << " + (" << mul << ") * (" + << remainder; + if(quotient != 0) + std::cerr << " + " << (period - 1) + << "*(" << quotient << ")"; + std::cerr << ")"; } - std::cout << ")" << std::endl; - + std::cerr << "\n"; } - return std::make_pair(quotient, remainder); + return decomposed_khp; } -std::map, std::pair> -Kh_periodicity_checker::compute_bounds(const polynomial& p, int period) const { - std::map> bounds; +bounds_vector +Kh_periodicity_checker::compute_bounds(const polynomial_tuple& p_tuple, int period) const { periodic_congruence_checker pcc(period); - for(map::const_iter i = p.coeffs; i; ++i) { - monomial mon; - int exp = 0; - if(i.key().m % ev_index) { - exp = i.key().m[ev_index]; - for(map::const_iter j = i.key().m; j; ++j) { - if(j.key() != ev_index) { + bounds_vector bounds_v; + for(auto& p: p_tuple) { + polynomial quotient, remainder, mul; + tie(quotient, remainder, mul) = p; + for(map::const_iter i = quotient.coeffs; i; ++i) { + monomial mon; + int exp = 0; + if(i.key().m % ev_index) { + exp = i.key().m[ev_index]; + for(map::const_iter j = i.key().m; j; ++j) { + if(j.key() != ev_index) { + int v = j.val() % (2 * period); + if(v < 0) v += (2 * period); + mon *= monomial(VARIABLE, j.key(), v); + } + } + } + else { + for(map::const_iter j = i.key().m; j; ++j) { int v = j.val() % (2 * period); if(v < 0) v += (2 * period); mon *= monomial(VARIABLE, j.key(), v); } } - } - else { - for(map::const_iter j = i.key().m; j; ++j) { - int v = j.val() % (2 + period); - if (v < 0) v += (2 * period); - mon *= monomial(VARIABLE, j.key(), v); + // std::cerr << polynomial(i.val() * pow(-1,exp), mon) << "\n"; + Z v_temp = i.val() * pow(-1, exp); + polynomial p_temp = (polynomial(1, mon) * mul).evaluate(-1, ev_index); + p_temp = pcc.reduce(p_temp - invert_variable(p_temp, index)); + // std::cerr << "p_temp = " << p_temp << "\n"; + // std::cerr << "v_temp = " << v_temp << "\n"; + // std::cerr << "min_exp = " << min_exp << "\n"; + if(bounds_v.count(p_temp)) { + if(v_temp >= 0) + bounds_v[p_temp].second += (v_temp * period); + else + bounds_v[p_temp].first += (v_temp * period); + } + else if(bounds_v.count(p_temp)) { + if(v_temp >= 0) + bounds_v[p_temp].first -= (v_temp * period); + else + bounds_v[p_temp].second -= (v_temp * period); + } + else { + bounds_v.emplace(p_temp, + std::make_pair((v_temp < 0 ? (v_temp * period) : Z(0)), (v_temp >= 0 ? (v_temp * period) : Z(0)))); } } - // std::cout << polynomial(i.val() * pow(-1, exp), mon) << "\n"; - Z v_temp = i.val() * pow(-1, exp); - polynomial p_temp = (polynomial(1, mon) * mul).evaluate(-1, ev_index); - p_temp = pcc.reduce(p_temp - invert_variable(p_temp, index)); - if(v_temp >= 0) - bounds[p_temp].second += (v_temp * period); - else - bounds[p_temp].first += (v_temp * period); } - // for(std::map>::iterator mi = bounds.begin(); mi != bounds.end(); ++mi) { - // std::cout << "Monomial: " << mi->first << "\n"; - // std::cout << "Max: " << std::get<1>(mi->second) - // << ", Min: " << std::get<0>(mi->second) << "\n"; - // } - return bounds; -} - -std::vector> -Kh_periodicity_checker::compute_basis_polynomials(int period) const { - std::vector res; - periodic_congruence_checker pcc(period); - for(int i = 1; i < period; i += 2) { - res.push_back(pcc.reduce(get_basis_polynomial(i))); + if(verbose) { + for(auto& t: bounds_v) { + Z neg, pos; + tie(neg, pos) = t.second; + std::cerr << "polynomial = " << t.first << "\n"; + std::cerr << "min = " << neg << ", max = " << pos << "\n"; + } } - return res; + return bounds_v; } -multivariate_laurentpoly Kh_periodicity_checker::get_basis_polynomial(monomial mon) const { - return (polynomial(Z(1), mon) * mul).evaluate(-1, ev_index) - - invert_variable((polynomial(Z(1), mon) * mul).evaluate(-1, ev_index), index); -} - -bool Kh_periodicity_checker::check(const polynomial& q, - const polynomial& r, +Test_Result Kh_periodicity_checker::check(const polynomial_tuple& polynomials, int period) const { periodic_congruence_checker pcc(period); - polynomial t = (leep + mul * (r - q)).evaluate(-1, ev_index); - t = pcc.reduce(t - invert_variable(t, index)); - if(pcc(t)) { - return true; + polynomial t = polynomial(COPY, leep); + for(auto& p : polynomials) { + polynomial quotient, remainder, mul; + tie(quotient, remainder, mul) = p; + t += mul * (remainder - quotient); + //std::cerr << "t = " << t << "\n"; } - else if(q == 0) - return false; - // std::cout << t << std::endl; - // std::cout << q << "\n"; - std::map> bounds = compute_bounds(q, period); - for(std::map>::iterator it = bounds.begin(); - it != bounds.end(); ++it) { - polynomial mon = it->first; + polynomial s = t.evaluate(-1, ev_index); + s = pcc.reduce(s - invert_variable(s, index)); + if(pcc(s)) { + return Test_Result::MAYBE; } - std::vector basis_polynomials = compute_basis_polynomials(period); - polynomial p = pcc.reduce(get_basis_polynomial(2 * period - 1)); - for(Z i = bounds[p].first; i <= bounds[p].second; i += 5) { - polynomial p_temp = t + polynomial(i, VARIABLE, index, 0) * p; - // std::cout << "i = " << i << "\n"; - // std::cout << "p_temp = " << p_temp << "\n"; - if(p_temp == 0) - return true; - for(std::vector::iterator it = basis_polynomials.begin(); it != basis_polynomials.end(); ++it) { - pair m = p_temp.coeffs.head(); - monomial mon = m.first; - Z c = m.second; - polynomial pp = pcc.reduce(get_basis_polynomial(mon)); - if(pp == *it) { - if(c < bounds[pp].first || c > bounds[pp].second) - break; - else { - // std::cout << "pp = " << pp << "\n"; - p_temp -= polynomial(c, VARIABLE, index, 0) * pp; - // std::cout << "p_temp = " << p_temp << "\n"; - if(p_temp == 0) - return true; - } - } - } + else if(all_of(polynomials.begin(), polynomials.end(), + [](std::tuple t) + { return get<0>(t) == 0; })) + return Test_Result::NO; + bounds_vector bounds = compute_bounds(polynomials, period); + + if(verbose) + std::cerr << "s = " << s << "\n"; + Kh_bounds_iterator Kh_b_it(bounds, period); + if(verbose) + std::cerr << "current_state = " << Kh_b_it.get_polynomial() << "\n"; + if(Kh_b_it.get_polynomial() == s) + return Test_Result::MAYBE; + while(Kh_b_it.advance()) { + if(verbose) + std::cerr << "current_state = " << Kh_b_it.get_polynomial() << "\n"; + if(s == Kh_b_it.get_polynomial()) + return Test_Result::MAYBE; } - return false; + return Test_Result::NO_NONTRIVIAL_DECOMP; } std::string Kh_periodicity_checker::operator () (int period) const { @@ -247,10 +304,11 @@ std::string Kh_periodicity_checker::operator () (int period) const { out << knot_name << ": period = " << period << ": No (Przytycki's criterion)."; } else { - std::pair q_r = compute_quotient_and_remainder(quot, period); - bool res = check(std::get<0>(q_r), std::get<1>(q_r), period); + auto q_r = compute_quotient_and_remainder(quot, period); + Test_Result res = check(q_r, period); out << knot_name << ": period = " << period << ": " - << (res ? "Maybe" : "No"); + << (res == Test_Result::MAYBE ? "Maybe" : + (res == Test_Result::NO ? "No" : "No (Nontrivial decomposition).")); } return out.str(); } diff --git a/periodicity.h b/periodicity.h index 9e37fb7..6119fea 100644 --- a/periodicity.h +++ b/periodicity.h @@ -6,6 +6,7 @@ #include #include #include +#include extern bool verbose; extern const char* knot; @@ -14,6 +15,8 @@ extern std::string periodicity_test; const std::vector primes_list = {5, 7, 11, 13, 17, 19}; +enum class Test_Result { MAYBE, NO, NO_NONTRIVIAL_DECOMP }; + const unsigned eval_index = 1; const unsigned invert_index = 2; @@ -59,6 +62,8 @@ periodic_congruence_checker::reduce(const multivariate_laurentpoly& pol) c monomial mon = monomial(VARIABLE, index, c); res += polynomial(i.val(), mon); } + // if(verbose) + // std::cout << "res = " << res << "\n"; return res; } @@ -78,43 +83,61 @@ class Przytycki_periodicity_checker { std::string operator() (int period) const; }; +class Kh_bounds_iterator { + using polynomial = multivariate_laurentpoly; + using monomial = multivariate_laurent_monomial; + using polynomial_tuple = std::vector>; + using bounds_vector = std::map, std::pair>; + + bounds_vector bv; + int period; + std::map current_state; + std::map>::iterator level; + +public: + Kh_bounds_iterator(bounds_vector v, int p) : + bv(v), period(p) { + for(auto& v: bv) { + current_state[v.first] = v.second.first; + } + level = bv.begin(); + } + ~Kh_bounds_iterator() {} + + bool advance(); + polynomial get_polynomial() const; +}; + class Kh_periodicity_checker { using polynomial = multivariate_laurentpoly; using monomial = multivariate_laurent_monomial; + using polynomial_tuple = std::vector>; + using bounds_vector = std::map, std::pair>; unsigned ev_index; unsigned index; - polynomial khp, leep, quot; - polynomial mul; + polynomial khp, leep; + std::vector quot, mul, quotients, remainders; std::string knot_name; - void compute_knot_polynomials(knot_diagram& kd); - void compute_quot(); - std::pair compute_quotient_and_remainder(const polynomial& p, - int period) const; - std::map> - compute_bounds(const polynomial& p, int period) const; - polynomial get_basis_polynomial(int exp) const { - return (polynomial(1, VARIABLE, index, exp) * mul).evaluate(-1, ev_index) - - invert_variable((polynomial(1, VARIABLE, index, exp) * mul).evaluate(-1, ev_index), index); - } - polynomial get_basis_polynomial(monomial mon) const; - std::vector compute_basis_polynomials(int period) const; - bool check(const polynomial& q, const polynomial& r, int period) const; + std::vector compute_knot_polynomials(knot_diagram& kd); + void compute_quot(const std::vector& lee_ss_polynomials); + polynomial_tuple + compute_quotient_and_remainder(const std::vector& p, int period) const; + bounds_vector + compute_bounds(const polynomial_tuple& p, int period) const; + Test_Result check(const polynomial_tuple& polynomials, int period) const; public: Kh_periodicity_checker(knot_diagram& kd, std::string knot_n) : knot_name(knot_n) { ev_index = 1; index = 2; - mul = polynomial(Z(1)) - + polynomial(1, VARIABLE, ev_index) * - polynomial(1, VARIABLE, index, 2); - - compute_knot_polynomials(kd); - compute_quot(); + quot = std::vector(); + mul = std::vector(); + compute_quot(compute_knot_polynomials(kd)); } ~Kh_periodicity_checker() {}