diff --git a/.gitignore b/.gitignore index 2368d6d..7695f4a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,9 @@ *~ *.o -/gss +/kk /main /testsurfaces -/serial.cmd* +/serial.cmd.[eo]* +/parallel.cmd.[eo]* /save */save diff --git a/Makefile b/Makefile index f207be9..9eb97de 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/README b/README index 8986544..4da80c4 100644 --- a/README +++ b/README @@ -1 +1,162 @@ -I modified cotton's readme. \ No newline at end of file +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, 554–586, arXiv:math/0210213. +D. Bar-Natan, Khovanov’s homology for tangles and cobordisms, + Geom. Topol. 9 (2005), 1443–1499, 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 [options...] + compute for knot or link + 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 : write output to + (stdout is the default) + -f : ground field (if applicable) + (Z2 is the default) + -v : verbose: report progress as the computation proceeds + can be one of: + Z2, Z3, Q + 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. diff --git a/algebra/Q.h b/algebra/Q.h index b6ee350..21a1d06 100644 --- a/algebra/Q.h +++ b/algebra/Q.h @@ -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 extended_gcd (const Q &q) const + tuple extended_gcd (const Q &q) const { if (*this != 0) - return triple (*this, 1, 0); + return tuple (*this, 1, 0); else - return triple (q, 0, 1); + return tuple (q, 0, 1); } Q gcd (const Q &q) const diff --git a/algebra/Z.h b/algebra/Z.h index 3575992..d23c0fc 100644 --- a/algebra/Z.h +++ b/algebra/Z.h @@ -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 extended_gcd (const Z &z) const + tuple 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 (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 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 (); } diff --git a/algebra/Z2.h b/algebra/Z2.h index f13f192..09be75a 100644 --- a/algebra/Z2.h +++ b/algebra/Z2.h @@ -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 extended_gcd (Z2 x) const + tuple extended_gcd (Z2 x) const { if (v) - return triple (Z2 (1), Z2 (1), Z2 (0)); + return make_tuple (Z2 (1), Z2 (1), Z2 (0)); else - return triple (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); } }; diff --git a/algebra/Zp.h b/algebra/Zp.h index dc53609..bd3fe0a 100644 --- a/algebra/Zp.h +++ b/algebra/Zp.h @@ -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 t = unsigned_extended_gcd (v, p); - assert (t.first == 1); - assert ((int)t.first == t.second*(int)v + t.third*(int)p); + tuple 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 extended_gcd (const Zp &x) const + tuple extended_gcd (const Zp &x) const { if (v) - return triple (v, 1, 0); + return make_tuple (v, Zp (1), Zp (0)); else - return triple (x, 0, 1); + return make_tuple (x, Zp (0), Zp (1)); } Zp gcd (const Zp &x) const diff --git a/algebra/algebra.cpp b/algebra/algebra.cpp index e467674..82b01a2 100644 --- a/algebra/algebra.cpp +++ b/algebra/algebra.cpp @@ -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 +static tuple extended_gcd_1 (int a, int b) { if (b == 0) - return triple (a, 1, 0); + return tuple (a, 1, 0); unsigned t = a % b; if (!t) - return triple (b, 0, 1); + return make_tuple (b, 0, 1); else { - triple s = unsigned_extended_gcd (b, t); + tuple 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 (d, x, y); + return make_tuple (d, x, y); } } -triple +tuple unsigned_extended_gcd (unsigned a, unsigned b) { return extended_gcd_1 ((int)a, (int)b); } -triple +tuple extended_gcd (int a, int b) { - triple t = extended_gcd_1 (std::abs (a), - std::abs (b)); - unsigned d = t.first; - int x = t.second, - y = t.third; + tuple 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 (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)); } diff --git a/algebra/algebra.h b/algebra/algebra.h index 42319f5..4acd0ca 100644 --- a/algebra/algebra.h +++ b/algebra/algebra.h @@ -1,6 +1,4 @@ -#include - #include 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 extended_gcd (int a, int b); +tuple extended_gcd (int a, int b); -triple unsigned_extended_gcd (unsigned a, unsigned b); +tuple unsigned_extended_gcd (unsigned a, unsigned b); template class linear_combination; template class linear_combination_const_iter; diff --git a/algebra/fraction_field.h b/algebra/fraction_field.h index d2ea6a4..3f648b6 100644 --- a/algebra/fraction_field.h +++ b/algebra/fraction_field.h @@ -36,6 +36,7 @@ template 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 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 fraction_field return fraction_field (1); } - triple extended_gcd (const fraction_field &x) const + tuple extended_gcd (const fraction_field &x) const { if (*this != 0) - return triple (*this, 1, 0); + return make_tuple (*this, fraction_field (1), fraction_field (0)); else - return triple (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::reduce () } T d = num.gcd (denom); - num = num.divide_exact (d); denom = denom.divide_exact (d); } @@ -220,7 +225,6 @@ fraction_field::check () { if (num == 0) return; - // check denom == 1 // assert (num.gcd (denom) == 1); } diff --git a/algebra/grading.h b/algebra/grading.h index 936aeb3..cbd3972 100644 --- a/algebra/grading.h +++ b/algebra/grading.h @@ -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; }; diff --git a/algebra/linear_combination.h b/algebra/linear_combination.h index dda27ce..373a0b8 100644 --- a/algebra/linear_combination.h +++ b/algebra/linear_combination.h @@ -39,8 +39,15 @@ class linear_combination for (typename map::const_iter i = lc.v; i; i ++) v.push (i.key (), R (COPY, i.val ())); } + + linear_combination (reader &r) + { + m = r.read_mod (); + v = map (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 linear_combination (ptr 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 (); + v = set (r); + } + ~linear_combination () { } linear_combination &operator = (const linear_combination &lc) @@ -346,6 +366,7 @@ class linear_combination } 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 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 (); } }; diff --git a/algebra/module.h b/algebra/module.h index 610802b..acd217b 100644 --- a/algebra/module.h +++ b/algebra/module.h @@ -14,10 +14,15 @@ template class module : public refcounted { private: + friend class reader; + friend class writer; + unsigned id; static unsigned id_counter; + static map > > reader_id_module; + static map, ptr > > direct_sum_idx; static map, @@ -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_vector () const; + set 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 free_poincare_polynomial () const; multivariate_laurentpoly free_delta_poincare_polynomial () const; + multivariate_laurentpoly free_ell_poincare_polynomial () const; ptr > add (basedvector >, 1> compound_summands) const; @@ -143,11 +157,16 @@ class module : public refcounted factors.append (this); } + ptr > graded_piece (grading hq) const; + + void write_self (writer &w) const { w.write_mod (this); } void show_self () const; void display_self () const; }; -template unsigned module::id_counter = 1; +template unsigned module::id_counter = 0; + +template map > > module::reader_id_module; template map, ptr > > module::direct_sum_idx; @@ -466,11 +485,11 @@ class base_module : public module 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 basedvector hq; public: - explicit_module (); // doesn't exist + explicit_module () = delete; explicit_module (unsigned r_, basedvector ann_, basedvector hq_) : r(r_), ann(ann_), hq(hq_) - { } + { + assert (hq.size () == r + ann.size ()); + } explicit explicit_module (unsigned r_, basedvector 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 { } ~free_submodule () { } - free_submodule &operator = (const free_submodule &); // doesn't exist + free_submodule &operator = (const free_submodule &) = delete; ptr > parent_module () const { return parent; } @@ -542,6 +563,9 @@ class free_submodule : public module linear_combination restrict (linear_combination v0) const; ptr > restrict_submodule (ptr > m) const; + + ptr > intersection (ptr > m) const; + ptr > plus (ptr > m) const; }; template @@ -562,13 +586,13 @@ class quotient_module : public module basedvector, 1> pi; public: - quotient_module (const quotient_module &); // doesn't exist + quotient_module (const quotient_module &) = delete; quotient_module (ptr > parent_) : parent(parent_) { } ~quotient_module () { } - quotient_module &operator = (const quotient_module &); // doesn't exsit + quotient_module &operator = (const quotient_module &) = delete; ptr > parent_module () const { return parent; } @@ -617,7 +641,7 @@ class map_impl : public refcounted ptr > to; public: - map_impl (const map_impl &); // doesn't exist + map_impl (const map_impl &) = delete; map_impl (ptr > 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 column (unsigned i) const = 0; + virtual const linear_combination column (unsigned i) const = 0; + virtual const linear_combination column_copy (unsigned i) const { return column (i); } linear_combination map (const linear_combination &lc) const { @@ -657,7 +682,11 @@ class explicit_map_impl : public map_impl { } ~explicit_map_impl () { } - linear_combination column (unsigned i) const { return columns[i]; } + const linear_combination column (unsigned i) const { return columns[i]; } + const linear_combination column_copy (unsigned i) const + { + return linear_combination (COPY, columns[i]); + } }; template @@ -667,7 +696,7 @@ class zero_map_impl : public map_impl zero_map_impl (ptr > fromto) : map_impl(fromto) { } zero_map_impl (ptr > from, ptr > to) : map_impl(from, to) { } - linear_combination column (unsigned i) const { return linear_combination (this->to); } + const linear_combination column (unsigned i) const { return linear_combination (this->to); } }; template @@ -677,7 +706,7 @@ class id_map_impl : public map_impl id_map_impl (ptr > fromto) : map_impl(fromto) { } id_map_impl (ptr > from, ptr > to) : map_impl(from, to) { } - linear_combination column (unsigned i) const + const linear_combination column (unsigned i) const { linear_combination r (this->to); r.muladd (1, i); @@ -700,7 +729,7 @@ class composition_impl : public map_impl assert (g->to == f->from); } - linear_combination column (unsigned i) const + const linear_combination column (unsigned i) const { return f->map (g->column (i)); } @@ -721,7 +750,7 @@ class direct_sum_impl : public map_impl { } - linear_combination column (unsigned i) const + const linear_combination column (unsigned i) const { pair p = f->from->project (g->from, i); @@ -756,7 +785,7 @@ class tensor_impl : public map_impl { } - linear_combination column (unsigned i) const + const linear_combination column (unsigned i) const { pair p = f->from->generator_factors (g->from, i); @@ -849,6 +878,15 @@ class mod_map mod_map (const map_builder &b) : impl(new explicit_map_impl (b.from, b.to, b.columns)) { } + + mod_map (reader &r) + { + ptr > from = r.read_mod (); + ptr > to = r.read_mod (); + basedvector, 1> columns (r); + impl = new explicit_map_impl (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 column (unsigned i) const { return impl->column (i); } - linear_combination operator [] (unsigned i) const { return impl->column (i); } + const linear_combination column (unsigned i) const { return impl->column (i); } + const linear_combination operator [] (unsigned i) const { return impl->column (i); } + + const linear_combination column_copy (unsigned i) const { return impl->column_copy (i); } linear_combination map (const linear_combination &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 > image () const; + ptr > image (basedvector, 1> vs) const; ptr > cokernel () const; @@ -934,9 +977,19 @@ class mod_map mod_map induced_map_to (ptr > new_to); mod_map induced_map (ptr > new_fromto); + mod_map graded_piece (grading hq) const; + // ??? basedvector, 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::improve_pivot_row (unsigned i, unsigned j, unsigned i2) } #endif - triple t = rc.extended_gcd (r2c); - assert (t.first == rc*t.second + t.third*r2c); + tuple 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 bool @@ -1149,8 +1202,8 @@ quotient_helper::improve_pivot_column (unsigned i, unsigned j, unsigned j2) } #endif - triple t = rc.extended_gcd (rc2); - assert (t.first == rc*t.second + t.third*rc2); + tuple 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::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::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::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::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 void @@ -1437,6 +1490,58 @@ module::free_delta_poincare_polynomial () const return r; } +template multivariate_laurentpoly +module::free_ell_poincare_polynomial () const +{ + multivariate_laurentpoly 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 basedvector +module::grading_vector () const +{ + basedvector v (dim ()); + for (unsigned i = 1; i <= dim (); i ++) + v[i] = generator_grading (i); + return v; +} + +template set +module::gradings () const +{ + set gs; + for (unsigned i = 1; i <= dim (); i ++) + gs += generator_grading (i); + return gs; +} + +template ptr > +module::graded_piece (grading hq) const +{ + basedvector, 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 v (this); + v.muladd (1, i); + s.append (v); + } + } + + mod_span span (this, s); + return submodule (span); +} + template void module::show_self () const { @@ -1520,6 +1625,28 @@ mod_map::induced_map (ptr > new_fromto) return new explicit_map_impl (new_fromto, v); } +template mod_map +mod_map::graded_piece (grading hq) const +{ + basedvector, 1> v (impl->from->dim ()); + for (unsigned i = 1; i <= impl->from->dim (); i ++) + { + grading ihq = impl->from->generator_grading (i); + + linear_combination c = column (i); + linear_combination d (impl->to); + for (linear_combination_const_iter 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 (impl->from, impl->to, v)); +} + template mod_map mod_map::restrict_from (ptr > new_from) const { @@ -1528,7 +1655,7 @@ mod_map::restrict_from (ptr > new_from) const basedvector, 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 (new_from, impl->to, v); + return mod_map (IMPL, new explicit_map_impl (new_from, impl->to, v)); } template mod_map @@ -1552,7 +1679,7 @@ mod_map::restrict (ptr > new_from, basedvector, 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 (new_from, new_to, v); + return mod_map (IMPL, new explicit_map_impl (new_from, new_to, v)); } template linear_combination @@ -1595,7 +1722,94 @@ free_submodule::restrict_submodule (ptr > m) const span[i] = restrict (m->inject_generator (i)); mod_span span2 (this, span); - return submodule (span2); + return this->submodule (span2); +} + +template ptr > +free_submodule::intersection (ptr > m) const +{ + assert (parent == m->parent); + + unsigned md = m->dim (), + d = dim (); + + basedvector, 1> intr; + + basedvector, 1> hperp, + hproj; + basedvector hpivots; + for (unsigned i = 1; i <= md; i ++) + { + linear_combination perp (COPY, m->gens[i]), + proj (parent); + + for (unsigned j = 1; j <= d; j ++) + { + unsigned k = pivots[j]; + if (perp % k) + { + const linear_combination &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 &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 span (parent, intr); + return parent->submodule (span); +} + +template ptr > +free_submodule::plus (ptr > m) const +{ + assert (parent == m->parent); + + basedvector, 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 span (parent, s); + return parent->submodule (span); } template bool @@ -1628,6 +1842,14 @@ mod_map::check_grading (grading delta) const } } +template mod_map +mod_map::operator * (const R &c) const +{ + basedvector, 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 (impl->from, impl->to, v)); +} template mod_map mod_map::operator + (const mod_map &m) const @@ -1636,8 +1858,8 @@ mod_map::operator + (const mod_map &m) const basedvector, 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 (impl->from, impl->to, v); + v[i] = column (i) + m.column (i); + return mod_map (IMPL, new explicit_map_impl (impl->from, impl->to, v)); } template ptr > @@ -1647,7 +1869,7 @@ mod_map::kernel () const to = impl->to; basedvector, 1> from_xs (from->dim ()); - for (unsigned i = 1; i <= to->dim (); i ++) + for (unsigned i = 1; i <= from->dim (); i ++) { linear_combination x (from); x.muladd (1, i); @@ -1670,13 +1892,21 @@ mod_map::kernel () const linear_combination &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 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 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::image () const return impl->to->submodule (span); } +template ptr > +mod_map::image (basedvector, 1> vs) const +{ + mod_span span (impl->from, vs); + ptr > s = impl->from->submodule (span); + mod_map r = restrict_from (s); + return r.image (); +} + template ptr > mod_map::cokernel () const { @@ -1767,13 +2006,19 @@ mod_span::mod_span (ptr > mod, linear_combination &x = xs[j]; R xc = x(i); + if (xc == 0) + continue; - if (! (vc | xc)) + if (vc == 0) { - triple t = vc.extended_gcd (xc); - assert (t.first == vc*t.second + t.third*xc); + v += x; + } + else if (! (vc | xc)) + { + tuple 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::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 void +writer::write_mod (ptr > m) +{ + pair 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 ptr > +reader::read_mod () +{ + int io_id = read_int (); + if (io_id < 0) + { + unsigned n = read_unsigned (); + unsigned r = read_unsigned (); + basedvector gr (n); + for (unsigned i = 1; i <= n; i ++) + gr[i] = grading (*this); + basedvector ann (n - r); + for (unsigned i = r + 1; i <= n; i ++) + ann[i - r] = R (*this); + + ptr > m = new explicit_module (r, ann, gr); + ar->io_id_id.push ((unsigned)(-io_id), m->id); + module::reader_id_module.push (m->id, m); + + return m; + } + else + { + unsigned id = ar->io_id_id(io_id); + return module::reader_id_module(id); + } +} diff --git a/algebra/multivariate_laurentpoly.h b/algebra/multivariate_laurentpoly.h index 49c2137..8e9f3a1 100644 --- a/algebra/multivariate_laurentpoly.h +++ b/algebra/multivariate_laurentpoly.h @@ -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 { diff --git a/algebra/multivariate_polynomial.h b/algebra/multivariate_polynomial.h index 75aac48..c35bd32 100644 --- a/algebra/multivariate_polynomial.h +++ b/algebra/multivariate_polynomial.h @@ -5,7 +5,7 @@ template 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 uncommon_factors (multivariate_polynomial b, basedvector ds); maybe diff --git a/algebra/polynomial.h b/algebra/polynomial.h index 4aa83c5..4d1771f 100644 --- a/algebra/polynomial.h +++ b/algebra/polynomial.h @@ -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 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 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 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 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::operator *= (T s) } template polynomial -polynomial::operator * (polynomial p) const +polynomial::operator * (const polynomial &p) const { polynomial r; @@ -213,14 +234,15 @@ polynomial::operator * (polynomial p) const return r; } -template pair, polynomial > -polynomial::divide_with_remainder (polynomial d) const +template tuple, polynomial > +polynomial::divide_with_remainder (const polynomial &d) const { + // num = *this assert (d != 0); polynomial r (COPY, *this); polynomial q; - + pair d_leading_term = d.coeffs.tail (); for (;;) { @@ -240,45 +262,80 @@ polynomial::divide_with_remainder (polynomial d) const assert (r == 0 || r.degree () < d.degree ()); // assert (*this == q*d + r); - return pair (q, r); + return make_tuple (q, r); } template polynomial -polynomial::mod (polynomial d) const +polynomial::mod (const polynomial &denom) const { - pair, polynomial > qr = divide_with_remainder (d); - return qr.second; + polynomial q, r; + tie (q, r) = divide_with_remainder (denom); + return r; } template bool -polynomial::divides (polynomial d) const +polynomial::divides (const polynomial &num) const { - pair, polynomial > 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 polynomial -polynomial::divide_exact (polynomial d) const +polynomial::divide_exact (const polynomial &denom) const { - pair, polynomial > 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 polynomial -polynomial::gcd (polynomial b) const +polynomial::gcd (const polynomial &b) const { polynomial a = *this; - while (b != 0) { - pair, polynomial > 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 polynomial +polynomial::lcm (const polynomial &b) const +{ + // a = *this + return divide_exact (gcd (b)) * b; +} + +template tuple, polynomial, polynomial > +polynomial::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 void polynomial::check () const @@ -338,14 +395,14 @@ class polynomial 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 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 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 void display_self () const { show_self (); newline (); } void show_self () const; }; - diff --git a/cobordism.cpp b/cobordism.cpp index 55acf28..72e8200 100644 --- a/cobordism.cpp +++ b/cobordism.cpp @@ -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); diff --git a/cobordism.h b/cobordism.h index e8dfc47..0365343 100644 --- a/cobordism.h +++ b/cobordism.h @@ -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, diff --git a/cube.h b/cube.h index b3883ac..248995e 100644 --- a/cube.h +++ b/cube.h @@ -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, 1> &out, resolution_diagram_builder &rdb) const = 0; @@ -16,8 +16,8 @@ template 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 linear_combination; + typedef ::linear_combination_const_iter linear_combination_const_iter; public: bool markedp_only; @@ -47,6 +47,7 @@ public: bool reverse_orientation, unsigned to_reverse) const; + mod_map compute_dinv (unsigned c); mod_map H_i (unsigned c); mod_map 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 >, 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 compute_twisted_map (basedvector edge_weight, unsigned dh, diff --git a/cube_impl.h b/cube_impl.h index 87ae5f8..e66ebf1 100644 --- a/cube_impl.h +++ b/cube_impl.h @@ -9,7 +9,7 @@ public: khC_generators (const cube &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::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, 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, 1> &out, resolution_diagram_builder &rdb) const @@ -302,7 +302,7 @@ cube::compute_X (unsigned p) const template mod_map cube::H_i (unsigned c) { - mod_map b (khC, 0); + map_builder b (khC, 0); for (unsigned i = 0; i < n_resolutions; i ++) { if (unsigned_bittest (i, c)) @@ -319,8 +319,23 @@ cube::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::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::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::H_i (unsigned c) return H_c; } +template mod_map +cube::compute_dinv (unsigned c) +{ + map_builder 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 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 dinv (p); + dinv.check_grading (grading (-1, -2)); + return dinv; +} + template void cube::check_reverse_crossings () { @@ -415,6 +534,50 @@ cube::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 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 >, 1> &out, resolution_diagram_builder &rdb) const diff --git a/gss.cpp b/gss.cpp deleted file mode 100644 index 3f8f28d..0000000 --- a/gss.cpp +++ /dev/null @@ -1,126 +0,0 @@ - -#include - -const char *program_name; - -void -usage () -{ - printf ("usage: %s [-f] [-h] [-o ] [-v] \n", program_name); - printf (" compute Szabo's geometric spectral sequence for 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 : write output to \n"); - printf (" (stdout is the default)\n"); - printf (" -v : verbose: report progress as the computation proceeds\n"); - printf (" 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 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 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); -} diff --git a/kk.cpp b/kk.cpp new file mode 100644 index 0000000..0d45025 --- /dev/null +++ b/kk.cpp @@ -0,0 +1,666 @@ + +#include + +const char *program_name; + +void +usage () +{ + printf ("usage: %s [options...] \n", program_name); + printf (" compute for knot or link \n"); + printf (" 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 : write output to \n"); + printf (" (stdout is the default)\n"); + printf (" -f : ground field (if applicable)\n"); + printf (" (Z2 is the default)\n"); + printf (" -v : verbose: report progress as the computation proceeds\n"); + printf (" can be one of:\n"); + printf (" Z2, Z3, Q\n"); + printf (" 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 mod_map +compute_link_splitting_d (knot_diagram &kd, + cube &c, + basedvector 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 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 crossing_over_sign; + + // crossings + set pending; + set 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 untwisted_d = c.compute_d (1, 0, 0, 0, 0); + assert (untwisted_d.compose (untwisted_d) == 0); + + mod_map 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 c (kd, reduced); + ptr > C = c.khC; + mod_map 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 pages; + + unsigned k = 1; + for (;;) + { + chain_complex_simplifier s (C, d, + maybe (k), maybe (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 void +compute_invariant () +{ + if (!strcmp (invariant, "kh")) + { + cube c (kd, reduced); + ptr > C = c.khC; + mod_map d = c.compute_d (1, 0, 0, 0, 0); + + unsigned m = kd.num_components (); + hg_grading_mapper mapper (m); + + chain_complex_simplifier s (C, d, + maybe (1), maybe (0)); + C = s.new_C; + d = s.new_d; + + sseq_bounds b (C, mapper); + sseq_page pg (b, 2, grading (0, 0), mod_map (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 c (kd, reduced); + ptr > C = c.khC; + + unsigned m = kd.num_components (); + basedvector comp_weight (m); + for (unsigned i = 1; i <= m; i ++) + comp_weight[i] = R ((int)(i - 1)); + + mod_map d = compute_link_splitting_d (kd, c, comp_weight); + + hg_grading_mapper mapper (m); + + sseq_bounds b (C, mapper); + basedvector pages; + + int k = 0; + for (;;) + { + chain_complex_simplifier s (C, d, + maybe (1 - 2*k), maybe (-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 c (kd, reduced); + ptr > C = c.khC; + + mod_map 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 pages; + + int k = 0; + for (;;) + { + chain_complex_simplifier s (C, d, + maybe (1), maybe (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 c (kd, 0); + ptr > C = c.khC; + + mod_map 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 s (C, d, + maybe (1), maybe (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 > hq_gens, + ptr > H) +{ + fprintf (fp, "hom={"); + bool first = 1; + for (map >::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 > hq_gens, + std::string name, + grading delta, + mod_map f) +{ + fprintf (fp, "%s={", name.c_str ()); + + bool first = 1; + for (map >::const_iter i = hq_gens; i; i ++) + { + grading from_hq = i.key (); + basedvector from_gens = i.val (); + + grading to_hq = from_hq + delta; + if (hq_gens % to_hq) + { + basedvector 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 > H, + mod_map sq1, + mod_map sq2) +{ + unsigned n = H->dim (); + + map > hq_gens; + for (unsigned i = 1; i <= H->dim (); i ++) + hq_gens[H->generator_grading (i)].append (i); + + unsigned t = 0; + for (map >::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 c (kd); + mod_map d = c.compute_d (1, 0, 0, 0, 0); + + chain_complex_simplifier s (c.khC, d, maybe (1), maybe (0)); + assert (s.new_d == 0); + + steenrod_square sq (c, d, s); + mod_map sq1 = sq.sq1 (); + mod_map sq2 = sq.sq2 (); + + ptr > 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, or 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 (); + else if (!strcmp (field, "Z3")) + compute_invariant > (); + else if (!strcmp (field, "Q")) + compute_invariant (); + else + { + fprintf (stderr, "error: unknown field %s\n", field); + exit (EXIT_FAILURE); + } + } + + if (file) + fclose (outfp); +} diff --git a/knot_diagram.cpp b/knot_diagram.cpp index 5b5e803..ea6c1b2 100644 --- a/knot_diagram.cpp +++ b/knot_diagram.cpp @@ -22,7 +22,7 @@ knot_diagram::knot_diagram (const planar_diagram &pd) crossings[c] = basedvector (4); } - smallbitset done (num_edges ()); + set 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 (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 (num_epts ()); + ept_index = basedvector (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 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) diff --git a/knot_diagram.h b/knot_diagram.h index 46247aa..e721233 100644 --- a/knot_diagram.h +++ b/knot_diagram.h @@ -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, 1> &crossings_); @@ -157,6 +171,8 @@ class knot_diagram int writhe () const { return (int)nplus - (int)nminus; } + unsigned total_linking_number () const; + basedvector, 1> planar_diagram_crossings () const; hash_t hash_self () const; diff --git a/knot_parser/knot_parser.cc b/knot_parser/knot_parser.cc index 6b764d5..9f0a338 100644 --- a/knot_parser/knot_parser.cc +++ b/knot_parser/knot_parser.cc @@ -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 ("", *(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 ("", *(yysemantic_stack_[(4) - (3)].int_vec2))); } - break; - - case 15: - -/* Line 678 of lalr1.cc */ -#line 130 "knot_parser/knot_parser.yy" - { - basedvector, 1> even_labels (1); - even_labels[1] = *(yysemantic_stack_[(4) - (3)].int_vec); - parsed_knot = knot_diagram (dt_code ("", even_labels)); - } - break; - case 16: - -/* Line 678 of lalr1.cc */ -#line 136 "knot_parser/knot_parser.yy" - { parsed_knot = knot_diagram (dt_code ("", *(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 ("", *(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 ("", (yysemantic_stack_[(4) - (3)].string))); } +/* Line 661 of lalr1.cc */ +#line 147 "knot_parser/knot_parser.yy" + { (yyval.kd) = new knot_diagram (planar_diagram ("", *(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, 1> even_labels (1); + even_labels[1] = *(yysemantic_stack_[(4) - (3)].int_vec); + (yyval.kd) = new knot_diagram (dt_code ("", 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 ("", *(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 ("", (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, 1> *v = new basedvector, 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, 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 *v = new basedvector (); @@ -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 *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, 1> *v = new basedvector, 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, 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 *v = new basedvector (); @@ -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; } - diff --git a/knot_parser/knot_parser.hh b/knot_parser/knot_parser.hh index b604953..7f07eb3 100644 --- a/knot_parser/knot_parser.hh +++ b/knot_parser/knot_parser.hh @@ -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 - -/* 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 #include #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_vec; basedvector, 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 */ diff --git a/knot_parser/knot_parser.yy b/knot_parser/knot_parser.yy index 9210974..2a30bdc 100644 --- a/knot_parser/knot_parser.yy +++ b/knot_parser/knot_parser.yy @@ -24,6 +24,7 @@ YY_DECL; basedvector *int_vec; basedvector, 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 ALT NONALT %token STRING +%type knot knot_1 +%type rolfsen_knot htw_knot mt_link planar_diagram dt torus_link unknot braid %type alt_spec %type 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 ("", *$3)); } + { $$ = new knot_diagram (planar_diagram ("", *$3)); } | PD '[' crossing_vec ']' - { parsed_knot = knot_diagram (planar_diagram ("", *$3)); } + { $$ = new knot_diagram (planar_diagram ("", *$3)); } ; dt: @@ -130,22 +152,22 @@ dt: { basedvector, 1> even_labels (1); even_labels[1] = *$3; - parsed_knot = knot_diagram (dt_code ("", even_labels)); + $$ = new knot_diagram (dt_code ("", even_labels)); } | DT '[' int_vec2 ']' - { parsed_knot = knot_diagram (dt_code ("", *$3)); } + { $$ = new knot_diagram (dt_code ("", *$3)); } | DT '[' STRING ']' - { parsed_knot = knot_diagram (dt_code ("", $3)); } + { $$ = new knot_diagram (dt_code ("", $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); } ; diff --git a/knot_parser/location.hh b/knot_parser/location.hh index c123693..7faaf2b 100644 --- a/knot_parser/location.hh +++ b/knot_parser/location.hh @@ -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 -# include # 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 */ diff --git a/knot_parser/position.hh b/knot_parser/position.hh index c034a2e..dbbea36 100644 --- a/knot_parser/position.hh +++ b/knot_parser/position.hh @@ -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 // std::max # include # include -# include + +# 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 */ diff --git a/knot_parser/stack.hh b/knot_parser/stack.hh index 3c16aa6..e005e60 100644 --- a/knot_parser/stack.hh +++ b/knot_parser/stack.hh @@ -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 +#ifndef YY_YY_KNOT_PARSER_STACK_HH_INCLUDED +# define YY_YY_KNOT_PARSER_STACK_HH_INCLUDED + +# include 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 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 */ diff --git a/knot_tables.cpp b/knot_tables.cpp index 2acaae2..3733799 100644 --- a/knot_tables.cpp +++ b/knot_tables.cpp @@ -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 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 &twists) { - unsigned n_crossings = twists.size (); unsigned e = 0; basedvector final_strands (n_strands); @@ -622,22 +641,44 @@ braid (unsigned n_strands, const basedvector &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, 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, 1> crossings (n_crossings); for (unsigned i = 1; i <= n_crossings; i ++) - crossings[i] = basedvector (4); + crossings[i] = basedvector (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 &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, 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); +} diff --git a/knotkit.h b/knotkit.h index c0165ae..b1974e6 100644 --- a/knotkit.h +++ b/knotkit.h @@ -14,13 +14,90 @@ class knot_diagram; #include #include +#include #include #include #include #include +#include #include +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 &twists); -planar_diagram braid (unsigned n_strands, unsigned n_twists, int twists_ar[]); +knot_diagram braid (unsigned n_strands, const basedvector &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); diff --git a/lib/hashmap.h b/lib/hashmap.h index 1616840..75ddae2 100644 --- a/lib/hashmap.h +++ b/lib/hashmap.h @@ -1,23 +1,29 @@ /* wrapper for std::unordered_map */ -template -struct hasher : public std::unary_function -{ - hash_t operator () (const K &k) const { return hash (k); } -}; - template -class hashmap : public map_wrapper >, K, V> +class hashmap : public map_wrapper >, K, V> { - typedef map_wrapper >, K, V> base; + typedef map_wrapper >, K, V> base; public: hashmap () { } hashmap (const hashmap &m) : base(m) { } hashmap (copy, const hashmap &m) : base(COPY, m) { } + hashmap (initializer_list > il) : base(il) { } hashmap (reader &r) : base(r) { } ~hashmap () { } hashmap &operator = (const hashmap &m) { base::operator = (m); return *this; } + hashmap &operator = (initializer_list > il) + { + base::operator = (il); + return *this; + } }; + +template +using hashmap_iter = map_wrapper_iter, K, V>; + +template +using hashmap_const_iter = map_wrapper_const_iter, K, V>; diff --git a/lib/hashset.h b/lib/hashset.h new file mode 100644 index 0000000..971eb2a --- /dev/null +++ b/lib/hashset.h @@ -0,0 +1,25 @@ + +/* wrapper for std::unordered_set */ + +template +class hashset : public set_wrapper >, T> +{ + typedef set_wrapper >, T> base; + + public: + hashset () { } + hashset (const hashset &m) : base(m) { } + hashset (copy, const hashset &m) : base(COPY, m) { } + hashset (initializer_list il) : base(il) { } + hashset (reader &r) : base(r) { } + ~hashset () { } + + hashset &operator = (const hashset &m) { base::operator = (m); return *this; } + hashset &operator = (initializer_list il) { base::operator = (il); return *this; } +}; + +template +using hashset_iter = set_wrapper_iter >, T>; + +template +using hashset_const_iter = set_wrapper_const_iter >, T>; diff --git a/lib/io.cpp b/lib/io.cpp index a02ccd0..c6a75fc 100644 --- a/lib/io.cpp +++ b/lib/io.cpp @@ -1,10 +1,236 @@ -#include +// #include +#include + +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); } diff --git a/lib/io.h b/lib/io.h index 9f499e9..1860c28 100644 --- a/lib/io.h +++ b/lib/io.h @@ -1,43 +1,162 @@ -extern FILE *open_file (const std::string &file, const char *mode); -extern void close_file (FILE *fp); +template 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 void write_mod (ptr > 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 ptr > 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 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 inline void write (writer &w, const T &x) { x.write_self (w); } diff --git a/lib/lib.h b/lib/lib.h index e72b113..1bb300c 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -7,17 +8,21 @@ #include #include +#include +#include + +#include #include #include #include #include #include -#include -#include +#include +#include +#include /* just need to implement ==, < */ -template bool operator != (const T &a, const T &b) { return ! (a == b); } template bool operator <= (const T &a, const T &b) { return (a < b) || (a == b); } template bool operator > (const T &a, const T &b) { return ! (a <= b); } template bool operator >= (const T &a, const T &b) { return ! (a < b); } @@ -25,6 +30,8 @@ template 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 +using std::tuple; +using std::get; +using std::make_tuple; +using std::tie; +using std::ignore; +using std::initializer_list; #include #include + +#include + #include + #include #include + +#include #include class bitset; @@ -172,12 +197,40 @@ inline int random_int (int from, int to) #include #include #include - #include #include + +template +struct hasher : public std::unary_function +{ + hash_t operator () (const K &k) const { return hash (k); } +}; + #include +#include + #include #include #include #include #include + +// ??? io + +class algebra_writer +{ +public: + // modules + unsigned io_id_counter; + map id_io_id; + + algebra_writer () : io_id_counter(0) { } + ~algebra_writer () { } +}; + +class algebra_reader +{ +public: + map io_id_id; + +}; diff --git a/lib/map.h b/lib/map.h index 3be8881..859829a 100644 --- a/lib/map.h +++ b/lib/map.h @@ -1,5 +1,5 @@ -/* wrapper for stl map */ +/* wrapper for std::map */ template class map : public map_wrapper, K, V> @@ -11,9 +11,20 @@ class map : public map_wrapper, 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 > il) : base(il) { } map (reader &r) : base(r) { } ~map () { } map &operator = (const map &m) { base::operator = (m); return *this; } + map &operator = (initializer_list > il) + { + base::operator = (il); + return *this; + } }; + +template +using map_iter = map_wrapper_iter, K, V>; + +template +using map_const_iter = map_wrapper_const_iter, K, V>; diff --git a/lib/map_wrapper.h b/lib/map_wrapper.h index 762bfc7..e263412 100644 --- a/lib/map_wrapper.h +++ b/lib/map_wrapper.h @@ -1,5 +1,5 @@ -/* wrapper for stl maps */ +/* wrapper for STL maps */ template class map_wrapper_iter; template class map_wrapper_const_iter; @@ -7,14 +7,23 @@ template class map_wrapper_const_iter; template class map_wrapper { - private: friend class map_wrapper_iter; friend class map_wrapper_const_iter; - + + 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 > il) : t(il) { } + ~map_impl () = default; + + map_impl &operator = (const map_impl &) = delete; }; ptr 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 > 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 > 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 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 -map_wrapper::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 map_wrapper::map_wrapper (reader &r) : impl(new map_impl) @@ -222,19 +233,19 @@ template class map_wrapper_iter { private: - map_wrapper &m; + ptr::map_impl> impl; typename M::iterator i, end; bool deleted; public: - map_wrapper_iter (map_wrapper &m_) : m(m_), i(m_.impl->t.begin ()), end(m_.impl->t.end ()), deleted(0) { } + map_wrapper_iter (map_wrapper &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 map_wrapper_const_iter { private: + ptr::map_impl> impl; typename M::const_iterator i, end; public: - map_wrapper_const_iter (const map_wrapper &m) : i(m.impl->t.begin ()), end(m.impl->t.end ()) { } + map_wrapper_const_iter (const map_wrapper &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; } diff --git a/lib/pair.h b/lib/pair.h index fb83a2f..46d8f51 100644 --- a/lib/pair.h +++ b/lib/pair.h @@ -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 +triple::triple (reader &r) +{ + read (r, first); + read (r, second); + read (r, third); +} + +template void +triple::write_self (writer &w) const +{ + write (w, first); + write (w, second); + write (w, third); +} diff --git a/lib/priority_queue.h b/lib/priority_queue.h index 6b008f7..c332977 100644 --- a/lib/priority_queue.h +++ b/lib/priority_queue.h @@ -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); } }; diff --git a/lib/refcount.h b/lib/refcount.h index f638e63..b51da0d 100644 --- a/lib/refcount.h +++ b/lib/refcount.h @@ -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 diff --git a/lib/set.h b/lib/set.h index 2137655..0f3e08f 100644 --- a/lib/set.h +++ b/lib/set.h @@ -1,149 +1,46 @@ -/* wrap for std::set */ - -template class set_iter; -template class set_const_iter; +/* wrapper for std::set */ template -class set +class set : public set_wrapper, T> { - private: - friend class set_iter; - friend class set_const_iter; - - class set_impl : public refcounted - { - public: - std::set t; - }; - - ptr impl; + typedef set_wrapper, T> base; public: - typedef set_iter iter; - typedef set_const_iter 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 (s.impl->t); } - set (reader &r); + set () { } + set (const set &m) : base(m) { } + set (copy, const set &m) : base(COPY, m) { } + set (initializer_list il) : base(il) { } + set (reader &r) : base(r) { } ~set () { } - set &operator = (const set &s) { impl = s.impl; return *this; } - - T pop () - { - typename std::set::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 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 &s); - set &operator &= (const set &s); - set &operator ^= (const set &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 set_iter -{ - set &s; - typename std::set::const_iterator i, end; - bool deleted; - - public: - set_iter (set &s_) : s(s_), i(s_.impl->t.begin ()), end(s_.impl->t.end ()), deleted(0) { } - ~set_iter () { } - - void del () - { - assert (!deleted); - typename std::set::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, T>; template -class set_const_iter -{ - typename std::set::const_iterator i, end; - - public: - set_const_iter (const set &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 -set::set (reader &r) -{ - unsigned n; - read (r, n); - T x; - for (unsigned i = 0; i < n; i ++) - { - read (r, x); - push (x); - } -} - -template const T & -set::head () const -{ - set_const_iter i = *this; - assert (i); - return i.val (); -} - -template const T & -set::tail () const -{ - typename std::set::const_reverse_iterator i = impl->t.rbegin (); - assert (i != impl->t.rend ()); - return *i; -} + using set_const_iter = set_wrapper_const_iter, T>; template bool set::operator == (const set &s) const { - typename std::set::const_iterator i = impl->t.begin (), + typename std::set::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::operator == (const set &s) const template bool set::operator < (const set &s) const { - typename std::set::const_iterator i = impl->t.begin (), + typename std::set::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::operator < (const set &s) const template bool set::operator <= (const set &s) const { - typename std::set::const_iterator i = impl->t.begin (), + typename std::set::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::operator <= (const set &s) const template bool set::toggle (const T &v) { - typename std::set::const_iterator i = impl->t.lower_bound (v), - end = impl->t.end (); + typename std::set::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::const_iterator j = --i; assert (*j < v); - impl->t.insert (j, v); + this->impl->t.insert (j, v); } return 0; } } template set & -set::operator |= (const set &s) +set::operator |= (const set &s) { std::set 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 set & -set::operator &= (const set &s) +set::operator &= (const set &s) { std::set 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 set & -set::operator ^= (const set &s) +set::operator ^= (const set &s) { #if 0 printf ("before:\n"); printf ("this:"); - for (typename std::set::const_iterator i = impl->t.begin (); i != impl->t.end (); i ++) + for (typename std::set::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::operator ^= (const set &s) #endif #if 1 - typename std::set::const_iterator i = impl->t.begin (), - iend = impl->t.end (), + typename std::set::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::operator ^= (const set &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::operator ^= (const set &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::operator ^= (const set &s) #if 0 std::set 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::const_iterator i = impl->t.begin (); i != impl->t.end (); i ++) + for (typename std::set::const_iterator i = this->impl->t.begin (); i != this->impl->t.end (); i ++) printf (" %d", *i); printf ("\n"); #endif return *this; } - -template void -set::write_self (writer &w) const -{ - write (w, card ()); - for (const_iter i = *this; i; i ++) - write (w, i.val ()); -} - -template hash_t -set::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; -} diff --git a/lib/set_wrapper.h b/lib/set_wrapper.h new file mode 100644 index 0000000..ef8eb04 --- /dev/null +++ b/lib/set_wrapper.h @@ -0,0 +1,171 @@ + +/* wrapper for STL maps */ + +template class set_wrapper_iter; +template class set_wrapper_const_iter; + +template +class set_wrapper +{ + friend class set_wrapper_iter; + friend class set_wrapper_const_iter; + + 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 il) : t(il) { } + ~set_wrapper_impl () = default; + + set_wrapper_impl &operator = (const set_wrapper_impl &) = delete; + }; + + ptr impl; + + public: + typedef set_wrapper_iter iter; + typedef set_wrapper_const_iter 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 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 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 set_wrapper_iter +{ + ptr::set_wrapper_impl> impl; + typename S::const_iterator i, end; + bool deleted; + + public: + set_wrapper_iter (set_wrapper &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 set_wrapper_const_iter +{ + ptr::set_wrapper_impl> impl; + typename S::const_iterator i, end; + + public: + set_wrapper_const_iter (const set_wrapper &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 +set_wrapper::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 const T & +set_wrapper::head () const +{ + set_wrapper_const_iter i = *this; + assert (i); + return i.val (); +} + +template const T & +set_wrapper::tail () const +{ + typename S::const_reverse_iterator i = impl->t.rbegin (); + assert (i != impl->t.rend ()); + return *i; +} + +template void +set_wrapper::write_self (writer &w) const +{ + write (w, card ()); + for (const_iter i = *this; i; i ++) + write (w, i.val ()); +} + +template hash_t +set_wrapper::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; +} diff --git a/lib/ullmanset.h b/lib/ullmanset.h index 658fc33..d6599ad 100644 --- a/lib/ullmanset.h +++ b/lib/ullmanset.h @@ -2,12 +2,15 @@ template class ullmanset_iter; template class ullmanset_const_iter; +template class ullmanset_const_stl_iter; + template class ullmanset { private: friend class ullmanset_iter; friend class ullmanset_const_iter; + friend class ullmanset_const_stl_iter; 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 d; public: typedef ullmanset_iter iter; typedef ullmanset_const_iter 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 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 begin () const; + inline ullmanset_const_stl_iter 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 void -ullmanset::unref () +ullmanset::data::delete_at_pos (unsigned p) { - if (d && --d->refcount == 0) - { - delete [] (char *)d; - d = 0; - } -} - -template void -ullmanset::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 ullmanset::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 +ullmanset::ullmanset (unsigned size, initializer_list il) + : ullmanset(size) +{ + for (unsigned i : il) + operator += (i); } template ullmanset::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 ullmanset::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::ullmanset (reader &r) template bool ullmanset::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::operator == (const ullmanset &s) template void ullmanset::push (unsigned k) { - assert (d); assert (!operator % (k)); unsigned p = d->n ++; d->kp[p].key = k; @@ -204,7 +189,6 @@ ullmanset::push (unsigned k) template void ullmanset::operator += (unsigned k) { - assert (d); assert ((k - B) >= 0); assert ((k - B) < d->size); if (!operator % (k)) @@ -218,13 +202,12 @@ ullmanset::operator += (unsigned k) template void ullmanset::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::write_self (writer &w) const write (w, i.val ()); } +template +class ullmanset_const_stl_iter +{ + private: + ptr::data> d; + unsigned p; + + public: + ullmanset_const_stl_iter (const ullmanset &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 ullmanset_const_stl_iter +ullmanset::begin () const +{ + return ullmanset_const_stl_iter (*this, 0); +} + +template ullmanset_const_stl_iter +ullmanset::end () const +{ + return ullmanset_const_stl_iter (*this, d->n); +} + template class ullmanset_iter { private: - ullmanset &s; + ptr::data> d; unsigned i; bool deleted; public: - ullmanset_iter (ullmanset &s_) : s(s_), i(0), deleted(0) { assert (s_.d); } + ullmanset_iter (ullmanset &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 class ullmanset_const_iter { private: - const ullmanset &s; + ptr::data> d; unsigned i; public: - ullmanset_const_iter (const ullmanset &s_) : s(s_), i(0) { assert (s_.d); } + ullmanset_const_iter (const ullmanset &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 ++; } }; diff --git a/lib/vector.h b/lib/vector.h index 52b1f15..06f4e52 100644 --- a/lib/vector.h +++ b/lib/vector.h @@ -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; } diff --git a/main.cpp b/main.cpp index 4ed6dc1..669272b 100644 --- a/main.cpp +++ b/main.cpp @@ -60,14 +60,14 @@ test_ring (int p) if (x != 0 && x | y) { - R q = y.div (x); + R q = y.divide_exact (x); assert (y == q * x); } if (x != 0 || y != 0) { - triple t = x.extended_gcd (y); - assert (t.first == t.second*x + t.third*y); + tuple t = x.extended_gcd (y); + assert (get<0> (t) == get<1> (t)*x + get<2> (t)*y); } for (int k = -n; k <= n; k ++) @@ -124,58 +124,3412 @@ rank_lte (multivariate_laurentpoly p, return 1; } -int -main () +triple, + multivariate_laurentpoly, + multivariate_laurentpoly > +square (knot_diagram &kd) +{ + cube c (kd); + mod_map d = c.compute_d (1, 0, 0, 0, 0); + + chain_complex_simplifier s (c.khC, d, 1); + + steenrod_square sq (c, d, s); + mod_map sq1 = sq.sq1 (); + // display ("sq1:\n", sq1); + + mod_map sq2 = sq.sq2 (); + // display ("sq2:\n", sq2); + + assert (sq1.compose (sq1) == 0); + assert (sq2.compose (sq2) + sq1.compose (sq2).compose (sq1) == 0); + + multivariate_laurentpoly P = s.new_C->free_poincare_polynomial (); + + ptr > sq1_im = sq1.image (); + multivariate_laurentpoly sq1_P = sq1_im->free_poincare_polynomial (); + + ptr > sq2_im = sq2.image (); + multivariate_laurentpoly sq2_P = sq2_im->free_poincare_polynomial (); + + return triple, + multivariate_laurentpoly, + multivariate_laurentpoly > (P, sq1_P, sq2_P); +} + +void +compute_show_kh_sq (knot_desc desc +#if 0 + , + multivariate_laurentpoly orig_P, + multivariate_laurentpoly orig_sq1_P, + multivariate_laurentpoly orig_sq2_P +#endif + ) +{ + knot_diagram kd = desc.diagram (); + + printf ("computing %s...\n", kd.name.c_str ()); + + cube c (kd); + mod_map d = c.compute_d (1, 0, 0, 0, 0); + + chain_complex_simplifier s (c.khC, d, 1); + + steenrod_square sq (c, d, s); + mod_map sq1 = sq.sq1 (); + mod_map sq2 = sq.sq2 (); + + assert (sq1.compose (sq1) == 0); + assert (sq2.compose (sq2) + sq1.compose (sq2).compose (sq1) == 0); + + multivariate_laurentpoly P = s.new_C->free_poincare_polynomial (); + + ptr > sq1_im = sq1.image (); + multivariate_laurentpoly sq1_P = sq1_im->free_poincare_polynomial (); + + ptr > sq2_im = sq2.image (); + multivariate_laurentpoly sq2_P = sq2_im->free_poincare_polynomial (); + + printf (" P "); display (P); + printf (" sq1_P "); display (sq1_P); + printf (" sq2_P "); display (sq2_P); + +#if 0 + assert (P == orig_P); + assert (sq1_P == orig_sq1_P); + assert (sq2_P == orig_sq2_P); +#endif +} + +unsigned +homological_width (ptr > H) +{ + int maxd = -1000, + mind = 1000; + set gs = H->gradings (); + for (set_const_iter gg = gs; gg; gg ++) + { + grading hq = gg.val (); + int d = 2 * hq.h - hq.q; + if (d < mind) + mind = d; + if (d > maxd) + maxd = d; + } + int dwidth = maxd - mind; + + assert (is_even (dwidth)); + unsigned hwidth = (dwidth / 2) + 1; + return hwidth; +} + +basedvector hwidth_knots; + +void +load (map, mod_map > > &knot_kh_sq, + knot_desc desc) +{ + char buf[1000]; + if (desc.t == knot_desc::TORUS) + { + sprintf (buf, "knot_kh_sq/T.dat"); + } + else + { + unsigned j0 = desc.j; + + switch (desc.t) + { + case knot_desc::ROLFSEN: + sprintf (buf, "knot_kh_sq/%d_%d.dat", desc.i, j0); + break; + + case knot_desc::HTW: + sprintf (buf, "knot_kh_sq/K%d_%d.dat", desc.i, j0); + break; + + case knot_desc::MT: + sprintf (buf, "knot_kh_sq/L%d_%d.dat", desc.i, j0); + break; + + default: abort (); + } + } + + struct stat stat_buf; + if (stat (buf, &stat_buf) != 0) + { + if (errno == ENOENT) + return; + + stderror ("stat: %s", buf); + exit (EXIT_FAILURE); + } + + printf ("loading %s...\n", buf); + + file_reader r (buf, 1); + map, mod_map > > m (r); + for (map, mod_map > >::const_iter i = m; i; i ++) + { + mod_map sq1 = i.val ().first; + ptr > H = sq1.domain (); + unsigned hwidth = homological_width (H); + // hwidth_knots[hwidth] ++; + +#if 0 + if (hwidth == 2) + continue; + if (i.key ().t == knot_desc::MT + && i.key ().diagram ().num_components () == 1) + continue; +#endif + + knot_kh_sq.push (i.key (), i.val ()); + } + + printf ("done.\n"); +} + +void +load (map, mod_map > > &knot_kh_sq, + const char *file) +{ + char buf[1000]; + sprintf (buf, "knot_kh_sq/%s", file); + + printf ("loading %s...\n", buf); + + struct stat stat_buf; + if (stat (buf, &stat_buf) != 0) + { + if (errno == ENOENT) + { + printf ("%s does not exist.\n", buf); + return; + } + + stderror ("stat: %s", buf); + exit (EXIT_FAILURE); + } + + file_reader r (buf, 1); + map, mod_map > > m (r); + for (map, mod_map > >::const_iter i = m; i; i ++) + { +#if 0 + mod_map sq1 = i.val ().first; + ptr > H = sq1.domain (); + unsigned hwidth = homological_width (H); + // hwidth_knots[hwidth] ++; +#endif + +#if 0 + if (hwidth == 2) + continue; + if (i.key ().t == knot_desc::MT + && i.key ().diagram ().num_components () == 1) + continue; +#endif + + knot_kh_sq.push (i.key (), i.val ()); + } + + printf ("done.\n"); +} + +static const int block_size = 100; + +void +sage_show (FILE *fp, + std::string prefix, + map > hq_gens, + ptr > H) +{ + fprintf (fp, "%s_hom={", prefix.c_str ()); + bool first = 1; + for (map >::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, + std::string prefix, + map > hq_gens, + std::string name, + grading delta, + mod_map f) +{ + fprintf (fp, "%s_%s={", prefix.c_str (), name.c_str ()); + + bool first = 1; + for (map >::const_iter i = hq_gens; i; i ++) + { + grading from_hq = i.key (); + basedvector from_gens = i.val (); + + grading to_hq = from_hq + delta; + if (hq_gens % to_hq) + { + basedvector 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, + std::string prefix, + ptr > H, + mod_map sq1, + mod_map sq2) +{ + unsigned n = H->dim (); + + map > hq_gens; + for (unsigned i = 1; i <= H->dim (); i ++) + hq_gens[H->generator_grading (i)].append (i); + + unsigned t = 0; + for (map >::const_iter i = hq_gens; i; i ++) + t += i.val ().size (); + assert (t == n); + + sage_show (fp, prefix, hq_gens, H); + sage_show (fp, prefix, hq_gens, "sq1", grading (1, 0), sq1); + sage_show (fp, prefix, hq_gens, "sq2", grading (2, 0), sq2); + fprintf (fp, "\n"); +} + +void +test_sage_show () +{ + knot_diagram kd (mt_link (11, 0, 449)); + show (kd); newline (); + + planar_diagram pd (kd); + pd.display_knottheory (); + + cube c (kd); + mod_map d = c.compute_d (1, 0, 0, 0, 0); + + chain_complex_simplifier s (c.khC, d, 1); + + steenrod_square sq (c, d, s); + mod_map sq1 = sq.sq1 (); + mod_map sq2 = sq.sq2 (); + + // display ("sq2:\n", sq2); + + sage_show_khsq (stdout, "L11n449", sq1.domain (), sq1, sq2); +} + +void +dump_sage () +{ + char buf[1000]; + +#if 0 + for (unsigned i = 10; i >= 1; i --) + { + if (i <= 10) + { + for (unsigned j = 1; j <= rolfsen_crossing_knots (i); j += block_size) + { + load (knot_kh_sq, knot_desc (knot_desc::ROLFSEN, i, j)); + } + } + ... + } +#endif + + for (unsigned i = 12; i >= 1; i --) + { + map, mod_map > > knot_kh_sq; + +#if 0 + sprintf (buf, "K%d.sage", i); + + FILE *fp = fopen (buf, "w"); + if (fp == 0) + { + stderror ("fopen: %s", buf); + exit (EXIT_FAILURE); + } + + for (unsigned j = 1; j <= htw_knots (i); j += block_size) + { + load (knot_kh_sq, knot_desc (knot_desc::HTW, i, j)); + } + + for (map, mod_map > >::const_iter k = knot_kh_sq; k; k ++) + { + sprintf (buf, "K%s", k.key ().name ().c_str ()); + sage_show_khsq (fp, buf, k.val ().first.domain (), k.val ().first, k.val ().second); + } + + fclose (fp); +#endif + +#if 1 + sprintf (buf, "L%d.sage", i); + + FILE *fp = fopen (buf, "w"); + if (fp == 0) + { + stderror ("fopen: %s", buf); + exit (EXIT_FAILURE); + } + + if (i <= 13) + { + for (unsigned j = 1; j <= mt_links (i); j += block_size) + { + load (knot_kh_sq, knot_desc (knot_desc::MT, i, j)); + } + } + + if (i == 14) + { + for (unsigned j = 1; j <= mt_links (14, 0); j += block_size) + { + load (knot_kh_sq, knot_desc (knot_desc::MT, 14, mt_links (14, 1) + j)); + } + } + + for (map, mod_map > >::const_iter k = knot_kh_sq; k; k ++) + { + sprintf (buf, "K%s", k.key ().name ().c_str ()); + sage_show_khsq (fp, buf, k.val ().first.domain (), k.val ().first, k.val ().second); + } + + fclose (fp); +#endif + } +} + +void +convert_knot_sq () +{ + FILE *fp = open_file ("L14.files", "r"); + char buf[1000]; + + gzfile_writer w ("L14_sq.dat.gz"); + w.write_unsigned (76516); + + set keys; + while (fgets (buf, 1000, fp)) + { + char *p = strchr (buf, '\n'); + if (p) + { + assert (p[1] == 0); + *p = 0; + } + + map, mod_map > > knot_sq; + load (knot_sq, buf); + + for (map, mod_map > >::const_iter k = knot_sq; k; k ++) + { + write (w, k.key ()); + write (w, k.val ()); + } + } + + // write (w, knot_sq); +} + +#if 0 +void +test_knot_sq () +{ + const char *knot_sq_files[] = { + "knot_sq/rolfsen_sq.dat.gz", + "knot_sq/Ksmall_sq.dat.gz", + "knot_sq/K11_sq.dat.gz", + "knot_sq/K12_sq.dat.gz", + "knot_sq/Lsmall_sq.dat.gz", + "knot_sq/L11_sq.dat.gz", + "knot_sq/L12_sq.dat.gz", + 0, + }; + + for (unsigned i = 0; knot_sq_files[i] != 0; i ++) + { + gzfile_reader r (knot_sq_files[i]); + map, mod_map > > knot_sq (r); + printf ("|knot_sq| = %d\n", knot_sq.card ()); + } +} + +pair, mod_map > +compute_kh_sq (const knot_desc &desc) +{ + abort (); +} +#endif + +template pair >, mod_map > +FU_complex (ptr > CF, + mod_map dF, + mod_map dU) +{ + unsigned n = CF->dim (); + + basedvector hq (n * 2); + for (unsigned i = 1; i <= n; i ++) + hq[i] = hq[n + i] = CF->generator_grading (i); + + ptr > CFU = new explicit_module (2 * n, + basedvector (), + hq); + map_builder b (CFU); + for (unsigned i = 1; i <= n; i ++) + { + for (linear_combination_const_iter j = dF[i]; j; j ++) + { + b[i].muladd (j.val (), j.key ()); + b[n + i].muladd (j.val (), n + j.key ()); + } + for (linear_combination_const_iter j = dU[i]; j; j ++) + { + b[i].muladd (j.val (), n + j.key ()); + } + } + mod_map dFU (b); + // assert (dFU.compose (dFU) == 0); + // dFU.check_sseq_graded (); + return pair >, mod_map > (CFU, dFU); +} + +void +compute_twistedU () { #if 0 + for (unsigned i = 1; i <= 11; i ++) + for (unsigned j = 1; j <= htw_knots (i, 0); j ++) + { + knot_diagram kd (htw_knot (i, 0, j)); + ...} +#endif + for (unsigned i = 1; i <= 10; i ++) + for (unsigned j = 1; j <= mt_links (i, 0); j ++) + { + knot_diagram kd (mt_link (i, 0, j)); + + kd.marked_edge = 1; + show (kd); newline (); + + typedef spanning_tree_complex::R R; + + spanning_tree_complex c (kd); + ptr > C = c.C; + + mod_map d2 = c.twisted_d2 (); + assert (d2.compose (d2) == 0); + + mod_map d2U = c.twisted_d2Un (1); + assert (d2.compose (d2U) == d2U.compose (d2)); + + chain_complex_simplifier s (C, d2, 2); + assert (s.new_d == 0); + printf ("|s.new_C| = %d\n", s.new_C->dim ()); + + pair >, mod_map > p = FU_complex (C, d2, d2U); + ptr > CFU = p.first; + mod_map dFU = p.second; + + chain_complex_simplifier s2 (CFU, dFU, 2); + assert (s2.new_d == 0); + printf ("|s2.new_C| = %d\n", s2.new_C->dim ()); + + if (s2.new_C->dim () < 2 * s.new_C->dim ()) + printf (" > EXAMPLE\n"); + } +} + + +void +test_forgetful_ss () +{ + typedef fraction_field > R; + + for (unsigned i = 1; i <= 12; i ++) + for (unsigned j = 1; j <= mt_links (i, 0); j ++) + { + knot_diagram kd (mt_link (i, 0, j)); + unsigned n = kd.num_components (); + if (n < 2) + continue; + + 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])); + } + + printf ("%d components:\n", n); + + map 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); + + printf (" kd w: %d\n", kd.writhe ()); + + multivariate_laurentpoly disj_P = 1; + for (unsigned k = 1; k <= n; k ++) + { + knot_diagram comp (SUBLINK, smallbitset (n, unsigned_2pow (k - 1)), kd); + + unsigned w = 0; + for (unsigned i = 1; i <= kd.n_crossings; i ++) + { + if (root_comp(u.find (kd.ept_edge (kd.crossings[i][1]))) == k + && root_comp(u.find (kd.ept_edge (kd.crossings[i][2]))) == k) + { + if (kd.is_to_ept (kd.crossings[i][1]) == kd.is_to_ept (kd.crossings[i][4])) + w ++; + else + w --; + } + } + + printf (" % 2d w: %d\n", k, w); + + cube c (comp); + mod_map d = c.compute_d (1, 0, 0, 0, 0); + + chain_complex_simplifier s (c.khC, d, 1); + assert (s.new_d == 0); + + multivariate_laurentpoly P = s.new_C->free_ell_poincare_polynomial (); + printf (" % 2d P: ", k); + display (P); + + disj_P *= (P + * multivariate_laurentpoly (1, VARIABLE, 1, w) + ); + } + + cube 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 untwisted_d = c.compute_d (1, 0, 0, 0, 0); + assert (untwisted_d.compose (untwisted_d) == 0); + + chain_complex_simplifier s1 (c.khC, untwisted_d, 1); + assert (s1.new_d == 0); + + multivariate_laurentpoly P1 = s1.new_C->free_ell_poincare_polynomial (); + display (" link P : ", P1); + + display (" disj_P (adj): ", disj_P); + + mod_map d = untwisted_d; + for (unsigned x = 1; x <= kd.n_crossings; x ++) + { + unsigned r1 = u.find (kd.ept_edge (kd.crossings[x][1])), + r2 = u.find (kd.ept_edge (kd.crossings[x][2])); + + d = d + c.compute_dinv (x)*(R (polynomial (1, root_comp(r1))) + 1); + d = d + c.compute_dinv (x)*(R (polynomial (1, root_comp(r2))) + 1); + +#if 0 + R hbar (polynomial (1, 1)); + R hbarp1 = hbar + 1; + + // if (u.find (kd.ept_edge (kd.crossings[x][1])) != u.find (kd.ept_edge (kd.crossings[x][2]))) + + if (u.find (kd.ept_edge (kd.crossings[x][1])) != comp1_root) + d = d + c.compute_dinv (x)*hbarp1; + + if (u.find (kd.ept_edge (kd.crossings[x][2])) != comp1_root) + d = d + c.compute_dinv (x)*hbarp1; +#endif + } + +#if 0 + mod_map h = d.compose (d); + display ("h:\n", h); +#endif + + assert (d.compose (d) == 0); + + // display ("d:\n", d); + + chain_complex_simplifier s2 (c.khC, d, -1); + assert (s2.new_d == 0); + + multivariate_laurentpoly P2 = (s2.new_C->free_ell_poincare_polynomial () + * multivariate_laurentpoly (1, VARIABLE, 1, kd.writhe ()) + ); + display (" Einf P (adj): ", P2); + + if (disj_P == P2) + printf (" disj_P == Einf P (adj): YES!\n"); + else + printf (" disj_P != Einf P (adj): NO :-(!\n"); + fflush (stdout); + } +} + +void +compute_forgetful_torsion () +{ + typedef polynomial > R; + + for (unsigned i = 1; i <= 12; i ++) + for (unsigned j = 1; j <= mt_links (i, 0); j ++) + { + knot_diagram kd (mt_link (i, 0, j)); + unsigned n = kd.num_components (); + if (n != 2) + continue; + + 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 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); + + cube 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 untwisted_d = c.compute_d (1, 0, 0, 0, 0); + assert (untwisted_d.compose (untwisted_d) == 0); + + mod_map d = untwisted_d; + for (unsigned x = 1; x <= kd.n_crossings; x ++) + { + unsigned r1 = u.find (kd.ept_edge (kd.crossings[x][1])), + r2 = u.find (kd.ept_edge (kd.crossings[x][2])); + + if (r1 != r2) + d = d + c.compute_dinv (x)*(R (1, 1)); + } + +#if 0 + mod_map h = d.compose (d); + display ("h:\n", h); +#endif + + assert (d.compose (d) == 0); + + // display ("d:\n", d); + + chain_complex_simplifier s (c.khC, d, 0); + printf ("|s.new_C| = %d\n", s.new_C->dim ()); + display ("s.new_d:\n", s.new_d); + +#if 0 + ptr > ker = s.new_d.kernel (); + printf ("|ker| = %d\n", ker->dim ()); + + ptr > im = s.new_d.image (); + printf ("|im| = %d\n", im->dim ()); +#endif + + ptr > H = s.new_d.homology (); + display ("H:\n", *H); + // printf ("dim H = %d, free rank H = %d\n", H->dim (), H->free_rank ()); + } +} + +void +test_forgetful_signs () +{ + typedef Q R; + +#if 1 + for (unsigned i = 1; i <= 14; i ++) + for (unsigned j = 1; j <= mt_links (i, 1); j ++) + { + knot_diagram kd (mt_link (i, 1, j)); +#endif +#if 0 + for (unsigned i = 2; i <= 16; i ++) + for (unsigned j = i; j <= 16; j ++) + { + knot_diagram kd (torus_knot (i, j)); + assert (kd.n_crossings == (i - 1) * j + && kd.n_crossings <= i * (j - 1)); + if (kd.n_crossings > 13) + continue; + } +#endif + + unsigned n = kd.num_components (); + if (n < 2) + continue; + assert (n < 97); + + 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 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 comp_weight (n); + for (unsigned i = 1; i <= n; i ++) + comp_weight[i] = R ((int)i); + + map crossing_over_sign; + + // crossings + set pending; + set 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 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 untwisted_d = c.compute_d (1, 0, 0, 0, 0); + assert (untwisted_d.compose (untwisted_d) == 0); + + mod_map 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 h = d.compose (d); + // display ("h:\n", h); + + assert (d.compose (d) == 0); + + ptr > Ek = c.khC; + mod_map dk = d; + + unsigned kinf; + for (int dq = 0;; dq -= 2) + { + chain_complex_simplifier s (Ek, dk, dq); + Ek = s.new_C; + dk = s.new_d; + + 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 ("kinf = %d, trivial bound = %d (total_lk = %d)\n", + kinf, trivial_bound, total_lk); + + if (trivial_bound < kinf) + printf (" > BETTER\n"); + } +} + +template sseq +compute_forgetfulss (knot_diagram &kd, + basedvector 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 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 crossing_over_sign; + + // crossings + set pending; + set 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); + + cube 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 untwisted_d = c.compute_d (1, 0, 0, 0, 0); + assert (untwisted_d.compose (untwisted_d) == 0); + + mod_map 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); + + ptr > C = c.khC; + // d + + int minh = 1000, + maxh = -1000, + minq = 1000, + maxq = -1000; + + for (unsigned i = 1; i <= C->dim (); i ++) + { + grading hq = 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 bounds (minh, maxh, minq, maxq); + + basedvector pages; + + for (unsigned dq = 0;;) + { + chain_complex_simplifier s (C, d, dq); + C = s.new_C; + d = s.new_d; + + dq -= 2; + + sseq_page pg (bounds); + for (unsigned i = 1; i <= C->dim (); i ++) + { + grading hq = C->generator_grading (i); + pg.rank[hq.h - bounds.minh][hq.q - bounds.minq] ++; + } + pages.append (pg); + +#if 0 + mod_map dk = d.graded_piece (grading (dq + 1, dq)); + dk.check_grading (grading (dq + 1, dq)); + + ptr > dk_im = dk.image (); + for (unsigned i = 1; i <= dk_im->dim (); i ++) + { + grading hq = dk_im->generator_grading (i); + pg.im_rank[hq.h - bounds.minh][hq.q - bounds.minq] ++; + } +#endif + +#if 0 + printf ("E_%d: ", (-dq) / 2); + display (C->free_poincare_polynomial ()); +#endif + + if (d == 0) + break; + } + + abort (); + // ??? + return sseq (bounds, grading (0, 0), grading (0, 0), pages); +} + +void +compute_lee_bound () +{ + typedef Z2 R; + +#if 0 + for (unsigned i = 2; i <= 16; i ++) + for (unsigned j = i; j <= 16; j ++) + { + knot_diagram kd (torus_knot (i, j)); + assert (kd.n_crossings == (i - 1) * j + && kd.n_crossings <= i * (j - 1)); + if (kd.n_crossings > 13) + continue; + } +#endif +#if 1 for (unsigned i = 1; i <= 10; i ++) for (unsigned j = 1; j <= rolfsen_crossing_knots (i); j ++) { knot_diagram kd (rolfsen_knot (i, j)); #endif + + show (kd); newline (); + + cube 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 d = c.compute_d (1, 0, 0, 0, 0); + assert (d.compose (d) == 0); + + for (unsigned x = 1; x <= kd.n_crossings; x ++) + d = d + c.H_i (x); + + assert (d.compose (d) == 0); + + ptr > Ek = c.khC; + mod_map dk = d; + + unsigned kinf; + for (int dq = 0;; dq += 2) + { + chain_complex_simplifier s (Ek, dk, dq); + Ek = s.new_C; + dk = s.new_d; + + printf ("|E%d| = %d\n", (dq / 2) + 1, Ek->dim ()); + if (dk == 0) + { + kinf = (dq / 2); + break; + } + } + + printf ("kinf = %d\n", kinf); + } +} + +void +test_crossing_ss () +{ + typedef multivariate_laurentpoly R; + + for (unsigned i = 1; i <= 14; i ++) + for (unsigned j = 1; j <= htw_knots (i); j ++) + { + knot_diagram kd (htw_knot (i, j)); + show (kd); newline (); + + cube 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 untwisted_d = c.compute_d (1, 0, 0, 0, 0); + assert (untwisted_d.compose (untwisted_d) == 0); + + mod_map d = untwisted_d; + for (unsigned x = 1; x <= kd.n_crossings; x ++) + { + d = d + c.compute_dinv (x)*(R (1, VARIABLE, x)); + } + + display ("d:\n", d); + + mod_map h = d.compose (d); + display ("h:\n", h); + } +} + +/* Kh homotopy type: + - check for CP^2, + - mutation invariance + - K-theory */ + +map > +compute_st (mod_map sq1, + mod_map sq2) +{ + ptr > H = sq1.domain (); + + map > st; + + bool first = 1; + set gs = H->gradings (); + for (set_const_iter gg = gs; gg; gg ++) + { + grading hq = gg.val (), + h1q (hq.h + 1, hq.q), + h2q (hq.h + 2, hq.q); + + ptr > H_hq = H->graded_piece (hq), + H_h1q = H->graded_piece (h1q), + H_h2q = H->graded_piece (h2q); + + mod_map S = sq2.restrict (H_hq, H_h2q), + A = sq1.restrict (H_hq, H_h1q), + B = sq1.restrict (H_h1q, H_h2q); + + ptr > S_im = S.image (), + A_ker = A.kernel (), + B_im = B.image (); + ptr > inter = S_im->intersection (B_im); + + mod_map S_res = S.restrict_from (A_ker); + ptr > S_res_im = S_res.image (); + + ptr > res_inter = S_res_im->intersection (B_im); + + int r1 = S_im->dim (); + int r2 = S_res_im->dim (); + int r3 = inter->dim (); + int r4 = res_inter->dim (); + + int s1 = r2 - r4, + s2 = r1 - r2 - r3 + r4, + s3 = r4, + s4 = r3 - r4; + + if (!s1 && !s2 && !s3 && !s4) + continue; + + basedvector s (4); + s[1] = s1; + s[2] = s2; + s[3] = s3; + s[4] = s4; + + st.push (hq, s); + } + + return st; +} + +void +display_st (map > st) +{ + bool first = 1; + for (map_const_iter > i = st; i; i ++) + { + grading hq = i.key (); + int s1 = i.val ()[1], + s2 = i.val ()[2], + s3 = i.val ()[3], + s4 = i.val ()[4]; + if (s1 == 0 && s2 == 0 && s3 == 0 && s4 == 0) + continue; + if (first) + first = 0; + else + printf (","); + printf ("$(%d, %d) \\mapsto (%d, %d, %d, %d)$", hq.h, hq.q, s1, s2, s3, s4); + } + newline (); +} + +void +test_kh_htt_stronger () +{ + map, + multivariate_laurentpoly >, + pair > > > P_sq1_knot_st; + + const char *knot_sq_files[] = { + "knot_sq/rolfsen_sq.dat.gz", + "knot_sq/Ksmall_sq.dat.gz", + "knot_sq/K11_sq.dat.gz", + "knot_sq/K12_sq.dat.gz", + "knot_sq/K13_sq.dat.gz", + "knot_sq/K14_sq.dat.gz", + "knot_sq/Lsmall_sq.dat.gz", + "knot_sq/L11_sq.dat.gz", + "knot_sq/L12_sq.dat.gz", + "knot_sq/L13_sq.dat.gz", + "knot_sq/L14_sq.dat.gz", + 0, + }; + + for (unsigned i = 0; knot_sq_files[i]; i ++) + { + gzfile_reader r (knot_sq_files[i]); + + printf ("loading %s...\n", knot_sq_files[i]); + + unsigned n = r.read_unsigned (); + for (unsigned i = 1; i <= n; i ++) + { + knot_desc desc (r); + pair, mod_map > p1 (r); + + if (desc.t == knot_desc::MT + || desc.t == knot_desc::MT_ALT + || desc.t == knot_desc::MT_NONALT) + { + knot_diagram kd = desc.diagram (); + if (kd.num_components () == 1) + continue; + } + + mod_map sq1 = p1.first, + sq2 = p1.second; + ptr > H = sq1.domain (); + multivariate_laurentpoly P = H->free_poincare_polynomial (); + + unsigned hwidth = homological_width (H); + + map > st + = compute_st (sq1, sq2); + + ptr > sq1_im = sq1.image (); + multivariate_laurentpoly sq1_im_P = sq1_im->free_poincare_polynomial (); + + pair > > &, + bool> p2 = P_sq1_knot_st.find (pair, + multivariate_laurentpoly > (P, sq1_im_P)); + if (p2.second) + { + if (p2.first.second != st) + { + printf ("DIFFER:\n"); + printf ("hwidth = %d\n", hwidth); + + show (p2.first.first); + display_st (p2.first.second); + + show (desc); + display_st (st); + + printf ("Kh["); + planar_diagram (p2.first.first.diagram ()).show_knottheory (); + printf (", Modulus -> Null][q,t] === Kh["); + planar_diagram (desc.diagram ()).show_knottheory (); + printf (", Modulus -> Null][q,t]\n"); + } + } + else + { + p2.first.first = desc; + p2.first.second = st; + } + } + } +} + +void +find_width4_in_h0 () +{ + const char *knot_sq_files[] = { + "knot_sq/rolfsen_sq.dat.gz", + "knot_sq/Ksmall_sq.dat.gz", + "knot_sq/K11_sq.dat.gz", + "knot_sq/K12_sq.dat.gz", + "knot_sq/K13_sq.dat.gz", + "knot_sq/K14_sq.dat.gz", + "knot_sq/K15_sq_part.dat.gz", + 0, + }; + + for (unsigned i = 0; knot_sq_files[i]; i ++) + { + gzfile_reader r (knot_sq_files[i]); + + printf ("loading %s...\n", knot_sq_files[i]); + fflush (stdout); + + unsigned n = r.read_unsigned (); + for (unsigned i = 1; i <= n; i ++) + { + knot_desc desc (r); + // show (desc); newline (); + + pair, mod_map > p (r); + + mod_map sq1 = p.first, + sq2 = p.second; + ptr > H = sq1.domain (); + + int minq = 1000, + maxq = -1000; + + for (unsigned j = 1; j <= H->dim (); j ++) + { + grading hq = H->generator_grading (j); + if (hq.h == 0) + { + if (hq.q < minq) + minq = hq.q; + if (hq.q > maxq) + maxq = hq.q; + } + } + + unsigned h0_width = 0; + if (minq <= maxq) + h0_width = (maxq - minq) / 2 + 1; + + // printf ("h0_width = %d\n", h0_width); + + if (h0_width >= 4) + { + show (desc); newline (); + // printf (" > WIDTH 4!!\n"); + } + } + } +} + +void +test_knot_sq () +{ + const char *knot_sq_files[] = { + "knot_sq/rolfsen_sq.dat.gz", + "knot_sq/Ksmall_sq.dat.gz", + "knot_sq/K11_sq.dat.gz", + "knot_sq/K12_sq.dat.gz", + "knot_sq/K13_sq.dat.gz", + "knot_sq/K14_sq.dat.gz", + "knot_sq/K15_sq_part.dat.gz", + "knot_sq/Lsmall_sq.dat.gz", + "knot_sq/L11_sq.dat.gz", + "knot_sq/L12_sq.dat.gz", + "knot_sq/L13_sq.dat.gz", + "knot_sq/L14_sq.dat.gz", + 0, + }; + + hashset mutants; + for (unsigned i = 11; i <= 15; i ++) + { + basedvector, 1> groups + = mutant_knot_groups (i); + for (unsigned j = 1; j <= groups.size (); j ++) + { + for (unsigned k = 1; k <= groups[j].size (); k ++) + mutants += knot_desc (knot_desc::HTW, i, groups[j][k]); + } + } + printf ("|mutants| = %d\n", mutants.card ()); + fflush (stdout); + + basedvector width_hist (7); + for (unsigned i = 1; i <= width_hist.size (); i ++) + width_hist[i] = 0; + + hashmap, mod_map > > mutant_knot_sq, + mutant_mknot_sq; + + { + gzfile_reader r ("knot_sq/mut_mknot.dat.gz"); + mutant_mknot_sq = hashmap, mod_map > > (r); + + for (hashmap, mod_map > >::const_iter i = mutant_mknot_sq; i; i ++) + { + knot_desc desc = i.key (); + + // careful: duplicate code! + pair, mod_map > p = i.val (); + + mod_map sq1 = p.first, + sq2 = p.second; + ptr > H = sq1.domain (); + + unsigned w = homological_width (H); + assert (w >= 1 && w <= 7); + width_hist[w] ++; + + assert (sq1.compose (sq1) == 0); + assert (sq2.compose (sq2) == sq1.compose (sq2).compose (sq1)); + + map > st + = compute_st (sq1, sq2); + for (map_const_iter > i = st; i; i ++) + { + if (i.val ()[1] != 0) + { + show (desc); newline (); + printf (" > has CP^2\n"); + fflush (stdout); + } + } + } + } + + for (unsigned i = 0; knot_sq_files[i]; i ++) + { + gzfile_reader r (knot_sq_files[i]); + + printf ("loading %s...\n", knot_sq_files[i]); + fflush (stdout); + + unsigned n = r.read_unsigned (); + for (unsigned i = 1; i <= n; i ++) + { + knot_desc desc (r); + + pair, mod_map > p (r); + if (mutants % desc) + mutant_knot_sq.push (desc, p); + + mod_map sq1 = p.first, + sq2 = p.second; + ptr > H = sq1.domain (); + + unsigned w = homological_width (H); + assert (w >= 1 && w <= 7); + width_hist[w] ++; + + assert (sq1.compose (sq1) == 0); + assert (sq2.compose (sq2) == sq1.compose (sq2).compose (sq1)); + + map > st + = compute_st (sq1, sq2); + for (map_const_iter > i = st; i; i ++) + { + if (i.val ()[1] != 0) + { + show (desc); newline (); + printf (" > has CP^2\n"); + fflush (stdout); + } + } + } + } + + printf ("|mutant_knot_sq| = %d\n", mutant_knot_sq.card ()); + printf ("width_hist:\n"); + for (unsigned i = 1; i <= width_hist.size (); i ++) + { + printf (" % 2d: %d\n", i, width_hist[i]); + } + fflush (stdout); + + unsigned missing = 0, + compared = 0; + for (unsigned i = 11; i <= 15; i ++) + { + basedvector, 1> groups + = mutant_knot_groups (i); + + for (unsigned j = 1; j <= groups.size (); j ++) + { + bool first = 1; + + knot_desc desc_1; + ptr > H_1; + map > st_1; + + for (unsigned k = 1; k <= groups[j].size (); k ++) + { + knot_desc desc (knot_desc::HTW, i, groups[j][k]); + + if (mutant_knot_sq % desc) + { + pair, mod_map > p = mutant_knot_sq(desc); + + mod_map sq1 = p.first, + sq2 = p.second; + ptr > H = sq1.domain (); + + map > st = compute_st (sq1, sq2); + + if (first) + { + first = 0; + desc_1 = desc; + H_1 = H; + st_1 = st; + } + else + { + if (H_1->free_poincare_polynomial () + == H->free_poincare_polynomial ()) + { + if (st_1 != st) + { + printf ("> DIFFER\n"); + display (" ", desc_1); + display (" ", desc); + fflush (stdout); + } + compared ++; + } + else if (mutant_mknot_sq % desc) + { + pair, mod_map > mp = mutant_mknot_sq(desc); + + mod_map msq1 = mp.first, + msq2 = mp.second; + ptr > mH = msq1.domain (); + + assert (H_1->free_poincare_polynomial () + == mH->free_poincare_polynomial ()); + + map > mst + = compute_st (msq1, msq2); + + if (st_1 != mst) + { + printf ("> DIFFER\n"); + display (" ", desc_1); + display (" ", desc); + fflush (stdout); + } + compared ++; + } + else + missing ++; + } + } + else + missing ++; + } + } + } + printf ("missing = %d\n", missing); + printf ("compared = %d\n", compared); + fflush (stdout); +} + +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 +bool +file_exists (const char *buf) +{ + struct stat stat_buf; + if (stat (buf, &stat_buf) != 0) + { + if (errno == ENOENT) + return 0; + + stderror ("stat: %s", buf); + exit (EXIT_FAILURE); + } + + return 1; +} + +void +convert_mut15 () +{ + hashmap, mod_map > > knot15_sq_part; + + basedvector, 1> groups = mutant_knot_groups (15); + for (unsigned i = 1; i <= groups.size (); i ++) + { + for (unsigned j = 1; j <= groups[i].size (); j ++) + { + knot_desc desc (knot_desc::HTW, i, groups[i][j]); + + char buf[1000]; + sprintf (buf, "/u/cseed/mut15.bak/K15_%d.dat.gz", groups[i][j]); + + if (file_exists (buf)) + { + gzfile_reader r (buf); + + mod_map sq1 (r); + mod_map sq2 (r); + knot15_sq_part.push (desc, + pair, mod_map > (sq1, sq2)); + } + } + } + + printf ("|knot15_sq_part| = %d\n", knot15_sq_part.card ()); + + gzfile_writer w ("/u/cseed/src/knotkit/knot_sq/K15_sq_part.dat.gz"); + write (w, knot15_sq_part); +} +#endif + +void +compute_mutant_mirrors () +{ + const char *knot_sq_files[] = { + // "knot_sq/K11_sq.dat.gz", + // "knot_sq/K12_sq.dat.gz", + // "knot_sq/K13_sq.dat.gz", + "knot_sq/K14_sq.dat.gz", + 0, + }; + unsigned minn = 14, + maxn = 14; + + hashset mutants; + for (unsigned i = minn; i <= maxn; i ++) + { + basedvector, 1> groups + = mutant_knot_groups (i); + for (unsigned j = 1; j <= groups.size (); j ++) + { + for (unsigned k = 1; k <= groups[j].size (); k ++) + mutants += knot_desc (knot_desc::HTW, i, groups[j][k]); + } + } + printf ("|mutants| = %d\n", mutants.card ()); + fflush (stdout); + + hashmap, mod_map > > mutant_knot_sq; + + for (unsigned i = 0; knot_sq_files[i]; i ++) + { + gzfile_reader r (knot_sq_files[i]); + + printf ("loading %s...\n", knot_sq_files[i]); + fflush (stdout); + + unsigned n = r.read_unsigned (); + for (unsigned i = 1; i <= n; i ++) + { + knot_desc k (r); + + pair, mod_map > p (r); + if (mutants % k) + mutant_knot_sq.push (k, p); + } + } + + printf ("|mutant_knot_sq| = %d\n", mutant_knot_sq.card ()); + fflush (stdout); + + map, mod_map > > mknot_kh_sq; + for (unsigned i = minn; i <= maxn; i ++) + { + basedvector, 1> groups + = mutant_knot_groups (i); + for (unsigned j = 1; j <= groups.size (); j ++) + { + unsigned n = groups[j].size (); + + basedvector >, 1> group_H (n); + for (unsigned k = 1; k <= n; k ++) + { + knot_desc desc (knot_desc::HTW, i, groups[j][k]); + pair, mod_map > p = mutant_knot_sq(desc); + group_H[k] = p.first.domain (); + } + + for (unsigned k = 2; k <= n; k ++) + { + if (group_H[1]->free_poincare_polynomial () + != group_H[k]->free_poincare_polynomial ()) + { + knot_desc desc (knot_desc::HTW, i, groups[j][k]); + show (desc); newline (); + fflush (stdout); + + char buf[1000]; + assert (desc.t == knot_desc::HTW); + sprintf (buf, "mknot/K%d_%d.dat.gz", desc.i, desc.j); + + if (!file_exists (buf)) + { + knot_diagram kd (MIRROR, desc.diagram ()); + + cube c (kd); + mod_map d = c.compute_d (1, 0, 0, 0, 0); + + chain_complex_simplifier s (c.khC, d, 1); + assert (s.new_d == 0); + + steenrod_square sq (c, d, s); + mod_map sq1 = sq.sq1 (); + mod_map sq2 = sq.sq2 (); + + ptr > H = sq1.domain (); + + assert (group_H[1]->free_poincare_polynomial () + == H->free_poincare_polynomial ()); + + gzfile_writer w (buf); + write (w, desc); + write (w, sq1); + write (w, sq2); + } + } + } + } + } +} + +void +convert_mknots () +{ + hashmap, mod_map > > mutant_mknot_sq; + + for (unsigned i = 11; i <= 15; i ++) + { + basedvector, 1> groups + = mutant_knot_groups (i); + for (unsigned j = 1; j <= groups.size (); j ++) + { + unsigned n = groups[j].size (); + for (unsigned k = 1; k <= n; k ++) + { + knot_desc desc (knot_desc::HTW, i, groups[j][k]); + + char buf[1000]; + assert (desc.t == knot_desc::HTW); + sprintf (buf, "mknot/K%d_%d.dat.gz", desc.i, desc.j); + + struct stat stat_buf; + if (stat (buf, &stat_buf) != 0) + { + if (errno != ENOENT) + { + stderror ("stat: %s", buf); + exit (EXIT_FAILURE); + } + } + else + { + printf ("loading %s...\n", buf); + + gzfile_reader r (buf); + + knot_desc desc_2 (r); + assert (desc_2 == desc); + + mod_map sq1 (r); + mod_map sq2 (r); + + mutant_mknot_sq.push (desc, + pair, mod_map > (sq1, sq2)); + } + } + } + } + + gzfile_writer w ("knot_sq/mut_mknot.dat.gz"); + write (w, mutant_mknot_sq); +} + +void +convert_15 () +{ + hashmap, mod_map > > knot15_sq; + + basedvector, 1> groups + = mutant_knot_groups (15); + for (unsigned i = 1; i <= groups.size (); i ++) + { + for (unsigned j = 1; j <= groups[i].size (); j ++) + { + unsigned k = groups[i][j]; + + char buf[1000]; + sprintf (buf, "/u/cseed/mut15.bak/K15_%d.dat.gz", k); + + if (file_exists (buf)) + { + printf ("loading %s...\n", buf); + fflush (stdout); + + gzfile_reader r (buf); + mod_map sq1 (r); + mod_map sq2 (r); + + knot_desc desc (knot_desc::HTW, 15, k); + knot15_sq.push (desc, + pair, mod_map > (sq1, sq2)); + } + } + } + + printf ("|knot15_sq| = %d\n", knot15_sq.card ()); + + gzfile_writer w ("/u/cseed/src/knotkit/K15_sq_part.dat.gz"); + write (w, knot15_sq); +} + +void +compare_gss_splitting () +{ + typedef Z2 R; + +#if 1 + for (unsigned i = 1; i <= 14; i ++) + for (unsigned j = 1; j <= mt_links (i, 1); j ++) + { + knot_diagram kd (mt_link (i, 1, j)); +#endif + + unsigned n = kd.num_components (); + if (n < 2) + continue; + + 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 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); + + cube c (kd); +#if 1 + 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 + + printf ("inter-component x:\n"); + mod_map ds (c.khC); + for (unsigned x = 1; x <= kd.n_crossings; x ++) + { + unsigned p1 = kd.crossings[x][1], + p2 = kd.crossings[x][2]; + 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) + { + printf (" %d\n", x); + + ds = ds + c.compute_dinv (x); + } + } + + mod_map d1 = c.compute_d (1, 0, 0, 0, 0); + assert (d1.compose (ds) == ds.compose (d1)); + + mod_map d2 = c.compute_d (2, 0, 0, 0, 0); + mod_map h2 = d2.compose (ds) + ds.compose (d2); + if (h2 != 0) + display ("h2:\n", h2); + + mod_map d3 = c.compute_d (3, 0, 0, 0, 0); + mod_map h3 = d3.compose (ds) + ds.compose (d3); + if (h3 != 0) + display ("h3:\n", h3); + + mod_map d = c.compute_d (0, 0, 0, 0, 0); + mod_map h = d.compose (ds) + ds.compose (d); + if (h != 0) + display ("h:\n", h); + } +} + +template unsigned +splitting_bound (knot_diagram &kd, + basedvector comp_weight) +{ + sseq ss = compute_forgetfulss (kd, comp_weight); + + assert (ss.pages.size () >= 1); + return ss.pages.size () - 1; +} + +basedvector, 1> +permutations (basedvector v) +{ + unsigned n = v.size (); + basedvector, 1> ps; + + if (n == 1) + { + ps.append (v); + return ps; + } + + for (unsigned i = 1; i <= n; i ++) + { + unsigned x = v[i]; + + basedvector v2 (n - 1); + for (unsigned j = 1; j < i; j ++) + v2[j] = v[j]; + for (unsigned j = i + 1; j <= n; j ++) + v2[j - 1] = v[j]; + + basedvector, 1> ps2 = permutations (v2); + for (unsigned j = 1; j <= ps2.size (); j ++) + { + basedvector p2 = ps2[j]; + assert (p2.size () == n - 1); + + basedvector v3 (n); + v3[1] = x; + for (unsigned k = 1; k <= n - 1; k ++) + v3[k + 1] = p2[k]; + ps.append (v3); + } + } + + return ps; +} + +basedvector, 1> +permutations (unsigned n) +{ + basedvector v (n); + for (unsigned i = 1; i <= n; i ++) + v[i] = i; + return permutations (v); +} + +template multivariate_laurentpoly +Kh_poincare_polynomial (knot_diagram &kd) +{ + cube c (kd); + mod_map d = c.compute_d (1, 0, 0, 0, 0); + chain_complex_simplifier s (c.khC, d, 0); + assert (s.new_d == 0); + return s.new_C->free_poincare_polynomial (); +} + +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 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 P_Lij = Kh_poincare_polynomial (Lij); + + knot_diagram Li_join_Lj (DISJOINT_UNION, + knot_diagram (SUBLINK, ci, kd), + knot_diagram (SUBLINK, cj, kd)); + + multivariate_laurentpoly P_Li_join_Lj = Kh_poincare_polynomial (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 () +{ + typedef fraction_field > Z2x; + for (unsigned i = 1; i <= 12; i ++) + for (unsigned j = 1; j <= mt_links (i); j ++) + { + knot_diagram kd (mt_link (i, j)); + unsigned m = kd.num_components (); + if (m == 1) + continue; + + show (kd); newline (); + printf (" m = %d\n", m); + + 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 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 comp_weightQ (m); + for (unsigned i = 1; i <= m; i ++) + comp_weightQ[i] = Q (i); + unsigned bQ = splitting_bound (kd, comp_weightQ); + + basedvector comp_weightZ2x (m); + for (unsigned i = 1; i <= m; i ++) + comp_weightZ2x[i] = Z2x (polynomial (Z2 (1), i)); + unsigned bZ2x = splitting_bound (kd, comp_weightZ2x); + + // lower bound + unsigned b = std::max (bQ, bZ2x); + + printf (" bQ = %d\n", bQ); + printf (" bZ2x = %d\n", bZ2x); + printf (" b = %d\n", b); + + unsigned total_lk = kd.total_linking_number (); + + unsigned b_lk_weak = compute_b_lk_weak (kd); + unsigned b_lk_weaker = total_lk == 0 ? 2 : total_lk; + + printf (" b_lk_weaker = %d\n", b_lk_weaker); + printf (" b_lk_weak = %d\n", b_lk_weak); + + assert (b_lk_weaker <= b_lk_weak); + if (b_lk_weaker < b_lk_weak) + printf (" > STRICTLY WEAKER\n"); + + basedvector, 1> ps = permutations (m); + unsigned r = kd.n_crossings; + for (unsigned i = 1; i <= ps.size (); i ++) + { + basedvector 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 < r) + r = ri; + } + printf (" r = %d\n", r); + + assert (b_lk_weak <= r); + assert (b <= r); + + // non-trivial link, sp at least 1. + assert (b_lk_weak >= 1); + if (b <= 1 + && b_lk_weak == 1) + continue; + + if (b > b_lk_weak) + { + if (b == r) + printf (" > sp = %d (b)\n", b); + else + printf (" > %d <= sp <= %d (b)\n", b, r); + } + else if (b == b_lk_weak) + { + if (b == r) + printf (" > sp = %d (b + b_lk_weak)\n", b); + else + printf (" > %d <= sp <= %d (b + b_lk_weak)\n", b, r); + } + else if (b_lk_weak == r) + { + assert (b < b_lk_weak); + printf (" > sp = %d (b_lk_weak)\n", b_lk_weak); + } + } +} + + +void +compute_forgetful_tables () +{ + // typedef fraction_field > R; + typedef Z2 R; + +#if 0 + for (unsigned i = 1; i <= 10; i ++) + for (unsigned j = 1; j <= mt_links (i); j ++) + { + knot_diagram kd (mt_link (i, j)); +#endif + { + // knot_diagram kd (mt_link (12, 0, 2087)); + // knot_diagram kd (mt_link (12, 0, 1705)); + // knot_diagram kd (mt_link (14, 0, 66759)); + // knot_diagram kd (mt_link (14, 0, 65798)); + knot_diagram kd (mt_link (13, 0, 8862)); + + abort (); + // sseq ss = compute_forgetfulss (kd); + sseq ss; + +#if 0 + if (ss.pages.size () < 2) + continue; +#endif + + for (unsigned k = 1; k <= ss.pages.size (); k ++) + { + if (k == 1) + printf ("%s &", kd.name.c_str ()); + else + printf (" &"); + + printf (" $E_%d$ & %d & $", k, ss.pages[k].total_rank ()); + + bool first = 1; + + const sseq_bounds &b = ss.bounds; + + for (int i = b.minh; i <= b.maxh; i ++) + for (int j = b.minq; j <= b.maxq; j ++) + { + unsigned r = ss.pages[k].rank[i - b.minh][j - b.minq]; + + if (r > 0) + { + + if (first) + first = 0; + else + printf (" + "); + + if (i == 0 + && j == 0) + printf ("%d", r); + else + { + if (r != 1) + printf ("%d", r); + + if (i != 0) + printf ("t^{%d}", i); + if (j != 0) + printf ("q^{%d}", j); + } + } + } + printf ("$ \\\\\n"); + } + } +} + +void +show_lk (const dt_code &dt) +{ + knot_diagram kd (dt); + + show (kd); newline (); + printf ("m = %d\n", kd.num_components ()); + + planar_diagram (kd).display_knottheory (); +} + +int +main () +{ + show_lk (mt_link (11, 1, 739)); + show_lk (mt_link (12, 1, 2521)); + show_lk (mt_link (12, 1, 2552)); + show_lk (mt_link (12, 1, 2672)); + show_lk (mt_link (12, 1, 2910)); + + show_lk (mt_link (12, 0, 2207)); + show_lk (mt_link (12, 0, 2209)); + show_lk (mt_link (12, 0, 2211)); + show_lk (mt_link (12, 0, 2214)); + show_lk (mt_link (12, 0, 2208)); + show_lk (mt_link (12, 0, 2230)); + show_lk (mt_link (12, 0, 2238)); + show_lk (mt_link (12, 0, 2245)); + show_lk (mt_link (12, 0, 2251)); + show_lk (mt_link (12, 0, 2255)); + show_lk (mt_link (12, 0, 2262)); + show_lk (mt_link (12, 0, 2292)); + return 0; + + { + knot_diagram kd (mt_link (12, 0, 2262)); + printf ("m = %d\n", kd.num_components ()); + + planar_diagram (kd).display_knottheory (); + } + return 0; + + compute_splitting_bounds (); + return 0; + + compute_forgetful_tables (); + return 0; + +#if 0 + { + knot_diagram kd (mt_link (5, 1, 3)); + show (kd); newline (); + + sseq ss = compute_forgetfulss (kd); + ss.texshow (stdout, "L5a3"); + } + return 0; +#endif + + compute_lee_bound (); + return 0; + + compare_gss_splitting (); + + { + knot_diagram kd (rolfsen_knot (3, 1)); + cube c (kd); + mod_map d = c.compute_d (1, 0, 0, 0, 0); + chain_complex_simplifier s (c.khC, d, 0); + assert (s.new_d == 0); + display ("s.new_C:\n", *s.new_C); + } + return 0; + + test_forgetful_signs (); + + { + knot_diagram kd (torus_knot (2, 2)); + printf ("n+ = %d, n- = %d\n", kd.nplus, kd.nminus); + cube c (kd); + sseq ss = compute_szabo_sseq (c); + ss.texshow (stdout, "Hopf"); + } + { + knot_diagram kd (MIRROR, knot_diagram (torus_knot (2, 2))); + printf ("n+ = %d, n- = %d\n", kd.nplus, kd.nminus); + cube c (kd); + sseq ss = compute_szabo_sseq (c); + ss.texshow (stdout, "Hopf"); + } + + return 0; + + compute_forgetful_torsion (); + return 0; + + test_forgetful_signs (); + test_crossing_ss (); + + find_width4_in_h0 (); + // convert_15 (); + // test_knot_sq (); + return 0; + + // convert_mut15 (); + + compute_mutant_mirrors (); + + test_kh_htt_stronger (); + + compute_mutant_mirrors (); + + test_knot_sq (); + + convert_mknots (); + + test_forgetful_ss (); + compute_twistedU (); + +#if 1 + knot_desc desc; + desc.t = knot_desc::HTW; + desc.i = 15; + desc.j = 15020; + + char buf[1000]; + sprintf (buf, "/scratch/network/cseed/incoming/K%d_%d.dat.gz", + desc.i, desc.j); + + desc = knot_desc (knot_desc::ROLFSEN, 3, 1); + + knot_diagram kd = desc.diagram (); + + cube c (kd); + mod_map d = c.compute_d (1, 0, 0, 0, 0); + + chain_complex_simplifier s (c.khC, d, 1); + assert (s.new_d == 0); + + steenrod_square sq (c, d, s); + mod_map sq1 = sq.sq1 (); + mod_map sq2 = sq.sq2 (); + + assert (sq1.compose (sq1) == 0); + assert (sq2.compose (sq2) + sq1.compose (sq2).compose (sq1) == 0); + +#if 1 + { + file_writer w (buf); + write (w, sq1); + write (w, sq2); + } +#endif +#endif + return 0; + + // convert_knot_sq (); + test_knot_sq (); + + // test_sage_show (); + dump_sage (); + +#if 0 + knot_diagram kd (rolfsen_knot (8, 19)); + show (kd); newline (); + + cube c (kd); + mod_map d = c.compute_d (1, 0, 0, 0, 0); + + chain_complex_simplifier s (c.khC, d, 1); + + steenrod_square sq (c, d, s); + mod_map sq1 = sq.sq1 (); + mod_map sq2 = sq.sq2 (); + + assert (sq1.compose (sq1) == 0); + assert (sq2.compose (sq2) + sq1.compose (sq2).compose (sq1) == 0); + + display ("sq1:\n", sq1); + display ("sq2:\n", sq2); + + { + file_writer w ("sqtest.dat"); + write (w, sq1); + write (w, sq2); + } + + { + file_reader r ("sqtest.dat"); + mod_map sq1p (r); + mod_map sq2p (r); + display ("sq1p:\n", sq1p); + display ("sq2p:\n", sq2p); + } + +#endif + +#if 0 + knot_diagram kd (mt_link (10, 0, 9)); + cube c (kd); +#endif + +#if 0 + for (unsigned i = 1; i <= 10; i ++) + for (unsigned j = 1; j <= mt_links (i, 0); j ++) + { + knot_diagram kd (mt_link (i, 0, j)); + kd.marked_edge = 1; + + cube c (kd, 1); + sseq ss = compute_szabo_sseq (c); + ss.texshow (stdout, kd.name); + } +#endif + +#if 0 +#if 1 + for (unsigned i = 10; i <= 10; i ++) + for (unsigned j = 124; j <= rolfsen_crossing_knots (i); j ++) + { + knot_diagram kd (rolfsen_knot (i, j)); +#endif +#if 0 + for (unsigned i = 1; i <= 10; i ++) + for (unsigned j = 1; j <= mt_links (i, 0); j ++) + { +#endif +#if 0 + for (unsigned i = 11; i <= 11; i ++) + for (unsigned j = 1; j <= htw_knots (i, 0); j ++) + { +#endif + // knot_diagram kd (htw_knot (i, 0, j)); + // knot_diagram kd (mt_link (i, 0, j)); + kd.marked_edge = 1; + + show (kd); newline (); + + cube c (kd, 1); + +#if 0 + mod_map d1 = c.compute_d (1, 0, 0, 0, 0); + + chain_complex_simplifier s (c.khC, d1, 1); + assert (s.new_d == 0); +#endif + + sseq ss = compute_szabo_sseq (c); + + multivariate_laurentpoly Phat = + ss.pages[ss.pages.size ()].delta_poincare_polynomial (ss.bounds); + + typedef spanning_tree_complex::R R; + + spanning_tree_complex spanc (kd); + mod_map d2 = spanc.twisted_d2 (); + mod_map d2U = spanc.twisted_d2Un (1); + + chain_complex_simplifier s2 (spanc.C, d2, 2); + assert (s2.new_d == 0); + + mod_map H_d2U = s2.pi.compose (d2U).compose (s2.iota); + assert (H_d2U.compose (H_d2U) == 0); + + ptr > ker = H_d2U.kernel (); + ptr > quot = s2.new_C->quotient (H_d2U.image ()); + + multivariate_laurentpoly Pminus1 + = ker->free_delta_poincare_polynomial (), + PminusU = quot->free_delta_poincare_polynomial (); + + if (PminusU != Pminus1) + { + display (" HFhat: ", Phat); + // display (" HF-: ", Pminus); + display (" HF- (1): ", Pminus1); + display (" HF- (U): ", PminusU); + } + } +#endif + +#if 0 + hwidth_knots = basedvector (10); + for (unsigned i = 1; i <= hwidth_knots.size (); i ++) + hwidth_knots[i] = 0; + + map, mod_map > > knot_kh_sq; + + for (unsigned i = 14; i >= 1; i --) + { +#if 0 + if (i <= 10) + { + for (unsigned j = 1; j <= rolfsen_crossing_knots (i); j += block_size) + { + load (knot_kh_sq, knot_desc (knot_desc::ROLFSEN, i, j)); + } + } +#endif + + for (unsigned j = 1; j <= htw_knots (i); j += block_size) + { + load (knot_kh_sq, knot_desc (knot_desc::HTW, i, j)); + } + + if (i <= 13) + { + for (unsigned j = 1; j <= mt_links (i); j += block_size) + { + load (knot_kh_sq, knot_desc (knot_desc::MT, i, j)); + } + } + + if (i == 14) + { + for (unsigned j = 1; j <= mt_links (14, 0); j += block_size) + { + load (knot_kh_sq, knot_desc (knot_desc::MT, 14, mt_links (14, 1) + j)); + } + } + } + + unsigned total_knots = 0; + printf ("hwidth_knots:\n"); + for (unsigned i = 1; i <= hwidth_knots.size (); i ++) + { + printf (" % 2d: %d\n", i, hwidth_knots[i]); + total_knots += hwidth_knots[i]; + } + printf ("total_knots = %d\n", total_knots); + + printf ("|knot_kh_sq| = %d\n", knot_kh_sq.card ()); + +#if 0 + map, + map >, + pair > > > P_sq1_knot_st; + + set > Ps; + basedvector collisons (10); + for (unsigned i = 1; i <= 10; i ++) + collisons[i] = 0; + + for (map, mod_map > >::const_iter i = knot_kh_sq; i; i ++) + { + show_st (knot_kh_sq, i.key ()); + + mod_map sq1 = i.val ().first; + mod_map sq2 = i.val ().second; + +#if 0 + display ("sq1:\n", sq1); + display ("sq2:\n", sq2); +#endif + + printf ("%s ", i.key ().name ().c_str ()); + + assert (sq1.compose (sq1) == 0); + assert (sq2.compose (sq2) + sq1.compose (sq2).compose (sq1) == 0); + + ptr > H = sq1.domain (); + unsigned hwidth = homological_width (H); + + map > st; + map sq1_ranks; + + bool first = 1; + + set gs = H->gradings (); + + for (set_const_iter gg = gs; gg; gg ++) + { + grading hq = gg.val (), + h1q (hq.h + 1, hq.q), + h2q (hq.h + 2, hq.q), + h3q (hq.h + 3, hq.q); + + // printf ("(%d, %d):\n", hq.h, hq.q); + + ptr > H_hq = H->graded_piece (hq), + H_h1q = H->graded_piece (h1q), + H_h2q = H->graded_piece (h2q), + H_h3q = H->graded_piece (h3q); + + mod_map S = sq2.restrict (H_hq, H_h2q), + T = sq2.restrict (H_h1q, H_h3q), + A = sq1.restrict (H_hq, H_h1q), + B = sq1.restrict (H_h1q, H_h2q), + C = sq1.restrict (H_h2q, H_h3q); + + ptr > Sker = S.kernel (), + Sim = S.image (), + Tker = T.kernel (), + Tim = T.image (), + Aker = A.kernel (), + Aim = A.image (), + Bker = B.kernel (), + Bim = B.image (), + Cker = C.kernel (), + Cim = C.image (); + + sq1_ranks.push (hq, Aim->dim ()); + + mod_map ArSker = A.restrict_from (Sker); + mod_map SrAker = S.restrict_from (Aker); + + mod_map TrAim = T.restrict_from (Aim); + mod_map TrBker = T.restrict_from (Bker); + mod_map BrTker = B.restrict_from (Tker); + + mod_map CrSim = C.restrict_from (Sim); + + ptr > ArSker_im = ArSker.image (); + ptr > SrAker_im = SrAker.image (); + + ptr > TrAim_im = TrAim.image (); + ptr > TrBker_im = TrBker.image (); + ptr > BrTker_im = BrTker.image (); + + ptr > CrSim_im = CrSim.image (); + + mod_map CrSrAker_im = C.restrict_from (SrAker_im); + mod_map TrArSker_im = T.restrict_from (ArSker_im); + + ptr > CrSrAker_im_im = CrSrAker_im.image (); + ptr > TrArSker_im_im = TrArSker_im.image (); + + ptr > Aker_cap_Sker = Aker->intersection (Sker); + + ptr > Aim_cap_Tker = Aim->intersection (Tker); + ptr > Bker_cap_Tker = Bker->intersection (Tker); + ptr > ArSker_im_cap_Tker = ArSker_im->intersection (Tker); + + ptr > Sim_cap_Bim = Sim->intersection (Bim); + ptr > Sim_cap_BrTker_im = Sim->intersection (BrTker_im); + ptr > Sim_cap_Cker = Sim->intersection (Cker); + ptr > SrAker_im_cap_Bim = SrAker_im->intersection (Bim); + ptr > SrAker_im_cap_BrTker_im = SrAker_im->intersection (BrTker_im); + ptr > SrAker_im_cap_Cker = SrAker_im->intersection (Cker); + + ptr > Tim_cap_Cim = Tim->intersection (Cim); + ptr > TrAim_im_cap_Cim = TrAim_im->intersection (Cim); + ptr > TrBker_im_cap_Cim = TrBker_im->intersection (Cim); + ptr > TrArSker_im_im_cap_Cim = TrBker_im->intersection (Cim); + + ptr > Tim_cap_CrSim_im = Tim->intersection (CrSim_im); + ptr > TrAim_im_cap_CrSim_im = TrAim_im->intersection (CrSim_im); + ptr > TrBker_im_cap_CrSim_im = TrBker_im->intersection (CrSim_im); + ptr > TrArSker_im_im_cap_CrSim_im = TrBker_im->intersection (CrSim_im); + + ptr > Tim_cap_CrSrAker_im_im = Tim->intersection (CrSrAker_im_im); + ptr > TrAim_im_cap_CrSrAker_im_im = TrAim_im->intersection (CrSrAker_im_im); + ptr > TrBker_im_cap_CrSrAker_im_im = TrBker_im->intersection (CrSrAker_im_im); + ptr > TrArSker_im_im_cap_CrSrAker_im_im = TrBker_im->intersection (CrSrAker_im_im); + + basedvector v; + + v.append (Sker->dim ()); + v.append (Sim->dim ()); + v.append (Tker->dim ()); + v.append (Tim->dim ()); + + v.append (Aker->dim ()); + v.append (Aim->dim ()); + v.append (Bker->dim ()); + v.append (Bim->dim ()); + v.append (Cker->dim ()); + v.append (Cim->dim ()); + + v.append (ArSker_im->dim ()); + v.append (SrAker_im->dim ()); + + v.append (TrAim_im->dim ()); + v.append (TrBker_im->dim ()); + v.append (BrTker_im->dim ()); + + v.append (CrSim_im->dim ()); + + v.append (CrSrAker_im_im->dim ()); + v.append (TrArSker_im_im->dim ()); + + v.append (Aker_cap_Sker->dim ()); + + v.append (Aim_cap_Tker->dim ()); + v.append (Bker_cap_Tker->dim ()); + v.append (ArSker_im_cap_Tker->dim ()); + + v.append (Sim_cap_Bim->dim ()); + v.append (Sim_cap_BrTker_im->dim ()); + v.append (Sim_cap_Cker->dim ()); + v.append (SrAker_im_cap_Bim->dim ()); + v.append (SrAker_im_cap_BrTker_im->dim ()); + v.append (SrAker_im_cap_Cker->dim ()); + + v.append (Tim_cap_Cim->dim ()); + v.append (TrAim_im_cap_Cim->dim ()); + v.append (TrBker_im_cap_Cim->dim ()); + v.append (TrArSker_im_im_cap_Cim->dim ()); + + v.append (Tim_cap_CrSim_im->dim ()); + v.append (TrAim_im_cap_CrSim_im->dim ()); + v.append (TrBker_im_cap_CrSim_im->dim ()); + v.append (TrArSker_im_im_cap_CrSim_im->dim ()); + + v.append (Tim_cap_CrSim_im->dim ()); + v.append (TrAim_im_cap_CrSim_im->dim ()); + v.append (TrBker_im_cap_CrSim_im->dim ()); + v.append (TrArSker_im_im_cap_CrSim_im->dim ()); + + st.push (hq, v); + } + newline (); + + multivariate_laurentpoly P = H->free_poincare_polynomial (); + pair > > &, + bool> p = P_sq1_knot_st.find (pair, + map > (P, sq1_ranks)); + if (p.second) + { + collisons[hwidth] ++; + Ps += P; + + if (p.first.second != st) + { + printf ("DIFFER:\n"); + printf ("hwidth = %d\n", hwidth); + + show_st (knot_kh_sq, p.first.first); + show_st (knot_kh_sq, i.key ()); + + printf ("Kh["); + planar_diagram (p.first.first.diagram ()).show_knottheory (); + printf (", Modulus -> Null][q,t] === Kh["); + planar_diagram (i.key ().diagram ()).show_knottheory (); + printf (", Modulus -> Null][q,t]\n"); + +#if 0 + printf ("%s:\n", + p.first.first.name ().c_str ()); + for (map >::const_iter j = p.first.second; j; j ++) + { + printf (" (%d, %d) -> [", + j.key ().h, j.key ().q); + for (unsigned k = 1; k <= j.val ().size (); k ++) + { + if (k > 1) + printf (","); + printf ("%d", j.val ()[k]); + } + newline (); + } + printf ("%s:\n", + i.key ().name ().c_str ()); + for (map >::const_iter j = st; j; j ++) + { + printf (" (%d, %d) -> [", + j.key ().h, j.key ().q); + for (unsigned k = 1; k <= j.val ().size (); k ++) + { + if (k > 1) + printf (","); + printf ("%d", j.val ()[k]); + } + newline (); + } +#endif + } + } + else + { + p.first.first = i.key (); + p.first.second = st; + } + } + + printf ("groups = %d\n", Ps.card ()); + printf ("collisons:\n"); + for (unsigned i = 1; i <= 10; i ++) + printf (" % 2d: %d\n", i, collisons[i]); + +#endif +#endif + +#if 0 +#if 0 + reader r ("sqtest.dat"); + + knot_desc kd (knot_desc::ROLFSEN, 8, 19); + mod_map sq1 (r); + mod_map sq2 (r); + + ptr > H = sq1.domain (); + + display ("sq1:\n", sq1); + display ("sq2:\n", sq2); +#endif + + for (unsigned i = 1; i <= 10; i ++) + for (unsigned j = 1; j <= rolfsen_crossing_knots (i); j ++) + { +#if 0 + // (Knot Atlas) L10n18 + int xings[10][4] = { + { 6, 1, 7, 2 }, + { 18, 7, 19, 8 }, + { 4,19,1,20 }, + { 5,12,6,13 }, + { 8,4,9,3 }, + { 13,17,14,16 }, + { 9,15,10,14 }, + { 15,11,16,10 }, + { 11,20,12,5 }, + { 2,18,3,17 }, + }; + knot_diagram kd (planar_diagram ("L10n18", 10, xings)); +#endif + + // (Knot Atlas) L10n102 + int xings[10][4] = { + { 6,1,7,2 }, { 10,3,11,4 }, { 14,7,15,8 }, { 8,13,5,14 }, { 11,18,12,19 }, { 15,20,16,17 }, { 19,16,20,9 }, { 17,12,18,13 }, { 2,5,3,6 }, { 4,9,1,10 }, + }; + knot_diagram kd (planar_diagram ("L10n102", 10, xings)); + + // knot_diagram kd (rolfsen_knot (i, j)); + // knot_diagram kd (mt_link (10, 0, 18)); + + // show (kd); newline (); + printf ("%s ", kd.name.c_str ()); + + cube c (kd); + mod_map d = c.compute_d (1, 0, 0, 0, 0); + + chain_complex_simplifier s (c.khC, d, 1); + + steenrod_square sq (c, d, s); + + mod_map sq1 = sq.sq1 (); + mod_map sq2 = sq.sq2 (); + + assert (sq1.compose (sq1) == 0); + assert (sq2.compose (sq2) + sq1.compose (sq2).compose (sq1) == 0); + + ptr > H = sq1.domain (); + + bool first = 1; + + // ??? + set gs = H->gradings (); + for (set_const_iter i = gs; i; i ++) + { + grading hq = i.val (), + h1q (hq.h + 1, hq.q), + h2q (hq.h + 2, hq.q); + + // printf ("(%d, %d):\n", hq.h, hq.q); + + ptr > H_hq = H->graded_piece (hq), + H_h1q = H->graded_piece (h1q), + H_h2q = H->graded_piece (h2q); + + mod_map whole = sq2.restrict (H_hq, H_h2q), + tail = sq1.restrict (H_hq, H_h1q), + head = sq1.restrict (H_h1q, H_h2q); + + ptr > whole_im = whole.image (), + tail_ker = tail.kernel (), + head_im = head.image (); + ptr > inter = whole_im->intersection (head_im); + + mod_map whole_res = whole.restrict_from (tail_ker); + ptr > whole_res_im = whole_res.image (); + + ptr > res_inter = whole_res_im->intersection (head_im); + + int r1 = whole_im->dim (); + int r2 = whole_res_im->dim (); + int r3 = inter->dim (); + int r4 = res_inter->dim (); + + if (r1 == 0 + && r2 == 0 + && r3 == 0 + && r4 == 0) + continue; + + // printf (" r = (%d, %d, %d, %d)\n", r1, r2, r3, r4); + + int s1 = r2 - r4, + s2 = r1 - r2 - r3 + r4, + s3 = r4, + s4 = r3 - r4; + + if (first) + { +#if 0 + show (kd); + printf (": "); +#endif + first = 0; + } + else + printf (", "); + printf ("(%d, %d) -> (%d, %d, %d, %d)", + hq.h, hq.q, + s1, s2, s3, s4); + } + // if (!first) + newline (); + } +#endif + +#if 0 + // knot_diagram kd (htw_knot (12, 0, 48)); + knot_diagram kd (htw_knot (10, 1, 23)); + show (kd); newline (); +#endif + +#if 0 + for (int a = 1; a >= 0; a --) + for (unsigned i = 1; i <= 9; i ++) + for (unsigned j = 1; j <= htw_knots (i, a); j ++) + { + knot_diagram kd (htw_knot (i, a, j)); + show (kd); newline (); + + cube c (kd); + mod_map d = c.compute_d (1, 0, 0, 0, 0); + + chain_complex_simplifier s (c.khC, d, 1); + + steenrod_square sq (c, d, s); + mod_map sq1 = sq.sq1 (); + // display ("sq1:\n", sq1); + + mod_map sq2 = sq.sq2 (); + if (a) + assert (sq2 == 0); + else + display ("sq2:\n", sq2); + + assert (sq1.compose (sq1) == 0); + assert (sq2.compose (sq2) + sq1.compose (sq2).compose (sq1) == 0); + } +#endif + +#if 0 + typedef Z2 R; + + for (unsigned i = 12; i <= 12; i ++) for (unsigned j = 1; j <= htw_knots (i, 0); j ++) { knot_diagram kd (htw_knot (i, 0, j)); + show (kd); newline (); + cube c (kd); + mod_map d = c.compute_d (1, 0, 0, 0, 0); + + chain_complex_simplifier s (c.khC, d, 1); + // assert (s.new_d == 0); + + printf ("|s.new_C| = %d\n", s.new_C->dim ()); + } +#endif + +#if 0 + map, + set > > kh_knot_map; + + for (int a = 1; a >= 0; a --) + for (unsigned i = 1; i <= 12; i ++) + for (unsigned j = 1; j <= htw_knots (i, a); j ++) + { + knot_diagram kd (htw_knot (i, a, j)); + kd.marked_edge = 1; + show (kd); newline (); + + cube c (kd, 1); + mod_map d = c.compute_d (1, 0, 0, 0, 0); + sseq_builder b (c.khC, d); + sseq ss = b.build_sseq (); + + multivariate_laurentpoly P = ss.pages[1].poincare_polynomial (ss.bounds); + kh_knot_map[P].push (triple (i, a, j)); + } + + { + writer w ("kh_knot_map.dat"); + write (w, kh_knot_map); + } +#endif + +#if 0 + compute_show_kh_sq (knot_desc (knot_desc::ROLFSEN, 8, 19)); + + map, + multivariate_laurentpoly, + multivariate_laurentpoly > > knot_kh_sq; + + for (unsigned i = 1; i <= 10; i ++) + for (unsigned j = 1; j <= rolfsen_crossing_knots (i); j += 4000) + { + load (knot_kh_sq, knot_desc (knot_desc::ROLFSEN, i, j)); + } + + for (unsigned i = 1; i <= 12; i ++) + for (unsigned j = 1; j <= htw_knots (i); j += 4000) + { + load (knot_kh_sq, knot_desc (knot_desc::HTW, i, j)); + } + + for (unsigned i = 1; i <= 13; i ++) + for (unsigned j = 1; j <= mt_links (i); j += 4000) + { + load (knot_kh_sq, knot_desc (knot_desc::MT, i, j)); + } + + map, + triple, + multivariate_laurentpoly > > m; + + multivariate_laurentpoly groups; + + for (map, + multivariate_laurentpoly, + multivariate_laurentpoly > >::const_iter i = knot_kh_sq; i; i ++) + { + multivariate_laurentpoly P = i.val ().first, + P_sq1 = i.val ().second, + P_sq2 = i.val ().third; + + pair, + multivariate_laurentpoly > &, + bool> p = m.find (P); + if (p.second) + { + groups += P; + + if (p.first.second != P_sq1 + || p.first.third != P_sq2) + { + printf ("DIFFER "); + display (P); + + printf (" %s\n", p.first.first.name ().c_str ()); + printf (" sq1 "); display (p.first.second); + printf (" sq2 "); display (p.first.third); + + printf (" %s\n", i.key ().name ().c_str ()); + printf (" sq1 "); display (P_sq1); + printf (" sq2 "); display (P_sq2); + } + } + else + { + p.first.first = i.key (); + p.first.second = P_sq1; + p.first.third = P_sq2; + } + } + + printf ("|groups| = %d\n", groups.card ()); + + printf ("done.\n"); +#endif + +#if 0 + reader r ("kh_knot_map.dat"); + map, + set > > kh_knot_map (r); + + for (map, + set > >::const_iter i = kh_knot_map; i; i ++) + { + if (i.val ().card () == 1) + continue; + + printf ("group\n"); + bool first = 1; + multivariate_laurentpoly P, sq1_P, sq2_P; + + for (set_const_iter > j = i.val (); j; j ++) + { + knot_diagram kd (htw_knot (j.val ().first, + j.val ().second, + j.val ().third)); + printf (" "); show (kd); newline (); + + triple, + multivariate_laurentpoly, + multivariate_laurentpoly > t = square (kd); +#if 0 + display ("t.first = ", t.first); + display ("i.key () = ", i.key ()); + assert (t.first == i.key ()); +#endif + + if (first) + { + P = t.first; + sq1_P = t.second; + sq2_P = t.third; + first = 0; + } + else + { + assert (P == t.first); + if (sq1_P != t.second) + printf (" prev sq1_P != sq1_P\n"); + if (sq2_P != t.third) + printf (" prev sq2_P != sq2_P\n"); + } + } + } +#endif + +#if 0 + typedef Z2 F; + typedef fraction_field > R; + + for (unsigned i = 1; i <= 10; i ++) + for (unsigned j = 1; j <= htw_knots (i, 0); j ++) + { + knot_diagram kd (htw_knot (i, 0, j)); kd.marked_edge = 1; show (kd); newline (); - spanning_tree_complex c (kd); + spanning_tree_complex st (kd); - mod_map > > E2_d = c.twisted_d2 (); - assert (E2_d.compose (E2_d) == 0); - // display ("E2_d:\n", E2_d); + mod_map d2 = st.twisted_d2 (); + assert (d2.compose (d2) == 0); - chain_complex_simplifier > > E2_s (c.C, E2_d, 2); - assert (E2_s.new_d == 0); + mod_map d2U1 = st.twisted_d2Un (1); + // mod_map d2U1 = st.twisted_d2U1_test (); - multivariate_laurentpoly E3_p = E2_s.new_C->free_delta_poincare_polynomial (); - printf ("E3_p = "); show (E3_p); newline (); - - mod_map > > tt_d = c.totally_twisted_kh_d (); - assert (tt_d.compose (tt_d) == 0); - // display ("tt_d:\n", tt_d); + assert (d2.compose (d2U1) + d2U1.compose (d2) == 0); - chain_complex_simplifier > > tt_s (c.C, tt_d, 2); - assert (tt_s.new_d == 0); + mod_map d2U2 = st.twisted_d2Un (2); + assert (d2.compose (d2U2) + d2U2.compose (d2) + d2U1.compose (d2U1) == 0); + + mod_map d2U3 = st.twisted_d2Un (3); + assert (d2.compose (d2U3) + d2U3.compose (d2) + + d2U2.compose (d2U1) + d2U1.compose (d2U2) == 0); - multivariate_laurentpoly tt_p = tt_s.new_C->free_delta_poincare_polynomial (); - printf ("tt_p = "); show (tt_p); newline (); + mod_map d2U4 = st.twisted_d2Un (4); + assert (d2.compose (d2U4) + d2U4.compose (d2) + + d2U3.compose (d2U1) + d2U1.compose (d2U3) + + d2U2.compose (d2U2) == 0); + + mod_map d2U5 = st.twisted_d2Un (5); + assert (d2.compose (d2U5) + d2U5.compose (d2) + + d2U4.compose (d2U1) + d2U1.compose (d2U4) + + d2U3.compose (d2U2) + d2U2.compose (d2U3) == 0); - cube kh_c (kd, 1); - mod_map kh_d = kh_c.compute_d (1, 0, 0, 0, 0); - - sseq_builder builder (kh_c.khC, kh_d); - sseq ss = builder.build_sseq (); - multivariate_laurentpoly kh_p = ss.pages[1].delta_poincare_polynomial (ss.bounds); - printf ("kh_p = "); show (kh_p); newline (); - - if (tt_p != kh_p) - printf (" > tt_p != kh_p!!\n"); - - if (! rank_lte (E3_p, tt_p)) - printf (" > rank E2 > rank tt!!\n"); + mod_map d2U6 = st.twisted_d2Un (6); + assert (d2.compose (d2U6) + d2U6.compose (d2) + + d2U5.compose (d2U1) + d2U1.compose (d2U5) + + d2U4.compose (d2U2) + d2U2.compose (d2U4) + + d2U3.compose (d2U3) == 0); } +#endif } diff --git a/mpi_aux.cpp b/mpi_aux.cpp new file mode 100644 index 0000000..724f4b5 --- /dev/null +++ b/mpi_aux.cpp @@ -0,0 +1,133 @@ + +#include +#include + +// #include + +#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 diff --git a/mpi_aux.h b/mpi_aux.h new file mode 100644 index 0000000..ed80442 --- /dev/null +++ b/mpi_aux.h @@ -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 diff --git a/mpimain.cpp b/mpimain.cpp new file mode 100644 index 0000000..81fefa8 --- /dev/null +++ b/mpimain.cpp @@ -0,0 +1,578 @@ + +#include + +#include +#include + +#define CMD_DO 1 +#define CMD_DIE 2 + +static const int block_size = 100; + +void +master () +{ + basedvector 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, 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 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 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 comp_weight (n); + for (unsigned i = 1; i <= n; i ++) + comp_weight[i] = R ((int)i); + + map crossing_over_sign; + + // crossings + set pending; + set 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 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 untwisted_d = c.compute_d (1, 0, 0, 0, 0); + assert (untwisted_d.compose (untwisted_d) == 0); + + mod_map 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 h = d.compose (d); + // display ("h:\n", h); + + assert (d.compose (d) == 0); + + ptr > Ek = c.khC; + mod_map dk = d; + + basedvector, 1> pages; + + unsigned kinf; + for (int dq = 0;; dq -= 2) + { + chain_complex_simplifier 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 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 P_Lij = Kh_poincare_polynomial (Lij); + + knot_diagram Li_join_Lj (DISJOINT_UNION, + knot_diagram (SUBLINK, ci, kd), + knot_diagram (SUBLINK, cj, kd)); + + multivariate_laurentpoly P_Li_join_Lj = Kh_poincare_polynomial (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 > 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 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 comp_weightQ (m); + for (unsigned i = 1; i <= m; i ++) + comp_weightQ[i] = Q (i); + unsigned bQ = splitting_bound (kd, comp_weightQ); + + basedvector comp_weightZ2x (m); + for (unsigned i = 1; i <= m; i ++) + comp_weightZ2x[i] = Z2x (polynomial (Z2 (1), i)); + unsigned bZ2x = splitting_bound (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, 1> ps = permutations (m); + unsigned upper = kd.n_crossings; + for (unsigned i = 1; i <= ps.size (); i ++) + { + basedvector 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; +} diff --git a/parallel.cmd b/parallel.cmd new file mode 100644 index 0000000..a074876 --- /dev/null +++ b/parallel.cmd @@ -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 diff --git a/planar_diagram.cpp b/planar_diagram.cpp index 1a23554..650d667 100644 --- a/planar_diagram.cpp +++ b/planar_diagram.cpp @@ -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 diff --git a/planar_diagram.h b/planar_diagram.h index cd095df..6c32c3a 100644 --- a/planar_diagram.h +++ b/planar_diagram.h @@ -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; }; diff --git a/rd_parser/rd_scanner.cc b/rd_parser/rd_scanner.cc index 372c166..6f19fc8 100644 --- a/rd_parser/rd_scanner.cc +++ b/rd_parser/rd_scanner.cc @@ -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; } diff --git a/serial.cmd b/serial.cmd new file mode 100644 index 0000000..22b916b --- /dev/null +++ b/serial.cmd @@ -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 diff --git a/simplify_chain_complex.h b/simplify_chain_complex.h new file mode 100644 index 0000000..189e48d --- /dev/null +++ b/simplify_chain_complex.h @@ -0,0 +1,249 @@ + +template class simplified_complex_generators +{ + unsigned new_n; + ptr > C; + basedvector 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 > C_, + basedvector 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 chain_complex_simplifier +{ + public: + ptr > C; + unsigned n; // |C| + mod_map d; + + ptr > new_C; + mod_map new_d; + + // pi : C -> new_C + mod_map pi; + + // iota : new_C -> C + mod_map iota; + + private: + set canceled; + + basedvector cancel_binv; + basedvector cancel_j; + basedvector, 1> cancel_di; + + basedvector, 1> new_d_columns; + basedvector, 1> preim; + + basedvector, 1> iota_columns; + + void cancel (unsigned i, R b, unsigned j); + + public: + chain_complex_simplifier (ptr > C_, + const mod_map &d_, + maybe dh, maybe dq); +}; + +template void +chain_complex_simplifier::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 k = new_d_columns[i]; k; k ++) + preim[k.key ()].yank (i); + for (set_const_iter k = preim[i]; k; k ++) + new_d_columns[k.val ()].yank (i); + for (linear_combination_const_iter k = new_d_columns[j]; k; k ++) + preim[k.key ()].yank (j); + + for (set_const_iter 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 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 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 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 (); + preim[i].clear (); + new_d_columns[j].clear (); + preim[j].clear (); +} + +template +chain_complex_simplifier::chain_complex_simplifier (ptr > C_, + const mod_map &d_, + maybe dh, maybe 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 j = new_d_columns[i]; j; j ++) + preim[j.key ()].push (i); + + linear_combination 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 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 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 > + (simplified_complex_generators (new_n, C, new_C_to_C_generator))); + map_builder db (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_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 (db); + + map_builder 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 (iotab); + + map_builder 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 di = cancel_di.pop (); + + for (linear_combination_const_iter ll = di; ll; ll ++) + { + R c = ll.val (); + pib[j].mulsub (binv * c, pib[ll.key ()]); + } + } + pi = mod_map (pib); + + assert (d.compose (iota) == iota.compose (new_d)); + assert (new_d.compose (pi) == pi.compose (d)); + assert (pi.compose (iota) == mod_map (new_C, 1)); +} diff --git a/spanning_tree_complex.h b/spanning_tree_complex.h index 5a7a091..385a9a0 100644 --- a/spanning_tree_complex.h +++ b/spanning_tree_complex.h @@ -25,6 +25,9 @@ class spanning_tree_complex mod_map totally_twisted_kh_d () const; mod_map twisted_d2 () const; + mod_map twisted_d2Un (unsigned n) const; + + mod_map twisted_d2U1_test () const; }; template @@ -39,7 +42,7 @@ public: tree_generators (const spanning_tree_complex &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::twisted_d2 () const return mod_map (b); } +template mod_map > > +spanning_tree_complex::twisted_d2Un (unsigned n) const +{ + assert (kd.marked_edge); + assert (n >= 1); + + map_builder b (C); + + basedvector 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 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 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 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 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 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 (1, (unsigned)(shift + k*A + l*B))); + x += R (polynomial (1, (unsigned)(shift - k*A - l*B))); + } + else + { + x += R (polynomial (1, (unsigned)(shift - k*A + l*B))); + x += R (polynomial (1, (unsigned)(shift + k*A - l*B))); + } + } + } + + b[i].muladd (x, j); + } + } + } + + return mod_map (b); +} + +template mod_map > > +spanning_tree_complex::twisted_d2U1_test () const +{ + assert (kd.marked_edge); + + map_builder b (C); + + basedvector 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 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 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 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 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 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 (1, (unsigned)(shift + A))); + x += R (polynomial (1, (unsigned)(shift - B))); + } + else + { + x += R (polynomial (1, (unsigned)(shift - A))); + x += R (polynomial (1, (unsigned)(shift + B))); + } + + b[i].muladd (x, j); + } + } + } + + return mod_map (b); +} + template mod_map > > spanning_tree_complex::totally_twisted_kh_d () const { diff --git a/sseq.cpp b/sseq.cpp index 662c8ab..0a1c4aa 100644 --- a/sseq.cpp +++ b/sseq.cpp @@ -2,7 +2,8 @@ #include 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) { diff --git a/sseq.h b/sseq.h index 29fa5a9..85cfd6a 100644 --- a/sseq.h +++ b/sseq.h @@ -7,6 +7,27 @@ class sseq_bounds public: sseq_bounds () { } + + template sseq_bounds (ptr > 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 > rank, im_rank; public: sseq_page () { } sseq_page (const sseq_bounds &b); + template sseq_page (const sseq_bounds &b, + unsigned k_, + grading dk_gr_, + mod_map 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 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 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 &pages_) - : bounds(b), pages(pages_) + sseq (const sseq_bounds &b, + const basedvector &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 void texshow (FILE *fp, M m); }; -template class simplified_complex_generators +template +sseq_page::sseq_page (const sseq_bounds &b, + unsigned k_, + grading dk_gr_, + mod_map dk, + M m) + : k(k_), + dk_gr(dk_gr_), + rank(b.width ()), + im_rank(b.width ()) { - unsigned new_n; - ptr > C; - basedvector 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 > C_, - basedvector 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 chain_complex_simplifier -{ - public: - typedef typename R::linear_combination linear_combination; - typedef typename R::linear_combination_const_iter linear_combination_const_iter; - - public: - ptr > C; - unsigned n; // |C| - const mod_map &d; - - ptr > new_C; - mod_map new_d; - - // chain homotopy equivalences - // pi : C -> new_C, iota : new_C -> C - mod_map pi, iota; - - private: - basedvector new_d0; - basedvector, 1> preim; - - bool build_pi_iota; - mod_map pi0, iota0; - set canceled; - - void cancel (unsigned i, R b, unsigned j); - - public: - chain_complex_simplifier (ptr > C_, - const mod_map &d_, - int dh, - bool build_pi_iota_ = 0); - -}; - -template void -chain_complex_simplifier::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 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 local_pi0 (C, 1), - local_iota0 (C, 1); + vector 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 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 kk = preim[j]; kk; kk ++) + ptr > 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 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 > 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 -chain_complex_simplifier::chain_complex_simplifier (ptr > C_, - const mod_map &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 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 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 (C, 1); - iota0 = mod_map (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 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 > - (simplified_complex_generators (new_n, C, new_C_to_C_generator))); - new_d = mod_map (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 (C, new_C); - iota = mod_map (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); } } diff --git a/steenrod_square.cpp b/steenrod_square.cpp new file mode 100644 index 0000000..7376a69 --- /dev/null +++ b/steenrod_square.cpp @@ -0,0 +1,547 @@ + +#include + +steenrod_square::steenrod_square (const cube &cor_, + mod_map &d_, + const chain_complex_simplifier &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 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 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, // G1cx + map, // bx + map > // sx +steenrod_square::boundary_matching (grading cgr, + linear_combination c, + unsigned x) const +{ + set G1cx; + map bx; + map sx; + + for (linear_combination_const_iter 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 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 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, // G1cx + map, // bx + map > // sx + (G1cx, bx, sx); +} + +mod_map +steenrod_square::sq1 () const +{ + map_builder b (s.new_C); + + for (unsigned i = 1; i <= s.new_C->dim (); i ++) + { + grading cgr = s.new_C->generator_grading (i); + linear_combination c = s.iota[i]; + assert (d.map (c) == 0); + + grading gr2 (cgr.h + 1, cgr.q); + if (! (KGij % gr2)) + continue; + + linear_combination sq1c (cor.khC); + + for (set_const_iter x = KGij[gr2]; x; x ++) + { + triple, + map, + map > t = boundary_matching (cgr, c, x.val ()); + + Z2 a = 0; + for (set_const_iter 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 (b); +} + +set > +steenrod_square::make_G2cx (grading cgr, + linear_combination c, + unsigned x) const +{ + set > G2cx; + + for (linear_combination_const_iter yy = c; yy; yy ++) + { + unsigned y = yy.key (); + + for (linear_combination_const_iter zz = d[y]; zz; zz ++) + { + unsigned z = zz.key (); + + if (d[z](x) == 1) + G2cx.push (pair (z, y)); + } + } + return G2cx; +} + +class graph +{ +public: + unsigned n_vertices; + unsigned n_edges; + + basedvector z; + basedvector y; + map, unsigned> zy_vertex; + + unsigned vertex (unsigned z, unsigned y) const + { + return zy_vertex(pair (z, y)); + } + + basedvector edge_from, edge_to; + set edge_oriented; + basedvector edge_label; + + map > incident_edges; + +public: + graph (set > 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 > G2cx) + : n_vertices(G2cx.card ()), + n_edges(0), + z(n_vertices), + y(n_vertices) +{ + unsigned j = 1; + for (set_const_iter > 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 done; + + set 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, + map > +steenrod_square::ladybug_matching (unsigned x, unsigned y) const +{ + set Gxy; + map lxy; + + for (linear_combination_const_iter 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 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 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, map > (Gxy, lxy); +} + +Z2 +steenrod_square::sq2_coeff (grading cgr, + linear_combination c, + unsigned x) const +{ + set > G2cx = make_G2cx (cgr, c, x); + + graph G (G2cx); + + set ys; + for (unsigned i = 1; i <= G.n_vertices; i ++) + ys += G.y[i]; + + for (set_const_iter yy = ys; yy; yy ++) + { + unsigned y = yy.val (); + + pair, + map > p = ladybug_matching (x, y); + + set Gxy = p.first; + map lxy = p.second; + + for (set_const_iter 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 zs; + for (unsigned i = 1; i <= G.n_vertices; i ++) + zs += G.z[i]; + + for (set_const_iter zz = zs; zz; zz ++) + { + unsigned z = zz.val (); + triple, + map, + map > t = boundary_matching (cgr, c, z); + + set Gcz = t.first; + map bz = t.second; + map sz = t.third; + + for (set_const_iter 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 +steenrod_square::sq2 () const +{ + map_builder b (s.new_C); + + for (unsigned i = 1; i <= s.new_C->dim (); i ++) + { + grading cgr = s.new_C->generator_grading (i); + linear_combination c = s.iota[i]; + assert (d.map (c) == 0); + + grading gr2 (cgr.h + 2, cgr.q); + if (! (KGij % gr2)) + continue; + + linear_combination sq2c (cor.khC); + for (set_const_iter 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 (b); +} diff --git a/steenrod_square.h b/steenrod_square.h new file mode 100644 index 0000000..176c5ce --- /dev/null +++ b/steenrod_square.h @@ -0,0 +1,42 @@ + +class steenrod_square +{ + // cube of resolutions (in steenrod_square, c will denote a cycle) + const cube &cor; + + mod_map d; + const chain_complex_simplifier &s; + + map > 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, // Gxy + map // lxy + > ladybug_matching (unsigned x, unsigned y) const; + + triple, // Gcx + map, // bx + map // sx + > boundary_matching (grading cgr, + linear_combination c, + unsigned x) const; + + set > make_G2cx (grading cgr, + linear_combination c, + unsigned x) const; + Z2 sq2_coeff (grading cgr, + linear_combination c, + unsigned x) const; + + public: + steenrod_square (const cube &cor_, + mod_map &d_, + const chain_complex_simplifier &s_); + ~steenrod_square () { } + + mod_map sq1 () const; + mod_map sq2 () const; +}; diff --git a/todo.txt b/todo.txt index ad38695..bf0f287 100644 --- a/todo.txt +++ b/todo.txt @@ -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 + +fields (F): Z2 Zp Q fraction_field (for just pids?) + +euclidean domains (E): Z polynomial + +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