Added support to compute Sq1 and Sq2 on Kh.

This commit is contained in:
Cotton Seed 2012-04-11 01:06:04 -04:00
parent a0e543e4df
commit 8dfa237fc4
12 changed files with 1291 additions and 185 deletions

View File

@ -19,7 +19,8 @@ CXXFLAGS = $(OPTFLAGS) -Wall -Wno-unused $(INCLUDES)
LIB_OBJS = lib/refcount.o \
lib/lib.o lib/smallbitset.o lib/bitset.o lib/setcommon.o lib/io.o lib/directed_multigraph.o
ALGEBRA_OBJS = algebra/algebra.o algebra/grading.o algebra/polynomial.o
KNOTKIT_OBJS = planar_diagram.o dt_code.o knot_diagram.o cube.o spanning_tree_complex.o \
KNOTKIT_OBJS = planar_diagram.o dt_code.o knot_diagram.o cube.o steenrod_square.o \
spanning_tree_complex.o \
smoothing.o cobordism.o knot_tables.o sseq.o \
knot_parser/knot_parser.o knot_parser/knot_scanner.o \
rd_parser/rd_parser.o rd_parser/rd_scanner.o
@ -38,7 +39,8 @@ ALGEBRA_HEADERS = algebra/algebra.h algebra/grading.h algebra/module.h \
algebra/polynomial.h algebra/multivariate_polynomial.h \
algebra/multivariate_laurentpoly.h algebra/fraction_field.h
KNOTKIT_HEADERS = knotkit.h planar_diagram.h dt_code.h knot_diagram.h \
smoothing.h cobordism.h cube.h spanning_tree_complex.h cube_impl.h sseq.h
smoothing.h cobordism.h cube.h steenrod_square.h \
spanning_tree_complex.h cube_impl.h sseq.h simplify_chain_complex.h
LIBS = -lgmp -lz

View File

@ -11,6 +11,7 @@ class Z2
public:
Z2 () : v(0) { }
Z2 (int x) : v((bool)(x & 1)) { }
Z2 (unsigned x) : v((bool)(x & 1)) { }
Z2 (bool v_) : v(v_) { }
Z2 (const Z2 &x) : v(x.v) { }
Z2 (copy, const Z2 &x) : v(x.v) { }

View File

@ -40,7 +40,7 @@ class linear_combination
v.push (i.key (), R (COPY, i.val ()));
}
~linear_combination () { }
linear_combination &operator = (const linear_combination &lc)
{
m = lc.m;

View File

@ -628,7 +628,8 @@ class map_impl : public refcounted
map_impl &operator = (const map_impl &) = delete;
virtual linear_combination<R> column (unsigned i) const = 0;
virtual const linear_combination<R> column (unsigned i) const = 0;
virtual const linear_combination<R> column_copy (unsigned i) const { return column (i); }
linear_combination<R> map (const linear_combination<R> &lc) const
{
@ -657,7 +658,11 @@ class explicit_map_impl : public map_impl<R>
{ }
~explicit_map_impl () { }
linear_combination<R> column (unsigned i) const { return columns[i]; }
const linear_combination<R> column (unsigned i) const { return columns[i]; }
const linear_combination<R> column_copy (unsigned i) const
{
return linear_combination<R> (COPY, columns[i]);
}
};
template<class R>
@ -667,7 +672,7 @@ class zero_map_impl : public map_impl<R>
zero_map_impl (ptr<const module<R> > fromto) : map_impl<R>(fromto) { }
zero_map_impl (ptr<const module<R> > from, ptr<const module<R> > to) : map_impl<R>(from, to) { }
linear_combination<R> column (unsigned i) const { return linear_combination<R> (this->to); }
const linear_combination<R> column (unsigned i) const { return linear_combination<R> (this->to); }
};
template<class R>
@ -677,7 +682,7 @@ class id_map_impl : public map_impl<R>
id_map_impl (ptr<const module<R> > fromto) : map_impl<R>(fromto) { }
id_map_impl (ptr<const module<R> > from, ptr<const module<R> > to) : map_impl<R>(from, to) { }
linear_combination<R> column (unsigned i) const
const linear_combination<R> column (unsigned i) const
{
linear_combination<R> r (this->to);
r.muladd (1, i);
@ -700,7 +705,7 @@ class composition_impl : public map_impl<R>
assert (g->to == f->from);
}
linear_combination<R> column (unsigned i) const
const linear_combination<R> column (unsigned i) const
{
return f->map (g->column (i));
}
@ -721,7 +726,7 @@ class direct_sum_impl : public map_impl<R>
{
}
linear_combination<R> column (unsigned i) const
const linear_combination<R> column (unsigned i) const
{
pair<unsigned, unsigned> p = f->from->project (g->from, i);
@ -756,7 +761,7 @@ class tensor_impl : public map_impl<R>
{
}
linear_combination<R> column (unsigned i) const
const linear_combination<R> column (unsigned i) const
{
pair<unsigned, unsigned> p = f->from->generator_factors (g->from, i);
@ -884,8 +889,10 @@ class mod_map
bool operator != (int x) const { return !operator == (x); }
linear_combination<R> column (unsigned i) const { return impl->column (i); }
linear_combination<R> operator [] (unsigned i) const { return impl->column (i); }
const linear_combination<R> column (unsigned i) const { return impl->column (i); }
const linear_combination<R> operator [] (unsigned i) const { return impl->column (i); }
const linear_combination<R> column_copy (unsigned i) const { return impl->column_copy (i); }
linear_combination<R> map (const linear_combination<R> &lc) const { return impl->map (lc); }
mod_map compose (const mod_map &m) const
@ -1637,8 +1644,8 @@ mod_map<R>::operator + (const mod_map &m) const
basedvector<linear_combination<R>, 1> v (impl->from->dim ());
for (unsigned i = 1; i <= m.impl->from->dim (); i ++)
v[i] = column (i) + m.columns (i);
return explicit_map_impl<R> (impl->from, impl->to, v);
v[i] = column (i) + m.column (i);
return mod_map (IMPL, new explicit_map_impl<R> (impl->from, impl->to, v));
}
template<class R> ptr<const free_submodule<R> >

4
cube.h
View File

@ -16,8 +16,8 @@ template<class R>
class cube /* of resolutions */
{
public:
typedef typename R::linear_combination linear_combination;
typedef typename R::linear_combination_const_iter linear_combination_const_iter;
typedef ::linear_combination<R> linear_combination;
typedef ::linear_combination_const_iter<R> linear_combination_const_iter;
public:
bool markedp_only;

View File

@ -14,11 +14,13 @@ class knot_diagram;
#include <dt_code.h>
#include <knot_diagram.h>
#include <simplify_chain_complex.h>
#include <sseq.h>
#include <smoothing.h>
#include <cobordism.h>
#include <cube.h>
#include <steenrod_square.h>
#include <spanning_tree_complex.h>
unsigned rolfsen_crossing_knots (unsigned n);

View File

@ -54,8 +54,9 @@ public:
triple (const F &first_, const S &second_, const T &third_)
: first(first_), second(second_), third(third_)
{ }
triple (reader &r);
~triple () { }
triple &operator = (const triple &t)
{
first = t.first;
@ -81,13 +82,11 @@ public:
return 1;
else if (second > t.second)
return 0;
if (third < t.third)
return 1;
else if (third > t.third)
return 0;
return third < t.third;
}
void write_self (writer &w) const;
hash_t hash_self () const
{
hash_t h = hash (first);
@ -95,3 +94,19 @@ public:
return hash_combine (h, hash (third));
}
};
template <class F, class S, class T>
triple<F, S, T>::triple (reader &r)
{
read (r, first);
read (r, second);
read (r, third);
}
template<class F, class S, class T> void
triple<F, S, T>::write_self (writer &w) const
{
write (w, first);
write (w, second);
write (w, third);
}

280
main.cpp
View File

@ -127,189 +127,143 @@ rank_lte (multivariate_laurentpoly<Z> p,
int
main ()
{
#if 0
ullmanset<1> empty;
assert (empty.size () == 0);
assert (empty.card () == 0);
assert (empty.is_empty ());
for (int a = 1; a >= 0; a --)
for (unsigned i = 1; i <= 9; i ++)
for (unsigned j = 1; j <= htw_knots (i, a); j ++)
{
knot_diagram kd (htw_knot (i, a, j));
show (kd); newline ();
cube<Z2> c (kd);
mod_map<Z2> d = c.compute_d (1, 0, 0, 0, 0);
ullmanset<1> empty2;
assert (empty == empty2);
chain_complex_simplifier<Z2> s (c.khC, d, 1);
steenrod_square sq (c, d, s);
mod_map<Z2> sq1 = sq.sq1 ();
// display ("sq1:\n", sq1);
ullmanset<1> emptycopy (COPY, empty);
assert (emptycopy == empty);
mod_map<Z2> sq2 = sq.sq2 ();
if (a)
assert (sq2 == 0);
else
display ("sq2:\n", sq2);
ullmanset<1> s (50, {1,2,5,5,2,1,3,4});
assert (s.card () == 5);
ullmanset<1> scopy (COPY, s);
assert (scopy == s);
printf ("s:");
for (int x : s)
printf (" %d", x);
newline ();
#endif
map<unsigned, const char *> m = { { 5, "foo" }, { 11, "bar" } };
hashmap<unsigned, const char *> m2 = { { 5, "foo" }, { 11, "bar" }, { 37, "baz" } };
for (std::pair<unsigned, const char *> i : m2)
{
printf ("%d -> %s\n", i.first, i.second);
}
assert (sq1.compose (sq1) == 0);
assert (sq2.compose (sq2) + sq1.compose (sq2).compose (sq1) == 0);
}
#if 0
set<unsigned> s {1,2,5,5,2,1,3,4};
printf ("s:");
for (int x : s)
printf (" %d", x);
newline ();
#endif
typedef Z2 R;
#if 0
basedvector<int, 1> v (4);
v[1] = 2;
v[2] = -1;
v[3] = 0xbf32813;
v[4] = -352182;
vector<int> sleb (512);
for (unsigned i = 0; i < 512; i ++)
sleb[i] = ((int)i << 23);
printf ("sleb:\n");
for (unsigned i = 0; i < 512; i ++)
printf (" %d\n", sleb[i]);
vector<unsigned> uleb (512);
for (unsigned i = 0; i < 512; i ++)
uleb[i] = ((unsigned)i << 23);
printf ("uleb:\n");
for (unsigned i = 0; i < 512; i ++)
printf (" %u\n", uleb[i]);
polynomial<Z> one (1);
polynomial<Z> x (1, 1);
polynomial<Z> bigp (Z (367521));
polynomial<Z> t = x + bigp*one;
polynomial<Z> p = (t*t*t + t*t + t + one)*(bigp*t*t + bigp*bigp*t + bigp*bigp*bigp)*(bigp*bigp*t*t*t + bigp*t*t + t + one);
display ("p: ", p);
{
file_writer w ("test.dat");
write (w, v);
write (w, p);
write (w, sleb);
write (w, uleb);
}
{
gzfile_writer w ("test.2.dat.gz");
write (w, v);
write (w, p);
write (w, sleb);
write (w, uleb);
}
system ("gzip -cd test.2.dat.gz > test.2.dat");
{
file_reader r ("test.dat");
basedvector<int, 1> v2 (r);
polynomial<Z> p2 (r);
vector<int> sleb2 (r);
printf ("sleb2:\n");
for (unsigned i = 0; i < 512; i ++)
printf (" %d\n", sleb2[i]);
vector<unsigned> uleb2 (r);
assert (v == v2);
assert (p == p2);
assert (sleb == sleb2);
assert (uleb == uleb2);
}
system ("gzip -c9 test.dat > test.dat.gz");
{
gzfile_reader r ("test.dat.gz");
basedvector<int, 1> v2 (r);
polynomial<Z> p2 (r);
vector<int> sleb2 (r);
vector<unsigned> uleb2 (r);
assert (v == v2);
assert (p == p2);
assert (sleb == sleb2);
assert (uleb == uleb2);
}
#endif
#if 0
#if 0
test_ring<Z> (0);
test_ring<polynomial<Z> > (0);
test_field<Z2> ();
test_field<Zp<7> > ();
test_field<Q> ();
// test_field<fraction_field<Zp<7> > > ();
#endif
#if 0
for (unsigned i = 1; i <= 10; i ++)
for (unsigned j = 1; j <= rolfsen_crossing_knots (i); j ++)
{
knot_diagram kd (rolfsen_knot (i, j));
#endif
for (unsigned i = 1; i <= 12; i ++)
for (unsigned i = 12; i <= 12; i ++)
for (unsigned j = 1; j <= htw_knots (i, 0); j ++)
{
knot_diagram kd (htw_knot (i, 0, j));
show (kd); newline ();
cube<R> c (kd);
mod_map<R> d = c.compute_d (1, 0, 0, 0, 0);
chain_complex_simplifier<R> s (c.khC, d, 1);
// assert (s.new_d == 0);
printf ("|s.new_C| = %d\n", s.new_C->dim ());
}
#endif
#if 1
map<multivariate_laurentpoly<Z>,
set<triple<unsigned, int, unsigned> > > kh_knot_map;
for (int a = 1; a >= 0; a --)
for (unsigned i = 1; i <= 12; i ++)
for (unsigned j = 1; j <= htw_knots (i, a); j ++)
{
knot_diagram kd (htw_knot (i, a, j));
kd.marked_edge = 1;
show (kd); newline ();
cube<Z2> c (kd, 1);
mod_map<Z2> d = c.compute_d (1, 0, 0, 0, 0);
sseq_builder b (c.khC, d);
sseq ss = b.build_sseq ();
multivariate_laurentpoly<Z> P = ss.pages[1].poincare_polynomial (ss.bounds);
kh_knot_map[P].push (triple<unsigned, int, unsigned> (i, a, j));
}
{
writer w ("kh_knot_map.dat");
write (w, kh_knot_map);
}
#endif
#if 0
reader r ("kh_knot_map.dat");
map<multivariate_laurentpoly<Z>,
set<triple<unsigned, int, unsigned> > > kh_knot_map (r);
for (map<multivariate_laurentpoly<Z>,
set<triple<unsigned, int, unsigned> > >::const_iter i = kh_knot_map; i; i ++)
{
printf ("P = "); display (i.key ());
for (set_const_iter<triple<unsigned, int, unsigned> > j = i.val (); j; j ++)
{
knot_diagram kd (htw_knot (j.val ().first,
j.val ().second,
j.val ().third));
printf (" ");
show (kd);
newline ();
}
}
#endif
#if 0
typedef Z2 F;
typedef fraction_field<polynomial<F> > R;
for (unsigned i = 1; i <= 10; i ++)
for (unsigned j = 1; j <= htw_knots (i, 0); j ++)
{
knot_diagram kd (htw_knot (i, 0, j));
kd.marked_edge = 1;
show (kd); newline ();
spanning_tree_complex<Z2> c (kd);
spanning_tree_complex<F> st (kd);
mod_map<fraction_field<polynomial<Z2> > > E2_d = c.twisted_d2 ();
assert (E2_d.compose (E2_d) == 0);
// display ("E2_d:\n", E2_d);
mod_map<R> d2 = st.twisted_d2 ();
assert (d2.compose (d2) == 0);
chain_complex_simplifier<fraction_field<polynomial<Z2> > > E2_s (c.C, E2_d, 2);
assert (E2_s.new_d == 0);
mod_map<R> d2U1 = st.twisted_d2Un (1);
// mod_map<R> d2U1 = st.twisted_d2U1_test ();
multivariate_laurentpoly<Z> E3_p = E2_s.new_C->free_delta_poincare_polynomial ();
printf ("E3_p = "); show (E3_p); newline ();
mod_map<fraction_field<polynomial<Z2> > > tt_d = c.totally_twisted_kh_d ();
assert (tt_d.compose (tt_d) == 0);
// display ("tt_d:\n", tt_d);
assert (d2.compose (d2U1) + d2U1.compose (d2) == 0);
chain_complex_simplifier<fraction_field<polynomial<Z2> > > tt_s (c.C, tt_d, 2);
assert (tt_s.new_d == 0);
mod_map<R> d2U2 = st.twisted_d2Un (2);
assert (d2.compose (d2U2) + d2U2.compose (d2) + d2U1.compose (d2U1) == 0);
mod_map<R> d2U3 = st.twisted_d2Un (3);
assert (d2.compose (d2U3) + d2U3.compose (d2)
+ d2U2.compose (d2U1) + d2U1.compose (d2U2) == 0);
multivariate_laurentpoly<Z> tt_p = tt_s.new_C->free_delta_poincare_polynomial ();
printf ("tt_p = "); show (tt_p); newline ();
mod_map<R> d2U4 = st.twisted_d2Un (4);
assert (d2.compose (d2U4) + d2U4.compose (d2)
+ d2U3.compose (d2U1) + d2U1.compose (d2U3)
+ d2U2.compose (d2U2) == 0);
mod_map<R> d2U5 = st.twisted_d2Un (5);
assert (d2.compose (d2U5) + d2U5.compose (d2)
+ d2U4.compose (d2U1) + d2U1.compose (d2U4)
+ d2U3.compose (d2U2) + d2U2.compose (d2U3) == 0);
cube<Z2> kh_c (kd, 1);
mod_map<Z2> kh_d = kh_c.compute_d (1, 0, 0, 0, 0);
sseq_builder builder (kh_c.khC, kh_d);
sseq ss = builder.build_sseq ();
multivariate_laurentpoly<Z> kh_p = ss.pages[1].delta_poincare_polynomial (ss.bounds);
printf ("kh_p = "); show (kh_p); newline ();
if (tt_p != kh_p)
printf (" > tt_p != kh_p!!\n");
if (! rank_lte (E3_p, tt_p))
printf (" > rank E2 > rank tt!!\n");
mod_map<R> d2U6 = st.twisted_d2Un (6);
assert (d2.compose (d2U6) + d2U6.compose (d2)
+ d2U5.compose (d2U1) + d2U1.compose (d2U5)
+ d2U4.compose (d2U2) + d2U2.compose (d2U4)
+ d2U3.compose (d2U3) == 0);
}
#endif
}

248
simplify_chain_complex.h Normal file
View File

@ -0,0 +1,248 @@
template<class R> class simplified_complex_generators
{
unsigned new_n;
ptr<const module<R> > C;
basedvector<unsigned, 1> new_C_to_C_generator;
public:
simplified_complex_generators (const simplified_complex_generators &g)
: new_n(g.new_n),
C(g.C),
new_C_to_C_generator(g.new_C_to_C_generator)
{ }
simplified_complex_generators (unsigned new_n_,
ptr<const module<R> > C_,
basedvector<unsigned, 1> new_C_to_C_generator_)
: new_n(new_n_),
C(C_),
new_C_to_C_generator(new_C_to_C_generator_)
{ }
~simplified_complex_generators () { }
simplified_complex_generators &operator = (const simplified_complex_generators &); // doesn't exist
unsigned dim () const { return new_n; }
unsigned free_rank () const { return new_n; }
grading generator_grading (unsigned i) const { return C->generator_grading (new_C_to_C_generator[i]); }
void show_generator (unsigned i) const { C->show_generator (new_C_to_C_generator[i]); }
R generator_ann (unsigned i) const { abort (); }
};
template<class R>
class chain_complex_simplifier
{
public:
ptr<const module<R> > C;
unsigned n; // |C|
mod_map<R> d;
ptr<const module<R> > new_C;
mod_map<R> new_d;
// pi : C -> new_C
mod_map<R> pi;
// iota : new_C -> C
mod_map<R> iota;
private:
set<unsigned> canceled;
basedvector<R, 1> cancel_binv;
basedvector<unsigned, 1> cancel_j;
basedvector<linear_combination<R>, 1> cancel_di;
basedvector<linear_combination<R>, 1> new_d_columns;
basedvector<set<unsigned>, 1> preim;
basedvector<linear_combination<R>, 1> iota_columns;
void cancel (unsigned i, R b, unsigned j);
public:
chain_complex_simplifier (ptr<const module<R> > C_,
const mod_map<R> &d_,
int dh);
};
template<class R> void
chain_complex_simplifier<R>::cancel (unsigned i, R b, unsigned j)
{
assert (i != j);
assert (b.is_unit ());
R binv = b.recip ();
canceled.push (i);
canceled.push (j);
new_d_columns[i].yank (j);
preim[j].yank (i);
for (linear_combination_const_iter<R> k = new_d_columns[i]; k; k ++)
preim[k.key ()].yank (i);
for (set_const_iter<unsigned> k = preim[i]; k; k ++)
new_d_columns[k.val ()].yank (i);
for (linear_combination_const_iter<R> k = new_d_columns[j]; k; k ++)
preim[k.key ()].yank (j);
for (set_const_iter<unsigned> kk = preim[j]; kk; kk ++)
{
unsigned k = kk.val ();
R a = new_d_columns[k](j);
assert (a != 0);
iota_columns[k].mulsub (a * binv, iota_columns[i]);
}
iota_columns[i].clear ();
iota_columns[j].clear ();
for (set_const_iter<unsigned> kk = preim[j]; kk; kk ++)
{
unsigned k = kk.val ();
R a = new_d_columns[k](j);
assert (a != 0);
R abinv = a * binv;
for (linear_combination_const_iter<R> ll = new_d_columns[i]; ll; ll ++)
{
unsigned ell = ll.key ();
R c = ll.val ();
assert (! (canceled % k));
assert (! (canceled % ell));
assert (k != i);
assert (k != j);
assert (ell != i);
assert (ell != j);
assert (ell != k);
new_d_columns[k].mulsub (abinv * c, ell);
if (new_d_columns[k] % ell)
preim[ell] += k;
else
preim[ell] -= k;
}
}
for (set_const_iter<unsigned> k = preim[j]; k; k ++)
new_d_columns[k.val ()].yank (j);
cancel_binv.append (binv);
cancel_j.append (j);
cancel_di.append (new_d_columns[i]);
new_d_columns[i] = linear_combination<R> ();
preim[i].clear ();
new_d_columns[j].clear ();
preim[j].clear ();
}
template<class R>
chain_complex_simplifier<R>::chain_complex_simplifier (ptr<const module<R> > C_,
const mod_map<R> &d_,
int dh)
: C(C_), n(C_->dim ()), d(d_),
new_d_columns(n),
preim(n),
iota_columns(n)
{
for (unsigned i = 1; i <= n; i ++)
{
new_d_columns[i] = d.column_copy (i);
for (linear_combination_const_iter<R> j = new_d_columns[i]; j; j ++)
preim[j.key ()].push (i);
linear_combination<R> x (C);
x.muladd (1, i);
iota_columns[i] = x;
}
for (unsigned i = n; i >= 1; i --)
{
if (canceled % i)
continue;
grading igr = C->generator_grading (i);
for (linear_combination_const_iter<R> j = new_d_columns[i]; j; j ++)
{
grading jgr = C->generator_grading (j.key ());
assert (jgr.h >= igr.h);
if (j.val ().is_unit ()
&& jgr.h - igr.h == dh)
{
cancel (i, j.val (), j.key ());
break;
}
}
}
// ??? might not be completely simplified
unsigned new_n = n - canceled.card ();
basedvector<unsigned, 1> new_C_to_C_generator (new_n),
C_to_new_C_generator (n);
for (unsigned i = 1, j = 1; i <= n; i ++)
{
if (canceled % i)
{
C_to_new_C_generator[i] = 0;
continue;
}
C_to_new_C_generator[i] = j;
new_C_to_C_generator[j] = i;
j ++;
}
new_C = (new base_module<R, simplified_complex_generators<R> >
(simplified_complex_generators<R> (new_n, C, new_C_to_C_generator)));
map_builder<R> db (new_C);
for (unsigned i = 1; i <= new_n; i ++)
{
unsigned i0 = new_C_to_C_generator[i];
for (linear_combination_const_iter<R> j0 = new_d_columns[i0]; j0; j0 ++)
{
unsigned j = C_to_new_C_generator[j0.key ()];
assert (j != 0);
db[i].muladd (j0.val (), j);
}
}
new_d = mod_map<R> (db);
map_builder<R> iotab (new_C, C);
for (unsigned i = 1; i <= new_n; i ++)
iotab[i] = iota_columns[new_C_to_C_generator[i]];
iota = mod_map<R> (iotab);
map_builder<R> pib (C, new_C);
for (unsigned i = 1; i <= new_n; i ++)
pib[new_C_to_C_generator[i]].muladd (1, i);
while (cancel_binv.size () > 0)
{
R binv = cancel_binv.pop ();
unsigned j = cancel_j.pop ();
linear_combination<R> di = cancel_di.pop ();
for (linear_combination_const_iter<R> ll = di; ll; ll ++)
{
R c = ll.val ();
pib[j].mulsub (binv * c, pib[ll.key ()]);
}
}
pi = mod_map<R> (pib);
assert (d.compose (iota) == iota.compose (new_d));
assert (new_d.compose (pi) == pi.compose (d));
assert (pi.compose (iota) == mod_map<R> (new_C, 1));
}

View File

@ -25,6 +25,9 @@ class spanning_tree_complex
mod_map<R> totally_twisted_kh_d () const;
mod_map<R> twisted_d2 () const;
mod_map<R> twisted_d2Un (unsigned n) const;
mod_map<R> twisted_d2U1_test () const;
};
template<class F>
@ -210,6 +213,291 @@ spanning_tree_complex<F>::twisted_d2 () const
return mod_map<R> (b);
}
template<class F> mod_map<fraction_field<polynomial<F> > >
spanning_tree_complex<F>::twisted_d2Un (unsigned n) const
{
assert (kd.marked_edge);
assert (n >= 1);
map_builder<R> b (C);
basedvector<int, 1> edge_weight (kd.num_edges ());
for (unsigned i = 1; i <= kd.num_edges (); i ++)
edge_weight[i] = 1; // (1 << i);
int total_weight = 0;
for (unsigned i = 1; i <= kd.num_edges (); i ++)
total_weight += edge_weight[i];
int shift = 2 * total_weight * n;
for (unsigned i = 1; i <= trees.size (); i ++)
{
set<unsigned> t = trees[i];
smallbitset r (kd.n_crossings);
for (unsigned k = 1; k <= kd.n_crossings; k ++)
{
if ((edge_height[k] == 1) == (t % k))
r.push (k);
}
smoothing s (kd, r);
for (set_const_iter<unsigned> ee = t; ee; ee ++)
{
unsigned e = ee.val ();
if (edge_height[e] != 0)
continue;
for (unsigned f = 1; f <= bg.num_edges (); f ++)
{
if (edge_height[f] != 1 || (t % f))
continue;
set<unsigned> t2 (COPY, t);
t2.yank (e);
t2.push (f);
unsigned j = tree_idx(t2, 0);
if (j == 0)
continue;
bool neg = 0;
for (unsigned a = kd.marked_edge;;)
{
unsigned p = s.edge_to (kd, a);
if (kd.ept_crossing[p] == e)
{
if (s.is_crossing_from_ept (kd, r, p))
neg = s.crossing_from_inside (kd, r, e);
else
neg = s.crossing_to_inside (kd, r, e);
break;
}
else if (kd.ept_crossing[p] == f)
{
if (s.is_crossing_from_ept (kd, r, p))
neg = s.crossing_from_inside (kd, r, f);
else
neg = s.crossing_to_inside (kd, r, f);
break;
}
a = s.next_edge (kd, r, a);
assert (a != kd.marked_edge);
}
set<unsigned> neither (COPY, t);
neither.yank (e);
smallbitset neither_r (kd.n_crossings);
for (unsigned k = 1; k <= kd.n_crossings; k ++)
{
if ((edge_height[k] == 1) == (neither % k))
neither_r.push (k);
}
smoothing neither_s (kd, neither_r);
set<unsigned> both (COPY, t);
both.push (f);
int A = 0;
for (unsigned k = 1; k <= kd.num_edges (); k ++)
{
if (neither_s.edge_circle[k]
!= neither_s.edge_circle[kd.marked_edge])
A += edge_weight[k];
}
smallbitset both_r (kd.n_crossings);
for (unsigned k = 1; k <= kd.n_crossings; k ++)
{
if ((edge_height[k] == 1) == (both % k))
both_r.push (k);
}
smoothing both_s (kd, both_r);
int B = 0;
for (unsigned k = 1; k <= kd.num_edges (); k ++)
{
if (both_s.edge_circle[k]
!= both_s.edge_circle[kd.marked_edge])
B += edge_weight[k];
}
assert (A >= 0 && B >= 0);
R x;
for (int k = 1; k <= (int)n; k ++)
{
if (n % k == 0)
{
int l = n / k;
assert (k * l == (int)n);
assert (shift >= k*A + l*B);
if (neg) // ^ (bool)((n + 1) & 1))
{
x += R (polynomial<F> (1, (unsigned)(shift + k*A + l*B)));
x += R (polynomial<F> (1, (unsigned)(shift - k*A - l*B)));
}
else
{
x += R (polynomial<F> (1, (unsigned)(shift - k*A + l*B)));
x += R (polynomial<F> (1, (unsigned)(shift + k*A - l*B)));
}
}
}
b[i].muladd (x, j);
}
}
}
return mod_map<R> (b);
}
template<class F> mod_map<fraction_field<polynomial<F> > >
spanning_tree_complex<F>::twisted_d2U1_test () const
{
assert (kd.marked_edge);
map_builder<R> b (C);
basedvector<int, 1> edge_weight (kd.num_edges ());
for (unsigned i = 1; i <= kd.num_edges (); i ++)
edge_weight[i] = 1; // (1 << i);
int total_weight = 0;
for (unsigned i = 1; i <= kd.num_edges (); i ++)
total_weight += edge_weight[i];
int shift = 2 * total_weight;
for (unsigned i = 1; i <= trees.size (); i ++)
{
set<unsigned> t = trees[i];
smallbitset r (kd.n_crossings);
for (unsigned k = 1; k <= kd.n_crossings; k ++)
{
if ((edge_height[k] == 1) == (t % k))
r.push (k);
}
smoothing s (kd, r);
for (set_const_iter<unsigned> ee = t; ee; ee ++)
{
unsigned e = ee.val ();
if (edge_height[e] != 0)
continue;
for (unsigned f = 1; f <= bg.num_edges (); f ++)
{
if (edge_height[f] != 1 || (t % f))
continue;
set<unsigned> t2 (COPY, t);
t2.yank (e);
t2.push (f);
unsigned j = tree_idx(t2, 0);
if (j == 0)
continue;
bool neg = 0;
for (unsigned a = kd.marked_edge;;)
{
unsigned p = s.edge_to (kd, a);
if (kd.ept_crossing[p] == e)
{
if (s.is_crossing_from_ept (kd, r, p))
neg = s.crossing_from_inside (kd, r, e);
else
neg = s.crossing_to_inside (kd, r, e);
break;
}
else if (kd.ept_crossing[p] == f)
{
if (s.is_crossing_from_ept (kd, r, p))
neg = s.crossing_from_inside (kd, r, f);
else
neg = s.crossing_to_inside (kd, r, f);
break;
}
a = s.next_edge (kd, r, a);
assert (a != kd.marked_edge);
}
set<unsigned> neither (COPY, t);
neither.yank (e);
smallbitset neither_r (kd.n_crossings);
for (unsigned k = 1; k <= kd.n_crossings; k ++)
{
if ((edge_height[k] == 1) == (neither % k))
neither_r.push (k);
}
smoothing neither_s (kd, neither_r);
set<unsigned> both (COPY, t);
both.push (f);
int A = 0;
for (unsigned k = 1; k <= kd.num_edges (); k ++)
{
if (neither_s.edge_circle[k]
!= neither_s.edge_circle[kd.marked_edge])
A += edge_weight[k];
}
smallbitset both_r (kd.n_crossings);
for (unsigned k = 1; k <= kd.n_crossings; k ++)
{
if ((edge_height[k] == 1) == (both % k))
both_r.push (k);
}
smoothing both_s (kd, both_r);
int B = 0;
for (unsigned k = 1; k <= kd.num_edges (); k ++)
{
if (both_s.edge_circle[k]
!= both_s.edge_circle[kd.marked_edge])
B += edge_weight[k];
}
assert (A >= 0 && B >= 0);
printf ("A = %d, B = %d\n", A, B);
R x;
// worked:
// bad: -, -/+, +
assert (shift >= A && shift >= B);
if (neg)
{
x += R (polynomial<F> (1, (unsigned)(shift + A)));
x += R (polynomial<F> (1, (unsigned)(shift - B)));
}
else
{
x += R (polynomial<F> (1, (unsigned)(shift - A)));
x += R (polynomial<F> (1, (unsigned)(shift + B)));
}
b[i].muladd (x, j);
}
}
}
return mod_map<R> (b);
}
template<class F> mod_map<fraction_field<polynomial<F> > >
spanning_tree_complex<F>::totally_twisted_kh_d () const
{

547
steenrod_square.cpp Normal file
View File

@ -0,0 +1,547 @@
#include <knotkit.h>
steenrod_square::steenrod_square (const cube<Z2> &cor_,
mod_map<Z2> &d_,
const chain_complex_simplifier<Z2> &s_)
: cor(cor_), d(d_), s(s_)
{
for (unsigned i = 1; i <= cor.khC->dim (); i ++)
{
grading igr = cor.khC->generator_grading (i);
KGij[igr].push (i);
}
}
Z2
steenrod_square::sC (unsigned x, unsigned y) const
{
pair<unsigned, unsigned> x_sm = cor.generator_state_monomial (x),
y_sm = cor.generator_state_monomial (y);
unsigned changed = x_sm.first ^ y_sm.first;
assert (unsigned_bitcount (changed) == 1);
unsigned i = unsigned_ffs (changed);
unsigned k = 0;
for (unsigned j = 1; j < i; j ++)
{
if (unsigned_bittest (x_sm.first, j))
k ++;
}
return Z2 (k);
}
Z2
steenrod_square::fC (unsigned x, unsigned y) const
{
pair<unsigned, unsigned> x_sm = cor.generator_state_monomial (x),
y_sm = cor.generator_state_monomial (y);
unsigned changed = x_sm.first ^ y_sm.first;
assert (unsigned_bitcount (changed) == 2);
unsigned i = unsigned_ffs (changed),
j = unsigned_ffs (unsigned_bitclear (changed, i));
assert (i < j);
unsigned ki = 0;
for (unsigned l = 1; l < i; l ++)
{
if (unsigned_bittest (x_sm.first, l))
ki ++;
}
unsigned kj = 0;
for (unsigned l = i + 1; l < j; l ++)
{
if (unsigned_bittest (x_sm.first, l))
kj ++;
}
return Z2 (ki) * Z2 (kj);
}
triple<set<unsigned>, // G1cx
map<unsigned, unsigned>, // bx
map<unsigned, Z2> > // sx
steenrod_square::boundary_matching (grading cgr,
linear_combination<Z2> c,
unsigned x) const
{
set<unsigned> G1cx;
map<unsigned, unsigned> bx;
map<unsigned, Z2> sx;
for (linear_combination_const_iter<Z2> yy = c; yy; yy ++)
{
assert (yy.val () == 1);
unsigned y = yy.key ();
if (d[y](x) == 1)
G1cx.push (y);
}
assert (is_even (G1cx.card ()));
for (set_const_iter<unsigned> i = G1cx; i; i ++)
{
unsigned y = i.val ();
i ++;
unsigned bxy = i.val ();
bx.push (y, bxy);
bx.push (bxy, y);
sx.push (y, 0);
sx.push (bxy, Z2 (1) + sC (x, y) + sC (x, bxy));
}
#ifndef NDEBUG
for (set_const_iter<unsigned> yy = G1cx; yy; yy ++)
{
unsigned y = yy.val ();
assert (sx(y) + sx(bx(y)) == Z2 (1) + sC (x, y) + sC (x, bx(y)));
}
#endif
return triple<set<unsigned>, // G1cx
map<unsigned, unsigned>, // bx
map<unsigned, Z2> > // sx
(G1cx, bx, sx);
}
mod_map<Z2>
steenrod_square::sq1 () const
{
map_builder<Z2> b (s.new_C);
for (unsigned i = 1; i <= s.new_C->dim (); i ++)
{
grading cgr = s.new_C->generator_grading (i);
linear_combination<Z2> c = s.iota[i];
assert (d.map (c) == 0);
grading gr2 (cgr.h + 1, cgr.q);
if (! (KGij % gr2))
continue;
linear_combination<Z2> sq1c (cor.khC);
for (set_const_iter<unsigned> x = KGij[gr2]; x; x ++)
{
triple<set<unsigned>,
map<unsigned, unsigned>,
map<unsigned, Z2> > t = boundary_matching (cgr, c, x.val ());
Z2 a = 0;
for (set_const_iter<unsigned> y = t.first; y; y ++)
a += t.third(y.val ());
sq1c.muladd (a, x.val ());
}
// display ("sq1c:\n", sq1c);
assert (d.map (sq1c) == 0);
b[i].muladd (1, s.pi.map (sq1c));
}
return mod_map<Z2> (b);
}
set<pair<unsigned, unsigned> >
steenrod_square::make_G2cx (grading cgr,
linear_combination<Z2> c,
unsigned x) const
{
set<pair<unsigned, unsigned> > G2cx;
for (linear_combination_const_iter<Z2> yy = c; yy; yy ++)
{
unsigned y = yy.key ();
for (linear_combination_const_iter<Z2> zz = d[y]; zz; zz ++)
{
unsigned z = zz.key ();
if (d[z](x) == 1)
G2cx.push (pair<unsigned, unsigned> (z, y));
}
}
return G2cx;
}
class graph
{
public:
unsigned n_vertices;
unsigned n_edges;
basedvector<unsigned, 1> z;
basedvector<unsigned, 1> y;
map<pair<unsigned, unsigned>, unsigned> zy_vertex;
unsigned vertex (unsigned z, unsigned y) const
{
return zy_vertex(pair<unsigned, unsigned> (z, y));
}
basedvector<unsigned, 1> edge_from, edge_to;
set<unsigned> edge_oriented;
basedvector<Z2, 1> edge_label;
map<unsigned, set<unsigned> > incident_edges;
public:
graph (set<pair<unsigned, unsigned> > G2cx);
~graph () { }
void add_edge (unsigned from_z, unsigned from_y,
unsigned to_z, unsigned to_y,
Z2 label,
bool oriented);
unsigned num_components () const;
Z2 f () const; // sum of weights
Z2 g () const;
};
graph::graph (set<pair<unsigned, unsigned> > G2cx)
: n_vertices(G2cx.card ()),
n_edges(0),
z(n_vertices),
y(n_vertices)
{
unsigned j = 1;
for (set_const_iter<pair<unsigned, unsigned> > i = G2cx; i; i ++, j ++)
{
z[j] = i.val ().first;
y[j] = i.val ().second;
zy_vertex.push (i.val (), j);
}
#ifndef NDEBUG
for (unsigned i = 1; i <= n_vertices; i ++)
{
assert (i == vertex (z[i], y[i]));
}
#endif
assert (j == n_vertices + 1);
}
void
graph::add_edge (unsigned from_z, unsigned from_y,
unsigned to_z, unsigned to_y,
Z2 label,
bool oriented)
{
unsigned e = ++ n_edges;
unsigned from = vertex (from_z, from_y),
to = vertex (to_z, to_y);
edge_from.append (from);
edge_to.append (to);
edge_label.append (label);
assert (e == edge_label.size ());
if (oriented)
edge_oriented.push (e);
incident_edges[from].push (e);
incident_edges[to].push (e);
}
unsigned
graph::num_components () const
{
unionfind<1> u (n_vertices);
for (unsigned i = 1; i <= n_edges; i ++)
u.join (edge_from[i], edge_to[i]);
return u.num_sets ();
}
Z2
graph::f () const
{
Z2 a = 0;
for (unsigned i = 1; i <= n_edges; i ++)
a += edge_label[i];
return a;
}
Z2
graph::g () const
{
set<unsigned> done;
set<unsigned> A,
B;
for (unsigned i = 1; i <= n_edges; i ++)
{
if (done % i)
continue;
unsigned j = i;
unsigned v = edge_to[j];
for (;;)
{
if (edge_oriented % j)
{
if (edge_to[j] == v)
A.push (j);
else
B.push (j);
}
done.push (j);
if (incident_edges[v].head () == j)
j = incident_edges[v].tail ();
else
{
assert (j == incident_edges[v].tail ());
j = incident_edges[v].head ();
}
if (v == edge_to[j])
v = edge_from[j];
else
{
assert (v == edge_from[j]);
v = edge_to[j];
}
if (j == i)
{
assert (v == edge_to[i]);
break;
}
}
}
assert (Z2 (A.card ()) == Z2 (B.card ()));
return Z2 (A.card ());
}
pair<set<unsigned>,
map<unsigned, unsigned> >
steenrod_square::ladybug_matching (unsigned x, unsigned y) const
{
set<unsigned> Gxy;
map<unsigned, unsigned> lxy;
for (linear_combination_const_iter<Z2> zz = d[y]; zz; zz ++)
{
unsigned z = zz.key ();
if (d[z](x) == 1)
Gxy.push (z);
}
if (Gxy.card () == 2)
{
unsigned z1 = Gxy.head (),
z2 = Gxy.tail ();
assert (z1 != z2);
lxy.push (z1, z2);
lxy.push (z2, z1);
}
else if (Gxy.card () == 4)
{
pair<unsigned, unsigned> x_sm = cor.generator_state_monomial (x),
y_sm = cor.generator_state_monomial (y);
unsigned changed = x_sm.first ^ y_sm.first;
assert (unsigned_bitcount (changed) == 2);
unsigned i = unsigned_ffs (changed),
j = unsigned_ffs (unsigned_bitclear (changed, i));
unsigned s00 = y_sm.first;
unsigned s01 = unsigned_bitset (s00, i);
unsigned s10 = unsigned_bitset (s00, j);
smoothing from_s (cor.kd, smallbitset (cor.n_crossings, s00));
basedvector<unsigned, 1> from_circle_edge_rep (from_s.n_circles);
for (unsigned j = 1; j <= cor.kd.num_edges (); j ++)
from_circle_edge_rep[from_s.edge_circle[j]] = j;
unsigned e1 = cor.kd.ept_edge (cor.kd.crossings[i][1]),
e3 = cor.kd.ept_edge (cor.kd.crossings[i][3]);
unsigned p = from_s.edge_circle[e1];
assert (p == from_s.edge_circle[e3]);
assert (unsigned_bittest (y_sm.second, p)); // p+
smoothing conf01 (cor.kd, smallbitset (cor.n_crossings, s01)),
conf10 (cor.kd, smallbitset (cor.n_crossings, s10));
assert (conf01.edge_circle[e1] != conf01.edge_circle[e3]);
assert (conf10.edge_circle[e1] != conf10.edge_circle[e3]);
unsigned m01 = 0,
m10 = 0;
for (unsigned i = 1; i <= from_s.n_circles; i ++)
{
if (unsigned_bittest (y_sm.second, i))
{
m01 = unsigned_bitset (m01, conf01.edge_circle[from_circle_edge_rep[i]]);
m10 = unsigned_bitset (m10, conf10.edge_circle[from_circle_edge_rep[i]]);
}
}
unsigned m01_a = unsigned_bitclear (unsigned_bitset (m01,
conf01.edge_circle[e1]),
conf01.edge_circle[e3]),
m10_a = unsigned_bitclear (unsigned_bitset (m10,
conf10.edge_circle[e1]),
conf10.edge_circle[e3]);
unsigned z01_a = cor.generator (s01, m01_a),
z10_a = cor.generator (s10, m10_a);
assert (Gxy(z01_a) && Gxy(z10_a));
lxy.push (z01_a, z10_a);
lxy.push (z10_a, z01_a);
unsigned m01_b = unsigned_bitclear (unsigned_bitset (m01,
conf01.edge_circle[e3]),
conf01.edge_circle[e1]),
m10_b = unsigned_bitclear (unsigned_bitset (m10,
conf10.edge_circle[e3]),
conf10.edge_circle[e1]);
unsigned z01_b = cor.generator (s01, m01_b),
z10_b = cor.generator (s10, m10_b);
assert (Gxy(z01_b) && Gxy(z10_b));
lxy.push (z01_b, z10_b);
lxy.push (z10_b, z01_b);
}
else
assert (Gxy.card () == 0);
assert (Gxy.card () == lxy.card ());
return pair<set<unsigned>, map<unsigned, unsigned> > (Gxy, lxy);
}
Z2
steenrod_square::sq2_coeff (grading cgr,
linear_combination<Z2> c,
unsigned x) const
{
set<pair<unsigned, unsigned> > G2cx = make_G2cx (cgr, c, x);
graph G (G2cx);
set<unsigned> ys;
for (unsigned i = 1; i <= G.n_vertices; i ++)
ys += G.y[i];
for (set_const_iter<unsigned> yy = ys; yy; yy ++)
{
unsigned y = yy.val ();
pair<set<unsigned>,
map<unsigned, unsigned> > p = ladybug_matching (x, y);
set<unsigned> Gxy = p.first;
map<unsigned, unsigned> lxy = p.second;
for (set_const_iter<unsigned> zz = Gxy; zz; zz ++)
{
unsigned z = zz.val ();
unsigned lxyz = lxy(z);
if (z < lxyz)
{
G.add_edge (z, y,
lxyz, y,
fC (x, y), 0);
}
}
}
set<unsigned> zs;
for (unsigned i = 1; i <= G.n_vertices; i ++)
zs += G.z[i];
for (set_const_iter<unsigned> zz = zs; zz; zz ++)
{
unsigned z = zz.val ();
triple<set<unsigned>,
map<unsigned, unsigned>,
map<unsigned, Z2> > t = boundary_matching (cgr, c, z);
set<unsigned> Gcz = t.first;
map<unsigned, unsigned> bz = t.second;
map<unsigned, Z2> sz = t.third;
for (set_const_iter<unsigned> yy = Gcz; yy; yy ++)
{
unsigned y = yy.val ();
unsigned bzy = bz(y);
if (y < bzy)
{
if (sz(y) == 0
&& sz(bzy) == 1)
{
G.add_edge (z, y,
z, bzy,
0, 1);
}
else if (sz(y) == 1
&& sz(bzy) == 0)
{
G.add_edge (z, bzy,
z, y,
0, 1);
}
else
{
assert (sz(y) == sz(bzy));
G.add_edge (z, y,
z, bzy,
0, 0);
}
}
}
}
#ifndef NDEBUG
for (unsigned i = 1; i <= G.n_edges; i ++)
{
assert (G.incident_edges[i].card () == 2);
}
#endif
// printf ("G.n_edges = %d\n", G.n_edges);
// printf ("#|G| = %d\n", G.num_components ());
return (Z2 (G.num_components ())
+ G.f ()
+ G.g ());
}
mod_map<Z2>
steenrod_square::sq2 () const
{
map_builder<Z2> b (s.new_C);
for (unsigned i = 1; i <= s.new_C->dim (); i ++)
{
grading cgr = s.new_C->generator_grading (i);
linear_combination<Z2> c = s.iota[i];
assert (d.map (c) == 0);
grading gr2 (cgr.h + 2, cgr.q);
if (! (KGij % gr2))
continue;
linear_combination<Z2> sq2c (cor.khC);
for (set_const_iter<unsigned> x = KGij[gr2]; x; x ++)
sq2c.muladd (sq2_coeff (cgr, c, x.val ()), x.val ());
// display ("sq2c:\n", sq2c);
assert (d.map (sq2c) == 0);
b[i].muladd (1, s.pi.map (sq2c));
}
return mod_map<Z2> (b);
}

42
steenrod_square.h Normal file
View File

@ -0,0 +1,42 @@
class steenrod_square
{
// cube of resolutions (in steenrod_square, c will denote a cycle)
const cube<Z2> &cor;
mod_map<Z2> d;
const chain_complex_simplifier<Z2> &s;
map<grading, set<unsigned> > KGij;
// sC, fC take generators as input, not hypercube vertices
Z2 sC (unsigned x, unsigned y) const;
Z2 fC (unsigned x, unsigned y) const;
pair<set<unsigned>, // Gxy
map<unsigned, unsigned> // lxy
> ladybug_matching (unsigned x, unsigned y) const;
triple<set<unsigned>, // Gcx
map<unsigned, unsigned>, // bx
map<unsigned, Z2> // sx
> boundary_matching (grading cgr,
linear_combination<Z2> c,
unsigned x) const;
set<pair<unsigned, unsigned> > make_G2cx (grading cgr,
linear_combination<Z2> c,
unsigned x) const;
Z2 sq2_coeff (grading cgr,
linear_combination<Z2> c,
unsigned x) const;
public:
steenrod_square (const cube<Z2> &cor_,
mod_map<Z2> &d_,
const chain_complex_simplifier<Z2> &s_);
~steenrod_square () { }
mod_map<Z2> sq1 () const;
mod_map<Z2> sq2 () const;
};