/* * attach and install edges between clusters. * essentially, class2() for interclust edges. */ void interclexp(graph_t* subg) { graph_t *g; node_t *n; edge_t *e,*prev; g = subg->root; for (n = agfstnode(subg); n; n = agnxtnode(subg,n)) { /* N.B. n may be in a sub-cluster of subg */ prev = NULL; for (e = agfstedge(subg->root,n); e; e = agnxtedge(subg->root,e,n)) { if (agcontains(subg,e)) continue; /* short/flat multi edges */ if (mergeable(prev,e)) { if (e->tail->u.rank == e->head->u.rank) e->u.to_virt = prev; else e->u.to_virt = NULL; if (prev->u.to_virt == NULL) continue; /* internal edge */ merge_chain(subg,e,prev->u.to_virt,FALSE); safe_other_edge(e); continue; } /* flat edges */ if (e->tail->u.rank == e->head->u.rank) { if (find_flat_edge(e->tail,e->head) == NULL) { flat_edge(g,e); prev = e; } else prev = NULL; continue; } assert (e->u.to_virt != NULL); /* forward edges */ if (e->head->u.rank > e->tail->u.rank) { make_interclust_chain(g,e->tail,e->head,e); prev = e; continue; } /* backward edges */ else { /* I think that make_interclust_chain should create call other_edge(e) anyway if (agcontains(subg,e->tail) && agfindedge(subg->root,e->head,e->tail)) other_edge(e); */ make_interclust_chain(g,e->head,e->tail,e); prev = e; } } } }
/* * attach and install edges between clusters. * essentially, class2() for interclust edges. */ void interclexp(graph_t * subg) { graph_t *g; node_t *n; edge_t *e, *prev, *next; g = agroot(subg); for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) { /* N.B. n may be in a sub-cluster of subg */ prev = NULL; for (e = agfstedge(agroot(subg), n); e; e = next) { next = agnxtedge(agroot(subg), e, n); if (agcontains(subg, e)) continue; #ifdef WITH_CGRAPH /* canonicalize edge */ e = AGMKOUT(e); #endif /* short/flat multi edges */ if (mergeable(prev, e)) { if (ND_rank(agtail(e)) == ND_rank(aghead(e))) ED_to_virt(e) = prev; else ED_to_virt(e) = NULL; if (ED_to_virt(prev) == NULL) continue; /* internal edge */ merge_chain(subg, e, ED_to_virt(prev), FALSE); safe_other_edge(e); continue; } /* flat edges */ if (ND_rank(agtail(e)) == ND_rank(aghead(e))) { edge_t* fe; if ((fe = find_flat_edge(agtail(e), aghead(e))) == NULL) { flat_edge(g, e); prev = e; } else if (e != fe) { safe_other_edge(e); if (!ED_to_virt(e)) merge_oneway(e, fe); } continue; } /* This assertion is still valid if the new ranking is not used */ #ifndef WITH_CGRAPH assert(ED_to_virt(e) != NULL); #endif /* forward edges */ if (ND_rank(aghead(e)) > ND_rank(agtail(e))) { make_interclust_chain(g, agtail(e), aghead(e), e); prev = e; continue; } /* backward edges */ else { /* I think that make_interclust_chain should create call other_edge(e) anyway if (agcontains(subg,agtail(e)) && agfindedge(subg->root,aghead(e),agtail(e))) other_edge(e); */ make_interclust_chain(g, aghead(e), agtail(e), e); prev = e; } } } }
void class2(graph_t* g) { int c; node_t *n,*t,*h; edge_t *e,*prev,*opp; g->u.nlist = NULL; g->u.n_nodes = 0; /* new */ mark_clusters(g); for (c = 1; c <= g->u.n_cluster; c++) build_skeleton(g,g->u.clust[c]); for (n = agfstnode(g); n; n = agnxtnode(g,n)) for (e = agfstout(g,n); e; e = agnxtout(g,e)) { if (e->head->u.weight_class <= 2) e->head->u.weight_class++; if (e->tail->u.weight_class <= 2) e->tail->u.weight_class++; } for (n = agfstnode(g); n; n = agnxtnode(g,n)) { if ((n->u.clust == NULL) && (n == UF_find(n))) {fast_node(g,n); g->u.n_nodes++;} prev = NULL; for (e = agfstout(g,n); e; e = agnxtout(g,e)) { /* already processed */ if (e->u.to_virt) continue; /* edges involving sub-clusters of g */ if (is_cluster_edge(e)) { /* following is new cluster multi-edge code */ if (mergeable(prev,e)) { if (prev->u.to_virt) { merge_chain(g,e,prev->u.to_virt,FALSE); other_edge(e); } else if (e->tail->u.rank == e->head->u.rank) { merge_oneway(e,prev); other_edge(e); } /* else is an intra-cluster edge */ continue; } interclrep(g,e); prev = e; continue; } /* merge multi-edges */ if (prev && (e->tail == prev->tail) && (e->head == prev->head)) { if (e->tail->u.rank == e->head->u.rank) { merge_oneway(e,prev); other_edge(e); continue; } if ((e->u.label == NULL) && (prev->u.label == NULL) && ports_eq(e,prev)) { if (Concentrate) e->u.edge_type = IGNORED; else{ merge_chain(g,e,prev->u.to_virt,TRUE); other_edge(e); } continue; } /* parallel edges with different labels fall through here */ } /* self edges */ if (e->tail == e->head) { other_edge(e); prev = e; continue; } t = UF_find(e->tail); h = UF_find(e->head); /* non-leader leaf nodes */ if ((e->tail != t) || (e->head != h)) { /* ### need to merge stuff */ continue; } /* flat edges */ if (e->tail->u.rank == e->head->u.rank) { flat_edge(g,e); prev = e; continue; } /* forward edges */ if (e->head->u.rank > e->tail->u.rank) { make_chain(g,e->tail,e->head,e); prev = e; continue; } /* backward edges */ else { /*other_edge(e);*/ if ((opp = agfindedge(g,e->head,e->tail))) { /* shadows a forward edge */ if (opp->u.to_virt == NULL) make_chain(g,opp->tail,opp->head,opp); if ((e->u.label == NULL) && (opp->u.label == NULL) && ports_eq(e,opp)) { if (Concentrate) { e->u.edge_type = IGNORED; opp->u.conc_opp_flag = TRUE; } else{ /* see above. this is getting out of hand */ other_edge(e); merge_chain(g,e,opp->u.to_virt,TRUE); } continue; } } make_chain(g,e->head,e->tail,e); prev = e; } } } /* since decompose() is not called on subgraphs */ if (g != g->root) { g->u.comp.list = ALLOC(1,g->u.comp.list,node_t*); g->u.comp.list[0] = g->u.nlist; }