/* 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 int minmax_edges2(graph_t * g, point slen) { node_t *n; edge_t *e = 0; if ((GD_maxset(g)) || (GD_minset(g))) { for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (n != UF_find(n)) continue; if ((ND_out(n).size == 0) && GD_maxset(g) && (n != GD_maxset(g))) { e = virtual_edge(n, GD_maxset(g), NULL); ED_minlen(e) = slen.y; } if ((ND_in(n).size == 0) && GD_minset(g) && (n != GD_minset(g))) { e = virtual_edge(GD_minset(g), n, NULL); ED_minlen(e) = slen.x; } } } return (e != 0); }