/* Find minimal e-free NFA for a?b?c?...z? for alphabet of size n. See http://www.research.att.com/~njas/sequences/A129403 Russ Cox April 2007 rsc@swtch.com gcc -O2 -Wall a129403.c a.out 6 >graph circo -Tps graph >graph.ps; gv graph.ps n total-edges 1 1 2 3 3 6 4 9 5 13 6 18 7 23 8 <= 28 9 <= 34 10 <= 41 */ #include #include #include #include #include #include #include #define uint _uint typedef unsigned int uint; typedef struct NFA NFA; enum { N = 16, Debug = 0, Heuristic = 0, /* set for heuristic construction */ }; int n; struct NFA { uint next[N+1][N]; }; uint next(NFA *nfa, uint state, int c) { int i; uint nstate; nstate = 0; for(i=0; inext[i][c]; return nstate; } int accepts(NFA *nfa, char *s) { uint state; state = 1; for(; *s; s++){ state = next(nfa, state, *s-'a'); if(state == 0) return 0; } return 1; } typedef struct Work Work; struct Work { uint state; int c; }; int oknfa(NFA *nfa, int maxletter) { int i, rq, wq; Work *e, *f; static Work q[(1<=e->c; i--){ f = &q[wq++]; f->state = next(nfa, e->state, i); if(f->state == 0) return 0; f->c = i+1; } } assert(rq <= (1< %c%d [label = \"%c\"];\n", 'A'+nsol, i, 'A'+nsol, i+1, 'a'+i); for(i=1; i %c%d [label = \"%c\"];\n", 'A'+nsol, 'A'+nsol, i+1, 'a'+i); } if(Heuristic){ for(i=0; i %c%d [label = \"%c\"];\n", 'A'+nsol, 'A'+nsol, n/2, 'a'+i); } for(i=0; iused) printf("\t%c%d -> %c%d [label = \"%c\"];\n", 'A'+nsol, a->from, 'A'+nsol, a->to, 'a'+a->c); } printf("}\n"); } /* * Can this NFA be completed successfully? */ int anyhope(NFA *nfa, int nextarrow) { int i, r; Arrow *a; a = arrow+nextarrow; for(i=nextarrow; inext[a->from][a->c] |= 1<to; r = oknfa(nfa, n); for(i=nextarrow; inext[a->from][a->c] ^= 1<to; } return r; } void printarrows(void) { int i; uint abits; abits = 0; for(i=0; i arrow && nextarrow < narrow && a[-1].c != a[0].c && !oknfa(nfa, a[0].c)) return; /* * See if we made a good NFA - if so, no more arrows! */ if(nextarrow == narrow && oknfa(nfa, n)){ if(usedarrows <= best){ if(usedarrows < best || nsol == 0){ nsol = 0; fseek(stdout, 0, 0); ftruncate(1, 0); printf("digraph {\n"); } fprintf(stderr, "best - %d ", usedarrows+fixed); printarrows(); best = usedarrows; printnfa(); nsol++; } return; } if(nextarrow == narrow) return; if(nextarrow%8 == 0){ if(!anyhope(nfa, nextarrow)) return; } /* Try not using the arrow. */ trynfa(nfa, nextarrow+1, usedarrows, abits<<1); /* Then try using the arrow (maybe it will be better!). */ if(usedarrows < best){ nfa->next[a->from][a->c] |= 1<to; a->used = 1; trynfa(nfa, nextarrow+1, usedarrows+1, (abits<<1)|1); nfa->next[a->from][a->c] ^= 1<to; a->used = 0; } } void alrm(int s) { printarrows(); alarm(30); } void quit(int s) { printarrows(); } int main(int argc, char **argv) { int label, start, end; Arrow *a; NFA nfa; signal(SIGALRM, alrm); signal(SIGQUIT, quit); alarm(30); if(argc < 2) n = 4; else n = atoi(argv[1]); if(argc < 3) best = (n*(n-1))/2+1+n; else best = atoi(argv[2]); /* Add required arrows. */ memset(&nfa, 0, sizeof nfa); for(label=0; label n/2) continue; } a = &arrow[narrow++]; a->from = start; a->to = end; a->c = label; } } } fprintf(stderr, "%d arrows [best %d+%d]\n", narrow, fixed, best); trynfa(&nfa, 0, 0, 0); fprintf(stderr, "best %d\n", best+fixed); printf("}\n"); return 0; }