00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "dot.h"
00033
00034 static void
00035 renewlist(elist * L)
00036 {
00037 int i;
00038 for (i = L->size; i >= 0; i--)
00039 L->list[i] = NULL;
00040 L->size = 0;
00041 }
00042
00043 static void
00044 cleanup1(graph_t * g)
00045 {
00046 node_t *n;
00047 edge_t *e, *f;
00048 int c;
00049
00050 for (c = 0; c < GD_comp(g).size; c++) {
00051 GD_nlist(g) = GD_comp(g).list[c];
00052 for (n = GD_nlist(g); n; n = ND_next(n)) {
00053 renewlist(&ND_in(n));
00054 renewlist(&ND_out(n));
00055 ND_mark(n) = FALSE;
00056 }
00057 }
00058 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00059 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00060 f = ED_to_virt(e);
00061 if (f && (e == ED_to_orig(f))) {
00062
00063
00064
00065 edge_t *e1, *f1;
00066 for (e1 = agfstout(g, n); e1; e1 = agnxtout(g, e1)) {
00067 if (e != e1) {
00068 f1 = ED_to_virt(e1);
00069 if (f1 && (f == f1)) {
00070 ED_to_virt(e1) = NULL;
00071 }
00072 }
00073 }
00074 free(f);
00075 }
00076 ED_to_virt(e) = NULL;
00077 }
00078 }
00079 free(GD_comp(g).list);
00080 GD_comp(g).list = NULL;
00081 GD_comp(g).size = 0;
00082 }
00083
00084
00085
00086
00087
00088 static void
00089 edgelabel_ranks(graph_t * g)
00090 {
00091 node_t *n;
00092 edge_t *e;
00093
00094 if (GD_has_labels(g) & EDGE_LABEL) {
00095 for (n = agfstnode(g); n; n = agnxtnode(g, n))
00096 for (e = agfstout(g, n); e; e = agnxtout(g, e))
00097 ED_minlen(e) *= 2;
00098 GD_ranksep(g) = (GD_ranksep(g) + 1) / 2;
00099 }
00100 }
00101
00102
00103 static void
00104 collapse_rankset(graph_t * g, graph_t * subg, int kind)
00105 {
00106 node_t *u, *v;
00107
00108 u = v = agfstnode(subg);
00109 if (u) {
00110 ND_ranktype(u) = kind;
00111 while ((v = agnxtnode(subg, v))) {
00112 UF_union(u, v);
00113 ND_ranktype(v) = ND_ranktype(u);
00114 }
00115 switch (kind) {
00116 case MINRANK:
00117 case SOURCERANK:
00118 if (GD_minset(g) == NULL)
00119 GD_minset(g) = u;
00120 else
00121 GD_minset(g) = UF_union(GD_minset(g), u);
00122 break;
00123 case MAXRANK:
00124 case SINKRANK:
00125 if (GD_maxset(g) == NULL)
00126 GD_maxset(g) = u;
00127 else
00128 GD_maxset(g) = UF_union(GD_maxset(g), u);
00129 break;
00130 }
00131 switch (kind) {
00132 case SOURCERANK:
00133 GD_minset(g)->u.ranktype = kind;
00134 break;
00135 case SINKRANK:
00136 GD_maxset(g)->u.ranktype = kind;
00137 break;
00138 }
00139 }
00140 }
00141
00142 static int
00143 rank_set_class(graph_t * g)
00144 {
00145 static char *name[] = { "same", "min", "source", "max", "sink", NULL };
00146 static int class[] =
00147 { SAMERANK, MINRANK, SOURCERANK, MAXRANK, SINKRANK, 0 };
00148 int val;
00149
00150 if (is_cluster(g))
00151 return CLUSTER;
00152 val = maptoken(agget(g, "rank"), name, class);
00153 GD_set_type(g) = val;
00154 return val;
00155 }
00156
00157 static int
00158 make_new_cluster(graph_t * g, graph_t * subg)
00159 {
00160 int cno;
00161 cno = ++(GD_n_cluster(g));
00162 GD_clust(g) = ZALLOC(cno + 1, GD_clust(g), graph_t *, GD_n_cluster(g));
00163 GD_clust(g)[cno] = subg;
00164 do_graph_label(subg);
00165 return cno;
00166 }
00167
00168 static void
00169 node_induce(graph_t * par, graph_t * g)
00170 {
00171 node_t *n, *nn;
00172 edge_t *e;
00173 int i;
00174
00175
00176 for (n = agfstnode(g); n; n = nn) {
00177 nn = agnxtnode(g, n);
00178 if (ND_ranktype(n)) {
00179 agdelete(g, n);
00180 continue;
00181 }
00182 for (i = 1; i < GD_n_cluster(par); i++)
00183 if (agcontains(GD_clust(par)[i], n))
00184 break;
00185 if (i < GD_n_cluster(par))
00186 agdelete(g, n);
00187 ND_clust(n) = NULL;
00188 }
00189
00190 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00191 for (e = agfstout(g->root, n); e; e = agnxtout(g->root, e)) {
00192 if (agcontains(g, e->head))
00193 aginsert(g, e);
00194 }
00195 }
00196 }
00197
00198 void
00199 dot_scan_ranks(graph_t * g)
00200 {
00201 node_t *n, *leader = NULL;
00202 GD_minrank(g) = MAXSHORT;
00203 GD_maxrank(g) = -1;
00204 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00205 if (GD_maxrank(g) < ND_rank(n))
00206 GD_maxrank(g) = ND_rank(n);
00207 if (GD_minrank(g) > ND_rank(n))
00208 GD_minrank(g) = ND_rank(n);
00209 if (leader == NULL)
00210 leader = n;
00211 else {
00212 if (ND_rank(n) < ND_rank(leader))
00213 leader = n;
00214 }
00215 }
00216 GD_leader(g) = leader;
00217 }
00218
00219 static void
00220 cluster_leader(graph_t * clust)
00221 {
00222 node_t *leader, *n;
00223 int maxrank = 0;
00224
00225
00226 leader = NULL;
00227 for (n = GD_nlist(clust); n; n = ND_next(n)) {
00228 if ((ND_rank(n) == 0) && (ND_node_type(n) == NORMAL))
00229 leader = n;
00230 if (maxrank < ND_rank(n))
00231 maxrank = ND_rank(n);
00232 }
00233 assert(leader != NULL);
00234 GD_leader(clust) = leader;
00235
00236 for (n = agfstnode(clust); n; n = agnxtnode(clust, n)) {
00237 assert((ND_UF_size(n) <= 1) || (n == leader));
00238 UF_union(n, leader);
00239 ND_ranktype(n) = CLUSTER;
00240 }
00241 }
00242
00243
00244
00245
00246
00247
00248
00249
00250 static void
00251 collapse_cluster(graph_t * g, graph_t * subg)
00252 {
00253 if (GD_cluster_was_collapsed(subg))
00254 return;
00255 GD_cluster_was_collapsed(subg) = TRUE;
00256 node_induce(g, subg);
00257 if (agfstnode(subg) == NULL)
00258 return;
00259 make_new_cluster(g, subg);
00260 if (CL_type == LOCAL) {
00261 dot_rank(subg);
00262 cluster_leader(subg);
00263 } else
00264 dot_scan_ranks(subg);
00265 }
00266
00267
00268 static void
00269 collapse_sets(graph_t * g)
00270 {
00271 int c;
00272 graph_t *mg, *subg;
00273 node_t *mn, *n;
00274 edge_t *me;
00275
00276 mg = g->meta_node->graph;
00277 for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) {
00278 mn = me->head;
00279 subg = agusergraph(mn);
00280
00281 c = rank_set_class(subg);
00282 if (c) {
00283 if ((c == CLUSTER) && CL_type == LOCAL)
00284 collapse_cluster(g, subg);
00285 else
00286 collapse_rankset(g, subg, c);
00287 }
00288
00289
00290 if (agget(subg, "ordering"))
00291 for (n = agfstnode(subg); n; n = agnxtnode(subg, n))
00292 ND_order(n) = 1;
00293 }
00294 }
00295
00296 static void
00297 find_clusters(graph_t * g)
00298 {
00299 graph_t *mg, *subg;
00300 node_t *mn;
00301 edge_t *me;
00302
00303 mg = g->meta_node->graph;
00304 for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) {
00305 mn = me->head;
00306 subg = agusergraph(mn);
00307
00308 if (GD_set_type(subg) == CLUSTER)
00309 collapse_cluster(g, subg);
00310 }
00311 }
00312
00313 static void
00314 set_minmax(graph_t * g)
00315 {
00316 int c;
00317
00318 GD_minrank(g) += GD_leader(g)->u.rank;
00319 GD_maxrank(g) += GD_leader(g)->u.rank;
00320 for (c = 1; c <= GD_n_cluster(g); c++)
00321 set_minmax(GD_clust(g)[c]);
00322 }
00323
00324
00325
00326
00327 static point
00328 minmax_edges(graph_t * g)
00329 {
00330 node_t *n;
00331 edge_t *e;
00332 point slen;
00333
00334 slen.x = slen.y = 0;
00335 if ((GD_maxset(g) == NULL) && (GD_minset(g) == NULL))
00336 return slen;
00337 if (GD_minset(g) != NULL)
00338 GD_minset(g) = UF_find(GD_minset(g));
00339 if (GD_maxset(g) != NULL)
00340 GD_maxset(g) = UF_find(GD_maxset(g));
00341
00342 if ((n = GD_maxset(g))) {
00343 slen.y = (GD_maxset(g)->u.ranktype == SINKRANK);
00344 while ((e = ND_out(n).list[0])) {
00345 assert(e->head == UF_find(e->head));
00346 reverse_edge(e);
00347 }
00348 }
00349 if ((n = GD_minset(g))) {
00350 slen.x = (GD_minset(g)->u.ranktype == SOURCERANK);
00351 while ((e = ND_in(n).list[0])) {
00352 assert(e->tail == UF_find(e->tail));
00353 reverse_edge(e);
00354 }
00355 }
00356 return slen;
00357 }
00358
00359 static int
00360 minmax_edges2(graph_t * g, point slen)
00361 {
00362 node_t *n;
00363 edge_t *e = 0;
00364
00365 if ((GD_maxset(g)) || (GD_minset(g))) {
00366 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00367 if (n != UF_find(n))
00368 continue;
00369 if ((ND_out(n).size == 0) && GD_maxset(g) && (n != GD_maxset(g))) {
00370 e = virtual_edge(n, GD_maxset(g), NULL);
00371 ED_minlen(e) = slen.y;
00372 }
00373 if ((ND_in(n).size == 0) && GD_minset(g) && (n != GD_minset(g))) {
00374 e = virtual_edge(GD_minset(g), n, NULL);
00375 ED_minlen(e) = slen.x;
00376 }
00377 }
00378 }
00379 return (e != 0);
00380 }
00381
00382
00383 static void
00384 rank1(graph_t * g)
00385 {
00386 int maxiter = INT_MAX;
00387 int c;
00388 char *s;
00389
00390 if ((s = agget(g, "nslimit1")))
00391 maxiter = atof(s) * agnnodes(g);
00392 for (c = 0; c < GD_comp(g).size; c++) {
00393 GD_nlist(g) = GD_comp(g).list[c];
00394 rank(g, (GD_n_cluster(g) == 0 ? 1 : 0), maxiter);
00395 }
00396 }
00397
00398
00399
00400
00401
00402
00403
00404 void expand_ranksets(graph_t * g)
00405 {
00406 int c;
00407 node_t *n, *leader;
00408
00409 if ((n = agfstnode(g))) {
00410 GD_minrank(g) = MAXSHORT;
00411 GD_maxrank(g) = -1;
00412 while (n) {
00413 leader = UF_find(n);
00414
00415
00416
00417 if (leader != n)
00418 ND_rank(n) += ND_rank(leader);
00419
00420 if (GD_maxrank(g) < ND_rank(n))
00421 GD_maxrank(g) = ND_rank(n);
00422 if (GD_minrank(g) > ND_rank(n))
00423 GD_minrank(g) = ND_rank(n);
00424
00425 if (ND_ranktype(n) && (ND_ranktype(n) != LEAFSET))
00426 UF_singleton(n);
00427 n = agnxtnode(g, n);
00428 }
00429 if (g == g->root) {
00430 if (CL_type == LOCAL) {
00431 for (c = 1; c <= GD_n_cluster(g); c++)
00432 set_minmax(GD_clust(g)[c]);
00433 } else {
00434 find_clusters(g);
00435 }
00436 }
00437 } else {
00438 GD_minrank(g) = GD_maxrank(g) = 0;
00439 }
00440 }
00441
00442 #ifdef ALLOW_LEVELS
00443 void
00444 setRanks (graph_t* g, attrsym_t* lsym)
00445 {
00446 node_t* n;
00447 char* s;
00448 char* ep;
00449 long v;
00450
00451 for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
00452 s = agxget (n, lsym->index);
00453 v = strtol (s, &ep, 10);
00454 if (ep == s)
00455 agerr(AGWARN, "no level attribute for node \"%s\"\n", n->name);
00456 ND_rank(n) = v;
00457 }
00458 }
00459 #endif
00460
00461 void dot_rank(graph_t * g)
00462 {
00463 point p;
00464 #ifdef ALLOW_LEVELS
00465 attrsym_t* N_level;
00466 #endif
00467 edgelabel_ranks(g);
00468 collapse_sets(g);
00469
00470 class1(g);
00471 p = minmax_edges(g);
00472 decompose(g, 0);
00473 acyclic(g);
00474 if (minmax_edges2(g, p))
00475 decompose(g, 0);
00476 #ifdef ALLOW_LEVELS
00477 if ((N_level = agfindattr(g->proto->n, "level")))
00478 setRanks(g, N_level);
00479 else
00480 #endif
00481 rank1(g);
00482 expand_ranksets(g);
00483 cleanup1(g);
00484 }
00485
00486 int is_cluster(graph_t * g)
00487 {
00488 return (strncmp(g->name, "cluster", 7) == 0);
00489 }
00490
00491 #ifdef OBSOLETE
00492 static node_t*
00493 merge_leaves(graph_t * g, node_t * cur, node_t * new)
00494 {
00495 node_t *rv;
00496
00497 if (cur == NULL)
00498 rv = new;
00499 else {
00500 rv = UF_union(cur, new);
00501 ND_ht_i(rv) = MAX(ND_ht_i(cur), ND_ht_i(new));
00502 ND_lw_i(rv) = ND_lw_i(cur) + ND_lw_i(new) + GD_nodesep(g) / 2;
00503 ND_rw_i(rv) = ND_rw_i(cur) + ND_rw_i(new) + GD_nodesep(g) / 2;
00504 }
00505 return rv;
00506 }
00507
00508 static void
00509 potential_leaf(graph_t * g, edge_t * e, node_t * leaf)
00510 {
00511 node_t *par;
00512
00513 if ((ED_tail_port(e).p.x) || (ED_head_port(e).p.x))
00514 return;
00515 if ((ED_minlen(e) != 1) || (ND_order(e->tail) > 0))
00516 return;
00517 par = ((leaf != e->head) ? e->head : e->tail);
00518 ND_ranktype(leaf) = LEAFSET;
00519 if (par == e->tail)
00520 GD_outleaf(par) = merge_leaves(g, GD_outleaf(par), leaf);
00521 else
00522 GD_inleaf(par) = merge_leaves(g, GD_inleaf(par), leaf);
00523 }
00524
00525 static void
00526 collapse_leaves(graph_t * g)
00527 {
00528 node_t *n;
00529 edge_t *e;
00530
00531 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00532
00533
00534 if ((ND_ranktype(n) != NOCMD) || (ND_order(n)))
00535 continue;
00536 if (agfstout(g, n) == NULL) {
00537 if ((e = agfstin(g, n)) && (agnxtin(g, e) == NULL)) {
00538 potential_leaf(g, e, n);
00539 continue;
00540 }
00541 }
00542 if (agfstin(g, n) == NULL) {
00543 if ((e = agfstout(g, n)) && (agnxtout(g, e) == NULL)) {
00544 potential_leaf(g, e, n);
00545 continue;
00546 }
00547 }
00548 }
00549 }
00550 #endif
00551