static void dot_cleanup_graph(graph_t * g) { int i, c; graph_t *clust; for (c = 1; c <= GD_n_cluster(g); c++) { clust = GD_clust(g)[c]; GD_cluster_was_collapsed(clust) = FALSE; dot_cleanup(clust); } if (GD_clust(g)) free (GD_clust(g)); if (GD_rankleader(g)) free (GD_rankleader(g)); free_list(GD_comp(g)); if (GD_rank(g)) { for (i = GD_minrank(g); i <= GD_maxrank(g); i++) free(GD_rank(g)[i].av); if (GD_minrank(g) == -1) free(GD_rank(g)-1); else free(GD_rank(g)); } if (g != agroot(g)) #ifndef WITH_CGRAPH memset(&(g->u), 0, sizeof(Agraphinfo_t)); #else /* WITH_CGRAPH */ agclean(g,AGRAPH,"Agraphinfo_t"); #endif /* WITH_CGRAPH */ }
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 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 void transpose_sweep(Agraph_t* g, int reverse) { int r,delta; for (r = GD_minrank(g); r <= GD_maxrank(g); r++) GD_rank(g)[r].candidate = TRUE; do { delta = 0; for (r = GD_minrank(g); r <= GD_maxrank(g); r++) if (GD_rank(g)[r].candidate) delta += transpose_onerank(g,r,reverse); } while (delta >= 1); /* while (delta > crossings(g)*(1.0 - Convergence));*/ }
void install_cluster(graph_t * g, node_t * n, int pass, nodequeue * q) { int r; graph_t *clust; clust = ND_clust(n); if (GD_installed(clust) != pass + 1) { for (r = GD_minrank(clust); r <= GD_maxrank(clust); r++) install_in_rank(g, GD_rankleader(clust)[r]); for (r = GD_minrank(clust); r <= GD_maxrank(clust); r++) enqueue_neighbors(q, GD_rankleader(clust)[r], pass); GD_installed(clust) = pass + 1; } }
/* build the global (flat) graph of the universe. this is 'flat' in the sense that there is one data structure for the entire graph (not 'flat' in the sense of flat edges within the same level.) */ static rank_t *globalize(Agraph_t *user, Agraph_t *topmodel) { rank_t *globrank; int minr,maxr,r; /* setup bookkeeping */ interclusterpaths(user, topmodel); /* allocate global ranks */ minr = GD_minrank(topmodel); maxr = GD_maxrank(topmodel); globrank = T_array(minr,maxr,sizeof(rank_t)); countup(user,globrank); for (r = minr; r <= maxr; r++) { globrank[r].v = N_NEW(globrank[r].n+1,Agnode_t*); /* NIL at end */ globrank[r].n = 0; /* reset it */ } /* installation */ for (r = minr; r <= maxr; r++) installglob(user,topmodel,globrank,r); removejunk(user, topmodel); reconnect(user, topmodel); /* optimization */ return globrank; }
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 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 crossings(graph_t *g) { int i, rv; rv = 0; for (i = GD_minrank(g); i < GD_maxrank(g); i++) { rv += crossings_below(g,i); } return rv; }
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); } }
void dot_rank(graph_t * g, aspect_t* asp) { if (agget (g, "newrank")) { GD_flags(g) |= NEW_RANK; dot2_rank (g, asp); } else dot1_rank (g, asp); if (Verbose) fprintf (stderr, "Maxrank = %d, minrank = %d\n", GD_maxrank(g), GD_minrank(g)); }
void dot_scan_ranks(graph_t * g) { node_t *n, *leader = NULL; GD_minrank(g) = MAXSHORT; GD_maxrank(g) = -1; for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (GD_maxrank(g) < ND_rank(n)) GD_maxrank(g) = ND_rank(n); if (GD_minrank(g) > ND_rank(n)) GD_minrank(g) = ND_rank(n); if (leader == NULL) leader = n; else { if (ND_rank(n) < ND_rank(leader)) leader = n; } } GD_leader(g) = leader; }
/* bind/construct representative of an internal cluster of a model graph */ static rep_t model_clust(Agraph_t *model, Agraph_t *origclust) { rep_t rep; rep = association(model,origclust); if (rep.type) return rep; rep.p = newpath(model,NILnode,GD_minrank(origclust),NILnode,GD_maxrank(origclust)); rep.type = SKELETON; associate(model,origclust,rep); return rep; }
static void dot_cleanup_graph(graph_t * g) { int i; graph_t *subg; for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) { dot_cleanup_graph(subg); } if (GD_clust(g)) free (GD_clust(g)); if (GD_rankleader(g)) free (GD_rankleader(g)); free_list(GD_comp(g)); if (GD_rank(g)) { for (i = GD_minrank(g); i <= GD_maxrank(g); i++) free(GD_rank(g)[i].av); if (GD_minrank(g) == -1) free(GD_rank(g)-1); else free(GD_rank(g)); } if (g != agroot(g)) agdelrec(g,"Agraphinfo_t"); }
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; } }
/* * Assigns ranks of non-leader nodes. * Expands same, min, max rank sets. * Leaf sets and clusters remain merged. * Sets minrank and maxrank appropriately. */ static void expand_ranksets(graph_t * g, aspect_t* asp) { int c; node_t *n, *leader; if ((n = agfstnode(g))) { GD_minrank(g) = MAXSHORT; GD_maxrank(g) = -1; while (n) { leader = UF_find(n); /* The following works because ND_rank(n) == 0 if n is not in a * cluster, and ND_rank(n) = the local rank offset if n is in * a cluster. */ if ((leader != n) && (!asp || (ND_rank(n) == 0))) ND_rank(n) += ND_rank(leader); if (GD_maxrank(g) < ND_rank(n)) GD_maxrank(g) = ND_rank(n); if (GD_minrank(g) > ND_rank(n)) GD_minrank(g) = ND_rank(n); if (ND_ranktype(n) && (ND_ranktype(n) != LEAFSET)) UF_singleton(n); n = agnxtnode(g, n); } if (g == dot_root(g)) { if (CL_type == LOCAL) { for (c = 1; c <= GD_n_cluster(g); c++) set_minmax(GD_clust(g)[c]); } else { find_clusters(g); } } } else { GD_minrank(g) = GD_maxrank(g) = 0; } }
static void remove_rankleaders(graph_t * g) { int r; node_t *v; edge_t *e; for (r = GD_minrank(g); r <= GD_maxrank(g); r++) { v = GD_rankleader(g)[r]; /* remove the entire chain */ while ((e = ND_out(v).list[0])) delete_fast_edge(e); while ((e = ND_in(v).list[0])) delete_fast_edge(e); delete_fast_node(agroot(g), v); GD_rankleader(g)[r] = NULL; } }
void dot_concentrate(graph_t * g) { int c, r, leftpos, rightpos; node_t *left, *right; if (GD_maxrank(g) - GD_minrank(g) <= 1) return; /* this is the downward looking pass. r is a candidate rank. */ for (r = 1; GD_rank(g)[r + 1].n; r++) { for (leftpos = 0; leftpos < GD_rank(g)[r].n; leftpos++) { left = GD_rank(g)[r].v[leftpos]; if (downcandidate(left) == FALSE) continue; for (rightpos = leftpos + 1; rightpos < GD_rank(g)[r].n; rightpos++) { right = GD_rank(g)[r].v[rightpos]; if (bothdowncandidates(left, right) == FALSE) break; } if (rightpos - leftpos > 1) mergevirtual(g, r, leftpos, rightpos - 1, DOWN); } } /* this is the corresponding upward pass */ while (r > 0) { for (leftpos = 0; leftpos < GD_rank(g)[r].n; leftpos++) { left = GD_rank(g)[r].v[leftpos]; if (upcandidate(left) == FALSE) continue; for (rightpos = leftpos + 1; rightpos < GD_rank(g)[r].n; rightpos++) { right = GD_rank(g)[r].v[rightpos]; if (bothupcandidates(left, right) == FALSE) break; } if (rightpos - leftpos > 1) mergevirtual(g, r, leftpos, rightpos - 1, UP); } r--; } for (c = 1; c <= GD_n_cluster(g); c++) rebuild_vlists(GD_clust(g)[c]); }
static void mincross_sweep(Agraph_t* g, int dir, boolean reverse) { int r,other,low,high,first,last; int hasfixed; low = GD_minrank(g); high = GD_maxrank(g); if (dir == 0) return; if (dir > 0) { first = low + 1; last = high; dir = 1;} /* down */ else { first = high - 1; last = low; dir = -1;} /* up */ for (r = first; r != last + dir; r += dir) { other = r - dir; hasfixed = medians(g,r,other); reorder(g,r,reverse,hasfixed); } transpose_sweep(g,NOT(reverse)); savebest(g); }
static void dot_cleanup_graph(graph_t * g) { int i, c; graph_t *clust; for (c = 1; c <= GD_n_cluster(g); c++) { clust = GD_clust(g)[c]; GD_cluster_was_collapsed(clust) = FALSE; dot_cleanup(clust); } free_list(GD_comp(g)); if ((g == g->root) && GD_rank(g)) { for (i = GD_minrank(g); i <= GD_maxrank(g); i++) free(GD_rank(g)[i].v); free(GD_rank(g)); } if (g != g->root) memset(&(g->u), 0, sizeof(Agraphinfo_t)); }
static void dumpRanks (graph_t * g) { int i, j; node_t* u; rank_t *rank = GD_rank(g); int rcnt = 0; for (i = GD_minrank(g); i <= GD_maxrank(g); i++) { fprintf (stderr, "[%d] :", i); for (j = 0; j < rank[i].n; j++) { u = rank[i].v[j]; rcnt++; if (streq(u->name,"virtual")) fprintf (stderr, " %x", u); else fprintf (stderr, " %s", u->name); } fprintf (stderr, "\n"); } fprintf (stderr, "count %d rank count = %d\n", fastn(g), rcnt); }
/* this function marks every node in <g> with its top-level cluster under <g> */ void mark_clusters(graph_t * g) { int c; node_t *n, *nn, *vn; edge_t *orig, *e; graph_t *clust; /* remove sub-clusters below this level */ for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (ND_ranktype(n) == CLUSTER) UF_singleton(n); ND_clust(n) = NULL; } for (c = 1; c <= GD_n_cluster(g); c++) { clust = GD_clust(g)[c]; for (n = agfstnode(clust); n; n = nn) { nn = agnxtnode(clust,n); if (ND_ranktype(n) != NORMAL) { agerr(AGWARN, "%s was already in a rankset, deleted from cluster %s\n", agnameof(n), agnameof(g)); agdelete(clust,n); continue; } UF_setname(n, GD_leader(clust)); ND_clust(n) = clust; ND_ranktype(n) = CLUSTER; /* here we mark the vnodes of edges in the cluster */ for (orig = agfstout(clust, n); orig; orig = agnxtout(clust, orig)) { if ((e = ED_to_virt(orig))) { #ifndef WITH_CGRAPH while (e && (vn = e->head)->u.node_type == VIRTUAL) { #else /* WITH_CGRAPH */ while (e && ND_node_type(vn =aghead(e)) == VIRTUAL) { #endif /* WITH_CGRAPH */ ND_clust(vn) = clust; e = ND_out(aghead(e)).list[0]; /* trouble if concentrators and clusters are mixed */ } } } } } } void build_skeleton(graph_t * g, graph_t * subg) { int r; node_t *v, *prev, *rl; edge_t *e; prev = NULL; GD_rankleader(subg) = N_NEW(GD_maxrank(subg) + 2, node_t *); for (r = GD_minrank(subg); r <= GD_maxrank(subg); r++) { v = GD_rankleader(subg)[r] = virtual_node(g); ND_rank(v) = r; ND_ranktype(v) = CLUSTER; ND_clust(v) = subg; if (prev) { e = virtual_edge(prev, v, NULL); ED_xpenalty(e) *= CL_CROSS; } prev = v; } /* set the counts on virtual edges of the cluster skeleton */ for (v = agfstnode(subg); v; v = agnxtnode(subg, v)) { rl = GD_rankleader(subg)[ND_rank(v)]; ND_UF_size(rl)++; for (e = agfstout(subg, v); e; e = agnxtout(subg, e)) { for (r = ND_rank(agtail(e)); r < ND_rank(aghead(e)); r++) { ED_count(ND_out(rl).list[0])++; } } } for (r = GD_minrank(subg); r <= GD_maxrank(subg); r++) { rl = GD_rankleader(subg)[r]; if (ND_UF_size(rl) > 1) ND_UF_size(rl)--; } }
static void invalidate(Agraph_t *g, int rank) { if (rank > GD_minrank(g)) GD_rank(g)[rank-1].crossing_cache.valid = FALSE; if (rank > GD_minrank(g)) GD_rank(g)[rank-1].candidate = TRUE; if (rank < GD_maxrank(g)) GD_rank(g)[rank+1].candidate = TRUE; }
static void resetNodeCountOnRanks(Agraph_t * g) { int i; for (i = GD_minrank(g); i <= GD_maxrank(g); i++) GD_rank(g)[i].n = 0; }
/* 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]); }