/* Merge the nodes of a min, max, or same rank set. */ void collapse_rankset(graph_t *g, graph_t *subg, int kind) { node_t *u,*v; u = v = agfstnode(subg); if (u) { ND_ranktype(u) = kind; while ((v = agnxtnode(subg,v))) { UF_union(u,v); ND_ranktype(v) = ND_ranktype(u); } switch (kind) { case MINRANK: case SOURCERANK: if (GD_minset(g) == NULL) GD_minset(g) = u; else GD_minset(g) = UF_union(GD_minset(g),u); break; case MAXRANK: case SINKRANK: if (GD_maxset(g) == NULL) GD_maxset(g) = u; else GD_maxset(g) = UF_union(GD_maxset(g),u); break; } switch (kind) { case SOURCERANK: GD_minset(g)->u.ranktype = kind; break; case SINKRANK: GD_maxset(g)->u.ranktype = kind; break; } } }
/* To ensure that min and max rank nodes always have the intended rank * assignment, reverse any incompatible edges. */ static point minmax_edges(graph_t * g) { node_t *n; edge_t *e; point slen; slen.x = slen.y = 0; if ((GD_maxset(g) == NULL) && (GD_minset(g) == NULL)) return slen; if (GD_minset(g) != NULL) GD_minset(g) = UF_find(GD_minset(g)); if (GD_maxset(g) != NULL) GD_maxset(g) = UF_find(GD_maxset(g)); if ((n = GD_maxset(g))) { slen.y = (ND_ranktype(GD_maxset(g)) == SINKRANK); while ((e = ND_out(n).list[0])) { assert(aghead(e) == UF_find(aghead(e))); reverse_edge(e); } } if ((n = GD_minset(g))) { slen.x = (ND_ranktype(GD_minset(g)) == SOURCERANK); while ((e = ND_in(n).list[0])) { assert(agtail(e) == UF_find(agtail(e))); reverse_edge(e); } } return slen; }
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(dot_root(g), n); e; e = agnxtout(dot_root(g), e)) { if (agcontains(g, aghead(e))) agsubedge(g,e,1); } } }
/* * 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 cluster_leader(graph_t * clust) { node_t *leader, *n; int maxrank = 0; /* find number of ranks and select a leader */ leader = NULL; for (n = GD_nlist(clust); n; n = ND_next(n)) { if ((ND_rank(n) == 0) && (ND_node_type(n) == NORMAL)) leader = n; if (maxrank < ND_rank(n)) maxrank = ND_rank(n); } assert(leader != NULL); GD_leader(clust) = leader; for (n = agfstnode(clust); n; n = agnxtnode(clust, n)) { assert((ND_UF_size(n) <= 1) || (n == leader)); UF_union(n, leader); ND_ranktype(n) = CLUSTER; } }
/* 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)--; } }
void UF_singleton(node_t * u) { ND_UF_size(u) = 1; ND_UF_parent(u) = NULL; ND_ranktype(u) = NORMAL; }