Merge branch 'master' of github.com:cseed/knotkit

Conflicts:
	knot_tables.cpp
This commit is contained in:
Joshua Batson 2013-10-18 12:46:25 -04:00
commit b51dbfe2a0
62 changed files with 8972 additions and 1693 deletions

5
.gitignore vendored
View File

@ -1,8 +1,9 @@
*~
*.o
/gss
/kk
/main
/testsurfaces
/serial.cmd*
/serial.cmd.[eo]*
/parallel.cmd.[eo]*
/save
*/save

View File

@ -1,24 +1,28 @@
BISON = /opt/local/bin/bison
FLEX = /opt/local/bin/flex
devel = 0
CXX = g++
BISON = bison
FLEX = flex
INCLUDES = -I/opt/local/include -I.
# CXX = g++
# CXX = OMPI_CXX=clang++ mpic++ -fno-color-diagnostics --stdlib=libc++ --std=c++11 -I/u/cseed/llvm-3.1/lib/c++/v1
CXX = clang++ -fno-color-diagnostics --stdlib=libc++ --std=c++11
INCLUDES = -I. -I/opt/local/include
# OPTFLAGS = -g
OPTFLAGS = -O2 -g
# OPTFLAGS = -O2 -DNDEBUG
LDFLAGS = -L/opt/local/lib
# LDFLAGS = -pg -L/opt/local/lib
CXXFLAGS = $(OPTFLAGS) -Wall -Wno-unused $(INCLUDES)
CXXFLAGS = $(OPTFLAGS) -DHOME="\"`pwd`\"" -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
@ -26,7 +30,8 @@ KNOTKIT_OBJS = planar_diagram.o dt_code.o knot_diagram.o cube.o spanning_tree_co
COMMON_OBJS = $(KNOTKIT_OBJS) $(ALGEBRA_OBJS) $(LIB_OBJS)
LIB_HEADERS = lib/lib.h lib/show.h lib/refcount.h lib/pair.h lib/maybe.h lib/vector.h \
lib/set.h lib/ullmanset.h lib/bitset.h lib/smallbitset.h lib/setcommon.h \
lib/set_wrapper.h lib/set.h lib/hashset.h \
lib/ullmanset.h lib/bitset.h lib/smallbitset.h lib/setcommon.h \
lib/map_wrapper.h lib/map.h lib/hashmap.h lib/ullmanmap.h lib/mapcommon.h \
lib/unionfind.h lib/priority_queue.h lib/io.h \
lib/directed_multigraph.h
@ -36,11 +41,12 @@ 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
LIBS = -lgmp -lz
all: gss
all: kk
%.o : %.cc
$(CXX) -c $(CXXFLAGS) $< -o $@
@ -48,15 +54,19 @@ all: gss
%.o : %.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@
gss: gss.o $(COMMON_OBJS)
$(CXX) $(LDFLAGS) -o gss $^ $(LIBS)
kk: kk.o $(COMMON_OBJS)
$(CXX) $(LDFLAGS) -o kk $^ $(LIBS)
main: main.o $(COMMON_OBJS)
$(CXX) $(LDFLAGS) -o main $^ $(LIBS)
mpimain: mpimain.o mpi_aux.o $(COMMON_OBJS)
$(CXX) $(LDFLAGS) -o mpimain $^ $(LIBS)
testlib: testlib.o $(COMMON_OBJS)
$(CXX) $(LDFLAGS) -o testlib $^
ifeq ($(devel),1)
knot_parser/knot_parser.cc knot_parser/knot_parser.hh: knot_parser/knot_parser.yy
$(BISON) knot_parser/knot_parser.yy -o knot_parser/knot_parser.cc
@ -74,6 +84,7 @@ rd_parser/rd_parser.cc rd_parser/rd_parser.hh: rd_parser/rd_parser.yy
rd_parser/rd_scanner.cc: rd_parser/rd_scanner.ll
$(FLEX) -o rd_parser/rd_scanner.cc rd_parser/rd_scanner.ll
endif
.PHONY: parser_files
parser_files: \
@ -87,7 +98,7 @@ parser_files: \
.PHONY: clean
clean:
rm -f *.o lib/*.o algebra/*.o knot_parser/*.o rd_parser/*.o
rm -f main gss
rm -f main kk mpimain
rm -f gmon.out
.PHONY: realclean
@ -104,4 +115,6 @@ realclean: clean
$(LIB_OBJS): $(LIB_HEADERS)
$(ALGEBRA_OBJS): $(ALGEBRA_HEADERS) $(LIB_HEADERS)
$(KNOTKIT_OBJS) main.o gss.o: $(KNOTKIT_HEADERS) $(ALGEBRA_HEADERS) $(LIB_HEADERS)
$(KNOTKIT_OBJS) main.o mpimain.o kk.o: $(KNOTKIT_HEADERS) $(ALGEBRA_HEADERS) $(LIB_HEADERS)
mpimain.o mpi_aux.o: mpi_aux.h

163
README
View File

@ -1 +1,162 @@
I modified cotton's readme.
knotkit is a C++ software package written by Cotton Seed
(cseed@math.princeton.edu) for computing some knot and manifold
invariants appearing in low-dimensional topology. Other contributors
include Josh Batson.
TABLE OF CONTENTS
1. INTRO
2. BUILDING
3. USAGE
4. UPCOMING CHANGES
5. FOR DEVELOPERS
1. INTRO
In addition to accepting knot presentations in a variety of formats
(see usage below), knotkit contains the following tables of knot data:
* The Rolfsen knot tables through 10 crossings, extracted from
Bar-Natan's Mathematica package, KnotTheory`,
* The Hoste-Weeks-Thistlewaite knot tables through 16 crossings taken
from knotscape, and
* and the Morwen Thistlewaite hyperbolic link tables taken from
SnapPy.
This version of knotkit has support to compute the following
invariants:
* Khovanov homology
See:
M. Khovanov, A Categorification of the Jones Polynomial, Duke
Math. J. 101 (2000), 359--426, arXiv:math/9908171.
D. Bar-Natan, On Khovanov's Categorification of the Jones Polynomial,
Algebraic and Geometric Topology 2 (2002), 337--370.
* Szabo's geometric spectral sequence
Computing gss was the original motivation for writing knotkit. For
more information on gss, see:
Z. Szabo, A geometric spectral sequence in Khovanov homology,
arXiv:1010.4252, and
C. Seed, Computations of Szabo's Geometric Spectral Sequence in Khovanov
Homology, arXiv:1110.0735.
* The Batson-Seed link splitting spectral sequence
See:
J. Batson, C. Seed, A Link Splitting Spectral Sequence in Khovanov
Homology.
* The Lipshitz-Sarkar Steenrod square on Khovanov homology
See:
R. Lipshitz, S. Sarkar, A Khovanov Homotopy Type, arXiv:1112.3932.
R. Lipshitz, S. Sarkar, A Steenrod Square on Khovanov Homology,
arXiv:1204.5776.
* Bar-Natan's analogue of Lee homology
See:
E. S. Lee, An endomorphism of the Khovanov invariant, Adv. Math. 197
(2005), 2, 554586, arXiv:math/0210213.
D. Bar-Natan, Khovanovs homology for tangles and cobordisms,
Geom. Topol. 9 (2005), 14431499, arXiv:math/0410495.
R. Lipshitz, S. Sarkar, A refinement of Rasmussen's s-invariant,
arXiv:1206.3532.
* The s-invariant coming from Bar-Natan's analogue of Lee homology
In addition to the above references, see:
J. Rasmussen, Khovanov homology and the slice genus, Invent.
Math. 182 2 (2010), 419--447, arXiv:math/0402131.
R. Lipshitz, S. Sarkar, A refinement of Rasmussen's s-invariant,
arXiv:1206.3532.
2. BUILDING
To build knotkit on OS X, you will need the latest version of XCode
(available for free in the App Store) and the GNU multiple precision
arithmetic library (GMP). You can get GMP here:
http://gmplib.org/
knotkit also builds under Linux. In addition to GMP, you will need a
C++ compiler which supports C++11. I use LLVM clang, but knotkit
should build with a recent version of GCC.
knotkit doesn't have a sophisticated build system. To build knotkit,
just run:
make
from the knotkit source directory. This should build the executable
"kk". For instructions on invoking kk, see usage below. If you run
into a problem, please contact me: Cotton Seed
(cotton@math.princeton.edu).
3. USAGE
The usage message for kk is given below. This can also be obtained by
running "kk -h".
A note about output. The output for commands kh, gss, ls and lee is a
.tex file which renders the bigraded homology group or spectral
sequence. The output for the command sq2 matches the output for the
program written by Lipshitz-Sarkar and is suitable for loading into
Sage. The command s outputs a single line of text.
usage: kk <invariant> [options...] <link>
compute <invariant> for knot or link <link>
<invariant> can be one of:
kh: Khovanov homology
gss: Szabo's geometric spectral sequence
lsss: Batson-Seed link splitting spectral sequence
component weights are 0, 1, ..., m
sq2: Lipshitz-Sarkar Steenrod square on Z/2 Kh
output suitable for Sage
leess: spectral sequence coming from Bar-Natan analogue of Lee's
deformation of Khovanov's complex (whew!)
s: Rasmussen's s-invariant coming from lee
output:
kh, gss, lsss, leess: .tex file
sq2: text in Sage format
s: text
options:
-r : compute reduced theory
-h : print this message
-o <file> : write output to <file>
(stdout is the default)
-f <field> : ground field (if applicable)
(Z2 is the default)
-v : verbose: report progress as the computation proceeds
<field> can be one of:
Z2, Z3, Q
<link> can be one of:
- the unknot, e.g. U or unknot
- a torus knot, e.g. T(2,3)
- a Rolfsen table knot, e.g. 10_124
- a Hoste-Thistlethwaite-Weeks knot, e.g. 11a12 or 12n214
- a Morwen Thistlethwaite link, e.g. L8n9 or L13n8862
- a planar diagram, e.g.
PD[X[1, 4, 2, 5], X[3, 6, 4, 1], X[5, 2, 6, 3]] or
PD[[1, 4, 2, 5], [3, 6, 4, 1], [5, 2, 6, 3]]
- a Dowker-Thistlethwaite code, e.g.
DTCode[6,8,2,4],
DT[dadbcda] or
DT[{6, -8}, {-10, 12, -14, 2, -4}]
- a braid, e.g. BR[2, {-1, -1, -1}]
- disjoint union (juxtaposition), e.g. T(2,3) U
4. UPCOMING CHANGES
The following changes are currently planned:
* support for Z/p, p arbitrary prime and F(x) field of rational functions
* Roberts' totally twisted Khovanov homology
* the E^3 page of the twisted spectral sequence Kh(L) => \widehat{HF}(\Sigma_L)
* spectral sequences of PIDs: lsss over F[x], gss over Z
* maps induced by cobordisms
5. FOR DEVELOPERS
If you are interested in contributing to knotkit or using it for a new
application, please contact me: Cotton Seed
(cotton@math.princeton.edu). I am interested in developing knotkit to
be an open platform for performing computations arising in
low-dimensional topology.

View File

@ -31,16 +31,16 @@ class Q
Q_impl (reader &r)
{
mpq_init (x);
mpz_inp_raw (mpq_numref (x), r.fp);
mpz_inp_raw (mpq_denref (x), r.fp);
r.read_mpz (mpq_numref (x));
r.read_mpz (mpq_denref (x));
}
~Q_impl () { mpq_clear (x); }
void write_self (writer &w) const
{
mpz_out_raw (w.fp, mpq_numref (x));
mpz_out_raw (w.fp, mpq_denref (x));
w.write_mpz (mpq_numref (x));
w.write_mpz (mpq_denref (x));
}
};
@ -163,12 +163,12 @@ class Q
Q div (const Q &d) const { return operator / (d); }
triple<Q, Q, Q> extended_gcd (const Q &q) const
tuple<Q, Q, Q> extended_gcd (const Q &q) const
{
if (*this != 0)
return triple<Q, Q, Q> (*this, 1, 0);
return tuple<Q, Q, Q> (*this, 1, 0);
else
return triple<Q, Q, Q> (q, 0, 1);
return tuple<Q, Q, Q> (q, 0, 1);
}
Q gcd (const Q &q) const

View File

@ -21,14 +21,14 @@ class Z
Z_impl (reader &r)
{
mpz_init (x);
mpz_inp_raw (x, r.fp);
r.read_mpz (x);
}
~Z_impl () { mpz_clear (x); }
void write_self (writer &w) const
{
mpz_out_raw (w.fp, x);
w.write_mpz (x);
}
};
@ -48,6 +48,7 @@ class Z
Z &operator = (int x) { impl = new Z_impl (x); return *this; }
bool operator == (const Z &z) const { return mpz_cmp (impl->x, z.impl->x) == 0; }
bool operator != (const Z &z) const { return !operator == (z); }
bool operator == (int y) const { return mpz_cmp_si (impl->x, y) == 0; }
bool operator != (int y) const { return !operator == (y); }
@ -91,13 +92,13 @@ class Z
return Z (STEAL, x);
}
Z operator / (const Z &z) const
Z operator / (const Z &denom) const
{
if (mpz_cmp_si (z.impl->x, 1) == 0)
if (mpz_cmp_si (denom.impl->x, 1) == 0)
return *this;
else
{
assert (mpz_cmp_si (z.impl->x, -1) == 0);
assert (mpz_cmp_si (denom.impl->x, -1) == 0);
mpz_t x;
mpz_init (x);
@ -112,6 +113,7 @@ class Z
return Z (COPY, *this);
}
// *this += z1*z2
Z &muladdeq (const Z &z1, const Z &z2)
{
mpz_addmul (impl->x, z1.impl->x, z2.impl->x);
@ -148,33 +150,30 @@ class Z
return *this;
}
bool divides (const Z &n) const
bool divides (const Z &num) const
{
// d = *this
return mpz_divisible_p (n.impl->x, impl->x);
return mpz_divisible_p (num.impl->x, impl->x);
}
bool operator | (const Z &num) const { return divides (num); }
bool operator | (const Z &z) const { return divides (z); }
Z div (const Z &d) const
Z divide_exact (const Z &denom) const
{
// n = *this
// num = *this
mpz_t q;
mpz_init (q);
mpz_divexact (q, impl->x, d.impl->x);
mpz_divexact (q, impl->x, denom.impl->x);
return Z (STEAL, q);
}
triple<Z, Z, Z> extended_gcd (const Z &z) const
tuple<Z, Z> divide_with_remainder (const Z &denom) const
{
mpz_t d, s, t;
mpz_init (d);
mpz_init (s);
mpz_init (t);
mpz_gcdext (d, s, t, impl->x, z.impl->x);
return triple<Z, Z, Z> (Z (STEAL, d),
Z (STEAL, s),
Z (STEAL, t));
// *this = num
mpz_t q, r;
mpz_init (q);
mpz_init (r);
mpz_tdiv_qr (q, r, impl->x, denom.impl->x);
return make_tuple (Z (STEAL, q),
Z (STEAL, r));
}
Z gcd (const Z &z) const
@ -191,6 +190,18 @@ class Z
return Z (STEAL, m);
}
tuple<Z, Z, Z> extended_gcd (const Z &z) const
{
mpz_t d, s, t;
mpz_init (d);
mpz_init (s);
mpz_init (t);
mpz_gcdext (d, s, t, impl->x, z.impl->x);
return make_tuple (Z (STEAL, d),
Z (STEAL, s),
Z (STEAL, t));
}
static void show_ring () { printf ("Z"); }
void show_self () const { mpz_out_str (stdout, 10, impl->x); }
void display_self () const { show_self (); newline (); }

View File

@ -11,15 +11,18 @@ 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) { }
Z2 (reader &r) { v = r.read_bool (); }
~Z2 () { }
Z2 &operator = (const Z2 &x) { v = x.v; return *this; }
Z2 &operator = (int x) { v = (bool)(x & 1); return *this; }
bool operator == (const Z2 &x) const { return v == x.v; }
bool operator != (const Z2 &x) const { return v != x.v; }
bool operator == (int x) const { return v == (bool)(x & 1); }
bool operator != (int x) const { return !operator == (x); }
@ -39,6 +42,12 @@ class Z2
Z2 &operator *= (const Z2 &x) { v &= x.v; return *this; }
Z2 &operator /= (const Z2 &x) { assert (x.v); return *this; }
// *this += z1*z2
Z2 &muladdeq (const Z2 &z1, const Z2 &z2)
{
return operator += (z1 * z2);
}
bool divides (Z2 x) const { return v || !x.v; }
bool operator | (const Z2 x) const { return divides (x); }
@ -54,15 +63,16 @@ class Z2
return Z2 (1);
}
triple<Z2, Z2, Z2> extended_gcd (Z2 x) const
tuple<Z2, Z2, Z2> extended_gcd (Z2 x) const
{
if (v)
return triple<Z2, Z2, Z2> (Z2 (1), Z2 (1), Z2 (0));
return make_tuple (Z2 (1), Z2 (1), Z2 (0));
else
return triple<Z2, Z2, Z2> (Z2 (1), Z2 (0), Z2 (1));
return make_tuple (Z2 (1), Z2 (0), Z2 (1));
}
static void show_ring () { printf ("Z2"); }
void write_self (writer &w) const { w.write_bool (v); }
void show_self () const { printf ("%d", (int)v); }
void display_self () const { printf ("%d\n", (int)v); }
};

View File

@ -32,6 +32,7 @@ class Zp
}
bool operator == (const Zp &x) const { return v == x.v; }
bool operator != (const Zp &x) const { return !operator == (x); }
bool operator == (int x) const { return operator == (Zp (x)); }
bool operator != (int x) const { return !operator == (x); }
@ -56,11 +57,11 @@ class Zp
Zp recip () const
{
triple<unsigned, int, int> t = unsigned_extended_gcd (v, p);
assert (t.first == 1);
assert ((int)t.first == t.second*(int)v + t.third*(int)p);
tuple<unsigned, int, int> t = unsigned_extended_gcd (v, p);
assert (get<0> (t) == 1);
assert ((int)get<0> (t) == get<1> (t)*(int)v + get<2> (t)*(int)p);
return Zp (t.second);
return Zp (get<1> (t));
}
Zp &operator += (const Zp &x)
@ -92,12 +93,12 @@ class Zp
Zp div (const Zp &d) const { return operator / (d); }
triple<Zp, Zp, Zp> extended_gcd (const Zp &x) const
tuple<Zp, Zp, Zp> extended_gcd (const Zp &x) const
{
if (v)
return triple<Zp, Zp, Zp> (v, 1, 0);
return make_tuple (v, Zp (1), Zp (0));
else
return triple<Zp, Zp, Zp> (x, 0, 1);
return make_tuple (x, Zp (0), Zp (1));
}
Zp gcd (const Zp &x) const

View File

@ -16,8 +16,8 @@ unsigned_gcd (unsigned a, unsigned b)
unsigned
int_gcd (int a, int b)
{
return unsigned_gcd ((unsigned)std::abs (a),
(unsigned)std::abs (b));
return unsigned_gcd ((unsigned)abs (a),
(unsigned)abs (b));
}
uint64
@ -35,47 +35,47 @@ uint64_gcd (uint64 a, uint64 b)
uint64
int64_gcd (int64 a, int64 b)
{
return uint64_gcd ((uint64)std::abs (a),
(uint64)std::abs (b));
return uint64_gcd ((uint64)abs64 (a),
(uint64)abs64 (b));
}
static triple<unsigned, int, int>
static tuple<unsigned, int, int>
extended_gcd_1 (int a, int b)
{
if (b == 0)
return triple<unsigned, int, int> (a, 1, 0);
return tuple<unsigned, int, int> (a, 1, 0);
unsigned t = a % b;
if (!t)
return triple<unsigned, int, int> (b, 0, 1);
return make_tuple (b, 0, 1);
else
{
triple<unsigned, int, int> s = unsigned_extended_gcd (b, t);
tuple<unsigned, int, int> s = unsigned_extended_gcd (b, t);
unsigned d = s.first;
int x = s.third,
y = s.second - s.third * (a / b);
unsigned d = get<0> (s);
int x = get<2> (s),
y = get<1> (s) - get<2> (s) * (a / b);
assert ((int)d == a*x + b*y);
return triple<unsigned, int, int> (d, x, y);
return make_tuple (d, x, y);
}
}
triple<unsigned, int, int>
tuple<unsigned, int, int>
unsigned_extended_gcd (unsigned a, unsigned b)
{
return extended_gcd_1 ((int)a, (int)b);
}
triple<unsigned, int, int>
tuple<unsigned, int, int>
extended_gcd (int a, int b)
{
triple<unsigned, int, int> t = extended_gcd_1 (std::abs (a),
std::abs (b));
unsigned d = t.first;
int x = t.second,
y = t.third;
tuple<unsigned, int, int> t = extended_gcd_1 (abs (a),
abs (b));
unsigned d = get<0> (t);
int x = get<1> (t),
y = get<2> (t);
if (a < 0)
x *= -1;
if (b < 0)
@ -83,7 +83,7 @@ extended_gcd (int a, int b)
assert ((int)d == a*x + b*y);
return triple<unsigned, int, int> (d, x, y);
return make_tuple (d, x, y);
}
unsigned
@ -100,12 +100,12 @@ uint64_lcm (uint64 a, uint64 b)
unsigned int_lcm (int a, int b)
{
return unsigned_lcm ((unsigned)std::abs (a),
(unsigned)std::abs (b));
return unsigned_lcm ((unsigned)abs (a),
(unsigned)abs (b));
}
uint64 int64_lcm (int64 a, int64 b)
{
return uint64_lcm ((uint64)std::abs (a),
(uint64)std::abs (b));
return uint64_lcm ((uint64)abs64 (a),
(uint64)abs64 (b));
}

View File

@ -1,6 +1,4 @@
#include <gmp.h>
#include <lib/lib.h>
inline int recip (int x)
@ -42,9 +40,9 @@ unsigned int_lcm (int a, int b);
uint64 int64_lcm (int64 a, int64 b);
// (d, x, y) = gcd (a, b) where x*a + y*b = d
triple<unsigned, int, int> extended_gcd (int a, int b);
tuple<unsigned, int, int> extended_gcd (int a, int b);
triple<unsigned, int, int> unsigned_extended_gcd (unsigned a, unsigned b);
tuple<unsigned, int, int> unsigned_extended_gcd (unsigned a, unsigned b);
template<class R> class linear_combination;
template<class R> class linear_combination_const_iter;

View File

@ -36,6 +36,7 @@ template<class T> class fraction_field
fraction_field &operator = (int x) { num = x; denom = 1; return *this; }
bool operator == (const fraction_field &q) const { return num * q.denom == q.num * denom; }
bool operator != (const fraction_field &q) const { return !operator == (q); }
bool operator == (int x) const { return num == denom * T (x); }
bool operator != (int x) const { return !operator == (x); }
@ -66,6 +67,11 @@ template<class T> class fraction_field
return fraction_field (new_num, denom*xe);
}
fraction_field operator - () const
{
return fraction_field (-num, denom);
}
fraction_field operator * (const fraction_field &x) const
{
T d1 = num.gcd (x.denom);
@ -187,12 +193,12 @@ template<class T> class fraction_field
return fraction_field (1);
}
triple<fraction_field, fraction_field, fraction_field> extended_gcd (const fraction_field &x) const
tuple<fraction_field, fraction_field, fraction_field> extended_gcd (const fraction_field &x) const
{
if (*this != 0)
return triple<fraction_field, fraction_field, fraction_field> (*this, 1, 0);
return make_tuple (*this, fraction_field (1), fraction_field (0));
else
return triple<fraction_field, fraction_field, fraction_field> (x, 0, 1);
return make_tuple (x, fraction_field (0), fraction_field (1));
}
static void show_ring () { printf ("fraction_field("); T::show_ring (); printf (")"); }
@ -210,7 +216,6 @@ fraction_field<T>::reduce ()
}
T d = num.gcd (denom);
num = num.divide_exact (d);
denom = denom.divide_exact (d);
}
@ -220,7 +225,6 @@ fraction_field<T>::check ()
{
if (num == 0)
return;
// check denom == 1
// assert (num.gcd (denom) == 1);
}

View File

@ -8,6 +8,12 @@ class grading
grading () : h(0), q(0) { }
grading (int h_, int q_) : h(h_), q(q_) { }
grading (const grading &gr) : h(gr.h), q(gr.q) { }
grading (reader &r)
{
h = r.read_int ();
q = r.read_int ();
}
~grading () { }
grading &operator = (const grading &gr) { h = gr.h; q = gr.q; return *this; }
@ -36,6 +42,8 @@ class grading
}
bool operator == (const grading &gr) const { return h == gr.h && q == gr.q; }
bool operator != (const grading &gr) const { return !operator == (gr); }
bool operator < (const grading &gr) const
{
return h < gr.h
@ -43,7 +51,13 @@ class grading
}
grading mirror_grading (unsigned nplus, unsigned nminus, bool torsion) const;
void write_self (writer &w) const
{
w.write_int (h);
w.write_int (q);
}
void show_self () const;
void display_self () const;
};

View File

@ -39,8 +39,15 @@ class linear_combination
for (typename map<unsigned, R>::const_iter i = lc.v; i; i ++)
v.push (i.key (), R (COPY, i.val ()));
}
linear_combination (reader &r)
{
m = r.read_mod<R> ();
v = map<unsigned, R> (r);
}
~linear_combination () { }
linear_combination &operator = (const linear_combination &lc)
{
m = lc.m;
@ -55,6 +62,7 @@ class linear_combination
lc3 -= lc2;
return lc3 == 0;
}
bool operator != (const linear_combination &lc) const { return !operator == (lc); }
bool operator == (int x) const
{
@ -163,6 +171,12 @@ class linear_combination
assert (!m->is_zero (i.val (), i.key ()));
}
#endif
void write_self (writer &w) const
{
write (w, *m);
write (w, v);
}
void show_self () const;
void display_self () const { show_self (); newline (); }
@ -336,6 +350,12 @@ class linear_combination<Z2>
linear_combination (ptr<const Z2mod> m_) : m(m_) { }
linear_combination (const linear_combination &lc) : m(lc.m), v(lc.v) { }
linear_combination (copy, const linear_combination &lc) : m(lc.m), v(COPY, lc.v) { }
linear_combination (reader &r)
{
m = r.read_mod<Z2> ();
v = set<unsigned> (r);
}
~linear_combination () { }
linear_combination &operator = (const linear_combination &lc)
@ -346,6 +366,7 @@ class linear_combination<Z2>
}
bool operator == (const linear_combination &lc) const { assert (m == lc.m); return v == lc.v; }
bool operator != (const linear_combination &lc) const { return !operator == (lc); }
bool operator == (int x) const { assert (x == 0); return v.is_empty (); }
bool operator != (int x) const { return !operator == (x); }
@ -445,6 +466,12 @@ class linear_combination<Z2>
void check () const;
#endif
void write_self (writer &w) const
{
write (w, *m);
write (w, v);
}
void show_self () const;
void display_self () const { show_self (); newline (); }
};

View File

@ -14,10 +14,15 @@ template<class R>
class module : public refcounted
{
private:
friend class reader;
friend class writer;
unsigned id;
static unsigned id_counter;
static map<unsigned, ptr<const module<R> > > reader_id_module;
static map<basedvector<unsigned, 1>,
ptr<const direct_sum<R> > > direct_sum_idx;
static map<basedvector<unsigned, 1>,
@ -28,13 +33,13 @@ class module : public refcounted
public:
module ()
{
id = id_counter;
id_counter ++;
id = id_counter;
}
module (const module &); // doesn't exist
module (const module &) = delete;
virtual ~module () { }
module &operator = (const module &); // doesn't exist
module &operator = (const module &) = delete;
public:
// the number of generators; n
@ -48,6 +53,9 @@ class module : public refcounted
// r < i <= n
virtual R generator_ann (unsigned i) const = 0;
basedvector<grading, 1> grading_vector () const;
set<grading> gradings () const;
bool is_free () const { return dim () == free_rank (); }
@ -56,7 +64,12 @@ class module : public refcounted
if (i <= free_rank ())
return c == 0;
else
return generator_ann (i) | c;
{
// ???
abort ();
// return generator_ann (i) | c;
}
}
R annihilator (R c, unsigned i) const
@ -75,6 +88,7 @@ class module : public refcounted
multivariate_laurentpoly<Z> free_poincare_polynomial () const;
multivariate_laurentpoly<Z> free_delta_poincare_polynomial () const;
multivariate_laurentpoly<Z> free_ell_poincare_polynomial () const;
ptr<const direct_sum<R> >
add (basedvector<ptr<const module<R> >, 1> compound_summands) const;
@ -143,11 +157,16 @@ class module : public refcounted
factors.append (this);
}
ptr<const free_submodule<R> > graded_piece (grading hq) const;
void write_self (writer &w) const { w.write_mod<R> (this); }
void show_self () const;
void display_self () const;
};
template<class R> unsigned module<R>::id_counter = 1;
template<class R> unsigned module<R>::id_counter = 0;
template<class R> map<unsigned, ptr<const module<R> > > module<R>::reader_id_module;
template<class R> map<basedvector<unsigned, 1>,
ptr<const direct_sum<R> > > module<R>::direct_sum_idx;
@ -466,11 +485,11 @@ class base_module : public module<R>
G g;
public:
base_module (); // doesn't exist
base_module () = delete;
base_module (const G &g_) : g(g_) { }
~base_module () { }
base_module &operator = (const base_module &); // doesn't exist
base_module &operator = (const base_module &) = delete;
unsigned dim () const { return g.dim (); }
unsigned free_rank () const { return g.free_rank (); }
@ -487,17 +506,19 @@ class explicit_module : public module<R>
basedvector<grading, 1> hq;
public:
explicit_module (); // doesn't exist
explicit_module () = delete;
explicit_module (unsigned r_,
basedvector<R, 1> ann_,
basedvector<grading, 1> hq_)
: r(r_), ann(ann_), hq(hq_)
{ }
{
assert (hq.size () == r + ann.size ());
}
explicit explicit_module (unsigned r_, basedvector<grading, 1> hq_) : r(r_), hq(hq_) { }
~explicit_module () { }
explicit_module &operator = (const explicit_module &); // doesn't exist
explicit_module &operator = (const explicit_module &) = delete;
unsigned dim () const { return r + ann.size (); }
unsigned free_rank () const { return r; }
@ -525,7 +546,7 @@ class free_submodule : public module<R>
{ }
~free_submodule () { }
free_submodule &operator = (const free_submodule &); // doesn't exist
free_submodule &operator = (const free_submodule &) = delete;
ptr<const module<R> > parent_module () const { return parent; }
@ -542,6 +563,9 @@ class free_submodule : public module<R>
linear_combination<R> restrict (linear_combination<R> v0) const;
ptr<const free_submodule<R> > restrict_submodule (ptr<const free_submodule<R> > m) const;
ptr<const free_submodule<R> > intersection (ptr<const free_submodule<R> > m) const;
ptr<const free_submodule<R> > plus (ptr<const free_submodule<R> > m) const;
};
template<class R>
@ -562,13 +586,13 @@ class quotient_module : public module<R>
basedvector<map<unsigned, R>, 1> pi;
public:
quotient_module (const quotient_module &); // doesn't exist
quotient_module (const quotient_module &) = delete;
quotient_module (ptr<const module<R> > parent_)
: parent(parent_)
{ }
~quotient_module () { }
quotient_module &operator = (const quotient_module &); // doesn't exsit
quotient_module &operator = (const quotient_module &) = delete;
ptr<const module<R> > parent_module () const { return parent; }
@ -617,7 +641,7 @@ class map_impl : public refcounted
ptr<const module<R> > to;
public:
map_impl (const map_impl &); // doesn't exist
map_impl (const map_impl &) = delete;
map_impl (ptr<const module<R> > fromto)
: from(fromto), to(fromto)
{ }
@ -626,9 +650,10 @@ class map_impl : public refcounted
{ }
virtual ~map_impl () { }
map_impl &operator = (const map_impl &); // doesn't exist
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 +682,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 +696,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 +706,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 +729,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 +750,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 +785,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);
@ -849,6 +878,15 @@ class mod_map
mod_map (const map_builder<R> &b)
: impl(new explicit_map_impl<R> (b.from, b.to, b.columns))
{ }
mod_map (reader &r)
{
ptr<const module<R> > from = r.read_mod<R> ();
ptr<const module<R> > to = r.read_mod<R> ();
basedvector<linear_combination<R>, 1> columns (r);
impl = new explicit_map_impl<R> (from, to, columns);
}
~mod_map () { }
mod_map &operator = (const mod_map &m) { impl = m.impl; return *this; }
@ -867,6 +905,7 @@ class mod_map
}
return 1;
}
bool operator != (const mod_map &m) const { return !operator == (m); }
bool operator == (int x) const
{
@ -883,8 +922,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
@ -908,6 +949,7 @@ class mod_map
// ?? add and other map operations should not be explicit
mod_map operator + (const mod_map &m) const;
mod_map operator * (const R &c) const;
bool homogeneous () const;
void check_grading (grading delta) const;
@ -917,6 +959,7 @@ class mod_map
// inj : im -> to
ptr<const free_submodule<R> > image () const;
ptr<const free_submodule<R> > image (basedvector<linear_combination<R>, 1> vs) const;
ptr<const quotient_module<R> > cokernel () const;
@ -934,9 +977,19 @@ class mod_map
mod_map induced_map_to (ptr<const quotient_module<R> > new_to);
mod_map induced_map (ptr<const quotient_module<R> > new_fromto);
mod_map graded_piece (grading hq) const;
// ???
basedvector<linear_combination<R>, 1> explicit_columns () const;
void write_self (writer &w) const
{
// write explicitly
write (w, *impl->from);
write (w, *impl->to);
write (w, explicit_columns ());
}
void show_self () const;
void display_self () const;
};
@ -1095,16 +1148,16 @@ quotient_helper<R>::improve_pivot_row (unsigned i, unsigned j, unsigned i2)
}
#endif
triple<R, R, R> t = rc.extended_gcd (r2c);
assert (t.first == rc*t.second + t.third*r2c);
tuple<R, R, R> t = rc.extended_gcd (r2c);
assert (get<0> (t) == rc*get<1> (t) + get<2> (t)*r2c);
rows[i] = r*t.second + r2*t.third;
rows[i2] = (rc.div (t.first))*r2 - (r2c.div (t.first))*r;
rows[i] = r*get<1> (t) + r2*get<2> (t);
rows[i2] = (rc.div (get<0> (t)))*r2 - (r2c.div (get<0> (t)))*r;
assert ((rc | r2c) == rc.divides (t.first));
assert (!rc.divides (t.first) || rows[i2](j) == 0);
assert ((rc | r2c) == rc.divides (get<0> (t)));
assert (!rc.divides (get<0> (t)) || rows[i2](j) == 0);
return !rc.divides (t.first);
return !rc.divides (get<0> (t));
}
template<class R> bool
@ -1149,8 +1202,8 @@ quotient_helper<R>::improve_pivot_column (unsigned i, unsigned j, unsigned j2)
}
#endif
triple<R, R, R> t = rc.extended_gcd (rc2);
assert (t.first == rc*t.second + t.third*rc2);
tuple<R, R, R> t = rc.extended_gcd (rc2);
assert (get<0> (t) == rc*get<1> (t) + get<2> (t)*rc2);
for (unsigned k = 1; k <= rows.size (); k ++)
{
@ -1158,9 +1211,9 @@ quotient_helper<R>::improve_pivot_column (unsigned i, unsigned j, unsigned j2)
R rkc = rk(j),
rkc2 = rk(j2);
rk.set_coeff (rkc*t.second + rkc2*t.third,
rk.set_coeff (rkc*get<1> (t) + rkc2*get<2> (t),
j);
rk.set_coeff (rkc2*(rc.div (t.first)) - rkc*(rc2.div (t.first)),
rk.set_coeff (rkc2*(rc.div (get<0> (t))) - rkc*(rc2.div (get<0> (t))),
j2);
}
@ -1169,8 +1222,8 @@ quotient_helper<R>::improve_pivot_column (unsigned i, unsigned j, unsigned j2)
assert (g.hq () == g2.hq ());
generators[j] = (rc.div (t.first)) * g + (rc2.div (t.first)) * g2;
generators[j2] = t.second * g2 - t.third * g;
generators[j] = (rc.div (get<0> (t))) * g + (rc2.div (get<0> (t))) * g2;
generators[j2] = get<1> (t) * g2 - get<2> (t) * g;
#if 0
for (unsigned k = 1; k <= rows.size (); k ++)
@ -1189,8 +1242,8 @@ quotient_helper<R>::improve_pivot_column (unsigned i, unsigned j, unsigned j2)
R d = ginv(j),
d2 = ginv(j2);
ginv.set_coeff (t.second*d + t.third*d2, j);
ginv.set_coeff (rc.div (t.first) * d2 - rc2.div (t.first) * d, j2);
ginv.set_coeff (get<1> (t)*d + get<2> (t)*d2, j);
ginv.set_coeff (rc.div (get<0> (t)) * d2 - rc2.div (get<0> (t)) * d, j2);
}
#if 0
@ -1207,10 +1260,10 @@ quotient_helper<R>::improve_pivot_column (unsigned i, unsigned j, unsigned j2)
}
#endif
assert ((rc | rc2) == rc.divides (t.first));
assert (!rc.divides (t.first) || r(j2) == 0);
assert ((rc | rc2) == rc.divides (get<0> (t)));
assert (!rc.divides (get<0> (t)) || r(j2) == 0);
return !rc.divides (t.first);
return !rc.divides (get<0> (t));
}
template<class R> void
@ -1437,6 +1490,58 @@ module<R>::free_delta_poincare_polynomial () const
return r;
}
template<class R> multivariate_laurentpoly<Z>
module<R>::free_ell_poincare_polynomial () const
{
multivariate_laurentpoly<Z> r;
for (unsigned i = 1; i <= free_rank (); i ++)
{
grading hq = generator_grading (i);
multivariate_laurent_monomial m;
m.push_exponent (1, hq.h - hq.q);
r.muladdeq (1, m);
}
return r;
}
template<class R> basedvector<grading, 1>
module<R>::grading_vector () const
{
basedvector<grading, 1> v (dim ());
for (unsigned i = 1; i <= dim (); i ++)
v[i] = generator_grading (i);
return v;
}
template<class R> set<grading>
module<R>::gradings () const
{
set<grading> gs;
for (unsigned i = 1; i <= dim (); i ++)
gs += generator_grading (i);
return gs;
}
template<class R> ptr<const free_submodule<R> >
module<R>::graded_piece (grading hq) const
{
basedvector<linear_combination<R>, 1> s;
for (unsigned i = 1; i <= dim (); i ++)
{
grading ihq = generator_grading (i);
if (ihq.h == hq.h
&& ihq.q == hq.q)
{
linear_combination<R> v (this);
v.muladd (1, i);
s.append (v);
}
}
mod_span<R> span (this, s);
return submodule (span);
}
template<class R> void
module<R>::show_self () const
{
@ -1520,6 +1625,28 @@ mod_map<R>::induced_map (ptr<const quotient_module<R> > new_fromto)
return new explicit_map_impl<R> (new_fromto, v);
}
template<class R> mod_map<R>
mod_map<R>::graded_piece (grading hq) const
{
basedvector<linear_combination<R>, 1> v (impl->from->dim ());
for (unsigned i = 1; i <= impl->from->dim (); i ++)
{
grading ihq = impl->from->generator_grading (i);
linear_combination<R> c = column (i);
linear_combination<R> d (impl->to);
for (linear_combination_const_iter<R> j = c; j; j ++)
{
grading jhq = impl->from->generator_grading (j.key ());
if (jhq.h - ihq.h == hq.h
&& jhq.q - ihq.q == hq.q)
d.muladd (j.val (), j.key ());
}
v[i] = d;
}
return mod_map (IMPL, new explicit_map_impl<R> (impl->from, impl->to, v));
}
template<class R> mod_map<R>
mod_map<R>::restrict_from (ptr<const free_submodule<R> > new_from) const
{
@ -1528,7 +1655,7 @@ mod_map<R>::restrict_from (ptr<const free_submodule<R> > new_from) const
basedvector<linear_combination<R>, 1> v (new_from->dim ());
for (unsigned i = 1; i <= new_from->dim (); i ++)
v[i] = map (new_from->inject_generator (i));
return new explicit_map_impl<R> (new_from, impl->to, v);
return mod_map (IMPL, new explicit_map_impl<R> (new_from, impl->to, v));
}
template<class R> mod_map<R>
@ -1552,7 +1679,7 @@ mod_map<R>::restrict (ptr<const free_submodule<R> > new_from,
basedvector<linear_combination<R>, 1> v (new_from->dim ());
for (unsigned i = 1; i <= new_from->dim (); i ++)
v[i] = new_to->restrict (map (new_from->inject_generator (i)));
return new explicit_map_impl<R> (new_from, new_to, v);
return mod_map (IMPL, new explicit_map_impl<R> (new_from, new_to, v));
}
template<class R> linear_combination<R>
@ -1595,7 +1722,94 @@ free_submodule<R>::restrict_submodule (ptr<const free_submodule<R> > m) const
span[i] = restrict (m->inject_generator (i));
mod_span<R> span2 (this, span);
return submodule (span2);
return this->submodule (span2);
}
template<class R> ptr<const free_submodule<R> >
free_submodule<R>::intersection (ptr<const free_submodule<R> > m) const
{
assert (parent == m->parent);
unsigned md = m->dim (),
d = dim ();
basedvector<linear_combination<R>, 1> intr;
basedvector<linear_combination<R>, 1> hperp,
hproj;
basedvector<unsigned, 1> hpivots;
for (unsigned i = 1; i <= md; i ++)
{
linear_combination<R> perp (COPY, m->gens[i]),
proj (parent);
for (unsigned j = 1; j <= d; j ++)
{
unsigned k = pivots[j];
if (perp % k)
{
const linear_combination<R> &g = gens[j];
R c = g(k);
R d = perp(k);
assert (c | d);
R q = d.div (c);
perp.mulsub (q, g);
proj.mulsub (q, g);
assert (! (perp % k));
}
}
for (unsigned j = 1; j <= hpivots.size (); j ++)
{
unsigned k = hpivots[j];
if (perp % k)
{
const linear_combination<R> &h = hperp[j];
R c = h(k);
R d = perp(k);
assert (c | d);
R q = d.div (c);
perp.mulsub (q, h);
proj.mulsub (q, hproj[j]);
assert (! (perp % k));
}
}
if (perp == 0)
intr.append (proj);
else
{
hperp.append (perp);
hproj.append (proj);
hpivots.append (perp.head ().first);
}
}
mod_span<R> span (parent, intr);
return parent->submodule (span);
}
template<class R> ptr<const free_submodule<R> >
free_submodule<R>::plus (ptr<const free_submodule<R> > m) const
{
assert (parent == m->parent);
basedvector<linear_combination<R>, 1> s;
for (unsigned i = 1; i <= dim (); i ++)
s.append (gens[i]);
for (unsigned i = 1; i <= m->dim (); i ++)
s.append (m->gens[i]);
mod_span<R> span (parent, s);
return parent->submodule (span);
}
template<class R> bool
@ -1628,6 +1842,14 @@ mod_map<R>::check_grading (grading delta) const
}
}
template<class R> mod_map<R>
mod_map<R>::operator * (const R &c) const
{
basedvector<linear_combination<R>, 1> v (impl->from->dim ());
for (unsigned i = 1; i <= impl->from->dim (); i ++)
v[i] = c*column (i);
return mod_map (IMPL, new explicit_map_impl<R> (impl->from, impl->to, v));
}
template<class R> mod_map<R>
mod_map<R>::operator + (const mod_map &m) const
@ -1636,8 +1858,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> >
@ -1647,7 +1869,7 @@ mod_map<R>::kernel () const
to = impl->to;
basedvector<linear_combination<R>, 1> from_xs (from->dim ());
for (unsigned i = 1; i <= to->dim (); i ++)
for (unsigned i = 1; i <= from->dim (); i ++)
{
linear_combination<R> x (from);
x.muladd (1, i);
@ -1670,13 +1892,21 @@ mod_map<R>::kernel () const
linear_combination<R> &to_x = to_xs[j],
&from_x = from_xs[j];
R to_xc = to_x(i);
if (! (to_vc | to_xc))
if (to_xc == 0)
continue;
if (to_vc == 0 && to_xc != 0)
{
triple<R, R, R> t = to_vc.extended_gcd (to_xc);
assert (t.first == to_vc*t.second + t.third*to_xc);
to_v += to_x;
from_v += from_x;
}
else if (! (to_vc | to_xc))
{
tuple<R, R, R> t = to_vc.extended_gcd (to_xc);
assert (get<0> (t) == to_vc*get<1> (t) + get<2> (t)*to_xc);
to_v = t.second*to_v + t.third*to_x;
from_v = t.second*from_v + t.third*from_x;
to_v = get<1> (t)*to_v + get<2> (t)*to_x;
from_v = get<1> (t)*from_v + get<2> (t)*from_x;
assert (to_v(i) != 0);
}
@ -1715,6 +1945,15 @@ mod_map<R>::image () const
return impl->to->submodule (span);
}
template<class R> ptr<const free_submodule<R> >
mod_map<R>::image (basedvector<linear_combination<R>, 1> vs) const
{
mod_span<R> span (impl->from, vs);
ptr<const free_submodule<R> > s = impl->from->submodule (span);
mod_map<R> r = restrict_from (s);
return r.image ();
}
template<class R> ptr<const quotient_module<R> >
mod_map<R>::cokernel () const
{
@ -1767,13 +2006,19 @@ mod_span<R>::mod_span (ptr<const module<R> > mod,
linear_combination<R> &x = xs[j];
R xc = x(i);
if (xc == 0)
continue;
if (! (vc | xc))
if (vc == 0)
{
triple<R, R, R> t = vc.extended_gcd (xc);
assert (t.first == vc*t.second + t.third*xc);
v += x;
}
else if (! (vc | xc))
{
tuple<R, R, R> t = vc.extended_gcd (xc);
assert (get<0> (t) == vc*get<1> (t) + get<2> (t)*xc);
v = t.second*v + t.third*x;
v = get<1> (t)*v + get<2> (t)*x;
assert (v(i) != 0);
}
@ -1820,8 +2065,68 @@ mod_map<R>::display_self () const
{
printf (" %d ", i);
impl->from->show_generator (i);
printf (" ");
show (impl->from->generator_grading (i));
printf (": ");
show (column (i));
newline ();
}
}
// ??? io
template<class R> void
writer::write_mod (ptr<const module<R> > m)
{
pair<unsigned &, bool> p = aw->id_io_id.find (m->id);
if (p.second)
{
write_int ((int)p.first);
}
else
{
++ aw->io_id_counter;
unsigned io_id = aw->io_id_counter;
p.first = io_id;
write_int (- (int)io_id);
unsigned n = m->dim (),
r = m->free_rank ();
write_unsigned (n);
write_unsigned (r);
for (unsigned i = 1; i <= n; i ++)
write (*this, m->generator_grading (i));
for (unsigned i = r + 1; i <= n; i ++)
write (*this, m->generator_ann (i));
}
}
template<class R> ptr<const module<R> >
reader::read_mod ()
{
int io_id = read_int ();
if (io_id < 0)
{
unsigned n = read_unsigned ();
unsigned r = read_unsigned ();
basedvector<grading, 1> gr (n);
for (unsigned i = 1; i <= n; i ++)
gr[i] = grading (*this);
basedvector<R, 1> ann (n - r);
for (unsigned i = r + 1; i <= n; i ++)
ann[i - r] = R (*this);
ptr<const module<R> > m = new explicit_module<R> (r, ann, gr);
ar->io_id_id.push ((unsigned)(-io_id), m->id);
module<R>::reader_id_module.push (m->id, m);
return m;
}
else
{
unsigned id = ar->io_id_id(io_id);
return module<R>::reader_id_module(id);
}
}

View File

@ -55,6 +55,7 @@ class multivariate_laurent_monomial
#endif
return m == e.m;
}
bool operator != (const multivariate_laurent_monomial &e) const { return !operator == (e); }
bool operator == (int x) const
{
@ -204,6 +205,12 @@ class multivariate_laurentpoly
coeffs.push (monomial (VARIABLE, i), c);
}
multivariate_laurentpoly (T c, variable, unsigned i, int e)
{
if (c != 0)
coeffs.push (monomial (VARIABLE, i, e), c);
}
multivariate_laurentpoly (T c, const monomial &m)
{
if (c != 0)
@ -212,7 +219,8 @@ class multivariate_laurentpoly
multivariate_laurentpoly (const multivariate_laurentpoly &p) : coeffs(p.coeffs) { }
multivariate_laurentpoly (copy, const multivariate_laurentpoly &p)
: coeffs(COPY2, p.coeffs)
// ??? COPY2?
: coeffs(COPY, p.coeffs)
{
}
@ -243,6 +251,7 @@ class multivariate_laurentpoly
#endif
return coeffs == p.coeffs;
}
bool operator != (const multivariate_laurentpoly &p) const { return !operator == (p); }
bool operator == (int x) const
{

View File

@ -5,7 +5,7 @@
template<unsigned n>
class multivariate_monomial
{
private:
public:
unsigned v[n];
public:
@ -56,6 +56,7 @@ class multivariate_monomial
}
return 1;
}
bool operator != (const multivariate_monomial &e) const { return !operator == (e); }
bool operator < (const multivariate_monomial &e) const
{
@ -199,7 +200,7 @@ public:
bool is_unit () const;
bool operator == (multivariate_polynomial p) const
bool operator == (const multivariate_polynomial &p) const
{
#ifndef NDEBUG
check ();
@ -207,6 +208,7 @@ public:
#endif
return coeffs == p.coeffs;
}
bool operator != (const multivariate_polynomial &p) const { return !operator == (p); }
bool operator == (int x) const
{
@ -263,6 +265,12 @@ public:
monomial common_monomial () const;
multivariate_polynomial gcd (const multivariate_polynomial &b) const
{
// ???
return multivariate_polynomial (1);
}
pair<multivariate_polynomial, multivariate_polynomial>
uncommon_factors (multivariate_polynomial b, basedvector<multivariate_polynomial, 1> ds);
maybe<multivariate_polynomial>

View File

@ -41,6 +41,7 @@ public:
polynomial (const polynomial &p) : coeffs(p.coeffs) { }
polynomial (copy, const polynomial &p) : coeffs(COPY, p.coeffs) { }
polynomial (reader &r) : coeffs(r) { }
~polynomial () { }
polynomial &operator = (const polynomial &p) { coeffs = p.coeffs; return *this; }
@ -64,7 +65,16 @@ public:
unsigned degree () const;
bool is_unit () const;
bool operator == (polynomial p) const
polynomial recip () const
{
assert (coeffs.card () == 1);
pair<unsigned, T> p = coeffs.head ();
assert (p.first == 0);
return polynomial (p.second.recip ());
}
bool operator == (const polynomial &p) const
{
#ifndef NDEBUG
check ();
@ -72,6 +82,7 @@ public:
#endif
return coeffs == p.coeffs;
}
bool operator != (const polynomial &p) const { return !operator == (p); }
bool operator == (int x) const
{
@ -95,6 +106,7 @@ public:
polynomial &operator *= (polynomial p) { return operator = (*this * p); }
polynomial &operator *= (T s);
// ??? rename
polynomial &add_term (T c, unsigned e)
{
T &c2 = coeffs[e];
@ -112,27 +124,36 @@ public:
return r;
}
polynomial operator - (polynomial p) const
polynomial operator - (const polynomial &p) const
{
polynomial r (COPY, *this);
r -= p;
return r;
}
polynomial operator * (polynomial p) const;
polynomial operator * (const polynomial &p) const;
pair<polynomial, polynomial> divide_with_remainder (polynomial d) const;
bool divides (const polynomial &num) const;
polynomial mod (polynomial d) const;
bool divides (polynomial d) const;
polynomial divide_exact (polynomial d) const;
// *this | num
bool operator | (const polynomial &num) const { return divides (num); }
polynomial gcd (polynomial b) const;
tuple<polynomial, polynomial> divide_with_remainder (const polynomial &denom) const;
polynomial mod (const polynomial &denom) const;
polynomial divide_exact (const polynomial &denom) const;
polynomial div (const polynomial &denom) const { return divide_exact (denom); }
polynomial gcd (const polynomial &b) const;
polynomial lcm (const polynomial &b) const;
tuple<polynomial, polynomial, polynomial> extended_gcd (const polynomial &b) const;
#ifndef NDEBUG
void check () const;
#endif
void write_self (writer &w) const { write (w, coeffs); }
static void show_ring () { T::show_ring (); printf ("[x]"); }
void display_self () const { show_self (); newline (); }
void show_self () const;
@ -197,7 +218,7 @@ polynomial<T>::operator *= (T s)
}
template<class T> polynomial<T>
polynomial<T>::operator * (polynomial p) const
polynomial<T>::operator * (const polynomial &p) const
{
polynomial r;
@ -213,14 +234,15 @@ polynomial<T>::operator * (polynomial p) const
return r;
}
template<class T> pair<polynomial<T>, polynomial<T> >
polynomial<T>::divide_with_remainder (polynomial d) const
template<class T> tuple<polynomial<T>, polynomial<T> >
polynomial<T>::divide_with_remainder (const polynomial &d) const
{
// num = *this
assert (d != 0);
polynomial r (COPY, *this);
polynomial q;
pair<unsigned, T> d_leading_term = d.coeffs.tail ();
for (;;)
{
@ -240,45 +262,80 @@ polynomial<T>::divide_with_remainder (polynomial d) const
assert (r == 0 || r.degree () < d.degree ());
// assert (*this == q*d + r);
return pair<polynomial, polynomial> (q, r);
return make_tuple (q, r);
}
template<class T> polynomial<T>
polynomial<T>::mod (polynomial d) const
polynomial<T>::mod (const polynomial &denom) const
{
pair<polynomial<T>, polynomial<T> > qr = divide_with_remainder (d);
return qr.second;
polynomial q, r;
tie (q, r) = divide_with_remainder (denom);
return r;
}
template<class T> bool
polynomial<T>::divides (polynomial d) const
polynomial<T>::divides (const polynomial &num) const
{
pair<polynomial<T>, polynomial<T> > qr = divide_with_remainder (d);
return qr.second == 0;
// denom = *this
polynomial q, r;
tie (q, r) = num.divide_with_remainder (*this);
return r == 0;
}
template<class T> polynomial<T>
polynomial<T>::divide_exact (polynomial d) const
polynomial<T>::divide_exact (const polynomial &denom) const
{
pair<polynomial<T>, polynomial<T> > qr = divide_with_remainder (d);
assert (qr.second == 0);
return qr.first;
polynomial q, r;
tie (q, r) = divide_with_remainder (denom);
assert (r == 0);
return q;
}
template<class T> polynomial<T>
polynomial<T>::gcd (polynomial b) const
polynomial<T>::gcd (const polynomial &b) const
{
polynomial a = *this;
while (b != 0)
{
pair<polynomial<T>, polynomial<T> > a_qr = a.divide_with_remainder (b);
polynomial r;
tie (ignore, r) = a.divide_with_remainder (b);
a = b;
b = a_qr.second;
b = r;
}
return a;
}
template<class T> polynomial<T>
polynomial<T>::lcm (const polynomial &b) const
{
// a = *this
return divide_exact (gcd (b)) * b;
}
template<class T> tuple<polynomial<T>, polynomial<T>, polynomial<T> >
polynomial<T>::extended_gcd (const polynomial &b) const
{
// a = *this
if (b == 0)
return make_tuple (*this, polynomial (1), polynomial (0));
polynomial q, r;
tie (q, r) = divide_with_remainder (b);
if (r == 0)
return make_tuple (b, polynomial (0), polynomial (1));
else
{
polynomial d, s, t;
tie (d, s, t) = b.extended_gcd (r);
polynomial s2 = t,
t2 = s - t*q;
return make_tuple (d, s2, t2);
}
}
#ifndef NDEBUG
template<class T> void
polynomial<T>::check () const
@ -338,14 +395,14 @@ class polynomial<Z2>
public:
polynomial () { }
explicit polynomial (int x)
polynomial (int x)
{
Z2 c (x);
if (c != 0)
coeffs.push (0);
}
explicit polynomial (Z2 c)
polynomial (Z2 c)
{
if (c != 0)
coeffs.push (0);
@ -380,7 +437,8 @@ class polynomial<Z2>
return *this;
}
bool operator == (polynomial p) const { return coeffs == p.coeffs; }
bool operator == (const polynomial &p) const { return coeffs == p.coeffs; }
bool operator != (const polynomial &p) const { return !operator == (p); }
bool operator == (int x) const
{
@ -395,6 +453,17 @@ class polynomial<Z2>
bool operator != (int x) const { return !operator == (x); }
unsigned degree () const { return coeffs.tail (); }
bool is_unit () const
{
return coeffs.card () == 1
&& coeffs.head () == 0;
}
polynomial recip () const
{
assert (is_unit ());
return 1;
}
polynomial &operator += (polynomial p) { coeffs ^= p.coeffs; return *this; }
polynomial &operator -= (polynomial p) { coeffs ^= p.coeffs; return *this; }
@ -443,4 +512,3 @@ class polynomial<Z2>
void display_self () const { show_self (); newline (); }
void show_self () const;
};

View File

@ -19,10 +19,10 @@ public:
public:
rd_unify ();
rd_unify (const rd_unify &); // doesn't exist
rd_unify (const rd_unify &) = delete;
~rd_unify () { }
rd_unify &operator = (const rd_unify &); // doesn't exist
rd_unify &operator = (const rd_unify &) = delete;
bool unify (const resolution_diagram &rd1, const resolution_diagram &rd2);
unsigned map_starting_monomial (unsigned m);

View File

@ -160,6 +160,7 @@ class resolution_diagram
resolution_diagram &operator = (const resolution_diagram &rd);
bool operator == (const resolution_diagram &rd) const;
bool operator != (const resolution_diagram &rd) const { return !operator == (rd); }
/* reverse, reverse_orientation leave starting/ending circle numbers
unchanged. */
@ -190,10 +191,10 @@ class resolution_diagram_builder
public:
resolution_diagram_builder ();
resolution_diagram_builder (const resolution_diagram_builder &); // doesn't exist
resolution_diagram_builder (const resolution_diagram_builder &) = delete;
~resolution_diagram_builder () { }
resolution_diagram_builder &operator = (const resolution_diagram_builder &); // doesn't exist
resolution_diagram_builder &operator = (const resolution_diagram_builder &) = delete;
void init (const knot_diagram &d,
smallbitset from_state, const smoothing &from_s,

17
cube.h
View File

@ -3,10 +3,10 @@ class map_rules
{
public:
map_rules () { }
map_rules (const map_rules &); // doesn't exist
map_rules (const map_rules &) = delete;
virtual ~map_rules () { }
map_rules &operator = (const map_rules &); // doesn't exist
map_rules &operator = (const map_rules &) = delete;
virtual void map (basedvector<pair<unsigned, unsigned>, 1> &out,
resolution_diagram_builder &rdb) const = 0;
@ -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;
@ -47,6 +47,7 @@ public:
bool reverse_orientation,
unsigned to_reverse) const;
mod_map<R> compute_dinv (unsigned c);
mod_map<R> H_i (unsigned c);
mod_map<R> compute_nu () const;
@ -77,10 +78,10 @@ class twisted_map_rules
{
public:
twisted_map_rules () { }
twisted_map_rules (const twisted_map_rules &); // doesn't exist
twisted_map_rules (const twisted_map_rules &) = delete;
virtual ~twisted_map_rules () { }
map_rules &operator = (const twisted_map_rules &); // doesn't exist
map_rules &operator = (const twisted_map_rules &) = delete;
virtual void map (basedvector<triple<unsigned, unsigned, set<unsigned> >, 1> &out,
resolution_diagram_builder &rdb) const = 0;
@ -100,10 +101,10 @@ class twisted_cube
: c(c_)
{ }
twisted_cube (const twisted_cube &); // doesn't exist
twisted_cube (const twisted_cube &) = delete;
~twisted_cube () { }
twisted_cube &operator = (const twisted_cube &); // doesn't exist
twisted_cube &operator = (const twisted_cube &) = delete;
mod_map<R> compute_twisted_map (basedvector<int, 1> edge_weight,
unsigned dh,

View File

@ -9,7 +9,7 @@ public:
khC_generators (const cube<R> &c_) : c(c_) { }
~khC_generators () { }
khC_generators &operator = (const khC_generators &); // doesn't exist
khC_generators &operator = (const khC_generators &) = delete;
unsigned dim () const { return c.n_generators; }
unsigned free_rank () const { return c.n_generators; }
@ -166,7 +166,7 @@ cube<R>::compute_map (unsigned dh, unsigned max_n,
continue;
assert (!unsigned_bittest (v_to, p));
}
b[generator (fromstate, v_from)].muladd
(sign, generator (tostate, v_to));
}
@ -187,10 +187,10 @@ class d_rules : public map_rules
{
public:
d_rules () { }
d_rules (const d_rules &); // doesn't exist
d_rules (const d_rules &) = delete;
~d_rules () { }
d_rules &operator = (const d_rules &); // doesn't exist
d_rules &operator = (const d_rules &) = delete;
void map (basedvector<pair<unsigned, unsigned>, 1> &out,
resolution_diagram_builder &rdb) const
@ -214,10 +214,10 @@ class twin_arrows_P_rules : public map_rules
{
public:
twin_arrows_P_rules () { }
twin_arrows_P_rules (const twin_arrows_P_rules &); // doesn't exist
twin_arrows_P_rules (const twin_arrows_P_rules &) = delete;
~twin_arrows_P_rules () { }
twin_arrows_P_rules &operator = (const twin_arrows_P_rules &); // doesn't exist
twin_arrows_P_rules &operator = (const twin_arrows_P_rules &) = delete;
void map (basedvector<pair<unsigned, unsigned>, 1> &out,
resolution_diagram_builder &rdb) const
@ -302,7 +302,7 @@ cube<R>::compute_X (unsigned p) const
template<class R> mod_map<R>
cube<R>::H_i (unsigned c)
{
mod_map<R> b (khC, 0);
map_builder<R> b (khC, 0);
for (unsigned i = 0; i < n_resolutions; i ++)
{
if (unsigned_bittest (i, c))
@ -319,8 +319,23 @@ cube<R>::H_i (unsigned c)
unsigned from = from_s.crossing_from_circle (kd, c),
to = from_s.crossing_to_circle (kd, c);
int sign = 1;
for (unsigned j = 1; j < c; j ++)
{
if (unsigned_bittest (i, j))
sign *= -1;
}
for (unsigned j = 0; j < from_s.num_monomials (); j ++)
{
if (markedp_only)
{
unsigned p = from_s.edge_circle[kd.marked_edge];
if (unsigned_bittest (j, p))
continue;
}
unsigned j2 = 0;
for (unsigned_const_iter k = j; k; k ++)
{
@ -336,7 +351,7 @@ cube<R>::H_i (unsigned c)
to_s.crossing_from_circle (kd, c));
j2 = unsigned_bitset (j2,
to_s.crossing_to_circle (kd, c));
v.muladd (1, generator (i2, j2));
v.muladd (-sign, generator (i2, j2));
}
else if (from != to
&& !unsigned_bittest (j, from)
@ -344,7 +359,7 @@ cube<R>::H_i (unsigned c)
{
assert (! unsigned_bittest (j2,
to_s.crossing_from_circle (kd, c)));
v.muladd (1, generator (i2, j2));
v.muladd (sign, generator (i2, j2));
}
}
}
@ -356,6 +371,110 @@ cube<R>::H_i (unsigned c)
return H_c;
}
template<class R> mod_map<R>
cube<R>::compute_dinv (unsigned c)
{
map_builder<R> p (khC);
for (unsigned i = 0; i < n_resolutions; i ++)
{
if (!unsigned_bittest (i, c))
continue;
int sign = 1;
for (unsigned j = 1; j < c; j ++)
{
if (unsigned_bittest (i, j))
sign *= -1;
}
smoothing from_s (kd, smallbitset (n_crossings, i));
unsigned i2 = unsigned_bitclear (i, c);
smoothing to_s (kd, smallbitset (n_crossings, i2));
basedvector<unsigned, 1> from_circle_edge_rep (from_s.n_circles);
for (unsigned j = 1; j <= kd.num_edges (); j ++)
from_circle_edge_rep[from_s.edge_circle[j]] = j;
unsigned a = from_s.crossing_from_circle (kd, c),
b = from_s.crossing_to_circle (kd, c);
unsigned x = to_s.crossing_from_circle (kd, c),
y = to_s.crossing_to_circle (kd, c);
for (unsigned j = 0; j < from_s.num_monomials (); j ++)
{
if (markedp_only)
{
unsigned p = from_s.edge_circle[kd.marked_edge];
if (unsigned_bittest (j, p))
continue;
}
unsigned j2 = 0;
for (unsigned_const_iter k = j; k; k ++)
{
unsigned s = k.val ();
j2 = unsigned_bitset (j2, to_s.edge_circle[from_circle_edge_rep[s]]);
}
if (a == b)
{
// split
assert (x != y);
if (unsigned_bittest (j, a))
{
// 1 -> x + y
j2 = unsigned_bitset (j2, x);
j2 = unsigned_bitclear (j2, y);
p[generator (i, j)].muladd (sign, generator (i2, j2));
j2 = unsigned_bitclear (j2, x);
j2 = unsigned_bitset (j2, y);
p[generator (i, j)].muladd (sign, generator (i2, j2));
}
else
{
// a -> xy
j2 = unsigned_bitclear (j2, x);
j2 = unsigned_bitclear (j2, y);
p[generator (i, j)].muladd (sign, generator (i2, j2));
}
}
else
{
// join
assert (x == y);
if (unsigned_bittest (j, a)
&& unsigned_bittest (j, b))
{
// 1 -> 1
j2 = unsigned_bitset (j2, x);
p[generator (i, j)].muladd (sign, generator (i2, j2));
}
else if ((unsigned_bittest (j, a)
&& !unsigned_bittest (j, b))
|| (!unsigned_bittest (j, a)
&& unsigned_bittest (j, b)))
{
// a, b -> x
j2 = unsigned_bitclear (j2, x);
p[generator (i, j)].muladd (sign, generator (i2, j2));
}
}
}
}
mod_map<R> dinv (p);
dinv.check_grading (grading (-1, -2));
return dinv;
}
template<class R> void
cube<R>::check_reverse_crossings ()
{
@ -415,6 +534,50 @@ cube<R>::cube (knot_diagram &kd_, bool markedp_only_)
{
smallbitset state (n_crossings, i);
s.init (kd, state);
#if 1
unsigned fromstate = i;
smoothing &from_s = s;
unsigned n_zerocrossings = n_crossings - unsigned_bitcount (fromstate);
unsigned n_cobordisms = ((unsigned)1) << n_zerocrossings;
for (unsigned j = 0; j < n_cobordisms; j ++)
{
unsigned tostate = unsigned_pack (n_crossings, fromstate, j);
unsigned crossings = tostate & ~fromstate;
smoothing to_s (kd, smallbitset (n_crossings, tostate));
set<unsigned> starting_circles,
ending_circles;
for (unsigned_const_iter k = crossings; k; k ++)
{
unsigned c = k.val ();
unsigned starting_from = s.ept_circle (kd, kd.crossings[c][2]),
starting_to = s.ept_circle (kd, kd.crossings[c][4]);
starting_circles += starting_from;
starting_circles += starting_to;
unsigned ending_from = to_s.ept_circle (kd, kd.crossings[c][2]),
ending_to = to_s.ept_circle (kd, kd.crossings[c][4]);
ending_circles += ending_from;
ending_circles += ending_to;
}
if (starting_circles.card () == 1
&& ending_circles.card () == 1)
{
unsigned k = unsigned_bitcount (crossings);
#if 0
s.show_self (kd, state);
printf (" crossings "); show (smallbitset (n_crossings, crossings));
newline ();
#endif
}
}
#endif
resolution_circles[i] = s.n_circles;
resolution_generator1[i] = n_generators + 1;
n_generators += s.num_generators (markedp_only);
@ -676,10 +839,10 @@ class twisted_barE_rules : public twisted_map_rules
{
public:
twisted_barE_rules () { }
twisted_barE_rules (const twisted_barE_rules &); // doesn't exist
twisted_barE_rules (const twisted_barE_rules &) = delete;
~twisted_barE_rules () { }
twisted_barE_rules &operator = (const twisted_barE_rules &); // doesn't exist
twisted_barE_rules &operator = (const twisted_barE_rules &) = delete;
void map (basedvector<triple<unsigned, unsigned, set<unsigned> >, 1> &out,
resolution_diagram_builder &rdb) const

126
gss.cpp
View File

@ -1,126 +0,0 @@
#include <knotkit.h>
const char *program_name;
void
usage ()
{
printf ("usage: %s [-f] [-h] [-o <file>] [-v] <knot>\n", program_name);
printf (" compute Szabo's geometric spectral sequence for knot <knot>\n");
printf ("options:\n");
printf (" -f : compute unreduced spectral sequence\n");
printf (" (reduced is the default)\n");
printf (" -h : print this message\n");
printf (" -o <file> : write output to <file>\n");
printf (" (stdout is the default)\n");
printf (" -v : verbose: report progress as the computation proceeds\n");
printf ("<knot> can be one of:\n");
printf (" - the unknot, e.g. U or unknot\n");
printf (" - a torus knot, e.g. T(2,3)\n");
printf (" - a Rolfsen table knot, e.g. 10_124\n");
printf (" - a Hoste-Thistlethwaite-Weeks knot, e.g. 11a12 or 12n214\n");
printf (" - a Morwen Thistlethwaite link, e.g. L9a21 or L14n7631\n");
printf (" - a planar diagram, e.g.\n");
printf (" PD[X[1, 4, 2, 5], X[3, 6, 4, 1], X[5, 2, 6, 3]] or\n");
printf (" PD[[1, 4, 2, 5], [3, 6, 4, 1], [5, 2, 6, 3]]\n");
printf (" - a Dowker-Thistlethwaite code, e.g.\n");
printf (" DTCode[6,8,2,4],\n");
printf (" DT[dadbcda] or\n");
printf (" DT[{6, -8}, {-10, 12, -14, 2, -4}]\n");
printf (" - a braid, e.g. BR[2, {-1, -1, -1}]\n");
}
int
main (int argc, char **argv)
{
program_name = argv[0];
bool reduced = 1;
const char *knot = 0;
const char *file = 0;
for (int i = 1; i < argc; i ++)
{
if (argv[i][0] == '-')
{
if (strcmp (argv[i], "-f") == 0)
reduced = 0;
else if (strcmp (argv[i], "-h") == 0)
{
usage ();
exit (EXIT_SUCCESS);
}
else if (!strcmp (argv[i], "-v"))
verbose = 1;
else if (!strcmp (argv[i], "-o"))
{
i ++;
if (i == argc)
{
fprintf (stderr, "error: missing argument to option `-o'\n");
exit (EXIT_FAILURE);
}
file = argv[i];
}
else
{
fprintf (stderr, "error: unknown argument `%s'\n", argv[1]);
usage ();
exit (EXIT_FAILURE);
}
}
else
{
if (knot)
{
fprintf (stderr, "error: too many arguments\n");
usage ();
exit (EXIT_FAILURE);
}
else
knot = argv[i];
}
}
if (!knot)
{
fprintf (stderr, "error: missing <knot> argument\n");
usage ();
exit (EXIT_FAILURE);
}
FILE *outfp = 0;
if (file)
{
outfp = fopen (file, "w");
if (!outfp)
{
stderror ("fopen: %s", file);
exit (EXIT_FAILURE);
}
}
else
outfp = stdout;
knot_diagram d = parse_knot (knot);
d.marked_edge = 1;
cube<Z2> c (d, reduced);
fprintf (outfp, "\\documentclass{article}\n\
\\usepackage{amsmath, tikz, hyperref}\n\
\\DeclareMathOperator{\\rank}{rank}\n\
\\setlength{\\parindent}{0pt}\n\
\n\
\\begin{document}\n\
\\pagestyle{empty}\n\
\\tableofcontents\n\
\\sloppy\n");
compute_szabo_sseq (c).texshow (outfp, d.name);
fprintf (outfp, "\\end{document}\n");
if (file)
fclose (outfp);
}

666
kk.cpp Normal file
View File

@ -0,0 +1,666 @@
#include <knotkit.h>
const char *program_name;
void
usage ()
{
printf ("usage: %s <invariant> [options...] <link>\n", program_name);
printf (" compute <invariant> for knot or link <link>\n");
printf ("<invariant> can be one of:\n");
printf (" kh: Khovanov homology\n");
printf (" gss: Szabo's geometric spectral sequence\n");
printf (" lsss: Batson-Seed link splitting spectral sequence\n");
printf (" component weights are 0, 1, ..., m\n");
printf (" sq2: Lipshitz-Sarkar Steenrod square on Z/2 Kh\n");
printf (" output suitable for Sage\n");
printf (" leess: spectral sequence coming from Bar-Natan analogue of Lee's\n");
printf (" deformation of Khovanov's complex (whew!)\n");
printf (" s: Rasmussen's s-invariant coming from lee\n");
printf ("output:\n");
printf (" kh, gss, lsss, leess: .tex file\n");
printf (" sq2: text in Sage format\n");
printf (" s: text\n");
printf ("options:\n");
printf (" -r : compute reduced theory\n");
printf (" -h : print this message\n");
printf (" -o <file> : write output to <file>\n");
printf (" (stdout is the default)\n");
printf (" -f <field> : ground field (if applicable)\n");
printf (" (Z2 is the default)\n");
printf (" -v : verbose: report progress as the computation proceeds\n");
printf ("<field> can be one of:\n");
printf (" Z2, Z3, Q\n");
printf ("<link> can be one of:\n");
printf (" - the unknot, e.g. U or unknot\n");
printf (" - a torus knot, e.g. T(2,3)\n");
printf (" - a Rolfsen table knot, e.g. 10_124\n");
printf (" - a Hoste-Thistlethwaite-Weeks knot, e.g. 11a12 or 12n214\n");
printf (" - a Morwen Thistlethwaite link, e.g. L8n9 or L13n8862\n");
printf (" - a planar diagram, e.g.\n");
printf (" PD[X[1, 4, 2, 5], X[3, 6, 4, 1], X[5, 2, 6, 3]] or\n");
printf (" PD[[1, 4, 2, 5], [3, 6, 4, 1], [5, 2, 6, 3]]\n");
printf (" - a Dowker-Thistlethwaite code, e.g.\n");
printf (" DTCode[6,8,2,4],\n");
printf (" DT[dadbcda] or\n");
printf (" DT[{6, -8}, {-10, 12, -14, 2, -4}]\n");
printf (" - a braid, e.g. BR[2, {-1, -1, -1}]\n");
printf (" - disjoint union (juxtaposition), e.g. T(2,3) U\n");
}
FILE *outfp = stdout;
void tex_header ()
{
fprintf (outfp, "\\documentclass{article}\n\
\\usepackage{amsmath, tikz, hyperref}\n\
\\DeclareMathOperator{\\rank}{rank}\n\
\\setlength{\\parindent}{0pt}\n\
\n\
\\begin{document}\n\
\\pagestyle{empty}\n\
\\sloppy\n");
}
void tex_footer ()
{
fprintf (outfp, "\\end{document}\n");
}
const char *knot = 0;
const char *invariant = 0;
const char *field = "Z2";
knot_diagram kd;
bool reduced = 0;
class hg_grading_mapper
{
unsigned m;
public:
hg_grading_mapper (unsigned m_) : m(m_) { }
grading operator () (grading hq) const
{
int t = hq.q - (int)m;
if (reduced)
t --;
assert (is_even (t));
return grading (hq.h, t / 2);
}
grading map_delta (grading d_hq) const
{
assert (is_even (d_hq.q));
return grading (d_hq.h, d_hq.q / 2);
}
void x_label (FILE *fp, int h) const
{
fprintf (fp, "%d", h);
}
void y_label (FILE *fp, int g) const
{
unsigned q = 2*g + (int)m;
if (reduced)
q ++;
fprintf (fp, "%d", q);
}
};
template<class R> mod_map<R>
compute_link_splitting_d (knot_diagram &kd,
cube<R> &c,
basedvector<R, 1> comp_weight)
{
unsigned n = kd.num_components ();
unionfind<1> u (kd.num_edges ());
for (unsigned i = 1; i <= kd.n_crossings; i ++)
{
u.join (kd.ept_edge (kd.crossings[i][1]),
kd.ept_edge (kd.crossings[i][3]));
u.join (kd.ept_edge (kd.crossings[i][2]),
kd.ept_edge (kd.crossings[i][4]));
}
map<unsigned, unsigned> root_comp;
unsigned t = 0;
for (unsigned i = 1; i <= kd.num_edges (); i ++)
{
if (u.find (i) == i)
{
++ t;
root_comp.push (i, t);
}
}
assert (t == n);
assert (comp_weight.size () == n);
map<unsigned, R> crossing_over_sign;
// crossings
set<unsigned> pending;
set<unsigned> finished;
crossing_over_sign.push (1, R (1));
pending.push (1);
while (pending.card () > 0)
{
unsigned x = pending.pop ();
finished.push (x);
R s = crossing_over_sign(x);
for (unsigned j = 1; j <= 4; j ++)
{
unsigned p = kd.crossings[x][j];
R t = kd.is_over_ept (p) ? s : -s; // sign of (x, p)
unsigned q = kd.edge_other_ept (p);
unsigned x2 = kd.ept_crossing[q];
R u = kd.is_over_ept (q) ? -t : t;
if (crossing_over_sign % x2)
assert (crossing_over_sign(x2) == u);
else
crossing_over_sign.push (x2, u);
if (! (finished % x2))
pending += x2;
}
}
assert (finished.card () == kd.n_crossings);
mod_map<R> untwisted_d = c.compute_d (1, 0, 0, 0, 0);
assert (untwisted_d.compose (untwisted_d) == 0);
mod_map<R> d = untwisted_d;
for (unsigned x = 1; x <= kd.n_crossings; x ++)
{
unsigned p1 = kd.crossings[x][1],
p2 = kd.crossings[x][2];
assert (kd.is_over_ept (p2));
unsigned r1 = u.find (kd.ept_edge (p1)),
r2 = u.find (kd.ept_edge (p2));
unsigned c1 = root_comp(r1),
c2 = root_comp(r2);
if (c1 != c2)
{
R s = crossing_over_sign(x);
R w_under = comp_weight[c1];
R w_over = comp_weight[c2];
d = d + c.compute_dinv (x)*(s*(w_over - w_under));
}
}
assert (d.compose (d) == 0);
return d;
}
void
compute_gss ()
{
cube<Z2> c (kd, reduced);
ptr<const module<Z2> > C = c.khC;
mod_map<Z2> d = c.compute_d (0, 0, 0, 0, 0);
unsigned m = kd.num_components ();
hg_grading_mapper mapper (m);
sseq_bounds b (C, mapper);
basedvector<sseq_page, 1> pages;
unsigned k = 1;
for (;;)
{
chain_complex_simplifier<Z2> s (C, d,
maybe<int> (k), maybe<int> (2*k - 2));
C = s.new_C;
d = s.new_d;
k ++;
grading dk_gr (k, 2*k - 2);
pages.append (sseq_page (b, k, dk_gr, d.graded_piece (dk_gr), mapper));
if (d == 0)
break;
}
sseq ss (b, pages);
tex_header ();
fprintf (outfp, "$E_k = %s^{Sz}_k(\\verb~%s~; \\verb~%s~)$:\\\\\n",
(reduced
? "\\widetilde{E}"
: "E"),
knot, field);
ss.texshow (outfp, mapper);
tex_footer ();
}
template<class R> void
compute_invariant ()
{
if (!strcmp (invariant, "kh"))
{
cube<R> c (kd, reduced);
ptr<const module<R> > C = c.khC;
mod_map<R> d = c.compute_d (1, 0, 0, 0, 0);
unsigned m = kd.num_components ();
hg_grading_mapper mapper (m);
chain_complex_simplifier<R> s (C, d,
maybe<int> (1), maybe<int> (0));
C = s.new_C;
d = s.new_d;
sseq_bounds b (C, mapper);
sseq_page pg (b, 2, grading (0, 0), mod_map<R> (C), mapper);
tex_header ();
fprintf (outfp, "Kh = $%s(\\verb~%s~; \\verb~%s~)$:\\\\\n",
(reduced
? "\\widetilde{Kh}"
: "Kh"),
knot,
field);
fprintf (outfp, "$\\rank Kh = %d$\\\\\n", C->dim ());
char buf[1000];
sprintf (buf, "$Kh$");
pg.texshow (outfp, b, buf, mapper);
tex_footer ();
}
else if (!strcmp (invariant, "lsss"))
{
cube<R> c (kd, reduced);
ptr<const module<R> > C = c.khC;
unsigned m = kd.num_components ();
basedvector<R, 1> comp_weight (m);
for (unsigned i = 1; i <= m; i ++)
comp_weight[i] = R ((int)(i - 1));
mod_map<R> d = compute_link_splitting_d (kd, c, comp_weight);
hg_grading_mapper mapper (m);
sseq_bounds b (C, mapper);
basedvector<sseq_page, 1> pages;
int k = 0;
for (;;)
{
chain_complex_simplifier<R> s (C, d,
maybe<int> (1 - 2*k), maybe<int> (-2*k));
C = s.new_C;
d = s.new_d;
k ++;
grading dk_gr (1 - 2*k, -2*k);
pages.append (sseq_page (b, k, dk_gr, d.graded_piece (dk_gr), mapper));
if (d == 0)
break;
}
sseq ss (b, pages);
tex_header ();
fprintf (outfp, "$E_k = %s^{BS}_k({}^{%d}\\verb~%s~; \\verb~%s~)$:\\\\\n",
(reduced
? "\\widetilde{E}"
: "E"),
m,
knot,
field);
ss.texshow (outfp, mapper);
tex_footer ();
}
else if (!strcmp (invariant, "leess"))
{
cube<R> c (kd, reduced);
ptr<const module<R> > C = c.khC;
mod_map<R> d = c.compute_d (1, 0, 0, 0, 0);
for (unsigned i = 1; i <= kd.n_crossings; i ++)
d = d + c.H_i (i);
assert (d.compose (d) == 0);
unsigned m = kd.num_components ();
hg_grading_mapper mapper (m);
sseq_bounds b (C, mapper);
basedvector<sseq_page, 1> pages;
int k = 0;
for (;;)
{
chain_complex_simplifier<R> s (C, d,
maybe<int> (1), maybe<int> (2*k));
C = s.new_C;
d = s.new_d;
k ++;
grading dk_gr (1, 2*k);
pages.append (sseq_page (b, k, dk_gr, d.graded_piece (dk_gr), mapper));
if (d == 0)
break;
}
sseq ss (b, pages);
tex_header ();
fprintf (outfp, "$E_k = %s^{BN}_k(\\verb~%s~; \\verb~%s~)$:\\\\\n",
(reduced
? "\\widetilde{E}"
: "E"),
knot, field);
ss.texshow (outfp, mapper);
tex_footer ();
}
else if (!strcmp (invariant, "s"))
{
unsigned m = kd.num_components ();
if (m != 1)
{
fprintf (stderr, "error: s-invariant only defined for knots\n");
exit (EXIT_FAILURE);
}
cube<R> c (kd, 0);
ptr<const module<R> > C = c.khC;
mod_map<R> d = c.compute_d (1, 0, 0, 0, 0);
for (unsigned i = 1; i <= kd.n_crossings; i ++)
d = d + c.H_i (i);
assert (d.compose (d) == 0);
int k = 0;
for (;;)
{
chain_complex_simplifier<R> s (C, d,
maybe<int> (1), maybe<int> (2*k));
C = s.new_C;
d = s.new_d;
k ++;
if (d == 0)
break;
}
assert (C->dim () == 2);
grading gr1 = C->generator_grading (1),
gr2 = C->generator_grading (2);
int qmin = gr1.q,
qmax = gr2.q;
if (qmax < qmin)
std::swap (qmin, qmax);
assert (qmax == qmin + 2);
fprintf (outfp, "s(%s; %s) = %d\n", knot, field, qmin + 1);
}
else
{
fprintf (stderr, "error: unknown invariant %s\n", invariant);
exit (EXIT_FAILURE);
}
}
void
sage_show (FILE *fp,
map<grading, basedvector<unsigned, 1> > hq_gens,
ptr<const module<Z2> > H)
{
fprintf (fp, "hom={");
bool first = 1;
for (map<grading, basedvector<unsigned, 1> >::const_iter i = hq_gens; i; i ++)
{
if (first)
first = 0;
else
fprintf (fp, ", ");
fprintf (fp, "(%d, %d): %d", i.key ().h, i.key ().q, i.val ().size ());
}
fprintf (fp, "}\n");
}
void
sage_show (FILE *fp,
map<grading, basedvector<unsigned, 1> > hq_gens,
std::string name,
grading delta,
mod_map<Z2> f)
{
fprintf (fp, "%s={", name.c_str ());
bool first = 1;
for (map<grading, basedvector<unsigned, 1> >::const_iter i = hq_gens; i; i ++)
{
grading from_hq = i.key ();
basedvector<unsigned, 1> from_gens = i.val ();
grading to_hq = from_hq + delta;
if (hq_gens % to_hq)
{
basedvector<unsigned, 1> to_gens = hq_gens(to_hq);
if (first)
first = 0;
else
fprintf (fp, ", ");
fprintf (fp, "(%d, %d): [", from_hq.h, from_hq.q);
bool first2 = 1;
for (unsigned j = 1; j <= from_gens.size (); j ++)
{
unsigned gj = from_gens[j];
if (first2)
first2 = 0;
else
fprintf (fp, ", ");
fprintf (fp, "(");
for (unsigned k = 1; k <= to_gens.size (); k ++)
{
unsigned gk = to_gens[k];
if (k > 1)
fprintf (fp, ", ");
if (f[gj](gk) == 1)
fprintf (fp, "1");
else
{
assert (f[gj](gk) == 0);
fprintf (fp, "0");
}
}
fprintf (fp, ")");
}
fprintf (fp, "]");
}
}
fprintf (fp, "}\n");
}
void
sage_show_khsq (FILE *fp,
ptr<const module<Z2> > H,
mod_map<Z2> sq1,
mod_map<Z2> sq2)
{
unsigned n = H->dim ();
map<grading, basedvector<unsigned, 1> > hq_gens;
for (unsigned i = 1; i <= H->dim (); i ++)
hq_gens[H->generator_grading (i)].append (i);
unsigned t = 0;
for (map<grading, basedvector<unsigned, 1> >::const_iter i = hq_gens; i; i ++)
t += i.val ().size ();
assert (t == n);
sage_show (fp, hq_gens, H);
sage_show (fp, hq_gens, "sq1", grading (1, 0), sq1);
sage_show (fp, hq_gens, "sq2", grading (2, 0), sq2);
}
void
compute_sq2 ()
{
cube<Z2> c (kd);
mod_map<Z2> d = c.compute_d (1, 0, 0, 0, 0);
chain_complex_simplifier<Z2> s (c.khC, d, maybe<int> (1), maybe<int> (0));
assert (s.new_d == 0);
steenrod_square sq (c, d, s);
mod_map<Z2> sq1 = sq.sq1 ();
mod_map<Z2> sq2 = sq.sq2 ();
ptr<const module<Z2> > H = sq1.domain ();
sage_show_khsq (outfp, H, sq1, sq2);
}
int
main (int argc, char **argv)
{
program_name = argv[0];
const char *file = 0;
for (int i = 1; i < argc; i ++)
{
if (argv[i][0] == '-')
{
if (strcmp (argv[i], "-r") == 0)
reduced = 1;
else if (strcmp (argv[i], "-h") == 0)
{
usage ();
exit (EXIT_SUCCESS);
}
else if (!strcmp (argv[i], "-v"))
verbose = 1;
else if (!strcmp (argv[i], "-f"))
{
i ++;
if (i == argc)
{
fprintf (stderr, "error: missing argument to option `-f'\n");
exit (EXIT_FAILURE);
}
field = argv[i];
}
else if (!strcmp (argv[i], "-o"))
{
i ++;
if (i == argc)
{
fprintf (stderr, "error: missing argument to option `-o'\n");
exit (EXIT_FAILURE);
}
file = argv[i];
}
else
{
fprintf (stderr, "error: unknown argument `%s'\n", argv[1]);
fprintf (stderr, " use -h for usage\n");
exit (EXIT_FAILURE);
}
}
else
{
if (knot)
{
fprintf (stderr, "error: too many arguments\n");
fprintf (stderr, " use -h for usage\n");
exit (EXIT_FAILURE);
}
else if (invariant)
knot = argv[i];
else
{
assert (invariant == 0);
invariant = argv[i];
}
}
}
if (!knot)
{
fprintf (stderr, "error: too few arguments, <invariant> or <knot> missing\n");
fprintf (stderr, " use -h for usage\n");
exit (EXIT_FAILURE);
}
if (file)
{
outfp = fopen (file, "w");
if (!outfp)
{
stderror ("fopen: %s", file);
exit (EXIT_FAILURE);
}
}
else
outfp = stdout;
kd = parse_knot (knot);
kd.marked_edge = 1;
if (!strcmp (invariant, "sq2"))
{
if (strcmp (field, "Z2"))
{
fprintf (stderr, "warning: sq2 only defined over Z2, ignoring -f %s\n", field);
field = "Z2";
}
compute_sq2 ();
}
else if (!strcmp (invariant, "gss"))
{
if (strcmp (field, "Z2"))
{
fprintf (stderr, "warning: gss only defined over Z2, ignoring -f %s\n", field);
field = "Z2";
}
compute_gss ();
}
else
{
if (!strcmp (field, "Z2"))
compute_invariant<Z2> ();
else if (!strcmp (field, "Z3"))
compute_invariant<Zp<3> > ();
else if (!strcmp (field, "Q"))
compute_invariant<Q> ();
else
{
fprintf (stderr, "error: unknown field %s\n", field);
exit (EXIT_FAILURE);
}
}
if (file)
fclose (outfp);
}

View File

@ -22,7 +22,7 @@ knot_diagram::knot_diagram (const planar_diagram &pd)
crossings[c] = basedvector<unsigned, 1> (4);
}
smallbitset done (num_edges ());
set<unsigned> done;
for (unsigned c0 = 1; c0 <= n_crossings; c0 ++)
{
for (unsigned i0 = 1; i0 <= 2; i0 ++)
@ -82,10 +82,10 @@ public:
public:
dt_layout (const dt_code &dt, knot_diagram &kd_);
dt_layout (const dt_layout &); // doesn't exist
dt_layout (const dt_layout &) = delete;
~dt_layout () { }
dt_layout &operator = (const dt_layout &); // doesn't exist
dt_layout &operator = (const dt_layout &) = delete;
unsigned find_crossing (unsigned prevc, unsigned previ, unsigned target,
bool under, unsigned dir);
@ -454,6 +454,60 @@ knot_diagram::knot_diagram (sublink,
calculate_nminus_nplus ();
}
knot_diagram::knot_diagram (disjoint_union,
const knot_diagram &kd1,
const knot_diagram &kd2)
: name(kd1.name + "+" + kd2.name),
n_crossings(kd1.n_crossings + kd2.n_crossings),
marked_edge(0),
crossings(n_crossings),
nminus(kd1.nminus + kd2.nminus),
nplus(kd1.nplus + kd2.nplus)
{
assert (kd1.marked_edge == 0);
assert (kd2.marked_edge == 0);
for (unsigned i = 1; i <= n_crossings; i ++)
crossings[i] = basedvector<unsigned, 1> (4);
for (unsigned i = 1; i <= kd1.n_crossings; i ++)
for (unsigned j = 1; j <= 4; j ++)
crossings[i][j] = kd1.crossings[i][j];
for (unsigned e = 1; e <= kd1.num_edges (); e ++)
{
if (kd1.edge_smoothing_oriented % e)
edge_smoothing_oriented.push (e);
}
for (unsigned i = 1; i <= kd2.n_crossings; i ++)
for (unsigned j = 1; j <= 4; j ++)
crossings[kd1.n_crossings + i][j] = kd1.num_epts () + kd2.crossings[i][j];
for (unsigned e = 1; e <= kd2.num_edges (); e ++)
{
if (kd2.edge_smoothing_oriented % e)
edge_smoothing_oriented.push (kd1.num_edges () + e);
}
// ?? break this out into aux function
ept_crossing = basedvector<unsigned, 1> (num_epts ());
ept_index = basedvector<unsigned, 1> (num_epts ());
for (unsigned i = 1; i <= n_crossings; i ++)
{
for (unsigned j = 1; j <= 4; j ++)
{
unsigned p = crossings[i][j];
ept_crossing[p] = i;
ept_index[p] = j;
}
}
#ifndef NDEBUG
check_crossings ();
#endif
}
knot_diagram::knot_diagram (mirror, const knot_diagram &kd)
: name("mirror(" + kd.name + ")"),
n_crossings(kd.n_crossings),
@ -521,6 +575,63 @@ knot_diagram::rotate_crossing (unsigned c)
}
}
unsigned
knot_diagram::total_linking_number () const
{
unionfind<1> u (num_edges ());
for (unsigned i = 1; i <= n_crossings; i ++)
{
u.join (ept_edge (crossings[i][1]),
ept_edge (crossings[i][3]));
u.join (ept_edge (crossings[i][2]),
ept_edge (crossings[i][4]));
}
unsigned n = u.num_sets ();
map<unsigned, unsigned> root_comp;
unsigned t = 0;
for (unsigned i = 1; i <= num_edges (); i ++)
{
if (u.find (i) == i)
{
++ t;
root_comp.push (i, t);
}
}
assert (t == n);
unsigned total_lk = 0;
for (unsigned i = 1; i <= n; i ++)
for (unsigned j = i + 1; j <= n; j ++)
{
if (i == j)
continue;
int lk = 0;
for (unsigned x = 1; x <= n_crossings; x ++)
{
unsigned r1 = root_comp(u.find (ept_edge (crossings[x][1]))),
r2 = root_comp(u.find (ept_edge (crossings[x][2])));
if (((r1 == i) && (r2 == j))
|| ((r2 == i) && (r1 == j)))
{
if (is_to_ept (crossings[x][1]) == is_to_ept (crossings[x][4]))
lk ++;
else
lk --;
}
}
assert (is_even (lk));
lk /= 2;
total_lk += abs (lk);
}
return total_lk;
}
knot_diagram::knot_diagram (connect_sum,
const knot_diagram &d1,
const knot_diagram &d2)

View File

@ -1,4 +1,14 @@
// for building knot_diagram
inline unsigned edge_from_ept (unsigned e)
{
return e * 2 - 1;
}
inline unsigned edge_to_ept (unsigned e)
{
return e * 2;
}
static inline unsigned
add_base1_mod4 (unsigned x, unsigned y)
{
@ -11,6 +21,7 @@ add_base1_mod4 (unsigned x, unsigned y)
enum mirror { MIRROR };
enum connect_sum { CONNECT_SUM };
enum sublink { SUBLINK };
enum disjoint_union { DISJOINT_UNION };
class knot_diagram
{
@ -122,6 +133,9 @@ class knot_diagram
knot_diagram (sublink,
smallbitset c,
const knot_diagram &kd);
knot_diagram (disjoint_union,
const knot_diagram &kd1,
const knot_diagram &kd2);
knot_diagram (const std::string &name_, unsigned n_crossings_, unsigned crossings_ar[][4]);
knot_diagram (const std::string &name_, const basedvector<basedvector<unsigned, 1>, 1> &crossings_);
@ -157,6 +171,8 @@ class knot_diagram
int writhe () const { return (int)nplus - (int)nminus; }
unsigned total_linking_number () const;
basedvector<basedvector<int, 1>, 1> planar_diagram_crossings () const;
hash_t hash_self () const;

View File

@ -1,9 +1,8 @@
/* A Bison parser, made by GNU Bison 2.4.3. */
/* A Bison parser, made by GNU Bison 2.6.5. */
/* Skeleton implementation for Bison LALR(1) parsers in C++
Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
Software Foundation, Inc.
Copyright (C) 2002-2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -34,37 +33,41 @@
/* First part of user declarations. */
/* Line 311 of lalr1.cc */
#line 40 "knot_parser/knot_parser.cc"
/* Line 278 of lalr1.cc */
#line 38 "knot_parser/knot_parser.cc"
#include "knot_parser.hh"
/* User implementation prologue. */
/* Line 317 of lalr1.cc */
#line 49 "knot_parser/knot_parser.cc"
/* Line 284 of lalr1.cc */
#line 46 "knot_parser/knot_parser.cc"
/* Unqualified %code blocks. */
/* Line 318 of lalr1.cc */
/* Line 285 of lalr1.cc */
#line 15 "knot_parser/knot_parser.yy"
#define YY_DECL \
yy::knot_parser::token_type knot_yylex (yy::knot_parser::semantic_type *yylval)
YY_DECL;
/* Line 318 of lalr1.cc */
#line 29 "knot_parser/knot_parser.yy"
/* Line 285 of lalr1.cc */
#line 30 "knot_parser/knot_parser.yy"
#define yylex knot_yylex
/* Line 285 of lalr1.cc */
#line 62 "knot_parser/knot_parser.cc"
/* Line 318 of lalr1.cc */
#line 68 "knot_parser/knot_parser.cc"
# ifndef YY_NULL
# if defined __cplusplus && 201103L <= __cplusplus
# define YY_NULL nullptr
# else
# define YY_NULL 0
# endif
# endif
#ifndef YY_
# if defined YYENABLE_NLS && YYENABLE_NLS
@ -78,6 +81,27 @@ YY_DECL;
# endif
#endif
#define YYRHSLOC(Rhs, K) ((Rhs)[K])
/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
If N is 0, then set CURRENT to the empty location which ends
the previous symbol: RHS[0] (always defined). */
# ifndef YYLLOC_DEFAULT
# define YYLLOC_DEFAULT(Current, Rhs, N) \
do \
if (N) \
{ \
(Current).begin = YYRHSLOC (Rhs, 1).begin; \
(Current).end = YYRHSLOC (Rhs, N).end; \
} \
else \
{ \
(Current).begin = (Current).end = YYRHSLOC (Rhs, 0).end; \
} \
while (/*CONSTCOND*/ false)
# endif
/* Suppress unused-variable warnings by "using" E. */
#define YYUSE(e) ((void) (e))
@ -128,49 +152,8 @@ do { \
namespace yy {
/* Line 380 of lalr1.cc */
#line 134 "knot_parser/knot_parser.cc"
#if YYERROR_VERBOSE
/* Return YYSTR after stripping away unnecessary quotes and
backslashes, so that it's suitable for yyerror. The heuristic is
that double-quoting is unnecessary unless the string contains an
apostrophe, a comma, or backslash (other than backslash-backslash).
YYSTR is taken from yytname. */
std::string
knot_parser::yytnamerr_ (const char *yystr)
{
if (*yystr == '"')
{
std::string yyr = "";
char const *yyp = yystr;
for (;;)
switch (*++yyp)
{
case '\'':
case ',':
goto do_not_strip_quotes;
case '\\':
if (*++yyp != '\\')
goto do_not_strip_quotes;
/* Fall through. */
default:
yyr += *yyp;
break;
case '"':
return yyr;
}
do_not_strip_quotes: ;
}
return yystr;
}
#endif
/* Line 352 of lalr1.cc */
#line 157 "knot_parser/knot_parser.cc"
/// Build a parser object.
knot_parser::knot_parser (knot_diagram &parsed_knot_yyarg)
@ -198,6 +181,9 @@ namespace yy {
{
YYUSE (yylocationp);
YYUSE (yyvaluep);
std::ostream& yyo = debug_stream ();
std::ostream& yyoutput = yyo;
YYUSE (yyoutput);
switch (yytype)
{
default:
@ -271,6 +257,18 @@ namespace yy {
}
#endif
inline bool
knot_parser::yy_pact_value_is_default_ (int yyvalue)
{
return yyvalue == yypact_ninf_;
}
inline bool
knot_parser::yy_table_value_is_error_ (int yyvalue)
{
return yyvalue == yytable_ninf_;
}
int
knot_parser::parse ()
{
@ -278,17 +276,18 @@ namespace yy {
int yychar = yyempty_;
int yytoken = 0;
/* State. */
// State.
int yyn;
int yylen = 0;
int yystate = 0;
/* Error handling. */
// Error handling.
int yynerrs_ = 0;
int yyerrstatus_ = 0;
/// Semantic value of the lookahead.
semantic_type yylval;
static semantic_type yyval_default;
semantic_type yylval = yyval_default;
/// Location of the lookahead.
location_type yylloc;
/// The locations where the error started and ended.
@ -330,7 +329,7 @@ namespace yy {
/* Try to take a decision without lookahead. */
yyn = yypact_[yystate];
if (yyn == yypact_ninf_)
if (yy_pact_value_is_default_ (yyn))
goto yydefault;
/* Read a lookahead token. */
@ -340,7 +339,6 @@ namespace yy {
yychar = yylex (&yylval);
}
/* Convert token to internal form. */
if (yychar <= yyeof_)
{
@ -363,8 +361,8 @@ namespace yy {
yyn = yytable_[yyn];
if (yyn <= 0)
{
if (yyn == 0 || yyn == yytable_ninf_)
goto yyerrlab;
if (yy_table_value_is_error_ (yyn))
goto yyerrlab;
yyn = -yyn;
goto yyreduce;
}
@ -418,17 +416,35 @@ namespace yy {
YY_REDUCE_PRINT (yyn);
switch (yyn)
{
case 10:
case 2:
/* Line 661 of lalr1.cc */
#line 60 "knot_parser/knot_parser.yy"
{
parsed_knot = *(yysemantic_stack_[(1) - (1)].kd);
delete (yysemantic_stack_[(1) - (1)].kd);
}
break;
/* Line 678 of lalr1.cc */
#line 67 "knot_parser/knot_parser.yy"
case 4:
/* Line 661 of lalr1.cc */
#line 69 "knot_parser/knot_parser.yy"
{
(yyval.kd) = new knot_diagram (DISJOINT_UNION, *(yysemantic_stack_[(2) - (1)].kd), *(yysemantic_stack_[(2) - (2)].kd));
delete (yysemantic_stack_[(2) - (1)].kd);
delete (yysemantic_stack_[(2) - (2)].kd);
}
break;
case 13:
/* Line 661 of lalr1.cc */
#line 89 "knot_parser/knot_parser.yy"
{
unsigned n = (yysemantic_stack_[(3) - (1)].integer),
k = (yysemantic_stack_[(3) - (3)].integer);
if (n >= 1 && n <= 10
&& k >= 1 && k <= rolfsen_crossing_knots (n))
parsed_knot = knot_diagram (rolfsen_knot (n, k));
(yyval.kd) = new knot_diagram (rolfsen_knot (n, k));
else
{
fprintf (stderr, "knot_parser: no such Rolfsen knot `%d_%d'\n",
@ -438,10 +454,9 @@ namespace yy {
}
break;
case 11:
/* Line 678 of lalr1.cc */
#line 85 "knot_parser/knot_parser.yy"
case 14:
/* Line 661 of lalr1.cc */
#line 107 "knot_parser/knot_parser.yy"
{
unsigned n = (yysemantic_stack_[(3) - (1)].integer),
k = (yysemantic_stack_[(3) - (3)].integer);
@ -449,7 +464,7 @@ namespace yy {
if (n >= 1 && n <= 16
&& k >= 1 && k <= htw_knots (n, alt))
parsed_knot = knot_diagram (htw_knot (n, alt, k));
(yyval.kd) = new knot_diagram (htw_knot (n, alt, k));
else
{
fprintf (stderr, "knot_parser: no such HTW knot `%d%c%d'\n",
@ -459,10 +474,9 @@ namespace yy {
}
break;
case 12:
/* Line 678 of lalr1.cc */
#line 104 "knot_parser/knot_parser.yy"
case 15:
/* Line 661 of lalr1.cc */
#line 126 "knot_parser/knot_parser.yy"
{
unsigned n = (yysemantic_stack_[(4) - (2)].integer),
k = (yysemantic_stack_[(4) - (4)].integer);
@ -470,7 +484,7 @@ namespace yy {
if (n >= 1 && n <= 14
&& k >= 1 && k <= mt_links (n, alt))
parsed_knot = knot_diagram (mt_link (n, alt, k));
(yyval.kd) = new knot_diagram (mt_link (n, alt, k));
else
{
fprintf (stderr, "knot_parser: no such MT link `%d%c%d'\n",
@ -480,75 +494,66 @@ namespace yy {
}
break;
case 13:
/* Line 678 of lalr1.cc */
#line 123 "knot_parser/knot_parser.yy"
{ parsed_knot = knot_diagram (planar_diagram ("<parsed>", *(yysemantic_stack_[(4) - (3)].int_vec2))); }
break;
case 14:
/* Line 678 of lalr1.cc */
#line 125 "knot_parser/knot_parser.yy"
{ parsed_knot = knot_diagram (planar_diagram ("<parsed>", *(yysemantic_stack_[(4) - (3)].int_vec2))); }
break;
case 15:
/* Line 678 of lalr1.cc */
#line 130 "knot_parser/knot_parser.yy"
{
basedvector<basedvector<int, 1>, 1> even_labels (1);
even_labels[1] = *(yysemantic_stack_[(4) - (3)].int_vec);
parsed_knot = knot_diagram (dt_code ("<parsed>", even_labels));
}
break;
case 16:
/* Line 678 of lalr1.cc */
#line 136 "knot_parser/knot_parser.yy"
{ parsed_knot = knot_diagram (dt_code ("<parsed>", *(yysemantic_stack_[(4) - (3)].int_vec2))); }
/* Line 661 of lalr1.cc */
#line 145 "knot_parser/knot_parser.yy"
{ (yyval.kd) = new knot_diagram (planar_diagram ("<parsed>", *(yysemantic_stack_[(4) - (3)].int_vec2))); }
break;
case 17:
/* Line 678 of lalr1.cc */
#line 138 "knot_parser/knot_parser.yy"
{ parsed_knot = knot_diagram (dt_code ("<parsed>", (yysemantic_stack_[(4) - (3)].string))); }
/* Line 661 of lalr1.cc */
#line 147 "knot_parser/knot_parser.yy"
{ (yyval.kd) = new knot_diagram (planar_diagram ("<parsed>", *(yysemantic_stack_[(4) - (3)].int_vec2))); }
break;
case 18:
/* Line 678 of lalr1.cc */
#line 143 "knot_parser/knot_parser.yy"
{ parsed_knot = knot_diagram (torus_knot ((yysemantic_stack_[(6) - (3)].integer), (yysemantic_stack_[(6) - (5)].integer))); }
/* Line 661 of lalr1.cc */
#line 152 "knot_parser/knot_parser.yy"
{
basedvector<basedvector<int, 1>, 1> even_labels (1);
even_labels[1] = *(yysemantic_stack_[(4) - (3)].int_vec);
(yyval.kd) = new knot_diagram (dt_code ("<parsed>", even_labels));
}
break;
case 19:
/* Line 678 of lalr1.cc */
#line 148 "knot_parser/knot_parser.yy"
{ parsed_knot = knot_diagram (braid ((yysemantic_stack_[(6) - (3)].integer), *(yysemantic_stack_[(6) - (5)].int_vec))); }
/* Line 661 of lalr1.cc */
#line 158 "knot_parser/knot_parser.yy"
{ (yyval.kd) = new knot_diagram (dt_code ("<parsed>", *(yysemantic_stack_[(4) - (3)].int_vec2))); }
break;
case 20:
/* Line 661 of lalr1.cc */
#line 160 "knot_parser/knot_parser.yy"
{ (yyval.kd) = new knot_diagram (dt_code ("<parsed>", (yysemantic_stack_[(4) - (3)].string))); }
break;
/* Line 678 of lalr1.cc */
#line 153 "knot_parser/knot_parser.yy"
case 21:
/* Line 661 of lalr1.cc */
#line 165 "knot_parser/knot_parser.yy"
{ (yyval.kd) = new knot_diagram (torus_knot ((yysemantic_stack_[(6) - (3)].integer), (yysemantic_stack_[(6) - (5)].integer))); }
break;
case 22:
/* Line 661 of lalr1.cc */
#line 170 "knot_parser/knot_parser.yy"
{ (yyval.kd) = new knot_diagram (braid ((yysemantic_stack_[(6) - (3)].integer), *(yysemantic_stack_[(6) - (5)].int_vec))); }
break;
case 23:
/* Line 661 of lalr1.cc */
#line 175 "knot_parser/knot_parser.yy"
{
unsigned unknot_ar[1][4] = {
{ 2, 1, 3, 4, },
};
parsed_knot = knot_diagram ("U", 1, unknot_ar);
(yyval.kd) = new knot_diagram ("U", 1, unknot_ar);
}
break;
case 23:
/* Line 678 of lalr1.cc */
#line 168 "knot_parser/knot_parser.yy"
case 26:
/* Line 661 of lalr1.cc */
#line 190 "knot_parser/knot_parser.yy"
{
basedvector<basedvector<int, 1>, 1> *v
= new basedvector<basedvector<int, 1>, 1> ();
@ -557,10 +562,9 @@ namespace yy {
}
break;
case 24:
/* Line 678 of lalr1.cc */
#line 175 "knot_parser/knot_parser.yy"
case 27:
/* Line 661 of lalr1.cc */
#line 197 "knot_parser/knot_parser.yy"
{
basedvector<basedvector<int, 1>, 1> *v = (yysemantic_stack_[(3) - (1)].int_vec2);
v->append (*(yysemantic_stack_[(3) - (3)].int_vec));
@ -568,24 +572,21 @@ namespace yy {
}
break;
case 25:
/* Line 678 of lalr1.cc */
#line 184 "knot_parser/knot_parser.yy"
case 28:
/* Line 661 of lalr1.cc */
#line 206 "knot_parser/knot_parser.yy"
{ (yyval.int_vec) = (yysemantic_stack_[(3) - (2)].int_vec); }
break;
case 26:
/* Line 678 of lalr1.cc */
#line 186 "knot_parser/knot_parser.yy"
case 29:
/* Line 661 of lalr1.cc */
#line 208 "knot_parser/knot_parser.yy"
{ (yyval.int_vec) = (yysemantic_stack_[(3) - (2)].int_vec); }
break;
case 27:
/* Line 678 of lalr1.cc */
#line 191 "knot_parser/knot_parser.yy"
case 30:
/* Line 661 of lalr1.cc */
#line 213 "knot_parser/knot_parser.yy"
{
basedvector<int, 1> *v =
new basedvector<int, 1> ();
@ -594,10 +595,9 @@ namespace yy {
}
break;
case 28:
/* Line 678 of lalr1.cc */
#line 198 "knot_parser/knot_parser.yy"
case 31:
/* Line 661 of lalr1.cc */
#line 220 "knot_parser/knot_parser.yy"
{
basedvector<int, 1> *v = (yysemantic_stack_[(3) - (1)].int_vec);
v->append ((yysemantic_stack_[(3) - (3)].integer));
@ -605,10 +605,9 @@ namespace yy {
}
break;
case 29:
/* Line 678 of lalr1.cc */
#line 207 "knot_parser/knot_parser.yy"
case 32:
/* Line 661 of lalr1.cc */
#line 229 "knot_parser/knot_parser.yy"
{
basedvector<basedvector<int, 1>, 1> *v
= new basedvector<basedvector<int, 1>, 1> ();
@ -617,10 +616,9 @@ namespace yy {
}
break;
case 30:
/* Line 678 of lalr1.cc */
#line 214 "knot_parser/knot_parser.yy"
case 33:
/* Line 661 of lalr1.cc */
#line 236 "knot_parser/knot_parser.yy"
{
basedvector<basedvector<int, 1>, 1> *v = (yysemantic_stack_[(3) - (1)].int_vec2);
v->append (*(yysemantic_stack_[(3) - (3)].int_vec));
@ -628,10 +626,9 @@ namespace yy {
}
break;
case 31:
/* Line 678 of lalr1.cc */
#line 223 "knot_parser/knot_parser.yy"
case 34:
/* Line 661 of lalr1.cc */
#line 245 "knot_parser/knot_parser.yy"
{
basedvector<int, 1> *v
= new basedvector<int, 1> ();
@ -644,12 +641,22 @@ namespace yy {
break;
/* Line 678 of lalr1.cc */
#line 650 "knot_parser/knot_parser.cc"
/* Line 661 of lalr1.cc */
#line 646 "knot_parser/knot_parser.cc"
default:
break;
}
/* User semantic actions sometimes alter yychar, and that requires
that yytoken be updated with the new translation. We take the
approach of translating immediately before every use of yytoken.
One alternative is translating here after every semantic action,
but that translation would be missed if the semantic action
invokes YYABORT, YYACCEPT, or YYERROR immediately after altering
yychar. In the case of YYABORT or YYACCEPT, an incorrect
destructor might then be invoked immediately. In the case of
YYERROR, subsequent parser actions might lead to an incorrect
destructor call or verbose syntax error message before the
lookahead is translated. */
YY_SYMBOL_PRINT ("-> $$ =", yyr1_[yyn], &yyval, &yyloc);
yypop_ (yylen);
@ -673,11 +680,17 @@ namespace yy {
| yyerrlab -- here on detecting error |
`------------------------------------*/
yyerrlab:
/* Make sure we have latest lookahead translation. See comments at
user semantic actions for why this is necessary. */
yytoken = yytranslate_ (yychar);
/* If not already recovering from an error, report this error. */
if (!yyerrstatus_)
{
++yynerrs_;
error (yylloc, yysyntax_error_ (yystate));
if (yychar == yyempty_)
yytoken = yyempty_;
error (yylloc, yysyntax_error_ (yystate, yytoken));
}
yyerror_range[1] = yylloc;
@ -732,7 +745,7 @@ namespace yy {
for (;;)
{
yyn = yypact_[yystate];
if (yyn != yypact_ninf_)
if (!yy_pact_value_is_default_ (yyn))
{
yyn += yyterror_;
if (0 <= yyn && yyn <= yylast_ && yycheck_[yyn] == yyterror_)
@ -782,7 +795,13 @@ namespace yy {
yyreturn:
if (yychar != yyempty_)
yydestruct_ ("Cleanup: discarding lookahead", yytoken, &yylval, &yylloc);
{
/* Make sure we have latest lookahead translation. See comments
at user semantic actions for why this is necessary. */
yytoken = yytranslate_ (yychar);
yydestruct_ ("Cleanup: discarding lookahead", yytoken, &yylval,
&yylloc);
}
/* Do not reclaim the symbols of the rule which action triggered
this YYABORT or YYACCEPT. */
@ -801,117 +820,76 @@ namespace yy {
// Generate an error message.
std::string
knot_parser::yysyntax_error_ (int yystate)
knot_parser::yysyntax_error_ (int, int)
{
std::string res;
YYUSE (yystate);
#if YYERROR_VERBOSE
int yyn = yypact_[yystate];
if (yypact_ninf_ < yyn && yyn <= yylast_)
{
/* Start YYX at -YYN if negative to avoid negative indexes in
YYCHECK. */
int yyxbegin = yyn < 0 ? -yyn : 0;
/* Stay within bounds of both yycheck and yytname. */
int yychecklim = yylast_ - yyn + 1;
int yyxend = yychecklim < yyntokens_ ? yychecklim : yyntokens_;
int count = 0;
for (int x = yyxbegin; x < yyxend; ++x)
if (yycheck_[x + yyn] == x && x != yyterror_)
++count;
// FIXME: This method of building the message is not compatible
// with internationalization. It should work like yacc.c does it.
// That is, first build a string that looks like this:
// "syntax error, unexpected %s or %s or %s"
// Then, invoke YY_ on this string.
// Finally, use the string as a format to output
// yytname_[tok], etc.
// Until this gets fixed, this message appears in English only.
res = "syntax error, unexpected ";
res += yytnamerr_ (yytname_[tok]);
if (count < 5)
{
count = 0;
for (int x = yyxbegin; x < yyxend; ++x)
if (yycheck_[x + yyn] == x && x != yyterror_)
{
res += (!count++) ? ", expecting " : " or ";
res += yytnamerr_ (yytname_[x]);
}
}
}
else
#endif
res = YY_("syntax error");
return res;
return YY_("syntax error");
}
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
const signed char knot_parser::yypact_ninf_ = -36;
const signed char knot_parser::yypact_ninf_ = -39;
const signed char
knot_parser::yypact_[] =
{
-1, 10, -9, 25, 26, 37, 9, -36, 43, -36,
-36, -36, -36, -36, -36, -36, -36, -36, -36, 41,
42, -7, -3, 44, 24, 45, -36, -36, -36, 30,
46, 46, 7, -36, 11, -36, -36, 33, 12, 15,
-4, 48, 34, 49, 16, -2, -36, 0, -36, 47,
-36, -36, -36, 51, 0, -36, 53, 38, -36, -36,
-36, -36, -36, 50, 39, 55, -36, -36, 52, 57,
54, 58, 59, -36
-1, 10, -9, 25, 26, 37, 9, -39, 43, -1,
-39, -39, -39, -39, -39, -39, -39, -39, -39, -39,
-39, 41, 42, -7, -3, 44, 24, 45, -39, -1,
-39, -39, 30, 46, 46, 7, -39, 11, -39, -39,
33, 12, 15, -4, 48, 34, 49, 16, -2, -39,
0, -39, 47, -39, -39, -39, 51, 0, -39, 53,
38, -39, -39, -39, -39, -39, 50, 39, 55, -39,
-39, 52, 57, 54, 58, 59, -39
};
/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE
doesn't specify something else to do. Zero means the default is an
error. */
/* YYDEFACT[S] -- default reduction number in state S. Performed when
YYTABLE doesn't specify something else to do. Zero means the
default is an error. */
const unsigned char
knot_parser::yydefact_[] =
{
0, 0, 0, 0, 0, 0, 0, 20, 0, 2,
3, 4, 5, 6, 7, 9, 8, 21, 22, 0,
0, 0, 0, 0, 0, 0, 1, 10, 11, 0,
0, 0, 0, 23, 0, 29, 27, 0, 0, 0,
0, 0, 0, 0, 0, 0, 13, 0, 14, 0,
17, 16, 15, 0, 0, 12, 0, 0, 26, 25,
24, 30, 28, 0, 0, 0, 19, 18, 0, 0,
0, 0, 0, 31
0, 0, 0, 0, 0, 0, 0, 23, 0, 2,
3, 5, 6, 7, 8, 9, 10, 12, 11, 24,
25, 0, 0, 0, 0, 0, 0, 0, 1, 4,
13, 14, 0, 0, 0, 0, 26, 0, 32, 30,
0, 0, 0, 0, 0, 0, 0, 0, 0, 16,
0, 17, 0, 20, 19, 18, 0, 0, 15, 0,
0, 29, 28, 27, 33, 31, 0, 0, 0, 22,
21, 0, 0, 0, 0, 0, 34
};
/* YYPGOTO[NTERM-NUM]. */
const signed char
knot_parser::yypgoto_[] =
{
-36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
40, 56, -35, 8, -36, 13
-39, -39, 62, -39, -39, -39, -39, -39, -39, -39,
-39, -39, 40, 56, -38, 5, -39, 13
};
/* YYDEFGOTO[NTERM-NUM]. */
const signed char
knot_parser::yydefgoto_[] =
{
-1, 8, 9, 10, 11, 12, 13, 14, 15, 16,
20, 32, 33, 39, 34, 35
-1, 8, 29, 10, 11, 12, 13, 14, 15, 16,
17, 18, 22, 35, 36, 42, 37, 38
};
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
positive, shift that token. If negative, reduce the rule which
number is the opposite. If zero, do what YYDEFACT says. */
number is the opposite. If YYTABLE_NINF_, syntax error. */
const signed char knot_parser::yytable_ninf_ = -1;
const unsigned char
knot_parser::yytable_[] =
{
36, 29, 1, 2, 3, 4, 5, 21, 6, 30,
7, 37, 60, 30, 31, 54, 30, 53, 31, 63,
59, 31, 17, 18, 46, 19, 47, 25, 48, 51,
49, 47, 52, 58, 53, 53, 17, 18, 44, 45,
24, 22, 23, 26, 27, 28, 43, 40, 42, 36,
50, 55, 57, 56, 62, 29, 64, 65, 68, 67,
70, 72, 61, 0, 41, 0, 0, 66, 0, 0,
0, 69, 0, 71, 0, 0, 73, 0, 38
39, 32, 1, 2, 3, 4, 5, 23, 6, 33,
7, 40, 63, 33, 34, 57, 33, 56, 34, 66,
62, 34, 19, 20, 49, 21, 50, 27, 51, 54,
52, 50, 55, 61, 56, 56, 19, 20, 47, 48,
26, 24, 25, 28, 30, 31, 46, 43, 45, 39,
53, 58, 60, 59, 65, 32, 67, 68, 71, 70,
73, 75, 9, 0, 0, 64, 44, 69, 0, 0,
0, 72, 0, 74, 0, 0, 76, 0, 0, 0,
41
};
/* YYCHECK. */
@ -919,13 +897,14 @@ namespace yy {
knot_parser::yycheck_[] =
{
3, 8, 3, 4, 5, 6, 7, 16, 9, 16,
11, 14, 47, 16, 21, 19, 16, 19, 21, 54,
11, 14, 50, 16, 21, 19, 16, 19, 21, 57,
22, 21, 12, 13, 17, 15, 19, 18, 17, 17,
19, 19, 17, 17, 19, 19, 12, 13, 30, 31,
19, 19, 17, 17, 19, 19, 12, 13, 33, 34,
3, 16, 16, 0, 3, 3, 16, 3, 3, 3,
17, 3, 3, 19, 3, 8, 3, 19, 3, 20,
3, 3, 49, -1, 24, -1, -1, 17, -1, -1,
-1, 19, -1, 19, -1, -1, 17, -1, 22
3, 3, 0, -1, -1, 52, 26, 17, -1, -1,
-1, 19, -1, 19, -1, -1, 17, -1, -1, -1,
24
};
/* STOS_[STATE-NUM] -- The (internal number of the) accessing
@ -934,13 +913,13 @@ namespace yy {
knot_parser::yystos_[] =
{
0, 3, 4, 5, 6, 7, 9, 11, 24, 25,
26, 27, 28, 29, 30, 31, 32, 12, 13, 15,
33, 16, 16, 16, 3, 18, 0, 3, 3, 8,
16, 21, 34, 35, 37, 38, 3, 14, 34, 36,
3, 33, 3, 16, 36, 36, 17, 19, 17, 19,
17, 17, 17, 19, 19, 3, 19, 3, 17, 22,
35, 38, 3, 35, 3, 19, 17, 20, 3, 19,
3, 19, 3, 17
26, 27, 28, 29, 30, 31, 32, 33, 34, 12,
13, 15, 35, 16, 16, 16, 3, 18, 0, 25,
3, 3, 8, 16, 21, 36, 37, 39, 40, 3,
14, 36, 38, 3, 35, 3, 16, 38, 38, 17,
19, 17, 19, 17, 17, 17, 19, 19, 3, 19,
3, 17, 22, 37, 40, 3, 37, 3, 19, 17,
20, 3, 19, 3, 19, 3, 17
};
#if YYDEBUG
@ -959,23 +938,23 @@ namespace yy {
const unsigned char
knot_parser::yyr1_[] =
{
0, 23, 24, 24, 24, 24, 24, 24, 24, 24,
25, 26, 27, 28, 28, 29, 29, 29, 30, 31,
32, 33, 33, 34, 34, 35, 35, 36, 36, 37,
37, 38
0, 23, 24, 25, 25, 26, 26, 26, 26, 26,
26, 26, 26, 27, 28, 29, 30, 30, 31, 31,
31, 32, 33, 34, 35, 35, 36, 36, 37, 37,
38, 38, 39, 39, 40
};
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
const unsigned char
knot_parser::yyr2_[] =
{
0, 2, 1, 1, 1, 1, 1, 1, 1, 1,
3, 3, 4, 4, 4, 4, 4, 4, 6, 6,
1, 1, 1, 1, 3, 3, 3, 1, 3, 1,
3, 10
0, 2, 1, 1, 2, 1, 1, 1, 1, 1,
1, 1, 1, 3, 3, 4, 4, 4, 4, 4,
4, 6, 6, 1, 1, 1, 1, 3, 3, 3,
1, 3, 1, 3, 10
};
#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
#if YYDEBUG
/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
First, the terminals, then, starting at \a yyntokens_, nonterminals. */
const char*
@ -983,30 +962,30 @@ namespace yy {
{
"\"end of file\"", "error", "$undefined", "INT", "PD", "DT", "BR",
"LINK", "X", "T", "U", "UNKNOT", "ALT", "NONALT", "STRING", "'_'", "'['",
"']'", "'('", "','", "')'", "'{'", "'}'", "$accept", "knot",
"rolfsen_knot", "htw_knot", "mt_link", "planar_diagram", "dt",
"']'", "'('", "','", "')'", "'{'", "'}'", "$accept", "entry", "knot",
"knot_1", "rolfsen_knot", "htw_knot", "mt_link", "planar_diagram", "dt",
"torus_link", "braid", "unknot", "alt_spec", "int_vec2", "int_vec",
"int_vec_1", "crossing_vec", "crossing", 0
"int_vec_1", "crossing_vec", "crossing", YY_NULL
};
#endif
#if YYDEBUG
/* YYRHS -- A `-1'-separated list of the rules' RHS. */
const knot_parser::rhs_number_type
knot_parser::yyrhs_[] =
{
24, 0, -1, 25, -1, 26, -1, 27, -1, 28,
-1, 29, -1, 30, -1, 32, -1, 31, -1, 3,
15, 3, -1, 3, 33, 3, -1, 7, 3, 33,
3, -1, 4, 16, 34, 17, -1, 4, 16, 37,
17, -1, 5, 16, 36, 17, -1, 5, 16, 34,
17, -1, 5, 16, 14, 17, -1, 9, 18, 3,
19, 3, 20, -1, 6, 16, 3, 19, 35, 17,
-1, 11, -1, 12, -1, 13, -1, 35, -1, 34,
19, 35, -1, 21, 36, 22, -1, 16, 36, 17,
-1, 3, -1, 36, 19, 3, -1, 38, -1, 37,
19, 38, -1, 8, 16, 3, 19, 3, 19, 3,
19, 3, 17, -1
24, 0, -1, 25, -1, 26, -1, 25, 25, -1,
27, -1, 28, -1, 29, -1, 30, -1, 31, -1,
32, -1, 34, -1, 33, -1, 3, 15, 3, -1,
3, 35, 3, -1, 7, 3, 35, 3, -1, 4,
16, 36, 17, -1, 4, 16, 39, 17, -1, 5,
16, 38, 17, -1, 5, 16, 36, 17, -1, 5,
16, 14, 17, -1, 9, 18, 3, 19, 3, 20,
-1, 6, 16, 3, 19, 37, 17, -1, 11, -1,
12, -1, 13, -1, 37, -1, 36, 19, 37, -1,
21, 38, 22, -1, 16, 38, 17, -1, 3, -1,
38, 19, 3, -1, 40, -1, 39, 19, 40, -1,
8, 16, 3, 19, 3, 19, 3, 19, 3, 17,
-1
};
/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
@ -1014,20 +993,20 @@ namespace yy {
const unsigned char
knot_parser::yyprhs_[] =
{
0, 0, 3, 5, 7, 9, 11, 13, 15, 17,
19, 23, 27, 32, 37, 42, 47, 52, 57, 64,
71, 73, 75, 77, 79, 83, 87, 91, 93, 97,
99, 103
0, 0, 3, 5, 7, 10, 12, 14, 16, 18,
20, 22, 24, 26, 30, 34, 39, 44, 49, 54,
59, 64, 71, 78, 80, 82, 84, 86, 90, 94,
98, 100, 104, 106, 110
};
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
const unsigned char
knot_parser::yyrline_[] =
{
0, 55, 55, 56, 57, 58, 59, 60, 61, 62,
66, 84, 103, 122, 124, 129, 135, 137, 142, 147,
152, 162, 163, 167, 174, 183, 185, 190, 197, 206,
213, 222
0, 59, 59, 67, 68, 77, 78, 79, 80, 81,
82, 83, 84, 88, 106, 125, 144, 146, 151, 157,
159, 164, 169, 174, 184, 185, 189, 196, 205, 207,
212, 219, 228, 235, 244
};
// Print the state stack on the debug stream.
@ -1102,10 +1081,10 @@ namespace yy {
}
const int knot_parser::yyeof_ = 0;
const int knot_parser::yylast_ = 78;
const int knot_parser::yynnts_ = 16;
const int knot_parser::yylast_ = 80;
const int knot_parser::yynnts_ = 18;
const int knot_parser::yyempty_ = -2;
const int knot_parser::yyfinal_ = 26;
const int knot_parser::yyfinal_ = 28;
const int knot_parser::yyterror_ = 1;
const int knot_parser::yyerrcode_ = 256;
const int knot_parser::yyntokens_ = 23;
@ -1115,13 +1094,10 @@ namespace yy {
} // yy
/* Line 1054 of lalr1.cc */
#line 1121 "knot_parser/knot_parser.cc"
/* Line 1056 of lalr1.cc */
#line 233 "knot_parser/knot_parser.yy"
/* Line 1106 of lalr1.cc */
#line 1099 "knot_parser/knot_parser.cc"
/* Line 1107 of lalr1.cc */
#line 255 "knot_parser/knot_parser.yy"
void
@ -1145,4 +1121,3 @@ parse_knot (const char *s)
return d;
}

View File

@ -1,9 +1,8 @@
/* A Bison parser, made by GNU Bison 2.4.3. */
/* A Bison parser, made by GNU Bison 2.6.5. */
/* Skeleton interface for Bison LALR(1) parsers in C++
Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
Software Foundation, Inc.
Copyright (C) 2002-2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -31,41 +30,30 @@
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
/**
** \file knot_parser/knot_parser.hh
** Define the yy::parser class.
*/
/* C++ LALR(1) parser skeleton written by Akim Demaille. */
#ifndef PARSER_HEADER_H
# define PARSER_HEADER_H
#ifndef YY_YY_KNOT_PARSER_KNOT_PARSER_HH_INCLUDED
# define YY_YY_KNOT_PARSER_KNOT_PARSER_HH_INCLUDED
/* "%code requires" blocks. */
/* Line 35 of lalr1.cc */
/* Line 36 of lalr1.cc */
#line 11 "knot_parser/knot_parser.yy"
#include <knotkit.h>
/* Line 35 of lalr1.cc */
#line 50 "knot_parser/knot_parser.hh"
/* Line 36 of lalr1.cc */
#line 52 "knot_parser/knot_parser.hh"
#include <string>
#include <iostream>
#include "stack.hh"
namespace yy {
/* Line 35 of lalr1.cc */
#line 61 "knot_parser/knot_parser.hh"
class position;
class location;
} // yy
/* Line 35 of lalr1.cc */
#line 68 "knot_parser/knot_parser.hh"
#include "location.hh"
/* Enabling traces. */
@ -73,43 +61,10 @@ namespace yy {
# define YYDEBUG 0
#endif
/* Enabling verbose error messages. */
#ifdef YYERROR_VERBOSE
# undef YYERROR_VERBOSE
# define YYERROR_VERBOSE 1
#else
# define YYERROR_VERBOSE 0
#endif
/* Enabling the token table. */
#ifndef YYTOKEN_TABLE
# define YYTOKEN_TABLE 0
#endif
/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
If N is 0, then set CURRENT to the empty location which ends
the previous symbol: RHS[0] (always defined). */
#ifndef YYLLOC_DEFAULT
# define YYLLOC_DEFAULT(Current, Rhs, N) \
do { \
if (N) \
{ \
(Current).begin = (Rhs)[1].begin; \
(Current).end = (Rhs)[N].end; \
} \
else \
{ \
(Current).begin = (Current).end = (Rhs)[0].end; \
} \
} while (false)
#endif
namespace yy {
/* Line 35 of lalr1.cc */
#line 113 "knot_parser/knot_parser.hh"
/* Line 36 of lalr1.cc */
#line 68 "knot_parser/knot_parser.hh"
/// A Bison parser.
class knot_parser
@ -119,8 +74,7 @@ namespace yy {
#ifndef YYSTYPE
union semantic_type
{
/* Line 35 of lalr1.cc */
/* Line 36 of lalr1.cc */
#line 21 "knot_parser/knot_parser.yy"
int integer;
@ -128,11 +82,11 @@ namespace yy {
basedvector<int, 1> *int_vec;
basedvector<basedvector<int, 1>, 1> *int_vec2;
const char *string;
knot_diagram *kd;
/* Line 35 of lalr1.cc */
#line 136 "knot_parser/knot_parser.hh"
/* Line 36 of lalr1.cc */
#line 90 "knot_parser/knot_parser.hh"
};
#else
typedef YYSTYPE semantic_type;
@ -194,7 +148,7 @@ namespace yy {
/// Generate an error message.
/// \param state the state where the error occurred.
/// \param tok the lookahead token.
virtual std::string yysyntax_error_ (int yystate);
virtual std::string yysyntax_error_ (int yystate, int tok);
#if YYDEBUG
/// \brief Report a symbol value on the debug stream.
@ -230,6 +184,14 @@ namespace yy {
/// The location stack.
location_stack_type yylocation_stack_;
/// Whether the given \c yypact_ value indicates a defaulted state.
/// \param yyvalue the value to check
static bool yy_pact_value_is_default_ (int yyvalue);
/// Whether the given \c yytable_ value indicates a syntax error.
/// \param yyvalue the value to check
static bool yy_table_value_is_error_ (int yyvalue);
/// Internal symbol numbers.
typedef unsigned char token_number_type;
/* Tables. */
@ -237,7 +199,7 @@ namespace yy {
static const signed char yypact_[];
static const signed char yypact_ninf_;
/// For a state, default rule to reduce.
/// For a state, default reduction number.
/// Unless\a yytable_ specifies something else to do.
/// Zero means the default is an error.
static const unsigned char yydefact_[];
@ -261,19 +223,12 @@ namespace yy {
/// For a rule, its LHS.
static const unsigned char yyr1_[];
/// For a rule, its RHS length.
static const unsigned char yyr2_[];
#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
/// For a symbol, its name in clear.
static const char* const yytname_[];
#endif
#if YYERROR_VERBOSE
/// Convert the symbol name \a n to a form suitable for a diagnostic.
virtual std::string yytnamerr_ (const char *n);
#endif
static const unsigned char yyr2_[];
#if YYDEBUG
/// For a symbol, its name in clear.
static const char* const yytname_[];
/// A type to store symbol numbers and -1.
typedef signed char rhs_number_type;
/// A `-1'-separated list of the rules' RHS.
@ -328,10 +283,9 @@ namespace yy {
};
} // yy
/* Line 35 of lalr1.cc */
#line 334 "knot_parser/knot_parser.hh"
/* Line 36 of lalr1.cc */
#line 288 "knot_parser/knot_parser.hh"
#endif /* ! defined PARSER_HEADER_H */
#endif /* !YY_YY_KNOT_PARSER_KNOT_PARSER_HH_INCLUDED */

View File

@ -24,6 +24,7 @@ YY_DECL;
basedvector<int, 1> *int_vec;
basedvector<basedvector<int, 1>, 1> *int_vec2;
const char *string;
knot_diagram *kd;
}
%code {
@ -36,9 +37,12 @@ YY_DECL;
%token PD DT BR LINK X T
%token U UNKNOT
%token <alternating> ALT NONALT
%token <string> STRING
%type <kd> knot knot_1
%type <kd> rolfsen_knot htw_knot mt_link planar_diagram dt torus_link unknot braid
%type <alternating> alt_spec
%type <int_vec> int_vec int_vec_1
@ -49,9 +53,27 @@ YY_DECL;
%%
%start knot;
%start entry;
entry:
knot
{
parsed_knot = *$1;
delete $1;
}
;
knot:
knot_1
| knot knot
{
$$ = new knot_diagram (DISJOINT_UNION, *$1, *$2);
delete $1;
delete $2;
}
;
knot_1:
rolfsen_knot
| htw_knot
| mt_link
@ -70,7 +92,7 @@ rolfsen_knot:
if (n >= 1 && n <= 10
&& k >= 1 && k <= rolfsen_crossing_knots (n))
parsed_knot = knot_diagram (rolfsen_knot (n, k));
$$ = new knot_diagram (rolfsen_knot (n, k));
else
{
fprintf (stderr, "knot_parser: no such Rolfsen knot `%d_%d'\n",
@ -89,7 +111,7 @@ htw_knot:
if (n >= 1 && n <= 16
&& k >= 1 && k <= htw_knots (n, alt))
parsed_knot = knot_diagram (htw_knot (n, alt, k));
$$ = new knot_diagram (htw_knot (n, alt, k));
else
{
fprintf (stderr, "knot_parser: no such HTW knot `%d%c%d'\n",
@ -108,7 +130,7 @@ mt_link:
if (n >= 1 && n <= 14
&& k >= 1 && k <= mt_links (n, alt))
parsed_knot = knot_diagram (mt_link (n, alt, k));
$$ = new knot_diagram (mt_link (n, alt, k));
else
{
fprintf (stderr, "knot_parser: no such MT link `%d%c%d'\n",
@ -120,9 +142,9 @@ mt_link:
planar_diagram:
PD '[' int_vec2 ']'
{ parsed_knot = knot_diagram (planar_diagram ("<parsed>", *$3)); }
{ $$ = new knot_diagram (planar_diagram ("<parsed>", *$3)); }
| PD '[' crossing_vec ']'
{ parsed_knot = knot_diagram (planar_diagram ("<parsed>", *$3)); }
{ $$ = new knot_diagram (planar_diagram ("<parsed>", *$3)); }
;
dt:
@ -130,22 +152,22 @@ dt:
{
basedvector<basedvector<int, 1>, 1> even_labels (1);
even_labels[1] = *$3;
parsed_knot = knot_diagram (dt_code ("<parsed>", even_labels));
$$ = new knot_diagram (dt_code ("<parsed>", even_labels));
}
| DT '[' int_vec2 ']'
{ parsed_knot = knot_diagram (dt_code ("<parsed>", *$3)); }
{ $$ = new knot_diagram (dt_code ("<parsed>", *$3)); }
| DT '[' STRING ']'
{ parsed_knot = knot_diagram (dt_code ("<parsed>", $3)); }
{ $$ = new knot_diagram (dt_code ("<parsed>", $3)); }
;
torus_link:
T '(' INT ',' INT ')'
{ parsed_knot = knot_diagram (torus_knot ($3, $5)); }
{ $$ = new knot_diagram (torus_knot ($3, $5)); }
;
braid:
BR '[' INT ',' int_vec ']'
{ parsed_knot = knot_diagram (braid ($3, *$5)); }
{ $$ = new knot_diagram (braid ($3, *$5)); }
;
unknot:
@ -154,7 +176,7 @@ unknot:
unsigned unknot_ar[1][4] = {
{ 2, 1, 3, 4, },
};
parsed_knot = knot_diagram ("U", 1, unknot_ar);
$$ = new knot_diagram ("U", 1, unknot_ar);
}
;

View File

@ -1,9 +1,8 @@
/* A Bison parser, made by GNU Bison 2.4.3. */
/* A Bison parser, made by GNU Bison 2.6.5. */
/* Locations for Bison parsers in C++
Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software
Foundation, Inc.
Copyright (C) 2002-2007, 2009-2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -32,39 +31,55 @@
version 2.2 of Bison. */
/**
** \file location.hh
** \file knot_parser/location.hh
** Define the yy::location class.
*/
#ifndef BISON_LOCATION_HH
# define BISON_LOCATION_HH
#ifndef YY_YY_KNOT_PARSER_LOCATION_HH_INCLUDED
# define YY_YY_KNOT_PARSER_LOCATION_HH_INCLUDED
# include <iostream>
# include <string>
# include "position.hh"
namespace yy {
/* Line 163 of location.cc */
#line 51 "knot_parser/location.hh"
/* Line 164 of location.cc */
#line 47 "knot_parser/location.hh"
/// Abstract a location.
class location
{
public:
/// Construct a location.
location ()
: begin (), end ()
/// Construct a location from \a b to \a e.
location (const position& b, const position& e)
: begin (b)
, end (e)
{
}
/// Construct a 0-width location in \a p.
explicit location (const position& p = position ())
: begin (p)
, end (p)
{
}
/// Construct a 0-width location in \a f, \a l, \a c.
explicit location (std::string* f,
unsigned int l = 1u,
unsigned int c = 1u)
: begin (f, l, c)
, end (f, l, c)
{
}
/// Initialization.
inline void initialize (std::string* fn)
void initialize (std::string* f = YY_NULL,
unsigned int l = 1u,
unsigned int c = 1u)
{
begin.initialize (fn);
begin.initialize (f, l, c);
end = begin;
}
@ -72,19 +87,19 @@ namespace yy {
** \{ */
public:
/// Reset initial location to final location.
inline void step ()
void step ()
{
begin = end;
}
/// Extend the current location to the COUNT next columns.
inline void columns (unsigned int count = 1)
void columns (unsigned int count = 1)
{
end += count;
}
/// Extend the current location to the COUNT next lines.
inline void lines (unsigned int count = 1)
void lines (unsigned int count = 1)
{
end.lines (count);
}
@ -158,8 +173,7 @@ namespace yy {
} // yy
/* Line 292 of location.cc */
#line 178 "knot_parser/location.hh"
/* Line 272 of location.cc */
#line 164 "knot_parser/location.hh"
#endif // not BISON_LOCATION_HH
#endif /* !YY_YY_KNOT_PARSER_LOCATION_HH_INCLUDED */

View File

@ -1,9 +1,8 @@
/* A Bison parser, made by GNU Bison 2.4.3. */
/* A Bison parser, made by GNU Bison 2.6.5. */
/* Positions for Bison parsers in C++
Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software
Foundation, Inc.
Copyright (C) 2002-2007, 2009-2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -32,60 +31,71 @@
version 2.2 of Bison. */
/**
** \file position.hh
** \file knot_parser/position.hh
** Define the yy::position class.
*/
#ifndef BISON_POSITION_HH
# define BISON_POSITION_HH
#ifndef YY_YY_KNOT_PARSER_POSITION_HH_INCLUDED
# define YY_YY_KNOT_PARSER_POSITION_HH_INCLUDED
# include <algorithm> // std::max
# include <iostream>
# include <string>
# include <algorithm>
# ifndef YY_NULL
# if defined __cplusplus && 201103L <= __cplusplus
# define YY_NULL nullptr
# else
# define YY_NULL 0
# endif
# endif
namespace yy {
/* Line 38 of location.cc */
#line 51 "knot_parser/position.hh"
#line 57 "knot_parser/position.hh"
/// Abstract a position.
class position
{
public:
/// Construct a position.
position ()
: filename (0), line (1), column (1)
explicit position (std::string* f = YY_NULL,
unsigned int l = 1u,
unsigned int c = 1u)
: filename (f)
, line (l)
, column (c)
{
}
/// Initialization.
inline void initialize (std::string* fn)
void initialize (std::string* fn = YY_NULL,
unsigned int l = 1u,
unsigned int c = 1u)
{
filename = fn;
line = 1;
column = 1;
line = l;
column = c;
}
/** \name Line and Column related manipulators
** \{ */
public:
/// (line related) Advance to the COUNT next lines.
inline void lines (int count = 1)
void lines (int count = 1)
{
column = 1;
column = 1u;
line += count;
}
/// (column related) Advance to the COUNT next columns.
inline void columns (int count = 1)
void columns (int count = 1)
{
column = std::max (1u, column + count);
}
/** \} */
public:
/// File name to which this position refers.
std::string* filename;
/// Current line number.
@ -95,7 +105,7 @@ namespace yy {
};
/// Add and assign a position.
inline const position&
inline position&
operator+= (position& res, const int width)
{
res.columns (width);
@ -111,7 +121,7 @@ namespace yy {
}
/// Add and assign a position.
inline const position&
inline position&
operator-= (position& res, const int width)
{
return res += -width;
@ -156,7 +166,6 @@ namespace yy {
} // yy
/* Line 145 of location.cc */
#line 162 "knot_parser/position.hh"
#endif // not BISON_POSITION_HH
/* Line 149 of location.cc */
#line 171 "knot_parser/position.hh"
#endif /* !YY_YY_KNOT_PARSER_POSITION_HH_INCLUDED */

View File

@ -1,9 +1,8 @@
/* A Bison parser, made by GNU Bison 2.4.3. */
/* A Bison parser, made by GNU Bison 2.6.5. */
/* Stack handling for Bison parsers in C++
Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
Software Foundation, Inc.
Copyright (C) 2002-2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -31,21 +30,24 @@
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
#ifndef BISON_STACK_HH
# define BISON_STACK_HH
/**
** \file knot_parser/stack.hh
** Define the yy::stack class.
*/
#include <deque>
#ifndef YY_YY_KNOT_PARSER_STACK_HH_INCLUDED
# define YY_YY_KNOT_PARSER_STACK_HH_INCLUDED
# include <deque>
namespace yy {
/* Line 1067 of lalr1.cc */
#line 44 "knot_parser/stack.hh"
/* Line 37 of stack.hh */
#line 47 "knot_parser/stack.hh"
template <class T, class S = std::deque<T> >
class stack
{
public:
// Hide our reversed order.
typedef typename S::reverse_iterator iterator;
typedef typename S::const_reverse_iterator const_iterator;
@ -84,7 +86,7 @@ namespace yy {
pop (unsigned int n = 1)
{
for (; n; --n)
seq_.pop_front ();
seq_.pop_front ();
}
inline
@ -98,7 +100,6 @@ namespace yy {
inline const_iterator end () const { return seq_.rend (); }
private:
S seq_;
};
@ -107,10 +108,9 @@ namespace yy {
class slice
{
public:
slice (const S& stack,
unsigned int range) : stack_ (stack),
range_ (range)
slice (const S& stack, unsigned int range)
: stack_ (stack)
, range_ (range)
{
}
@ -122,15 +122,12 @@ namespace yy {
}
private:
const S& stack_;
unsigned int range_;
};
} // yy
/* Line 119 of stack.hh */
#line 132 "knot_parser/stack.hh"
/* Line 1153 of lalr1.cc */
#line 134 "knot_parser/stack.hh"
#endif // not BISON_STACK_HH[]dnl
#endif /* !YY_YY_KNOT_PARSER_STACK_HH_INCLUDED */

View File

@ -402,7 +402,7 @@ htw_knot (unsigned n, bool alternating, unsigned k)
before += htw_alternating[i];
off = 8 * (before + k - 1);
file = HOME "alternating";
file = HOME "/alternating";
}
else
{
@ -411,7 +411,7 @@ htw_knot (unsigned n, bool alternating, unsigned k)
before += htw_nonalternating[i];
off = 10 * (before + k - 1);
file = HOME "nonalternating";
file = HOME "/nonalternating";
}
FILE *fp = fopen (file, "r");
if (fp == 0)
@ -499,6 +499,13 @@ mt_links (unsigned n, bool alternating)
return mt_nonalternating[n - 1];
}
unsigned
mt_links (unsigned n)
{
assert (between (1, n, 14));
return mt_alternating[n - 1] + mt_nonalternating[n - 1];
}
dt_code
mt_link (unsigned n, bool alternating, unsigned k)
{
@ -507,7 +514,7 @@ mt_link (unsigned n, bool alternating, unsigned k)
char buf[1000];
sprintf (buf, HOME "mtlinks/hyperbolic_data_%02d%c", n, alternating ? 'a' : 'n');
sprintf (buf, HOME "/mtlinks/hyperbolic_data_%02d%c", n, alternating ? 'a' : 'n');
FILE *fp = fopen (buf, "r");
if (fp == 0)
{
@ -535,6 +542,19 @@ mt_link (unsigned n, bool alternating, unsigned k)
return dt_code (buf2, buf);
}
dt_code
mt_link (unsigned n, unsigned k)
{
assert (between (1, n, 16));
assert (k >= 1);
unsigned na = mt_links (n, 1);
if (k <= na)
return mt_link (n, 1, k);
else
return mt_link (n, 0, k - na);
}
planar_diagram
torus_knot (unsigned n_strands, unsigned n_shifts)
{
@ -594,7 +614,7 @@ torus_knot (unsigned n_strands, unsigned n_shifts)
return planar_diagram (std::string (buf), crossings);
}
planar_diagram
knot_diagram
braid (unsigned n_strands, unsigned n_twists, int twists_ar[])
{
basedvector<int, 1> twists (n_twists);
@ -603,10 +623,9 @@ braid (unsigned n_strands, unsigned n_twists, int twists_ar[])
return braid (n_strands, twists);
}
planar_diagram
knot_diagram
braid (unsigned n_strands, const basedvector<int, 1> &twists)
{
unsigned n_crossings = twists.size ();
unsigned e = 0;
basedvector<unsigned, 1> final_strands (n_strands);
@ -622,22 +641,44 @@ braid (unsigned n_strands, const basedvector<int, 1> &twists)
last_twist[i] = 0;
for (unsigned i = 1; i <= twists.size (); i ++)
{
unsigned t = std::abs (twists[i]);
unsigned t = abs (twists[i]);
last_twist[t] = i;
last_twist[t + 1] = i;
}
#ifndef NDEBUG
for (unsigned i = 1; i <= n_strands; i ++)
assert (last_twist[i] != 0);
#endif
basedvector<basedvector<int, 1>, 1> crossings (n_crossings);
unsigned n_crossings = twists.size ();
for (unsigned i = 1; i <= n_strands; i ++)
{
if (last_twist[i] == 0)
n_crossings ++;
}
basedvector<basedvector<unsigned, 1>, 1> crossings (n_crossings);
for (unsigned i = 1; i <= n_crossings; i ++)
crossings[i] = basedvector<int, 1> (4);
crossings[i] = basedvector<unsigned, 1> (4);
unsigned c = twists.size ();
for (unsigned i = 1; i <= n_strands; i ++)
{
if (last_twist[i] == 0)
{
++ c;
unsigned e1 = strands[i];
unsigned e2 = ++ e;
strands[i] = final_strands[i] = 0;
crossings[c][1] = edge_from_ept (e1);
crossings[c][2] = edge_to_ept (e2);
crossings[c][3] = edge_from_ept (e2);
crossings[c][4] = edge_to_ept (e1);
}
}
assert (c == n_crossings);
for (unsigned i = 1; i <= twists.size (); i ++)
{
unsigned t = std::abs (twists[i]);
unsigned t = abs (twists[i]);
unsigned e1 = strands[t],
e4 = strands[t + 1];
unsigned e2, e3;
@ -668,27 +709,30 @@ braid (unsigned n_strands, const basedvector<int, 1> &twists)
if (twists[i] > 0)
{
crossings[i][1] = e1;
crossings[i][2] = e2;
crossings[i][3] = e3;
crossings[i][4] = e4;
crossings[i][1] = edge_to_ept (e1);
crossings[i][2] = edge_from_ept (e2);
crossings[i][3] = edge_from_ept (e3);
crossings[i][4] = edge_to_ept (e4);
}
else
{
crossings[i][1] = e2;
crossings[i][2] = e3;
crossings[i][3] = e4;
crossings[i][4] = e1;
crossings[i][1] = edge_from_ept (e2);
crossings[i][2] = edge_from_ept (e3);
crossings[i][3] = edge_to_ept (e4);
crossings[i][4] = edge_to_ept (e1);
}
}
assert (e == n_crossings * 2);
#ifndef NDEBUG
for (unsigned i = 1; i <= n_strands; i ++)
assert (final_strands[i] == 0);
{
assert (strands[i] == 0);
assert (final_strands[i] == 0);
}
#endif
return planar_diagram ("abraid", crossings);
return knot_diagram ("abraid", crossings);
}
basedvector<basedvector<unsigned, 1>, 1>
@ -697,7 +741,7 @@ mutant_knot_groups (unsigned n)
assert (11 <= n && n <= 15);
char buf[1000];
sprintf (buf, HOME "mutant_knot_groups/dat%d", n);
sprintf (buf, HOME "/mutant_knot_groups/dat%d", n);
FILE *fp = fopen (buf, "r");
if (fp == 0)
@ -728,3 +772,138 @@ mutant_knot_groups (unsigned n)
return r;
}
knot_diagram
knot_desc::diagram () const
{
switch (t)
{
case ROLFSEN:
return knot_diagram (rolfsen_knot (i, j));
case HTW:
return knot_diagram (htw_knot (i, j));
case HTW_ALT:
return knot_diagram (htw_knot (i, 1, j));
case HTW_NONALT:
return knot_diagram (htw_knot (i, 0, j));
case MT:
return knot_diagram (mt_link (i, j));
case MT_ALT:
return knot_diagram (mt_link (i, 1, j));
case MT_NONALT:
return knot_diagram (mt_link (i, 0, j));
case TORUS:
return knot_diagram (torus_knot (i, j));
default: abort ();
}
}
std::string
knot_desc::name () const
{
char buf[1000];
#if 0
sprintf (buf, "knot_desc(%d, %d, %d)", (int)t, i, j);
return buf;
#endif
switch (t)
{
case ROLFSEN:
sprintf (buf, "%d_%d", i, j);
break;
case HTW:
{
unsigned na = htw_knots (i, 1);
if (j <= na)
sprintf (buf, "%da%d", i, j);
else
sprintf (buf, "%dn%d", i, j - na);
}
break;
case HTW_ALT:
sprintf (buf, "%da%d", i, j);
break;
case HTW_NONALT:
sprintf (buf, "%dn%d", i, j);
break;
case MT:
{
unsigned na = mt_links (i, 1);
if (j <= na)
sprintf (buf, "L%da%d", i, j);
else
sprintf (buf, "L%dn%d", i, j - na);
}
break;
case MT_ALT:
sprintf (buf, "L%da%d", i, j);
break;
case MT_NONALT:
sprintf (buf, "L%dn%d", i, j);
break;
case TORUS:
sprintf (buf, "T(%d, %d)", i, j);
break;
default: abort ();
}
return buf;
}
unsigned
knot_desc::table_crossing_knots () const
{
switch (t)
{
case ROLFSEN:
return rolfsen_crossing_knots (i);
case HTW:
return htw_knots (i);
case HTW_ALT:
return htw_knots (i, 1);
case HTW_NONALT:
return htw_knots (i, 0);
case MT:
return mt_links (i);
case MT_ALT:
return mt_links (i, 1);
case MT_NONALT:
return mt_links (i, 0);
default: abort ();
}
}
knot_desc::knot_desc (reader &r)
{
int x;
read (r, x);
t = (table)x;
read (r, i);
read (r, j);
}
void
knot_desc::write_self (writer &w) const
{
write (w, (int)t);
write (w, i);
write (w, j);
}

View File

@ -14,13 +14,90 @@ 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>
class knot_desc
{
public:
enum table
{
NONE,
ROLFSEN,
HTW,
HTW_ALT,
HTW_NONALT,
MT,
MT_ALT,
MT_NONALT,
TORUS,
};
table t;
unsigned i;
unsigned j;
public:
knot_desc () : t(NONE) { }
knot_desc (table t_, unsigned i_, unsigned j_)
: t(t_), i(i_), j(j_)
{ }
knot_desc (const knot_desc &desc)
: t(desc.t), i(desc.i), j(desc.j)
{ }
knot_desc (reader &r);
~knot_desc () { }
knot_desc &operator = (const knot_desc &desc)
{
t = desc.t;
i = desc.i;
j = desc.j;
return *this;
}
bool operator == (const knot_desc &desc) const
{
return t == desc.t && i == desc.i && j == desc.j;
}
bool operator < (const knot_desc &desc) const
{
if ((int)t < (int)desc.t)
return 1;
else if ((int)t > (int)desc.t)
return 0;
if (i < desc.i)
return 1;
else if (i > desc.i)
return 0;
return j < desc.j;
}
knot_diagram diagram () const;
std::string name () const;
unsigned table_crossing_knots () const;
hash_t hash_self () const
{
return hash_combine (hash ((int)t),
hash_combine (hash (i),
hash (j)));
}
void write_self (writer &w) const;
void show_self () const { printf ("%s", name ().c_str ()); }
void display_self () const { show_self (); newline (); }
};
unsigned rolfsen_crossing_knots (unsigned n);
planar_diagram rolfsen_knot (unsigned n, unsigned k);
@ -31,12 +108,15 @@ dt_code htw_knot (unsigned n, bool alternating, unsigned k);
dt_code htw_knot (unsigned n, unsigned k);
unsigned mt_links (unsigned n, bool alternating);
unsigned mt_links (unsigned n);
dt_code mt_link (unsigned n, bool alternating, unsigned k);
dt_code mt_link (unsigned n, unsigned k);
planar_diagram torus_knot (unsigned n_strands, unsigned n_shifts);
planar_diagram braid (unsigned n_strands, const basedvector<int, 1> &twists);
planar_diagram braid (unsigned n_strands, unsigned n_twists, int twists_ar[]);
knot_diagram braid (unsigned n_strands, const basedvector<int, 1> &twists);
knot_diagram braid (unsigned n_strands, unsigned n_twists, int twists_ar[]);
knot_diagram parse_knot (const char *s);
resolution_diagram parse_resolution_diagram (const char *s);

View File

@ -1,23 +1,29 @@
/* wrapper for std::unordered_map */
template<class K>
struct hasher : public std::unary_function<K, hash_t>
{
hash_t operator () (const K &k) const { return hash (k); }
};
template<class K, class V>
class hashmap : public map_wrapper<std::tr1::unordered_map<K, V, hasher<K> >, K, V>
class hashmap : public map_wrapper<std::unordered_map<K, V, hasher<K> >, K, V>
{
typedef map_wrapper<std::tr1::unordered_map<K, V, hasher<K> >, K, V> base;
typedef map_wrapper<std::unordered_map<K, V, hasher<K> >, K, V> base;
public:
hashmap () { }
hashmap (const hashmap &m) : base(m) { }
hashmap (copy, const hashmap &m) : base(COPY, m) { }
hashmap (initializer_list<std::pair<const K, V> > il) : base(il) { }
hashmap (reader &r) : base(r) { }
~hashmap () { }
hashmap &operator = (const hashmap &m) { base::operator = (m); return *this; }
hashmap &operator = (initializer_list<std::pair<const K, V> > il)
{
base::operator = (il);
return *this;
}
};
template<class K, class V>
using hashmap_iter = map_wrapper_iter<std::unordered_map<K, V>, K, V>;
template<class K, class V>
using hashmap_const_iter = map_wrapper_const_iter<std::unordered_map<K, V>, K, V>;

25
lib/hashset.h Normal file
View File

@ -0,0 +1,25 @@
/* wrapper for std::unordered_set */
template<class T>
class hashset : public set_wrapper<std::unordered_set<T, hasher<T> >, T>
{
typedef set_wrapper<std::unordered_set<T, hasher<T> >, T> base;
public:
hashset () { }
hashset (const hashset &m) : base(m) { }
hashset (copy, const hashset &m) : base(COPY, m) { }
hashset (initializer_list<T> il) : base(il) { }
hashset (reader &r) : base(r) { }
~hashset () { }
hashset &operator = (const hashset &m) { base::operator = (m); return *this; }
hashset &operator = (initializer_list<T> il) { base::operator = (il); return *this; }
};
template<class T>
using hashset_iter = set_wrapper_iter<std::unordered_set<T, hasher<T> >, T>;
template<class T>
using hashset_const_iter = set_wrapper_const_iter<std::unordered_set<T, hasher<T> >, T>;

View File

@ -1,10 +1,236 @@
#include <lib/lib.h>
// #include <lib/lib.h>
#include <algebra/algebra.h>
writer::writer (bool raw_)
: raw(raw_),
aw(new algebra_writer)
{
}
writer::~writer ()
{
delete aw;
}
void
writer::write_int (int x)
{
if (raw)
write_raw (&x, sizeof x, 1);
else
{
uint8 buf[5];
unsigned n = 0;
bool more = 1;
while (more)
{
uint8 b = (uint8)(x & 0x7f);
x >>= 7;
if ((x == 0
&& ! (b & 0x40))
|| (x == -1
&& (b & 0x40) == 0x40))
more = 0;
else
b |= 0x80;
assert (n < 5);
buf[n] = b;
n ++;
}
write_raw (buf, sizeof buf[0], n);
}
}
void
writer::write_unsigned (unsigned x)
{
if (raw)
write_raw (&x, sizeof x, 1);
else
{
uint8 buf[5];
unsigned n = 0;
bool more = 1;
while (more)
{
uint8 b = (uint8)(x & 0x7f);
x >>= 7;
if ((x == 0
&& ! (b & 0x40)))
more = 0;
else
b |= 0x80;
assert (n < 5);
buf[n] = b;
n ++;
}
write_raw (buf, sizeof buf[0], n);
}
}
void
writer::write_uint64 (uint64 x)
{
if (raw)
write_raw (&x, sizeof x, 1);
else
{
uint8 buf[10];
unsigned n = 0;
bool more = 1;
while (more)
{
uint8 b = (uint8)(x & 0x7f);
x >>= 7;
if ((x == 0
&& ! (b & 0x40)))
more = 0;
else
b |= 0x80;
assert (n < 10);
buf[n] = b;
n ++;
}
write_raw (buf, sizeof buf[0], n);
}
}
void
writer::write_mpz (const mpz_t x)
{
assert (!raw);
size_t count;
void *buf = mpz_export (nullptr, &count, -1, 1, -1, 0, x);
write_unsigned ((unsigned)count);
write_raw (buf, 1, count);
free (buf);
}
reader::reader (bool raw_)
: raw(raw_),
ar(new algebra_reader)
{
}
reader::~reader ()
{
delete ar;
}
int
reader::read_int ()
{
int x = 0;
if (raw)
read_raw (&x, sizeof x, 1);
else
{
int shift = 0;
for (;;)
{
uint8 b = read_uint8 ();
x |= ((int)(b & 0x7f) << shift);
shift += 7;
if (! (b & 0x80))
{
if (shift < int_bits
&& (b & 0x40))
x = (x << (int_bits - shift)) >> (int_bits - shift);
break;
}
}
}
return x;
}
unsigned
reader::read_unsigned ()
{
unsigned x = 0;
if (raw)
read_raw (&x, sizeof x, 1);
else
{
unsigned shift = 0;
for (;;)
{
uint8 b = read_uint8 ();
x |= ((unsigned)(b & 0x7f) << shift);
shift += 7;
if (! (b & 0x80))
break;
}
}
return x;
}
uint64
reader::read_uint64 ()
{
uint64 x = 0;
if (raw)
read_raw (&x, sizeof x, 1);
else
{
uint64 shift = 0;
for (;;)
{
uint8 b = read_uint8 ();
x |= ((uint64)(b & 0x7f) << shift);
shift += 7;
if (! (b & 0x80))
break;
}
}
return x;
}
void
reader::read_mpz (mpz_t x)
{
assert (!raw);
unsigned count = read_unsigned ();
void *p = malloc (count);
if (!p)
{
stderror ("malloc");
exit (EXIT_FAILURE);
}
read_raw (p, 1, count);
mpz_import (x, count, -1, 1, -1, 0, p);
free (p);
}
FILE *open_file (const std::string &file, const char *mode)
{
FILE *fp = fopen (file.c_str (), mode);
if (fp == 0)
if (!fp)
{
stderror ("fopen: %s", file.c_str ());
exit (EXIT_FAILURE);
@ -17,41 +243,32 @@ void close_file (FILE *fp)
fclose (fp);
}
writer::writer (const std::string &file)
: fp(0)
gzFile
open_gzfile (const std::string &file, const char *mode)
{
fp = open_file (file, "w");
}
writer::~writer ()
{
if (fp)
gzFile gzfp = gzopen (file.c_str (), mode);
if (!gzfp)
{
fclose (fp);
fp = 0;
stderror ("gzopen: %s", file.c_str ());
exit (EXIT_FAILURE);
}
return gzfp;
}
reader::reader (const std::string &file)
: fp(0)
extern void close_gzfile (gzFile gzfp)
{
fp = open_file (file, "r");
}
reader::~reader ()
{
if (fp)
int r = gzclose (gzfp);
if (r != Z_OK)
{
fclose (fp);
fp = 0;
stderror ("gzclose");
exit (EXIT_FAILURE);
}
}
void
writer::write_char (char x)
file_writer::write_raw (const void *p, size_t itemsize, size_t nitems)
{
if (fwrite (&x, sizeof x, 1, fp) != 1)
if (fwrite (p, itemsize, nitems, fp) != nitems)
{
stderror ("fwrite");
exit (EXIT_FAILURE);
@ -59,103 +276,47 @@ writer::write_char (char x)
}
void
writer::write_bool (bool x)
file_writer::write_mpz (const mpz_t x)
{
if (fwrite (&x, sizeof x, 1, fp) != 1)
mpz_out_raw (fp, x);
}
void
file_reader::read_raw (void *p, size_t itemsize, size_t nitems)
{
if (fread (p, itemsize, nitems, fp) != nitems)
{
stderror ("fwrite");
stderror ("fread");
exit (EXIT_FAILURE);
}
}
void
writer::write_int (int x)
file_reader::read_mpz (mpz_t x)
{
if (fwrite (&x, sizeof x, 1, fp) != 1)
mpz_inp_raw (x, fp);
}
void
gzfile_writer::write_raw (const void *p, size_t itemsize, size_t nitems)
{
unsigned nbytes = itemsize*nitems;
if (gzwrite (gzfp, p, nbytes) != nbytes)
{
stderror ("fwrite");
stderror ("gzwrite");
exit (EXIT_FAILURE);
}
}
void
writer::write_unsigned (unsigned x)
gzfile_reader::read_raw (void *p, size_t itemsize, size_t nitems)
{
if (fwrite (&x, sizeof x, 1, fp) != 1)
{
stderror ("fwrite");
exit (EXIT_FAILURE);
}
}
void
writer::write_uint64 (uint64 x)
{
if (fwrite (&x, sizeof x, 1, fp) != 1)
{
stderror ("fwrite");
exit (EXIT_FAILURE);
}
}
bool
reader::read_bool ()
{
bool x;
if (fread (&x, sizeof x, 1, fp) != 1)
unsigned nbytes = itemsize*nitems;
if (gzread (gzfp, p, nbytes) != nitems)
{
stderror ("fread");
exit (EXIT_FAILURE);
}
return x;
}
char
reader::read_char ()
{
char x;
if (fread (&x, sizeof x, 1, fp) != 1)
{
stderror ("fread");
exit (EXIT_FAILURE);
}
return x;
}
int
reader::read_int ()
{
int x;
if (fread (&x, sizeof x, 1, fp) != 1)
{
stderror ("fread");
exit (EXIT_FAILURE);
}
return x;
}
unsigned
reader::read_unsigned ()
{
unsigned x;
if (fread (&x, sizeof x, 1, fp) != 1)
{
stderror ("fread");
exit (EXIT_FAILURE);
}
return x;
}
uint64
reader::read_uint64 ()
{
uint64 x;
if (fread (&x, sizeof x, 1, fp) != 1)
{
stderror ("fread");
exit (EXIT_FAILURE);
}
return x;
}
void
@ -164,12 +325,7 @@ read (reader &r, std::string &s)
unsigned n = r.read_unsigned ();
char buf[n + 1];
unsigned k = fread (buf, sizeof (char), n + 1, r.fp);
if (k != n + 1)
{
stderror ("fread");
exit (EXIT_FAILURE);
}
r.read_raw (buf, sizeof (char), n + 1);
assert (buf[n] == 0);
s = std::string (buf);
@ -181,9 +337,5 @@ write (writer &w, const std::string &s)
unsigned n = s.length ();
w.write_unsigned (n);
if (fwrite (s.c_str (), sizeof (char), n + 1, w.fp) != n + 1)
{
stderror ("fwrite");
exit (EXIT_FAILURE);
}
w.write_raw (s.c_str (), sizeof (char), n + 1);
}

161
lib/io.h
View File

@ -1,43 +1,162 @@
extern FILE *open_file (const std::string &file, const char *mode);
extern void close_file (FILE *fp);
template<class R> class module;
class algebra_writer;
class algebra_reader;
class writer
{
public:
FILE *fp;
bool raw;
algebra_writer *aw;
public:
writer (const std::string &file);
writer (const writer &); // doesn't exist
~writer ();
writer (const writer &) = delete;
writer (bool raw_);
virtual ~writer ();
writer &operator = (const writer &); // doesn't exist
writer &operator = (const writer &) = delete;
void write_bool (bool x);
void write_char (char x);
virtual void write_raw (const void *p, size_t itemsize, size_t nitems) = 0;
void write_bool (bool x) { write_raw (&x, sizeof x, 1); }
void write_char (char x) { write_raw (&x, sizeof x, 1); }
void write_uint8 (uint8 x) { write_raw (&x, sizeof x, 1); }
void write_int (int x);
void write_unsigned (unsigned x);
void write_uint64 (uint64 x);
virtual void write_mpz (const mpz_t x);
template<class R> void write_mod (ptr<const module<R> > m);
};
class reader
{
public:
FILE *fp;
public:
reader (const std::string &file);
reader (const reader &); // doesn't exist
~reader ();
bool raw;
algebra_reader *ar;
reader &operator = (const reader &); // doesn't exist
public:
reader (const reader &) = delete;
reader (bool raw_);
virtual ~reader ();
reader &operator = (const reader &) = delete;
virtual void read_raw (void *p, size_t itemsize, size_t nitems) = 0;
bool read_bool ()
{
bool x;
read_raw (&x, sizeof x, 1);
return x;
}
char read_char ()
{
char x;
read_raw (&x, sizeof x, 1);
return x;
}
uint8 read_uint8 ()
{
uint8 x;
read_raw (&x, sizeof x, 1);
return x;
}
bool read_bool ();
char read_char ();
int read_int ();
unsigned read_unsigned ();
uint64 read_uint64 ();
virtual void read_mpz (mpz_t x);
template<class R> ptr<const module<R> > read_mod ();
};
extern FILE *open_file (const std::string &file, const char *mode);
extern void close_file (FILE *fp);
extern gzFile open_gzfile (const std::string &file, const char *mode);
extern void close_gzfile (gzFile fp);
class file_writer : public writer
{
public:
FILE *fp;
public:
file_writer (const std::string &file, bool raw = false)
: writer(raw),
fp(open_file (file, "w"))
{
}
file_writer (const file_writer &) = delete;
~file_writer () { close_file (fp); }
file_writer &operator = (const file_writer &) = delete;
void write_raw (const void *p, size_t itemsize, size_t nitems);
void write_mpz (const mpz_t x);
};
class file_reader : public reader
{
public:
FILE *fp;
public:
file_reader (const std::string &file, bool raw = false)
: reader(raw),
fp(open_file (file, "r"))
{
}
file_reader (const file_reader &) = delete;
~file_reader () { close_file (fp); }
file_reader &operator = (const file_reader &) = delete;
void read_raw (void *p, size_t itemsize, size_t nitems);
void read_mpz (mpz_t x);
};
class gzfile_writer : public writer
{
public:
gzFile gzfp;
public:
gzfile_writer (const std::string &file)
: writer(false),
gzfp(open_gzfile (file, "w9"))
{
}
gzfile_writer (const gzfile_writer &) = delete;
~gzfile_writer () { close_gzfile (gzfp); }
gzfile_writer &operator = (const gzfile_writer &) = delete;
void write_raw (const void *p, size_t itemsize, size_t nitems);
};
class gzfile_reader : public reader
{
public:
gzFile gzfp;
public:
gzfile_reader (const std::string &file)
: reader(false),
gzfp(open_gzfile (file, "r"))
{
}
gzfile_reader (const gzfile_reader &) = delete;
~gzfile_reader () { close_gzfile (gzfp); }
gzfile_reader &operator = (const gzfile_reader &) = delete;
void read_raw (void *p, size_t itemsize, size_t nitems);
};
inline void read (reader &r, bool &x) { x = r.read_bool (); }
@ -45,7 +164,7 @@ inline void read (reader &r, char &x) { x = r.read_char (); }
inline void read (reader &r, int &x) { x = r.read_int (); }
inline void read (reader &r, unsigned &x) { x = r.read_unsigned (); }
inline void read (reader &r, uint64 &x) { x = r.read_uint64 (); }
void read (reader &r, std::string &s);
extern void read (reader &r, std::string &s);
template<class T> inline void read (reader &r, T &x) { x = T(r); }
inline void ctor_read (reader &r, bool *p) { *p = r.read_bool (); }
@ -60,5 +179,5 @@ inline void write (writer &w, char x) { w.write_char (x); }
inline void write (writer &w, int x) { w.write_int (x); }
inline void write (writer &w, unsigned x) { w.write_unsigned (x); }
inline void write (writer &w, uint64 x) { w.write_uint64 (x); }
void write (writer &w, const std::string &s);
extern void write (writer &w, const std::string &s);
template<class T> inline void write (writer &w, const T &x) { x.write_self (w); }

View File

@ -1,5 +1,6 @@
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
@ -7,17 +8,21 @@
#include <sys/stat.h>
#include <sys/errno.h>
#include <gmp.h>
#include <zlib.h>
#include <initializer_list>
#include <set>
#include <map>
#include <string>
#include <queue>
#include <algorithm>
#include <tr1/functional>
#include <tr1/unordered_map>
#include <functional>
#include <unordered_set>
#include <unordered_map>
/* just need to implement ==, < */
template<class T> bool operator != (const T &a, const T &b) { return ! (a == b); }
template<class T> bool operator <= (const T &a, const T &b) { return (a < b) || (a == b); }
template<class T> bool operator > (const T &a, const T &b) { return ! (a <= b); }
template<class T> bool operator >= (const T &a, const T &b) { return ! (a < b); }
@ -25,6 +30,8 @@ template<class T> bool operator >= (const T &a, const T &b) { return ! (a < b);
typedef enum copy { COPY, COPY1 } copy;
typedef enum copy2 { COPY2 } copy2;
typedef unsigned char uint8;
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
@ -33,8 +40,15 @@ typedef unsigned long ulong;
typedef long long int64;
typedef unsigned long long uint64;
inline int64 abs64 (int64 x) { return llabs (x); }
typedef size_t hash_t;
static const unsigned uint8_bits = 8;
static const unsigned char_bits = 8;
static const unsigned uchar_bits = 8;
static const unsigned int_bits = 32;
inline hash_t hash (bool x) { return (hash_t)x; }
inline hash_t hash (char x) { return (hash_t)x; }
inline hash_t hash (unsigned char x) { return (hash_t)x; }
@ -147,13 +161,24 @@ void stderror (const char *fmt, ...);
int alpha_to_int (char c);
#include <lib/io.h>
using std::tuple;
using std::get;
using std::make_tuple;
using std::tie;
using std::ignore;
using std::initializer_list;
#include <lib/show.h>
#include <lib/refcount.h>
#include <lib/io.h>
#include <lib/pair.h>
#include <lib/maybe.h>
#include <lib/vector.h>
#include <lib/set_wrapper.h>
#include <lib/set.h>
class bitset;
@ -172,12 +197,40 @@ inline int random_int (int from, int to)
#include <lib/bitset.h>
#include <lib/ullmanset.h>
#include <lib/setcommon.h>
#include <lib/map_wrapper.h>
#include <lib/map.h>
template<class K>
struct hasher : public std::unary_function<K, hash_t>
{
hash_t operator () (const K &k) const { return hash (k); }
};
#include <lib/hashmap.h>
#include <lib/hashset.h>
#include <lib/ullmanmap.h>
#include <lib/mapcommon.h>
#include <lib/unionfind.h>
#include <lib/priority_queue.h>
#include <lib/directed_multigraph.h>
// ??? io
class algebra_writer
{
public:
// modules
unsigned io_id_counter;
map<unsigned, unsigned> id_io_id;
algebra_writer () : io_id_counter(0) { }
~algebra_writer () { }
};
class algebra_reader
{
public:
map<unsigned, unsigned> io_id_id;
};

View File

@ -1,5 +1,5 @@
/* wrapper for stl map */
/* wrapper for std::map */
template<class K, class V>
class map : public map_wrapper<std::map<K, V>, K, V>
@ -11,9 +11,20 @@ class map : public map_wrapper<std::map<K, V>, K, V>
map (unsigned dummy_size) : base(dummy_size) { }
map (const map &m) : base(m) { }
map (copy, const map &m) : base(COPY, m) { }
map (copy2, const map &m) : base(COPY2, m) { }
map (initializer_list<std::pair<const K, V> > il) : base(il) { }
map (reader &r) : base(r) { }
~map () { }
map &operator = (const map &m) { base::operator = (m); return *this; }
map &operator = (initializer_list<std::pair<const K, V> > il)
{
base::operator = (il);
return *this;
}
};
template<class K, class V>
using map_iter = map_wrapper_iter<std::map<K, V>, K, V>;
template<class K, class V>
using map_const_iter = map_wrapper_const_iter<std::map<K, V>, K, V>;

View File

@ -1,5 +1,5 @@
/* wrapper for stl maps */
/* wrapper for STL maps */
template<class M, class K, class V> class map_wrapper_iter;
template<class M, class K, class V> class map_wrapper_const_iter;
@ -7,14 +7,23 @@ template<class M, class K, class V> class map_wrapper_const_iter;
template<class M, class K, class V>
class map_wrapper
{
private:
friend class map_wrapper_iter<M, K, V>;
friend class map_wrapper_const_iter<M, K, V>;
protected:
class map_impl : public refcounted
{
public:
M t;
public:
map_impl () = default;
map_impl (const map_impl &) = delete;
map_impl (const M &t_) : t(t_) { }
map_impl (initializer_list<std::pair<const K, V> > il) : t(il) { }
~map_impl () = default;
map_impl &operator = (const map_impl &) = delete;
};
ptr<map_impl> impl;
@ -25,14 +34,24 @@ class map_wrapper
public:
map_wrapper () : impl(new map_impl) { }
map_wrapper (unsigned dummy_size) : impl(new map_impl) { }
map_wrapper (const map_wrapper &m) : impl(m.impl) { }
map_wrapper (copy, const map_wrapper &m) : impl(new map_impl) { impl->t = M (m.impl->t); }
map_wrapper (copy2, const map_wrapper &m);
map_wrapper (copy, const map_wrapper &m) : impl(new map_impl (m.impl->t)) { }
map_wrapper (initializer_list<std::pair<const K, V> > il)
: impl(new map_impl (il))
{ }
map_wrapper (reader &r);
~map_wrapper () { }
map_wrapper &operator = (const map_wrapper &m) { impl = m.impl; return *this; }
map_wrapper &operator = (initializer_list<std::pair<const K, V> > il)
{
impl->t = il;
return *this;
}
// range-based for
typename M::const_iterator begin () const { return impl->t.begin (); }
typename M::const_iterator end () const { return impl->t.end (); }
/* returns the pair associated to the smallest key */
pair<K, V> head () const
@ -130,20 +149,12 @@ class map_wrapper
}
bool operator == (const map_wrapper &m) const;
bool operator != (const map_wrapper &m) const { return !operator == (m); }
bool operator < (const map_wrapper &m) const;
void write_self (writer &w) const;
};
template<class M, class K, class V>
map_wrapper<M, K, V>::map_wrapper (copy2, const map_wrapper &m)
: impl(new map_impl)
{
/* Keys are immutable. Just copy the values. */
for (const_iter i = m; i; i ++)
push (i.key (), V (COPY, i.val ()));
}
template<class M, class K, class V>
map_wrapper<M, K, V>::map_wrapper (reader &r)
: impl(new map_impl)
@ -222,19 +233,19 @@ template<class M, class K, class V>
class map_wrapper_iter
{
private:
map_wrapper<M, K, V> &m;
ptr<typename map_wrapper<M, K, V>::map_impl> impl;
typename M::iterator i, end;
bool deleted;
public:
map_wrapper_iter (map_wrapper<M, K, V> &m_) : m(m_), i(m_.impl->t.begin ()), end(m_.impl->t.end ()), deleted(0) { }
map_wrapper_iter (map_wrapper<M, K, V> &m) : impl(m.impl), i(m.impl->t.begin ()), end(m.impl->t.end ()), deleted(0) { }
~map_wrapper_iter () { }
void del ()
{
assert (!deleted);
typename M::iterator iprev = i ++;
m.impl->t.erase (iprev);
impl->t.erase (iprev);
deleted = 1;
}
@ -249,10 +260,11 @@ template<class M, class K, class V>
class map_wrapper_const_iter
{
private:
ptr<const typename map_wrapper<M, K, V>::map_impl> impl;
typename M::const_iterator i, end;
public:
map_wrapper_const_iter (const map_wrapper<M, K, V> &m) : i(m.impl->t.begin ()), end(m.impl->t.end ()) { }
map_wrapper_const_iter (const map_wrapper<M, K, V> &m) : impl(m.impl), i(m.impl->t.begin ()), end(m.impl->t.end ()) { }
~map_wrapper_const_iter () { }
const K &key () const { return i->first; }

View File

@ -17,6 +17,7 @@ class pair
pair &operator = (const pair &p) { first = p.first; second = p.second; return *this; }
bool operator == (const pair &p) const { return first == p.first && second == p.second; }
bool operator != (const pair &p) const { return !operator == (p); }
bool operator < (const pair &p) const { return (first < p.first
|| (first == p.first && second < p.second)); }
@ -53,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;
@ -67,6 +69,8 @@ public:
{
return first == t.first && second == t.second && third == t.third;
}
bool operator != (const triple &t) const { return !operator == (t); }
bool operator < (const triple &t) const
{
if (first < t.first)
@ -78,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);
@ -92,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);
}

View File

@ -18,6 +18,8 @@ class priority_queue
weighted &operator = (const weighted &w) { v = w.v; pri = w.pri; }
bool operator == (const weighted &w) const { return v == w.v && pri == w.pri; }
bool operator != (const weighted &w) const { return !operator == (w); }
bool operator < (const weighted &w) const { return pri > w.pri || (pri == w.pri && v < w.v); }
};

View File

@ -42,10 +42,10 @@ class refcounted
public:
refcounted () : refcount(0) { }
refcounted (const refcounted &rc); // doesn't exist
refcounted (const refcounted &rc) = delete;
~refcounted () { }
refcounted &operator = (const refcounted &rc); // doesn't exist
refcounted &operator = (const refcounted &rc) = delete;
};
template<class T>

219
lib/set.h
View File

@ -1,149 +1,46 @@
/* wrap for std::set */
template<class T> class set_iter;
template<class T> class set_const_iter;
/* wrapper for std::set */
template<class T>
class set
class set : public set_wrapper<std::set<T>, T>
{
private:
friend class set_iter<T>;
friend class set_const_iter<T>;
class set_impl : public refcounted
{
public:
std::set<T> t;
};
ptr<set_impl> impl;
typedef set_wrapper<std::set<T>, T> base;
public:
typedef set_iter<T> iter;
typedef set_const_iter<T> const_iter;
public:
set () : impl(new set_impl) { }
set (unsigned dummy_size) : impl(new set_impl) { }
set (const set &s) : impl(s.impl) { }
set (copy, const set &s) : impl(new set_impl) { impl->t = std::set<T> (s.impl->t); }
set (reader &r);
set () { }
set (const set &m) : base(m) { }
set (copy, const set &m) : base(COPY, m) { }
set (initializer_list<T> il) : base(il) { }
set (reader &r) : base(r) { }
~set () { }
set &operator = (const set &s) { impl = s.impl; return *this; }
T pop ()
{
typename std::set<T>::const_iterator i = impl->t.begin ();
assert (i != impl->t.end ());
T tmp = *i;
impl->t.erase (i);
return tmp;
}
bool is_empty () const { return impl->t.empty (); }
unsigned card () const { return impl->t.size (); }
const T &head () const;
const T &tail () const;
set &operator = (const set &m) { base::operator = (m); return *this; }
set &operator = (initializer_list<T> il) { base::operator = (il); }
bool operator == (const set &s) const;
bool operator != (const set &s) const { return !operator == (s); }
bool operator < (const set &s) const;
bool operator <= (const set &s) const;
void clear () { impl->t.clear (); }
void push (const T &v) { assert (impl->t.find (v) == impl->t.end ()); impl->t.insert (v); }
bool toggle (const T &v);
void operator += (const T &v) { impl->t.insert (v); }
void operator -= (const T &v) { impl->t.erase (v); }
void yank (const T &v) { assert (operator % (v)); impl->t.erase (v); }
set &operator |= (const set<T> &s);
set &operator &= (const set<T> &s);
set &operator ^= (const set<T> &s);
bool operator % (const T &v) const { return impl->t.find (v) != impl->t.end (); }
bool operator () (const T &v) const { return operator % (v); }
void write_self (writer &w) const;
hash_t hash_self () const;
set &operator |= (const set &s);
set &operator &= (const set &s);
set &operator ^= (const set &s);
};
template<class T>
class set_iter
{
set<T> &s;
typename std::set<T>::const_iterator i, end;
bool deleted;
public:
set_iter (set<T> &s_) : s(s_), i(s_.impl->t.begin ()), end(s_.impl->t.end ()), deleted(0) { }
~set_iter () { }
void del ()
{
assert (!deleted);
typename std::set<T>::const_iterator iprev = i ++;
s.impl->t.erase (iprev);
deleted = 1;
}
const T &val () const { assert (!deleted); return *i; }
operator bool () const { assert (!deleted); return i != end; }
set_iter &operator ++ () { if (deleted) deleted = 0; else i ++; return *this; }
void operator ++ (int) { operator ++ (); }
};
using set_iter = set_wrapper_iter<std::set<T>, T>;
template<class T>
class set_const_iter
{
typename std::set<T>::const_iterator i, end;
public:
set_const_iter (const set<T> &s) : i(s.impl->t.begin ()), end(s.impl->t.end ()) { }
~set_const_iter () { }
const T &val () const { return *i; }
operator bool () const { return i != end; }
set_const_iter &operator ++ () { i ++; return *this; }
void operator ++ (int) { i ++; }
};
template<class T>
set<T>::set (reader &r)
{
unsigned n;
read (r, n);
T x;
for (unsigned i = 0; i < n; i ++)
{
read (r, x);
push (x);
}
}
template<class T> const T &
set<T>::head () const
{
set_const_iter<T> i = *this;
assert (i);
return i.val ();
}
template<class T> const T &
set<T>::tail () const
{
typename std::set<T>::const_reverse_iterator i = impl->t.rbegin ();
assert (i != impl->t.rend ());
return *i;
}
using set_const_iter = set_wrapper_const_iter<std::set<T>, T>;
template<class T> bool
set<T>::operator == (const set &s) const
{
typename std::set<T>::const_iterator i = impl->t.begin (),
typename std::set<T>::const_iterator i = this->impl->t.begin (),
j = s.impl->t.begin (),
iend = impl->t.end (),
iend = this->impl->t.end (),
jend = s.impl->t.end ();
while (i != iend && j != jend && *i == *j)
@ -155,9 +52,9 @@ set<T>::operator == (const set &s) const
template<class T> bool
set<T>::operator < (const set &s) const
{
typename std::set<T>::const_iterator i = impl->t.begin (),
typename std::set<T>::const_iterator i = this->impl->t.begin (),
j = s.impl->t.begin (),
iend = impl->t.end (),
iend = this->impl->t.end (),
jend = s.impl->t.end ();
while (i != iend && j != jend && *i == *j)
@ -169,9 +66,9 @@ set<T>::operator < (const set &s) const
template<class T> bool
set<T>::operator <= (const set &s) const
{
typename std::set<T>::const_iterator i = impl->t.begin (),
typename std::set<T>::const_iterator i = this->impl->t.begin (),
j = s.impl->t.begin (),
iend = impl->t.end (),
iend = this->impl->t.end (),
jend = s.impl->t.end ();
while (i != iend && j != jend && *i == *j)
@ -184,56 +81,56 @@ set<T>::operator <= (const set &s) const
template<class T> bool
set<T>::toggle (const T &v)
{
typename std::set<T>::const_iterator i = impl->t.lower_bound (v),
end = impl->t.end ();
typename std::set<T>::const_iterator i = this->impl->t.lower_bound (v),
end = this->impl->t.end ();
if (i != end && *i == v)
{
impl->t.erase (i);
this->impl->t.erase (i);
return 1;
}
else
{
if (i == impl->t.begin ())
impl->t.insert (v);
if (i == this->impl->t.begin ())
this->impl->t.insert (v);
else
{
typename std::set<T>::const_iterator j = --i;
assert (*j < v);
impl->t.insert (j, v);
this->impl->t.insert (j, v);
}
return 0;
}
}
template<class T> set<T> &
set<T>::operator |= (const set<T> &s)
set<T>::operator |= (const set &s)
{
std::set<T> news;
std::set_union (impl->t.begin (), impl->t.end (),
std::set_union (this->impl->t.begin (), this->impl->t.end (),
s.impl->t.begin (), s.impl->t.end (),
inserter (news, news.begin ()));
impl->t = news;
this->impl->t = news;
return *this;
}
template<class T> set<T> &
set<T>::operator &= (const set<T> &s)
set<T>::operator &= (const set &s)
{
std::set<T> news;
std::set_intersection (impl->t.begin (), impl->t.end (),
std::set_intersection (this->impl->t.begin (), this->impl->t.end (),
s.impl->t.begin (), s.impl->t.end (),
inserter (news, news.begin ()));
impl->t = news;
this->impl->t = news;
return *this;
}
template<class T> set<T> &
set<T>::operator ^= (const set<T> &s)
set<T>::operator ^= (const set &s)
{
#if 0
printf ("before:\n");
printf ("this:");
for (typename std::set<T>::const_iterator i = impl->t.begin (); i != impl->t.end (); i ++)
for (typename std::set<T>::const_iterator i = this->impl->t.begin (); i != this->impl->t.end (); i ++)
printf (" %d", *i);
printf ("\n");
printf ("s:");
@ -243,25 +140,25 @@ set<T>::operator ^= (const set<T> &s)
#endif
#if 1
typename std::set<T>::const_iterator i = impl->t.begin (),
iend = impl->t.end (),
typename std::set<T>::const_iterator i = this->impl->t.begin (),
iend = this->impl->t.end (),
j = s.impl->t.begin (),
jend = s.impl->t.end ();
while (i != iend && j != jend && *i == *j)
{
impl->t.erase (i);
i = impl->t.begin ();
this->impl->t.erase (i);
i = this->impl->t.begin ();
j ++;
}
if (i == iend)
impl->t.insert (j, jend);
this->impl->t.insert (j, jend);
else
{
if (j != jend && *j < *i)
{
i = impl->t.insert (*j).first;
i = this->impl->t.insert (*j).first;
j ++;
}
@ -274,14 +171,14 @@ set<T>::operator ^= (const set<T> &s)
{
while (j != jend)
{
iprev = impl->t.insert (iprev, *j);
iprev = this->impl->t.insert (iprev, *j);
j ++;
}
break;
}
else if (*i == *j)
{
impl->t.erase (i);
this->impl->t.erase (i);
i = iprev;
j ++;
}
@ -289,12 +186,12 @@ set<T>::operator ^= (const set<T> &s)
{
while (j != jend && *j < *i)
{
iprev = impl->t.insert (iprev, *j);
iprev = this->impl->t.insert (iprev, *j);
j ++;
}
if (j != jend && *j == *i)
{
impl->t.erase (i);
this->impl->t.erase (i);
i = iprev;
j ++;
}
@ -305,37 +202,19 @@ set<T>::operator ^= (const set<T> &s)
#if 0
std::set<T> news;
std::set_symmetric_difference (impl->t.begin (), impl->t.end (),
std::set_symmetric_difference (this->impl->t.begin (), this->impl->t.end (),
s.impl->t.begin (), s.impl->t.end (),
inserter (news, news.begin ()));
impl->t = news;
this->impl->t = news;
#endif
#if 0
printf ("after:\n");
printf ("this:");
for (typename std::set<T>::const_iterator i = impl->t.begin (); i != impl->t.end (); i ++)
for (typename std::set<T>::const_iterator i = this->impl->t.begin (); i != this->impl->t.end (); i ++)
printf (" %d", *i);
printf ("\n");
#endif
return *this;
}
template<class T> void
set<T>::write_self (writer &w) const
{
write (w, card ());
for (const_iter i = *this; i; i ++)
write (w, i.val ());
}
template<class T> hash_t
set<T>::hash_self () const
{
hash_t h = hash (card ());
unsigned j = 0;
for (const_iter i = *this; i && j < 10; i ++, j ++)
h = hash_combine (h, hash (i.val ()));
return h;
}

171
lib/set_wrapper.h Normal file
View File

@ -0,0 +1,171 @@
/* wrapper for STL maps */
template<class S, class T> class set_wrapper_iter;
template<class S, class T> class set_wrapper_const_iter;
template<class S, class T>
class set_wrapper
{
friend class set_wrapper_iter<S, T>;
friend class set_wrapper_const_iter<S, T>;
protected:
class set_wrapper_impl : public refcounted
{
public:
S t;
public:
set_wrapper_impl () = default;
set_wrapper_impl (const set_wrapper_impl &) = delete;
set_wrapper_impl (const S &t_) : t(t_) { }
set_wrapper_impl (initializer_list<T> il) : t(il) { }
~set_wrapper_impl () = default;
set_wrapper_impl &operator = (const set_wrapper_impl &) = delete;
};
ptr<set_wrapper_impl> impl;
public:
typedef set_wrapper_iter<S, T> iter;
typedef set_wrapper_const_iter<S, T> const_iter;
public:
set_wrapper () : impl(new set_wrapper_impl) { }
set_wrapper (const set_wrapper &s) : impl(s.impl) { }
set_wrapper (copy, const set_wrapper &s)
: impl(new set_wrapper_impl (s.impl->t))
{ }
set_wrapper (initializer_list<T> il)
: impl(new set_wrapper_impl (il))
{ }
set_wrapper (reader &r);
~set_wrapper () { }
set_wrapper &operator = (const set_wrapper &s) { impl = s.impl; return *this; }
set_wrapper &operator = (initializer_list<T> li)
{
impl->t = li;
}
// range-based for
typename S::const_iterator begin () const { return impl->t.begin (); }
typename S::const_iterator end () const { return impl->t.end (); }
T pop ()
{
typename S::const_iterator i = impl->t.begin ();
assert (i != impl->t.end ());
T tmp = *i;
impl->t.erase (i);
return tmp;
}
bool is_empty () const { return impl->t.empty (); }
unsigned card () const { return impl->t.size (); }
const T &head () const;
const T &tail () const;
void clear () { impl->t.clear (); }
void push (const T &v) { assert (impl->t.find (v) == impl->t.end ()); impl->t.insert (v); }
void operator += (const T &v) { impl->t.insert (v); }
void operator -= (const T &v) { impl->t.erase (v); }
void yank (const T &v) { assert (operator % (v)); impl->t.erase (v); }
bool operator % (const T &v) const { return impl->t.find (v) != impl->t.end (); }
bool operator () (const T &v) const { return operator % (v); }
void write_self (writer &w) const;
hash_t hash_self () const;
};
template<class S, class T>
class set_wrapper_iter
{
ptr<typename set_wrapper<S, T>::set_wrapper_impl> impl;
typename S::const_iterator i, end;
bool deleted;
public:
set_wrapper_iter (set_wrapper<S, T> &s) : impl(s.impl), i(s.impl->t.begin ()), end(s.impl->t.end ()), deleted(0) { }
~set_wrapper_iter () { }
void del ()
{
assert (!deleted);
typename S::const_iterator iprev = i ++;
impl->t.erase (iprev);
deleted = 1;
}
const T &val () const { assert (!deleted); return *i; }
operator bool () const { assert (!deleted); return i != end; }
set_wrapper_iter &operator ++ () { if (deleted) deleted = 0; else i ++; return *this; }
void operator ++ (int) { operator ++ (); }
};
template<class S, class T>
class set_wrapper_const_iter
{
ptr<const typename set_wrapper<S, T>::set_wrapper_impl> impl;
typename S::const_iterator i, end;
public:
set_wrapper_const_iter (const set_wrapper<S, T> &s) : impl(s.impl), i(s.impl->t.begin ()), end(s.impl->t.end ()) { }
~set_wrapper_const_iter () { }
const T &val () const { return *i; }
operator bool () const { return i != end; }
set_wrapper_const_iter &operator ++ () { i ++; return *this; }
void operator ++ (int) { i ++; }
};
template<class S, class T>
set_wrapper<S, T>::set_wrapper (reader &r)
: impl(new set_wrapper_impl)
{
unsigned n;
read (r, n);
T x;
for (unsigned i = 0; i < n; i ++)
{
read (r, x);
push (x);
}
}
template<class S, class T> const T &
set_wrapper<S, T>::head () const
{
set_wrapper_const_iter<S, T> i = *this;
assert (i);
return i.val ();
}
template<class S, class T> const T &
set_wrapper<S, T>::tail () const
{
typename S::const_reverse_iterator i = impl->t.rbegin ();
assert (i != impl->t.rend ());
return *i;
}
template<class S, class T> void
set_wrapper<S, T>::write_self (writer &w) const
{
write (w, card ());
for (const_iter i = *this; i; i ++)
write (w, i.val ());
}
template<class S, class T> hash_t
set_wrapper<S, T>::hash_self () const
{
hash_t h = hash (card ());
unsigned j = 0;
for (const_iter i = *this; i && j < 10; i ++, j ++)
h = hash_combine (h, hash (i.val ()));
return h;
}

View File

@ -2,12 +2,15 @@
template<unsigned B> class ullmanset_iter;
template<unsigned B> class ullmanset_const_iter;
template<unsigned B> class ullmanset_const_stl_iter;
template<unsigned B>
class ullmanset
{
private:
friend class ullmanset_iter<B>;
friend class ullmanset_const_iter<B>;
friend class ullmanset_const_stl_iter<B>;
class keypos
{
@ -16,57 +19,56 @@ class ullmanset
unsigned pos;
};
class data
class data : public refcounted
{
public:
unsigned refcount;
unsigned size;
unsigned n;
keypos kp[1];
public:
inline void delete_at_pos (unsigned p);
};
data *d;
void ref (data *newd) { assert (!d); d = newd; if (d) d->refcount ++; }
void unref ();
inline void delete_at_pos (unsigned p);
ptr<data> d;
public:
typedef ullmanset_iter<B> iter;
typedef ullmanset_const_iter<B> const_iter;
public:
ullmanset () : d(0) { }
ullmanset (unsigned size);
ullmanset (const ullmanset &s) : d(0) { ref (s.d); }
ullmanset () : ullmanset(0) { }
ullmanset (const ullmanset &s) : d(s.d) { }
ullmanset (copy, const ullmanset &s);
// ullmanset (const unsignedset &t);
ullmanset (const bitset &t);
ullmanset (unsigned size, initializer_list<unsigned> il);
ullmanset (reader &r);
~ullmanset () { unref (); }
~ullmanset () { }
ullmanset &operator = (const ullmanset &s) { unref (); ref (s.d); return *this; }
// ullmanset &operator = (const unsignedset &t);
ullmanset &operator = (const ullmanset &s) { d = s.d; return *this; }
ullmanset &operator = (const bitset &t);
unsigned size () const { return d ? d->size : 0; }
// range-based for
inline ullmanset_const_stl_iter<B> begin () const;
inline ullmanset_const_stl_iter<B> end () const;
bool is_empty () const { assert (d); return d->n == 0; }
unsigned card () const { assert (d); return d->n; }
unsigned head () const { assert (d); assert (d->n > 0); return d->kp[0].key; }
unsigned size () const { return d->size; }
bool is_empty () const { return d->n == 0; }
unsigned card () const { return d->n; }
unsigned head () const { assert (d->n > 0); return d->kp[0].key; }
bool operator == (const ullmanset &s);
bool operator != (const ullmanset &s) { return !operator == (s); }
void restore (unsigned old_card)
{
assert (d);
assert (d->n >= old_card);
d->n = old_card;
}
void clear () { if (d) { d->n = 0; } }
void clear () { d->n = 0; }
inline void push (unsigned k);
inline void operator += (unsigned k); // ??? should these be inline?
@ -88,89 +90,75 @@ class ullmanset
bool operator % (unsigned k) const
{
assert (d);
assert ((k - B) >= 0);
assert ((k - B) < d->size);
unsigned p = d->kp[k - B].pos;
return p < d->n && d->kp[p].key == k;
}
bool operator () (unsigned k) const { return operator % (k); }
// always 0-based
unsigned nth (unsigned p) const { assert (d); assert (p < d->n); return d->kp[p].key; }
unsigned nth (unsigned p) const
{
assert (p < d->n);
return d->kp[p].key;
}
unsigned position (unsigned k) const { assert (operator % (k)); return d->kp[k - B].pos; }
unsigned position (unsigned k) const
{
assert (operator % (k));
return d->kp[k - B].pos;
}
void write_self (writer &w) const;
};
template<unsigned B> void
ullmanset<B>::unref ()
ullmanset<B>::data::delete_at_pos (unsigned p)
{
if (d && --d->refcount == 0)
{
delete [] (char *)d;
d = 0;
}
}
template<unsigned B> void
ullmanset<B>::delete_at_pos (unsigned p)
{
assert (d);
assert (p < d->n);
unsigned n = --d->n;
assert (p < n);
--n;
if (p != n)
{
unsigned ell = d->kp[n].key;
d->kp[ell - B].pos = p;
d->kp[p].key = ell;
unsigned ell = kp[n].key;
kp[ell - B].pos = p;
kp[p].key = ell;
}
}
template<unsigned B>
ullmanset<B>::ullmanset (unsigned size)
: d(0)
{
data *newd = (data *)new char[sizeof (data)
+ sizeof (keypos) * size
- sizeof (keypos)];
newd->refcount = 0;
new (newd) data;
newd->size = size;
newd->n = 0;
ref (newd);
d = newd;
}
template<unsigned B>
ullmanset<B>::ullmanset (unsigned size, initializer_list<unsigned> il)
: ullmanset(size)
{
for (unsigned i : il)
operator += (i);
}
template<unsigned B>
ullmanset<B>::ullmanset (copy, const ullmanset &s)
: d(0)
: ullmanset(s.size ())
{
if (s.d)
{
unsigned bytes = (sizeof (data)
+ sizeof (keypos) * s.d->size
- sizeof (keypos));
data *newd = (data *)new char[bytes];
memcpy (newd, s.d, bytes);
newd->refcount = 0;
ref (newd);
}
d->n = s.d->n;
memcpy (&d->kp[0], &s.d->kp[0], sizeof (keypos) * d->n);
}
template<unsigned B>
ullmanset<B>::ullmanset (reader &r)
: d(0)
: ullmanset(r.read_unsigned ())
{
unsigned size_ = r.read_unsigned ();
if (size_ > 0)
{
data *newd = (data *)new char[sizeof (data) + sizeof (keypos) * (size_ - 1)];
newd->refcount = 0;
newd->size = size_;
newd->n = 0;
ref (newd);
}
unsigned card_ = r.read_unsigned ();
for (unsigned i = 0; i < card_; i ++)
push (r.read_unsigned ());
@ -179,8 +167,6 @@ ullmanset<B>::ullmanset (reader &r)
template<unsigned B> bool
ullmanset<B>::operator == (const ullmanset &s)
{
assert (d);
assert (s.d);
if (d->n != s.d->n)
return 0;
for (iter i = *this; i; i ++)
@ -194,7 +180,6 @@ ullmanset<B>::operator == (const ullmanset &s)
template<unsigned B> void
ullmanset<B>::push (unsigned k)
{
assert (d);
assert (!operator % (k));
unsigned p = d->n ++;
d->kp[p].key = k;
@ -204,7 +189,6 @@ ullmanset<B>::push (unsigned k)
template<unsigned B> void
ullmanset<B>::operator += (unsigned k)
{
assert (d);
assert ((k - B) >= 0);
assert ((k - B) < d->size);
if (!operator % (k))
@ -218,13 +202,12 @@ ullmanset<B>::operator += (unsigned k)
template<unsigned B> void
ullmanset<B>::operator -= (unsigned k)
{
assert (d);
assert ((k - B) >= 0);
assert ((k - B) < d->size);
if (operator % (k))
{
unsigned p = d->kp[k - B].pos;
delete_at_pos (p);
d->delete_at_pos (p);
}
}
@ -270,22 +253,49 @@ ullmanset<B>::write_self (writer &w) const
write (w, i.val ());
}
template<unsigned B>
class ullmanset_const_stl_iter
{
private:
ptr<typename ullmanset<B>::data> d;
unsigned p;
public:
ullmanset_const_stl_iter (const ullmanset<B> &s, unsigned p_) : d(s.d), p(p_) { }
bool operator != (const ullmanset_const_stl_iter &end) const { return p != end.p; }
unsigned operator * () const { assert (p < d->n); return d->kp[p].key; }
ullmanset_const_stl_iter &operator ++ () { p ++; return *this; }
};
template<unsigned B> ullmanset_const_stl_iter<B>
ullmanset<B>::begin () const
{
return ullmanset_const_stl_iter<B> (*this, 0);
}
template<unsigned B> ullmanset_const_stl_iter<B>
ullmanset<B>::end () const
{
return ullmanset_const_stl_iter<B> (*this, d->n);
}
template<unsigned B>
class ullmanset_iter
{
private:
ullmanset<B> &s;
ptr<typename ullmanset<B>::data> d;
unsigned i;
bool deleted;
public:
ullmanset_iter (ullmanset<B> &s_) : s(s_), i(0), deleted(0) { assert (s_.d); }
ullmanset_iter (ullmanset<B> &s) : d(s.d), i(0), deleted(0) { }
~ullmanset_iter () { }
void del () { assert (!deleted); assert (i < s.d->n); s.delete_at_pos (i); }
unsigned val () const { assert (!deleted); assert (i < s.d->n); return s.d->kp[i].key; }
unsigned pos () const { assert (!deleted); assert (i < s.d->n); return i; }
operator bool () const { assert (!deleted); return i < s.d->n; }
void del () { assert (!deleted); assert (i < d->n); d->delete_at_pos (i); }
unsigned val () const { assert (!deleted); assert (i < d->n); return d->kp[i].key; }
unsigned pos () const { assert (!deleted); assert (i < d->n); return i; }
operator bool () const { assert (!deleted); return i < d->n; }
void operator ++ () { if (deleted) deleted = 0; else i ++; }
void operator ++ (int) { operator ++ (); }
};
@ -294,16 +304,16 @@ template<unsigned B>
class ullmanset_const_iter
{
private:
const ullmanset<B> &s;
ptr<typename ullmanset<B>::data> d;
unsigned i;
public:
ullmanset_const_iter (const ullmanset<B> &s_) : s(s_), i(0) { assert (s_.d); }
ullmanset_const_iter (const ullmanset<B> &s) : d(s.d), i(0) { }
~ullmanset_const_iter () { }
unsigned val () const { assert (i < s.d->n); return s.d->kp[i].key; }
unsigned pos () const { assert (i < s.d->n); return i; }
operator bool () const { return i < s.d->n; }
unsigned val () const { assert (i < d->n); return d->kp[i].key; }
unsigned pos () const { assert (i < d->n); return i; }
operator bool () const { return i < d->n; }
void operator ++ () { i ++; }
void operator ++ (int) { i ++; }
};

View File

@ -36,8 +36,10 @@ public:
vector &operator = (const vector &v) { unref (); ref (v.d); return *this; }
bool operator < (const vector &v) const;
bool operator == (const vector &v) const;
bool operator != (const vector &v) const { return !operator == (v); }
bool operator < (const vector &v) const;
bool operator % (unsigned i) { return d && i < d->n; }

3422
main.cpp

File diff suppressed because it is too large Load Diff

133
mpi_aux.cpp Normal file
View File

@ -0,0 +1,133 @@
#include <mpi.h>
#include <mpi_aux.h>
// #include <knotkit.h>
#define DATATAG 1
void
comm_init (int *argc, char ***argv)
{
MPI_Init (argc, argv);
}
void
comm_finalize ()
{
MPI_Finalize ();
}
int
self_rank ()
{
int node;
MPI_Comm_rank (MPI_COMM_WORLD, &node);
return node;
}
int
num_tasks ()
{
int ntasks;
MPI_Comm_size (MPI_COMM_WORLD, &ntasks);
return ntasks;
}
void
send_int (int v, int dest)
{
MPI_Send (&v, 1, MPI_INT, dest, DATATAG, MPI_COMM_WORLD);
}
void
send_string (const char *s, int dest)
{
int n = strlen (s);
MPI_Send (&n, 1, MPI_INT, dest, DATATAG, MPI_COMM_WORLD);
MPI_Send ((void *)s, n, MPI_CHAR, dest, DATATAG, MPI_COMM_WORLD);
}
void
send_string (const std::string &s, int dest)
{
send_string (s.c_str (), dest);
}
int
recv_int (int *src)
{
int v;
MPI_Status status;
MPI_Recv (&v, /* message buffer */
1, /* one data item */
MPI_INT, /* of type int */
MPI_ANY_SOURCE, /* receive from any sender */
MPI_ANY_TAG, /* any type of message */
MPI_COMM_WORLD, /* default communicator */
&status); /* info about the received message */
if (src)
*src = status.MPI_SOURCE;
return v;
}
std::string
recv_string (int *src)
{
int n;
MPI_Status status;
MPI_Recv (&n, /* message buffer */
1, /* one data item */
MPI_INT, /* of type int */
MPI_ANY_SOURCE, /* receive from any sender */
MPI_ANY_TAG, /* any type of message */
MPI_COMM_WORLD, /* default communicator */
&status); /* info about the received message */
char *s = new char[n + 1];
MPI_Recv (s, /* message buffer */
n, /* one data item */
MPI_CHAR, /* of type int */
status.MPI_SOURCE, /* receive from any sender */
MPI_ANY_TAG, /* any type of message */
MPI_COMM_WORLD, /* default communicator */
&status); /* info about the received message */
if (src)
*src = status.MPI_SOURCE;
s[n] = '\0';
std::string s_std (s);
delete [] s;
return s_std;
}
#if 0
void
send_htw_knot (unsigned n, bool alternating, unsigned k, int dest)
{
int data[3];
data[0] = (int)n;
data[1] = (int)alternating;
data[2] = (int)k;
MPI_Send (&data, 3, MPI_INT, dest, DATATAG, MPI_COMM_WORLD);
}
knot_diagram
recv_knot (int *src)
{
int data[3];
MPI_Status status;
MPI_Recv (&data, /* message buffer */
3, /* one data item */
MPI_INT, /* of type int */
MPI_ANY_SOURCE, /* receive from any sender */
MPI_ANY_TAG, /* any type of message */
MPI_COMM_WORLD, /* default communicator */
&status); /* info about the received message */
if (src)
*src = status.MPI_SOURCE;
dt_code k = htw_knot ((unsigned)data[0],
(bool)data[1],
(unsigned)data[2]);
return knot_diagram (k);
}
#endif

22
mpi_aux.h Normal file
View File

@ -0,0 +1,22 @@
void comm_init (int *argc, char ***argv);
void comm_finalize ();
int self_rank ();
int num_tasks ();
void send_int (int v, int dest);
void send_string (const char *s, int dest);
void send_string (const std::string &s, int dest);
int recv_int (int *src);
std::string recv_string (int *src);
inline int recv_int () { return recv_int (0); }
inline std::string recv_string () { return recv_string (0); }
#if 0
void send_htw_knot (unsigned n, bool alternating, unsigned k, int dest);
knot_diagram recv_knot (int *src);
knot_diagram recv_knot () { return recv_knot (0); }
#endif

578
mpimain.cpp Normal file
View File

@ -0,0 +1,578 @@
#include <knotkit.h>
#include <mpi.h>
#include <mpi_aux.h>
#define CMD_DO 1
#define CMD_DIE 2
static const int block_size = 100;
void
master ()
{
basedvector<knot_desc, 1> work;
for (unsigned i = 1; i <= 10; i ++)
for (unsigned j = 1; j <= mt_links (i); j ++)
{
knot_diagram kd (mt_links (i, j));
unsigned n = kd.num_components ();
if (n < 2)
continue;
work.append (knot_desc (knot_desc::MT, i, j));
}
#if 0
basedvector<basedvector<unsigned, 1>, 1> groups = mutant_knot_groups (15);
for (unsigned i = 1; i <= groups.size (); i ++)
for (unsigned j = 1; j <= groups[i].size (); j ++)
work.append (knot_desc (knot_desc::HTW, 15, groups[i][j]));
#endif
#if 0
for (unsigned i = 14; i >= 1; i --)
{
if (i <= 10)
{
for (unsigned j = 1; j <= rolfsen_crossing_knots (i); j += block_size)
{
work.append (knot_desc (ROLFSEN, i, j));
}
}
for (unsigned j = 1; j <= htw_knots (i); j += block_size)
{
work.append (knot_desc (HTW, i, j));
}
if (i <= 13)
{
for (unsigned j = 1; j <= mt_links (i); j += block_size)
{
work.append (knot_desc (MT, i, j));
}
}
}
#endif
int ntasks = num_tasks ();
set<unsigned> active;
for (int rank = 1; rank < ntasks && work.size () > 0; rank ++)
{
send_int (CMD_DO, rank);
knot_desc desc = work.pop ();
send_int ((int)desc.t, rank);
send_int ((int)desc.i, rank);
send_int ((int)desc.j, rank);
active.push (rank);
}
while (work.size () > 0)
{
int rank;
int dummy = recv_int (&rank);
send_int (CMD_DO, rank);
knot_desc desc = work.pop ();
send_int ((int)desc.t, rank);
send_int ((int)desc.i, rank);
send_int ((int)desc.j, rank);
}
while (active.card () > 0)
{
int rank;
int dummy = recv_int (&rank);
active -= rank;
}
for (int rank = 1; rank < ntasks; rank ++)
{
send_int (CMD_DIE, rank);
}
}
bool
file_exists (const char *file)
{
struct stat stat_buf;
if (stat (file, &stat_buf) != 0)
{
if (errno == ENOENT)
return 0;
stderror ("stat: %s", file);
exit (EXIT_FAILURE);
}
return 1;
}
#if 0
void
compute_forgetful (int rank, knot_desc desc, const char *buf)
{
knot_diagram kd = desc.diagram ();
typedef Zp<97> R;
unsigned n = kd.num_components ();
assert (n >= 2);
assert (n < 97);
printf ("[% 2d] ", rank);
show (kd);
newline ();
unionfind<1> u (kd.num_edges ());
for (unsigned i = 1; i <= kd.n_crossings; i ++)
{
u.join (kd.ept_edge (kd.crossings[i][1]),
kd.ept_edge (kd.crossings[i][3]));
u.join (kd.ept_edge (kd.crossings[i][2]),
kd.ept_edge (kd.crossings[i][4]));
}
map<unsigned, unsigned> root_comp;
unsigned t = 0;
for (unsigned i = 1; i <= kd.num_edges (); i ++)
{
if (u.find (i) == i)
{
++ t;
root_comp.push (i, t);
}
}
assert (t == n);
basedvector<R, 1> comp_weight (n);
for (unsigned i = 1; i <= n; i ++)
comp_weight[i] = R ((int)i);
map<unsigned, R> crossing_over_sign;
// crossings
set<unsigned> pending;
set<unsigned> finished;
crossing_over_sign.push (1, R (1));
pending.push (1);
while (pending.card () > 0)
{
unsigned x = pending.pop ();
finished.push (x);
R s = crossing_over_sign(x);
for (unsigned j = 1; j <= 4; j ++)
{
unsigned p = kd.crossings[x][j];
R t = kd.is_over_ept (p) ? s : -s; // sign of (x, p)
unsigned q = kd.edge_other_ept (p);
unsigned x2 = kd.ept_crossing[q];
R u = kd.is_over_ept (q) ? -t : t;
if (crossing_over_sign % x2)
assert (crossing_over_sign(x2) == u);
else
crossing_over_sign.push (x2, u);
if (! (finished % x2))
pending += x2;
}
}
assert (finished.card () == kd.n_crossings);
#if 0
printf ("crossing_over_sign:\n");
for (unsigned i = 1; i <= kd.n_crossings; i ++)
{
printf (" % 2d: ", i);
display (crossing_over_sign(i));
}
#endif
cube<R> c (kd);
#if 0
for (unsigned i = 0; i < c.n_resolutions; i ++)
{
smallbitset state (kd.n_crossings, i);
smoothing s (kd, state);
s.show_self (kd, state);
newline ();
}
#endif
mod_map<R> untwisted_d = c.compute_d (1, 0, 0, 0, 0);
assert (untwisted_d.compose (untwisted_d) == 0);
mod_map<R> d = untwisted_d;
for (unsigned x = 1; x <= kd.n_crossings; x ++)
{
unsigned p1 = kd.crossings[x][1],
p2 = kd.crossings[x][2];
assert (kd.is_over_ept (p2));
unsigned r1 = u.find (kd.ept_edge (p1)),
r2 = u.find (kd.ept_edge (p2));
unsigned c1 = root_comp(r1),
c2 = root_comp(r2);
if (c1 != c2)
{
R s = crossing_over_sign(x);
R w_under = comp_weight[c1];
R w_over = comp_weight[c2];
d = d + c.compute_dinv (x)*(s*(w_over - w_under))
;
}
}
// display ("d:\n", d);
// mod_map<Z> h = d.compose (d);
// display ("h:\n", h);
assert (d.compose (d) == 0);
ptr<const module<R> > Ek = c.khC;
mod_map<R> dk = d;
basedvector<multivariate_laurentpoly<Z>, 1> pages;
unsigned kinf;
for (int dq = 0;; dq -= 2)
{
chain_complex_simplifier<R> s (Ek, dk, dq);
Ek = s.new_C;
dk = s.new_d;
pages.append (Ek->free_poincare_polynomial ());
printf ("[% 2d] ", rank);
printf ("|E%d| = %d\n", ((- dq) / 2) + 1, Ek->dim ());
if (dk == 0)
{
kinf = ((- dq) / 2);
break;
}
}
unsigned total_lk = kd.total_linking_number ();
unsigned trivial_bound = total_lk == 0 ? 2 : total_lk;
printf ("[% 2d] ", rank);
printf ("kinf = %d, trivial bound = %d (total_lk = %d)\n",
kinf, trivial_bound, total_lk);
if (trivial_bound < kinf)
{
printf ("[% 2d] ", rank);
printf (" > BETTER\n");
}
fflush (stdout);
assert (desc.t == knot_desc::MT);
gzfile_writer w (buf);
write (w, desc);
write (w, pages);
}
#endif
unsigned
compute_b_lk_weak (knot_diagram &kd)
{
unsigned m = kd.num_components ();
assert (m > 1);
if (m == 2)
{
unsigned total_lk = kd.total_linking_number ();
return total_lk == 0 ? 2 : total_lk;
}
unionfind<1> u (kd.num_edges ());
for (unsigned i = 1; i <= kd.n_crossings; i ++)
{
u.join (kd.ept_edge (kd.crossings[i][1]),
kd.ept_edge (kd.crossings[i][3]));
u.join (kd.ept_edge (kd.crossings[i][2]),
kd.ept_edge (kd.crossings[i][4]));
}
assert (m == u.num_sets ());
map<unsigned, unsigned> root_comp;
unsigned t = 0;
for (unsigned i = 1; i <= kd.num_edges (); i ++)
{
if (u.find (i) == i)
{
++ t;
root_comp.push (i, t);
}
}
assert (t == m);
unsigned b_lk_weak = 0;
for (unsigned i = 1; i <= m; i ++)
for (unsigned j = i + 1; j <= m; j ++)
{
assert (i < j);
int lk = 0;
for (unsigned x = 1; x <= kd.n_crossings; x ++)
{
unsigned r1 = root_comp(u.find (kd.ept_edge (kd.crossings[x][1]))),
r2 = root_comp(u.find (kd.ept_edge (kd.crossings[x][2])));
if (((r1 == i) && (r2 == j))
|| ((r2 == i) && (r1 == j)))
{
if (kd.is_to_ept (kd.crossings[x][1]) == kd.is_to_ept (kd.crossings[x][4]))
lk ++;
else
lk --;
}
}
assert (is_even (lk));
lk /= 2;
if (lk == 0)
{
smallbitset ci (m);
ci.push (i);
smallbitset cj (m);
cj.push (j);
smallbitset c (m);
c.push (i);
c.push (j);
knot_diagram Lij (SUBLINK, c, kd);
multivariate_laurentpoly<Z> P_Lij = Kh_poincare_polynomial<Z2> (Lij);
knot_diagram Li_join_Lj (DISJOINT_UNION,
knot_diagram (SUBLINK, ci, kd),
knot_diagram (SUBLINK, cj, kd));
multivariate_laurentpoly<Z> P_Li_join_Lj = Kh_poincare_polynomial<Z2> (Li_join_Lj);
if (P_Lij != P_Li_join_Lj)
lk = 2; // non-split
}
b_lk_weak += abs (lk);
}
return b_lk_weak == 0 ? 2 : b_lk_weak;
}
void
compute_splitting_bounds (const knot_desc &desc)
{
typedef fraction_field<polynomial<Z2> > Z2x;
int rank = self_rank ();
knot_diagram kd = desc.diagram ();
unsigned m = kd.num_components ();
assert (m > 1);
printf ("[% 2d] ", rank); show (kd); newline ();
printf ("[% 2d] m = %d\n", rank, m);
unsigned total_lk = kd.total_linking_number ();
printf ("[% 2d] total_lk = %d\n", rank, total_lk);
unionfind<1> u (kd.num_edges ());
for (unsigned i = 1; i <= kd.n_crossings; i ++)
{
u.join (kd.ept_edge (kd.crossings[i][1]),
kd.ept_edge (kd.crossings[i][3]));
u.join (kd.ept_edge (kd.crossings[i][2]),
kd.ept_edge (kd.crossings[i][4]));
}
assert (u.num_sets () == m);
map<unsigned, unsigned> root_comp;
unsigned t = 0;
for (unsigned i = 1; i <= kd.num_edges (); i ++)
{
if (u.find (i) == i)
{
++ t;
root_comp.push (i, t);
}
}
assert (t == m);
basedvector<Q, 1> comp_weightQ (m);
for (unsigned i = 1; i <= m; i ++)
comp_weightQ[i] = Q (i);
unsigned bQ = splitting_bound<Q> (kd, comp_weightQ);
basedvector<Z2x, 1> comp_weightZ2x (m);
for (unsigned i = 1; i <= m; i ++)
comp_weightZ2x[i] = Z2x (polynomial<Z2> (Z2 (1), i));
unsigned bZ2x = splitting_bound<Z2x> (kd, comp_weightZ2x);
// lower bound
unsigned b = std::max (bQ, bZ2x);
// adjust parity
if ((total_lk & 1) != (b & 1))
b ++;
printf ("[% 2d] bQ = %d\n", rank, bQ);
printf ("[% 2d] bZ2x = %d\n", rank, bZ2x);
printf ("[% 2d] b = %d\n", rank, b);
unsigned b_lk_weaker = total_lk == 0 ? 2 : total_lk; // kd is non-split
unsigned b_lk_weak = compute_b_lk_weak (kd);
assert (b_lk_weaker <= b_lk_weak);
printf ("[% 2d] b_lk_weaker = %d\n", rank, b_lk_weaker);
printf ("[% 2d] b_lk_weak = %d\n", rank, b_lk_weak);
if (b_lk_weaker < b_lk_weak)
printf ("[% 2d] > STRICTLY WEAKER\n", rank);
basedvector<basedvector<unsigned, 1>, 1> ps = permutations (m);
unsigned upper = kd.n_crossings;
for (unsigned i = 1; i <= ps.size (); i ++)
{
basedvector<unsigned, 1> p = ps[i];
unsigned ri = 0;
for (unsigned j = 1; j <= kd.n_crossings; j ++)
{
unsigned upper_e = kd.ept_edge (kd.crossings[j][2]),
lower_e = kd.ept_edge (kd.crossings[j][1]);
unsigned upper_c = root_comp(u.find (upper_e)),
lower_c = root_comp(u.find (lower_e));
if (upper_c != lower_c
&& p[upper_c] < p[lower_c])
ri ++;
}
if (ri < upper)
upper = ri;
}
printf ("[% 2d] upper = %d\n", rank, upper);
assert (b_lk_weak <= upper);
assert (b <= upper);
// non-trivial link, sp at least 1.
unsigned best = std::max (b, b_lk_weak);
if (best == upper)
printf ("[% 2d] > sp = %d", rank, upper);
else
printf ("[% 2d] > %d <= sp <= %d", rank, best, upper);
printf (" ");
if (b == best
&& b_lk_weak == best)
printf ("(b + b_lk_weak)");
else if (b == best)
printf ("(b)");
else
{
assert (b_lk_weak == best);
printf ("(b_lk_weak)");
}
fflush (stdout);
char buf[1000];
assert (desc.t == knot_desc::MT);
sprintf (buf, "splitting/L%d_%d.dat.gz\n", desc.i, desc.j);
{
gzfile_reader r (buf);
write (r, desc);
write (r, bQ);
write (r, bZ2x);
write (r, b);
write (r, b_lk_weak);
write (r, upper);
}
}
void
slave ()
{
int rank = self_rank ();
for (;;)
{
int cmd = recv_int ();
switch (cmd)
{
case CMD_DO:
{
knot_desc desc;
desc.t = (knot_desc::table)recv_int ();
desc.i = (unsigned)recv_int ();
desc.j = (unsigned)recv_int ();
printf ("[% 2d] CMD_DO %s\n", rank, desc.name ().c_str ());
compute_splitting_bounds (desc);
send_int (0, 0);
}
break;
case CMD_DIE:
return;
}
}
}
int
main (int argc, char **argv)
{
comm_init (&argc, &argv);
int rank = self_rank (),
ntasks = num_tasks ();
printf ("[% 2d] alive\n", rank);
fflush (stdout);
if (rank == 0)
{
printf ("ntasks = %d\n", ntasks);
fflush (stdout);
master ();
}
else
slave ();
comm_finalize ();
return 0;
}

20
parallel.cmd Normal file
View File

@ -0,0 +1,20 @@
# mpi job, runtime max 5days
#PBS -l nodes=3:ppn=4,walltime=150:00:00
# xxx PBS -l mem=80gb
#
# sends mail if the process aborts, when it begins, and
# when it ends (abe)
#PBS -m abe
#
module load openmpi/gcc
# go to the directory with the program
cd $HOME/src/knotkit
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/u/cseed/llvm-3.1/lib
export LD_LIBRARY_PATH
echo $LD_LIBRARY_PATH
# and run it
numprocs=`wc -l <${PBS_NODEFILE}`
mpiexec -np $numprocs ./mpimain

View File

@ -19,21 +19,20 @@ planar_diagram::planar_diagram (const knot_diagram &kd)
}
void
planar_diagram::display_bohua () const
planar_diagram::show_knottheory () const
{
printf ("%s\t[", name.c_str ());
printf ("PD[");
for (unsigned i = 1; i <= crossings.size (); i ++)
{
if (i > 1)
printf (",");
printf ("[%d,%d,%d,%d]",
printf ("X[%d,%d,%d,%d]",
crossings[i][1],
crossings[i][2],
crossings[i][3],
crossings[i][4]);
}
printf ("]\n");
printf ("]");
}
void

View File

@ -21,8 +21,9 @@ public:
{ }
~planar_diagram () { }
void display_bohua () const;
void show_knottheory () const;
void display_knottheory () const { show_knottheory (); newline (); }
void show_self () const { printf ("planar_diagram %s", name.c_str ()); }
void display_self () const;
};

View File

@ -66,6 +66,7 @@ typedef int16_t flex_int16_t;
typedef uint16_t flex_uint16_t;
typedef int32_t flex_int32_t;
typedef uint32_t flex_uint32_t;
typedef uint64_t flex_uint64_t;
#else
typedef signed char flex_int8_t;
typedef short int flex_int16_t;
@ -172,7 +173,12 @@ typedef unsigned int flex_uint32_t;
typedef struct yy_buffer_state *YY_BUFFER_STATE;
#endif
extern int rd_yyleng;
#ifndef YY_TYPEDEF_YY_SIZE_T
#define YY_TYPEDEF_YY_SIZE_T
typedef size_t yy_size_t;
#endif
extern yy_size_t rd_yyleng;
extern FILE *rd_yyin, *rd_yyout;
@ -198,11 +204,6 @@ extern FILE *rd_yyin, *rd_yyout;
#define unput(c) yyunput( c, (yytext_ptr) )
#ifndef YY_TYPEDEF_YY_SIZE_T
#define YY_TYPEDEF_YY_SIZE_T
typedef size_t yy_size_t;
#endif
#ifndef YY_STRUCT_YY_BUFFER_STATE
#define YY_STRUCT_YY_BUFFER_STATE
struct yy_buffer_state
@ -220,7 +221,7 @@ struct yy_buffer_state
/* Number of characters read into yy_ch_buf, not including EOB
* characters.
*/
int yy_n_chars;
yy_size_t yy_n_chars;
/* Whether we "own" the buffer - i.e., we know we created it,
* and can realloc() it to grow it, and should free() it to
@ -290,8 +291,8 @@ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
/* yy_hold_char holds the character lost when rd_yytext is formed. */
static char yy_hold_char;
static int yy_n_chars; /* number of characters read into yy_ch_buf */
int rd_yyleng;
static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
yy_size_t rd_yyleng;
/* Points to current character in buffer. */
static char *yy_c_buf_p = (char *) 0;
@ -319,7 +320,7 @@ static void rd_yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
YY_BUFFER_STATE rd_yy_scan_buffer (char *base,yy_size_t size );
YY_BUFFER_STATE rd_yy_scan_string (yyconst char *yy_str );
YY_BUFFER_STATE rd_yy_scan_bytes (yyconst char *bytes,int len );
YY_BUFFER_STATE rd_yy_scan_bytes (yyconst char *bytes,yy_size_t len );
void *rd_yyalloc (yy_size_t );
void *rd_yyrealloc (void *,yy_size_t );
@ -377,7 +378,7 @@ static void yy_fatal_error (yyconst char msg[] );
*/
#define YY_DO_BEFORE_ACTION \
(yytext_ptr) = yy_bp; \
rd_yyleng = (size_t) (yy_cp - yy_bp); \
rd_yyleng = (yy_size_t) (yy_cp - yy_bp); \
(yy_hold_char) = *yy_cp; \
*yy_cp = '\0'; \
(yy_c_buf_p) = yy_cp;
@ -483,7 +484,7 @@ char *rd_yytext;
typedef yy::rd_parser::token token;
typedef yy::rd_parser::token_type token_type;
#line 487 "rd_parser/rd_scanner.cc"
#line 488 "rd_parser/rd_scanner.cc"
#define INITIAL 0
@ -522,7 +523,7 @@ FILE *rd_yyget_out (void );
void rd_yyset_out (FILE * out_str );
int rd_yyget_leng (void );
yy_size_t rd_yyget_leng (void );
char *rd_yyget_text (void );
@ -581,7 +582,7 @@ static int input (void );
if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
{ \
int c = '*'; \
int n; \
yy_size_t n; \
for ( n = 0; n < max_size && \
(c = getc( rd_yyin )) != EOF && c != '\n'; ++n ) \
buf[n] = (char) c; \
@ -666,7 +667,7 @@ YY_DECL
#line 16 "rd_parser/rd_scanner.ll"
#line 670 "rd_parser/rd_scanner.cc"
#line 671 "rd_parser/rd_scanner.cc"
if ( !(yy_init) )
{
@ -794,7 +795,7 @@ YY_RULE_SETUP
#line 49 "rd_parser/rd_scanner.ll"
ECHO;
YY_BREAK
#line 798 "rd_parser/rd_scanner.cc"
#line 799 "rd_parser/rd_scanner.cc"
case YY_STATE_EOF(INITIAL):
yyterminate();
@ -981,7 +982,7 @@ static int yy_get_next_buffer (void)
else
{
int num_to_read =
yy_size_t num_to_read =
YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
while ( num_to_read <= 0 )
@ -995,7 +996,7 @@ static int yy_get_next_buffer (void)
if ( b->yy_is_our_buffer )
{
int new_size = b->yy_buf_size * 2;
yy_size_t new_size = b->yy_buf_size * 2;
if ( new_size <= 0 )
b->yy_buf_size += b->yy_buf_size / 8;
@ -1026,7 +1027,7 @@ static int yy_get_next_buffer (void)
/* Read in more data. */
YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
(yy_n_chars), (size_t) num_to_read );
(yy_n_chars), num_to_read );
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
}
@ -1148,7 +1149,7 @@ static int yy_get_next_buffer (void)
else
{ /* need more input */
int offset = (yy_c_buf_p) - (yytext_ptr);
yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
++(yy_c_buf_p);
switch ( yy_get_next_buffer( ) )
@ -1172,7 +1173,7 @@ static int yy_get_next_buffer (void)
case EOB_ACT_END_OF_FILE:
{
if ( rd_yywrap( ) )
return EOF;
return 0;
if ( ! (yy_did_buffer_switch_on_eof) )
YY_NEW_FILE;
@ -1424,7 +1425,7 @@ void rd_yypop_buffer_state (void)
*/
static void rd_yyensure_buffer_stack (void)
{
int num_to_alloc;
yy_size_t num_to_alloc;
if (!(yy_buffer_stack)) {
@ -1521,12 +1522,11 @@ YY_BUFFER_STATE rd_yy_scan_string (yyconst char * yystr )
*
* @return the newly allocated buffer state object.
*/
YY_BUFFER_STATE rd_yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
YY_BUFFER_STATE rd_yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len )
{
YY_BUFFER_STATE b;
char *buf;
yy_size_t n;
int i;
yy_size_t n, i;
/* Get memory for full buffer, including space for trailing EOB's. */
n = _yybytes_len + 2;
@ -1608,7 +1608,7 @@ FILE *rd_yyget_out (void)
/** Get the length of the current token.
*
*/
int rd_yyget_leng (void)
yy_size_t rd_yyget_leng (void)
{
return rd_yyleng;
}

15
serial.cmd Normal file
View File

@ -0,0 +1,15 @@
# serial job
#PBS -l nodes=1:ppn=1,walltime=4:00:00
# xxx PBS -l mem=80gb
#
# sends mail if the process aborts, when it begins, and
# when it ends (abe)
#PBS -m abe
#
# load intel compiler settings before running the program
# since we compiled it with intel 10.1
# module load intel/10.1
# go to the directory with the program
cd $HOME/src/knotkit
# and run it
LD_LIBRARY_PATH=/u/cseed/llvm-3.1/lib ./main

249
simplify_chain_complex.h Normal file
View File

@ -0,0 +1,249 @@
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_,
maybe<int> dh, maybe<int> dq);
};
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_,
maybe<int> dh, maybe<int> dq)
: 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 ());
if (j.val ().is_unit ()
&& (dh.is_none ()
|| (jgr.h - igr.h == dh.some ()))
&& (dq.is_none ()
|| (jgr.q - igr.q == dq.some ())))
{
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>
@ -39,7 +42,7 @@ public:
tree_generators (const spanning_tree_complex<F> &c_) : c(c_) { }
~tree_generators () { }
tree_generators &operator = (const tree_generators &); // doesn't exist
tree_generators &operator = (const tree_generators &) = delete;
unsigned dim () const { return c.trees.size (); }
unsigned free_rank () const { return c.trees.size (); }
@ -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
{

114
sseq.cpp
View File

@ -2,7 +2,8 @@
#include <knotkit.h>
sseq_page::sseq_page (const sseq_bounds &b)
: rank(b.width ()),
: k(0),
rank(b.width ()),
im_rank(b.width ())
{
for (unsigned i = 0; i < b.width (); i ++)
@ -140,87 +141,6 @@ sseq_page::delta_poincare_polynomial (const sseq_bounds &b) const
return r;
}
void
sseq_page::texshow (FILE *fp, const sseq_bounds &b, unsigned dh, bool last)
{
fprintf (fp, "\
\\begin{tikzpicture}[scale=.66]\n\
\\draw[->] (0,0) -- (%d.5,0) node[right] {$t$};\n\
\\draw[->] (0,0) -- (0,%d.5) node[above] {$q$};\n\
\\draw[step=1] (0,0) grid (%d,%d);\n",
b.width (), (b.height () + 1) / 2, b.width (), (b.height () + 1) / 2);
fprintf (fp, " \\draw (%.3f,-0.8) node[below] {$",
((double)b.width () + 0.5) / 2);
if (last)
fprintf (fp, "E_\\infty = ");
fprintf (fp, "E_{%d}$};\n",
dh);
/* label axes */
for (int x = b.minh; x <= b.maxh; x ++)
{
fprintf (fp, "\
\\draw (%d.5,-.2) node[below] {$%d$};\n",
x - b.minh, x);
}
for (int y = b.minq; y <= b.maxq; y += 2)
{
fprintf (fp, "\
\\draw (-.2,%d.5) node[left] {$%d$};\n",
(y - b.minq) / 2, y);
}
for (unsigned i = 0; i < b.width (); i ++)
for (unsigned j = 0; j < b.height (); j ++)
{
int r = rank[i][j];
if (r == 1)
{
assert (is_even (j));
fprintf (fp, "\
\\fill (%d.5, %d.5) circle (.15);\n",
i, j / 2);
}
else if (r > 1)
{
assert (is_even (j));
fprintf (fp, "\
\\draw (%d.5, %d.5) node {$%d$};\n",
i, j / 2, r);
}
}
for (unsigned i = 0; i < b.width (); i ++)
for (unsigned j = 0; j < b.height (); j ++)
{
unsigned r = im_rank[i][j];
if (r == 0)
continue;
unsigned dx = dh,
dy = dh - 1; // in "boxes"
assert (dx >= 2); // eliminated d_1
double h = sqrt ((double)(dx * dx + dy * dy));
double xadj = (double)dx / h * 0.3;
double yadj = (double)dy / h * 0.3;
assert (is_even (j));
fprintf (fp, " \\draw[->] (%.3f, %.3f) -- ",
(double)i + 0.5 + xadj, (double)(j / 2) + 0.5 + yadj);
if (r > 1)
fprintf (fp, "node[color=red!75!black] {$%d$} ", r);
fprintf (fp, "(%.3f, %.3f);\n",
(double)(i + dx) + 0.5 - xadj, (double)(j / 2 + dy) + 0.5 - yadj);
}
fprintf (fp, "\
\\end{tikzpicture}\n");
fflush (fp);
}
sseq
sseq::operator + (const sseq &ss2) const
{
@ -280,36 +200,6 @@ sseq::shift (int dh, int dq) const
pages);
}
bool
sseq::equal_as_spaces (const sseq &ss) const
{
if (bounds != ss.bounds
|| pages.size () != ss.pages.size ())
return 0;
for (unsigned i = 1; i <= pages.size (); i ++)
{
if (!pages[i].equal_as_spaces (ss.pages[i]))
return 0;
}
return 1;
}
void
sseq::texshow (FILE *fp, std::string name)
{
fprintf (fp, "\\section{Knot $%s$}\n", name.c_str ());
unsigned n = pages.size ();
for (unsigned i = 1; i <= n; i ++)
fprintf (fp, "$\\rank E_%d = %d$ \\\\\n",
i + 1, pages[i].total_rank ());
for (unsigned i = 1; i <= n; i ++)
pages[i].texshow (fp, bounds, i + 1, i == n);
}
void
sseq_builder::cancel (unsigned d)
{

435
sseq.h
View File

@ -7,6 +7,27 @@ class sseq_bounds
public:
sseq_bounds () { }
template<class R, class M> sseq_bounds (ptr<const module<R> > C, M m)
{
grading hq1 = m(C->generator_grading (1));
minh = maxh = hq1.h;
minq = maxq = hq1.q;
for (unsigned i = 2; i <= C->dim (); i ++)
{
grading hq = m(C->generator_grading (i));
if (hq.h < minh)
minh = hq.h;
if (hq.h > maxh)
maxh = hq.h;
if (hq.q < minq)
minq = hq.q;
if (hq.q > maxq)
maxq = hq.q;
}
}
sseq_bounds (int minh_, int maxh_, int minq_, int maxq_)
: minh(minh_), maxh(maxh_), minq(minq_), maxq(maxq_)
{ }
@ -34,25 +55,40 @@ class sseq_bounds
&& minq == b.minq
&& maxq == b.maxq;
}
bool operator != (const sseq_bounds &b) const { return !operator == (b); }
};
class sseq_page
{
public:
/* bounds come from sseq */
unsigned k;
grading dk_gr;
vector<vector<unsigned> > rank,
im_rank;
public:
sseq_page () { }
sseq_page (const sseq_bounds &b);
template<class R, class M> sseq_page (const sseq_bounds &b,
unsigned k_,
grading dk_gr_,
mod_map<R> d,
M m);
sseq_page (const sseq_page &pg)
: rank(pg.rank), im_rank(pg.im_rank)
: k(pg.k), dk_gr(pg.dk_gr), rank(pg.rank), im_rank(pg.im_rank)
{ }
~sseq_page () { }
bool operator == (const sseq_page &pg) const { return rank == pg.rank && im_rank == pg.im_rank; }
bool equal_as_spaces (const sseq_page &pg) const { return rank == pg.rank; }
bool operator == (const sseq_page &pg) const
{
return k == pg.k
&& dk_gr == pg.dk_gr
&& rank == pg.rank
&& im_rank == pg.im_rank;
}
bool operator != (const sseq_page &pg) const { return !operator == (pg); }
unsigned total_rank () const;
multivariate_laurentpoly<Z> poincare_polynomial (const sseq_bounds &b) const;
@ -64,7 +100,7 @@ class sseq_page
const sseq_bounds &b1, const sseq_page &pg1,
const sseq_bounds &b2, const sseq_page &pg2);
void texshow (FILE *fp, const sseq_bounds &b, unsigned dh, bool last);
template<class M> void texshow (FILE *fp, const sseq_bounds &b, const char *label, M m);
};
class sseq
@ -75,8 +111,10 @@ class sseq
public:
sseq () { }
sseq (const sseq_bounds &b, const basedvector<sseq_page, 1> &pages_)
: bounds(b), pages(pages_)
sseq (const sseq_bounds &b,
const basedvector<sseq_page, 1> &pages_)
: bounds(b),
pages(pages_)
{ }
sseq (const sseq_bounds &b)
: bounds(b)
@ -84,7 +122,12 @@ class sseq
sseq (const sseq &ss) : bounds(ss.bounds), pages(ss.pages) { }
~sseq () { }
sseq &operator = (const sseq &ss) { bounds = ss.bounds; pages = ss.pages; return *this; }
sseq &operator = (const sseq &ss)
{
bounds = ss.bounds;
pages = ss.pages;
return *this;
}
sseq operator + (const sseq &ss2) const; // direct sum
sseq otimes (const sseq &ss2) const; // tensor product
@ -95,279 +138,157 @@ class sseq
unsigned homological_width () const { return pages[1].homological_width (bounds); }
bool operator == (const sseq &ss) const { return bounds == ss.bounds && pages == ss.pages; }
bool equal_as_spaces (const sseq &ss) const;
bool operator != (const sseq &ss) const { return !operator == (ss); }
void texshow (FILE *fp, std::string name);
template<class M> void texshow (FILE *fp, M m);
};
template<class R> class simplified_complex_generators
template<class R, class M>
sseq_page::sseq_page (const sseq_bounds &b,
unsigned k_,
grading dk_gr_,
mod_map<R> dk,
M m)
: k(k_),
dk_gr(dk_gr_),
rank(b.width ()),
im_rank(b.width ())
{
unsigned new_n;
ptr<const module<R> > C;
basedvector<unsigned, 1> new_C_to_C_generator;
dk.check_grading (dk_gr);
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 () { }
grading m_dk_gr = m.map_delta(dk_gr);
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:
typedef typename R::linear_combination linear_combination;
typedef typename R::linear_combination_const_iter linear_combination_const_iter;
public:
ptr<const module<R> > C;
unsigned n; // |C|
const mod_map<R> &d;
ptr<const module<R> > new_C;
mod_map<R> new_d;
// chain homotopy equivalences
// pi : C -> new_C, iota : new_C -> C
mod_map<R> pi, iota;
private:
basedvector<linear_combination, 1> new_d0;
basedvector<set<unsigned>, 1> preim;
bool build_pi_iota;
mod_map<R> pi0, iota0;
set<unsigned> canceled;
void cancel (unsigned i, R b, unsigned j);
public:
chain_complex_simplifier (ptr<const module<R> > C_,
const mod_map<R> &d_,
int dh,
bool build_pi_iota_ = 0);
};
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_d0[i].yank (j);
preim[j].yank (i);
for (linear_combination_const_iter k = new_d0[i]; k; k ++)
preim[k.key ()].yank (i);
for (set_const_iter<unsigned> k = preim[i]; k; k ++)
new_d0[k.val ()].yank (i);
for (linear_combination_const_iter k = new_d0[j]; k; k ++)
preim[k.key ()].yank (j);
if (build_pi_iota)
for (unsigned i = 0; i < b.width (); i ++)
{
mod_map<R> local_pi0 (C, 1),
local_iota0 (C, 1);
vector<unsigned> r (b.height ()),
im_r (b.height ());
for (unsigned j = 0; j < b.height (); j ++)
r[j] = im_r[j] = 0;
local_pi0[i].clear ();
local_pi0[j].clear ();
local_iota0[i].clear ();
local_iota0[j].clear ();
for (linear_combination_const_iter ll = new_d0[i]; ll; ll ++)
{
R c = ll.val ();
local_pi0[j].mulsub (binv * c, ll.key ());
}
for (set_const_iter<unsigned> kk = preim[j]; kk; kk ++)
{
unsigned k = kk.val ();
R a = new_d0[k](j);
assert (a != 0);
local_iota0[k].mulsub (a * binv, i);
}
pi0 = local_pi0.compose (pi0);
iota0 = iota0.compose (local_iota0);
rank[i] = r;
im_rank[i] = im_r;
}
for (set_const_iter<unsigned> kk = preim[j]; kk; kk ++)
ptr<const module<R> > C = dk.domain ();
for (unsigned i = 1; i <= C->dim (); i ++)
{
unsigned k = kk.val ();
R a = new_d0[k](j);
assert (a != 0);
R abinv = a * binv;
for (linear_combination_const_iter ll = new_d0[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_d0[k].mulsub (abinv * c, ell);
if (new_d0[k] % ell)
preim[ell] += k;
else
preim[ell] -= k;
}
grading gr = m(C->generator_grading (i));
rank[(unsigned)(gr.h - b.minh)][(unsigned)(gr.q - b.minq)] ++;
}
for (set_const_iter<unsigned> k = preim[j]; k; k ++)
new_d0[k.val ()].yank (j);
new_d0[i].clear ();
preim[i].clear ();
new_d0[j].clear ();
preim[j].clear ();
#if 0 // expensive
if (build_pi_iota)
ptr<const free_submodule<R> > im = dk.image ();
for (unsigned i = 1; i <= im->dim (); i ++)
{
assert (pi0.compose (d) == new_d0.compose (pi0));
assert (iota0.compose (new_d0) == d.compose (iota0));
grading gr = m(im->generator_grading (i));
im_rank[(unsigned)(gr.h - m_dk_gr.h - b.minh)][(unsigned)(gr.q - m_dk_gr.q - b.minq)] ++;
}
#endif
}
template<class R>
chain_complex_simplifier<R>::chain_complex_simplifier (ptr<const module<R> > C_,
const mod_map<R> &d_,
int dh,
bool build_pi_iota_)
: C(C_), n(C_->dim ()), d(d_),
new_d0(COPY2, d_.explicit_columns ()),
preim(C_->dim ()),
build_pi_iota(build_pi_iota_)
template<class M> void
sseq_page::texshow (FILE *fp, const sseq_bounds &b, const char *label, M m)
{
grading m_dk_gr = m.map_delta(dk_gr);
unsigned dh = m_dk_gr.h,
dq = m_dk_gr.q;
fprintf (fp, "\
\\begin{tikzpicture}[scale=.66]\n\
\\draw[->] (0,0) -- (%d.5,0) node[right] {$t$};\n\
\\draw[->] (0,0) -- (0,%d.5) node[above] {$q$};\n\
\\draw[step=1] (0,0) grid (%d,%d);\n",
b.width (), b.height (), b.width (), b.height ());
fprintf (fp, " \\draw (%.3f,-0.8) node[below] {%s};\n",
((double)b.width () + 0.5) / 2, label);
/* label axes */
for (int x = b.minh; x <= b.maxh; x ++)
{
fprintf (fp, "\
\\draw (%d.5,-.2) node[below] {$",
x - b.minh);
m.x_label (fp, x);
fprintf (fp, "$};\n");
}
for (int y = b.minq; y <= b.maxq; y ++)
{
fprintf (fp, "\
\\draw (-.2,%d.5) node[left] {$",
y - b.minq);
m.y_label (fp, y);
fprintf (fp, "$};\n");
}
for (unsigned i = 0; i < b.width (); i ++)
for (unsigned j = 0; j < b.height (); j ++)
{
int r = rank[i][j];
if (r == 1)
{
fprintf (fp, "\
\\fill (%d.5, %d.5) circle (.15);\n",
i, j);
}
else if (r > 1)
{
fprintf (fp, "\
\\draw (%d.5, %d.5) node {$%d$};\n",
i, j, r);
}
}
for (unsigned i = 0; i < b.width (); i ++)
for (unsigned j = 0; j < b.height (); j ++)
{
unsigned r = im_rank[i][j];
if (r == 0)
continue;
int dx = dh,
dy = dq; // in "boxes"
double h = sqrt ((double)(dx * dx + dy * dy));
double xadj = (double)dx / h * 0.3;
double yadj = (double)dy / h * 0.3;
fprintf (fp, " \\draw[->] (%.3f, %.3f) -- ",
(double)i + 0.5 + xadj, (double)j + 0.5 + yadj);
if (r > 1)
fprintf (fp, "node[color=red!75!black] {$%d$} ", r);
fprintf (fp, "(%.3f, %.3f);\n",
(double)((int)i + dx) + 0.5 - xadj, (double)((int)j + dy) + 0.5 - yadj);
}
fprintf (fp, "\
\\end{tikzpicture}\n");
fflush (fp);
}
template<class M> void
sseq::texshow (FILE *fp, M m)
{
unsigned n = pages.size ();
for (unsigned i = 1; i <= n; i ++)
{
for (linear_combination_const_iter j = d[i]; j; j ++)
preim[j.key ()].push (i);
if (i == n)
fprintf (fp, "$\\rank E_\\infty = \\rank E_%d = %d$ \\\\\n",
pages[i].k, pages[i].total_rank ());
else
fprintf (fp, "$\\rank E_%d = %d$ \\\\\n",
pages[i].k, pages[i].total_rank ());
}
if (build_pi_iota)
for (unsigned i = 1; i <= n; i ++)
{
pi0 = mod_map<R> (C, 1);
iota0 = mod_map<R> (C, 1);
#if 0 // expensive
assert (pi0.compose (d) == new_d0.compose (pi0));
assert (iota0.compose (new_d0) == d.compose (iota0));
#endif
}
Lretry:
for (unsigned i = n; i >= 1; i --)
{
if (canceled % i)
continue;
grading igr = C->generator_grading (i);
for (linear_combination_const_iter j = new_d0[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 ());
goto Lretry;
}
}
}
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)));
new_d = mod_map<R> (new_C);
for (unsigned i = 1; i <= new_n; i ++)
{
unsigned i0 = new_C_to_C_generator[i];
for (linear_combination_const_iter j0 = new_d0[i0]; j0; j0 ++)
{
unsigned j = C_to_new_C_generator[j0.key ()];
assert (j != 0);
new_d[i].muladd (j0.val (), j);
}
}
if (build_pi_iota)
{
pi = mod_map<R> (C, new_C);
iota = mod_map<R> (new_C, C);
for (unsigned i0 = 1; i0 <= n; i0 ++)
{
for (linear_combination_const_iter j0 = pi0[i0]; j0; j0 ++)
{
unsigned j = C_to_new_C_generator[j0.key ()];
pi[i0].muladd (j0.val (), j);
}
}
for (unsigned i = 1; i <= new_n; i ++)
{
unsigned i0 = new_C_to_C_generator[i];
iota[i] = iota0[i0];
}
#if 0 // expensive
assert (pi.compose (d) == new_d.compose (pi));
assert (d.compose (iota) == iota.compose (new_d));
#endif
char buf[1000];
if (i == n)
sprintf (buf, "$E_\\infty = E_{%d}$", pages[i].k);
else
sprintf (buf, "$E_{%d}$", pages[i].k);
pages[i].texshow (fp, bounds, buf, m);
}
}

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;
};

View File

@ -13,10 +13,8 @@ in knotkit/
deepcopy
in lib/
- add hashset
- between interoperation between sets that require bounds (bitset,
ullmanset) and those that don't (set, hashset)
- add make_pair, etc.
in algebra/
- linear_combnation can be more efficient (eg no searching when
@ -25,3 +23,73 @@ in algebra/
- cleaner interface for gcd, etc. in fraction_field
- support kernel, cokernel of torsion modules
- change gcd et al so gcd is always positive
- split linear_combination into internal and external versions
git:
- fix bug in Josh's version
- make this master, merge into Josh's version
- merge in square to master => then write paper!
- merge in other improvements (sped up linear algebra? multivariate (laurent) polynomial?)
- should exponents on polynomials be Z or unsigned?
general:
- unify simplify_chain_complex, sseq, kernel/image/homology (as much as possible)
- sseq over Z
- quadratic linear solver (enumerator?)
- classes should either COPY or fully SHARE, but not some of each
(e.g. knot_diagram, resolution_diagram, etc.) -- this is the right
semantics.
- clean up/delete setcommon, mapcommon
- incorporate sage dump into standard classes
- update use of tuples in steenrod square
- test mutation invariance, other questions of Robert and Sucharit
- write paper
c++11:
- make vector wrap std::vector (probably faster)
- use tuple instead of pair, triple; and use tie, a great idiom
- standardize ring, field interface so test_ring works for everything
- get clear on default semantics: prefer default when possible
- standardize use of {} for initializers
- initializer_list for container types
- support for iterator
- compress Steenrod square data
- get mpimain running again, run 15 xing mutants
- simplifications to run (5, 8) with symmetries.
notes:
all rings (R): multivariate_laurentpoly<R>
fields (F): Z2 Zp Q fraction_field<E> (for just pids?)
euclidean domains (E): Z polynomial<F>
euclidean domain interface:
num/demon : denom must be a unit
= num.operator / (denom)
denom.divides (num)
denom | num
num.divide_exact (denom)
(q, r) = num.divide_with_remainder (denom)
(q, r) = num / denom
(q, r) = num.operator / (denom)
satisfies r = 0 or f(r) < f(denom) and num = q*denom + r
gcd (a, b)
lcm (a, b)
r = num.mod (denom)
satisfies r = 0 or f(r) < f(denom)
(d, s, t) = a.extended_gcd (b)
satifies d is the gcd and d = a*s + b*t