|
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 * dot_mincross(g) takes a ranked graphs, and finds an ordering 00017 * that avoids edge crossings. clusters are expanded. 00018 * N.B. the rank structure is global (not allocated per cluster) 00019 * because mincross may compare nodes in different clusters. 00020 */ 00021 00022 #include "dot.h" 00023 00024 /* #define DEBUG */ 00025 #define MARK(v) (ND_mark(v)) 00026 #define saveorder(v) (ND_coord(v)).x 00027 #define flatindex(v) ND_low(v) 00028 00029 /* forward declarations */ 00030 static boolean medians(graph_t * g, int r0, int r1); 00031 static int nodeposcmpf(node_t ** n0, node_t ** n1); 00032 static int edgeidcmpf(edge_t ** e0, edge_t ** e1); 00033 static void flat_breakcycles(graph_t * g); 00034 static void flat_reorder(graph_t * g); 00035 static void flat_search(graph_t * g, node_t * v); 00036 static void init_mincross(graph_t * g); 00037 static void merge2(graph_t * g); 00038 static void init_mccomp(graph_t * g, int c); 00039 static void cleanup2(graph_t * g, int nc); 00040 static int mincross_clust(graph_t * par, graph_t * g, int); 00041 static int mincross(graph_t * g, int startpass, int endpass, int); 00042 static void mincross_step(graph_t * g, int pass); 00043 static void mincross_options(graph_t * g); 00044 static void save_best(graph_t * g); 00045 static void restore_best(graph_t * g); 00046 static adjmatrix_t *new_matrix(int i, int j); 00047 static void free_matrix(adjmatrix_t * p); 00048 #ifdef DEBUG 00049 void check_rs(graph_t * g, int null_ok); 00050 void check_order(void); 00051 void check_vlists(graph_t * g); 00052 void node_in_root_vlist(node_t * n); 00053 #endif 00054 00055 00056 /* mincross parameters */ 00057 static int MinQuit; 00058 static double Convergence; 00059 00060 static graph_t *Root; 00061 static int GlobalMinRank, GlobalMaxRank; 00062 static edge_t **TE_list; 00063 static int *TI_list; 00064 static boolean ReMincross; 00065 00066 /* dot_mincross: 00067 * Minimize edge crossings 00068 * Note that nodes are not placed into GD_rank(g) until mincross() 00069 * is called. 00070 */ 00071 void dot_mincross(graph_t * g, int doBalance) 00072 { 00073 int c, nc; 00074 char *s; 00075 00076 init_mincross(g); 00077 00078 for (nc = c = 0; c < GD_comp(g).size; c++) { 00079 init_mccomp(g, c); 00080 nc += mincross(g, 0, 2, doBalance); 00081 } 00082 00083 merge2(g); 00084 00085 /* run mincross on contents of each cluster */ 00086 for (c = 1; c <= GD_n_cluster(g); c++) { 00087 nc += mincross_clust(g, GD_clust(g)[c], doBalance); 00088 #ifdef DEBUG 00089 check_vlists(GD_clust(g)[c]); 00090 check_order(); 00091 #endif 00092 } 00093 00094 if ((GD_n_cluster(g) > 0) 00095 && (!(s = agget(g, "remincross")) || (mapbool(s)))) { 00096 mark_lowclusters(g); 00097 ReMincross = TRUE; 00098 nc = mincross(g, 2, 2, doBalance); 00099 #ifdef DEBUG 00100 for (c = 1; c <= GD_n_cluster(g); c++) 00101 check_vlists(GD_clust(g)[c]); 00102 #endif 00103 } 00104 cleanup2(g, nc); 00105 } 00106 00107 static adjmatrix_t *new_matrix(int i, int j) 00108 { 00109 adjmatrix_t *rv = NEW(adjmatrix_t); 00110 rv->nrows = i; 00111 rv->ncols = j; 00112 rv->data = N_NEW(i * j, char); 00113 return rv; 00114 } 00115 00116 static void free_matrix(adjmatrix_t * p) 00117 { 00118 if (p) { 00119 free(p->data); 00120 free(p); 00121 } 00122 } 00123 00124 #define ELT(M,i,j) (M->data[((i)*M->ncols)+(j)]) 00125 00126 static void init_mccomp(graph_t * g, int c) 00127 { 00128 int r; 00129 00130 GD_nlist(g) = GD_comp(g).list[c]; 00131 if (c > 0) { 00132 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) { 00133 GD_rank(g)[r].v = GD_rank(g)[r].v + GD_rank(g)[r].n; 00134 GD_rank(g)[r].n = 0; 00135 } 00136 } 00137 } 00138 00139 static int betweenclust(edge_t * e) 00140 { 00141 while (ED_to_orig(e)) 00142 e = ED_to_orig(e); 00143 return (ND_clust(agtail(e)) != ND_clust(aghead(e))); 00144 } 00145 00146 static void do_ordering_node (graph_t * g, node_t* n, int outflag) 00147 { 00148 int i, ne; 00149 node_t *u, *v; 00150 edge_t *e, *f, *fe; 00151 edge_t **sortlist = TE_list; 00152 00153 if (ND_clust(n)) 00154 return; 00155 if (outflag) { 00156 for (i = ne = 0; (e = ND_out(n).list[i]); i++) 00157 if (!betweenclust(e)) 00158 sortlist[ne++] = e; 00159 } else { 00160 for (i = ne = 0; (e = ND_in(n).list[i]); i++) 00161 if (!betweenclust(e)) 00162 sortlist[ne++] = e; 00163 } 00164 if (ne <= 1) 00165 return; 00166 /* write null terminator at end of list. 00167 requires +1 in TE_list alloccation */ 00168 sortlist[ne] = 0; 00169 qsort(sortlist, ne, sizeof(sortlist[0]), (qsort_cmpf) edgeidcmpf); 00170 for (ne = 1; (f = sortlist[ne]); ne++) { 00171 e = sortlist[ne - 1]; 00172 if (outflag) { 00173 u = aghead(e); 00174 v = aghead(f); 00175 } else { 00176 u = agtail(e); 00177 v = agtail(f); 00178 } 00179 if (find_flat_edge(u, v)) 00180 return; 00181 fe = new_virtual_edge(u, v, NULL); 00182 ED_edge_type(fe) = FLATORDER; 00183 flat_edge(g, fe); 00184 } 00185 } 00186 00187 static void do_ordering(graph_t * g, int outflag) 00188 { 00189 /* Order all nodes in graph */ 00190 node_t *n; 00191 00192 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00193 do_ordering_node (g, n, outflag); 00194 } 00195 } 00196 00197 static void do_ordering_for_nodes(graph_t * g) 00198 { 00199 /* Order nodes which have the "ordered" attribute */ 00200 node_t *n; 00201 const char *ordering; 00202 00203 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00204 if ((ordering = late_string(n, N_ordering, NULL))) { 00205 if (streq(ordering, "out")) 00206 do_ordering_node(g, n, TRUE); 00207 else if (streq(ordering, "in")) 00208 do_ordering_node(g, n, FALSE); 00209 else if (ordering[0]) 00210 agerr(AGERR, "ordering '%s' not recognized for node '%s'.\n", ordering, agnameof(n)); 00211 } 00212 } 00213 } 00214 00215 /* ordered_edges: 00216 * handle case where graph specifies edge ordering 00217 * If the graph does not have an ordering attribute, we then 00218 * check for nodes having the attribute. 00219 * Note that, in this implementation, the value of G_ordering 00220 * dominates the value of N_ordering. 00221 */ 00222 static void ordered_edges(graph_t * g) 00223 { 00224 char *ordering; 00225 00226 if (!G_ordering && !N_ordering) 00227 return; 00228 if ((ordering = late_string(g, G_ordering, NULL))) { 00229 if (streq(ordering, "out")) 00230 do_ordering(g, TRUE); 00231 else if (streq(ordering, "in")) 00232 do_ordering(g, FALSE); 00233 else if (ordering[0]) 00234 agerr(AGERR, "ordering '%s' not recognized.\n", ordering); 00235 } 00236 else 00237 { 00238 #ifndef WITH_CGRAPH 00239 /* search meta-graph to find subgraphs that may be ordered */ 00240 graph_t *mg, *subg; 00241 node_t *mm, *mn; 00242 edge_t *me; 00243 00244 mm = g->meta_node; 00245 mg = mm->graph; 00246 for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) { 00247 mn = me->head; 00248 subg = agusergraph(mn); 00249 #else /* WITH_CGRAPH */ 00250 graph_t *subg; 00251 00252 for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) { 00253 #endif /* WITH_CGRAPH */ 00254 /* clusters are processed by separate calls to ordered_edges */ 00255 if (!is_cluster(subg)) 00256 ordered_edges(subg); 00257 } 00258 if (N_ordering) do_ordering_for_nodes (g); 00259 } 00260 } 00261 00262 static int mincross_clust(graph_t * par, graph_t * g, int doBalance) 00263 { 00264 int c, nc; 00265 00266 expand_cluster(g); 00267 ordered_edges(g); 00268 flat_breakcycles(g); 00269 flat_reorder(g); 00270 nc = mincross(g, 2, 2, doBalance); 00271 00272 for (c = 1; c <= GD_n_cluster(g); c++) 00273 nc += mincross_clust(g, GD_clust(g)[c], doBalance); 00274 00275 save_vlist(g); 00276 return nc; 00277 } 00278 00279 static int left2right(graph_t * g, node_t * v, node_t * w) 00280 { 00281 adjmatrix_t *M; 00282 int rv; 00283 00284 /* CLUSTER indicates orig nodes of clusters, and vnodes of skeletons */ 00285 if (ReMincross == FALSE) { 00286 if ((ND_clust(v) != ND_clust(w)) && (ND_clust(v)) && (ND_clust(w))) { 00287 /* the following allows cluster skeletons to be swapped */ 00288 if ((ND_ranktype(v) == CLUSTER) 00289 && (ND_node_type(v) == VIRTUAL)) 00290 return FALSE; 00291 if ((ND_ranktype(w) == CLUSTER) 00292 && (ND_node_type(w) == VIRTUAL)) 00293 return FALSE; 00294 return TRUE; 00295 /*return ((ND_ranktype(v) != CLUSTER) && (ND_ranktype(w) != CLUSTER)); */ 00296 } 00297 } else { 00298 if ((ND_clust(v)) != (ND_clust(w))) 00299 return TRUE; 00300 } 00301 M = GD_rank(g)[ND_rank(v)].flat; 00302 if (M == NULL) 00303 rv = FALSE; 00304 else { 00305 if (GD_flip(g)) { 00306 node_t *t = v; 00307 v = w; 00308 w = t; 00309 } 00310 rv = ELT(M, flatindex(v), flatindex(w)); 00311 } 00312 return rv; 00313 } 00314 00315 static int in_cross(node_t * v, node_t * w) 00316 { 00317 register edge_t **e1, **e2; 00318 register int inv, cross = 0, t; 00319 00320 for (e2 = ND_in(w).list; *e2; e2++) { 00321 register int cnt = ED_xpenalty(*e2); 00322 00323 inv = ND_order((agtail(*e2))); 00324 00325 for (e1 = ND_in(v).list; *e1; e1++) { 00326 t = ND_order(agtail(*e1)) - inv; 00327 if ((t > 0) 00328 || ((t == 0) 00329 && ( ED_tail_port(*e1).p.x > ED_tail_port(*e2).p.x))) 00330 cross += ED_xpenalty(*e1) * cnt; 00331 } 00332 } 00333 return cross; 00334 } 00335 00336 static int out_cross(node_t * v, node_t * w) 00337 { 00338 register edge_t **e1, **e2; 00339 register int inv, cross = 0, t; 00340 00341 for (e2 = ND_out(w).list; *e2; e2++) { 00342 register int cnt = ED_xpenalty(*e2); 00343 inv = ND_order(aghead(*e2)); 00344 00345 for (e1 = ND_out(v).list; *e1; e1++) { 00346 t = ND_order(aghead(*e1)) - inv; 00347 if ((t > 0) 00348 || ((t == 0) 00349 && ((ED_head_port(*e1)).p.x > (ED_head_port(*e2)).p.x))) 00350 cross += ((ED_xpenalty(*e1)) * cnt); 00351 } 00352 } 00353 return cross; 00354 00355 } 00356 00357 static void exchange(node_t * v, node_t * w) 00358 { 00359 int vi, wi, r; 00360 00361 r = ND_rank(v); 00362 vi = ND_order(v); 00363 wi = ND_order(w); 00364 ND_order(v) = wi; 00365 GD_rank(Root)[r].v[wi] = v; 00366 ND_order(w) = vi; 00367 GD_rank(Root)[r].v[vi] = w; 00368 } 00369 00370 static void balanceNodes(graph_t * g, int r, node_t * v, node_t * w) 00371 { 00372 node_t *s; /* separator node */ 00373 int sepIndex; 00374 int nullType; /* type of null nodes */ 00375 int cntDummy = 0, cntOri = 0; 00376 int k = 0, m = 0, k1 = 0, m1 = 0, i = 0; 00377 00378 /* we only consider v and w of different types */ 00379 if (ND_node_type(v) == ND_node_type(w)) 00380 return; 00381 00382 /* count the number of dummy and original nodes */ 00383 for (i = 0; i < GD_rank(g)[r].n; i++) { 00384 if (ND_node_type(GD_rank(g)[r].v[i]) == NORMAL) 00385 cntOri++; 00386 else 00387 cntDummy++; 00388 } 00389 00390 if (cntOri < cntDummy) { 00391 if (ND_node_type(v) == NORMAL) 00392 s = v; 00393 else 00394 s = w; 00395 } else { 00396 if (ND_node_type(v) == NORMAL) 00397 s = w; 00398 else 00399 s = v; 00400 } 00401 00402 /* get the separator node index */ 00403 for (i = 0; i < GD_rank(g)[r].n; i++) { 00404 if (GD_rank(g)[r].v[i] == s) 00405 sepIndex = i; 00406 } 00407 00408 nullType = (ND_node_type(s) == NORMAL) ? VIRTUAL : NORMAL; 00409 00410 /* count the number of null nodes to the left and 00411 * right of the separator node 00412 */ 00413 for (i = sepIndex - 1; i >= 0; i--) { 00414 if (ND_node_type(GD_rank(g)[r].v[i]) == nullType) 00415 k++; 00416 else 00417 break; 00418 } 00419 00420 for (i = sepIndex + 1; i < GD_rank(g)[r].n; i++) { 00421 if (ND_node_type(GD_rank(g)[r].v[i]) == nullType) 00422 m++; 00423 else 00424 break; 00425 } 00426 00427 /* now exchange v,w and calculate the same counts */ 00428 00429 exchange(v, w); 00430 00431 /* get the separator node index */ 00432 for (i = 0; i < GD_rank(g)[r].n; i++) { 00433 if (GD_rank(g)[r].v[i] == s) 00434 sepIndex = i; 00435 } 00436 00437 /* count the number of null nodes to the left and 00438 * right of the separator node 00439 */ 00440 for (i = sepIndex - 1; i >= 0; i--) { 00441 if (ND_node_type(GD_rank(g)[r].v[i]) == nullType) 00442 k1++; 00443 else 00444 break; 00445 } 00446 00447 for (i = sepIndex + 1; i < GD_rank(g)[r].n; i++) { 00448 if (ND_node_type(GD_rank(g)[r].v[i]) == nullType) 00449 m1++; 00450 else 00451 break; 00452 } 00453 00454 if (abs(k1 - m1) > abs(k - m)) { 00455 exchange(v, w); //revert to the original ordering 00456 } 00457 } 00458 00459 static int balance(graph_t * g) 00460 { 00461 int i, c0, c1, rv; 00462 node_t *v, *w; 00463 int r; 00464 00465 rv = 0; 00466 00467 for (r = GD_maxrank(g); r >= GD_minrank(g); r--) { 00468 00469 GD_rank(g)[r].candidate = FALSE; 00470 for (i = 0; i < GD_rank(g)[r].n - 1; i++) { 00471 v = GD_rank(g)[r].v[i]; 00472 w = GD_rank(g)[r].v[i + 1]; 00473 assert(ND_order(v) < ND_order(w)); 00474 if (left2right(g, v, w)) 00475 continue; 00476 c0 = c1 = 0; 00477 if (r > 0) { 00478 c0 += in_cross(v, w); 00479 c1 += in_cross(w, v); 00480 } 00481 00482 if (GD_rank(g)[r + 1].n > 0) { 00483 c0 += out_cross(v, w); 00484 c1 += out_cross(w, v); 00485 } 00486 #if 0 00487 if ((c1 < c0) || ((c0 > 0) && reverse && (c1 == c0))) { 00488 exchange(v, w); 00489 rv += (c0 - c1); 00490 GD_rank(Root)[r].valid = FALSE; 00491 GD_rank(g)[r].candidate = TRUE; 00492 00493 if (r > GD_minrank(g)) { 00494 GD_rank(Root)[r - 1].valid = FALSE; 00495 GD_rank(g)[r - 1].candidate = TRUE; 00496 } 00497 if (r < GD_maxrank(g)) { 00498 GD_rank(Root)[r + 1].valid = FALSE; 00499 GD_rank(g)[r + 1].candidate = TRUE; 00500 } 00501 } 00502 #endif 00503 00504 if (c1 <= c0) { 00505 balanceNodes(g, r, v, w); 00506 } 00507 } 00508 } 00509 return rv; 00510 } 00511 00512 static int transpose_step(graph_t * g, int r, int reverse) 00513 { 00514 int i, c0, c1, rv; 00515 node_t *v, *w; 00516 00517 rv = 0; 00518 GD_rank(g)[r].candidate = FALSE; 00519 for (i = 0; i < GD_rank(g)[r].n - 1; i++) { 00520 v = GD_rank(g)[r].v[i]; 00521 w = GD_rank(g)[r].v[i + 1]; 00522 assert(ND_order(v) < ND_order(w)); 00523 if (left2right(g, v, w)) 00524 continue; 00525 c0 = c1 = 0; 00526 if (r > 0) { 00527 c0 += in_cross(v, w); 00528 c1 += in_cross(w, v); 00529 } 00530 if (GD_rank(g)[r + 1].n > 0) { 00531 c0 += out_cross(v, w); 00532 c1 += out_cross(w, v); 00533 } 00534 if ((c1 < c0) || ((c0 > 0) && reverse && (c1 == c0))) { 00535 exchange(v, w); 00536 rv += (c0 - c1); 00537 GD_rank(Root)[r].valid = FALSE; 00538 GD_rank(g)[r].candidate = TRUE; 00539 00540 if (r > GD_minrank(g)) { 00541 GD_rank(Root)[r - 1].valid = FALSE; 00542 GD_rank(g)[r - 1].candidate = TRUE; 00543 } 00544 if (r < GD_maxrank(g)) { 00545 GD_rank(Root)[r + 1].valid = FALSE; 00546 GD_rank(g)[r + 1].candidate = TRUE; 00547 } 00548 } 00549 } 00550 return rv; 00551 } 00552 00553 static void transpose(graph_t * g, int reverse) 00554 { 00555 int r, delta; 00556 00557 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) 00558 GD_rank(g)[r].candidate = TRUE; 00559 do { 00560 delta = 0; 00561 #ifdef NOTDEF 00562 /* don't run both the upward and downward passes- they cancel. 00563 i tried making it depend on whether an odd or even pass, 00564 but that didn't help. */ 00565 for (r = GD_maxrank(g); r >= GD_minrank(g); r--) 00566 if (GD_rank(g)[r].candidate) 00567 delta += transpose_step(g, r, reverse); 00568 #endif 00569 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) { 00570 if (GD_rank(g)[r].candidate) { 00571 delta += transpose_step(g, r, reverse); 00572 } 00573 } 00574 /*} while (delta > ncross(g)*(1.0 - Convergence)); */ 00575 } while (delta >= 1); 00576 } 00577 00578 static int mincross(graph_t * g, int startpass, int endpass, int doBalance) 00579 { 00580 int maxthispass, iter, trying, pass; 00581 int cur_cross, best_cross; 00582 00583 if (startpass > 1) { 00584 cur_cross = best_cross = ncross(g); 00585 save_best(g); 00586 } else 00587 cur_cross = best_cross = INT_MAX; 00588 for (pass = startpass; pass <= endpass; pass++) { 00589 if (pass <= 1) { 00590 maxthispass = MIN(4, MaxIter); 00591 if (g == agroot(g)) 00592 build_ranks(g, pass); 00593 if (pass == 0) 00594 flat_breakcycles(g); 00595 flat_reorder(g); 00596 00597 if ((cur_cross = ncross(g)) <= best_cross) { 00598 save_best(g); 00599 best_cross = cur_cross; 00600 } 00601 trying = 0; 00602 } else { 00603 maxthispass = MaxIter; 00604 if (cur_cross > best_cross) 00605 restore_best(g); 00606 cur_cross = best_cross; 00607 } 00608 trying = 0; 00609 for (iter = 0; iter < maxthispass; iter++) { 00610 if (Verbose) 00611 fprintf(stderr, 00612 "mincross: pass %d iter %d trying %d cur_cross %d best_cross %d\n", 00613 pass, iter, trying, cur_cross, best_cross); 00614 if (trying++ >= MinQuit) 00615 break; 00616 if (cur_cross == 0) 00617 break; 00618 mincross_step(g, iter); 00619 if ((cur_cross = ncross(g)) <= best_cross) { 00620 save_best(g); 00621 if (cur_cross < Convergence * best_cross) 00622 trying = 0; 00623 best_cross = cur_cross; 00624 } 00625 } 00626 if (cur_cross == 0) 00627 break; 00628 } 00629 if (cur_cross > best_cross) 00630 restore_best(g); 00631 if (best_cross > 0) { 00632 transpose(g, FALSE); 00633 best_cross = ncross(g); 00634 } 00635 if (doBalance) { 00636 for (iter = 0; iter < maxthispass; iter++) 00637 balance(g); 00638 } 00639 00640 return best_cross; 00641 } 00642 00643 static void restore_best(graph_t * g) 00644 { 00645 node_t *n; 00646 int r; 00647 00648 for (n = GD_nlist(g); n; n = ND_next(n)) 00649 ND_order(n) = saveorder(n); 00650 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) { 00651 GD_rank(Root)[r].valid = FALSE; 00652 qsort(GD_rank(g)[r].v, GD_rank(g)[r].n, sizeof(GD_rank(g)[0].v[0]), 00653 (qsort_cmpf) nodeposcmpf); 00654 } 00655 } 00656 00657 static void save_best(graph_t * g) 00658 { 00659 node_t *n; 00660 for (n = GD_nlist(g); n; n = ND_next(n)) 00661 saveorder(n) = ND_order(n); 00662 } 00663 00664 /* merges the connected components of g */ 00665 static void merge_components(graph_t * g) 00666 { 00667 int c; 00668 node_t *u, *v; 00669 00670 if (GD_comp(g).size <= 1) 00671 return; 00672 u = NULL; 00673 for (c = 0; c < GD_comp(g).size; c++) { 00674 v = GD_comp(g).list[c]; 00675 if (u) 00676 ND_next(u) = v; 00677 ND_prev(v) = u; 00678 while (ND_next(v)) { 00679 v = ND_next(v); 00680 } 00681 u = v; 00682 } 00683 GD_comp(g).size = 1; 00684 GD_nlist(g) = GD_comp(g).list[0]; 00685 GD_minrank(g) = GlobalMinRank; 00686 GD_maxrank(g) = GlobalMaxRank; 00687 } 00688 00689 /* merge connected components, create globally consistent rank lists */ 00690 static void merge2(graph_t * g) 00691 { 00692 int i, r; 00693 node_t *v; 00694 00695 /* merge the components and rank limits */ 00696 merge_components(g); 00697 00698 /* install complete ranks */ 00699 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) { 00700 GD_rank(g)[r].n = GD_rank(g)[r].an; 00701 GD_rank(g)[r].v = GD_rank(g)[r].av; 00702 for (i = 0; i < GD_rank(g)[r].n; i++) { 00703 v = GD_rank(g)[r].v[i]; 00704 if (v == NULL) { 00705 if (Verbose) 00706 fprintf(stderr, 00707 "merge2: graph %s, rank %d has only %d < %d nodes\n", 00708 agnameof(g), r, i, GD_rank(g)[r].n); 00709 GD_rank(g)[r].n = i; 00710 break; 00711 } 00712 ND_order(v) = i; 00713 } 00714 } 00715 } 00716 00717 static void cleanup2(graph_t * g, int nc) 00718 { 00719 int i, j, r, c; 00720 node_t *v; 00721 edge_t *e; 00722 00723 if (TI_list) { 00724 free(TI_list); 00725 TI_list = NULL; 00726 } 00727 if (TE_list) { 00728 free(TE_list); 00729 TE_list = NULL; 00730 } 00731 /* fix vlists of clusters */ 00732 for (c = 1; c <= GD_n_cluster(g); c++) 00733 rec_reset_vlists(GD_clust(g)[c]); 00734 00735 /* remove node temporary edges for ordering nodes */ 00736 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) { 00737 for (i = 0; i < GD_rank(g)[r].n; i++) { 00738 v = GD_rank(g)[r].v[i]; 00739 ND_order(v) = i; 00740 if (ND_flat_out(v).list) { 00741 for (j = 0; (e = ND_flat_out(v).list[j]); j++) 00742 if (ED_edge_type(e) == FLATORDER) { 00743 delete_flat_edge(e); 00744 #ifdef WITH_CGRAPH 00745 free(e->base.data); 00746 #endif 00747 free(e); 00748 j--; 00749 } 00750 } 00751 } 00752 free_matrix(GD_rank(g)[r].flat); 00753 } 00754 if (Verbose) 00755 fprintf(stderr, "mincross %s: %d crossings, %.2f secs.\n", 00756 agnameof(g), nc, elapsed_sec()); 00757 } 00758 00759 static node_t *neighbor(node_t * v, int dir) 00760 { 00761 node_t *rv; 00762 00763 rv = NULL; 00764 if (dir < 0) { 00765 if (ND_order(v) > 0) 00766 rv = GD_rank(Root)[ND_rank(v)].v[ND_order(v) - 1]; 00767 } else 00768 rv = GD_rank(Root)[ND_rank(v)].v[ND_order(v) + 1]; 00769 return rv; 00770 } 00771 00772 static int is_a_normal_node_of(graph_t * g, node_t * v) 00773 { 00774 return ((ND_node_type(v) == NORMAL) && agcontains(g, v)); 00775 } 00776 00777 static int is_a_vnode_of_an_edge_of(graph_t * g, node_t * v) 00778 { 00779 if ((ND_node_type(v) == VIRTUAL) 00780 && (ND_in(v).size == 1) && (ND_out(v).size == 1)) { 00781 edge_t *e = ND_out(v).list[0]; 00782 while (ED_edge_type(e) != NORMAL) 00783 e = ED_to_orig(e); 00784 if (agcontains(g, e)) 00785 return TRUE; 00786 } 00787 return FALSE; 00788 } 00789 00790 static int inside_cluster(graph_t * g, node_t * v) 00791 { 00792 return (is_a_normal_node_of(g, v) | is_a_vnode_of_an_edge_of(g, v)); 00793 } 00794 00795 static node_t *furthestnode(graph_t * g, node_t * v, int dir) 00796 { 00797 node_t *u, *rv; 00798 00799 rv = u = v; 00800 while ((u = neighbor(u, dir))) { 00801 if (is_a_normal_node_of(g, u)) 00802 rv = u; 00803 else if (is_a_vnode_of_an_edge_of(g, u)) 00804 rv = u; 00805 } 00806 return rv; 00807 } 00808 00809 void save_vlist(graph_t * g) 00810 { 00811 int r; 00812 00813 if (GD_rankleader(g)) 00814 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) { 00815 GD_rankleader(g)[r] = GD_rank(g)[r].v[0]; 00816 } 00817 } 00818 00819 void rec_save_vlists(graph_t * g) 00820 { 00821 int c; 00822 00823 save_vlist(g); 00824 for (c = 1; c <= GD_n_cluster(g); c++) 00825 rec_save_vlists(GD_clust(g)[c]); 00826 } 00827 00828 00829 void rec_reset_vlists(graph_t * g) 00830 { 00831 int r, c; 00832 node_t *u, *v, *w; 00833 00834 /* fix vlists of sub-clusters */ 00835 for (c = 1; c <= GD_n_cluster(g); c++) 00836 rec_reset_vlists(GD_clust(g)[c]); 00837 00838 if (GD_rankleader(g)) 00839 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) { 00840 v = GD_rankleader(g)[r]; 00841 #ifdef DEBUG 00842 node_in_root_vlist(v); 00843 #endif 00844 u = furthestnode(g, v, -1); 00845 w = furthestnode(g, v, 1); 00846 GD_rankleader(g)[r] = u; 00847 #ifdef DEBUG 00848 assert(GD_rank(g->root)[r].v[ND_order(u)] == u); 00849 #endif 00850 #ifndef WITH_CGRAPH 00851 GD_rank(g)[r].v = ND_rank(g->root)[r].v + ND_order(u); 00852 #else /* WITH_CGRAPH */ 00853 GD_rank(g)[r].v = GD_rank(agroot(g))[r].v + ND_order(u); 00854 #endif /* WITH_CGRAPH */ 00855 GD_rank(g)[r].n = ND_order(w) - ND_order(u) + 1; 00856 } 00857 } 00858 00859 #ifdef WITH_CGRAPH 00860 /* realFillRanks: 00861 * The structures in crossing minimization and positioning require 00862 * that clusters have some node on each rank. This function recursively 00863 * guarantees this property. It takes into account nodes and edges in 00864 * a cluster, the latter causing dummy nodes for intervening ranks. 00865 * For any rank without node, we create a real node of small size. This 00866 * is stored in the subgraph sg, for easy removal later. 00867 * 00868 * I believe it is not necessary to do this for the root graph, as these 00869 * are laid out one component at a time and these will necessarily have a 00870 * node on each rank from source to sink levels. 00871 */ 00872 static Agraph_t* 00873 realFillRanks (Agraph_t* g, int rnks[], int rnks_sz, Agraph_t* sg) 00874 { 00875 int i, c; 00876 Agedge_t* e; 00877 Agnode_t* n; 00878 00879 for (c = 1; c <= GD_n_cluster(g); c++) 00880 sg = realFillRanks (GD_clust(g)[c], rnks, rnks_sz, sg); 00881 00882 if (agroot(g) == g) 00883 return sg; 00884 memset (rnks, 0, sizeof(int)*rnks_sz); 00885 for (n = agfstnode(g); n; n = agnxtnode(g,n)) { 00886 rnks[ND_rank(n)] = 1; 00887 for (e = agfstout(g,n); e; e = agnxtout(g,e)) { 00888 for (i = ND_rank(n)+1; i <= ND_rank(aghead(e)); i++) 00889 rnks[i] = 1; 00890 } 00891 } 00892 for (i = GD_minrank(g); i <= GD_maxrank(g); i++) { 00893 if (rnks[i] == 0) { 00894 if (!sg) { 00895 sg = agsubg (agroot(g), "_new_rank", 1); 00896 } 00897 n = agnode (sg, NULL, 1); 00898 agbindrec(n, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE); 00899 ND_rank(n) = i; 00900 ND_lw(n) = ND_rw(n) = 0.5; 00901 ND_ht(n) = 1; 00902 ND_UF_size(n) = 1; 00903 alloc_elist(4, ND_in(n)); 00904 alloc_elist(4, ND_out(n)); 00905 agsubnode (g, n, 1); 00906 } 00907 } 00908 return sg; 00909 } 00910 00911 static void 00912 fillRanks (Agraph_t* g) 00913 { 00914 Agraph_t* sg; 00915 int rnks_sz = GD_maxrank(g) + 2; 00916 int* rnks = N_NEW(rnks_sz, int); 00917 sg = realFillRanks (g, rnks, rnks_sz, NULL); 00918 free (rnks); 00919 } 00920 #endif 00921 00922 static void init_mincross(graph_t * g) 00923 { 00924 int size; 00925 00926 if (Verbose) 00927 start_timer(); 00928 00929 ReMincross = FALSE; 00930 Root = g; 00931 /* alloc +1 for the null terminator usage in do_ordering() */ 00932 /* also, the +1 avoids attempts to alloc 0 sizes, something 00933 that efence complains about */ 00934 size = agnedges(agroot(g)) + 1; 00935 TE_list = N_NEW(size, edge_t *); 00936 TI_list = N_NEW(size, int); 00937 mincross_options(g); 00938 #ifdef WITH_CGRAPH 00939 if (GD_flags(g) & NEW_RANK) 00940 fillRanks (g); 00941 #endif 00942 class2(g); 00943 decompose(g, 1); 00944 allocate_ranks(g); 00945 ordered_edges(g); 00946 GlobalMinRank = GD_minrank(g); 00947 GlobalMaxRank = GD_maxrank(g); 00948 } 00949 00950 void flat_rev(Agraph_t * g, Agedge_t * e) 00951 { 00952 int j; 00953 Agedge_t *rev; 00954 00955 if (!ND_flat_out(aghead(e)).list) 00956 rev = NULL; 00957 else 00958 for (j = 0; (rev = ND_flat_out(aghead(e)).list[j]); j++) 00959 if (aghead(rev) == agtail(e)) 00960 break; 00961 if (rev) { 00962 merge_oneway(e, rev); 00963 if (ED_to_virt(e) == 0) 00964 ED_to_virt(e) = rev; 00965 if ((ED_edge_type(rev) == FLATORDER) 00966 && (ED_to_orig(rev) == 0)) 00967 ED_to_orig(rev) = e; 00968 elist_append(e, ND_other(agtail(e))); 00969 } else { 00970 rev = new_virtual_edge(aghead(e), agtail(e), e); 00971 if (ED_edge_type(e) == FLATORDER) 00972 ED_edge_type(rev) = FLATORDER; 00973 else 00974 ED_edge_type(rev) = REVERSED; 00975 ED_label(rev) = ED_label(e); 00976 flat_edge(g, rev); 00977 } 00978 } 00979 00980 static void flat_search(graph_t * g, node_t * v) 00981 { 00982 int i; 00983 boolean hascl; 00984 edge_t *e; 00985 adjmatrix_t *M = GD_rank(g)[ND_rank(v)].flat; 00986 00987 ND_mark(v) = TRUE; 00988 ND_onstack(v) = TRUE; 00989 #ifndef WITH_CGRAPH 00990 hascl = (ND_n_cluster(g->root) > 0); 00991 #else /* WITH_CGRAPH */ 00992 hascl = (GD_n_cluster(agroot(g)) > 0); 00993 #endif /* WITH_CGRAPH */ 00994 if (ND_flat_out(v).list) 00995 for (i = 0; (e = ND_flat_out(v).list[i]); i++) { 00996 if (hascl 00997 && NOT(agcontains(g, agtail(e)) && agcontains(g, aghead(e)))) 00998 continue; 00999 if (ED_weight(e) == 0) 01000 continue; 01001 if (ND_onstack(aghead(e)) == TRUE) { 01002 assert(flatindex(aghead(e)) < M->nrows); 01003 assert(flatindex(agtail(e)) < M->ncols); 01004 ELT(M, flatindex(aghead(e)), flatindex(agtail(e))) = 1; 01005 delete_flat_edge(e); 01006 i--; 01007 if (ED_edge_type(e) == FLATORDER) 01008 continue; 01009 flat_rev(g, e); 01010 } else { 01011 assert(flatindex(aghead(e)) < M->nrows); 01012 assert(flatindex(agtail(e)) < M->ncols); 01013 ELT(M, flatindex(agtail(e)), flatindex(aghead(e))) = 1; 01014 if (ND_mark(aghead(e)) == FALSE) 01015 flat_search(g, aghead(e)); 01016 } 01017 } 01018 ND_onstack(v) = FALSE; 01019 } 01020 01021 static void flat_breakcycles(graph_t * g) 01022 { 01023 int i, r, flat; 01024 node_t *v; 01025 01026 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) { 01027 flat = 0; 01028 for (i = 0; i < GD_rank(g)[r].n; i++) { 01029 v = GD_rank(g)[r].v[i]; 01030 ND_mark(v) = ND_onstack(v) = FALSE; 01031 flatindex(v) = i; 01032 if ((ND_flat_out(v).size > 0) && (flat == 0)) { 01033 GD_rank(g)[r].flat = 01034 new_matrix(GD_rank(g)[r].n, GD_rank(g)[r].n); 01035 flat = 1; 01036 } 01037 } 01038 if (flat) { 01039 for (i = 0; i < GD_rank(g)[r].n; i++) { 01040 v = GD_rank(g)[r].v[i]; 01041 if (ND_mark(v) == FALSE) 01042 flat_search(g, v); 01043 } 01044 } 01045 } 01046 } 01047 01048 /* allocate_ranks: 01049 * Allocate rank structure, determining number of nodes per rank. 01050 * Note that no nodes are put into the structure yet. 01051 */ 01052 void allocate_ranks(graph_t * g) 01053 { 01054 int r, low, high, *cn; 01055 node_t *n; 01056 edge_t *e; 01057 01058 cn = N_NEW(GD_maxrank(g) + 2, int); /* must be 0 based, not GD_minrank */ 01059 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 01060 cn[ND_rank(n)]++; 01061 for (e = agfstout(g, n); e; e = agnxtout(g, e)) { 01062 low = ND_rank(agtail(e)); 01063 high = ND_rank(aghead(e)); 01064 if (low > high) { 01065 int t = low; 01066 low = high; 01067 high = t; 01068 } 01069 for (r = low + 1; r < high; r++) 01070 cn[r]++; 01071 } 01072 } 01073 GD_rank(g) = N_NEW(GD_maxrank(g) + 2, rank_t); 01074 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) { 01075 GD_rank(g)[r].an = GD_rank(g)[r].n = cn[r]; 01076 GD_rank(g)[r].av = GD_rank(g)[r].v = N_NEW(cn[r] + 1, node_t *); 01077 } 01078 free(cn); 01079 } 01080 01081 /* install a node at the current right end of its rank */ 01082 void install_in_rank(graph_t * g, node_t * n) 01083 { 01084 int i, r; 01085 01086 r = ND_rank(n); 01087 i = GD_rank(g)[r].n; 01088 if (GD_rank(g)[r].an <= 0) { 01089 agerr(AGERR, "install_in_rank, line %d: %s %s rank %d i = %d an = 0\n", 01090 __LINE__, agnameof(g), agnameof(n), r, i); 01091 return; 01092 } 01093 01094 GD_rank(g)[r].v[i] = n; 01095 ND_order(n) = i; 01096 GD_rank(g)[r].n++; 01097 assert(GD_rank(g)[r].n <= GD_rank(g)[r].an); 01098 #ifdef DEBUG 01099 { 01100 node_t *v; 01101 01102 for (v = GD_nlist(g); v; v = ND_next(v)) 01103 if (v == n) 01104 break; 01105 assert(v != NULL); 01106 } 01107 #endif 01108 if (ND_order(n) > GD_rank(Root)[r].an) { 01109 agerr(AGERR, "install_in_rank, line %d: ND_order(%s) [%d] > GD_rank(Root)[%d].an [%d]\n", 01110 __LINE__, agnameof(n), ND_order(n), r, GD_rank(Root)[r].an); 01111 return; 01112 } 01113 if ((r < GD_minrank(g)) || (r > GD_maxrank(g))) { 01114 agerr(AGERR, "install_in_rank, line %d: rank %d not in rank range [%d,%d]\n", 01115 __LINE__, r, GD_minrank(g), GD_maxrank(g)); 01116 return; 01117 } 01118 if (GD_rank(g)[r].v + ND_order(n) > 01119 GD_rank(g)[r].av + GD_rank(Root)[r].an) { 01120 agerr(AGERR, "install_in_rank, line %d: GD_rank(g)[%d].v + ND_order(%s) [%d] > GD_rank(g)[%d].av + GD_rank(Root)[%d].an [%d]\n", 01121 __LINE__, r, agnameof(n),GD_rank(g)[r].v + ND_order(n), r, r, GD_rank(g)[r].av+GD_rank(Root)[r].an); 01122 return; 01123 } 01124 } 01125 01126 /* install nodes in ranks. the initial ordering ensure that series-parallel 01127 * graphs such as trees are drawn with no crossings. it tries searching 01128 * in- and out-edges and takes the better of the two initial orderings. 01129 */ 01130 void build_ranks(graph_t * g, int pass) 01131 { 01132 int i, j; 01133 node_t *n, *n0; 01134 edge_t **otheredges; 01135 nodequeue *q; 01136 01137 q = new_queue(GD_n_nodes(g)); 01138 for (n = GD_nlist(g); n; n = ND_next(n)) 01139 MARK(n) = FALSE; 01140 01141 #ifdef DEBUG 01142 { 01143 edge_t *e; 01144 for (n = GD_nlist(g); n; n = ND_next(n)) { 01145 for (i = 0; (e = ND_out(n).list[i]); i++) 01146 assert(MARK(aghead(e)) == FALSE); 01147 for (i = 0; (e = ND_in(n).list[i]); i++) 01148 assert(MARK(agtail(e)) == FALSE); 01149 } 01150 } 01151 #endif 01152 01153 for (i = GD_minrank(g); i <= GD_maxrank(g); i++) 01154 GD_rank(g)[i].n = 0; 01155 01156 for (n = GD_nlist(g); n; n = ND_next(n)) { 01157 otheredges = ((pass == 0) ? ND_in(n).list : ND_out(n).list); 01158 if (otheredges[0] != NULL) 01159 continue; 01160 if (MARK(n) == FALSE) { 01161 MARK(n) = TRUE; 01162 enqueue(q, n); 01163 while ((n0 = dequeue(q))) { 01164 if (ND_ranktype(n0) != CLUSTER) { 01165 install_in_rank(g, n0); 01166 enqueue_neighbors(q, n0, pass); 01167 } else { 01168 install_cluster(g, n0, pass, q); 01169 } 01170 } 01171 } 01172 } 01173 if (dequeue(q)) 01174 agerr(AGERR, "surprise\n"); 01175 for (i = GD_minrank(g); i <= GD_maxrank(g); i++) { 01176 GD_rank(Root)[i].valid = FALSE; 01177 if (GD_flip(g) && (GD_rank(g)[i].n > 0)) { 01178 int n, ndiv2; 01179 node_t **vlist = GD_rank(g)[i].v; 01180 n = GD_rank(g)[i].n - 1; 01181 ndiv2 = n / 2; 01182 for (j = 0; j <= ndiv2; j++) 01183 exchange(vlist[j], vlist[n - j]); 01184 } 01185 } 01186 01187 if ((g == agroot(g)) && ncross(g) > 0) 01188 transpose(g, FALSE); 01189 free_queue(q); 01190 } 01191 01192 void enqueue_neighbors(nodequeue * q, node_t * n0, int pass) 01193 { 01194 int i; 01195 edge_t *e; 01196 01197 if (pass == 0) { 01198 for (i = 0; i < ND_out(n0).size; i++) { 01199 e = ND_out(n0).list[i]; 01200 if ((MARK(aghead(e))) == FALSE) { 01201 MARK(aghead(e)) = TRUE; 01202 enqueue(q, aghead(e)); 01203 } 01204 } 01205 } else { 01206 for (i = 0; i < ND_in(n0).size; i++) { 01207 e = ND_in(n0).list[i]; 01208 if ((MARK(agtail(e))) == FALSE) { 01209 MARK(agtail(e)) = TRUE; 01210 enqueue(q, agtail(e)); 01211 } 01212 } 01213 } 01214 } 01215 01216 /* construct nodes reachable from 'here' in post-order. 01217 * This is the same as doing a topological sort in reverse order. 01218 */ 01219 static int postorder(graph_t * g, node_t * v, node_t ** list, int r) 01220 { 01221 edge_t *e; 01222 int i, cnt = 0; 01223 01224 MARK(v) = TRUE; 01225 if (ND_flat_out(v).size > 0) { 01226 for (i = 0; (e = ND_flat_out(v).list[i]); i++) { 01227 if (ED_weight(e) == 0) 01228 continue; 01229 if ((ND_node_type(aghead(e)) == NORMAL) & 01230 (NOT(agcontains(g, aghead(e))))) 01231 continue; 01232 if (ND_clust(aghead(e)) != ND_clust(agtail(e))) 01233 continue; 01234 01235 if (MARK(aghead(e)) == FALSE) 01236 cnt += postorder(g, aghead(e), list + cnt, r); 01237 } 01238 } 01239 assert(ND_rank(v) == r); 01240 list[cnt++] = v; 01241 return cnt; 01242 } 01243 01244 static void flat_reorder(graph_t * g) 01245 { 01246 int i, j, r, pos, n_search, local_in_cnt, local_out_cnt; 01247 node_t *v, **left, **right, *t; 01248 node_t **temprank = NULL; 01249 edge_t *flat_e, *e; 01250 01251 if (GD_has_flat_edges(g) == FALSE) 01252 return; 01253 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) { 01254 for (i = 0; i < GD_rank(g)[r].n; i++) 01255 MARK(GD_rank(g)[r].v[i]) = FALSE; 01256 temprank = ALLOC(i + 1, temprank, node_t *); 01257 pos = 0; 01258 for (i = 0; i < GD_rank(g)[r].n; i++) { 01259 v = GD_rank(g)[r].v[i]; 01260 01261 local_in_cnt = local_out_cnt = 0; 01262 for (j = 0; j < ND_flat_in(v).size; j++) { 01263 flat_e = ND_flat_in(v).list[j]; 01264 if ((ED_weight(flat_e) > 0) 01265 && (inside_cluster(g, agtail(flat_e)))) 01266 local_in_cnt++; 01267 } 01268 for (j = 0; j < ND_flat_out(v).size; j++) { 01269 flat_e = ND_flat_out(v).list[j]; 01270 if ((ED_weight(flat_e) > 0) 01271 && (inside_cluster(g, aghead(flat_e)))) 01272 local_out_cnt++; 01273 } 01274 if ((local_in_cnt == 0) && (local_out_cnt == 0)) 01275 temprank[pos++] = v; 01276 else { 01277 if ((MARK(v) == FALSE) && (local_in_cnt == 0)) { 01278 left = temprank + pos; 01279 n_search = postorder(g, v, left, r); 01280 if (GD_flip(g) == FALSE) { 01281 right = left + n_search - 1; 01282 while (left < right) { 01283 t = *left; 01284 *left = *right; 01285 *right = t; 01286 left++; 01287 right--; 01288 } 01289 } 01290 pos += n_search; 01291 } 01292 } 01293 } 01294 if (pos) { 01295 for (i = 0; i < GD_rank(g)[r].n; i++) { 01296 v = GD_rank(g)[r].v[i] = temprank[i]; 01297 ND_order(v) = i + (GD_rank(g)[r].v - GD_rank(Root)[r].v); 01298 } 01299 01300 /* nonconstraint flat edges must be made LR */ 01301 for (i = 0; i < GD_rank(g)[r].n; i++) { 01302 v = GD_rank(g)[r].v[i]; 01303 if (ND_flat_out(v).list) { 01304 for (j = 0; (e = ND_flat_out(v).list[j]); j++) { 01305 if (ND_order(aghead(e)) < ND_order(agtail(e))) { 01306 /*assert(ED_weight(e) == 0); */ 01307 delete_flat_edge(e); 01308 j--; 01309 flat_rev(g, e); 01310 } 01311 } 01312 } 01313 } 01314 } 01315 /* else do no harm! */ 01316 GD_rank(Root)[r].valid = FALSE; 01317 } 01318 if (temprank) 01319 free(temprank); 01320 } 01321 01322 static void reorder(graph_t * g, int r, int reverse, int hasfixed) 01323 { 01324 int changed = 0, nelt; 01325 boolean muststay, sawclust; 01326 node_t **vlist = GD_rank(g)[r].v; 01327 node_t **lp, **rp, **ep = vlist + GD_rank(g)[r].n; 01328 01329 for (nelt = GD_rank(g)[r].n - 1; nelt >= 0; nelt--) { 01330 lp = vlist; 01331 while (lp < ep) { 01332 /* find leftmost node that can be compared */ 01333 while ((lp < ep) && (ND_mval(*lp) < 0)) 01334 lp++; 01335 if (lp >= ep) 01336 break; 01337 /* find the node that can be compared */ 01338 sawclust = muststay = FALSE; 01339 for (rp = lp + 1; rp < ep; rp++) { 01340 if (sawclust && ND_clust(*rp)) 01341 continue; /* ### */ 01342 if (left2right(g, *lp, *rp)) { 01343 muststay = TRUE; 01344 break; 01345 } 01346 if (ND_mval(*rp) >= 0) 01347 break; 01348 if (ND_clust(*rp)) 01349 sawclust = TRUE; /* ### */ 01350 } 01351 if (rp >= ep) 01352 break; 01353 if (muststay == FALSE) { 01354 register int p1 = (ND_mval(*lp)); 01355 register int p2 = (ND_mval(*rp)); 01356 if ((p1 > p2) || ((p1 == p2) && (reverse))) { 01357 exchange(*lp, *rp); 01358 changed++; 01359 } 01360 } 01361 lp = rp; 01362 } 01363 if ((hasfixed == FALSE) && (reverse == FALSE)) 01364 ep--; 01365 } 01366 01367 if (changed) { 01368 GD_rank(Root)[r].valid = FALSE; 01369 if (r > 0) 01370 GD_rank(Root)[r - 1].valid = FALSE; 01371 } 01372 } 01373 01374 static void mincross_step(graph_t * g, int pass) 01375 { 01376 int r, other, first, last, dir; 01377 int hasfixed, reverse; 01378 01379 if ((pass % 4) < 2) 01380 reverse = TRUE; 01381 else 01382 reverse = FALSE; 01383 if (pass % 2) { 01384 r = GD_maxrank(g) - 1; 01385 dir = -1; 01386 } /* up pass */ 01387 else { 01388 r = 1; 01389 dir = 1; 01390 } /* down pass */ 01391 01392 if (pass % 2 == 0) { /* down pass */ 01393 first = GD_minrank(g) + 1; 01394 if (GD_minrank(g) > GD_minrank(Root)) 01395 first--; 01396 last = GD_maxrank(g); 01397 dir = 1; 01398 } else { /* up pass */ 01399 first = GD_maxrank(g) - 1; 01400 last = GD_minrank(g); 01401 if (GD_maxrank(g) < GD_maxrank(Root)) 01402 first++; 01403 dir = -1; 01404 } 01405 01406 for (r = first; r != last + dir; r += dir) { 01407 other = r - dir; 01408 hasfixed = medians(g, r, other); 01409 reorder(g, r, reverse, hasfixed); 01410 } 01411 transpose(g, NOT(reverse)); 01412 } 01413 01414 static int local_cross(elist l, int dir) 01415 { 01416 int i, j, is_out; 01417 int cross = 0; 01418 edge_t *e, *f; 01419 if (dir > 0) 01420 is_out = TRUE; 01421 else 01422 is_out = FALSE; 01423 for (i = 0; (e = l.list[i]); i++) { 01424 if (is_out) 01425 for (j = i + 1; (f = l.list[j]); j++) { 01426 if ((ND_order(aghead(f)) - ND_order(aghead(e))) 01427 * (ED_tail_port(f).p.x - ED_tail_port(e).p.x) < 0) 01428 cross += ED_xpenalty(e) * ED_xpenalty(f); 01429 } else 01430 for (j = i + 1; (f = l.list[j]); j++) { 01431 if ((ND_order(agtail(f)) - ND_order(agtail(e))) 01432 * (ED_head_port(f).p.x - ED_head_port(e).p.x) < 0) 01433 cross += ED_xpenalty(e) * ED_xpenalty(f); 01434 } 01435 } 01436 return cross; 01437 } 01438 01439 static int rcross(graph_t * g, int r) 01440 { 01441 static int *Count, C; 01442 int top, bot, cross, max, i, k; 01443 node_t **rtop, *v; 01444 01445 cross = 0; 01446 max = 0; 01447 rtop = GD_rank(g)[r].v; 01448 01449 if (C <= GD_rank(Root)[r + 1].n) { 01450 C = GD_rank(Root)[r + 1].n + 1; 01451 Count = ALLOC(C, Count, int); 01452 } 01453 01454 for (i = 0; i < GD_rank(g)[r + 1].n; i++) 01455 Count[i] = 0; 01456 01457 for (top = 0; top < GD_rank(g)[r].n; top++) { 01458 register edge_t *e; 01459 if (max > 0) { 01460 for (i = 0; (e = ND_out(rtop[top]).list[i]); i++) { 01461 for (k = ND_order(aghead(e)) + 1; k <= max; k++) 01462 cross += Count[k] * ED_xpenalty(e); 01463 } 01464 } 01465 for (i = 0; (e = ND_out(rtop[top]).list[i]); i++) { 01466 register int inv = ND_order(aghead(e)); 01467 if (inv > max) 01468 max = inv; 01469 Count[inv] += ED_xpenalty(e); 01470 } 01471 } 01472 for (top = 0; top < GD_rank(g)[r].n; top++) { 01473 v = GD_rank(g)[r].v[top]; 01474 if (ND_has_port(v)) 01475 cross += local_cross(ND_out(v), 1); 01476 } 01477 for (bot = 0; bot < GD_rank(g)[r + 1].n; bot++) { 01478 v = GD_rank(g)[r + 1].v[bot]; 01479 if (ND_has_port(v)) 01480 cross += local_cross(ND_in(v), -1); 01481 } 01482 return cross; 01483 } 01484 01485 int ncross(graph_t * g) 01486 { 01487 int r, count, nc; 01488 01489 g = Root; 01490 count = 0; 01491 for (r = GD_minrank(g); r < GD_maxrank(g); r++) { 01492 if (GD_rank(g)[r].valid) 01493 count += GD_rank(g)[r].cache_nc; 01494 else { 01495 nc = GD_rank(g)[r].cache_nc = rcross(g, r); 01496 count += nc; 01497 GD_rank(g)[r].valid = TRUE; 01498 } 01499 } 01500 return count; 01501 } 01502 01503 static int ordercmpf(int *i0, int *i1) 01504 { 01505 return (*i0) - (*i1); 01506 } 01507 01508 /* flat_mval: 01509 * Calculate a mval for nodes with no in or out non-flat edges. 01510 * Assume (ND_out(n).size == 0) && (ND_in(n).size == 0) 01511 * Find flat edge a->n where a has the largest order and set 01512 * n.mval = a.mval+1, assuming a.mval is defined (>=0). 01513 * If there are no flat in edges, find flat edge n->a where a 01514 * has the smallest order and set * n.mval = a.mval-1, assuming 01515 * a.mval is > 0. 01516 * Return true if n.mval is left -1, indicating a fixed node for sorting. 01517 */ 01518 static int flat_mval(node_t * n) 01519 { 01520 int i; 01521 edge_t *e, **fl; 01522 node_t *nn; 01523 01524 if (ND_flat_in(n).size > 0) { 01525 fl = ND_flat_in(n).list; 01526 nn = agtail(fl[0]); 01527 for (i = 1; (e = fl[i]); i++) 01528 if (ND_order(agtail(e)) > ND_order(nn)) 01529 nn = agtail(e); 01530 if (ND_mval(nn) >= 0) { 01531 ND_mval(n) = ND_mval(nn) + 1; 01532 return FALSE; 01533 } 01534 } else if (ND_flat_out(n).size > 0) { 01535 fl = ND_flat_out(n).list; 01536 nn = aghead(fl[0]); 01537 for (i = 1; (e = fl[i]); i++) 01538 if (ND_order(aghead(e)) < ND_order(nn)) 01539 nn = aghead(e); 01540 if (ND_mval(nn) > 0) { 01541 ND_mval(n) = ND_mval(nn) - 1; 01542 return FALSE; 01543 } 01544 } 01545 return TRUE; 01546 } 01547 01548 #define VAL(node,port) (MC_SCALE * ND_order(node) + (port).order) 01549 01550 static boolean medians(graph_t * g, int r0, int r1) 01551 { 01552 int i, j, j0, lm, rm, lspan, rspan, *list; 01553 node_t *n, **v; 01554 edge_t *e; 01555 boolean hasfixed = FALSE; 01556 01557 list = TI_list; 01558 v = GD_rank(g)[r0].v; 01559 for (i = 0; i < GD_rank(g)[r0].n; i++) { 01560 n = v[i]; 01561 j = 0; 01562 if (r1 > r0) 01563 for (j0 = 0; (e = ND_out(n).list[j0]); j0++) { 01564 if (ED_xpenalty(e) > 0) 01565 list[j++] = VAL(aghead(e), ED_head_port(e)); 01566 } else 01567 for (j0 = 0; (e = ND_in(n).list[j0]); j0++) { 01568 if (ED_xpenalty(e) > 0) 01569 list[j++] = VAL(agtail(e), ED_tail_port(e)); 01570 } 01571 switch (j) { 01572 case 0: 01573 ND_mval(n) = -1; 01574 break; 01575 case 1: 01576 ND_mval(n) = list[0]; 01577 break; 01578 case 2: 01579 ND_mval(n) = (list[0] + list[1]) / 2; 01580 break; 01581 default: 01582 qsort(list, j, sizeof(int), (qsort_cmpf) ordercmpf); 01583 if (j % 2) 01584 ND_mval(n) = list[j / 2]; 01585 else { 01586 /* weighted median */ 01587 rm = j / 2; 01588 lm = rm - 1; 01589 rspan = list[j - 1] - list[rm]; 01590 lspan = list[lm] - list[0]; 01591 if (lspan == rspan) 01592 ND_mval(n) = (list[lm] + list[rm]) / 2; 01593 else { 01594 int w = list[lm] * rspan + list[rm] * lspan; 01595 ND_mval(n) = w / (lspan + rspan); 01596 } 01597 } 01598 } 01599 } 01600 for (i = 0; i < GD_rank(g)[r0].n; i++) { 01601 n = v[i]; 01602 if ((ND_out(n).size == 0) && (ND_in(n).size == 0)) 01603 hasfixed |= flat_mval(n); 01604 } 01605 return hasfixed; 01606 } 01607 01608 static int nodeposcmpf(node_t ** n0, node_t ** n1) 01609 { 01610 return (ND_order(*n0) - ND_order(*n1)); 01611 } 01612 01613 static int edgeidcmpf(edge_t ** e0, edge_t ** e1) 01614 { 01615 return (AGSEQ(*e0) - AGSEQ(*e1)); 01616 } 01617 01618 /* following code deals with weights of edges of "virtual" nodes */ 01619 #define ORDINARY 0 01620 #define SINGLETON 1 01621 #define VIRTUALNODE 2 01622 #define NTYPES 3 01623 01624 #define C_EE 1 01625 #define C_VS 2 01626 #define C_SS 2 01627 #define C_VV 4 01628 01629 static int table[NTYPES][NTYPES] = { 01630 /* ordinary */ {C_EE, C_EE, C_EE}, 01631 /* singleton */ {C_EE, C_SS, C_VS}, 01632 /* virtual */ {C_EE, C_VS, C_VV} 01633 }; 01634 01635 static int endpoint_class(node_t * n) 01636 { 01637 if (ND_node_type(n) == VIRTUAL) 01638 return VIRTUALNODE; 01639 if (ND_weight_class(n) <= 1) 01640 return SINGLETON; 01641 return ORDINARY; 01642 } 01643 01644 void virtual_weight(edge_t * e) 01645 { 01646 int t; 01647 t = table[endpoint_class(agtail(e))][endpoint_class(aghead(e))]; 01648 ED_weight(e) *= t; 01649 } 01650 01651 #ifdef DEBUG 01652 void check_rs(graph_t * g, int null_ok) 01653 { 01654 int i, r; 01655 node_t *v, *prev; 01656 01657 fprintf(stderr, "\n\n%s:\n", g->name); 01658 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) { 01659 fprintf(stderr, "%d: ", r); 01660 prev = NULL; 01661 for (i = 0; i < GD_rank(g)[r].n; i++) { 01662 v = GD_rank(g)[r].v[i]; 01663 if (v == NULL) { 01664 fprintf(stderr, "NULL\t"); 01665 if (null_ok == FALSE) 01666 abort(); 01667 } else { 01668 fprintf(stderr, "%s(%d)\t", v->name, ND_mval(v)); 01669 assert(ND_rank(v) == r); 01670 assert(v != prev); 01671 prev = v; 01672 } 01673 } 01674 fprintf(stderr, "\n"); 01675 } 01676 } 01677 01678 void check_order(void) 01679 { 01680 int i, r; 01681 node_t *v; 01682 graph_t *g = Root; 01683 01684 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) { 01685 assert(GD_rank(g)[r].v[GD_rank(g)[r].n] == NULL); 01686 for (i = 0; v = GD_rank(g)[r].v[i]; i++) { 01687 assert(ND_rank(v) == r); 01688 assert(ND_order(v) == i); 01689 } 01690 } 01691 } 01692 #endif 01693 01694 static void mincross_options(graph_t * g) 01695 { 01696 char *p; 01697 double f; 01698 01699 /* set default values */ 01700 MinQuit = 8; 01701 MaxIter = 24; 01702 Convergence = .995; 01703 01704 p = agget(g, "mclimit"); 01705 if (p && ((f = atof(p)) > 0.0)) { 01706 MinQuit = MAX(1, MinQuit * f); 01707 MaxIter = MAX(1, MaxIter * f); 01708 } 01709 } 01710 01711 #ifdef DEBUG 01712 void check_exchange(node_t * v, node_t * w) 01713 { 01714 int i, r; 01715 node_t *u; 01716 01717 if ((ND_clust(v) == NULL) && (ND_clust(w) == NULL)) 01718 return; 01719 assert((ND_clust(v) == NULL) || (ND_clust(w) == NULL)); 01720 assert(ND_rank(v) == ND_rank(w)); 01721 assert(ND_order(v) < ND_order(w)); 01722 r = ND_rank(v); 01723 01724 for (i = ND_order(v) + 1; i < ND_order(w); i++) { 01725 u = GD_rank(v->graph)[r].v[i]; 01726 if (ND_clust(u)) 01727 abort(); 01728 } 01729 } 01730 01731 void check_vlists(graph_t * g) 01732 { 01733 int c, i, j, r; 01734 node_t *u; 01735 01736 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) { 01737 for (i = 0; i < GD_rank(g)[r].n; i++) { 01738 u = GD_rank(g)[r].v[i]; 01739 j = ND_order(u); 01740 assert(GD_rank(Root)[r].v[j] == u); 01741 } 01742 if (GD_rankleader(g)) { 01743 u = GD_rankleader(g)[r]; 01744 j = ND_order(u); 01745 assert(GD_rank(Root)[r].v[j] == u); 01746 } 01747 } 01748 for (c = 1; c <= GD_n_cluster(g); c++) 01749 check_vlists(GD_clust(g)[c]); 01750 } 01751 01752 void node_in_root_vlist(node_t * n) 01753 { 01754 node_t **vptr; 01755 01756 for (vptr = GD_rank(Root)[ND_rank(n)].v; *vptr; vptr++) 01757 if (*vptr == n) 01758 break; 01759 if (*vptr == 0) 01760 abort(); 01761 } 01762 #endif /* DEBUG code */
1.7.5