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 #include "dot.h"
00026
00027
00028 #define MARK(v) ((v)->u.mark)
00029 #define saveorder(v) ((v)->u.coord.x)
00030 #define flatindex(v) ((v)->u.low)
00031
00032
00033 static boolean medians(graph_t * g, int r0, int r1);
00034 static int nodeposcmpf(node_t ** n0, node_t ** n1);
00035 static int edgeidcmpf(edge_t ** e0, edge_t ** e1);
00036 static void flat_breakcycles(graph_t * g);
00037 static void flat_reorder(graph_t * g);
00038 static void flat_search(graph_t * g, node_t * v);
00039 static void init_mincross(graph_t * g);
00040 static void merge2(graph_t * g);
00041 static void init_mccomp(graph_t * g, int c);
00042 static void cleanup2(graph_t * g, int nc);
00043 static int mincross_clust(graph_t * par, graph_t * g);
00044 static int mincross(graph_t * g, int startpass, int endpass);
00045 static void init_mincross(graph_t * g);
00046 static void mincross_step(graph_t * g, int pass);
00047 static void mincross_options(graph_t * g);
00048 static void save_best(graph_t * g);
00049 static void restore_best(graph_t * g);
00050 static adjmatrix_t *new_matrix(int i, int j);
00051 static void free_matrix(adjmatrix_t * p);
00052 #ifdef DEBUG
00053 void check_rs(graph_t * g, int null_ok);
00054 void check_order(void);
00055 void check_vlists(graph_t * g);
00056 void node_in_root_vlist(node_t * n);
00057 #endif
00058
00059
00060
00061 static int MinQuit;
00062 static double Convergence;
00063
00064 static graph_t *Root;
00065 static int GlobalMinRank, GlobalMaxRank;
00066 static edge_t **TE_list;
00067 static int *TI_list;
00068 static boolean ReMincross;
00069
00070
00071
00072
00073
00074
00075 void dot_mincross(graph_t * g)
00076 {
00077 int c, nc;
00078 char *s;
00079
00080 init_mincross(g);
00081
00082 for (nc = c = 0; c < GD_comp(g).size; c++) {
00083 init_mccomp(g, c);
00084 nc += mincross(g, 0, 2);
00085 }
00086
00087 merge2(g);
00088
00089
00090 for (c = 1; c <= GD_n_cluster(g); c++) {
00091 nc += mincross_clust(g, GD_clust(g)[c]);
00092 #ifdef DEBUG
00093 check_vlists(GD_clust(g)[c]);
00094 check_order();
00095 #endif
00096 }
00097
00098 if ((GD_n_cluster(g) > 0)
00099 && (!(s = agget(g, "remincross")) || (mapbool(s)))) {
00100 mark_lowclusters(g);
00101 ReMincross = TRUE;
00102 nc = mincross(g, 2, 2);
00103 #ifdef DEBUG
00104 for (c = 1; c <= GD_n_cluster(g); c++)
00105 check_vlists(GD_clust(g)[c]);
00106 #endif
00107 }
00108 cleanup2(g, nc);
00109 }
00110
00111 static adjmatrix_t *new_matrix(int i, int j)
00112 {
00113 adjmatrix_t *rv = NEW(adjmatrix_t);
00114 rv->nrows = i;
00115 rv->ncols = j;
00116 rv->data = N_NEW(i * j, char);
00117 return rv;
00118 }
00119
00120 static void free_matrix(adjmatrix_t * p)
00121 {
00122 if (p) {
00123 free(p->data);
00124 free(p);
00125 }
00126 }
00127
00128 #define ELT(M,i,j) (M->data[((i)*M->ncols)+(j)])
00129
00130 static void
00131 init_mccomp(graph_t * g, int c)
00132 {
00133 int r;
00134
00135 GD_nlist(g) = GD_comp(g).list[c];
00136 if (c > 0) {
00137 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
00138 GD_rank(g)[r].v = GD_rank(g)[r].v + GD_rank(g)[r].n;
00139 GD_rank(g)[r].n = 0;
00140 }
00141 }
00142 }
00143
00144 static int betweenclust(edge_t * e)
00145 {
00146 while (ED_to_orig(e))
00147 e = ED_to_orig(e);
00148 return (ND_clust(e->tail) != ND_clust(e->head));
00149 }
00150
00151 static void
00152 do_ordering(graph_t * g, int outflag)
00153 {
00154 int i, ne;
00155 node_t *n, *u, *v;
00156 edge_t *e, *f, *fe;
00157 edge_t **sortlist = TE_list;
00158
00159 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00160 if (ND_clust(n))
00161 continue;
00162 if (outflag) {
00163 for (i = ne = 0; (e = ND_out(n).list[i]); i++)
00164 if (!betweenclust(e))
00165 sortlist[ne++] = e;
00166 } else {
00167 for (i = ne = 0; (e = ND_in(n).list[i]); i++)
00168 if (!betweenclust(e))
00169 sortlist[ne++] = e;
00170 }
00171 if (ne <= 1)
00172 continue;
00173
00174
00175 sortlist[ne] = 0;
00176 qsort(sortlist, ne, sizeof(sortlist[0]), (qsort_cmpf) edgeidcmpf);
00177 for (ne = 1; (f = sortlist[ne]); ne++) {
00178 e = sortlist[ne - 1];
00179 if (outflag) {
00180 u = e->head;
00181 v = f->head;
00182 } else {
00183 u = e->tail;
00184 v = f->tail;
00185 }
00186 if (find_flat_edge(u, v))
00187 continue;
00188 fe = new_virtual_edge(u, v, NULL);
00189 ED_edge_type(fe) = FLATORDER;
00190 flat_edge(g, fe);
00191 }
00192 }
00193 }
00194
00195
00196
00197
00198 static void
00199 ordered_edges(graph_t * g)
00200 {
00201 char *ordering;
00202
00203 if ((ordering = agget(g, "ordering"))) {
00204 if (streq(ordering, "out"))
00205 do_ordering(g, TRUE);
00206 else if (streq(ordering, "in"))
00207 do_ordering(g, FALSE);
00208 else if (ordering[0])
00209 agerr(AGERR, "ordering '%s' not recognized.\n", ordering);
00210 }
00211
00212 else {
00213
00214 graph_t *mg, *subg;
00215 node_t *mm, *mn;
00216 edge_t *me;
00217
00218 mm = g->meta_node;
00219 mg = mm->graph;
00220 for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) {
00221 mn = me->head;
00222 subg = agusergraph(mn);
00223
00224 if (!is_cluster(subg))
00225 ordered_edges(subg);
00226 }
00227 }
00228 }
00229
00230 static int
00231 mincross_clust(graph_t * par, graph_t * g)
00232 {
00233 int c, nc;
00234
00235 expand_cluster(g);
00236 ordered_edges(g);
00237 flat_breakcycles(g);
00238 flat_reorder(g);
00239 nc = mincross(g, 2, 2);
00240
00241 for (c = 1; c <= GD_n_cluster(g); c++)
00242 nc += mincross_clust(g, GD_clust(g)[c]);
00243
00244 save_vlist(g);
00245 return nc;
00246 }
00247
00248 static int
00249 left2right(graph_t * g, node_t * v, node_t * w)
00250 {
00251 adjmatrix_t *M;
00252 int rv;
00253
00254
00255 if (ReMincross == FALSE) {
00256 if ((ND_clust(v) != ND_clust(w)) && (ND_clust(v)) && (ND_clust(w))) {
00257
00258 if ((ND_ranktype(v) == CLUSTER)
00259 && (ND_node_type(v) == VIRTUAL))
00260 return FALSE;
00261 if ((ND_ranktype(w) == CLUSTER)
00262 && (ND_node_type(w) == VIRTUAL))
00263 return FALSE;
00264 return TRUE;
00265
00266 }
00267 } else {
00268 if ((ND_clust(v)) != (ND_clust(w)))
00269 return TRUE;
00270 }
00271 M = GD_rank(g)[ND_rank(v)].flat;
00272 if (M == NULL)
00273 rv = FALSE;
00274 else {
00275 if (GD_flip(g)) {
00276 node_t *t = v;
00277 v = w;
00278 w = t;
00279 }
00280 rv = ELT(M, flatindex(v), flatindex(w));
00281 }
00282 return rv;
00283 }
00284
00285 static int
00286 in_cross(node_t * v, node_t * w)
00287 {
00288 register edge_t **e1, **e2;
00289 register int inv, cross = 0, t;
00290
00291 for (e2 = ND_in(w).list; *e2; e2++) {
00292 register int cnt = (*e2)->u.xpenalty;
00293 inv = ((*e2)->tail)->u.order;
00294
00295 for (e1 = ND_in(v).list; *e1; e1++) {
00296 t = ((*e1)->tail)->u.order - inv;
00297 if ((t > 0)
00298 || ((t == 0)
00299 && ((*e1)->u.tail_port.p.x > (*e2)->u.tail_port.p.x)))
00300 cross += (*e1)->u.xpenalty * cnt;
00301 }
00302 }
00303 return cross;
00304 }
00305
00306 static int
00307 out_cross(node_t * v, node_t * w)
00308 {
00309 register edge_t **e1, **e2;
00310 register int inv, cross = 0, t;
00311
00312 for (e2 = ND_out(w).list; *e2; e2++) {
00313 register int cnt = (*e2)->u.xpenalty;
00314 inv = ((*e2)->head)->u.order;
00315
00316 for (e1 = ND_out(v).list; *e1; e1++) {
00317 t = ((*e1)->head)->u.order - inv;
00318 if ((t > 0)
00319 || ((t == 0)
00320 && ((*e1)->u.head_port.p.x > (*e2)->u.head_port.p.x)))
00321 cross += (*e1)->u.xpenalty * cnt;
00322 }
00323 }
00324 return cross;
00325
00326 }
00327
00328 static void
00329 exchange(node_t * v, node_t * w)
00330 {
00331 int vi, wi, r;
00332
00333 r = ND_rank(v);
00334 vi = ND_order(v);
00335 wi = ND_order(w);
00336 ND_order(v) = wi;
00337 GD_rank(Root)[r].v[wi] = v;
00338 ND_order(w) = vi;
00339 GD_rank(Root)[r].v[vi] = w;
00340 }
00341
00342 static int
00343 transpose_step(graph_t * g, int r, int reverse)
00344 {
00345 int i, c0, c1, rv;
00346 node_t *v, *w;
00347
00348 rv = 0;
00349 GD_rank(g)[r].candidate = FALSE;
00350 for (i = 0; i < GD_rank(g)[r].n - 1; i++) {
00351 v = GD_rank(g)[r].v[i];
00352 w = GD_rank(g)[r].v[i + 1];
00353 assert(ND_order(v) < ND_order(w));
00354 if (left2right(g, v, w))
00355 continue;
00356 c0 = c1 = 0;
00357 if (r > 0) {
00358 c0 += in_cross(v, w);
00359 c1 += in_cross(w, v);
00360 }
00361 if (GD_rank(g)[r + 1].n > 0) {
00362 c0 += out_cross(v, w);
00363 c1 += out_cross(w, v);
00364 }
00365 if ((c1 < c0) || ((c0 > 0) && reverse && (c1 == c0))) {
00366 exchange(v, w);
00367 rv += (c0 - c1);
00368 GD_rank(Root)[r].valid = FALSE;
00369 GD_rank(g)[r].candidate = TRUE;
00370
00371 if (r > GD_minrank(g)) {
00372 GD_rank(Root)[r - 1].valid = FALSE;
00373 GD_rank(g)[r - 1].candidate = TRUE;
00374 }
00375 if (r < GD_maxrank(g)) {
00376 GD_rank(Root)[r + 1].valid = FALSE;
00377 GD_rank(g)[r + 1].candidate = TRUE;
00378 }
00379 }
00380 }
00381 return rv;
00382 }
00383
00384 static void
00385 transpose(graph_t * g, int reverse)
00386 {
00387 int r, delta;
00388
00389 for (r = GD_minrank(g); r <= GD_maxrank(g); r++)
00390 GD_rank(g)[r].candidate = TRUE;
00391 do {
00392 delta = 0;
00393 #ifdef NOTDEF
00394
00395
00396
00397 for (r = GD_maxrank(g); r >= GD_minrank(g); r--)
00398 if (GD_rank(g)[r].candidate)
00399 delta += transpose_step(g, r, reverse);
00400 #endif
00401 for (r = GD_minrank(g); r <= GD_maxrank(g); r++)
00402 if (GD_rank(g)[r].candidate)
00403 delta += transpose_step(g, r, reverse);
00404
00405 } while (delta >= 1);
00406 }
00407
00408 static int mincross(graph_t * g, int startpass, int endpass)
00409 {
00410 int maxthispass, iter, trying, pass;
00411 int cur_cross, best_cross;
00412
00413 if (startpass > 1) {
00414 cur_cross = best_cross = ncross(g);
00415 save_best(g);
00416 } else
00417 cur_cross = best_cross = INT_MAX;
00418 for (pass = startpass; pass <= endpass; pass++) {
00419 if (pass <= 1) {
00420 maxthispass = MIN(4, MaxIter);
00421 if (g == g->root)
00422 build_ranks(g, pass);
00423 if (pass == 0)
00424 flat_breakcycles(g);
00425 flat_reorder(g);
00426
00427 if ((cur_cross = ncross(g)) <= best_cross) {
00428 save_best(g);
00429 best_cross = cur_cross;
00430 }
00431 trying = 0;
00432 } else {
00433 maxthispass = MaxIter;
00434 if (cur_cross > best_cross)
00435 restore_best(g);
00436 cur_cross = best_cross;
00437 }
00438 trying = 0;
00439 for (iter = 0; iter < maxthispass; iter++) {
00440 if (Verbose)
00441 fprintf(stderr,
00442 "mincross: pass %d iter %d trying %d cur_cross %d best_cross %d\n",
00443 pass, iter, trying, cur_cross, best_cross);
00444 if (trying++ >= MinQuit)
00445 break;
00446 if (cur_cross == 0)
00447 break;
00448 mincross_step(g, iter);
00449 if ((cur_cross = ncross(g)) <= best_cross) {
00450 save_best(g);
00451 if (cur_cross < Convergence * best_cross)
00452 trying = 0;
00453 best_cross = cur_cross;
00454 }
00455 }
00456 if (cur_cross == 0)
00457 break;
00458 }
00459 if (cur_cross > best_cross)
00460 restore_best(g);
00461 if (best_cross > 0) {
00462 transpose(g, FALSE);
00463 best_cross = ncross(g);
00464 }
00465 return best_cross;
00466 }
00467
00468 static void restore_best(graph_t * g)
00469 {
00470 node_t *n;
00471 int r;
00472
00473 for (n = GD_nlist(g); n; n = ND_next(n))
00474 ND_order(n) = saveorder(n);
00475 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
00476 GD_rank(Root)[r].valid = FALSE;
00477 qsort(GD_rank(g)[r].v, GD_rank(g)[r].n, sizeof(GD_rank(g)[0].v[0]),
00478 (qsort_cmpf) nodeposcmpf);
00479 }
00480 }
00481
00482 static void save_best(graph_t * g)
00483 {
00484 node_t *n;
00485 for (n = GD_nlist(g); n; n = ND_next(n))
00486 saveorder(n) = ND_order(n);
00487 }
00488
00489
00490 static void
00491 merge_components(graph_t * g)
00492 {
00493 int c;
00494 node_t *u, *v;
00495
00496 if (GD_comp(g).size <= 1)
00497 return;
00498 u = NULL;
00499 for (c = 0; c < GD_comp(g).size; c++) {
00500 v = GD_comp(g).list[c];
00501 if (u)
00502 ND_next(u) = v;
00503 ND_prev(v) = u;
00504 while (ND_next(v)) {
00505 v = ND_next(v);
00506 }
00507 u = v;
00508 }
00509 GD_comp(g).size = 1;
00510 GD_nlist(g) = GD_comp(g).list[0];
00511 GD_minrank(g) = GlobalMinRank;
00512 GD_maxrank(g) = GlobalMaxRank;
00513 }
00514
00515
00516 static void merge2(graph_t * g)
00517 {
00518 int i, r;
00519 node_t *v;
00520
00521
00522 merge_components(g);
00523
00524
00525 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
00526 GD_rank(g)[r].n = GD_rank(g)[r].an;
00527 GD_rank(g)[r].v = GD_rank(g)[r].av;
00528 for (i = 0; i < GD_rank(g)[r].n; i++) {
00529 v = GD_rank(g)[r].v[i];
00530 if (v == NULL) {
00531 if (Verbose)
00532 fprintf(stderr,
00533 "merge2: graph %s, rank %d has only %d < %d nodes\n",
00534 g->name, r, i, GD_rank(g)[r].n);
00535 GD_rank(g)[r].n = i;
00536 break;
00537 }
00538 ND_order(v) = i;
00539 }
00540 }
00541 }
00542
00543 static void cleanup2(graph_t * g, int nc)
00544 {
00545 int i, j, r, c;
00546 node_t *v;
00547 edge_t *e;
00548
00549 if (TI_list) {
00550 free(TI_list);
00551 TI_list = NULL;
00552 }
00553 if (TE_list) {
00554 free(TE_list);
00555 TE_list = NULL;
00556 }
00557
00558 for (c = 1; c <= GD_n_cluster(g); c++)
00559 rec_reset_vlists(GD_clust(g)[c]);
00560
00561
00562 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
00563 for (i = 0; i < GD_rank(g)[r].n; i++) {
00564 v = GD_rank(g)[r].v[i];
00565 ND_order(v) = i;
00566 if (ND_flat_out(v).list) {
00567 for (j = 0; (e = ND_flat_out(v).list[j]); j++)
00568 if (ED_edge_type(e) == FLATORDER) {
00569 delete_flat_edge(e);
00570 free(e);
00571 j--;
00572 }
00573 }
00574 }
00575 free_matrix(GD_rank(g)[r].flat);
00576 }
00577 if (Verbose)
00578 fprintf(stderr, "mincross %s: %d crossings, %.2f secs.\n",
00579 g->name, nc, elapsed_sec());
00580 }
00581
00582 static node_t *neighbor(node_t * v, int dir)
00583 {
00584 node_t *rv;
00585
00586 rv = NULL;
00587 if (dir < 0) {
00588 if (ND_order(v) > 0)
00589 rv = GD_rank(Root)[ND_rank(v)].v[ND_order(v) - 1];
00590 } else
00591 rv = GD_rank(Root)[ND_rank(v)].v[ND_order(v) + 1];
00592 return rv;
00593 }
00594
00595 static int
00596 is_a_normal_node_of(graph_t * g, node_t * v)
00597 {
00598 return ((ND_node_type(v) == NORMAL) && agcontains(g, v));
00599 }
00600
00601 static int
00602 is_a_vnode_of_an_edge_of(graph_t * g, node_t * v)
00603 {
00604 if ((ND_node_type(v) == VIRTUAL)
00605 && (ND_in(v).size == 1) && (ND_out(v).size == 1)) {
00606 edge_t *e = ND_out(v).list[0];
00607 while (ED_edge_type(e) != NORMAL)
00608 e = ED_to_orig(e);
00609 if (agcontains(g, e))
00610 return TRUE;
00611 }
00612 return FALSE;
00613 }
00614
00615 static int
00616 inside_cluster(graph_t * g, node_t * v)
00617 {
00618 return (is_a_normal_node_of(g, v) | is_a_vnode_of_an_edge_of(g, v));
00619 }
00620
00621 static node_t *furthestnode(graph_t * g, node_t * v, int dir)
00622 {
00623 node_t *u, *rv;
00624
00625 rv = u = v;
00626 while ((u = neighbor(u, dir))) {
00627 if (is_a_normal_node_of(g, u))
00628 rv = u;
00629 else if (is_a_vnode_of_an_edge_of(g, u))
00630 rv = u;
00631 }
00632 return rv;
00633 }
00634
00635 void save_vlist(graph_t * g)
00636 {
00637 int r;
00638
00639 if (GD_rankleader(g))
00640 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
00641 GD_rankleader(g)[r] = GD_rank(g)[r].v[0];
00642 }
00643 }
00644
00645 void rec_save_vlists(graph_t * g)
00646 {
00647 int c;
00648
00649 save_vlist(g);
00650 for (c = 1; c <= GD_n_cluster(g); c++)
00651 rec_save_vlists(GD_clust(g)[c]);
00652 }
00653
00654
00655 void rec_reset_vlists(graph_t * g)
00656 {
00657 int r, c;
00658 node_t *u, *v, *w;
00659
00660
00661 for (c = 1; c <= GD_n_cluster(g); c++)
00662 rec_reset_vlists(GD_clust(g)[c]);
00663
00664 if (GD_rankleader(g))
00665 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
00666 v = GD_rankleader(g)[r];
00667 #ifdef DEBUG
00668 node_in_root_vlist(v);
00669 #endif
00670 u = furthestnode(g, v, -1);
00671 w = furthestnode(g, v, 1);
00672 GD_rankleader(g)[r] = u;
00673 #ifdef DEBUG
00674 assert(GD_rank(g->root)[r].v[ND_order(u)] == u);
00675 #endif
00676 GD_rank(g)[r].v = ND_rank(g->root)[r].v + ND_order(u);
00677 GD_rank(g)[r].n = ND_order(w) - ND_order(u) + 1;
00678 }
00679 }
00680
00681 static void init_mincross(graph_t * g)
00682 {
00683 int size;
00684
00685 if (Verbose)
00686 start_timer();
00687
00688 ReMincross = FALSE;
00689 Root = g;
00690
00691
00692
00693 size = agnedges(g->root) + 1;
00694 TE_list = N_NEW(size, edge_t *);
00695 TI_list = N_NEW(size, int);
00696 mincross_options(g);
00697 class2(g);
00698 decompose(g, 1);
00699 allocate_ranks(g);
00700 ordered_edges(g);
00701 GlobalMinRank = GD_minrank(g);
00702 GlobalMaxRank = GD_maxrank(g);
00703 }
00704
00705 static void flat_search(graph_t * g, node_t * v)
00706 {
00707 int i, j;
00708 boolean hascl;
00709 edge_t *e, *rev;
00710 adjmatrix_t *M = GD_rank(g)[ND_rank(v)].flat;
00711
00712 ND_mark(v) = TRUE;
00713 ND_onstack(v) = TRUE;
00714 hascl = (ND_n_cluster(g->root) > 0);
00715 if (ND_flat_out(v).list)
00716 for (i = 0; (e = ND_flat_out(v).list[i]); i++) {
00717 if (hascl
00718 && NOT(agcontains(g, e->tail) && agcontains(g, e->head)))
00719 continue;
00720 if (ED_weight(e) == 0)
00721 continue;
00722 if (ND_onstack(e->head) == TRUE) {
00723 assert(flatindex(e->head) < M->nrows);
00724 assert(flatindex(e->tail) < M->ncols);
00725 ELT(M, flatindex(e->head), flatindex(e->tail)) = 1;
00726 delete_flat_edge(e);
00727 i--;
00728 if (ED_edge_type(e) == FLATORDER)
00729 continue;
00730 for (j = 0; (rev = ND_flat_out(e->head).list[j]); j++)
00731 if (rev->head == e->tail)
00732 break;
00733 if (rev) {
00734 merge_oneway(e, rev);
00735 if (ED_to_virt(e) == 0)
00736 ED_to_virt(e) = rev;
00737 if ((ED_edge_type(rev) == FLATORDER)
00738 && (ED_to_orig(rev) == 0))
00739 ED_to_orig(rev) = e;
00740 elist_append(e, ND_other(e->tail));
00741 } else {
00742 rev = new_virtual_edge(e->head, e->tail, e);
00743 ED_edge_type(rev) = REVERSED;
00744 ED_label(rev) = ED_label(e);
00745 flat_edge(g, rev);
00746 }
00747 } else {
00748 assert(flatindex(e->head) < M->nrows);
00749 assert(flatindex(e->tail) < M->ncols);
00750 ELT(M, flatindex(e->tail), flatindex(e->head)) = 1;
00751 if (ND_mark(e->head) == FALSE)
00752 flat_search(g, e->head);
00753 }
00754 }
00755 ND_onstack(v) = FALSE;
00756 }
00757
00758 static void flat_breakcycles(graph_t * g)
00759 {
00760 int i, r, flat;
00761 node_t *v;
00762
00763 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
00764 flat = 0;
00765 for (i = 0; i < GD_rank(g)[r].n; i++) {
00766 v = GD_rank(g)[r].v[i];
00767 ND_mark(v) = ND_onstack(v) = FALSE;
00768 flatindex(v) = i;
00769 if ((ND_flat_out(v).size > 0) && (flat == 0)) {
00770 GD_rank(g)[r].flat =
00771 new_matrix(GD_rank(g)[r].n, GD_rank(g)[r].n);
00772 flat = 1;
00773 }
00774 }
00775 if (flat) {
00776 for (i = 0; i < GD_rank(g)[r].n; i++) {
00777 v = GD_rank(g)[r].v[i];
00778 if (ND_mark(v) == FALSE)
00779 flat_search(g, v);
00780 }
00781 }
00782 }
00783 }
00784
00785
00786
00787
00788
00789 void
00790 allocate_ranks(graph_t * g)
00791 {
00792 int r, low, high, *cn;
00793 node_t *n;
00794 edge_t *e;
00795
00796 cn = N_NEW(GD_maxrank(g) + 2, int);
00797 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00798 cn[ND_rank(n)]++;
00799 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00800 low = ND_rank(e->tail);
00801 high = ND_rank(e->head);
00802 if (low > high) {
00803 int t = low;
00804 low = high;
00805 high = t;
00806 }
00807 for (r = low + 1; r < high; r++)
00808 cn[r]++;
00809 }
00810 }
00811 GD_rank(g) = N_NEW(GD_maxrank(g) + 2, rank_t);
00812 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
00813 GD_rank(g)[r].an = GD_rank(g)[r].n = cn[r];
00814 GD_rank(g)[r].av = GD_rank(g)[r].v = N_NEW(cn[r] + 1, node_t *);
00815 }
00816 free (cn);
00817 }
00818
00819
00820 void install_in_rank(graph_t * g, node_t * n)
00821 {
00822 int i, r;
00823
00824 r = ND_rank(n);
00825 i = GD_rank(g)[r].n;
00826 if (GD_rank(g)[r].an <= 0) {
00827 agerr(AGERR, "install_in_rank %s %s rank %d i = %d an = 0\n",
00828 g->name, n->name, r, i);
00829 abort();
00830 }
00831
00832 GD_rank(g)[r].v[i] = n;
00833 ND_order(n) = i;
00834 GD_rank(g)[r].n++;
00835 assert(GD_rank(g)[r].n <= GD_rank(g)[r].an);
00836 #ifdef DEBUG
00837 {
00838 node_t *v;
00839
00840 for (v = GD_nlist(g); v; v = ND_next(v))
00841 if (v == n)
00842 break;
00843 assert(v != NULL);
00844 }
00845 #endif
00846 if (ND_order(n) > GD_rank(Root)[r].an)
00847 abort();
00848 if ((r < GD_minrank(g)) || (r > GD_maxrank(g)))
00849 abort();
00850 if (GD_rank(g)[r].v + ND_order(n) >
00851 GD_rank(g)[r].av + GD_rank(Root)[r].an)
00852 abort();
00853 }
00854
00855
00856
00857
00858
00859 void build_ranks(graph_t * g, int pass)
00860 {
00861 int i, j;
00862 node_t *n, *n0;
00863 edge_t **otheredges;
00864 nodequeue *q;
00865
00866 q = new_queue(GD_n_nodes(g));
00867 for (n = GD_nlist(g); n; n = ND_next(n))
00868 MARK(n) = FALSE;
00869
00870 #ifdef DEBUG
00871 {
00872 edge_t *e;
00873 for (n = GD_nlist(g); n; n = ND_next(n)) {
00874 for (i = 0; (e = ND_out(n).list[i]); i++)
00875 assert(MARK(e->head) == FALSE);
00876 for (i = 0; (e = ND_in(n).list[i]); i++)
00877 assert(MARK(e->tail) == FALSE);
00878 }
00879 }
00880 #endif
00881
00882 for (i = GD_minrank(g); i <= GD_maxrank(g); i++)
00883 GD_rank(g)[i].n = 0;
00884
00885 for (n = GD_nlist(g); n; n = ND_next(n)) {
00886 otheredges = ((pass == 0) ? ND_in(n).list : ND_out(n).list);
00887 if (otheredges[0] != NULL)
00888 continue;
00889 if (MARK(n) == FALSE) {
00890 MARK(n) = TRUE;
00891 enqueue(q, n);
00892 while ((n0 = dequeue(q))) {
00893 if (ND_ranktype(n0) != CLUSTER) {
00894 install_in_rank(g, n0);
00895 enqueue_neighbors(q, n0, pass);
00896 } else {
00897 install_cluster(g, n0, pass, q);
00898 }
00899 }
00900 }
00901 }
00902 if (dequeue(q))
00903 agerr(AGERR, "surprise\n");
00904 for (i = GD_minrank(g); i <= GD_maxrank(g); i++) {
00905 GD_rank(Root)[i].valid = FALSE;
00906 if (GD_flip(g) && (GD_rank(g)[i].n > 0)) {
00907 int n, ndiv2;
00908 node_t **vlist = GD_rank(g)[i].v;
00909 n = GD_rank(g)[i].n - 1;
00910 ndiv2 = n / 2;
00911 for (j = 0; j <= ndiv2; j++)
00912 exchange(vlist[j], vlist[n - j]);
00913 }
00914 }
00915
00916 if ((g == g->root) && ncross(g) > 0)
00917 transpose(g, FALSE);
00918 free_queue(q);
00919 }
00920
00921 void enqueue_neighbors(nodequeue * q, node_t * n0, int pass)
00922 {
00923 int i;
00924 edge_t *e;
00925
00926 if (pass == 0) {
00927 for (i = 0; i < ND_out(n0).size; i++) {
00928 e = ND_out(n0).list[i];
00929 if ((MARK(e->head)) == FALSE) {
00930 MARK(e->head) = TRUE;
00931 enqueue(q, e->head);
00932 }
00933 }
00934 } else {
00935 for (i = 0; i < ND_in(n0).size; i++) {
00936 e = ND_in(n0).list[i];
00937 if ((MARK(e->tail)) == FALSE) {
00938 MARK(e->tail) = TRUE;
00939 enqueue(q, e->tail);
00940 }
00941 }
00942 }
00943 }
00944
00945
00946
00947
00948 static int postorder(graph_t * g, node_t * v, node_t ** list)
00949 {
00950 edge_t *e;
00951 int i, cnt = 0;
00952
00953 MARK(v) = TRUE;
00954 if (ND_flat_out(v).size > 0) {
00955 for (i = 0; (e = ND_flat_out(v).list[i]); i++) {
00956 if ((ND_node_type(e->head) == NORMAL) &
00957 (NOT(agcontains(g, e->head))))
00958 continue;
00959 if (ND_clust(e->head) != ND_clust(e->tail))
00960 continue;
00961
00962 if (MARK(e->head) == FALSE)
00963 cnt += postorder(g, e->head, list + cnt);
00964 }
00965 }
00966 list[cnt++] = v;
00967 return cnt;
00968 }
00969
00970 static void flat_reorder(graph_t * g)
00971 {
00972 int i, j, r, pos, n_search, local_in_cnt, local_out_cnt;
00973 node_t *v, **left, **right, *t;
00974 node_t **temprank = NULL;
00975 edge_t *flat_e;
00976
00977 if (GD_has_flat_edges(g) == FALSE)
00978 return;
00979 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
00980 for (i = 0; i < GD_rank(g)[r].n; i++)
00981 MARK(GD_rank(g)[r].v[i]) = FALSE;
00982 temprank = ALLOC(i + 1, temprank, node_t *);
00983 pos = 0;
00984 for (i = 0; i < GD_rank(g)[r].n; i++) {
00985 v = GD_rank(g)[r].v[i];
00986
00987 local_in_cnt = local_out_cnt = 0;
00988 for (j = 0; j < ND_flat_in(v).size; j++) {
00989 flat_e = ND_flat_in(v).list[j];
00990 if (inside_cluster(g, flat_e->tail))
00991 local_in_cnt++;
00992 }
00993 for (j = 0; j < ND_flat_out(v).size; j++) {
00994 flat_e = ND_flat_out(v).list[j];
00995 if (inside_cluster(g, flat_e->head))
00996 local_out_cnt++;
00997 }
00998 if ((local_in_cnt == 0) && (local_out_cnt == 0))
00999 temprank[pos++] = v;
01000 else {
01001 if ((MARK(v) == FALSE) && (local_in_cnt == 0)) {
01002 left = temprank + pos;
01003 n_search = postorder(g, v, left);
01004 if (GD_flip(g) == FALSE) {
01005 right = left + n_search - 1;
01006 while (left < right) {
01007 t = *left;
01008 *left = *right;
01009 *right = t;
01010 left++;
01011 right--;
01012 }
01013 }
01014 pos += n_search;
01015 }
01016 }
01017 }
01018 if (pos)
01019 for (i = 0; i < GD_rank(g)[r].n; i++) {
01020 v = GD_rank(g)[r].v[i] = temprank[i];
01021 ND_order(v) = i + (GD_rank(g)[r].v - GD_rank(Root)[r].v);
01022 }
01023
01024 GD_rank(Root)[r].valid = FALSE;
01025 }
01026 if (temprank)
01027 free(temprank);
01028 }
01029
01030 static void
01031 reorder(graph_t * g, int r, int reverse, int hasfixed)
01032 {
01033 int changed = 0, nelt;
01034 boolean muststay, sawclust;
01035 node_t **vlist = GD_rank(g)[r].v;
01036 node_t **lp, **rp, **ep = vlist + GD_rank(g)[r].n;
01037
01038 for (nelt = GD_rank(g)[r].n - 1; nelt >= 0; nelt--) {
01039 lp = vlist;
01040 while (lp < ep) {
01041
01042 while ((lp < ep) && ((*lp)->u.mval < 0))
01043 lp++;
01044 if (lp >= ep)
01045 break;
01046
01047 sawclust = muststay = FALSE;
01048 for (rp = lp + 1; rp < ep; rp++) {
01049 if (sawclust && (*rp)->u.clust)
01050 continue;
01051 if (left2right(g, *lp, *rp)) {
01052 muststay = TRUE;
01053 break;
01054 }
01055 if ((*rp)->u.mval >= 0)
01056 break;
01057 if ((*rp)->u.clust)
01058 sawclust = TRUE;
01059 }
01060 if (rp >= ep)
01061 break;
01062 if (muststay == FALSE) {
01063 register int p1 = ((*lp)->u.mval);
01064 register int p2 = ((*rp)->u.mval);
01065 if ((p1 > p2) || ((p1 == p2) && (reverse))) {
01066 exchange(*lp, *rp);
01067 changed++;
01068 }
01069 }
01070 lp = rp;
01071 }
01072 if ((hasfixed == FALSE) && (reverse == FALSE))
01073 ep--;
01074 }
01075
01076 if (changed) {
01077 GD_rank(Root)[r].valid = FALSE;
01078 if (r > 0)
01079 GD_rank(Root)[r - 1].valid = FALSE;
01080 }
01081 }
01082
01083 static void
01084 mincross_step(graph_t * g, int pass)
01085 {
01086 int r, other, first, last, dir;
01087 int hasfixed, reverse;
01088
01089 if ((pass % 4) < 2)
01090 reverse = TRUE;
01091 else
01092 reverse = FALSE;
01093 if (pass % 2) {
01094 r = GD_maxrank(g) - 1;
01095 dir = -1;
01096 }
01097 else {
01098 r = 1;
01099 dir = 1;
01100 }
01101
01102 if (pass % 2 == 0) {
01103 first = GD_minrank(g) + 1;
01104 if (GD_minrank(g) > GD_minrank(Root))
01105 first--;
01106 last = GD_maxrank(g);
01107 dir = 1;
01108 } else {
01109 first = GD_maxrank(g) - 1;
01110 last = GD_minrank(g);
01111 if (GD_maxrank(g) < GD_maxrank(Root))
01112 first++;
01113 dir = -1;
01114 }
01115
01116 for (r = first; r != last + dir; r += dir) {
01117 other = r - dir;
01118 hasfixed = medians(g, r, other);
01119 reorder(g, r, reverse, hasfixed);
01120 }
01121 transpose(g, NOT(reverse));
01122 }
01123
01124 static int
01125 local_cross(elist l, int dir)
01126 {
01127 int i, j, is_out;
01128 int cross = 0;
01129 edge_t *e, *f;
01130 if (dir > 0)
01131 is_out = TRUE;
01132 else
01133 is_out = FALSE;
01134 for (i = 0; (e = l.list[i]); i++) {
01135 if (is_out)
01136 for (j = i + 1; (f = l.list[j]); j++) {
01137 if ((ND_order(f->head) -
01138 ND_order(e->head)) * (ED_tail_port(f).p.x -
01139 ED_tail_port(e).p.x) < 0)
01140 cross += ED_xpenalty(e) * ED_xpenalty(f);
01141 } else
01142 for (j = i + 1; (f = l.list[j]); j++) {
01143 if ((ND_order(f->tail) -
01144 ND_order(e->tail)) * (ED_head_port(f).p.x -
01145 ED_head_port(e).p.x) < 0)
01146 cross += ED_xpenalty(e) * ED_xpenalty(f);
01147 }
01148 }
01149 return cross;
01150 }
01151
01152 static int
01153 rcross(graph_t * g, int r)
01154 {
01155 static int *Count, C;
01156 int top, bot, cross, max, i, k;
01157 node_t **rtop, *v;
01158
01159 cross = 0;
01160 max = 0;
01161 rtop = GD_rank(g)[r].v;
01162
01163 if (C <= GD_rank(Root)[r + 1].n) {
01164 C = GD_rank(Root)[r + 1].n + 1;
01165 Count = ALLOC(C, Count, int);
01166 }
01167
01168 for (i = 0; i < GD_rank(g)[r + 1].n; i++)
01169 Count[i] = 0;
01170
01171 for (top = 0; top < GD_rank(g)[r].n; top++) {
01172 register edge_t *e;
01173 if (max > 0) {
01174 for (i = 0; (e = rtop[top]->u.out.list[i]); i++) {
01175 for (k = ND_order(e->head) + 1; k <= max; k++)
01176 cross += Count[k] * ED_xpenalty(e);
01177 }
01178 }
01179 for (i = 0; (e = rtop[top]->u.out.list[i]); i++) {
01180 register int inv = ND_order(e->head);
01181 if (inv > max)
01182 max = inv;
01183 Count[inv] += ED_xpenalty(e);
01184 }
01185 }
01186 for (top = 0; top < GD_rank(g)[r].n; top++) {
01187 v = GD_rank(g)[r].v[top];
01188 if (ND_has_port(v))
01189 cross += local_cross(ND_out(v), 1);
01190 }
01191 for (bot = 0; bot < GD_rank(g)[r + 1].n; bot++) {
01192 v = GD_rank(g)[r + 1].v[bot];
01193 if (ND_has_port(v))
01194 cross += local_cross(ND_in(v), -1);
01195 }
01196 return cross;
01197 }
01198
01199 int ncross(graph_t * g)
01200 {
01201 int r, count, nc;
01202
01203 g = Root;
01204 count = 0;
01205 for (r = GD_minrank(g); r < GD_maxrank(g); r++) {
01206 if (GD_rank(g)[r].valid)
01207 count += GD_rank(g)[r].cache_nc;
01208 else {
01209 nc = GD_rank(g)[r].cache_nc = rcross(g, r);
01210 count += nc;
01211 GD_rank(g)[r].valid = TRUE;
01212 }
01213 }
01214 return count;
01215 }
01216
01217 static int
01218 ordercmpf(int *i0, int *i1)
01219 {
01220 return (*i0) - (*i1);
01221 }
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233 static int
01234 flat_mval(node_t * n)
01235 {
01236 int i;
01237 edge_t *e, **fl;
01238 node_t *nn;
01239
01240 if (ND_flat_in(n).size > 0) {
01241 fl = ND_flat_in(n).list;
01242 nn = fl[0]->tail;
01243 for (i = 1; (e = fl[i]); i++)
01244 if (ND_order(e->tail) > ND_order(nn))
01245 nn = e->tail;
01246 if (ND_mval(nn) >= 0) {
01247 ND_mval(n) = ND_mval(nn) + 1;
01248 return FALSE;
01249 }
01250 } else if (ND_flat_out(n).size > 0) {
01251 fl = ND_flat_out(n).list;
01252 nn = fl[0]->head;
01253 for (i = 1; (e = fl[i]); i++)
01254 if (ND_order(e->head) < ND_order(nn))
01255 nn = e->head;
01256 if (ND_mval(nn) > 0) {
01257 ND_mval(n) = ND_mval(nn) - 1;
01258 return FALSE;
01259 }
01260 }
01261 return TRUE;
01262 }
01263
01264 #define VAL(node,port) (MC_SCALE * (node)->u.order + (port).order)
01265
01266 static boolean medians(graph_t * g, int r0, int r1)
01267 {
01268 int i, j, j0, lm, rm, lspan, rspan, *list;
01269 node_t *n, **v;
01270 edge_t *e;
01271 boolean hasfixed = FALSE;
01272
01273 list = TI_list;
01274 v = GD_rank(g)[r0].v;
01275 for (i = 0; i < GD_rank(g)[r0].n; i++) {
01276 n = v[i];
01277 j = 0;
01278 if (r1 > r0)
01279 for (j0 = 0; (e = ND_out(n).list[j0]); j0++) {
01280 if (ED_xpenalty(e) > 0)
01281 list[j++] = VAL(e->head, ED_head_port(e));
01282 } else
01283 for (j0 = 0; (e = ND_in(n).list[j0]); j0++) {
01284 if (ED_xpenalty(e) > 0)
01285 list[j++] = VAL(e->tail, ED_tail_port(e));
01286 }
01287 switch (j) {
01288 case 0:
01289 ND_mval(n) = -1;
01290 break;
01291 case 1:
01292 ND_mval(n) = list[0];
01293 break;
01294 case 2:
01295 ND_mval(n) = (list[0] + list[1]) / 2;
01296 break;
01297 default:
01298 qsort(list, j, sizeof(int), (qsort_cmpf) ordercmpf);
01299 if (j % 2)
01300 ND_mval(n) = list[j / 2];
01301 else {
01302
01303 rm = j / 2;
01304 lm = rm - 1;
01305 rspan = list[j - 1] - list[rm];
01306 lspan = list[lm] - list[0];
01307 if (lspan == rspan)
01308 ND_mval(n) = (list[lm] + list[rm]) / 2;
01309 else {
01310 int w = list[lm] * rspan + list[rm] * lspan;
01311 ND_mval(n) = w / (lspan + rspan);
01312 }
01313 }
01314 }
01315 }
01316 for (i = 0; i < GD_rank(g)[r0].n; i++) {
01317 n = v[i];
01318 if ((ND_out(n).size == 0) && (ND_in(n).size == 0))
01319 hasfixed |= flat_mval(n);
01320 }
01321 return hasfixed;
01322 }
01323
01324 static int nodeposcmpf(node_t ** n0, node_t ** n1)
01325 {
01326 return ((*n0)->u.order - (*n1)->u.order);
01327 }
01328
01329 static int edgeidcmpf(edge_t ** e0, edge_t ** e1)
01330 {
01331 return ((*e0)->id - (*e1)->id);
01332 }
01333
01334
01335 #define ORDINARY 0
01336 #define SINGLETON 1
01337 #define VIRTUALNODE 2
01338 #define NTYPES 3
01339
01340 #define C_EE 1
01341 #define C_VS 2
01342 #define C_SS 2
01343 #define C_VV 4
01344
01345 static int table[NTYPES][NTYPES] = {
01346 {C_EE, C_EE, C_EE},
01347 {C_EE, C_SS, C_VS},
01348 {C_EE, C_VS, C_VV}
01349 };
01350
01351 static int endpoint_class(node_t * n)
01352 {
01353 if (ND_node_type(n) == VIRTUAL)
01354 return VIRTUALNODE;
01355 if (ND_weight_class(n) <= 1)
01356 return SINGLETON;
01357 return ORDINARY;
01358 }
01359
01360 void virtual_weight(edge_t * e)
01361 {
01362 int t;
01363 t = table[endpoint_class(e->tail)][endpoint_class(e->head)];
01364 ED_weight(e) *= t;
01365 }
01366
01367 #ifdef DEBUG
01368 void check_rs(graph_t * g, int null_ok)
01369 {
01370 int i, r;
01371 node_t *v, *prev;
01372
01373 fprintf(stderr, "\n\n%s:\n", g->name);
01374 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
01375 fprintf(stderr, "%d: ", r);
01376 prev = NULL;
01377 for (i = 0; i < GD_rank(g)[r].n; i++) {
01378 v = GD_rank(g)[r].v[i];
01379 if (v == NULL) {
01380 fprintf(stderr, "NULL\t");
01381 if (null_ok == FALSE)
01382 abort();
01383 } else {
01384 fprintf(stderr, "%s(%d)\t", v->name, ND_mval(v));
01385 assert(ND_rank(v) == r);
01386 assert(v != prev);
01387 prev = v;
01388 }
01389 }
01390 fprintf(stderr, "\n");
01391 }
01392 }
01393
01394 void check_order(void)
01395 {
01396 int i, r;
01397 node_t *v;
01398 graph_t *g = Root;
01399
01400 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
01401 assert(GD_rank(g)[r].v[GD_rank(g)[r].n] == NULL);
01402 for (i = 0; v = GD_rank(g)[r].v[i]; i++)
01403 assert(ND_order(v) == i);
01404 }
01405 }
01406 #endif
01407
01408 static void mincross_options(graph_t * g)
01409 {
01410 char *p;
01411 double f;
01412
01413
01414 MinQuit = 8;
01415 MaxIter = 24;
01416 Convergence = .995;
01417
01418 p = agget(g, "mclimit");
01419 if (p && ((f = atof(p)) > 0.0)) {
01420 MinQuit = MAX(1, MinQuit * f);
01421 MaxIter = MAX(1, MaxIter * f);
01422 }
01423 }
01424
01425 #ifdef DEBUG
01426 void check_exchange(node_t * v, node_t * w)
01427 {
01428 int i, r;
01429 node_t *u;
01430
01431 if ((ND_clust(v) == NULL) && (ND_clust(w) == NULL))
01432 return;
01433 assert((ND_clust(v) == NULL) || (ND_clust(w) == NULL));
01434 assert(ND_rank(v) == ND_rank(w));
01435 assert(ND_order(v) < ND_order(w));
01436 r = ND_rank(v);
01437
01438 for (i = ND_order(v) + 1; i < ND_order(w); i++) {
01439 u = GD_rank(v->graph)[r].v[i];
01440 if (ND_clust(u))
01441 abort();
01442 }
01443 }
01444
01445 void check_vlists(graph_t * g)
01446 {
01447 int c, i, j, r;
01448 node_t *u;
01449
01450 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
01451 for (i = 0; i < GD_rank(g)[r].n; i++) {
01452 u = GD_rank(g)[r].v[i];
01453 j = ND_order(u);
01454 assert(GD_rank(Root)[r].v[j] == u);
01455 }
01456 if (GD_rankleader(g)) {
01457 u = GD_rankleader(g)[r];
01458 j = ND_order(u);
01459 assert(GD_rank(Root)[r].v[j] == u);
01460 }
01461 }
01462 for (c = 1; c <= GD_n_cluster(g); c++)
01463 check_vlists(GD_clust(g)[c]);
01464 }
01465
01466 void node_in_root_vlist(node_t * n)
01467 {
01468 node_t **vptr;
01469
01470 for (vptr = GD_rank(Root)[ND_rank(n)].v; *vptr; vptr++)
01471 if (*vptr == n)
01472 break;
01473 if (*vptr == 0)
01474 abort();
01475 }
01476 #endif