#include #include #include #include #include #define E 0 #define N 1 #define W 2 #define S 3 #define SEQDIM 20 #define NUMSQUARESYM 8 typedef short int sequence; /* variabili globali */ static int squaresymv[NUMSQUARESYM][4 + E]; static int squaresymswap[NUMSQUARESYM]; static char chardir[4+E]; //static int numcanonseq = 0; static int verbose = 0; static int debug = 0; static int nocanon = 0; static int seqlen = 8; /* prototipi */ void action (sequence *seq, sequence *dseq, int revert, int rotate, int squaresym); void init_data (void); void printseq (sequence *seq); void printseqinfo (sequence *seq); void readseq (sequence *seq, char *stringa); void canonify (sequence *seq); void firstsequence (sequence *seq); int nextsequence (sequence *seq); int nextsequencerec (sequence *seq, int start); int checkclosed (sequence *seq); int seqcmp (sequence *seq1, sequence *seq2); int storecanon (sequence *seq); int countflaps (sequence *seq); int computelt (sequence *seq); int computedc (sequence *seq); int computearea (sequence *seq, sequence *perm); int countsymmetries (sequence *seq); int nextjuxtaposed (sequence *seq, int first); int arejuxtaposed (sequence *seq, int first, int second); /* not used right now */ void buildpartition (sequence *seq, sequence *perm); int countgrossassemblages (sequence *perm); void firstgrossassemblage (sequence *perm, sequence *assemblage); int nextgrossassemblage (sequence *perm, sequence *assemblage); int nextgrossassemblagerec (sequence *perm, sequence *assemblage, int i); int nextpileperm (sequence *perm, sequence *assemblage, int pile, int lastpile); void printpileperm (sequence *perm, sequence *assemblage, int pile, int lastpile); int checkassemblable (sequence *perm, sequence *assemblage); int iscanonassemblage (sequence *seq, sequence *perm, sequence *assemblage); int computedf (sequence *seq, sequence *perm, sequence *assemblage); void actionassemblage (sequence *seq, sequence *perm, sequence *assemblage, sequence *newassemblage, int revert, int rotate, int squaresym, int swap); int samepile (sequence *perm, int i, int j); int isassemblage (sequence *perm, sequence *assemblage); /* codice */ int main (int argc, char *argv[]) { sequence seq[SEQDIM], cseq[SEQDIM]; int i; int numseq; char *argv0; verbose = 0; argv0 = argv[0]; while (argc >= 2 && *argv[1] == '-') { if (strcmp (argv[1], "-n") == 0) { assert (argc >= 3); seqlen = atoi (argv[2]); assert (seqlen <= SEQDIM); argc -= 2; argv += 2; continue; } if (strcmp (argv[1], "-c") == 0) { nocanon = 1; argc--; argv++; continue; } if (strcmp (argv[1], "-v") == 0) { verbose++; argc--; argv++; continue; } if (strcmp (argv[1], "-d") == 0) { debug++; argc--; argv++; continue; } if (strcmp (argv[1], "-h") == 0) { printf ("%s [-n ][-c][-d] [sequence]\n", argv0); printf (" -n number of tiles (default 8)\n"); printf (" -c do not canonify\n"); printf (" -v increase verbosity\n"); printf (" -d increase debug level\n"); argc--; argv++; exit (0); } } init_data (); if (argc >= 2) { readseq (seq, argv[1]); verbose++; printseqinfo (seq); if (nocanon == 0) { canonify (seq); printseqinfo (seq); } } else { firstsequence (seq); numseq = 0; do { if (!checkclosed (seq)) continue; for (i = 0; i < seqlen; i++) cseq[i] = seq[i]; canonify (cseq); if (seqcmp (seq, cseq) != 0) continue; printseqinfo (seq); numseq++; } while (nextsequence (seq)); fprintf (stderr, "Found %d sequences\n", numseq); /* numseq = findsequences (); verbose = 0; for (i = 0; i < numcanonseq; i++) { printseqinfo (canonseq[i]); } fprintf (stderr, "Found %d sequences\n", numseq); */ } return (0); } void printseqinfo (sequence *seq) { int count, countgross, countassemblable, countcanonassemblages; int countdeltaassemblages; sequence perm[SEQDIM]; sequence assemblage[SEQDIM]; int i, dc; printseq (seq); buildpartition (seq, perm); printf (" f=%d", countflaps (seq)); printf (" area=%d", computearea (seq, perm)); dc = computedc (seq); //printf (" Lt=%d", computelt (seq)); printf (" Dc=%d", dc); printf (" symcount=%d", countsymmetries (seq)); countgross = countgrossassemblages (perm); if (verbose >= 2) printf (" grossassemblages=%d", countgross); firstgrossassemblage (perm, assemblage); count = countassemblable = countcanonassemblages = countdeltaassemblages = 0; do { if (checkassemblable (perm, assemblage)) { countassemblable++; if (iscanonassemblage (seq, perm, assemblage)) { countcanonassemblages++; if (dc + computedf(seq, perm, assemblage) == 0) countdeltaassemblages++; } } count++; } while (nextgrossassemblage (perm, assemblage)); assert (count == countgross); //printf (" assemblables=%d", countassemblable); printf (" assemblages=%d", countcanonassemblages); printf (" deltaiszero=%d", countdeltaassemblages); //if (verbose) //{ // printf (" perm=("); // for (i = 0; i < seqlen; i++) printf ("%d ", perm[i]); // printf (")"); //} printf ("\n"); if (verbose) { firstgrossassemblage (perm, assemblage); do { if (checkassemblable (perm, assemblage) && iscanonassemblage (seq, perm, assemblage)) { if (dc + computedf(seq, perm, assemblage) == 0) { printf (" Assemblage with delta = 0: sla"); for (i = 0; i < seqlen; i++) { printf (" %c", chardir[seq[i]]); printf ("%d", assemblage[i]+1); } printf ("\n"); } } } while (nextgrossassemblage (perm, assemblage)); } } /* * ================================================================== * calcola il contributo al linking number dovuto ai twist */ int computelt (sequence *seq) { int i, diff; int sign, oriz; int lt = 0; for (i = 0; i < seqlen; i++) { sign = 1; if ((i % 2) == 1) sign = -1; diff = seq[i] - seq[(i+1)%seqlen]; if (diff < 0) diff = -diff; if (diff == 1 || diff == 3) continue; // curva oriz = 0; if (seq[i] == E || seq[i] == W) oriz = 1; if (seq[i] == N || seq[i] == S) oriz = -1; assert (oriz != 0); lt -= sign*oriz; } assert (2*(lt/2) == lt); return (lt/2); } /* * ================================================================== * calcola il contributo a Delta dovuto alle curve */ int computedc (sequence *seq) { int i, diff; int curvasx; int sign; int dc = 0; for (i = 0; i < seqlen; i++) { sign = 1; if ((i % 2) == 1) sign = -1; diff = seq[i] - seq[(i+1)%seqlen]; diff += 4; // forse non serve, ma sui negativi non mi fido... assert (diff >= 0); diff = diff % 4; curvasx = 0; if (diff == 1) curvasx = 1; if (diff == 3) curvasx = -1; if (curvasx == 0) continue; dc -= sign*curvasx; } return (dc); } void canonify (sequence *seq) { sequence wseq[SEQDIM]; sequence optseq[SEQDIM]; int i; int revert, rotate, sqsym; for (i = 0; i < seqlen; i++) optseq[i] = seq[i]; for (revert = -1; revert <=1; revert+=2) { for (rotate = 0; rotate < seqlen; rotate++) { for (sqsym = 0; sqsym < NUMSQUARESYM; sqsym++) { // for (i = 0; i < seqlen; i++) wseq[i] = seq[i]; action (seq, wseq, revert, rotate, sqsym); if (seqcmp (wseq, optseq) < 0) { for (i = 0; i < seqlen; i++) optseq[i] = wseq[i]; } } } } for (i = 0; i < seqlen; i++) seq[i] = optseq[i]; } int countsymmetries (sequence *seq) { sequence wseq[SEQDIM]; int count = 0; int revert, rotate, sqsym; for (revert = -1; revert <=1; revert+=2) { for (rotate = 0; rotate < seqlen; rotate++) { for (sqsym = 0; sqsym < NUMSQUARESYM; sqsym++) { action (seq, wseq, revert, rotate, sqsym); if (seqcmp (wseq, seq) == 0) count++; } } } return (count); } void buildpartition (sequence *seq, sequence *perm) { int i, delta; for (i = 0; i < seqlen; i++) { delta = nextjuxtaposed (seq, i); perm[i] = (i + delta) % seqlen; } return; } int computearea (sequence *seq, sequence *perm) { int i; int area = 0; assert (perm); for (i = 0; i < seqlen; i++) { if (perm[i] <= i) area++; } return (area); } int countgrossassemblages (sequence *perm) { int i, j, order; int assemblages = 1; for (i = 0; i < seqlen; i++) { if (perm[i] > i) continue; /* noncanonical representative */ if (perm[i] == i) continue; /* it would count as 1 */ for (order = 2, j = perm[i]; j != i; j = perm[j], order++) { assemblages *= order; } } return (assemblages); } void firstgrossassemblage (sequence *perm, sequence *assemblage) { int i, j, s; for (i = 0; i < seqlen; i++) assemblage[i] = -1; for (i = 0; i < seqlen; i++) { if (perm[i] > i) continue; /* noncanonical representative */ if (perm[i] == i) { assemblage[i] = 0; /* c'e' un solo piano in questo caso */ continue; } s = 0; assemblage[i] = s++; for (j = perm[i]; j != i; j = perm[j]) assemblage[j] = s++; } return; } int nextgrossassemblage (sequence *perm, sequence *assemblage) { int i; for (i = 0; i < seqlen; i++) { if (perm[i] <= i) return (nextgrossassemblagerec (perm, assemblage, i)); } fprintf (stderr, "ERRORE FATALE in nextgrossassemblage\n"); exit (1); } int nextgrossassemblagerec (sequence *perm, sequence *assemblage, int i) { int j; assert (perm[i] <= i); j = i+1; for (j = i+1; j < seqlen; j++) { if (perm[j] <= j) { if (nextgrossassemblagerec (perm, assemblage, j)) return (1); break; } } if (perm[i] == i) return (0); /* caso particolare, solo una permutazione */ /* qui devo ciclare sulle permutazioni del mucchio indicato da i */ return (nextpileperm (perm, assemblage, i, i)); } int nextpileperm (sequence *perm, sequence *assemblage, int pile, int lastpile) { int nextpile; int targetind, targetval; //printpileperm (perm,assemblage,pile,lastpile); nextpile = perm[pile]; assert (pile != nextpile); if (nextpile == lastpile) return (0); /* caso di permutazione di un solo elemento */ if (nextpileperm (perm, assemblage, nextpile, lastpile)) return (1); /* se arrivo qui gli elementi successivi sono in ordine crescente */ targetind = pile; targetval = seqlen + 1; for (nextpile = perm[pile]; nextpile != lastpile; nextpile = perm[nextpile]) { if (assemblage[nextpile] > assemblage[pile]) { if (assemblage[nextpile] < targetval) { targetval = assemblage[nextpile]; targetind = nextpile; } } } if (targetval > seqlen) { /* we have finished, must reset to the first perm */ targetval = assemblage[pile]; assemblage[pile] = assemblage[perm[pile]]; for (nextpile = perm[pile]; nextpile != lastpile; nextpile = perm[nextpile]) { if (perm[nextpile] == lastpile) { assemblage[nextpile] = targetval; return (0); } assemblage[nextpile] = assemblage[perm[nextpile]]; } assert (0); } /* i rimanenti elementi sono in ordine crescente devo scambiare * i contenuti di pile e targetind */ assert (assemblage[targetind] == targetval); assemblage[targetind] = assemblage[pile]; assemblage[pile] = targetval; return (1); } int iscanonassemblage (sequence *seq, sequence *perm, sequence *assemblage) { static sequence wseq[SEQDIM], newassemblage[SEQDIM]; int revert, rotate, sqsym; int swap, swapr; for (revert = -1; revert <=1; revert+=2) { swapr = (1-revert)/2; for (rotate = 0; rotate < seqlen; rotate++) { swap = swapr + rotate; swap = swap % 2; for (sqsym = 0; sqsym < NUMSQUARESYM; sqsym++) { action (seq, wseq, revert, rotate, sqsym); if (seqcmp (wseq, seq) != 0) continue; actionassemblage (seq, perm, assemblage, newassemblage, revert, rotate, sqsym, (swap + squaresymswap[sqsym]) % 2); if (seqcmp (newassemblage, assemblage) < 0) return (0); // noncanonical assemblage } } } return (1); } int checkassemblable (sequence *perm, sequence *assemblage) { int i, j, ii, jj; for (i = 0; i < seqlen; i++) { if (perm[i] == i) continue; for (j = perm[i]; j != i; j = perm[j]) { ii = i + 1; ii = ii % seqlen; jj = j + 1; jj = jj % seqlen; if (ii != jj && samepile (perm, ii, jj)) { if ((assemblage[i]-assemblage[j])*(assemblage[ii]-assemblage[jj]) < 0) return (0); } jj = j + seqlen - 1; jj = jj % seqlen; if (ii != jj && samepile (perm, ii, jj)) { if ((assemblage[i]-assemblage[j])*(assemblage[ii]-assemblage[jj]) < 0) return (0); } } } return (1); } /* * ================================================================== * calcola il contributo a Delta dovuto ai flap */ int computedf (sequence *seq, sequence *perm, sequence *assemblage) { int i, ip1, im1, diff; int delta; int df = 0; for (i = 0; i < seqlen; i++) { ip1 = i+1; ip1 = ip1%seqlen; diff = seq[i] - seq[ip1]; diff += 4; assert (diff >= 0); diff = diff % 4; if (diff != 2) continue; // non e' un flap im1 = i - 1 + seqlen; im1 = im1%seqlen; diff = assemblage[ip1] - assemblage[im1]; delta = 2; if (diff > 0) delta = -delta; if (seq[i] == N || seq[i] == S) delta = -delta; df += delta; } return (df); } void actionassemblage (sequence *seq, sequence *perm, sequence *assemblage, sequence *newassemblage, int revert, int rotate, int squaresym, int swap) { sequence tseq[SEQDIM]; int i, j, destad, piani; assert (revert == 1 || revert == -1); assert (rotate >= 0 && rotate < seqlen); assert (squaresym >= 0 && squaresym < NUMSQUARESYM); assert (swap == 0 || swap == 1); for (i = 0; i < seqlen; i++) tseq[i] = assemblage[i]; for (i = 0; i < seqlen; i++) { if (revert > 0) destad = rotate + i; else destad = rotate - 1 - i + 2*seqlen; destad = destad % seqlen; newassemblage[destad] = tseq[i]; } if (swap) { for (i = 0; i < seqlen; i++) { if (perm[i] > i) continue; // non canonical position if (perm[i] == i) continue; // single floor: nothing happens piani = 1; for (j = perm[i]; j != i; j = perm[j]) piani++; newassemblage[i] = piani - 1 - newassemblage[i]; for (j = perm[i]; j != i; j = perm[j]) newassemblage[j] = piani - 1 - newassemblage[j]; } } /* XXXX */ //isassemblage(perm, newassemblage); if (debug) { printf ("\n revert=%d rotate=%d squaresym=%d swap=%d\n", revert, rotate, squaresym, swap); for (i = 0; i < seqlen; i++) { printf ("%d", assemblage[i]); } printf ("\n"); for (i = 0; i < seqlen; i++) { printf ("%d", newassemblage[i]); } } } int samepile (sequence *perm, int i, int j) { int ii; if (i == j) return (1); for (ii = perm[i]; ii != i; ii = perm[ii]) { if (ii == j) return (1); } return (0); } void printpileperm (sequence *perm, sequence *assemblage, int pile, int lastpile) { printf ("pile perm: "); do { printf ("%d", assemblage[pile]); pile = perm[pile]; } while (pile != lastpile); printf ("\n"); } int isassemblage (sequence *perm, sequence *assemblage) { int i, j, piani; static int found[SEQDIM]; for (i = 0; i < seqlen; i++) assert (assemblage[i] >= 0); for (i = 0; i < seqlen; i++) found[i] = 0; for (i = 0; i < seqlen; i++) { assert (perm[i] >= 0 && perm[i] < seqlen); found[perm[i]] = 1; } for (i = 0; i < seqlen; i++) assert (found[i]); /* surjective -> bijective */ for (i = 0; i < seqlen; i++) { if (perm[i] > i) continue; // noncanonical position if (perm[i] == i) { assert (assemblage[i] == 0); continue; } piani = 1; for (j = perm[i]; j != i; j = perm[j]) piani++; for (j = 0; j < piani; j++) found[j] = 0; found[assemblage[i]] = 1; assert (assemblage[i] < piani); for (j = perm[i]; j != i; j = perm[j]) { found[assemblage[j]] = 1; assert (assemblage[j] < piani); assert (perm[j] > j); } } return (1); } /* * ciclo su tutte le sequenze chiuse */ void firstsequence (sequence *seq) { int i; for (i = 0; i < seqlen; i++) seq[i] = E; } int nextsequence (sequence *seq) { return (nextsequencerec(seq, 0)); } int nextsequencerec (sequence *seq, int start) { int startp1; startp1 = start + 1; if (startp1 < seqlen) { if (nextsequencerec (seq, startp1)) return (1); } seq[start]++; if (seq[start] < E + 4) return (1); seq[start] = E; return (0); } void action (sequence *seq, sequence *dseq, int revert, int rotate, int squaresym) { sequence tseq[SEQDIM]; int i, destad; assert (revert == 1 || revert == -1); assert (rotate >= 0 && rotate < seqlen); assert (squaresym >= 0 && squaresym < NUMSQUARESYM); for (i = 0; i < seqlen; i++) tseq[i] = seq[i]; for (i = 0; i < seqlen; i++) { destad = rotate + revert*i + seqlen; destad = destad % seqlen; dseq[destad] = squaresymv[squaresym][tseq[i]]; } } int checkclosed (sequence *seq) { int i; int numn = 0; int nums = 0; int nume = 0; int numw = 0; for (i = 0; i < seqlen; i++) { if (seq[i] == E) nume++; if (seq[i] == W) numw++; if (seq[i] == N) numn++; if (seq[i] == S) nums++; } if (nume != numw) return (0); if (numn != nums) return (0); return (1); } /* * check whether the tile left of seq[first] is juxtaposed to that * left of seq[second] * this is safe to call for any integral first, second * but is always true if first = second mod seqlen * i.e. it assumes the sequence to be closed */ int arejuxtaposed (sequence *seq, int first, int second) { int i, j; int numn = 0; int nums = 0; int nume = 0; int numw = 0; first = first % seqlen; if (first < 0) first += seqlen; second = second % seqlen; if (second < 0) second += seqlen; if (second < first) second += seqlen; for (i = first; i < second; i++) { j = i % seqlen; if (seq[j] == E) nume++; if (seq[j] == W) numw++; if (seq[j] == N) numn++; if (seq[j] == S) nums++; } if (nume != numw) return (0); if (numn != nums) return (0); return (1); } /* * count minimum number of directions to get back to starting position * it assumes tile >= 0 * tile is the tile left to seq[tile] */ int nextjuxtaposed (sequence *seq, int tile) { int j, delta; int numns = 0; int numew = 0; for (delta = 1; delta < seqlen; delta++) { j = (tile + delta) % seqlen; if (seq[j] == E) numew++; if (seq[j] == W) numew--; if (seq[j] == N) numns++; if (seq[j] == S) numns--; if (numew == 0 && numns == 0) return (delta); } return (0); } int seqcmp (sequence *seq1, sequence *seq2) { int i; for (i = 0; i < seqlen; i++) { if (seq1[i] != seq2[i]) return ((seq1[i] < seq2[i])?(-1):1); } return (0); } void printseq (sequence *seq) { int i; for (i = 0; i < seqlen; i++) { printf ("%c", chardir[seq[i]]); } } void readseq (sequence *seq, char *stringa) { int i, seqlensaved; char ch, *chpt; for (i = 0, chpt = stringa; *chpt && i < SEQDIM; i++) { while (isspace(ch = tolower(*chpt++))); assert (isalpha(ch)); switch (ch) { case 'e': seq[i] = E; break; case 'n': seq[i] = N; break; case 'w': seq[i] = W; break; case 's': seq[i] = S; break; default: fprintf (stderr, "invalid character %c\n", stringa[i]); exit (10); break; } } seqlensaved = seqlen; seqlen = i; if (!checkclosed(seq)) { printf ("Error: sequence is not closed.\n"); exit (3); } if (seqlen != seqlensaved) fprintf (stderr, "warning: length of sequence not default, changing it!\n"); } int countflaps (sequence *seq) { int i, diff; int flapsnum = 0; for (i = 0; i < seqlen; i++) { diff = seq[i] - seq[(i+1)%seqlen]; if (diff == 2 || diff == -2) flapsnum++; } return (flapsnum); } /* */ void init_data () { int actid = 0; int rot, dir, resdir; int swap = 0; assert ((N - E) == 1); assert ((W - N) == 1); assert ((S - W) == 1); assert (seqlen <= SEQDIM); swap = 0; for (rot = 0; rot < 4; rot++) { for (dir = 0; dir < 4; dir++) { resdir = (dir + rot) % 4; squaresymv[actid][dir+E] = resdir + E; } squaresymswap[actid] = swap; swap = 1 - swap; actid++; } swap = 1; for (rot = 0; rot < 4; rot++) { for (dir = 0; dir < 4; dir++) { resdir = dir; if ((dir % 2) == 0) resdir = 2 - resdir; resdir = (resdir + rot) % 4; squaresymv[actid][dir+E] = resdir + E; } squaresymswap[actid] = swap; swap = 1 - swap; actid++; } assert (actid == NUMSQUARESYM); chardir[N] = 'N'; chardir[E] = 'E'; chardir[S] = 'S'; chardir[W] = 'W'; }