Added support to compute Sq1 and Sq2 on Kh.
This commit is contained in:
parent
a0e543e4df
commit
8dfa237fc4
6
Makefile
6
Makefile
@ -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
|
||||
|
||||
|
@ -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) { }
|
||||
|
@ -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
4
cube.h
@ -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;
|
||||
|
@ -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);
|
||||
|
23
lib/pair.h
23
lib/pair.h
@ -54,6 +54,7 @@ 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)
|
||||
@ -82,12 +83,10 @@ public:
|
||||
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);
|
||||
}
|
||||
|
272
main.cpp
272
main.cpp
@ -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 ();
|
||||
|
||||
ullmanset<1> empty2;
|
||||
assert (empty == empty2);
|
||||
cube<Z2> c (kd);
|
||||
mod_map<Z2> d = c.compute_d (1, 0, 0, 0, 0);
|
||||
|
||||
ullmanset<1> emptycopy (COPY, empty);
|
||||
assert (emptycopy == empty);
|
||||
chain_complex_simplifier<Z2> s (c.khC, d, 1);
|
||||
|
||||
ullmanset<1> s (50, {1,2,5,5,2,1,3,4});
|
||||
assert (s.card () == 5);
|
||||
steenrod_square sq (c, d, s);
|
||||
mod_map<Z2> sq1 = sq.sq1 ();
|
||||
// display ("sq1:\n", sq1);
|
||||
|
||||
ullmanset<1> scopy (COPY, s);
|
||||
assert (scopy == s);
|
||||
mod_map<Z2> sq2 = sq.sq2 ();
|
||||
if (a)
|
||||
assert (sq2 == 0);
|
||||
else
|
||||
display ("sq2:\n", sq2);
|
||||
|
||||
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 ();
|
||||
assert (d2.compose (d2U1) + d2U1.compose (d2) == 0);
|
||||
|
||||
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);
|
||||
mod_map<R> d2U2 = st.twisted_d2Un (2);
|
||||
assert (d2.compose (d2U2) + d2U2.compose (d2) + d2U1.compose (d2U1) == 0);
|
||||
|
||||
chain_complex_simplifier<fraction_field<polynomial<Z2> > > tt_s (c.C, tt_d, 2);
|
||||
assert (tt_s.new_d == 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);
|
||||
|
||||
cube<Z2> kh_c (kd, 1);
|
||||
mod_map<Z2> kh_d = kh_c.compute_d (1, 0, 0, 0, 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);
|
||||
|
||||
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
248
simplify_chain_complex.h
Normal 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));
|
||||
}
|
@ -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
547
steenrod_square.cpp
Normal 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
42
steenrod_square.h
Normal 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;
|
||||
};
|
Loading…
Reference in New Issue
Block a user