/* clustNode: * Generate a special cluster node representing the end node * of an edge to the cluster cg. n is a node whose name is the same * as the cluster cg. clg is the subgraph of all of * the original nodes, which will be deleted later. */ static node_t *clustNode(node_t * n, graph_t * cg, agxbuf * xb, graph_t * clg) { node_t *cn; static int idx = 0; char num[100]; agxbput(xb, "__"); sprintf(num, "%d", idx++); agxbput(xb, num); agxbputc(xb, ':'); agxbput(xb, cg->name); cn = agnode(cg->root, agxbuse(xb)); SET_CLUST_NODE(cn); aginsert(cg, cn); aginsert(clg, n); /* set attributes */ N_label = setAttr(cn->graph, cn, "label", "", N_label); N_style = setAttr(cn->graph, cn, "style", "invis", N_style); N_shape = setAttr(cn->graph, cn, "shape", "box", N_shape); /* N_width = setAttr (cn->graph, cn, "width", "0.0001", N_width); */ return cn; }
/* 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; }
/* mapN: * Convert cluster nodes back to ordinary nodes * If n is already ordinary, return it. * Otherwise, we know node's name is "__i:xxx" * where i is some number and xxx is the nodes's original name. * Create new node of name xxx if it doesn't exist and add n to clg * for later deletion. */ static node_t *mapN(node_t * n, graph_t * clg) { extern Agdict_t *agdictof(void *); node_t *nn; char *name; graph_t *g = n->graph; Agdict_t *d; Agsym_t **list; Agsym_t *sym; if (!(IS_CLUST_NODE(n))) return n; aginsert(clg, n); name = strchr(n->name, ':'); assert(name); name++; if ((nn = agfindnode(g, name))) return nn; nn = agnode(g, name); /* Set all attributes to default */ d = agdictof(n); list = d->list; while ((sym = *list++)) { /* Can use pointer comparison because of ref strings. */ if (agxget(nn, sym->index) != sym->value) agxset(nn, sym->index, sym->value); } return nn; }
static void node_induce(graph_t * par, graph_t * g) { node_t *n, *nn; edge_t *e; int i; /* enforce that a node is in at most one cluster at this level */ for (n = agfstnode(g); n; n = nn) { nn = agnxtnode(g, n); if (ND_ranktype(n)) { agdelete(g, n); continue; } for (i = 1; i < GD_n_cluster(par); i++) if (agcontains(GD_clust(par)[i], n)) break; if (i < GD_n_cluster(par)) agdelete(g, n); ND_clust(n) = NULL; } for (n = agfstnode(g); n; n = agnxtnode(g, n)) { for (e = agfstout(agroot(g), n); e; e = agnxtout(agroot(g), e)) { if (agcontains(g, aghead(e))) #ifndef WITH_CGRAPH aginsert(g, e); #else /* WITH_CGRAPH */ agsubedge(g,e,1); #endif /* WITH_CGRAPH */ } } }
/* spanning_tree: * Construct spanning forest of g as subgraph */ static Agraph_t *spanning_tree(Agraph_t * g) { Agnode_t *n; Agraph_t *tree; char gname[SMALLBUF]; static int id = 0; sprintf(gname, "_span_%d", id++); tree = agsubg(g, gname); for (n = agfstnode(g); n; n = agnxtnode(g, n)) { aginsert(tree, n); DISTONE(n) = 0; DISTTWO(n) = 0; UNSET_VISITED(n); } for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (!VISITED(n)) { TPARENT(n) = NULL; dfs(g, n, tree); } } return tree; }
/* block_graph: * Add induced edges. */ static void block_graph(Agraph_t * g, block_t * sn) { Agnode_t *n; Agedge_t *e; Agraph_t *subg = sn->sub_graph; for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) { for (e = agfstout(g, n); e; e = agnxtout(g, e)) { if (BLOCK(e->head) == sn) aginsert(subg, e); } } }
static void dfs(Agraph_t * g, Agnode_t * n, Agraph_t * out, char *marks) { Agedge_t *e; Agnode_t *other; MARK(n) = 1; #ifndef WITH_CGRAPH aginsert(out, n); #else /* WITH_CGRAPH */ agsubnode(out,n,1); #endif /* WITH_CGRAPH */ for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) { if ((other = agtail(e)) == n) other = aghead(e); if (!MARK(other)) dfs(g, other, out, marks); } }
/* dfs: * Simple depth first search, adding traversed edges to tree. */ static void dfs(Agraph_t * g, Agnode_t * n, Agraph_t * tree) { Agedge_t *e; Agnode_t *neighbor; SET_VISITED(n); for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) { neighbor = e->head; if (neighbor == n) neighbor = e->tail; if (!VISITED(neighbor)) { /* add the edge to the dfs tree */ aginsert(tree, e); TPARENT(neighbor) = n; dfs(g, neighbor, tree); } } }
static void addNode(block_t * bp, Agnode_t * n) { aginsert(bp->sub_graph, n); SET_BCDONE(n); BLOCK(n) = bp; }