/* clone_graph: * Create two copies of the argument graph * One is a subgraph, the other is an actual copy since we will be * adding edges to it. */ static Agraph_t* clone_graph(Agraph_t* ing, Agraph_t** xg) { Agraph_t* clone; Agraph_t* xclone; Agnode_t* n; Agnode_t* xn; Agnode_t* xh; Agedge_t* e; Agedge_t* xe; char gname[SMALLBUF]; static int id = 0; sprintf (gname, "_clone_%d", id++); clone = agsubg(ing, gname); sprintf (gname, "_clone_%d", id++); xclone = agopen(gname, ing->kind); for(n = agfstnode(ing); n; n = agnxtnode(ing, n)) { aginsert (clone, n); xn = agnode (xclone, n->name); CLONE(n) = xn; } for(n = agfstnode(ing); n; n = agnxtnode(ing, n)) { xn = CLONE(n); for(e = agfstout(ing, n); e; e = agnxtout(ing, e)) { aginsert (clone, e); xh = CLONE(e->head); xe = agedge (xclone, xn, xh); ORIGE(xe) = e; DEGREE(xn) += 1; DEGREE(xh) += 1; } } *xg = xclone; #ifdef OLD clone = agopen("clone", root->kind); for(n = agfstnode(root); n; n = agnxtnode(root, n)) { cn = agnode(clone, n->name); ND_alg(cn) = DATA(n); BCDONE(cn) = 0; } for(n = agfstnode(root); n; n = agnxtnode(root, n)) { Agnode_t *t = agnode(clone, n); for(e = agfstout(root, n); e; e = agnxtout(root, e)) { Agnode_t *h = agnode(clone, e->head->name); agedge(clone, t, h); } } #endif return clone; }
/* dfs: * * Current scheme adds articulation point to first non-trivial child * block. If none exists, it will be added to its parent's block, if * non-trivial, or else given its own block. * * FIX: * This should be modified to: * - allow user to specify which block gets a node, perhaps on per-node basis. * - if an articulation point is not used in one of its non-trivial blocks, * dummy edges should be added to preserve biconnectivity * - turn on user-supplied blocks. * */ static void dfs(Agraph_t * g, Agnode_t * n, circ_state * state, int isRoot) { Agedge_t *e; Agnode_t *curtop; LOWVAL(n) = VAL(n) = state->orderCount++; stackPush(state->bcstack, n); for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) { Agnode_t *neighbor = e->head; if (neighbor == n) neighbor = e->tail; if (neighbor == PARENT(n)) continue; if (VAL(neighbor)) { LOWVAL(n) = min_value(LOWVAL(n), VAL(neighbor)); continue; } if (!stackCheck(state->bcstack, n)) { stackPush(state->bcstack, n); } PARENT(neighbor) = n; curtop = top(state->bcstack); dfs(g, neighbor, state, 0); LOWVAL(n) = min_value(LOWVAL(n), LOWVAL(neighbor)); if (LOWVAL(neighbor) >= VAL(n)) { block_t *block = NULL; Agnode_t *np; if (top(state->bcstack) != curtop) do { np = stackPop(state->bcstack); if (!BCDONE(np)) { if (!block) block = makeBlock(g, state); addNode(block, np); } } while (np != n); if (block) { /* If block != NULL, it's not empty */ if (isRoot && (BLOCK(n) == block)) insertBlock(&state->bl, block); else appendBlock(&state->bl, block); } if ((LOWVAL(n) < VAL(n)) && (!stackCheck(state->bcstack, n))) { stackPush(state->bcstack, n); } } } if ((LOWVAL(n) == VAL(n)) && !BCDONE(n)) { block_t *block = makeBlock(g, state); stackPop(state->bcstack); addNode(block, n); if (isRoot) insertBlock(&state->bl, block); else appendBlock(&state->bl, block); } }
/* find_blocks: */ static void find_blocks(Agraph_t * g, circ_state * state) { Agnode_t *n; Agnode_t *root = NULL; block_t *rootBlock = NULL; blocklist_t ublks; #ifdef USER_BLOCKS graph_t *clust_subg; graph_t *mg; edge_t *me; node_t *mm; int isRoot; #endif initBlocklist(&ublks); /* check to see if there is a node which is set to be the root */ if (state->rootname) { root = agfindnode(g, state->rootname); } if (!root && state->N_root) { for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (late_bool(ORIGN(n), state->N_root, 0)) { root = n; break; } } } #ifdef USER_BLOCKS /* process clusters first */ /* by construction, all subgraphs are blocks and are non-empty */ mm = g->meta_node; mg = mm->graph; for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) { block_t *block; clust_subg = agusergraph(me->head); isRoot = 0; block = mkBlock(clust_subg); /* block = makeBlock(g, state); */ for (n = agfstnode(clust_subg); n; n = agnxtnode(clust_subg, n)) { if (!BCDONE(n)) { /* test not necessary if blocks disjoint */ SET_BCDONE(n); BLOCK(n) = block; if (n == root) isRoot = 1; } } if (isRoot) { /* Assume blocks are disjoint, so don't check if rootBlock is * already assigned. */ rootBlock = block; insertBlock(&state->bl, block); } else { appendBlock(&state->bl, block); } } ublks.first = state->bl.first; ublks.last = state->bl.last; #endif if (!root) root = agfstnode(g); dfs(g, root, state, !rootBlock); #ifdef USER_BLOCKS /* If g has user-supplied blocks, it may be disconnected. * We then fall into the following ugly loop. * We are guaranteed !VISITED(n) and PARENT(n) has been * set to a visited node. */ if (ublks.first) { while (n = findUnvisited(&ublks)) { dfs(g, n, state, 0); } } #endif }