freeTreeList (G);
}
+static int decreasingrankcmpf(node_t **n0, node_t **n1) {
+ return ND_rank(*n1) - ND_rank(*n0);
+}
+
+static int increasingrankcmpf(node_t **n0, node_t **n1) {
+ return ND_rank(*n0) - ND_rank(*n1);
+}
+
static void TB_balance(void)
{
node_t *n;
edge_t *e;
- int i, low, high, choice, *nrank;
+ int i, ii, low, high, choice, *nrank;
int inweight, outweight;
+ int adj = 0;
+ char *s;
scan_and_normalize();
nrank = N_NEW(Maxrank + 1, int);
for (i = 0; i <= Maxrank; i++)
nrank[i] = 0;
- for (n = GD_nlist(G); n; n = ND_next(n))
- if (ND_node_type(n) == NORMAL)
- nrank[ND_rank(n)]++;
- for (n = GD_nlist(G); n; n = ND_next(n)) {
- if (ND_node_type(n) != NORMAL)
- continue;
- inweight = outweight = 0;
- low = 0;
- high = Maxrank;
- for (i = 0; (e = ND_in(n).list[i]); i++) {
- inweight += ED_weight(e);
- low = MAX(low, ND_rank(agtail(e)) + ED_minlen(e));
- }
- for (i = 0; (e = ND_out(n).list[i]); i++) {
- outweight += ED_weight(e);
- high = MIN(high, ND_rank(aghead(e)) - ED_minlen(e));
- }
- if (low < 0)
- low = 0; /* vnodes can have ranks < 0 */
- if (inweight == outweight) {
- choice = low;
- for (i = low + 1; i <= high; i++)
- if (nrank[i] < nrank[choice])
- choice = i;
- nrank[ND_rank(n)]--;
- nrank[choice]++;
- ND_rank(n) = choice;
- }
- free_list(ND_tree_in(n));
- free_list(ND_tree_out(n));
- ND_mark(n) = FALSE;
+ if (s = agget(G,"TBbalance")) {
+ if (streq(s,"min")) adj = 1;
+ else if (streq(s,"max")) adj = 2;
+ if (adj) for (n = GD_nlist(G); n; n = ND_next(n))
+ if (ND_node_type(n) == NORMAL)
+ if (ND_out(n).size == 0)
+ ND_rank(n) = ((adj == 1)? Minrank : Maxrank);
+ }
+ for (ii = 0, n = GD_nlist(G); n; ii++, n = ND_next(n)) {
+ Tree_node.list[ii] = n;
+ }
+ Tree_node.size = ii;
+ qsort(Tree_node.list, Tree_node.size, sizeof(Tree_node.list[0]),
+ adj > 1? decreasingrankcmpf : increasingrankcmpf);
+ for (i = 0; i < Tree_node.size; i++) {
+ n = Tree_node.list[i];
+ if (ND_node_type(n) == NORMAL)
+ nrank[ND_rank(n)]++;
+ }
+ for (ii = 0; ii < Tree_node.size; ii++) {
+ n = Tree_node.list[ii];
+ if (ND_node_type(n) != NORMAL)
+ continue;
+ inweight = outweight = 0;
+ low = 0;
+ high = Maxrank;
+ for (i = 0; (e = ND_in(n).list[i]); i++) {
+ inweight += ED_weight(e);
+ low = MAX(low, ND_rank(agtail(e)) + ED_minlen(e));
+ }
+ for (i = 0; (e = ND_out(n).list[i]); i++) {
+ outweight += ED_weight(e);
+ high = MIN(high, ND_rank(aghead(e)) - ED_minlen(e));
+ }
+ if (low < 0)
+ low = 0; /* vnodes can have ranks < 0 */
+ if (adj) {
+ if (inweight == outweight)
+ ND_rank(n) = (adj == 1? low : high);
+ }
+ else {
+ if (inweight == outweight) {
+ choice = low;
+ for (i = low + 1; i <= high; i++)
+ if (nrank[i] < nrank[choice])
+ choice = i;
+ nrank[ND_rank(n)]--;
+ nrank[choice]++;
+ ND_rank(n) = choice;
+ }
+ }
+ free_list(ND_tree_in(n));
+ free_list(ND_tree_out(n));
+ ND_mark(n) = FALSE;
}
free(nrank);
}
GD_nlist(g) = ND_next(n);
}
-node_t *virtual_node(graph_t * g)
+node_t *named_virtual_node(graph_t * g, char *s)
{
node_t *n;
n = NEW(node_t);
-// agnameof(n) = "virtual";
AGTYPE(n) = AGNODE;
n->base.data = (Agrec_t*)NEW(Agnodeinfo_t);
n->root = agroot(g);
ND_lw(n) = ND_rw(n) = 1;
ND_ht(n) = 1;
ND_UF_size(n) = 1;
+ if (s) ND_alg(n) = s;
alloc_elist(4, ND_in(n));
alloc_elist(4, ND_out(n));
fast_node(g, n);
return n;
}
+node_t *virtual_node(graph_t * g)
+{
+ return named_virtual_node(g,0);
+}
+
void flat_edge(graph_t * g, edge_t * e)
{
elist_append(e, ND_flat_out(agtail(e)));