static int minimal_ladders(ladders_rec_t *rec) { Vertex *uu, *vv; int rc = 0; char *start = rec->start; char *goal = rec->goal; /* build the amplified graph gg */ gg = gb_new_graph(0L); gg->vertices = __g->vertices; gg->n = __g->n; (gg->vertices + gg->n)->name = start; uu = find_word(start, plant_new_edge); if (!uu) { uu = gg->vertices + gg->n++; } if (strncmp(start, goal, 5) == 0) { vv = uu; } else { (gg->vertices + gg->n)->name = goal; vv = find_word(goal, plant_new_edge); if (!vv) { vv = gg->vertices + gg->n++; } } if (gg->n == __g->n + 2) { if (hamm_dist(start, goal) == 1) { gg->n--; plant_new_edge(uu); gg->n++; } } /* print the answer */ if (dijkstra(uu, vv, gg, NULL) < 0) { strbuf_append_printf(&rec->path, "Sorry, there's no ladder from %s to %s.", start, goal); } else { rc = dijkstra_result(rec, vv); } /* remove all traces of gg */ for (uu = __g->vertices + gg->n-1; uu >= __g->vertices+__g->n; uu--) { register Arc *a; for (a = uu->arcs; a; a = a->next) { vv = a->tip; vv->arcs = vv->arcs->next; } uu->arcs = NULL; } gb_recycle(gg); return rc; }
//#line 6 "../PROTOTYPES/ladders.ch" int main(int argc, char *argv[]) //#line 94 "../ladders.w" { /*5:*/ //#line 120 "../ladders.w" while (--argc) { if (strcmp(argv[argc], "-v") == 0) verbose = 1; else if (strcmp(argv[argc], "-a") == 0) alph = 1; else if (strcmp(argv[argc], "-f") == 0) freq = 1; else if (strcmp(argv[argc], "-h") == 0) heur = 1; else if (strcmp(argv[argc], "-e") == 0) echo = 1; else if (sscanf(argv[argc], "-n%lu", &n) == 1) randm = 0; else if (sscanf(argv[argc], "-r%lu", &n) == 1) randm = 1; else if (sscanf(argv[argc], "-s%ld", &seed) == 1); else { fprintf(stderr, "Usage: %s [-v][-a][-f][-h][-e][-nN][-rN][-sN]\n", argv[0]); return -2; } } if (alph || randm) freq = 0; if (freq) heur = 0; /*:5*/ //#line 95 "../ladders.w" ; /*6:*/ //#line 149 "../ladders.w" g = words(n, (randm ? zero_vector : NULL), 0L, seed); quit_if(g == NULL, panic_code); /*8:*/ //#line 165 "../ladders.w" if (verbose) { if (alph) printf("(alphabetic distance selected)\n"); if (freq) printf("(frequency-based distances selected)\n"); if (heur) printf("(lowerbound heuristic will be used to focus the search)\n"); if (randm) printf("(random selection of %ld words with seed %ld)\n", g->n, seed); else printf("(the graph has %ld words)\n", g->n); } /*:8*/ //#line 152 "../ladders.w" ; /*9:*/ //#line 183 "../ladders.w" if (alph) { register Vertex *u; for (u = g->vertices + g->n - 1; u >= g->vertices; u--) { register Arc *a; register char *p = u->name; for (a = u->arcs; a; a = a->next) { register char *q = a->tip->name; a->len = a_dist(a->loc); } } } else if (freq) { register Vertex *u; for (u = g->vertices + g->n - 1; u >= g->vertices; u--) { register Arc *a; for (a = u->arcs; a; a = a->next) a->len = freq_cost(a->tip); } } /*:9*/ //#line 153 "../ladders.w" ; /*10:*/ //#line 202 "../ladders.w" if (alph || freq || heur) { init_queue = init_128; del_min = del_128; enqueue = enq_128; requeue = req_128; } /*:10*/ //#line 154 "../ladders.w" ; /*:6*/ //#line 96 "../ladders.w" ; while (1) { /*26:*/ //#line 373 "../ladders.w" putchar('\n'); restart: if (prompt_for_five("Starting", start) != 0) break; if (prompt_for_five(" Goal", goal) != 0) goto restart; /*:26*/ //#line 98 "../ladders.w" ; /*13:*/ //#line 245 "../ladders.w" /*14:*/ //#line 251 "../ladders.w" gg = gb_new_graph(0L); quit_if(gg == NULL, no_room + 5); gg->vertices = g->vertices; gg->n = g->n; /*15:*/ //#line 266 "../ladders.w" (gg->vertices + gg->n)->name = start; uu = find_word(start, plant_new_edge); if (!uu) uu = gg->vertices + gg->n++; /*:15*/ //#line 256 "../ladders.w" ; /*16:*/ //#line 272 "../ladders.w" if (strncmp(start, goal, 5) == 0) vv = uu; else { (gg->vertices + gg->n)->name = goal; vv = find_word(goal, plant_new_edge); if (!vv) vv = gg->vertices + gg->n++; } /*:16*/ //#line 257 "../ladders.w" ; if (gg->n == g->n + 2) /*19: */ //#line 311 "../ladders.w" if (hamm_dist(start, goal) == 1) { gg->n--; plant_new_edge(uu); gg->n++; } /*:19*/ //#line 258 "../ladders.w" ; quit_if(gb_trouble_code, no_room + 6); /*:14*/ //#line 246 "../ladders.w" ; /*21:*/ //#line 333 "../ladders.w" if (!heur) min_dist = dijkstra(uu, vv, gg, NULL); else if (alph) min_dist = dijkstra(uu, vv, gg, alph_heur); else min_dist = dijkstra(uu, vv, gg, hamm_heur); /*:21*/ //#line 247 "../ladders.w" ; /*24:*/ //#line 350 "../ladders.w" if (min_dist < 0) printf("Sorry, there's no ladder from %s to %s.\n", start, goal); else print_dijkstra_result(vv); /*:24*/ //#line 248 "../ladders.w" ; /*25:*/ //#line 360 "../ladders.w" for (uu = g->vertices + gg->n - 1; uu >= g->vertices + g->n; uu--) { register Arc *a; for (a = uu->arcs; a; a = a->next) { vv = a->tip; vv->arcs = vv->arcs->next; } uu->arcs = NULL; } gb_recycle(gg); /*:25*/ //#line 249 "../ladders.w" ; /*:13*/ //#line 100 "../ladders.w" ; } return 0; }
char * makegraph(char *iname) { FILE *infile; Graph *G = NULL; char inbuf[LINE],outfilename[LINE]; register char *cp; char *method; int count, lineno=0, numlevels, nerrors; int i, m=0, prefixlen; int edgeConnMeth, haux, stubsPerTrans, tsEdges, ssEdges; long seed; geo_parms parmsbuf[MAXLEVEL]; /* make sure MAXLEVEL >= 3 */ if ((infile = fopen(iname, "r")) == NULL) { sprintf(errstr, "can't open input file %s", iname); die(errstr); } /* set up output file name */ sprintf(outfilename,"%s-",iname); prefixlen = strlen(outfilename); do { fgets(inbuf, LINE - 1, infile); lineno++; method = strtok(inbuf, delim); } while (((method == NULL) || (*method == '#')) && !feof(infile)); /* skip over comments and blank lines */ if ((cp = strtok(NULL, delim))==NULL) return "missing <number of graphs>"; count = atoi(cp); if ((cp = strtok(NULL, delim))==NULL) seed = 0; else seed = atol(cp); if (strcmp(method,GEO_KW)==0) { if (cp = get_geoparms(infile,parmsbuf)) return cp; m = GEO; } else if (strcmp(method,HIER_KW)==0) { if (cp = get_hierparms(infile, &numlevels, &edgeConnMeth, &haux, parmsbuf)) return cp; m = HIER; } else if (strcmp(method,TS_KW)==0) { if (cp = get_tsparms(infile, &stubsPerTrans, &tsEdges, &ssEdges, parmsbuf)) return cp; m = TS; } else { sprintf(errstr,"Unknown generation method %s",method); return errstr; } if (seed) gb_init_rand(seed); else gb_init_rand(DEFAULT_SEED); for (i=0; i<count; i++) { sprintf(outfilename+prefixlen,"%d.gb",i); switch(m) { case GEO: do { gb_recycle(G); G = geo(0,parmsbuf); } while (G != NULL && !isconnected(G)); break; case HIER: G = geo_hier(0,numlevels,edgeConnMeth,haux,parmsbuf); break; case TS: G = transtub(0,stubsPerTrans,tsEdges,ssEdges,&parmsbuf[0], &parmsbuf[1],&parmsbuf[2]); break; default: return "This can't happen!"; } /* switch */ if (G==NULL) { sprintf(errstr,"Error creating graph %d, trouble code=%d",i, gb_trouble_code); return errstr; } nerrors = save_graph(G, outfilename); if (nerrors > 0) fprintf(stderr, "%s had %d anomalies\n", outfilename,nerrors); gb_recycle(G); } /* for */ return NULL; }
Graph * geo_hier(long seed, int nlevels, /* number of levels (=size of following array) */ int edgemeth, /* method of attaching edges */ int aux, /* auxiliary parameter for edge method (threshold) */ geo_parms *pp) /* array of parameter structures, one per level */ { Graph *newG, *tG, *GG, *srcG, *dstG; long *numv; /* array of sizes of lower-level graphs */ geo_parms *curparms, workparms[MAXLEVEL]; register i,k,indx; long dst; int temp,total,lowsize,otherend,blen,level; long maxP[MAXLEVEL], maxDiam[MAXLEVEL], wt[MAXLEVEL]; Vertex *np,*vp,*up,*base; Arc *ap; char vnamestr[MAXNAMELEN]; if (seed) /* convention: zero seed means don't use */ gb_init_rand(seed); if (nlevels < 1 || nlevels > MAXLEVEL) { gb_trouble_code = bad_specs+HIER_TRBL; return NULL; } /* 1 <= nlevels <= MAXLEVEL */ /* copy the parameters so we can modify them, and caller doesn't * see the changes. */ for (level=0; level<nlevels; level++) bcopy((char *)&pp[level],&workparms[level],sizeof(geo_parms)); level = 0; gb_trouble_code = 0; tG = NULL; do { gb_recycle(tG); tG = geo(0L,workparms); } while (tG != NULL && !isconnected(tG)); if (tG==NULL) return tG; maxDiam[0] = fdiam(tG); maxP[0] = maxDiam[0]; wt[0] = 1; for (i=1; i<nlevels; i++) maxDiam[i] = -1; curparms = workparms; while (++level < nlevels) { long tdiam; curparms++; /* parameters for graphs @ next level */ /* spread out the numbers of nodes per graph at this level */ numv = (long *) calloc(tG->n,sizeof(long)); lowsize = curparms->n; randomize(numv,tG->n,curparms->n,3*tG->n); /* create a subordinate graph for each vertex in the "top" graph, * and add it into the new graph as a whole. * We construct the subgraphs all at once to ensure that each * has a unique address. */ for (i=0,vp=tG->vertices; i<tG->n; i++,vp++) { curparms->n = numv[i]; do { newG = geo(0L,curparms); if (newG==NULL) return NULL; } while (!isconnected(newG)); vp->sub = newG; tdiam = fdiam(newG); if (tdiam>maxDiam[level]) maxDiam[level] = tdiam; } /* do some calculations before "flattening" the top Graph */ total = 0; for (i=0; i<tG->n; i++) { /* translate node numbers */ temp = numv[i]; numv[i]= total; total += temp; } if (total != tG->n*lowsize) { fprintf(stderr,"bad size of new graph!\n"); fprintf(stderr,"total %d tG->n %ld lowsize %d\n",total,tG->n,lowsize); gb_trouble_code = impossible+HIER_TRBL; return NULL; } /* now create what will become the "new" top-level graph */ newG = gb_new_graph(total); if (newG==NULL) { gb_trouble_code += HIER_TRBL; return NULL; } /* resolution of the new graph */ newG->Gscale = tG->Gscale * curparms->scale; /* compute edge weights for this level */ wt[level] = maxP[level-1] + 1; maxP[level] = (maxDiam[level]*wt[level]) + (maxDiam[level-1]*maxP[level-1]); for (i=0,vp=tG->vertices; i<tG->n; i++,vp++) { strcpy(vnamestr,vp->name); /* base name for all "offspring" */ blen = strlen(vnamestr); vnamestr[blen] = '.'; GG = tG->vertices[i].sub; base = newG->vertices + numv[i]; /* start of this node's */ for (k=0,np=base,up=GG->vertices; k<GG->n; k++,np++,up++) { /* add the node's edges */ for (ap=up->arcs; ap; ap=ap->next) { otherend = ap->tip - GG->vertices; if (k < otherend) gb_new_edge(np,base+otherend,ap->len); } /* now set the new node's position */ np->xpos = tG->vertices[i].xpos * curparms->scale + up->xpos; np->ypos = tG->vertices[i].ypos * curparms->scale + up->ypos; /* give the "new" node a name by catenating top & bot names */ strcpy(vnamestr+blen+1,up->name); np->name = gb_save_string(vnamestr); } /* loop over GG's vertices */ } /* loop over top-level vertices */ /* * Now we have to transfer the top-level edges to new graph. * This is done by one of three methods: * 0: choose a random node in each subgraph * 1: attach to the smallest-degree non-leaf node in each * 2: attach to smallest-degree node * 3: attach to first node with degree less than aux */ for (i=0; i<tG->n; i++) { Vertex *srcp, *dstp; Graph *srcG, *dstG; srcG = tG->vertices[i].sub; if (srcG == NULL) { /* paranoia */ gb_trouble_code = impossible+HIER_TRBL+1; return NULL; } for (ap=tG->vertices[i].arcs; ap; ap=ap->next) { dst = ap->tip - tG->vertices; if (i > dst) /* consider each edge only ONCE */ continue; dstG = ap->tip->sub; if (dstG == NULL) { /* paranoia */ gb_trouble_code = impossible+HIER_TRBL+1; return NULL; } /* choose endpoints of the top-level edge */ switch (edgemeth) { case 0: /* choose random node in each */ srcp = srcG->vertices + gb_next_rand()%srcG->n; dstp = dstG->vertices + gb_next_rand()%dstG->n; break; case 1: /* find nonleaf node of least degree in each */ /* This causes problems with graph size < 3 */ if (srcG->n > 2) srcp = find_small_deg(srcG,NOLEAF); else srcp = find_small_deg(srcG,LEAFOK); if (dstG->n > 2) dstp = find_small_deg(dstG,NOLEAF); else dstp = find_small_deg(dstG,LEAFOK); break; case 2: /* find node of smallest degree */ srcp = find_small_deg(srcG,LEAFOK); dstp = find_small_deg(dstG,LEAFOK); break; case 3: /* first node w/degree < aux */ srcp = find_thresh_deg(srcG,aux); dstp = find_thresh_deg(dstG,aux); default: gb_trouble_code = bad_specs+HIER_TRBL; return NULL; } /* switch on edgemeth */ /* pointer arithmetic: isn't it fun? printf("Copying edge from %d to %d\n", numv[i]+(srcp - srcG->vertices), numv[dst] + (dstp - dstG->vertices)); */ if (srcp==NULL || dstp==NULL) { gb_trouble_code = impossible + HIER_TRBL+2; return NULL; } srcp = newG->vertices + numv[i] + (srcp - srcG->vertices); dstp = newG->vertices + numv[dst] + (dstp - dstG->vertices); gb_new_edge(srcp,dstp,idist(srcp,dstp)); } /* for each arc */ } /* for each vertex of top graph */ /* now make the "new" graph the "top" graph and recycle others */ for (i=0,vp=tG->vertices; i<tG->n; i++,vp++) gb_recycle(vp->sub); gb_recycle(tG); tG = newG; free(numv); } /* while more levels */ /* Finally, go back and add the policy weights, * based upon the computed max diameters * and Max Path lengths. */ for (i=0; i<tG->n; i++) for (ap=tG->vertices[i].arcs; ap; ap=ap->next) { dst = ap->tip - tG->vertices; if (i > dst) /* consider each edge only ONCE */ continue; assert(i != dst); /* no self loops */ /* i < dst: it is safe to refer to ap's mate by ap+1. */ level = edge_level(&tG->vertices[i],&tG->vertices[dst],nlevels); ap->policywt = (ap+1)->policywt = wt[level]; } /* construct the utility and id strings for the new graph. * Space constraints will restrict us to keeping about 4 levels' * worth of info. */ { char buf[ID_FIELD_SIZE+1]; register char *cp; int len, nextlen, left; strcpy(tG->util_types,GEO_UTIL); /* same for all geo graphs, */ /* defined in geo.h */ cp = tG->id; sprintf(cp,"geo_hier(%ld,%d,%d,%d,[",seed,nlevels,edgemeth,aux); len = strlen(cp); left = ID_FIELD_SIZE - len; cp += len; for (i=0; (i < nlevels) && (left > 0); i++) { nextlen = printparms(buf,&pp[i]); strncpy(cp,buf,left); left -= nextlen; cp += nextlen; } if (left > 0) { sprintf(buf,"])"); nextlen = strlen(buf); strncpy(cp,buf,left); } } return tG; } /* geo_hier() */