/* sets ports that represent connections to subclusters */ static void subclustports(Agraph_t *ug) { Agraph_t *model, *clustmodel; Agnode_t *x; Agedge_t *e; vpath_t *p; Dict_t *d; double frac; /* walk all the paths */ model = GD_model(ug); d = repdict(model); for (p = dtfirst(d); p; p = dtnext(d,p)) { if ((ND_type(p->v[p->low])) == NODETYPE_CNODE) { x = p->v[p->low]; clustmodel = GD_model(ND_cluster(x)); frac = (ND_order(x) + 1) / GD_rank(clustmodel)[ND_rank(x)].n; e = p->e[p->low]; ED_tailport(e).p.x = 2 * PORTCLAMP * (frac - 0.5) + p->tailport; } if ((ND_type(p->v[p->high])) == NODETYPE_CNODE) { x = p->v[p->high]; clustmodel = GD_model(ND_cluster(x)); frac = (ND_order(x) + 1) / GD_rank(clustmodel)[ND_rank(x)].n; e = p->e[p->high-1]; ED_headport(e).p.x = 2 * PORTCLAMP * (frac - 0.5) + p->headport; } } }
int transpose_onerank(Agraph_t* g, int r, boolean reverse) { int i,c0,c1,rv; node_t *v,*w; rv = 0; GD_rank(g)[r].candidate = FALSE; for (i = leftmost(g,r); i < rightmost(g,r); i++) { v = GD_rank(g)[r].v[i]; w = GD_rank(g)[r].v[i+1]; assert (ND_order(v) < ND_order(w)); if (left2right(g,v,w)) continue; c0 = c1 = 0; if (r > GD_minrank(g)) { c0 += in_cross(v,w); c1 += in_cross(w,v); } if (r < GD_maxrank(g)) { c0 += out_cross(v,w); c1 += out_cross(w,v); } if ((c1 < c0) || ((c0 > 0) && reverse && (c1 == c0))) { exchange(g,v,w); rv += (c0 - c1); } } return rv; }
static void infuse(graph_t * g, node_t * n) { node_t *lead; lead = GD_rankleader(g)[ND_rank(n)]; if ((lead == NULL) || (ND_order(lead) > ND_order(n))) GD_rankleader(g)[ND_rank(n)] = n; }
static void merge_ranks(graph_t * subg) { int i, d, r, pos, ipos; node_t *v; graph_t *root; root = agroot(subg); if (GD_minrank(subg) > 0) #ifndef WITH_CGRAPH ND_rank(root)[GD_minrank(subg) - 1].valid = FALSE; #else /* WITH_CGRAPH */ GD_rank(root)[GD_minrank(subg) - 1].valid = FALSE; #endif /* WITH_CGRAPH */ for (r = GD_minrank(subg); r <= GD_maxrank(subg); r++) { d = GD_rank(subg)[r].n; #ifndef WITH_CGRAPH ipos = pos = GD_rankleader(subg)[r]->u.order; #else /* WITH_CGRAPH */ ipos = pos = ND_order(GD_rankleader(subg)[r]); #endif /* WITH_CGRAPH */ make_slots(root, r, pos, d); for (i = 0; i < GD_rank(subg)[r].n; i++) { #ifndef WITH_CGRAPH v = ND_rank(root)[r].v[pos] = GD_rank(subg)[r].v[i]; #else /* WITH_CGRAPH */ v = GD_rank(root)[r].v[pos] = GD_rank(subg)[r].v[i]; #endif /* WITH_CGRAPH */ ND_order(v) = pos++; #ifndef WITH_CGRAPH v->graph = subg->root; #else /* WITH_CGRAPH */ /* real nodes automatically have v->root = root graph */ if (ND_node_type(v) == VIRTUAL) v->root = root; #endif /* WITH_CGRAPH */ delete_fast_node(subg, v); fast_node(agroot(subg), v); GD_n_nodes(agroot(subg))++; } #ifndef WITH_CGRAPH GD_rank(subg)[r].v = ND_rank(root)[r].v + ipos; ND_rank(root)[r].valid = FALSE; #else /* WITH_CGRAPH */ GD_rank(subg)[r].v = GD_rank(root)[r].v + ipos; GD_rank(root)[r].valid = FALSE; #endif /* WITH_CGRAPH */ } if (r < GD_maxrank(root)) GD_rank(root)[r].valid = FALSE; GD_expanded(subg) = TRUE; }
static int presort_cmpf(const void *arg0, const void *arg1) { Agnode_t *n0, *n1; Agraph_t *c0, *c1; n0 = *(Agnode_t**)arg0; n1 = *(Agnode_t**)arg1; c0 = ND_cluster(n0); c1 = ND_cluster(n1); if (c0 == c1) return 0; assert(ND_rank(n0) == ND_rank(n1)); n0 = GD_skel(c0)->v[ND_rank(n0)]; n1 = GD_skel(c1)->v[ND_rank(n1)]; return ND_order(n0) - ND_order(n1); }
static int in_cross(node_t *v,node_t *w) { register edge_t *e1,*e2; register int inv, cross = 0, t; for (e2 = agfstin(w->graph,w); e2; e2 = agnxtin(w->graph,e2)) { register int cnt = ED_xpenalty(e2); inv = ND_order(e2->tail); for (e1 = agfstin(v->graph,v); e1; e1 = agnxtin(v->graph,e1)) { t = ND_order(e1->tail) - inv; if ((t > 0) || ((t == 0) && (ED_tailport(e1).p.x > ED_tailport(e2).p.x))) cross += ED_xpenalty(e1) * cnt; } } return cross; }
/* Execute union commands for "same rank" subgraphs and clusters. */ static void collapse_sets(graph_t *rg, graph_t *g) { int c; graph_t *subg; #ifdef OBSOLETE node_t *n; #endif for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) { c = rank_set_class(subg); if (c) { if ((c == CLUSTER) && CL_type == LOCAL) collapse_cluster(rg, subg); else collapse_rankset(rg, subg, c); } else collapse_sets(rg, subg); #ifdef OBSOLETE Collapsing leaves is currently obsolete /* mark nodes with ordered edges so their leaves are not collapsed */ if (agget(subg, "ordering")) for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) ND_order(n) = 1; #endif } }
static void restorebest(graph_t *g) { Agnode_t *n; int i; for (i = GD_minrank(g); i <= GD_maxrank(g); i++) GD_rank(g)[i].changed = FALSE; for (n = agfstnode(g); n; n = agnxtnode(g,n)) { if (ND_order(n) != ND_saveorder(n)) { invalidate(g,ND_rank(n)); GD_rank(g)[i].changed = TRUE; ND_order(n) = ND_saveorder(n); } } for (i = GD_minrank(g); i <= GD_maxrank(g); i++) { if (GD_rank(g)[i].changed) qsort(GD_rank(g)[i].v,GD_rank(g)[i].n,sizeof(Agnode_t*),ND_order_cmpf); } }
static void install(Agraph_t *g, Agnode_t *n) { int rank; rank_t *r; rank = ND_rank(n); r = &GD_rank(g)[rank]; r->v[r->n] = n; ND_order(n) = r->n++; }
static void rebuild_vlists(graph_t * g) { int c, i, r, maxi; node_t *n, *lead; edge_t *e, *rep; for (r = GD_minrank(g); r <= GD_maxrank(g); r++) GD_rankleader(g)[r] = NULL; for (n = agfstnode(g); n; n = agnxtnode(g, n)) { infuse(g, n); for (e = agfstout(g, n); e; e = agnxtout(g, e)) { for (rep = e; ED_to_virt(rep); rep = ED_to_virt(rep)); while (ND_rank(rep->head) < ND_rank(e->head)) { infuse(g, rep->head); rep = ND_out(rep->head).list[0]; } } } for (r = GD_minrank(g); r <= GD_maxrank(g); r++) { lead = GD_rankleader(g)[r]; if (ND_rank(g->root)[r].v[ND_order(lead)] != lead) abort(); GD_rank(g)[r].v = ND_rank(g->root)[r].v + GD_rankleader(g)[r]->u.order; maxi = -1; for (i = 0; i < GD_rank(g)[r].n; i++) { if ((n = GD_rank(g)[r].v[i]) == NULL) break; if (ND_node_type(n) == NORMAL) { if (agcontains(g, n)) maxi = i; else break; } else { edge_t *e; for (e = ND_in(n).list[0]; e && ED_to_orig(e); e = ED_to_orig(e)); if (e && (agcontains(g, e->tail)) && agcontains(g, e->head)) maxi = i; } } if (maxi == -1) agerr(AGWARN, "degenerate concentrated rank %s,%d\n", g->name, r); GD_rank(g)[r].n = maxi + 1; } for (c = 1; c <= GD_n_cluster(g); c++) rebuild_vlists(GD_clust(g)[c]); }
static void mergevirtual(graph_t * g, int r, int lpos, int rpos, int dir) { int i, k; node_t *left, *right; edge_t *e, *f, *e0; left = GD_rank(g)[r].v[lpos]; /* merge all right nodes into the leftmost one */ for (i = lpos + 1; i <= rpos; i++) { right = GD_rank(g)[r].v[i]; if (dir == DOWN) { while ((e = ND_out(right).list[0])) { for (k = 0; (f = ND_out(left).list[k]); k++) if (f->head == e->head) break; if (f == NULL) f = virtual_edge(left, e->head, e); while ((e0 = ND_in(right).list[0])) { merge_oneway(e0, f); /*ED_weight(f) += ED_weight(e0); */ delete_fast_edge(e0); } delete_fast_edge(e); } } else { while ((e = ND_in(right).list[0])) { for (k = 0; (f = ND_in(left).list[k]); k++) if (f->tail == e->tail) break; if (f == NULL) f = virtual_edge(e->tail, left, e); while ((e0 = ND_out(right).list[0])) { merge_oneway(e0, f); delete_fast_edge(e0); } delete_fast_edge(e); } } assert(ND_in(right).size + ND_out(right).size == 0); delete_fast_node(g, right); } k = lpos + 1; i = rpos + 1; while (i < GD_rank(g)[r].n) { node_t *n; n = GD_rank(g)[r].v[k] = GD_rank(g)[r].v[i]; ND_order(n) = k; k++; i++; } GD_rank(g)[r].n = k; GD_rank(g)[r].v[k] = NULL; }
static void savebest(graph_t *g) { int nc; Agnode_t *n; nc = crossings(g); if (nc < GD_bestcrossings(g)) { for (n = agfstnode(g); n; n = agnxtnode(g,n)) ND_saveorder(n) = ND_order(n); GD_bestcrossings(g) = nc; GD_lastwin(g) = GD_pass(g); } }
static void presort(Agraph_t *ug) { int r; int i; Agraph_t *mg; if (ug == ug->root) return; mg = GD_model(ug); for (r = GD_minrank(mg); r <= GD_maxrank(mg); r++) { qsort(GD_rank(mg)[r].v,GD_rank(mg)[r].n,sizeof(Agnode_t*),presort_cmpf); for (i = leftmost(mg,r); i < rightmost(mg,r); i++) ND_order(GD_rank(mg)[r].v[i]) = i; } }
static void attach_phase_attrs (Agraph_t * g, int maxphase) { Agsym_t* rk = agnodeattr(g,"rank",""); Agsym_t* order = agnodeattr(g,"order",""); Agnode_t* n; char buf[BUFSIZ]; for (n = agfstnode(g); n; n = agnxtnode(g,n)) { if (maxphase >= 1) { sprintf(buf, "%d", ND_rank(n)); ag_xset(n,rk,buf); } if (maxphase >= 2) { sprintf(buf, "%d", ND_order(n)); ag_xset(n,order,buf); } } }
int rank_set_class(graph_t* g) { static char *name[] = {"same","min","source","max","sink",NULL}; static int class[] = {SAMERANK,MINRANK,SOURCERANK,MAXRANK,SINKRANK,0}; int val; if (is_cluster(g)) return CLUSTER; val = maptoken(agget(g,"rank"),name,class); GD_set_type(g) = val; return val; } /* Execute union commands for "same rank" subgraphs and clusters. */ void collapse_sets(graph_t* g) { int c; graph_t *mg,*subg; node_t *mn,*n; edge_t *me; mg = g->meta_node->graph; for (me = agfstout(mg,g->meta_node); me; me = agnxtout(mg,me)) { mn = me->head; subg = agusergraph(mn); c = rank_set_class(subg); if (c) { if ((c == CLUSTER) && CL_type == LOCAL) collapse_cluster(g,subg); else collapse_rankset(g,subg,c); } /* mark nodes with ordered edges so their leaves are not collapsed */ if (agget(subg,"ordering")) for (n = agfstnode(subg); n; n = agnxtnode(subg,n)) ND_order(n) = 1; } }
/* swaps two nodes in the same level */ static void exchange(Agraph_t *g, Agnode_t *u, Agnode_t *v) { rank_t *r; int ui,vi,rank; assert(ND_rank(u) == ND_rank(v)); rank = ND_rank(u); r = &GD_rank(g)[rank]; ui = ND_order(u); vi = ND_order(v); ND_order(v) = ui; ND_order(u) = vi; r->v[ND_order(u)] = u; r->v[ND_order(v)] = v; r->crossing_cache.valid = FALSE; r->changed = TRUE; r->candidate = TRUE; /* old dot had this. i have qualms. sn */ invalidate(g,rank); }
/* make d slots starting at position pos (where 1 already exists) */ static void make_slots(graph_t * root, int r, int pos, int d) { int i; node_t *v, **vlist; #ifndef WITH_CGRAPH vlist = ND_rank(root)[r].v; #else /* WITH_CGRAPH */ vlist = GD_rank(root)[r].v; #endif /* WITH_CGRAPH */ if (d <= 0) { #ifndef WITH_CGRAPH for (i = pos - d + 1; i < ND_rank(root)[r].n; i++) { #else /* WITH_CGRAPH */ for (i = pos - d + 1; i < GD_rank(root)[r].n; i++) { #endif /* WITH_CGRAPH */ v = vlist[i]; ND_order(v) = i + d - 1; vlist[ND_order(v)] = v; } #ifndef WITH_CGRAPH for (i = ND_rank(root)[r].n + d - 1; i < ND_rank(root)[r].n; i++) #else /* WITH_CGRAPH */ for (i = GD_rank(root)[r].n + d - 1; i < GD_rank(root)[r].n; i++) #endif /* WITH_CGRAPH */ vlist[i] = NULL; } else { /*assert(ND_rank(root)[r].n + d - 1 <= ND_rank(root)[r].an);*/ #ifndef WITH_CGRAPH for (i = ND_rank(root)[r].n - 1; i > pos; i--) { #else /* WITH_CGRAPH */ for (i = GD_rank(root)[r].n - 1; i > pos; i--) { #endif /* WITH_CGRAPH */ v = vlist[i]; ND_order(v) = i + d - 1; vlist[ND_order(v)] = v; } for (i = pos + 1; i < pos + d; i++) vlist[i] = NULL; } #ifndef WITH_CGRAPH ND_rank(root)[r].n += d - 1; #else /* WITH_CGRAPH */ GD_rank(root)[r].n += d - 1; #endif /* WITH_CGRAPH */ } static node_t* clone_vn(graph_t * g, node_t * vn) { node_t *rv; int r; r = ND_rank(vn); make_slots(g, r, ND_order(vn), 2); rv = virtual_node(g); ND_lw(rv) = ND_lw(vn); ND_rw(rv) = ND_rw(vn); ND_rank(rv) = ND_rank(vn); ND_order(rv) = ND_order(vn) + 1; GD_rank(g)[r].v[ND_order(rv)] = rv; return rv; }
/* this assumes one level per node - no mega-nodes */ static void apply_model(Agraph_t *ug) { Agnode_t *un; for (un = agfstnode(ug); un; un = agnxtnode(ug,un)) ND_order(un) = ND_order(ND_rep(un)); }
/* Execute union commands for "same rank" subgraphs and clusters. */ static void collapse_sets(graph_t *rg, graph_t *g) { int c; graph_t *subg; #ifdef OBSOLETE node_t *n; #endif #ifndef WITH_CGRAPH graph_t *mg; node_t *mn; edge_t *me; mg = g->meta_node->graph; for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) { mn = aghead(me); subg = agusergraph(mn); #else /* WITH_CGRAPH */ for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) { #endif /* WITH_CGRAPH */ c = rank_set_class(subg); if (c) { if ((c == CLUSTER) && CL_type == LOCAL) collapse_cluster(rg, subg); else collapse_rankset(rg, subg, c); } else collapse_sets(rg, subg); #ifdef OBSOLETE Collapsing leaves is currently obsolete /* mark nodes with ordered edges so their leaves are not collapsed */ if (agget(subg, "ordering")) for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) ND_order(n) = 1; #endif } } static void find_clusters(graph_t * g) { graph_t *subg; #ifndef WITH_CGRAPH graph_t *mg; node_t *mn; edge_t *me; mg = g->meta_node->graph; for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) { mn = me->head; subg = agusergraph(mn); #else /* WITH_CGRAPH */ for (subg = agfstsubg(agroot(g)); subg; subg = agnxtsubg(subg)) { #endif /* WITH_CGRAPH */ if (GD_set_type(subg) == CLUSTER) collapse_cluster(g, subg); } } static void set_minmax(graph_t * g) { int c; GD_minrank(g) += ND_rank(GD_leader(g)); GD_maxrank(g) += ND_rank(GD_leader(g)); for (c = 1; c <= GD_n_cluster(g); c++) set_minmax(GD_clust(g)[c]); }
static int ND_order_cmpf(const void *arg0, const void *arg1) { return ND_order(*(Agnode_t**)arg0) - ND_order(*(Agnode_t**)arg1); }