Graphviz  2.29.20120524.0446
lib/dotgen/mincross.c
Go to the documentation of this file.
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 */