diff --git a/Makefile b/Makefile index 6be5ece..1738feb 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ BISON = /opt/local/bin/bison FLEX = /opt/local/bin/flex # CXX = g++ +# CXX = mpic++ CXX = clang++ -fno-color-diagnostics --stdlib=libc++ --std=c++11 INCLUDES = -I/opt/local/include -I. @@ -58,6 +59,9 @@ gss: gss.o $(COMMON_OBJS) main: main.o $(COMMON_OBJS) $(CXX) $(LDFLAGS) -o main $^ $(LIBS) +mpimain: mpimain.o mpi_aux.o $(COMMON_OBJS) + $(CXX) $(LDFLAGS) -o main $^ $(LIBS) + testlib: testlib.o $(COMMON_OBJS) $(CXX) $(LDFLAGS) -o testlib $^ @@ -108,4 +112,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 gss.o: $(KNOTKIT_HEADERS) $(ALGEBRA_HEADERS) $(LIB_HEADERS) + +mpimain.o mpi_aux.o: mpi_aux.h diff --git a/knot_tables.cpp b/knot_tables.cpp index 6849294..101c8de 100644 --- a/knot_tables.cpp +++ b/knot_tables.cpp @@ -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) { @@ -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) { @@ -728,3 +748,132 @@ 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]; + 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 bfa33db..63ec89e 100644 --- a/knotkit.h +++ b/knotkit.h @@ -23,6 +23,74 @@ class knot_diagram; #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; + + 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); @@ -33,7 +101,10 @@ 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); 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..8601f0e --- /dev/null +++ b/mpi_aux.h @@ -0,0 +1,20 @@ + +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); + +void send_htw_knot (unsigned n, bool alternating, unsigned k, int dest); + +int recv_int (int *src); +knot_diagram recv_knot (int *src); +std::string recv_string (int *src); + +inline int recv_int () { return recv_int (0); } +knot_diagram recv_knot () { return recv_knot (0); } +std::string recv_string () { return recv_string (0); } diff --git a/mpimain.cpp b/mpimain.cpp new file mode 100644 index 0000000..578c53d --- /dev/null +++ b/mpimain.cpp @@ -0,0 +1,218 @@ + +#include + +#include +#include + +#define CMD_DO 1 +#define CMD_DIE 2 + +void +master () +{ + basedvector work; + + work.append (knot_desc (TORUS, 0, 0)); + + for (int a = 1; a >= 0; a --) + for (unsigned i = 1; i <= 10; i ++) + for (unsigned j = 1; j <= rolfsen_crossing_knots (i); j += 4000) + { + work.append (knot_desc (ROLFSEN, i, j)); + } + + for (int a = 1; a >= 0; a --) + for (unsigned i = 1; i <= 14; i ++) + for (unsigned j = 1; j <= htw_knots (i); j += 4000) + { + work.append (knot_desc (HTW, i, j)); + } + + for (int a = 1; a >= 0; a --) + for (unsigned i = 1; i <= 13; i ++) + for (unsigned j = 1; j <= mt_links (i); j += 4000) + { + work.append (knot_desc (MT, i, j)); + } + + int ntasks = num_tasks (); + + assert (work.size () > ntasks); + + 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); + send_int ((int)desc.i); + send_int ((int)desc.j); + + 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); + send_int ((int)desc.i); + send_int ((int)desc.j); + } + + 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); + } +} + +void +compute_kh_sq (map, + multivariate_laurentpoly, + multivariate_laurentpoly > > &knot_kh_sq, + knot_desc &desc) +{ + knot_diagram kd = desc.diagram (); + + unsigned rank = self_rank (); + + printf ("[% 2d] %s\n", rank, kd.name.c_str ()); + fflush (stdout); + + 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 (); + + knot_kh_sq.push (desc, + triple, + multivariate_laurentpoly, + multivariate_laurentpoly > (P, sq1_P, sq2_P)); +} + +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 = (knot_desc::table)recv_int (); + desc.j = (knot_desc::table)recv_int (); + + map, + multivariate_laurentpoly, + multivariate_laurentpoly > > knot_kh_sq; + + char buf[1000]; + if (desc.t == TORUS) + { + sprintf (buf, "T.dat"); + + for (unsigned t = 3; t <= 16; t ++) // twists + for (unsigned s = 2; s <= t; s ++) // strands + { + if ((s - 1) * t > 16) + continue; + + desc.i = s; + desc.j = t; + + compute_kh_sq (knot_kh_sq, desc); + } + } + else + { + unsigned j0 = desc.j; + + assert (desc.t == knot_desc::HTW || desc.t == knot_desc::MT); + sprintf (buf, "%c%d.dat", + desc.t == knot_desc::HTW ? 'K' : 'L', + j0); + + for (unsigned j = j0; + j <= std::min (j0 + 4000, + desc.table_crossing_knots ()); + j ++) + { + desc.j = j; + + compute_kh_sq (knot_kh_sq, desc); + } + } + + { + writer w (buf); + write (w, kh_knot_map); + } + + 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; +}