/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/circogen/blocktree.c

Go to the documentation of this file.
00001 /* $Id: blocktree.c,v 1.2 2006/05/21 06:33:19 ellson Exp $ $Revision: 1.2 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 
00018 #include "blocktree.h"
00019 
00020 static int min_value(int x, int y)
00021 {
00022     if (x < y)
00023         return x;
00024     return y;
00025 }
00026 
00027 static void addNode(block_t * bp, Agnode_t * n)
00028 {
00029     aginsert(bp->sub_graph, n);
00030     SET_BCDONE(n);
00031     BLOCK(n) = bp;
00032 }
00033 
00034 static Agraph_t *makeBlockGraph(Agraph_t * g, circ_state * state)
00035 {
00036     char name[SMALLBUF];
00037     Agraph_t *subg;
00038 
00039     sprintf(name, "_block_%d", state->blockCount++);
00040     subg = agsubg(g, name);
00041     return subg;
00042 }
00043 
00044 static block_t *makeBlock(Agraph_t * g, circ_state * state)
00045 {
00046     Agraph_t *subg = makeBlockGraph(g, state);
00047     block_t *bp = mkBlock(subg);
00048 
00049     return bp;
00050 }
00051 
00052 /* dfs:
00053  *
00054  * Current scheme adds articulation point to first non-trivial child
00055  * block. If none exists, it will be added to its parent's block, if
00056  * non-trivial, or else given its own block.
00057  *
00058  * FIX:
00059  * This should be modified to:
00060  *  - allow user to specify which block gets a node, perhaps on per-node basis.
00061  *  - if an articulation point is not used in one of its non-trivial blocks,
00062  *    dummy edges should be added to preserve biconnectivity
00063  *  - turn on user-supplied blocks.
00064  *
00065  */
00066 static void dfs(Agraph_t * g, Agnode_t * n, circ_state * state, int isRoot)
00067 {
00068     Agedge_t *e;
00069     Agnode_t *curtop;
00070 
00071     LOWVAL(n) = VAL(n) = state->orderCount++;
00072 
00073     stackPush(state->bcstack, n);
00074 
00075     for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
00076         Agnode_t *neighbor = e->head;
00077         if (neighbor == n)
00078             neighbor = e->tail;
00079 
00080         if (neighbor == PARENT(n))
00081             continue;
00082 
00083         if (VAL(neighbor)) {
00084             LOWVAL(n) = min_value(LOWVAL(n), VAL(neighbor));
00085             continue;
00086         }
00087         if (!stackCheck(state->bcstack, n)) {
00088             stackPush(state->bcstack, n);
00089         }
00090 
00091         PARENT(neighbor) = n;
00092         curtop = top(state->bcstack);
00093         dfs(g, neighbor, state, 0);
00094 
00095         LOWVAL(n) = min_value(LOWVAL(n), LOWVAL(neighbor));
00096         if (LOWVAL(neighbor) >= VAL(n)) {
00097             block_t *block = NULL;
00098             Agnode_t *np;
00099             if (top(state->bcstack) != curtop)
00100                 do {
00101                     np = stackPop(state->bcstack);
00102                     if (!BCDONE(np)) {
00103                         if (!block)
00104                             block = makeBlock(g, state);
00105                         addNode(block, np);
00106                     }
00107                 } while (np != n);
00108             if (block) {        /* If block != NULL, it's not empty */
00109                 if (isRoot && (BLOCK(n) == block))
00110                     insertBlock(&state->bl, block);
00111                 else
00112                     appendBlock(&state->bl, block);
00113             }
00114             if ((LOWVAL(n) < VAL(n)) && (!stackCheck(state->bcstack, n))) {
00115                 stackPush(state->bcstack, n);
00116             }
00117         }
00118     }
00119     if ((LOWVAL(n) == VAL(n)) && !BCDONE(n)) {
00120         block_t *block = makeBlock(g, state);
00121         stackPop(state->bcstack);
00122         addNode(block, n);
00123         if (isRoot)
00124             insertBlock(&state->bl, block);
00125         else
00126             appendBlock(&state->bl, block);
00127     }
00128 }
00129 
00130 #ifdef USER_BLOCKS
00131 /* findUnvisited:
00132  * Look for unvisited node n in visited block (i.e., some nodes in
00133  * the block have been visited) with neighbor not in block. Note
00134  * that therefore neighbor is unvisited. Set neighbor's parent to n
00135  * and return neighbor.
00136  * Guaranteed blp is non-empty.
00137  * 
00138  */
00139 static Agnode_t *findUnvisited(blocklist_t * blp)
00140 {
00141     Agnode_t *retn = NULL;
00142   FIX:finish Agnode_t * n;
00143     Agnode_t *newn;
00144     graph_t *clust_subg;
00145     edge_t *e;
00146     block_t *bp;
00147     block_t *prev = NULL;
00148 
00149     for (bp = blp->first; prev != blp->last; bp = bp->next) {
00150         prev = bp;
00151         clust = bp->sub_graph;
00152 
00153         if (DONE(bp))
00154             continue;
00155         if (PARTIAL(bp)) {
00156             for (n = agfstnode(clust); n; n = agnxtnode(clust, n)) {
00157                 if (!VISITED(n)) {
00158                     for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
00159                         newn = e->head;
00160                         if (newn == n)
00161                             newn = e->tail;
00162                         if ((BLOCK(newn) != bp)) {
00163                             retn = newn;
00164                             return;
00165                         }
00166                     }
00167                     /* mark n visited */
00168                 }
00169             }
00170             /* mark bp done */
00171         } else {
00172         }
00173     }
00174     return retn;
00175 }
00176 #endif
00177 
00178 /* find_blocks:
00179  */
00180 static void find_blocks(Agraph_t * g, circ_state * state)
00181 {
00182     Agnode_t *n;
00183     Agnode_t *root = NULL;
00184     block_t *rootBlock = NULL;
00185     blocklist_t ublks;
00186 #ifdef USER_BLOCKS
00187     graph_t *clust_subg;
00188     graph_t *mg;
00189     edge_t *me;
00190     node_t *mm;
00191     int isRoot;
00192 #endif
00193 
00194     initBlocklist(&ublks);
00195 
00196     /*      check to see if there is a node which is set to be the root
00197      */
00198     if (state->rootname) {
00199         root = agfindnode(g, state->rootname);
00200     }
00201     if (!root && state->N_root) {
00202         for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00203             if (late_bool(ORIGN(n), state->N_root, 0)) {
00204                 root = n;
00205                 break;
00206             }
00207         }
00208     }
00209 #ifdef USER_BLOCKS
00210     /* process clusters first */
00211     /* by construction, all subgraphs are blocks and are non-empty */
00212     mm = g->meta_node;
00213     mg = mm->graph;
00214     for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) {
00215         block_t *block;
00216 
00217         clust_subg = agusergraph(me->head);
00218 
00219         isRoot = 0;
00220         block = mkBlock(clust_subg);
00221         /* block = makeBlock(g, state); */
00222         for (n = agfstnode(clust_subg); n; n = agnxtnode(clust_subg, n)) {
00223             if (!BCDONE(n)) {   /* test not necessary if blocks disjoint */
00224                 SET_BCDONE(n);
00225                 BLOCK(n) = block;
00226                 if (n == root)
00227                     isRoot = 1;
00228             }
00229         }
00230         if (isRoot) {
00231             /* Assume blocks are disjoint, so don't check if rootBlock is
00232              * already assigned.
00233              */
00234             rootBlock = block;
00235             insertBlock(&state->bl, block);
00236         } else {
00237             appendBlock(&state->bl, block);
00238         }
00239     }
00240     ublks.first = state->bl.first;
00241     ublks.last = state->bl.last;
00242 #endif
00243 
00244     if (!root)
00245         root = agfstnode(g);
00246     dfs(g, root, state, !rootBlock);
00247 
00248 #ifdef USER_BLOCKS
00249     /* If g has user-supplied blocks, it may be disconnected.
00250      * We then fall into the following ugly loop.
00251      * We are guaranteed !VISITED(n) and PARENT(n) has been
00252      * set to a visited node.
00253      */
00254     if (ublks.first) {
00255         while (n = findUnvisited(&ublks)) {
00256             dfs(g, n, state, 0);
00257         }
00258     }
00259 #endif
00260 }
00261 
00262 /* create_block_tree:
00263  * Construct block tree by peeling nodes from block list in state.
00264  * When done, return root. The block list is empty
00265  * FIX: use largest block as root
00266  */
00267 block_t *createBlocktree(Agraph_t * g, circ_state * state)
00268 {
00269     block_t *bp;
00270     block_t *next;
00271     block_t *root;
00272     int min;
00273     /* int        ordercnt; */
00274 
00275     find_blocks(g, state);
00276 
00277     bp = state->bl.first;       /* if root chosen, will be first */
00278     /* Otherwise, just pick first as root */
00279     root = bp;
00280 
00281     /* Find node with minimum VAL value to find parent block */
00282     /* FIX: Should be some way to avoid search below.               */
00283     /* ordercnt = state->orderCount;  */
00284     for (bp = bp->next; bp; bp = next) {
00285         Agnode_t *n;
00286         Agnode_t *parent;
00287         Agnode_t *child;
00288         Agraph_t *subg = bp->sub_graph;
00289 
00290         child = n = agfstnode(subg);
00291         min = VAL(n);
00292         parent = PARENT(n);
00293         for (n = agnxtnode(subg, n); n; n = agnxtnode(subg, n)) {
00294             if (VAL(n) < min) {
00295                 child = n;
00296                 min = VAL(n);
00297                 parent = PARENT(n);
00298             }
00299         }
00300         SET_PARENT(parent);
00301         CHILD(bp) = child;
00302         next = bp->next;        /* save next since list insertion destroys it */
00303         appendBlock(&(BLOCK(parent)->children), bp);
00304     }
00305     initBlocklist(&state->bl);  /* zero out list */
00306     return root;
00307 }
00308 
00309 void freeBlocktree(block_t * bp)
00310 {
00311     block_t *child;
00312     block_t *next;
00313 
00314     for (child = bp->children.first; child; child = next) {
00315         next = child->next;
00316         freeBlocktree(child);
00317     }
00318 
00319     freeBlock(bp);
00320 }
00321 
00322 #ifdef DEBUG
00323 static void indent(int i)
00324 {
00325     while (i--)
00326         fputs("  ", stderr);
00327 }
00328 
00329 void print_blocktree(block_t * sn, int depth)
00330 {
00331     block_t *child;
00332     Agnode_t *n;
00333     Agraph_t *g;
00334 
00335     indent(depth);
00336     g = sn->sub_graph;
00337     fprintf(stderr, "%s:", g->name);
00338     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00339         fprintf(stderr, " %s", n->name);
00340     }
00341     fputs("\n", stderr);
00342 
00343     depth++;
00344     for (child = sn->children.first; child; child = child->next) {
00345         print_blocktree(child, depth);
00346     }
00347 }
00348 
00349 #endif

Generated on Mon Mar 31 19:03:23 2008 for Graphviz by  doxygen 1.5.1