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; }
int main() { /*36:*/ #line 716 "./gb_graph.w" g= gb_new_graph(2L); if(g==NULL){ fprintf(stderr,"Oops, I couldn't even create a trivial graph!\n"); return-4; } u= g->vertices;v= u+1; u->name= gb_save_string("vertex 0"); v->name= gb_save_string("vertex 1"); /*:36*/ #line 30 "./gb_graph.w" ; /*18:*/ #line 327 "./gb_graph.w" if(gb_alloc(0L,s)!=NULL||gb_trouble_code!=2){ fprintf(stderr,"Allocation error 2 wasn't reported properly!\n");return-2; } for(;g->vv.I<100;g->vv.I++)if(gb_alloc(100000L,s)){ g->uu.I++; printf("."); fflush(stdout); } if(g->uu.I<100&&gb_trouble_code!=3){ fprintf(stderr,"Allocation error 1 wasn't reported properly!\n");return-1; } if(g->uu.I==0){ fprintf(stderr,"I couldn't allocate any memory!\n");return-3; } gb_free(s); printf("Hey, I allocated %ld00000 bytes successfully. Terrific...\n",g->uu.I); gb_trouble_code= 0; /*:18*/ #line 31 "./gb_graph.w" ; /*38:*/ #line 735 "./gb_graph.w" if(strncmp(u->name,v->name,7)){ fprintf(stderr,"Something is fouled up in the string storage machinery!\n"); return-5; } gb_new_edge(v,u,-1L); gb_new_edge(u,u,1L); gb_new_arc(v,u,-1L); if((edge_trick&(siz_t)(u->arcs))|| (edge_trick&(siz_t)(u->arcs->next->next))|| !(edge_trick&(siz_t)(v->arcs->next))) printf("Warning: The \"edge trick\" failed!\n"); if(v->name[7]+g->n!=v->arcs->next->tip->name[7]+g->m-2){ fprintf(stderr,"Sorry, the graph data structures aren't working yet.\n"); return-6; } /*:38*/ #line 32 "./gb_graph.w" ; printf("OK, the gb_graph routines seem to work!\n"); return 0; }
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() */
//#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; }
Graph * geo(long seed, geo_parms *pp) { double p,d,L,radius,r; u_char *occ; register int scale; unsigned nbytes, index, x, y; u_long units,pertrange; int mallocd; register i,j; Graph *G; Vertex *up,*vp; char namestr[128]; gb_trouble_code = 0; if (seed) /* zero seed means "already init'd */ gb_init_rand(seed); scale = pp->scale; L = sqrt(2.0) * scale; gb_trouble_code = 0; if ((pp->alpha <= 0.0) || (pp->alpha > 1.0)) gb_trouble_code=bad_specs+1; if (pp->gamma < 0.0) gb_trouble_code=bad_specs+GEO_TRBL; if (pp->beta < 0.0) gb_trouble_code=bad_specs+GEO_TRBL; if (pp->n > (scale * scale)) gb_trouble_code=bad_specs+GEO_TRBL; if (gb_trouble_code) return NULL; radius = pp->gamma * L; /* comes in as a fraction of diagonal */ #define posn(x,y) ((x)*scale)+(y) #define bitset(v,i) (v[(i)/NBBY]&(1<<((i)%NBBY))) #define setbit(v,i) v[(i)/NBBY] |= (1<<((i)%NBBY)) /* create a new graph structure */ if ((G=gb_new_graph(pp->n)) == NULL) return NULL; nbytes = ((scale*scale)%NBBY ? (scale*scale/NBBY)+1 : (scale*scale)/NBBY); if (nbytes < STACKMAX) { /* small amount - just do it in the stack */ occ = (u_char *) alloca(nbytes); mallocd = 0; } else { occ = (u_char *) malloc(nbytes); mallocd = 1; } for (i=0; i<nbytes; i++) occ[i] = 0; /* place each of n points in the plane */ for (i=0,vp = G->vertices; i<pp->n; i++,vp++) { sprintf(namestr,"%d",i); /* name is just node number */ vp->name = gb_save_string(namestr); do { vp->xpos = gb_next_rand()%scale; /* position: 0..scale-1 */ vp->ypos = gb_next_rand()%scale; /* position: 0..scale-1 */ index = posn(vp->xpos,vp->ypos); } while (bitset(occ,index)); setbit(occ,index); } /* Now go back and add the edges */ for (i=0,up = G->vertices; i<(pp->n)-1; i++,up++) for (j=i+1, vp = &G->vertices[i+1]; j<pp->n; j++,vp++) { d = distance(up,vp); switch (pp->method) { case RG2: /* Waxman's */ d = randfrac()*L; /* fall through */ case RG1: /* Waxman's */ p = pp->alpha * exp(-d/(L*pp->beta)); break; case RANDOM: /* the classic */ p = pp->alpha; break; case EXP: p = pp->alpha * exp(-d/(L-d)); break; case DL: /* Doar-Leslie */ p = pp->alpha * (pp->gamma/pp->n) * exp(-d/(L*pp->beta)); break; case LOC: /* Locality model, two probabilities */ if (d <= radius) p = pp->alpha; else p = pp->beta; break; default: die("Bad edge method in geo()!"); } if (randfrac() < p) gb_new_edge(up,vp,(int)rint(d)); } /* Fill in the "id" string to say how the graph was created */ G->Gscale = scale; sprintf(G->id,"geo(%ld,", seed); i = strlen(G->id); i += printparms(G->id+i,pp); G->id[i] = ')'; G->id[i+1] = (char) 0; strcpy(G->util_types,GEO_UTIL); /* clean up */ if (mallocd) free(occ); return G; }