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() */
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(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; }