/* cloneSubg: * Clone subgraph sg in tgt. */ static Agraph_t *cloneSubg(Agraph_t * tgt, Agraph_t * g, Dt_t* emap) { Agraph_t *ng; Agraph_t *sg; Agnode_t *t; Agnode_t *newt; Agedge_t *e; Agedge_t *newe; char* name; ng = (Agraph_t *) (copy(tgt, OBJ(g))); if (!ng) return 0; for (t = agfstnode(g); t; t = agnxtnode(g, t)) { newt = agnode(tgt, agnameof(t), 0); if (!newt) { exerror("node %s not found in cloned graph %s", agnameof(t), agnameof(tgt)); return 0; } else agsubnode(ng, newt, 1); } for (t = agfstnode(g); t; t = agnxtnode(g, t)) { for (e = agfstout(g, t); e; e = agnxtout(g, e)) { newe = mapEdge (emap, e); if (!newe) { name = agnameof(AGMKOUT(e)); if (name) exerror("edge (%s,%s)[%s] not found in cloned graph %s", agnameof(agtail(e)), agnameof(aghead(e)), name, agnameof(tgt)); else exerror("edge (%s,%s) not found in cloned graph %s", agnameof(agtail(e)), agnameof(aghead(e)), agnameof(tgt)); return 0; } else agsubedge(ng, newe, 1); } } for (sg = agfstsubg(g); sg; sg = agnxtsubg(sg)) { if (!cloneSubg(ng, sg, emap)) { exerror("error cloning subgraph %s from graph %s", agnameof(sg), agnameof(g)); return 0; } } return ng; }
/* clone: * Create new object of type AGTYPE(obj) with all of its * attributes and substructure. * If obj is an edge, end nodes are cloned if necessary. * If obj is a graph, if g is null, create a clone top-level * graph. Otherwise, create a clone subgraph of g. * Assume obj != NULL. */ Agobj_t *clone(Agraph_t * g, Agobj_t * obj) { Agobj_t *nobj = 0; Agedge_t *e; Agnode_t *h; Agnode_t *t; int kind = AGTYPE(obj); char *name; if ((kind != AGRAPH) && !g) { exerror("NULL graph with non-graph object in clone()"); return 0; } switch (kind) { case AGNODE: /* same as copy node */ name = agnameof(obj); nobj = (Agobj_t *) openNode(g, name); if (nobj) copyAttr(obj, nobj); break; case AGRAPH: name = agnameof(obj); if (g) nobj = (Agobj_t *) openSubg(g, name); else nobj = (Agobj_t *) openG(name, ((Agraph_t *) obj)->desc); if (nobj) { copyAttr(obj, nobj); cloneGraph((Agraph_t *) nobj, (Agraph_t *) obj); } break; case AGINEDGE: case AGOUTEDGE: e = (Agedge_t *) obj; t = (Agnode_t *) clone(g, OBJ(agtail(e))); h = (Agnode_t *) clone(g, OBJ(aghead(e))); name = agnameof (AGMKOUT(e)); nobj = (Agobj_t *) openEdge(g, t, h, name); if (nobj) copyAttr(obj, nobj); break; } return nobj; }
/* cloneGraph: * Clone node, edge and subgraph structure from src to tgt. */ static void cloneGraph(Agraph_t * tgt, Agraph_t * src) { Agedge_t *e; Agedge_t *ne; Agnode_t *t; Agraph_t *sg; char* name; Dt_t* emap = dtopen (&edgepair, Dtoset); edgepair_t* data = (edgepair_t*)malloc(sizeof(edgepair_t)*agnedges(src)); edgepair_t* ep = data; for (t = agfstnode(src); t; t = agnxtnode(src, t)) { if (!copy(tgt, OBJ(t))) { exerror("error cloning node %s from graph %s", agnameof(t), agnameof(src)); } } for (t = agfstnode(src); t; t = agnxtnode(src, t)) { for (e = agfstout(src, t); e; e = agnxtout(src, e)) { if (!(ne = (Agedge_t*)copy(tgt, OBJ(e)))) { name = agnameof(AGMKOUT(e)); if (name) exerror("error cloning edge (%s,%s)[%s] from graph %s", agnameof(agtail(e)), agnameof(aghead(e)), name, agnameof(src)); else exerror("error cloning edge (%s,%s) from graph %s", agnameof(agtail(e)), agnameof(aghead(e)), agnameof(src)); return; } ep->key = e; ep->val = ne; dtinsert (emap, ep++); } } for (sg = agfstsubg(src); sg; sg = agnxtsubg(sg)) { if (!cloneSubg(tgt, sg, emap)) { exerror("error cloning subgraph %s from graph %s", agnameof(sg), agnameof(src)); } } dtclose (emap); free (data); }
/* * 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; } } } }