Graphviz 2.29.20120208.0545
lib/circogen/blocktree.c
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 
00015 #include "blocktree.h"
00016 
00017 static void addNode(block_t * bp, Agnode_t * n)
00018 {
00019 #ifndef WITH_CGRAPH
00020     aginsert(bp->sub_graph, n);
00021 #else /* WITH_CGRAPH */
00022     agsubnode(bp->sub_graph, n,1);
00023 #endif /* WITH_CGRAPH */
00024     BLOCK(n) = bp;
00025 }
00026 
00027 static Agraph_t *makeBlockGraph(Agraph_t * g, circ_state * state)
00028 {
00029     char name[SMALLBUF];
00030     Agraph_t *subg;
00031 
00032     sprintf(name, "_block_%d", state->blockCount++);
00033 #ifndef WITH_CGRAPH
00034     subg = agsubg(g, name);
00035 #else /* WITH_CGRAPH */
00036     subg = agsubg(g, name,1);
00037     agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE);        //node custom data
00038 #endif /* WITH_CGRAPH */
00039     return subg;
00040 }
00041 
00042 static block_t *makeBlock(Agraph_t * g, circ_state * state)
00043 {
00044     Agraph_t *subg = makeBlockGraph(g, state);
00045     block_t *bp = mkBlock(subg);
00046 
00047     return bp;
00048 }
00049 
00050 typedef struct {
00051     Agedge_t *top;
00052     int sz;
00053 } estack;
00054 
00055 static void
00056 push (estack* s, Agedge_t* e)
00057 {
00058     ENEXT(e) = s->top;
00059     s->top = e;
00060     s->sz += 1;
00061 }
00062 
00063 static Agedge_t*
00064 pop (estack* s)
00065 {
00066     Agedge_t *top = s->top;
00067 
00068     if (top) {
00069         assert(s->sz > 0);
00070         s->top = ENEXT(top);
00071         s->sz -= 1;
00072     } else {
00073         assert(0);
00074     }
00075 
00076     return top;
00077 }
00078 
00079 
00080 /* dfs:
00081  *
00082  * Current scheme adds articulation point to first non-trivial child
00083  * block. If none exists, it will be added to its parent's block, if
00084  * non-trivial, or else given its own block.
00085  *
00086  * FIX:
00087  * This should be modified to:
00088  *  - allow user to specify which block gets a node, perhaps on per-node basis.
00089  *  - if an articulation point is not used in one of its non-trivial blocks,
00090  *    dummy edges should be added to preserve biconnectivity
00091  *  - turn on user-supplied blocks.
00092  *  - Post-process to move articulation point to largest block
00093  */
00094 static void dfs(Agraph_t * g, Agnode_t * u, circ_state * state, int isRoot, estack* stk)
00095 {
00096     Agedge_t *e;
00097     Agnode_t *v;
00098 
00099     LOWVAL(u) = VAL(u) = state->orderCount++;
00100     for (e = agfstedge(g, u); e; e = agnxtedge(g, e, u)) {
00101         v = aghead (e);
00102         if (v == u) {
00103             v = agtail(e);
00104             if (!EDGEORDER(e)) EDGEORDER(e) = -1;
00105         }
00106         else {
00107             if (!EDGEORDER(e)) EDGEORDER(e) = 1;
00108         }
00109 
00110         if (VAL(v) == 0) {   /* Since VAL(root) == 0, it gets treated as artificial cut point */
00111             PARENT(v) = u;
00112             push(stk, e);
00113             dfs(g, v, state, 0, stk);
00114             LOWVAL(u) = MIN(LOWVAL(u), LOWVAL(v));
00115             if (LOWVAL(v) >= VAL(u)) {       /* u is an articulation point */
00116                 block_t *block = NULL;
00117                 Agnode_t *np;
00118                 Agedge_t *ep;
00119                 do {
00120                     ep = pop(stk);
00121                     if (EDGEORDER(ep) == 1)
00122                         np = aghead (ep);
00123                     else
00124                         np = agtail (ep);
00125                     if (!BLOCK(np)) {
00126                         if (!block)
00127                             block = makeBlock(g, state);
00128                         addNode(block, np);
00129                     }
00130                 } while (ep != e);
00131                 if (block) {    /* If block != NULL, it's not empty */
00132                     if (!BLOCK(u) && blockSize (block) > 1)
00133                         addNode(block, u);
00134                     if (isRoot && (BLOCK(u) == block))
00135                         insertBlock(&state->bl, block);
00136                     else
00137                         appendBlock(&state->bl, block);
00138                 }
00139             }
00140         } else if (PARENT(u) != v) {
00141             LOWVAL(u) = MIN(LOWVAL(u), VAL(v));
00142         }
00143     }
00144     if (isRoot && !BLOCK(u)) {
00145         block_t *block = makeBlock(g, state);
00146         addNode(block, u);
00147         insertBlock(&state->bl, block);
00148     }
00149 }
00150 
00151 
00152 /* find_blocks:
00153  */
00154 static void find_blocks(Agraph_t * g, circ_state * state)
00155 {
00156     Agnode_t *n;
00157     Agnode_t *root = NULL;
00158     estack stk;
00159 
00160     /*      check to see if there is a node which is set to be the root
00161      */
00162     if (state->rootname) {
00163         root = agfindnode(g, state->rootname);
00164     }
00165     if (!root && state->N_root) {
00166         for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00167             if (late_bool(ORIGN(n), state->N_root, 0)) {
00168                 root = n;
00169                 break;
00170             }
00171         }
00172     }
00173 
00174     if (!root)
00175         root = agfstnode(g);
00176     if (Verbose)
00177         fprintf (stderr, "root = %s\n", agnameof(root));
00178     stk.sz = 0;
00179     stk.top = NULL;
00180     dfs(g, root, state, 1, &stk);
00181 
00182 }
00183 
00184 /* create_block_tree:
00185  * Construct block tree by peeling nodes from block list in state.
00186  * When done, return root. The block list is empty
00187  * FIX: use largest block as root
00188  */
00189 block_t *createBlocktree(Agraph_t * g, circ_state * state)
00190 {
00191     block_t *bp;
00192     block_t *next;
00193     block_t *root;
00194     int min;
00195     /* int        ordercnt; */
00196 
00197     find_blocks(g, state);
00198 
00199     bp = state->bl.first;       /* if root chosen, will be first */
00200     /* Otherwise, just pick first as root */
00201     root = bp;
00202 
00203     /* Find node with minimum VAL value to find parent block */
00204     /* FIX: Should be some way to avoid search below.               */
00205     /* ordercnt = state->orderCount;  */
00206     for (bp = bp->next; bp; bp = next) {
00207         Agnode_t *n;
00208         Agnode_t *parent;
00209         Agnode_t *child;
00210         Agraph_t *subg = bp->sub_graph;
00211 
00212         child = n = agfstnode(subg);
00213 
00214         min = VAL(n);
00215         parent = PARENT(n);
00216         for (n = agnxtnode(subg, n); n; n = agnxtnode(subg, n)) {
00217             if (VAL(n) < min) {
00218                 child = n;
00219                 min = VAL(n);
00220                 parent = PARENT(n);
00221             }
00222         }
00223         SET_PARENT(parent);
00224         CHILD(bp) = child;
00225         next = bp->next;        /* save next since list insertion destroys it */
00226         appendBlock(&(BLOCK(parent)->children), bp);
00227     }
00228     initBlocklist(&state->bl);  /* zero out list */
00229     return root;
00230 }
00231 
00232 void freeBlocktree(block_t * bp)
00233 {
00234     block_t *child;
00235     block_t *next;
00236 
00237     for (child = bp->children.first; child; child = next) {
00238         next = child->next;
00239         freeBlocktree(child);
00240     }
00241 
00242     freeBlock(bp);
00243 }
00244 
00245 #ifdef DEBUG
00246 static void indent(int i)
00247 {
00248     while (i--)
00249         fputs("  ", stderr);
00250 }
00251 
00252 void print_blocktree(block_t * sn, int depth)
00253 {
00254     block_t *child;
00255     Agnode_t *n;
00256     Agraph_t *g;
00257 
00258     indent(depth);
00259     g = sn->sub_graph;
00260     fprintf(stderr, "%s:", g->name);
00261     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00262         fprintf(stderr, " %s", n->name);
00263     }
00264     fputs("\n", stderr);
00265 
00266     depth++;
00267     for (child = sn->children.first; child; child = child->next) {
00268         print_blocktree(child, depth);
00269     }
00270 }
00271 
00272 #endif