ad0f60f5c0
lsss, leess, sq2, s) to prepare for release of the link splitting spectral sequence paper on the arXiv.
521 lines
11 KiB
C++
521 lines
11 KiB
C++
|
|
#include <knotkit.h>
|
|
|
|
sseq_page::sseq_page (const sseq_bounds &b)
|
|
: k(0),
|
|
rank(b.width ()),
|
|
im_rank(b.width ())
|
|
{
|
|
for (unsigned i = 0; i < b.width (); i ++)
|
|
{
|
|
vector<unsigned> r (b.height ()),
|
|
im_r (b.height ());
|
|
for (unsigned j = 0; j < b.height (); j ++)
|
|
r[j] = im_r[j] = 0;
|
|
|
|
rank[i] = r;
|
|
im_rank[i] = im_r;
|
|
}
|
|
}
|
|
|
|
void
|
|
sseq_page::addeq (const sseq_bounds &b, const sseq_bounds &b2, const sseq_page &pg2)
|
|
{
|
|
for (unsigned i = 0; i < b2.width (); i ++)
|
|
{
|
|
for (unsigned j = 0; j < b2.height (); j ++)
|
|
{
|
|
rank[i + b2.minh - b.minh][j + b2.minq - b.minq]
|
|
+= pg2.rank[i][j];
|
|
im_rank[i + b2.minh - b.minh][j + b2.minq - b.minq]
|
|
+= pg2.im_rank[i][j];
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
sseq_page::otimes_addeq (const sseq_bounds &b,
|
|
const sseq_bounds &b1, const sseq_page &pg1,
|
|
const sseq_bounds &b2, const sseq_page &pg2)
|
|
{
|
|
for (int i1 = b1.minh; i1 <= b1.maxh; i1 ++)
|
|
for (int j1 = b1.minq; j1 <= b1.maxq; j1 ++)
|
|
{
|
|
for (int i2 = b2.minh; i2 <= b2.maxh; i2 ++)
|
|
for (int j2 = b2.minq; j2 <= b2.maxq; j2 ++)
|
|
{
|
|
unsigned n1 = pg1.rank[i1 - b1.minh][j1 - b1.minq],
|
|
n2 = pg2.rank[i2 - b2.minh][j2 - b2.minq];
|
|
unsigned k1 = pg1.im_rank[i1 - b1.minh][j1 - b1.minq],
|
|
k2 = pg2.im_rank[i2 - b2.minh][j2 - b2.minq];
|
|
|
|
rank[i1 + i2 - b.minh][j1 + j2 + 1 - b.minq]
|
|
+= n1 * n2;
|
|
im_rank[i1 + i2 - b.minh][j1 + j2 + 1 - b.minq]
|
|
+= n1*k2 + n2*k1 - k1*k2;
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned
|
|
sseq_page::total_rank () const
|
|
{
|
|
unsigned r = 0;
|
|
for (unsigned i = 0; i < rank.size (); i ++)
|
|
{
|
|
for (unsigned j = 0; j < rank[i].size (); j ++)
|
|
r += rank[i][j];
|
|
}
|
|
return r;
|
|
}
|
|
|
|
unsigned
|
|
sseq_page::homological_width (const sseq_bounds &b) const
|
|
{
|
|
int mind = 0, maxd = 0;
|
|
bool first = 1;
|
|
|
|
for (int i = b.minh; i <= b.maxh; i ++)
|
|
for (int j = b.minq; j <= b.maxq; j ++)
|
|
{
|
|
if (rank[i - b.minh][j - b.minq] > 0)
|
|
{
|
|
int d = j - 2*i;
|
|
if (first)
|
|
{
|
|
first = 0;
|
|
mind = maxd = d;
|
|
}
|
|
else
|
|
{
|
|
if (d < mind)
|
|
mind = d;
|
|
if (d > maxd)
|
|
maxd = d;
|
|
}
|
|
}
|
|
}
|
|
if (first)
|
|
return 0;
|
|
else
|
|
{
|
|
assert (maxd >= mind);
|
|
return maxd - mind + 1;
|
|
}
|
|
}
|
|
|
|
multivariate_laurentpoly<Z>
|
|
sseq_page::poincare_polynomial (const sseq_bounds &b) const
|
|
{
|
|
multivariate_laurentpoly<Z> r;
|
|
for (int i = b.minh; i <= b.maxh; i ++)
|
|
{
|
|
for (int j = b.minq; j <= b.maxq; j ++)
|
|
{
|
|
unsigned c = rank[i - b.minh][j - b.minq];
|
|
if (c)
|
|
{
|
|
multivariate_laurent_monomial m;
|
|
m.push_exponent (1, i);
|
|
m.push_exponent (2, j);
|
|
r.muladdeq (c, m);
|
|
}
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
multivariate_laurentpoly<Z>
|
|
sseq_page::delta_poincare_polynomial (const sseq_bounds &b) const
|
|
{
|
|
multivariate_laurentpoly<Z> r;
|
|
for (int i = b.minh; i <= b.maxh; i ++)
|
|
{
|
|
for (int j = b.minq; j <= b.maxq; j ++)
|
|
{
|
|
unsigned c = rank[i - b.minh][j - b.minq];
|
|
if (c)
|
|
r.muladdeq (c, multivariate_laurent_monomial (VARIABLE, 1, j - 2*i));
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
sseq
|
|
sseq::operator + (const sseq &ss2) const
|
|
{
|
|
sseq_bounds b (std::min (bounds.minh, ss2.bounds.minh),
|
|
std::max (bounds.maxh, ss2.bounds.maxh),
|
|
std::min (bounds.minq, ss2.bounds.minq),
|
|
std::max (bounds.maxq, ss2.bounds.maxq));
|
|
sseq r (b);
|
|
|
|
unsigned n = std::max (pages.size (),
|
|
ss2.pages.size ());
|
|
for (unsigned i = 1; i <= n; i ++)
|
|
{
|
|
sseq_page pg (b);
|
|
if (i <= pages.size ())
|
|
pg.addeq (b, bounds, pages[i]);
|
|
if (i <= ss2.pages.size ())
|
|
pg.addeq (b, ss2.bounds, ss2.pages[i]);
|
|
r.pages.append (pg);
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
sseq
|
|
sseq::otimes (const sseq &ss2) const
|
|
{
|
|
sseq_bounds b (bounds.minh + ss2.bounds.minh,
|
|
bounds.maxh + ss2.bounds.maxh,
|
|
bounds.minq + ss2.bounds.minq + 1,
|
|
bounds.maxq + ss2.bounds.maxq + 1);
|
|
sseq r (b);
|
|
|
|
unsigned n1 = pages.size (),
|
|
n2 = ss2.pages.size ();
|
|
|
|
unsigned n = std::max (n1, n2);
|
|
for (unsigned i = 1; i <= n; i ++)
|
|
{
|
|
sseq_page pg (b);
|
|
pg.otimes_addeq (b,
|
|
bounds, pages[std::min (i, n1)],
|
|
ss2.bounds, ss2.pages[std::min (i, n2)]);
|
|
r.pages.append (pg);
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
sseq
|
|
sseq::shift (int dh, int dq) const
|
|
{
|
|
return sseq (sseq_bounds (bounds.minh + dh,
|
|
bounds.maxh + dh,
|
|
bounds.minq + dq,
|
|
bounds.maxq + dq),
|
|
pages);
|
|
}
|
|
|
|
void
|
|
sseq_builder::cancel (unsigned d)
|
|
{
|
|
unsigned n = C->dim ();
|
|
|
|
unsigned step = n / 8;
|
|
if (verbose
|
|
&& d == 1
|
|
&& step)
|
|
{
|
|
fprintf (stderr, "cancelling generators...\n");
|
|
fprintf (stderr, "%d generators.\n", n);
|
|
}
|
|
|
|
for (unsigned i = n; i >= 1; i --)
|
|
{
|
|
if (! (present % i))
|
|
continue;
|
|
|
|
if (verbose
|
|
&& d == 1
|
|
&& step
|
|
&& ((n - i) % step) == 0)
|
|
{
|
|
fprintf (stderr, "%d / %d generators cancelled.\n", (n - i), n);
|
|
}
|
|
|
|
grading igr = C->generator_grading (i);
|
|
for (set_const_iter<unsigned> j = im[i]; j; j ++)
|
|
{
|
|
grading jgr = C->generator_grading (j.val ());
|
|
assert (jgr.h > igr.h);
|
|
if ((unsigned)(jgr.h - igr.h) == d)
|
|
{
|
|
cancel (i, j.val ());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (verbose
|
|
&& d == 1
|
|
&& step
|
|
&& (n % step) != 0)
|
|
{
|
|
fprintf (stderr, "%d / %d generators cancelled.\n", n, n);
|
|
}
|
|
if (verbose
|
|
&& d == 1
|
|
&& step)
|
|
{
|
|
fprintf (stderr, "cancelling generators done.\n");
|
|
}
|
|
|
|
#if 0
|
|
unsigned m = present.card ();
|
|
|
|
basedvector<unsigned, 1> pri (m),
|
|
nth (m);
|
|
for (ullmanset<1>::const_iter ii = present; ii; ii ++)
|
|
{
|
|
unsigned i = ii.val ();
|
|
grading igr = C->generator_grading (i);
|
|
|
|
unsigned max_pri = 0;
|
|
for (set_const_iter<unsigned> j = im[i]; j; j ++)
|
|
{
|
|
grading jgr = C->generator_grading (j.val ());
|
|
assert (jgr.h > igr.h);
|
|
if ((unsigned)(jgr.h - igr.h) == d)
|
|
{
|
|
unsigned p = 100000000 - (im[i].card () - 1) * (preim[j.val ()].card () - 1);
|
|
if (p > max_pri)
|
|
max_pri = p;
|
|
}
|
|
}
|
|
|
|
unsigned p = ii.pos () + 1;
|
|
pri[p] = max_pri;
|
|
nth[p] = i;
|
|
}
|
|
priority_queue q (m, pri);
|
|
for (unsigned i = 1; i <= m; i ++)
|
|
q.push (i);
|
|
while (!q.is_empty ())
|
|
{
|
|
unsigned p = q.pop ();
|
|
unsigned i = nth[p];
|
|
|
|
grading igr = C->generator_grading (i);
|
|
|
|
unsigned max_pri = 0,
|
|
maxj = 0;
|
|
for (set_const_iter<unsigned> j = im[i]; j; j ++)
|
|
{
|
|
grading jgr = C->generator_grading (j.val ());
|
|
assert (jgr.h > igr.h);
|
|
if ((unsigned)(jgr.h - igr.h) == d)
|
|
{
|
|
unsigned p = 100000000 - (im[i].card () - 1) * (preim[j.val ()].card () - 1);
|
|
if (p > max_pri)
|
|
{
|
|
max_pri = p;
|
|
maxj = j.val ();
|
|
}
|
|
}
|
|
}
|
|
if (maxj)
|
|
cancel (i, maxj);
|
|
}
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
for (ullmanset<1>::const_iter ii = present; ii; ii ++)
|
|
{
|
|
unsigned i = ii.val ();
|
|
grading igr = C->generator_grading (i);
|
|
for (set_const_iter<unsigned> j = im[i]; j; j ++)
|
|
{
|
|
grading jgr = C->generator_grading (j.val ());
|
|
assert (jgr.h > igr.h);
|
|
assert ((unsigned)(jgr.h - igr.h) > d);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void
|
|
sseq_builder::cancel (unsigned i, unsigned j)
|
|
{
|
|
assert (i != j);
|
|
|
|
present.yank (i);
|
|
present.yank (j);
|
|
|
|
im[i].yank (j);
|
|
preim[j].yank (i);
|
|
|
|
for (set_const_iter<unsigned> k = im[i]; k; k ++)
|
|
preim[k.val ()].yank (i);
|
|
for (set_const_iter<unsigned> k = preim[i]; k; k ++)
|
|
im[k.val ()].yank (i);
|
|
for (set_const_iter<unsigned> k = im[j]; k; k ++)
|
|
preim[k.val ()].yank (j);
|
|
for (set_const_iter<unsigned> k = preim[j]; k; k ++)
|
|
im[k.val ()].yank (j);
|
|
|
|
for (set_const_iter<unsigned> kk = preim[j]; kk; kk ++)
|
|
{
|
|
for (set_const_iter<unsigned> ll = im[i]; ll; ll ++)
|
|
{
|
|
unsigned k = kk.val (),
|
|
ell = ll.val ();
|
|
|
|
assert (present % k);
|
|
assert (present % ell);
|
|
assert (k != i);
|
|
assert (k != j);
|
|
assert (ell != i);
|
|
assert (ell != j);
|
|
assert (ell != k);
|
|
|
|
if (im[k].toggle (ell))
|
|
preim[ell].yank (k);
|
|
else
|
|
preim[ell].push (k);
|
|
}
|
|
}
|
|
|
|
im[i].clear ();
|
|
preim[i].clear ();
|
|
im[j].clear ();
|
|
preim[j].clear ();
|
|
}
|
|
|
|
sseq_builder::linear_combination
|
|
sseq_builder::lc (const set<unsigned> &s)
|
|
{
|
|
linear_combination r;
|
|
for (set<unsigned>::const_iter i = s; i; i ++)
|
|
r.muladd (1, i.val ());
|
|
return r;
|
|
}
|
|
|
|
bool
|
|
sseq_builder::im_zero ()
|
|
{
|
|
for (ullmanset<1>::const_iter i = present; i; i ++)
|
|
{
|
|
if (!im[i.val ()].is_empty ())
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
sseq_builder::sseq_builder (const ptr<const module<Z2> > &C_,
|
|
const mod_map<Z2> &d)
|
|
: C(C_), present(C->dim ()), im(C->dim ()), preim(C->dim ())
|
|
{
|
|
unsigned n = C->dim ();
|
|
|
|
for (unsigned i = 1; i <= n; i ++)
|
|
present.push (i);
|
|
|
|
for (unsigned i = 1; i <= n; i ++)
|
|
{
|
|
for (linear_combination_const_iter j = d[i]; j; j ++)
|
|
{
|
|
im[i].push (j.key ());
|
|
preim[j.key ()].push (i);
|
|
}
|
|
}
|
|
}
|
|
|
|
sseq
|
|
sseq_builder::build_sseq ()
|
|
{
|
|
if (verbose)
|
|
{
|
|
fprintf (stderr, "computing spectral sequence...\n");
|
|
fprintf (stderr, "computing E^1...\n");
|
|
}
|
|
|
|
unsigned dh = 1;
|
|
cancel (dh);
|
|
dh ++;
|
|
|
|
if (verbose)
|
|
fprintf (stderr, "computing E^1 done.\n");
|
|
|
|
unsigned i0 = present.head ();
|
|
grading i0gr = C->generator_grading (i0);
|
|
int minh = i0gr.h,
|
|
maxh = i0gr.h,
|
|
minq = i0gr.q,
|
|
maxq = i0gr.q;
|
|
for (ullmanset<1>::const_iter i = present; i; i ++)
|
|
{
|
|
grading igr = C->generator_grading (i.val ());
|
|
if (igr.h < minh)
|
|
minh = igr.h;
|
|
if (igr.h > maxh)
|
|
maxh = igr.h;
|
|
if (igr.q < minq)
|
|
minq = igr.q;
|
|
if (igr.q > maxq)
|
|
maxq = igr.q;
|
|
}
|
|
sseq_bounds b (minh, maxh, minq, maxq);
|
|
sseq r (b);
|
|
|
|
#if 0
|
|
printf ("minh=%d, maxh=%d, minq=%d, maxq=%d\n",
|
|
minh, maxh, minq, maxq);
|
|
#endif
|
|
|
|
for (;;)
|
|
{
|
|
if (verbose)
|
|
fprintf (stderr, "computing E^%d...\n", dh);
|
|
|
|
sseq_page pg (b);
|
|
|
|
basedvector<linear_combination, 1> span;
|
|
for (ullmanset<1>::const_iter i = present; i; i ++)
|
|
{
|
|
grading igr = C->generator_grading (i.val ());
|
|
|
|
#if 0
|
|
printf ("i=%d, igr.h=%d, igr.q=%d\n",
|
|
i.val (), igr.h, igr.q);
|
|
#endif
|
|
|
|
pg.rank[igr.h - minh][igr.q - minq] ++;
|
|
|
|
linear_combination v (C);
|
|
for (set<unsigned>::const_iter j = im[i.val ()]; j; j ++)
|
|
{
|
|
grading jgr = C->generator_grading (j.val ());
|
|
|
|
if (jgr.h - igr.h == (int)dh)
|
|
{
|
|
assert ((jgr.h - igr.h - 1) * 2 == (jgr.q - igr.q));
|
|
|
|
v.muladd (1, j.val ());
|
|
}
|
|
}
|
|
span.append (v);
|
|
}
|
|
|
|
unsigned dq = (dh - 1) * 2;
|
|
|
|
mod_span<Z2> span2 (C, span);
|
|
ptr<const module<Z2> > im2 = C->submodule (span2);
|
|
|
|
for (unsigned i = 1; i <= im2->dim (); i ++)
|
|
{
|
|
grading igr = im2->generator_grading (i);
|
|
pg.im_rank[igr.h - dh - minh][igr.q - dq - minq] ++;
|
|
}
|
|
|
|
r.pages.append (pg);
|
|
|
|
if (verbose)
|
|
fprintf (stderr, "computing E^%d done.\n", dh);
|
|
|
|
if (im_zero ())
|
|
break;
|
|
|
|
cancel (dh);
|
|
dh ++;
|
|
}
|
|
|
|
if (verbose)
|
|
fprintf (stderr, "computing spectral sequence done.\n");
|
|
|
|
return r;
|
|
}
|