ts.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:21k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* $Id: ts.c,v 1.1 1996/10/04 13:37:05 calvert Exp $
  2.  * 
  3.  * ts.c -- routines to construct transit-stub graphs
  4.  *         using the Stanford GraphBase tools.
  5.  *
  6.  * This code calls the routines in geog.c
  7.  *
  8.  */
  9. #include <stdio.h>
  10. #include <sys/types.h> /* for NBBY */
  11. #ifndef FBSD
  12. #include <alloca.h>
  13. #endif
  14. #include "gb_graph.h"
  15. #include <math.h>
  16. #include "geog.h"
  17. #include <limits.h>
  18. #include <string.h>
  19. #include <assert.h>
  20. static char tsId[]="$Id: ts.c,v 1.1 1996/10/04 13:37:05 calvert Exp $";
  21. /* convention for trouble codes: TS adds 7-9 */
  22. #define TS_TRBL 7
  23. #define vtoi(g,v) ((v) - (g)->vertices)
  24. #define link vv.G /* Graph utility field */
  25. /* Graph aux fields */
  26. /* The following three are stored with the FINAL graph */
  27. #define MaxTdiam xx.I    /* Maximum Transit diameter (hops) */
  28. #define MaxSdiam yy.I    /* Maximum Stub diameter (hops) */
  29. #define Topdiam zz.I    /* Top-level Diameter (hops) */
  30. /* The following two are used ONLY in Stub graphs */
  31. #define Gxoff   xx.I            /* global x offset of stub domain graph */
  32. #define Gyoff   yy.I            /* global y offset of stub domain graph */
  33. #define TS_UTIL  "ZZZIIZIZIZZIII"
  34.                       /* VVVVVVAAGGGGGG */
  35.                       /* uvwxyzabuvwxyz
  36.          uvwxyz */
  37. #define sub     u.G             /* subordinate graph of a node */
  38. #define flat z.V /* corresponding node in "flat" graph */
  39. #define vindex(V,G) ((V) - (G)->vertices) 
  40. #define halfup(x) (((x)>>1)+1)
  41. #define OVERALL_DENSITY_FACTOR 80.0
  42. #define STUB_DENSITY_FACTOR 16.0
  43. #define TRANSIT_SPREAD 0.5
  44. #define STACKMAX 0x800 /* max memory allocated in stack */
  45. #define RANDMULT 3 /* multiplier for random iterations */
  46. /* determines max deviation from mean */
  47. /*
  48. #define BADRETURN(x) { free(nnodes); free(nstubs); free(nstubnodes);
  49.   return (x); }
  50. */
  51. /* fast diameter computation using Floyd-Warshall
  52.  * Returns the HOP diameter of the graph, i.e. each edge given UNIT wt.
  53.  * Leaves the LENGTH diameter of the graph in g->Gldiam.
  54.  * It also works for DIRECTED graphs. */
  55. long
  56. fdiam(Graph *g)
  57. {
  58. register i,j,k;
  59. long **dist, **ldist;
  60. int changed,mallocd;
  61. long diam, ldiam, newdist = 0, otherend;
  62. Vertex *v;
  63. Arc *a;
  64.     i = g->n*g->n*sizeof(long*);
  65.     if (i<STACKMAX) {
  66. dist = (long **)alloca(i);
  67. ldist = (long**)alloca(i);
  68. mallocd = 0;
  69.     } else {
  70. dist = (long **)malloc(i);
  71.         ldist = (long**)malloc(i);
  72. mallocd = 1;
  73.     }
  74.     for (i=0; i < g->n; i++) {
  75. if (mallocd) {
  76.     dist[i] = (long *)malloc(g->n*sizeof(long));
  77.     ldist[i] = (long *)malloc(g->n*sizeof(long));
  78. } else {
  79.     dist[i] = (long *)alloca(g->n*sizeof(long));
  80.     ldist[i] = (long *)alloca(g->n*sizeof(long));
  81. }
  82. for (j=0; j < g->n; j++)
  83.   dist[i][j] = ldist[i][j] =  BIGINT;
  84. dist[i][i] = ldist[i][i] = 0;
  85.     }
  86.     for (i=0,v=g->vertices; i < g->n; i++,v++)
  87. for (a=v->arcs; a; a=a->next) {
  88.     otherend = vtoi(g,a->tip);
  89.     ldist[i][otherend] = a->len;       /* edge weight */
  90.     dist[i][otherend] = 1;
  91. }
  92.     /* iterate until nothing changes */
  93.     changed = 1;
  94.     while (changed) {
  95.       /* INVARIANT: dist[i][k] == BIGINT  === ldist[i][k] == BIGINT */
  96. changed = 0;
  97. for (i=0; i<g->n; i++)
  98.     for (j=0; j<g->n; j++) {
  99. for (k=0; k<g->n; k++) { /* i < k < j */
  100.     if (i==j || j==k || i==k)
  101. continue;
  102.     /* i != j && j != k && i != k */
  103.     if (dist[i][k] == BIGINT ||
  104. dist[k][j] == BIGINT)
  105. continue; /* nothing to gain */
  106.     newdist = dist[i][k] + dist[k][j];
  107.     if (newdist < dist[i][j]) {
  108. dist[i][j] = newdist;
  109. changed++;
  110.     } /* if shorter */
  111.     newdist = ldist[i][k] + ldist[k][j];
  112.     if (newdist < ldist[i][j]) {
  113. ldist[i][j] = newdist;
  114. changed++;
  115.     } /* if shorter */
  116.         } /* for k */
  117.             } /* for j */
  118.     } /* while (changed) */
  119.     diam = ldiam = 0;
  120.     /* now find max shortest path */
  121.     for (i=0; i<g->n; i++)
  122. for (j=0; j<g->n; j++) {
  123.   if (dist[i][j] > diam)
  124.     diam = dist[i][j];
  125.   if (ldist[i][j] > diam)
  126.     ldiam = ldist[i][j];
  127.         }
  128.     if (mallocd) {
  129.       for (i=0; i<g->n; i++) {
  130. free(dist[i]);
  131. free(ldist[i]);
  132.       }
  133.       free(dist);
  134.       free(ldist);
  135.     }
  136. /* Store the Euclidean diameter; for now we don't do anything with it.
  137.     g->Gldiam = ldiam;
  138. */ 
  139.     return diam;
  140. } /* fdiam */
  141. void
  142. die(s)
  143. {
  144. fprintf(stderr,"Fatal error %sn",s);
  145. exit(1);
  146. }
  147. /* Create a copy of each edge in fromG in toG. */
  148. /* Also places a pointer in each node in fromG pointing to the  */
  149. /* corresponding node in toG. */
  150. /* Requires: fromG != NULL, toG != NULL, toG->n >= fromG->n */
  151. void
  152. copyedges(Graph *fromG, Graph *toG, long base)
  153. {
  154. register i, indx;
  155. Vertex *np, *vp, *basep;
  156. Arc *ap;
  157. basep = toG->vertices + base;
  158. for (i=0,vp=fromG->vertices,np=basep; i<fromG->n;
  159.      i++,vp++,np++) {
  160.   
  161.   vp->flat = np; /* keep a pointer from old v to new */
  162.   for (ap=vp->arcs; ap; ap=ap->next) {
  163.     indx = vindex(ap->tip,fromG);
  164.     if (i<indx) /* do each edge only once */ {
  165.       gb_new_edge(np,basep+indx,ap->len); /* euclidean doesn't change! */
  166.       np->arcs->policywt = 1;           /* unit weight for policy  */
  167.       (np->arcs+1)->policywt = 1;       /* both directions!  */
  168.     }
  169.   }
  170. }
  171. } /* copyedges() */
  172. /* Generate Transit-Stub graphs. */
  173. /* Returns NULL without cleaning up when any subroutine call [e.g. geo(),  */
  174. /* gb_new_graph()] fails.    */
  175. Graph *
  176. transtub(long seed,
  177.  int spx, /* mean # stubs/transit node */
  178.  int nrants, /* # random transit-stub edges */
  179.  int nranss, /* # random stub-stub edges */
  180.  geo_parms* toppp, /* params for transit connectivity */
  181.  geo_parms* transpp, /*   "     "  transit domains */
  182.  geo_parms* stubpp) /*   "     "  stub domains */
  183. {
  184. int topdiam, /* diameter of top-level graph */
  185.     transdiam=0,  /* max diameter of a transit domain graph*/
  186.     stubdiam=0; /* max diameter of a stub domain graph */
  187. long ts, /* length of transit-stub edges */
  188.      ss, /* length of stub-stub edges */
  189.      tt; /* length of transit-transit edges */
  190. Graph *topG=NULL, *newG=NULL, *stubG=NULL, *finalG, *dgp, *ddgp, *sgp, *tempg;
  191. /* XXX this should be ifdef'd to be "int" on 32-bit machines and "short"  */
  192. /* on 64-bit machines.  Who needs a graph with more than 2 billion nodes? */
  193. long *nnodes=NULL, *nstubs=NULL, *nstubnodes=NULL;
  194. long maxtnodes, maxstubs, maxstubnodes, maxtotal;
  195. /* for positioning in plane. */
  196. long globscale, xoffset, yoffset, maxstuboff, maxx, minx, maxy, miny, xrange,
  197. yrange;
  198. long i,j,k;
  199. long indx, diam, totalnodes, base, dom;
  200. char dnodename[ID_FIELD_SIZE], snodename[ID_FIELD_SIZE];
  201. int dnamelen, numtries=0;
  202. register Vertex *v,*dnp, *snp, /* domain node and stub node pointers */
  203.        *ddnp, *fp, *tp, *tmp;
  204. Arc *a;
  205. long dnn,snn, /* domain node number, stub node number */
  206.      snum, /* stub number */
  207.      attachnode; /* index of edge endpoint */
  208. /* XXXXXX We need to copy ALL parameters because we modify them, and they
  209.  * need to be saved with the output graph. */
  210. geo_parms workparms;
  211.    if (seed)
  212. gb_init_rand(seed);
  213. /* allocate dynamic arrays.  We can calc upper bounds on sizes */
  214. /* because increase above mean due to randomize() is at most number */
  215. /* of iterations.  Note: These look weird, but they are correct. */
  216.    maxtnodes = transpp->n + (RANDMULT *toppp->n);
  217.    maxstubs = spx + (RANDMULT * maxtnodes);
  218.    maxstubnodes = stubpp->n + (RANDMULT*maxstubs);
  219.    /*   We can already calculate the total number of nodes  */
  220.    totalnodes = toppp->n * transpp->n * (spx * stubpp->n + 1);
  221.    nstubs = (long *)malloc(maxtnodes*sizeof(long)); /* stubs per T node */
  222.    nstubnodes = (long *)malloc(maxstubs*sizeof(long)); /* stub nodes per stub*/
  223.    nnodes = (long *)malloc(toppp->n*sizeof(long));  /* nodes per T dom */
  224. /* Compute the scales.  The global scale determines the actual unit sizes.
  225.  * The others determine how big (i.e. how much of the whole square) a transit
  226.  * domain and a stub domain are.  That is, the fraction of the square
  227.  * covered by a transit domain is TRANSIT_SPREAD^2. XXX should be a parameter
  228.  * Fraction of a square covered by a stub domain = (stubpp->scale/globscale)^2.
  229.  */
  230.    globscale = (long) rint(sqrt(totalnodes*OVERALL_DENSITY_FACTOR));
  231.    toppp->scale = globscale;
  232.    transpp->scale = (long) rint(globscale*TRANSIT_SPREAD);
  233.    if (transpp->scale&1)
  234.      transpp->scale += 1;
  235.    stubpp->scale = (long) rint(sqrt(maxstubnodes*STUB_DENSITY_FACTOR));
  236.    assert(stubpp->scale < globscale);
  237.    do {
  238. gb_recycle(topG);
  239. topG = geo(0,toppp);
  240. if (topG==NULL) {
  241.     free(nnodes);
  242.     free(nstubs);
  243.     free(nstubnodes);
  244.     return NULL;       /* don't mess with geo's trouble code */
  245. }
  246.    } while (!isconnected(topG) && ++numtries < 100);
  247.    if (numtries >= 100) 
  248. die("Failed to get a connected graph after 100 triesn");
  249.          /* XXX return NULL + set code */
  250.    topdiam = fdiam(topG);
  251.    /* randomize the number of nodes per transit domain */
  252.    randomize(nnodes,topG->n,transpp->n,RANDMULT*topG->n);
  253.    workparms = *transpp;
  254.    for (i=0,v=topG->vertices;  i<topG->n; i++,v++) {
  255.      
  256.      xoffset = v->xpos - (transpp->scale/2);
  257.      yoffset = v->ypos - (transpp->scale/2);
  258.      if (xoffset < 0)
  259.        xoffset = 0;
  260.      if (yoffset < 0)
  261.        yoffset = 0;
  262.      if ((xoffset + transpp->scale) > globscale)
  263.        xoffset = globscale - transpp->scale;
  264.      if ((yoffset + transpp->scale) > globscale)
  265.        yoffset = globscale - transpp->scale;
  266.      /* v == &topG->vertices[i], represents one whole transit domain */
  267.      /* create a connected domain graph */
  268.      workparms.n = nnodes[i];
  269.      newG = geo(0,&workparms);   /* create graph with nnodes[i] nodes */
  270.      if (newG==NULL) return NULL;
  271.      numtries = 0;
  272.      while (!isconnected(newG) && ++numtries<=100) {
  273.        gb_recycle(newG);
  274.        newG = geo(0,&workparms);   /* create graph with nnodes[i] nodes */
  275.        if (newG == NULL) return NULL;
  276.      }
  277.      if (numtries > 100)
  278.        die("Failed to get connected domain graph.");
  279.      if (gb_trouble_code)
  280.        return NULL;
  281.      
  282.      diam = fdiam(newG);
  283.      if (diam > transdiam) transdiam = diam;
  284.      
  285.      v->sub = newG;
  286.      /* randomize the number of stubs per transit node for this t domain */
  287.      randomize(nstubs,newG->n,spx,RANDMULT*newG->n);
  288.         
  289.      /* now for each node k in this T domain, create some S */
  290.      /* domains to attach to it.  These (nstubs[k] of 'em) domains  */
  291.      /* average stubpp->n nodes per domain. */
  292.      workparms = *stubpp;
  293.      for (k=0,dnp=newG->vertices; k<newG->n; k++,dnp++) {
  294.        /* dnp == &newG->vertices[k] */
  295.        /* k is the index of the current transit node */
  296.        dnp->sub = NULL;
  297.        dnp->xpos += xoffset;     /* position this node in the global plane */
  298.        dnp->ypos += yoffset;
  299.        /* Compute the range of possible offsets for stubs from this node. */
  300.        /* The furthest point of a stub may be up to stubscale from node */
  301.        /* (in each direction).  That is, the origin of the node is in the */
  302.        /* range [max(0,dnp->pos-stubpp->scale),dnp->pos] */
  303.        minx = dnp->xpos - stubpp->scale;
  304.        if (minx < 0) minx = 0;
  305.        miny = dnp->ypos - stubpp->scale;
  306.        if (miny < 0) miny = 0;
  307.        maxx = dnp->xpos;
  308.        if (maxx + stubpp->scale > globscale)
  309.  maxx = globscale - stubpp->scale;
  310.        maxy = dnp->ypos;
  311.        if (maxy + stubpp->scale > globscale)
  312.  maxy = globscale - stubpp->scale;
  313.        xrange = maxx - minx;
  314.        yrange = maxy - miny;
  315.        randomize(nstubnodes,nstubs[k],stubpp->n,RANDMULT*nstubs[k]);
  316.        for (j=0; j< nstubs[k]; j++) { /* create this many stubs */ 
  317.  workparms.n = nstubnodes[j]; /* with this many nodes */
  318.  stubG = geo(0,&workparms);
  319.  if (stubG == NULL) return NULL;
  320.  while (!isconnected(stubG)) {
  321.    gb_recycle(stubG);
  322.    stubG = geo(0,&workparms);
  323.    if (stubG == NULL) return NULL;
  324.  }
  325.  /* compute the offset of this stub from dnp's position */
  326.  /* These won't be used until the graph is "flattened" in the */
  327.  /* final stage. */
  328.  if (xrange)
  329.    stubG->Gxoff = minx + (random() % xrange);
  330.  else
  331.    stubG->Gxoff = minx;
  332.  if (yrange)
  333.    stubG->Gyoff = miny + (random() % yrange);
  334.  else
  335.    stubG->Gyoff = miny;
  336.  /* keep track of max of all stub diameters */
  337.  diam = fdiam(stubG);
  338.  if (diam > stubdiam) stubdiam = diam;
  339.  /* add the graph to the node's list */
  340.  stubG->link = dnp->sub;
  341.  dnp->sub = stubG;
  342.        } /* create stubs attached to node u */
  343.      } /* for each vertex of this transit domain */
  344.    }  /* for each top-level domain */
  345.    /*
  346.     * Edge length calculations. Main constraints are:
  347.     *  (0) 2ts > topdiam
  348.     *  (1) 2ss > stubdiam
  349.     *  (2) 2tt > transdiam
  350.     *  (3) 2ts > topdiam*tt + (tipdiam+1)*transdiam  [implies (0)]
  351.     *  (4) 2ss > 2stubdiam+2ts+(topdiam)tt+(topdiam+1)transdiam
  352.     *      =
  353.     *       ss > stubdiam + ts + (topdiam)tt/2 + (topdiam+1)transdiam/2
  354.     *      => 
  355.     *       ss > stubdiam
  356.     *      => {2ss > ss, transitivity >}
  357.     *       2ss > stubdiam [i.e. (1)]
  358.     *  (5) ss ~ 2ts + e [desirable but may or may not always be true]
  359.     *  where 
  360.     *  tt = length of edges connecting transit domains
  361.     *  ts = length of edges connecting transits to stubs
  362.     *  ss = length of (random) edges connecting stubs to stubs.
  363.     *
  364.     *  Noting that 2*((X>>1)+1) > X for nonnegative X, we define
  365.     *
  366.     * halfup(x) to be (((x)>>1)+1)
  367.     */
  368.     tt = halfup(transdiam);
  369.     ts = halfup(topdiam*tt) + halfup((topdiam+1)*transdiam);
  370.     ss = stubdiam  + 2*ts;
  371.    /*
  372.     *  Note that all intra-domain edges can keep original length!
  373.     */
  374.    /* Now we can flatten the hierarchy of graphs into the final Graph */
  375.    finalG = gb_new_graph(totalnodes);
  376.    base = 0;
  377.    for (dom=0,v=topG->vertices; dom<topG->n; dom++,v++) { /* for each domain */
  378. /* v = &topG->vertices[dom] */
  379. dgp = v->sub; /* dgp points to the "current" domain graph */
  380. copyedges(dgp,finalG,base); /* copy in edges of the domain */
  381. /* NB lengths of edges do not change      */
  382. /* Policy weights are set to unity by copyedges() */
  383. base += dgp->n; /* account for the domain's nodes */
  384. /* now go through the nodes of this domain */
  385. for (dnn=0,dnp=dgp->vertices; dnn<dgp->n; dnn++,dnp++) {
  386.     /* name of this (transit) node */
  387.     sprintf(dnodename,"T:%d.%d",dom,dnn);
  388.     dnp->flat->name = gb_save_string(dnodename);
  389.     
  390.     /* position of this node */
  391.     dnp->flat->xpos = dnp->xpos;
  392.     dnp->flat->ypos = dnp->ypos;
  393.     /* get ready for stubs */
  394.     strcpy(snodename,dnodename);
  395.     snodename[0] = 'S'; /* change transit to stub */
  396.     dnamelen = strlen(dnodename);
  397.     /* now deal with stubs */
  398.     snum = 0;
  399.     sgp = dnp->sub;
  400.     while (sgp) {
  401.       Vertex *anp;
  402. copyedges(sgp,finalG,base);
  403. for (snn=0,snp=sgp->vertices; snn<sgp->n; snn++,snp++) {
  404.     /* name each node */
  405.     sprintf(snodename+dnamelen,"/%d.%d",snum,snn);
  406.     snp->flat->name = gb_save_string(snodename);
  407.                     /* and position it correctly */
  408.     snp->flat->xpos = snp->xpos + sgp->Gxoff;
  409.     snp->flat->ypos = snp->ypos + sgp->Gyoff;
  410.     assert(snp->flat->xpos < globscale);
  411.     assert(snp->flat->ypos < globscale);
  412.         } /* for each node of this stub */
  413. attachnode = gb_next_rand()%sgp->n;
  414.                 anp = finalG->vertices+(base+attachnode);
  415.         assert((dnp->flat-finalG->vertices) < (anp-finalG->vertices));
  416. gb_new_edge(dnp->flat,anp, idist(dnp->flat,anp));
  417.                 dnp->flat->arcs->policywt = ts;
  418.         (dnp->flat->arcs+1)->policywt = ts;
  419. base += sgp->n; /* account for this stub's nodes */
  420. sgp = sgp->link;
  421. snum++;
  422.     } /* for each stub graph of this node */
  423. }  /* for each node of this domain */
  424.    } /* for each domain */
  425.    if (base != totalnodes) {
  426. fprintf(stderr,"incorrect node total: base=%d, totalnodes=%dn",
  427. base,totalnodes);
  428. exit(3);
  429.    }
  430.    /* Now we have to place the top-level (interdomain) edges */
  431.    /* Can do this now because each "old" node has a pointer to */
  432.    /* corresponding node in the "flat" graph, also each node has*/
  433.    /* a hierarchical name. */
  434.    for (dom=0,v=topG->vertices; dom<topG->n; dom++,v++) { /* for each domain */
  435. dgp = v->sub;
  436. for (a=v->arcs;a;a=a->next) {  /* add edges to other domains */
  437.     /* choose an endpoint in each graph */
  438.     dnp = dgp->vertices + (gb_next_rand()%dgp->n);
  439.     ddgp = a->tip->sub;
  440.     ddnp = ddgp->vertices + (gb_next_rand()%ddgp->n);
  441.     fp = dnp->flat;
  442.     tp = ddnp->flat;
  443.     if (tp < fp) {
  444.       tmp = fp;
  445.       fp = tp;
  446.       tp = tmp;
  447.     }
  448.     gb_new_edge(fp,tp,idist(fp,tp));
  449.     /* fp < tp */
  450.     fp->arcs->policywt = tt;
  451.     (fp->arcs+1)->policywt = tt;
  452.         }
  453.    }
  454.    /* Next add some RANDOM transit-stub edges. */
  455.    for (i=0; i<nrants; i++) {
  456. dnp = topG->vertices + (gb_next_rand()%topG->n); /*choose dom*/
  457. dgp = dnp->sub;
  458. dnp = dgp->vertices[gb_next_rand()%dgp->n].flat; /* and a node */
  459. assert(dnp->name[0]=='T'); /* sanity check */
  460. do { /* choose S node NOT already connected to this T dom node */
  461.    snp = finalG->vertices + (gb_next_rand()%finalG->n);
  462. } while (!td_OK(snp,dnp));
  463. if (snp < dnp) {     /* we require dnp < snp */
  464.   tmp = dnp;
  465.   dnp = snp;
  466.   snp = tmp;
  467. }
  468. gb_new_edge(dnp,snp,idist(dnp,snp));
  469. dnp->arcs->policywt = ts;
  470. (dnp->arcs+1)->policywt = ts;
  471.    }
  472.    /* Next, add some RANDOM stub-stub edges. */
  473.    /* Don't add edges between nodes in the same stub domain; */
  474.    /* anything else is OK. */
  475.    for (i=0; i<nranss; i++) {
  476. do {
  477.     /* pick two nodes at random that aren't in the same stub */
  478.     dnp = finalG->vertices + (gb_next_rand()%finalG->n);
  479.     ddnp = finalG->vertices + (gb_next_rand()%finalG->n);
  480. } while (!stubs_OK(dnp,ddnp));
  481. if (ddnp < dnp) {  /* required is dnp < ddnp */
  482.   tmp = dnp;
  483.   dnp = ddnp;
  484.   ddnp = dnp;
  485. }
  486. gb_new_edge(dnp,ddnp,idist(dnp,ddnp));
  487. /* fp < tp */
  488. dnp->arcs->policywt = ss;
  489. (dnp->arcs+1)->policywt = ss;
  490.    }
  491.    /* Finally, put the parameter info in the "id" string of the new graph */
  492.    sprintf(finalG->id,"transtub(%ld,%d,%d,%d,",
  493. seed,spx,nrants,nranss);
  494.    i = strlen(finalG->id);
  495.    i += printparms(dnodename,toppp);
  496.    if (i<ID_FIELD_SIZE) {
  497. strcat(finalG->id,dnodename);
  498. finalG->id[i++] = ',';
  499. finalG->id[i] = (char) 0;
  500.         i += printparms(dnodename,transpp);
  501.         if (i<ID_FIELD_SIZE) {
  502.     strcat(finalG->id,dnodename);
  503.     finalG->id[i++] = ',';
  504.     finalG->id[i] = (char) 0;
  505.     i += printparms(dnodename,stubpp);
  506.             if (i<ID_FIELD_SIZE) {
  507. strcat(finalG->id,dnodename);
  508. finalG->id[i++] = ')';
  509.                 if (i<ID_FIELD_SIZE)
  510.     finalG->id[i] = (char) 0;
  511.     } else {
  512. strncat(finalG->id,dnodename,
  513. (ID_FIELD_SIZE-strlen(finalG->id)));
  514.     }
  515.         } else
  516.     finalG->id[strlen(finalG->id)] = (char) 0;
  517.    } else
  518. finalG->id[strlen(finalG->id)] = (char) 0;
  519.    strcpy(finalG->util_types,TS_UTIL);
  520.    finalG->Gscale = globscale; /* uu */
  521.    finalG->MaxTdiam = transdiam; /* xx */
  522.    finalG->MaxSdiam = stubdiam; /* yy */
  523.    finalG->Topdiam = topdiam; /* zz */
  524.    /* CLEAN UP: free up all the memory we grabbed. */
  525.    for (v=topG->vertices; v<topG->vertices+topG->n; v++) {
  526. dgp = v->sub;
  527. for (dnp = dgp->vertices; dnp<dgp->vertices+dgp->n; dnp++) {
  528.     sgp = NULL;
  529.     tempg = dnp->sub;
  530.     while (tempg) {
  531. sgp = tempg;
  532. tempg = tempg->link;
  533. gb_recycle(sgp);
  534.     }
  535. }
  536. gb_recycle(dgp);
  537.    }
  538.    gb_recycle(topG);
  539.    free((char *)nstubnodes);
  540.    free((char *)nstubs);
  541.    free((char *)nnodes); /* free the last little bit */
  542.    /* return the new graph! */
  543.    return finalG;
  544. }  /* ts() */
  545. /* return true if it's OK to put an edge between stub node snp and */
  546. /* transit node dnp.   The criteria are: */
  547. /*    - snp is a stub node */
  548. /*    - dnp is a transit node  */
  549. /*    - the stub domain is not administratively "under" this transit    */
  550. /*      node. */
  551. int
  552. td_OK(Vertex *snp,Vertex *dnp)
  553. {
  554. int dlen, slen;
  555.     if (*snp->name != 'S') return 0;
  556.     dlen = strlen(dnp->name+2);
  557.     slen = strcspn(snp->name+2,"/");
  558.     /* if the domain prefix is the same, it's NOT OK */
  559.     return ((dlen != slen) || strncmp(dnp->name+2,snp->name+2,dlen));
  560. }
  561. /* OK to put an extra edge between two stub nodes, as long as they are */
  562. /* not already in the same stub domain.  This is checked by the initial */
  563. /* prefix of their names, i.e. the part before the final '.' */
  564. /* if these two strings differ, it's OK. */
  565. int
  566. stubs_OK(Vertex *snp0,Vertex *snp1)
  567. {
  568. int slen0, slen1;
  569. char *cp;
  570.     if (*snp0->name != 'S' ||
  571.         *snp1->name != 'S')
  572. return 0;
  573.     /* find the last occurrence of "." in each string */
  574.     /* I don't trust strrchr(), gdb doesn't seem to either */
  575.     slen0 = strlen(snp0->name);
  576.     cp = snp0->name + slen0; /* initially points to null */
  577.     while (*cp != '.' && --cp > snp0->name) slen0--;
  578.     slen1 = strlen(snp0->name);
  579.     cp = snp1->name + slen1; /* initially points to null */
  580.     while (*cp != '.' && --cp > snp1->name) slen1--;
  581.     /* strncmp returns nonzero if strings differ, which means "OK" */
  582.     return strncmp(snp0->name,snp1->name,(slen0>slen1?slen1:slen0));
  583. }