|
Graphviz
2.29.20120524.0446
|
00001 /* $Id$ $Revision$ */ 00002 /* vim:set shiftwidth=4 ts=8: */ 00003 00004 /************************************************************************* 00005 * Copyright (c) 2011 AT&T Intellectual Property 00006 * All rights reserved. This program and the accompanying materials 00007 * are made available under the terms of the Eclipse Public License v1.0 00008 * which accompanies this distribution, and is available at 00009 * http://www.eclipse.org/legal/epl-v10.html 00010 * 00011 * Contributors: See CVS logs. Details at http://www.graphviz.org/ 00012 *************************************************************************/ 00013 00014 00015 /* 00016 * Rank the nodes of a directed graph, subject to user-defined 00017 * sets of nodes to be kept on the same, min, or max rank. 00018 * The temporary acyclic fast graph is constructed and ranked 00019 * by a network-simplex technique. Then ranks are propagated 00020 * to non-leader nodes and temporary edges are deleted. 00021 * Leaf nodes and top-level clusters are left collapsed, though. 00022 * Assigns global minrank and maxrank of graph and all clusters. 00023 * 00024 * TODO: safety code. must not be in two clusters at same level. 00025 * must not be in same/min/max/rank and a cluster at the same time. 00026 * watch out for interactions between leaves and clusters. 00027 */ 00028 00029 #include "dot.h" 00030 00031 static void dot1_rank(graph_t * g, aspect_t* asp); 00032 #ifdef WITH_CGRAPH 00033 static void dot2_rank(graph_t * g, aspect_t* asp); 00034 #endif 00035 00036 static void 00037 renewlist(elist * L) 00038 { 00039 int i; 00040 for (i = L->size; i >= 0; i--) 00041 L->list[i] = NULL; 00042 L->size = 0; 00043 } 00044 00045 static void 00046 cleanup1(graph_t * g) 00047 { 00048 node_t *n; 00049 edge_t *e, *f; 00050 int c; 00051 00052 for (c = 0; c < GD_comp(g).size; c++) { 00053 GD_nlist(g) = GD_comp(g).list[c]; 00054 for (n = GD_nlist(g); n; n = ND_next(n)) { 00055 renewlist(&ND_in(n)); 00056 renewlist(&ND_out(n)); 00057 ND_mark(n) = FALSE; 00058 } 00059 } 00060 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00061 for (e = agfstout(g, n); e; e = agnxtout(g, e)) { 00062 f = ED_to_virt(e); 00063 /* Null out any other references to f to make sure we don't 00064 * handle it a second time. For example, parallel multiedges 00065 * share a virtual edge. 00066 */ 00067 if (f && (e == ED_to_orig(f))) { 00068 edge_t *e1, *f1; 00069 #ifndef WITH_CGRAPH 00070 for (e1 = agfstout(g, n); e1; e1 = agnxtout(g, e1)) { 00071 if (e != e1) { 00072 f1 = ED_to_virt(e1); 00073 if (f1 && (f == f1)) { 00074 ED_to_virt(e1) = NULL; 00075 } 00076 } 00077 } 00078 #else 00079 node_t *n1; 00080 for (n1 = agfstnode(g); n1; n1 = agnxtnode(g, n1)) { 00081 for (e1 = agfstout(g, n1); e1; e1 = agnxtout(g, e1)) { 00082 if (e != e1) { 00083 f1 = ED_to_virt(e1); 00084 if (f1 && (f == f1)) { 00085 ED_to_virt(e1) = NULL; 00086 } 00087 } 00088 } 00089 } 00090 free(f->base.data); 00091 #endif 00092 free(f); 00093 } 00094 ED_to_virt(e) = NULL; 00095 } 00096 } 00097 free(GD_comp(g).list); 00098 GD_comp(g).list = NULL; 00099 GD_comp(g).size = 0; 00100 } 00101 00102 /* When there are edge labels, extra ranks are reserved here for the virtual 00103 * nodes of the labels. This is done by doubling the input edge lengths. 00104 * The input rank separation is adjusted to compensate. 00105 */ 00106 static void 00107 edgelabel_ranks(graph_t * g) 00108 { 00109 node_t *n; 00110 edge_t *e; 00111 00112 if (GD_has_labels(g) & EDGE_LABEL) { 00113 for (n = agfstnode(g); n; n = agnxtnode(g, n)) 00114 for (e = agfstout(g, n); e; e = agnxtout(g, e)) 00115 ED_minlen(e) *= 2; 00116 GD_ranksep(g) = (GD_ranksep(g) + 1) / 2; 00117 } 00118 } 00119 00120 /* Merge the nodes of a min, max, or same rank set. */ 00121 static void 00122 collapse_rankset(graph_t * g, graph_t * subg, int kind) 00123 { 00124 node_t *u, *v; 00125 00126 u = v = agfstnode(subg); 00127 if (u) { 00128 ND_ranktype(u) = kind; 00129 while ((v = agnxtnode(subg, v))) { 00130 UF_union(u, v); 00131 ND_ranktype(v) = ND_ranktype(u); 00132 } 00133 switch (kind) { 00134 case MINRANK: 00135 case SOURCERANK: 00136 if (GD_minset(g) == NULL) 00137 GD_minset(g) = u; 00138 else 00139 GD_minset(g) = UF_union(GD_minset(g), u); 00140 break; 00141 case MAXRANK: 00142 case SINKRANK: 00143 if (GD_maxset(g) == NULL) 00144 GD_maxset(g) = u; 00145 else 00146 GD_maxset(g) = UF_union(GD_maxset(g), u); 00147 break; 00148 } 00149 switch (kind) { 00150 case SOURCERANK: 00151 ND_ranktype(GD_minset(g)) = kind; 00152 break; 00153 case SINKRANK: 00154 ND_ranktype(GD_maxset(g)) = kind; 00155 break; 00156 } 00157 } 00158 } 00159 00160 static int 00161 rank_set_class(graph_t * g) 00162 { 00163 static char *name[] = { "same", "min", "source", "max", "sink", NULL }; 00164 static int class[] = 00165 { SAMERANK, MINRANK, SOURCERANK, MAXRANK, SINKRANK, 0 }; 00166 int val; 00167 00168 if (is_cluster(g)) 00169 return CLUSTER; 00170 val = maptoken(agget(g, "rank"), name, class); 00171 GD_set_type(g) = val; 00172 return val; 00173 } 00174 00175 static int 00176 make_new_cluster(graph_t * g, graph_t * subg) 00177 { 00178 int cno; 00179 cno = ++(GD_n_cluster(g)); 00180 GD_clust(g) = ZALLOC(cno + 1, GD_clust(g), graph_t *, GD_n_cluster(g)); 00181 GD_clust(g)[cno] = subg; 00182 do_graph_label(subg); 00183 return cno; 00184 } 00185 00186 static void 00187 node_induce(graph_t * par, graph_t * g) 00188 { 00189 node_t *n, *nn; 00190 edge_t *e; 00191 int i; 00192 00193 /* enforce that a node is in at most one cluster at this level */ 00194 for (n = agfstnode(g); n; n = nn) { 00195 nn = agnxtnode(g, n); 00196 if (ND_ranktype(n)) { 00197 agdelete(g, n); 00198 continue; 00199 } 00200 for (i = 1; i < GD_n_cluster(par); i++) 00201 if (agcontains(GD_clust(par)[i], n)) 00202 break; 00203 if (i < GD_n_cluster(par)) 00204 agdelete(g, n); 00205 ND_clust(n) = NULL; 00206 } 00207 00208 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00209 for (e = agfstout(agroot(g), n); e; e = agnxtout(agroot(g), e)) { 00210 if (agcontains(g, aghead(e))) 00211 #ifndef WITH_CGRAPH 00212 aginsert(g, e); 00213 #else /* WITH_CGRAPH */ 00214 agsubedge(g,e,1); 00215 #endif /* WITH_CGRAPH */ 00216 } 00217 } 00218 } 00219 00220 void 00221 dot_scan_ranks(graph_t * g) 00222 { 00223 node_t *n, *leader = NULL; 00224 GD_minrank(g) = MAXSHORT; 00225 GD_maxrank(g) = -1; 00226 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00227 if (GD_maxrank(g) < ND_rank(n)) 00228 GD_maxrank(g) = ND_rank(n); 00229 if (GD_minrank(g) > ND_rank(n)) 00230 GD_minrank(g) = ND_rank(n); 00231 if (leader == NULL) 00232 leader = n; 00233 else { 00234 if (ND_rank(n) < ND_rank(leader)) 00235 leader = n; 00236 } 00237 } 00238 GD_leader(g) = leader; 00239 } 00240 00241 static void 00242 cluster_leader(graph_t * clust) 00243 { 00244 node_t *leader, *n; 00245 int maxrank = 0; 00246 00247 /* find number of ranks and select a leader */ 00248 leader = NULL; 00249 for (n = GD_nlist(clust); n; n = ND_next(n)) { 00250 if ((ND_rank(n) == 0) && (ND_node_type(n) == NORMAL)) 00251 leader = n; 00252 if (maxrank < ND_rank(n)) 00253 maxrank = ND_rank(n); 00254 } 00255 assert(leader != NULL); 00256 GD_leader(clust) = leader; 00257 00258 for (n = agfstnode(clust); n; n = agnxtnode(clust, n)) { 00259 assert((ND_UF_size(n) <= 1) || (n == leader)); 00260 UF_union(n, leader); 00261 ND_ranktype(n) = CLUSTER; 00262 } 00263 } 00264 00265 /* 00266 * A cluster is collapsed in three steps. 00267 * 1) The nodes of the cluster are ranked locally. 00268 * 2) The cluster is collapsed into one node on the least rank. 00269 * 3) In class1(), any inter-cluster edges are converted using 00270 * the "virtual node + 2 edges" trick. 00271 */ 00272 static void 00273 collapse_cluster(graph_t * g, graph_t * subg) 00274 { 00275 if (GD_parent(subg)) { 00276 #ifndef WITH_CGRAPH 00277 agerr(AGWARN, "Cluster %s is multiply defined in %s and %s - this may cause problems.\n", subg->name, 00278 g->name, GD_parent(subg)->name); 00279 #endif 00280 return; 00281 } 00282 GD_parent(subg) = g; 00283 node_induce(g, subg); 00284 if (agfstnode(subg) == NULL) 00285 return; 00286 make_new_cluster(g, subg); 00287 if (CL_type == LOCAL) { 00288 dot1_rank(subg, 0); 00289 cluster_leader(subg); 00290 } else 00291 dot_scan_ranks(subg); 00292 } 00293 00294 /* Execute union commands for "same rank" subgraphs and clusters. */ 00295 static void 00296 collapse_sets(graph_t *rg, graph_t *g) 00297 { 00298 int c; 00299 graph_t *subg; 00300 #ifdef OBSOLETE 00301 node_t *n; 00302 #endif 00303 00304 #ifndef WITH_CGRAPH 00305 graph_t *mg; 00306 node_t *mn; 00307 edge_t *me; 00308 mg = g->meta_node->graph; 00309 for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) { 00310 mn = aghead(me); 00311 subg = agusergraph(mn); 00312 #else /* WITH_CGRAPH */ 00313 for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) { 00314 #endif /* WITH_CGRAPH */ 00315 c = rank_set_class(subg); 00316 if (c) { 00317 if ((c == CLUSTER) && CL_type == LOCAL) 00318 collapse_cluster(rg, subg); 00319 else 00320 collapse_rankset(rg, subg, c); 00321 } 00322 else collapse_sets(rg, subg); 00323 00324 #ifdef OBSOLETE 00325 Collapsing leaves is currently obsolete 00326 00327 /* mark nodes with ordered edges so their leaves are not collapsed */ 00328 if (agget(subg, "ordering")) 00329 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) 00330 ND_order(n) = 1; 00331 #endif 00332 } 00333 } 00334 00335 static void 00336 find_clusters(graph_t * g) 00337 { 00338 graph_t *subg; 00339 #ifndef WITH_CGRAPH 00340 graph_t *mg; 00341 node_t *mn; 00342 edge_t *me; 00343 00344 mg = g->meta_node->graph; 00345 for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) { 00346 mn = me->head; 00347 subg = agusergraph(mn); 00348 #else /* WITH_CGRAPH */ 00349 for (subg = agfstsubg(agroot(g)); subg; subg = agnxtsubg(subg)) { 00350 #endif /* WITH_CGRAPH */ 00351 if (GD_set_type(subg) == CLUSTER) 00352 collapse_cluster(g, subg); 00353 } 00354 } 00355 00356 static void 00357 set_minmax(graph_t * g) 00358 { 00359 int c; 00360 00361 GD_minrank(g) += ND_rank(GD_leader(g)); 00362 GD_maxrank(g) += ND_rank(GD_leader(g)); 00363 for (c = 1; c <= GD_n_cluster(g); c++) 00364 set_minmax(GD_clust(g)[c]); 00365 } 00366 00367 /* To ensure that min and max rank nodes always have the intended rank 00368 * assignment, reverse any incompatible edges. 00369 */ 00370 static point 00371 minmax_edges(graph_t * g) 00372 { 00373 node_t *n; 00374 edge_t *e; 00375 point slen; 00376 00377 slen.x = slen.y = 0; 00378 if ((GD_maxset(g) == NULL) && (GD_minset(g) == NULL)) 00379 return slen; 00380 if (GD_minset(g) != NULL) 00381 GD_minset(g) = UF_find(GD_minset(g)); 00382 if (GD_maxset(g) != NULL) 00383 GD_maxset(g) = UF_find(GD_maxset(g)); 00384 00385 if ((n = GD_maxset(g))) { 00386 slen.y = (ND_ranktype(GD_maxset(g)) == SINKRANK); 00387 while ((e = ND_out(n).list[0])) { 00388 assert(aghead(e) == UF_find(aghead(e))); 00389 reverse_edge(e); 00390 } 00391 } 00392 if ((n = GD_minset(g))) { 00393 slen.x = (ND_ranktype(GD_minset(g)) == SOURCERANK); 00394 while ((e = ND_in(n).list[0])) { 00395 assert(agtail(e) == UF_find(agtail(e))); 00396 reverse_edge(e); 00397 } 00398 } 00399 return slen; 00400 } 00401 00402 static int 00403 minmax_edges2(graph_t * g, point slen) 00404 { 00405 node_t *n; 00406 edge_t *e = 0; 00407 00408 if ((GD_maxset(g)) || (GD_minset(g))) { 00409 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00410 if (n != UF_find(n)) 00411 continue; 00412 if ((ND_out(n).size == 0) && GD_maxset(g) && (n != GD_maxset(g))) { 00413 e = virtual_edge(n, GD_maxset(g), NULL); 00414 ED_minlen(e) = slen.y; 00415 ED_weight(e) = 0; 00416 } 00417 if ((ND_in(n).size == 0) && GD_minset(g) && (n != GD_minset(g))) { 00418 e = virtual_edge(GD_minset(g), n, NULL); 00419 ED_minlen(e) = slen.x; 00420 ED_weight(e) = 0; 00421 } 00422 } 00423 } 00424 return (e != 0); 00425 } 00426 00427 /* Run the network simplex algorithm on each component. */ 00428 void rank1(graph_t * g) 00429 { 00430 int maxiter = INT_MAX; 00431 int c; 00432 char *s; 00433 00434 if ((s = agget(g, "nslimit1"))) 00435 maxiter = atof(s) * agnnodes(g); 00436 for (c = 0; c < GD_comp(g).size; c++) { 00437 GD_nlist(g) = GD_comp(g).list[c]; 00438 rank(g, (GD_n_cluster(g) == 0 ? 1 : 0), maxiter); /* TB balance */ 00439 } 00440 } 00441 00442 /* 00443 * Assigns ranks of non-leader nodes. 00444 * Expands same, min, max rank sets. 00445 * Leaf sets and clusters remain merged. 00446 * Sets minrank and maxrank appropriately. 00447 */ 00448 static void expand_ranksets(graph_t * g, aspect_t* asp) 00449 { 00450 int c; 00451 node_t *n, *leader; 00452 00453 if ((n = agfstnode(g))) { 00454 GD_minrank(g) = MAXSHORT; 00455 GD_maxrank(g) = -1; 00456 while (n) { 00457 leader = UF_find(n); 00458 /* The following works because ND_rank(n) == 0 if n is not in a 00459 * cluster, and ND_rank(n) = the local rank offset if n is in 00460 * a cluster. */ 00461 if ((leader != n) && (!asp || (ND_rank(n) == 0))) 00462 ND_rank(n) += ND_rank(leader); 00463 00464 if (GD_maxrank(g) < ND_rank(n)) 00465 GD_maxrank(g) = ND_rank(n); 00466 if (GD_minrank(g) > ND_rank(n)) 00467 GD_minrank(g) = ND_rank(n); 00468 00469 if (ND_ranktype(n) && (ND_ranktype(n) != LEAFSET)) 00470 UF_singleton(n); 00471 n = agnxtnode(g, n); 00472 } 00473 if (g == agroot(g)) { 00474 if (CL_type == LOCAL) { 00475 for (c = 1; c <= GD_n_cluster(g); c++) 00476 set_minmax(GD_clust(g)[c]); 00477 } else { 00478 find_clusters(g); 00479 } 00480 } 00481 } else { 00482 GD_minrank(g) = GD_maxrank(g) = 0; 00483 } 00484 } 00485 00486 #ifdef ALLOW_LEVELS 00487 void 00488 setRanks (graph_t* g, attrsym_t* lsym) 00489 { 00490 node_t* n; 00491 char* s; 00492 char* ep; 00493 long v; 00494 00495 for (n = agfstnode(g); n; n = agnxtnode(g,n)) { 00496 s = agxget (n, lsym->index); 00497 v = strtol (s, &ep, 10); 00498 if (ep == s) 00499 agerr(AGWARN, "no level attribute for node \"%s\"\n", n->name); 00500 ND_rank(n) = v; 00501 } 00502 } 00503 #endif 00504 00505 #ifdef UNUSED 00506 static node_t **virtualEdgeHeadList = NULL; 00507 static node_t **virtualEdgeTailList = NULL; 00508 static int nVirtualEdges = 0; 00509 00510 static void 00511 saveVirtualEdges(graph_t *g) 00512 { 00513 edge_t *e; 00514 node_t *n; 00515 int cnt = 0; 00516 int lc; 00517 00518 if (virtualEdgeHeadList != NULL) { 00519 free(virtualEdgeHeadList); 00520 } 00521 if (virtualEdgeTailList != NULL) { 00522 free(virtualEdgeTailList); 00523 } 00524 00525 /* allocate memory */ 00526 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00527 for (lc = 0; lc < ND_in(n).size; lc++) { 00528 e = ND_in(n).list[lc]; 00529 if (ED_edge_type(e) == VIRTUAL) cnt++; 00530 } 00531 } 00532 00533 nVirtualEdges = cnt; 00534 virtualEdgeHeadList = N_GNEW(cnt, node_t*); 00535 virtualEdgeTailList = N_GNEW(cnt, node_t*); 00536 00537 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00538 for (lc = 0, cnt = 0; lc < ND_in(n).size; lc++) { 00539 e = ND_in(n).list[lc]; 00540 if (ED_edge_type(e) == VIRTUAL) { 00541 virtualEdgeHeadList[cnt] = e->head; 00542 virtualEdgeTailList[cnt] = e->tail; 00543 if (Verbose) 00544 printf("saved virtual edge: %s->%s\n", 00545 virtualEdgeTailList[cnt]->name, 00546 virtualEdgeHeadList[cnt]->name); 00547 cnt++; 00548 } 00549 } 00550 } 00551 } 00552 00553 static void 00554 restoreVirtualEdges(graph_t *g) 00555 { 00556 int i; 00557 edge_t e; 00558 00559 for (i = 0; i < nVirtualEdges; i++) { 00560 if (virtualEdgeTailList[i] && virtualEdgeHeadList[i]) { 00561 if (Verbose) 00562 printf("restoring virtual edge: %s->%s\n", 00563 virtualEdgeTailList[i]->name, virtualEdgeHeadList[i]->name); 00564 virtual_edge(virtualEdgeTailList[i], virtualEdgeHeadList[i], NULL); 00565 } 00566 } 00567 if (Verbose) 00568 printf("restored %d virt edges\n", nVirtualEdges); 00569 } 00570 #endif 00571 00572 /* dot1_rank: 00573 * asp != NULL => g is root 00574 */ 00575 static void dot1_rank(graph_t * g, aspect_t* asp) 00576 { 00577 point p; 00578 #ifdef ALLOW_LEVELS 00579 attrsym_t* N_level; 00580 #endif 00581 edgelabel_ranks(g); 00582 00583 if (asp) { 00584 init_UF_size(g); 00585 initEdgeTypes(g); 00586 } 00587 00588 collapse_sets(g,g); 00589 /*collapse_leaves(g); */ 00590 class1(g); 00591 p = minmax_edges(g); 00592 decompose(g, 0); 00593 if (asp && ((GD_comp(g).size > 1)||(GD_n_cluster(g) > 0))) { 00594 asp->badGraph = 1; 00595 asp = NULL; 00596 } 00597 acyclic(g); 00598 if (minmax_edges2(g, p)) 00599 decompose(g, 0); 00600 #ifdef ALLOW_LEVELS 00601 if ((N_level = agfindattr(g->proto->n, "level"))) 00602 setRanks(g, N_level); 00603 else 00604 #endif 00605 00606 if (asp) 00607 rank3(g, asp); 00608 else 00609 rank1(g); 00610 00611 expand_ranksets(g, asp); 00612 cleanup1(g); 00613 } 00614 00615 void dot_rank(graph_t * g, aspect_t* asp) 00616 { 00617 #ifdef WITH_CGRAPH 00618 if (agget (g, "newrank")) { 00619 GD_flags(g) |= NEW_RANK; 00620 dot2_rank (g, asp); 00621 } 00622 else 00623 #endif 00624 dot1_rank (g, asp); 00625 } 00626 00627 int is_cluster(graph_t * g) 00628 { 00629 return (strncmp(agnameof(g), "cluster", 7) == 0); 00630 } 00631 00632 #ifdef OBSOLETE 00633 static node_t* 00634 merge_leaves(graph_t * g, node_t * cur, node_t * new) 00635 { 00636 node_t *rv; 00637 00638 if (cur == NULL) 00639 rv = new; 00640 else { 00641 rv = UF_union(cur, new); 00642 ND_ht(rv) = MAX(ND_ht(cur), ND_ht(new)); 00643 ND_lw(rv) = ND_lw(cur) + ND_lw(new) + GD_nodesep(g) / 2; 00644 ND_rw(rv) = ND_rw(cur) + ND_rw(new) + GD_nodesep(g) / 2; 00645 } 00646 return rv; 00647 } 00648 00649 static void 00650 potential_leaf(graph_t * g, edge_t * e, node_t * leaf) 00651 { 00652 node_t *par; 00653 00654 if ((ED_tail_port(e).p.x) || (ED_head_port(e).p.x)) 00655 return; 00656 if ((ED_minlen(e) != 1) || (ND_order(agtail(e)) > 0)) 00657 return; 00658 par = ((leaf != aghead(e)) ? aghead(e) : agtail(e)); 00659 ND_ranktype(leaf) = LEAFSET; 00660 if (par == agtail(e)) 00661 GD_outleaf(par) = merge_leaves(g, GD_outleaf(par), leaf); 00662 else 00663 GD_inleaf(par) = merge_leaves(g, GD_inleaf(par), leaf); 00664 } 00665 00666 static void 00667 collapse_leaves(graph_t * g) 00668 { 00669 node_t *n; 00670 edge_t *e; 00671 00672 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00673 00674 /* consider n as a potential leaf of some other node. */ 00675 if ((ND_ranktype(n) != NOCMD) || (ND_order(n))) 00676 continue; 00677 if (agfstout(g, n) == NULL) { 00678 if ((e = agfstin(g, n)) && (agnxtin(g, e) == NULL)) { 00679 #ifndef WITH_CGRAPH 00680 potential_leaf(g, e, n); 00681 #else 00682 potential_leaf(g, AGMKOUT(e), n); 00683 #endif 00684 continue; 00685 } 00686 } 00687 if (agfstin(g, n) == NULL) { 00688 if ((e = agfstout(g, n)) && (agnxtout(g, e) == NULL)) { 00689 potential_leaf(g, e, n); 00690 continue; 00691 } 00692 } 00693 } 00694 } 00695 #endif 00696 00697 #ifdef WITH_CGRAPH 00698 /* new ranking code: 00699 * Allows more constraints 00700 * Copy of level.c in dotgen2 00701 * Many of the utility functions are simpler or gone with 00702 * cgraph library. 00703 */ 00704 #define BACKWARD_PENALTY 1000 00705 #define STRONG_CLUSTER_WEIGHT 1000 00706 #define NORANK 6 00707 #define ROOT "\177root" 00708 #define TOPNODE "\177top" 00709 #define BOTNODE "\177bot" 00710 00711 /* hops is not used in dot, so we overload it to 00712 * contain the index of the connected component 00713 */ 00714 #define ND_comp(n) ND_hops(n) 00715 00716 extern int rank2(Agraph_t *, int, int, int); 00717 00718 static void set_parent(graph_t* g, graph_t* p) 00719 { 00720 GD_parent(g) = p; 00721 make_new_cluster(p, g); 00722 node_induce(p, g); 00723 } 00724 00725 static int is_empty(graph_t * g) 00726 { 00727 return (!agfstnode(g)); 00728 } 00729 00730 static int is_a_strong_cluster(graph_t * g) 00731 { 00732 int rv; 00733 char *str = agget(g, "compact"); 00734 /* rv = mapBool((str), TRUE); */ 00735 rv = mapBool((str), FALSE); 00736 return rv; 00737 } 00738 00739 static int rankset_kind(graph_t * g) 00740 { 00741 char *str = agget(g, "rank"); 00742 00743 if (str && str[0]) { 00744 if (!strcmp(str, "min")) 00745 return MINRANK; 00746 if (!strcmp(str, "source")) 00747 return SOURCERANK; 00748 if (!strcmp(str, "max")) 00749 return MAXRANK; 00750 if (!strcmp(str, "sink")) 00751 return SINKRANK; 00752 if (!strcmp(str, "same")) 00753 return SAMERANK; 00754 } 00755 return NORANK; 00756 } 00757 00758 static int is_nonconstraint(edge_t * e) 00759 { 00760 char *constr; 00761 00762 if (E_constr && (constr = agxget(e, E_constr))) { 00763 if (constr[0] && mapbool(constr) == FALSE) 00764 return TRUE; 00765 } 00766 return FALSE; 00767 } 00768 00769 static node_t *find(node_t * n) 00770 { 00771 node_t *set; 00772 if ((set = ND_set(n))) { 00773 if (set != n) 00774 set = ND_set(n) = find(set); 00775 } else 00776 set = ND_set(n) = n; 00777 return set; 00778 } 00779 00780 static node_t *union_one(node_t * leader, node_t * n) 00781 { 00782 if (n) 00783 return (ND_set(find(n)) = find(leader)); 00784 else 00785 return leader; 00786 } 00787 00788 static node_t *union_all(graph_t * g) 00789 { 00790 node_t *n, *leader; 00791 00792 n = agfstnode(g); 00793 if (!n) 00794 return n; 00795 leader = find(n); 00796 while ((n = agnxtnode(g, n))) 00797 union_one(leader, n); 00798 return leader; 00799 } 00800 00801 static void compile_samerank(graph_t * ug, graph_t * parent_clust) 00802 { 00803 graph_t *s; /* subgraph being scanned */ 00804 graph_t *clust; /* cluster that contains the rankset */ 00805 node_t *n, *leader; 00806 00807 if (is_empty(ug)) 00808 return; 00809 if (is_a_cluster(ug)) { 00810 clust = ug; 00811 if (parent_clust) { 00812 GD_level(ug) = GD_level(parent_clust) + 1; 00813 set_parent(ug, parent_clust); 00814 } 00815 else 00816 GD_level(ug) = 0; 00817 } else 00818 clust = parent_clust; 00819 00820 /* process subgraphs of this subgraph */ 00821 for (s = agfstsubg(ug); s; s = agnxtsubg(s)) 00822 compile_samerank(s, clust); 00823 00824 /* process this subgraph as a cluster */ 00825 if (is_a_cluster(ug)) { 00826 for (n = agfstnode(ug); n; n = agnxtnode(ug, n)) { 00827 if (ND_clust(n) == 0) 00828 ND_clust(n) = ug; 00829 #ifdef DEBUG 00830 fprintf(stderr, "(%s) %s %p\n", agnameof(ug), agnameof(n), 00831 ND_clust(n)); 00832 #endif 00833 } 00834 } 00835 00836 /* process this subgraph as a rankset */ 00837 switch (rankset_kind(ug)) { 00838 case SOURCERANK: 00839 GD_has_sourcerank(clust) = TRUE; /* fall through */ 00840 case MINRANK: 00841 leader = union_all(ug); 00842 GD_minrep(clust) = union_one(leader, GD_minrep(clust)); 00843 break; 00844 case SINKRANK: 00845 GD_has_sinkrank(clust) = TRUE; /* fall through */ 00846 case MAXRANK: 00847 leader = union_all(ug); 00848 GD_maxrep(clust) = union_one(leader, GD_maxrep(clust)); 00849 break; 00850 case SAMERANK: 00851 leader = union_all(ug); 00852 /* do we need to record these ranksets? */ 00853 break; 00854 case NORANK: 00855 break; 00856 default: /* unrecognized - warn and do nothing */ 00857 agerr(AGWARN, "%s has unrecognized rank=%s", agnameof(ug), 00858 agget(ug, "rank")); 00859 } 00860 00861 /* a cluster may become degenerate */ 00862 if (is_a_cluster(ug) && GD_minrep(ug)) { 00863 if (GD_minrep(ug) == GD_maxrep(ug)) { 00864 node_t *up = union_all(ug); 00865 GD_minrep(ug) = up; 00866 GD_maxrep(ug) = up; 00867 } 00868 } 00869 } 00870 00871 static graph_t *dot_lca(graph_t * c0, graph_t * c1) 00872 { 00873 while (c0 != c1) { 00874 if (GD_level(c0) >= GD_level(c1)) 00875 c0 = GD_parent(c0); 00876 else 00877 c1 = GD_parent(c1); 00878 } 00879 return c0; 00880 } 00881 00882 static int is_internal_to_cluster(edge_t * e) 00883 { 00884 graph_t *par, *ct, *ch; 00885 ct = ND_clust(agtail(e)); 00886 ch = ND_clust(aghead(e)); 00887 if (ct == ch) 00888 return TRUE; 00889 par = dot_lca(ct, ch); 00890 /* if (par == agroot(par)) */ 00891 /* return FALSE; */ 00892 if ((par == ct) || (par == ch)) 00893 return TRUE; 00894 return FALSE; 00895 } 00896 00897 static node_t* Last_node; 00898 static node_t* makeXnode (graph_t* G, char* name) 00899 { 00900 node_t *n = agnode(G, name, 1); 00901 alloc_elist(4, ND_in(n)); 00902 alloc_elist(4, ND_out(n)); 00903 if (Last_node) { 00904 ND_prev(n) = Last_node; 00905 ND_next(Last_node) = n; 00906 } else { 00907 ND_prev(n) = NULL; 00908 GD_nlist(G) = n; 00909 } 00910 Last_node = n; 00911 ND_next(n) = NULL; 00912 00913 return n; 00914 } 00915 00916 static void compile_nodes(graph_t * g, graph_t * Xg) 00917 { 00918 /* build variables */ 00919 node_t *n; 00920 00921 Last_node = NULL; 00922 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00923 if (find(n) == n) 00924 ND_rep(n) = makeXnode (Xg, agnameof(n)); 00925 } 00926 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00927 if (ND_rep(n) == 0) 00928 ND_rep(n) = ND_rep(find(n)); 00929 } 00930 } 00931 00932 static void merge(edge_t * e, int minlen, int weight) 00933 { 00934 ED_minlen(e) = MAX(ED_minlen(e), minlen); 00935 ED_weight(e) += weight; 00936 } 00937 00938 static void strong(graph_t * g, node_t * t, node_t * h, edge_t * orig) 00939 { 00940 edge_t *e; 00941 if ((e = agfindedge(g, t, h)) || 00942 (e = agfindedge(g, h, t)) || (e = agedge(g, t, h, 0, 1))) 00943 merge(e, ED_minlen(orig), ED_weight(orig)); 00944 else 00945 agerr(AGERR, "ranking: failure to create strong constraint edge between nodes %s and %s\n", 00946 agnameof(t), agnameof(h)); 00947 } 00948 00949 static void weak(graph_t * g, node_t * t, node_t * h, edge_t * orig) 00950 { 00951 node_t *v; 00952 edge_t *e, *f; 00953 static int id; 00954 char buf[100]; 00955 00956 for (e = agfstin(g, t); e; e = agnxtin(g, e)) { 00957 /* merge with existing weak edge (e,f) */ 00958 v = agtail(e); 00959 if ((f = agfstout(g, v)) && (aghead(f) == h)) { 00960 return; 00961 } 00962 } 00963 if (!e) { 00964 sprintf (buf, "_weak_%d", id++); 00965 v = makeXnode(g, buf); 00966 e = agedge(g, v, t, 0, 1); 00967 f = agedge(g, v, h, 0, 1); 00968 } 00969 ED_minlen(e) = MAX(ED_minlen(e), 0); /* effectively a nop */ 00970 ED_weight(e) += ED_weight(orig) * BACKWARD_PENALTY; 00971 ED_minlen(f) = MAX(ED_minlen(f), ED_minlen(orig)); 00972 ED_weight(f) += ED_weight(orig); 00973 } 00974 00975 static void compile_edges(graph_t * ug, graph_t * Xg) 00976 { 00977 node_t *n; 00978 edge_t *e; 00979 node_t *Xt, *Xh; 00980 graph_t *tc, *hc; 00981 00982 /* build edge constraints */ 00983 for (n = agfstnode(ug); n; n = agnxtnode(ug, n)) { 00984 Xt = ND_rep(n); 00985 for (e = agfstout(ug, n); e; e = agnxtout(ug, e)) { 00986 if (is_nonconstraint(e)) 00987 continue; 00988 Xh = ND_rep(find(aghead(e))); 00989 if (Xt == Xh) 00990 continue; 00991 00992 tc = ND_clust(agtail(e)); 00993 hc = ND_clust(aghead(e)); 00994 00995 if (is_internal_to_cluster(e)) { 00996 /* determine if graph requires reversed edge */ 00997 if ((find(agtail(e)) == GD_maxrep(ND_clust(agtail(e)))) 00998 || (find(aghead(e)) == GD_minrep(ND_clust(aghead(e))))) { 00999 node_t *temp = Xt; 01000 Xt = Xh; 01001 Xh = temp; 01002 } 01003 strong(Xg, Xt, Xh, e); 01004 } else { 01005 if (is_a_strong_cluster(tc) || is_a_strong_cluster(hc)) 01006 weak(Xg, Xt, Xh, e); 01007 else 01008 strong(Xg, Xt, Xh, e); 01009 } 01010 } 01011 } 01012 } 01013 01014 static void compile_clusters(graph_t* g, graph_t* Xg, node_t* top, node_t* bot) 01015 { 01016 node_t *n; 01017 node_t *rep; 01018 edge_t *e; 01019 graph_t *sub; 01020 01021 if (is_a_cluster(g) && is_a_strong_cluster(g)) { 01022 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 01023 if (agfstin(g, n) == 0) { 01024 rep = ND_rep(find(n)); 01025 if (!top) top = makeXnode(Xg,TOPNODE); 01026 agedge(Xg, top, rep, 0, 1); 01027 } 01028 if (agfstout(g, n) == 0) { 01029 rep = ND_rep(find(n)); 01030 if (!bot) bot = makeXnode(Xg,BOTNODE); 01031 agedge(Xg, rep, bot, 0, 1); 01032 } 01033 } 01034 if (top && bot) { 01035 e = agedge(Xg, top, bot, 0, 1); 01036 merge(e, 0, STRONG_CLUSTER_WEIGHT); 01037 } 01038 } 01039 for (sub = agfstsubg(g); sub; sub = agnxtsubg(sub)) 01040 compile_clusters(sub, Xg, top, bot); 01041 } 01042 01043 static void reverse_edge2(graph_t * g, edge_t * e) 01044 { 01045 edge_t *rev; 01046 01047 rev = agfindedge(g, aghead(e), agtail(e)); 01048 if (!rev) 01049 rev = agedge(g, aghead(e), agtail(e), 0, 1); 01050 merge(rev, ED_minlen(e), ED_weight(e)); 01051 agdelete(g, e); 01052 } 01053 01054 static void dfs(graph_t * g, node_t * v) 01055 { 01056 edge_t *e, *f; 01057 node_t *w; 01058 01059 if (ND_mark(v)) 01060 return; 01061 ND_mark(v) = TRUE; 01062 ND_onstack(v) = TRUE; 01063 for (e = agfstout(g, v); e; e = f) { 01064 f = agnxtout(g, e); 01065 w = aghead(e); 01066 if (ND_onstack(w)) 01067 reverse_edge2(g, e); 01068 else { 01069 if (ND_mark(w) == FALSE) 01070 dfs(g, w); 01071 } 01072 } 01073 ND_onstack(v) = FALSE; 01074 } 01075 01076 static void break_cycles(graph_t * g) 01077 { 01078 node_t *n; 01079 01080 for (n = agfstnode(g); n; n = agnxtnode(g, n)) 01081 ND_mark(n) = ND_onstack(n) = FALSE; 01082 for (n = agfstnode(g); n; n = agnxtnode(g, n)) 01083 dfs(g, n); 01084 } 01085 01086 static void setMinMax (graph_t* g, int doRoot) 01087 { 01088 int c, v; 01089 node_t *n; 01090 node_t* leader; 01091 01092 /* Do child clusters */ 01093 for (c = 1; c <= GD_n_cluster(g); c++) 01094 setMinMax(GD_clust(g)[c], 0); 01095 01096 if (!GD_parent(g) && !doRoot) // root graph 01097 return; 01098 01099 GD_minrank(g) = MAXSHORT; 01100 GD_maxrank(g) = -1; 01101 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 01102 v = ND_rank(n); 01103 if (GD_maxrank(g) < v) 01104 GD_maxrank(g) = v; 01105 if (GD_minrank(g) > v) { 01106 GD_minrank(g) = v; 01107 leader = n; 01108 } 01109 } 01110 GD_leader(g) = leader; 01111 } 01112 01113 /* readout_levels: 01114 * Store node rank information in original graph. 01115 * Set rank bounds in graph and clusters 01116 * Free added data structures. 01117 * 01118 * rank2 is called with balance=1, which ensures that minrank=0 01119 */ 01120 static void readout_levels(graph_t * g, graph_t * Xg, int ncc) 01121 { 01122 node_t *n; 01123 node_t *xn; 01124 int* minrk = NULL; 01125 int doRoot = 0; 01126 01127 GD_minrank(g) = MAXSHORT; 01128 GD_maxrank(g) = -1; 01129 if (ncc > 1) { 01130 int i; 01131 minrk = N_NEW(ncc+1,int); 01132 for (i = 1; i <= ncc; i++) 01133 minrk[i] = MAXSHORT; 01134 } 01135 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 01136 xn = ND_rep(find(n)); 01137 ND_rank(n) = ND_rank(xn); 01138 if (GD_maxrank(g) < ND_rank(n)) 01139 GD_maxrank(g) = ND_rank(n); 01140 if (GD_minrank(g) > ND_rank(n)) 01141 GD_minrank(g) = ND_rank(n); 01142 if (minrk) { 01143 ND_comp(n) = ND_comp(xn); 01144 minrk[ND_comp(n)] = MIN(minrk[ND_comp(n)],ND_rank(n)); 01145 } 01146 } 01147 if (minrk) { 01148 for (n = agfstnode(g); n; n = agnxtnode(g, n)) 01149 ND_rank(n) -= minrk[ND_comp(n)]; 01150 /* Non-uniform shifting, so recompute maxrank/minrank of root graph */ 01151 doRoot = 1; 01152 } 01153 else if (GD_minrank(g) > 0) { /* should never happen */ 01154 int delta = GD_minrank(g); 01155 for (n = agfstnode(g); n; n = agnxtnode(g, n)) 01156 ND_rank(n) -= delta; 01157 GD_minrank(g) -= delta; 01158 GD_maxrank(g) -= delta; 01159 } 01160 01161 setMinMax(g, doRoot); 01162 01163 /* release fastgraph memory from Xg */ 01164 for (n = agfstnode(Xg); n; n = agnxtnode(Xg, n)) { 01165 free_list(ND_in(n)); 01166 free_list(ND_out(n)); 01167 } 01168 01169 free(ND_alg(agfstnode(g))); 01170 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 01171 ND_alg(n) = NULL; 01172 } 01173 if (minrk) 01174 free (minrk); 01175 } 01176 01177 static void dfscc(graph_t * g, node_t * n, int cc) 01178 { 01179 edge_t *e; 01180 if (ND_comp(n) == 0) { 01181 ND_comp(n) = cc; 01182 for (e = agfstout(g, n); e; e = agnxtout(g, e)) 01183 dfscc(g, aghead(e), cc); 01184 for (e = agfstin(g, n); e; e = agnxtin(g, e)) 01185 dfscc(g, agtail(e), cc); 01186 } 01187 } 01188 01189 static int connect_components(graph_t * g) 01190 { 01191 int cc = 0; 01192 node_t *n; 01193 01194 for (n = agfstnode(g); n; n = agnxtnode(g, n)) 01195 ND_comp(n) = 0; 01196 for (n = agfstnode(g); n; n = agnxtnode(g, n)) 01197 if (ND_comp(n) == 0) 01198 dfscc(g, n, ++cc); 01199 if (cc > 1) { 01200 node_t *root = makeXnode(g, ROOT); 01201 int ncc = 1; 01202 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 01203 if (ND_comp(n) == ncc) { 01204 (void) agedge(g, root, n, 0, 1); 01205 ncc++; 01206 } 01207 } 01208 } 01209 return (cc); 01210 } 01211 01212 static void add_fast_edges (graph_t * g) 01213 { 01214 node_t *n; 01215 edge_t *e; 01216 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 01217 for (e = agfstout(g, n); e; e = agnxtout(g, e)) { 01218 elist_append(e, ND_out(n)); 01219 elist_append(e, ND_in(aghead(e))); 01220 } 01221 } 01222 } 01223 01224 static void my_init_graph(Agraph_t *g, Agobj_t *graph, void *arg) 01225 { int *sz = arg; agbindrec(graph,"level graph rec",sz[0],TRUE); } 01226 static void my_init_node(Agraph_t *g, Agobj_t *node, void *arg) 01227 { int *sz = arg; agbindrec(node,"level node rec",sz[1],TRUE); } 01228 static void my_init_edge(Agraph_t *g, Agobj_t *edge, void *arg) 01229 { int *sz = arg; agbindrec(edge,"level edge rec",sz[2],TRUE); } 01230 static Agcbdisc_t mydisc = { {my_init_graph,0,0}, {my_init_node,0,0}, {my_init_edge,0,0} }; 01231 01232 int infosizes[] = { 01233 sizeof(Agraphinfo_t), 01234 sizeof(Agnodeinfo_t), 01235 sizeof(Agedgeinfo_t) 01236 }; 01237 01238 void dot2_rank(graph_t * g, aspect_t* asp) 01239 { 01240 int ssize; 01241 int ncc, maxiter = INT_MAX; 01242 char *s; 01243 #ifdef ALLOW_LEVELS 01244 attrsym_t* N_level; 01245 #endif 01246 Last_node = NULL; 01247 graph_t *Xg = agopen("level assignment constraints", Agstrictdirected, 0); 01248 agbindrec(Xg,"level graph rec",sizeof(Agraphinfo_t),TRUE); 01249 agpushdisc(Xg,&mydisc,infosizes); 01250 01251 edgelabel_ranks(g); 01252 01253 if ((s = agget(g, "nslimit1"))) 01254 maxiter = atof(s) * agnnodes(g); 01255 else 01256 maxiter = INT_MAX; 01257 01258 compile_samerank(g, 0); 01259 compile_nodes(g, Xg); 01260 compile_edges(g, Xg); 01261 compile_clusters(g, Xg, 0, 0); 01262 break_cycles(Xg); 01263 ncc = connect_components(Xg); 01264 add_fast_edges (Xg); 01265 01266 if (asp) { 01267 init_UF_size(Xg); 01268 initEdgeTypes(Xg); 01269 } 01270 01271 if ((s = agget(g, "searchsize"))) 01272 ssize = atoi(s); 01273 else 01274 ssize = -1; 01275 rank2(Xg, 1, maxiter, ssize); 01276 /* fastgr(Xg); */ 01277 readout_levels(g, Xg, ncc); 01278 #ifdef DEBUG 01279 fprintf (stderr, "Xg %d nodes %d edges\n", agnnodes(Xg), agnedges(Xg)); 01280 #endif 01281 agclose(Xg); 01282 } 01283 01284 #endif /* WITH_CGRAPH */ 01285 /* end of new ranking code 01286 */
1.7.5