/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/dotgen/mincross.c

Go to the documentation of this file.
00001 /* $Id: mincross.c,v 1.10 2006/12/07 22:49:36 erg Exp $ $Revision: 1.10 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 
00018 /* 
00019  * dot_mincross(g) takes a ranked graphs, and finds an ordering
00020  * that avoids edge crossings.  clusters are expanded.
00021  * N.B. the rank structure is global (not allocated per cluster)
00022  * because mincross may compare nodes in different clusters.
00023  */
00024 
00025 #include "dot.h"
00026 
00027 /* #define DEBUG */
00028 #define MARK(v)                 ((v)->u.mark)
00029 #define saveorder(v)    ((v)->u.coord.x)
00030 #define flatindex(v)    ((v)->u.low)
00031 
00032         /* forward declarations */
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         /* mincross parameters */
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 /* dot_mincross:
00071  * Minimize edge crossings
00072  * Note that nodes are not placed into GD_rank(g) until mincross()
00073  * is called.
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     /* run mincross on contents of each cluster */
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         /* write null terminator at end of list.
00174            requires +1 in TE_list alloccation */
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 /* ordered_edges:
00196  * handle case where graph specifies edge ordering
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         /* search meta-graph to find subgraphs that may be ordered */
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             /* clusters are processed by seperate calls to ordered_edges */
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     /* CLUSTER indicates orig nodes of clusters, and vnodes of skeletons */
00255     if (ReMincross == FALSE) {
00256         if ((ND_clust(v) != ND_clust(w)) && (ND_clust(v)) && (ND_clust(w))) {
00257             /* the following allows cluster skeletons to be swapped */
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             /*return ((ND_ranktype(v) != CLUSTER) && (ND_ranktype(w) != CLUSTER)); */
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         /* don't run both the upward and downward passes- they cancel. 
00395            i tried making it depend on whether an odd or even pass, 
00396            but that didn't help. */
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         /*} while (delta > ncross(g)*(1.0 - Convergence)); */
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 /* merges the connected components of g */
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 /* merge connected components, create globally consistent rank lists */
00516 static void merge2(graph_t * g)
00517 {
00518     int i, r;
00519     node_t *v;
00520 
00521     /* merge the components and rank limits */
00522     merge_components(g);
00523 
00524     /* install complete ranks */
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     /* fix vlists of clusters */
00558     for (c = 1; c <= GD_n_cluster(g); c++)
00559         rec_reset_vlists(GD_clust(g)[c]);
00560 
00561     /* remove node temporary edges for ordering nodes */
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     /* fix vlists of sub-clusters */
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     /* alloc +1 for the null terminator usage in do_ordering() */
00691     /* also, the +1 avoids attempts to alloc 0 sizes, something
00692        that efence complains about */
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 /* allocate_ranks:
00786  * Allocate rank structure, determining number of nodes per rank.
00787  * Note that no nodes are put into the structure yet.
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); /* must be 0 based, not GD_minrank */
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 /* install a node at the current right end of its rank */
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 /*      install nodes in ranks. the initial ordering ensure that series-parallel
00856  *      graphs such as trees are drawn with no crossings.  it tries searching
00857  *      in- and out-edges and takes the better of the two initial orderings.
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 /* construct nodes reachable from 'here' in post-order.
00946  * This is the same as doing a topological sort in reverse order.
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         /* else do no harm! */
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             /* find leftmost node that can be compared */
01042             while ((lp < ep) && ((*lp)->u.mval < 0))
01043                 lp++;
01044             if (lp >= ep)
01045                 break;
01046             /* find the node that can be compared */
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     } /* up pass */
01097     else {
01098         r = 1;
01099         dir = 1;
01100     }                           /* down pass */
01101 
01102     if (pass % 2 == 0) {        /* down pass */
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 {                    /* up pass */
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 /* flat_mval:
01224  * Calculate a mval for nodes with no in or out non-flat edges.
01225  * Assume (ND_out(n).size == 0) && (ND_in(n).size == 0)
01226  * Find flat edge a->n where a has the largest order and set
01227  * n.mval = a.mval+1, assuming a.mval is defined (>=0).
01228  * If there are no flat in edges, find flat edge n->a where a 
01229  * has the smallest order and set * n.mval = a.mval-1, assuming 
01230  * a.mval is > 0.
01231  * Return true if n.mval is left -1, indicating a fixed node for sorting.
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                 /* weighted median */
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 /* following code deals with weights of edges of "virtual" nodes */
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     /* ordinary */ {C_EE, C_EE, C_EE},
01347     /* singleton */ {C_EE, C_SS, C_VS},
01348     /* virtual */ {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     /* set default values */
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                          /* DEBUG code */

Generated on Mon Mar 31 19:03:26 2008 for Graphviz by  doxygen 1.5.1