/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/common/ns.c

Go to the documentation of this file.
00001 /* $Id: ns.c,v 1.12 2007/06/25 17:49:29 erg Exp $ $Revision: 1.12 $ */
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  * Network Simplex Algorithm for Ranking Nodes of a DAG
00020  */
00021 
00022 #include "render.h"
00023 
00024 static int init_graph(graph_t *);
00025 static void dfs_cutval(node_t * v, edge_t * par);
00026 static int dfs_range(node_t * v, edge_t * par, int low);
00027 static int x_val(edge_t * e, node_t * v, int dir);
00028 #ifdef DEBUG
00029 static void check_cycles(graph_t * g);
00030 #endif
00031 
00032 #define LENGTH(e)               (ND_rank(e->head) - ND_rank(e->tail))
00033 #define SLACK(e)                (LENGTH(e) - ED_minlen(e))
00034 #define SEQ(a,b,c)              (((a) <= (b)) && ((b) <= (c)))
00035 #define TREE_EDGE(e)    (ED_tree_index(e) >= 0)
00036 
00037 static graph_t *G;
00038 static int N_nodes, N_edges;
00039 static int Minrank, Maxrank;
00040 static int S_i;                 /* search index for enter_edge */
00041 static int Search_size;
00042 #define SEARCHSIZE 30
00043 static nlist_t Tree_node;
00044 static elist Tree_edge;
00045 
00046 static void add_tree_edge(edge_t * e)
00047 {
00048     node_t *n;
00049     if (TREE_EDGE(e))
00050         abort();
00051     ED_tree_index(e) = Tree_edge.size;
00052     Tree_edge.list[Tree_edge.size++] = e;
00053     if (ND_mark(e->tail) == FALSE)
00054         Tree_node.list[Tree_node.size++] = e->tail;
00055     if (ND_mark(e->head) == FALSE)
00056         Tree_node.list[Tree_node.size++] = e->head;
00057     n = e->tail;
00058     ND_mark(n) = TRUE;
00059     ND_tree_out(n).list[ND_tree_out(n).size++] = e;
00060     ND_tree_out(n).list[ND_tree_out(n).size] = NULL;
00061     if (ND_out(n).list[ND_tree_out(n).size - 1] == 0)
00062         abort();
00063     n = e->head;
00064     ND_mark(n) = TRUE;
00065     ND_tree_in(n).list[ND_tree_in(n).size++] = e;
00066     ND_tree_in(n).list[ND_tree_in(n).size] = NULL;
00067     if (ND_in(n).list[ND_tree_in(n).size - 1] == 0)
00068         abort();
00069 }
00070 
00071 static void exchange_tree_edges(edge_t * e, edge_t * f)
00072 {
00073     int i, j;
00074     node_t *n;
00075 
00076     ED_tree_index(f) = ED_tree_index(e);
00077     Tree_edge.list[ED_tree_index(e)] = f;
00078     ED_tree_index(e) = -1;
00079 
00080     n = e->tail;
00081     i = --(ND_tree_out(n).size);
00082     for (j = 0; j <= i; j++)
00083         if (ND_tree_out(n).list[j] == e)
00084             break;
00085     ND_tree_out(n).list[j] = ND_tree_out(n).list[i];
00086     ND_tree_out(n).list[i] = NULL;
00087     n = e->head;
00088     i = --(ND_tree_in(n).size);
00089     for (j = 0; j <= i; j++)
00090         if (ND_tree_in(n).list[j] == e)
00091             break;
00092     ND_tree_in(n).list[j] = ND_tree_in(n).list[i];
00093     ND_tree_in(n).list[i] = NULL;
00094 
00095     n = f->tail;
00096     ND_tree_out(n).list[ND_tree_out(n).size++] = f;
00097     ND_tree_out(n).list[ND_tree_out(n).size] = NULL;
00098     n = f->head;
00099     ND_tree_in(n).list[ND_tree_in(n).size++] = f;
00100     ND_tree_in(n).list[ND_tree_in(n).size] = NULL;
00101 }
00102 
00103 static
00104 void init_rank(void)
00105 {
00106     int i, ctr;
00107     nodequeue *Q;
00108     node_t *v;
00109     edge_t *e;
00110 
00111     Q = new_queue(N_nodes);
00112     ctr = 0;
00113 
00114     for (v = GD_nlist(G); v; v = ND_next(v)) {
00115         if (ND_priority(v) == 0)
00116             enqueue(Q, v);
00117     }
00118 
00119     while ((v = dequeue(Q))) {
00120         ND_rank(v) = 0;
00121         ctr++;
00122         for (i = 0; (e = ND_in(v).list[i]); i++)
00123             ND_rank(v) = MAX(ND_rank(v), ND_rank(e->tail) + ED_minlen(e));
00124         for (i = 0; (e = ND_out(v).list[i]); i++) {
00125             if (--(ND_priority(e->head)) <= 0)
00126                 enqueue(Q, e->head);
00127         }
00128     }
00129     if (ctr != N_nodes) {
00130         agerr(AGERR, "trouble in init_rank\n");
00131         for (v = GD_nlist(G); v; v = ND_next(v))
00132             if (ND_priority(v))
00133                 agerr(AGPREV, "\t%s %d\n", v->name, ND_priority(v));
00134     }
00135     free_queue(Q);
00136 }
00137 
00138 static node_t *incident(edge_t * e)
00139 {
00140     if (ND_mark(e->tail)) {
00141         if (ND_mark(e->head) == FALSE)
00142             return e->tail;
00143     } else {
00144         if (ND_mark(e->head))
00145             return e->head;
00146     }
00147     return NULL;
00148 }
00149 
00150 static edge_t *leave_edge(void)
00151 {
00152     edge_t *f, *rv = NULL;
00153     int j, cnt = 0;
00154 
00155     j = S_i;
00156     while (S_i < Tree_edge.size) {
00157         if ((f = Tree_edge.list[S_i])->u.cutvalue < 0) {
00158             if (rv) {
00159                 if (ED_cutvalue(rv) > ED_cutvalue(f))
00160                     rv = f;
00161             } else
00162                 rv = Tree_edge.list[S_i];
00163             if (++cnt >= Search_size)
00164                 return rv;
00165         }
00166         S_i++;
00167     }
00168     if (j > 0) {
00169         S_i = 0;
00170         while (S_i < j) {
00171             if ((f = Tree_edge.list[S_i])->u.cutvalue < 0) {
00172                 if (rv) {
00173                     if (ED_cutvalue(rv) > ED_cutvalue(f))
00174                         rv = f;
00175                 } else
00176                     rv = Tree_edge.list[S_i];
00177                 if (++cnt >= Search_size)
00178                     return rv;
00179             }
00180             S_i++;
00181         }
00182     }
00183     return rv;
00184 }
00185 
00186 static edge_t *Enter;
00187 static int Low, Lim, Slack;
00188 
00189 static void dfs_enter_outedge(node_t * v)
00190 {
00191     int i, slack;
00192     edge_t *e;
00193 
00194     for (i = 0; (e = ND_out(v).list[i]); i++) {
00195         if (TREE_EDGE(e) == FALSE) {
00196             if (!SEQ(Low, ND_lim(e->head), Lim)) {
00197                 slack = SLACK(e);
00198                 if ((slack < Slack) || (Enter == NULL)) {
00199                     Enter = e;
00200                     Slack = slack;
00201                 }
00202             }
00203         } else if (ND_lim(e->head) < ND_lim(v))
00204             dfs_enter_outedge(e->head);
00205     }
00206     for (i = 0; (e = ND_tree_in(v).list[i]) && (Slack > 0); i++)
00207         if (ND_lim(e->tail) < ND_lim(v))
00208             dfs_enter_outedge(e->tail);
00209 }
00210 
00211 static void dfs_enter_inedge(node_t * v)
00212 {
00213     int i, slack;
00214     edge_t *e;
00215 
00216     for (i = 0; (e = ND_in(v).list[i]); i++) {
00217         if (TREE_EDGE(e) == FALSE) {
00218             if (!SEQ(Low, ND_lim(e->tail), Lim)) {
00219                 slack = SLACK(e);
00220                 if ((slack < Slack) || (Enter == NULL)) {
00221                     Enter = e;
00222                     Slack = slack;
00223                 }
00224             }
00225         } else if (ND_lim(e->tail) < ND_lim(v))
00226             dfs_enter_inedge(e->tail);
00227     }
00228     for (i = 0; (e = ND_tree_out(v).list[i]) && (Slack > 0); i++)
00229         if (ND_lim(e->head) < ND_lim(v))
00230             dfs_enter_inedge(e->head);
00231 }
00232 
00233 static edge_t *enter_edge(edge_t * e)
00234 {
00235     node_t *v;
00236     int outsearch;
00237 
00238     /* v is the down node */
00239     if (ND_lim(e->tail) < ND_lim(e->head)) {
00240         v = e->tail;
00241         outsearch = FALSE;
00242     } else {
00243         v = e->head;
00244         outsearch = TRUE;
00245     }
00246     Enter = NULL;
00247     Slack = INT_MAX;
00248     Low = ND_low(v);
00249     Lim = ND_lim(v);
00250     if (outsearch)
00251         dfs_enter_outedge(v);
00252     else
00253         dfs_enter_inedge(v);
00254     return Enter;
00255 }
00256 
00257 static int treesearch(node_t * v)
00258 {
00259     int i;
00260     edge_t *e;
00261 
00262     for (i = 0; (e = ND_out(v).list[i]); i++) {
00263         if ((ND_mark(e->head) == FALSE) && (SLACK(e) == 0)) {
00264             add_tree_edge(e);
00265             if ((Tree_edge.size == N_nodes - 1) || treesearch(e->head))
00266                 return TRUE;
00267         }
00268     }
00269     for (i = 0; (e = ND_in(v).list[i]); i++) {
00270         if ((ND_mark(e->tail) == FALSE) && (SLACK(e) == 0)) {
00271             add_tree_edge(e);
00272             if ((Tree_edge.size == N_nodes - 1) || treesearch(e->tail))
00273                 return TRUE;
00274         }
00275     }
00276     return FALSE;
00277 }
00278 
00279 static int tight_tree(void)
00280 {
00281     int i;
00282     node_t *n;
00283 
00284     for (n = GD_nlist(G); n; n = ND_next(n)) {
00285         ND_mark(n) = FALSE;
00286         ND_tree_in(n).list[0] = ND_tree_out(n).list[0] = NULL;
00287         ND_tree_in(n).size = ND_tree_out(n).size = 0;
00288     }
00289     for (i = 0; i < Tree_edge.size; i++)
00290         Tree_edge.list[i]->u.tree_index = -1;
00291 
00292     Tree_node.size = Tree_edge.size = 0;
00293     for (n = GD_nlist(G); n && (Tree_edge.size == 0); n = ND_next(n))
00294         treesearch(n);
00295     return Tree_node.size;
00296 }
00297 
00298 static void init_cutvalues(void)
00299 {
00300     dfs_range(GD_nlist(G), NULL, 1);
00301     dfs_cutval(GD_nlist(G), NULL);
00302 }
00303 
00304 static int feasible_tree(void)
00305 {
00306     int i, delta;
00307     node_t *n;
00308     edge_t *e, *f;
00309 
00310     if (N_nodes <= 1)
00311         return 0;
00312     while (tight_tree() < N_nodes) {
00313         e = NULL;
00314         for (n = GD_nlist(G); n; n = ND_next(n)) {
00315             for (i = 0; (f = ND_out(n).list[i]); i++) {
00316                 if ((TREE_EDGE(f) == FALSE) && incident(f) && ((e == NULL)
00317                                                                || (SLACK(f)
00318                                                                    <
00319                                                                    SLACK
00320                                                                    (e))))
00321                     e = f;
00322             }
00323         }
00324         if (e) {
00325             delta = SLACK(e);
00326             if (delta) {
00327                 if (incident(e) == e->head)
00328                     delta = -delta;
00329                 for (i = 0; i < Tree_node.size; i++)
00330                     Tree_node.list[i]->u.rank += delta;
00331             }
00332         } else {
00333 #ifdef DEBUG
00334             fprintf(stderr, "not in tight tree:\n");
00335             for (n = GD_nlist(G); n; n = ND_next(n)) {
00336                 for (i = 0; i < Tree_node.size; i++)
00337                     if (Tree_node.list[i] == n)
00338                         break;
00339                 if (i >= Tree_node.size)
00340                     fprintf(stderr, "\t%s\n", n->name);
00341             }
00342 #endif
00343             return 1;
00344         }
00345     }
00346     init_cutvalues();
00347     return 0;
00348 }
00349 
00350 /* walk up from v to LCA(v,w), setting new cutvalues. */
00351 static node_t *treeupdate(node_t * v, node_t * w, int cutvalue, int dir)
00352 {
00353     edge_t *e;
00354     int d;
00355 
00356     while (!SEQ(ND_low(v), ND_lim(w), ND_lim(v))) {
00357         e = ND_par(v);
00358         if (v == e->tail)
00359             d = dir;
00360         else
00361             d = NOT(dir);
00362         if (d)
00363             ED_cutvalue(e) += cutvalue;
00364         else
00365             ED_cutvalue(e) -= cutvalue;
00366         if (ND_lim(e->tail) > ND_lim(e->head))
00367             v = e->tail;
00368         else
00369             v = e->head;
00370     }
00371     return v;
00372 }
00373 
00374 static void rerank(node_t * v, int delta)
00375 {
00376     int i;
00377     edge_t *e;
00378 
00379     ND_rank(v) -= delta;
00380     for (i = 0; (e = ND_tree_out(v).list[i]); i++)
00381         if (e != ND_par(v))
00382             rerank(e->head, delta);
00383     for (i = 0; (e = ND_tree_in(v).list[i]); i++)
00384         if (e != ND_par(v))
00385             rerank(e->tail, delta);
00386 }
00387 
00388 /* e is the tree edge that is leaving and f is the nontree edge that
00389  * is entering.  compute new cut values, ranks, and exchange e and f.
00390  */
00391 static void 
00392 update(edge_t * e, edge_t * f)
00393 {
00394     int cutvalue, delta;
00395     node_t *lca;
00396 
00397     delta = SLACK(f);
00398     /* "for (v = in nodes in tail side of e) do ND_rank(v) -= delta;" */
00399     if (delta > 0) {
00400         int s;
00401         s = ND_tree_in(e->tail).size + ND_tree_out(e->tail).size;
00402         if (s == 1)
00403             rerank(e->tail, delta);
00404         else {
00405             s = ND_tree_in(e->head).size + ND_tree_out(e->head).size;
00406             if (s == 1)
00407                 rerank(e->head, -delta);
00408             else {
00409                 if (ND_lim(e->tail) < ND_lim(e->head))
00410                     rerank(e->tail, delta);
00411                 else
00412                     rerank(e->head, -delta);
00413             }
00414         }
00415     }
00416 
00417     cutvalue = ED_cutvalue(e);
00418     lca = treeupdate(f->tail, f->head, cutvalue, 1);
00419     if (treeupdate(f->head, f->tail, cutvalue, 0) != lca)
00420         abort();
00421     ED_cutvalue(f) = -cutvalue;
00422     ED_cutvalue(e) = 0;
00423     exchange_tree_edges(e, f);
00424     dfs_range(lca, ND_par(lca), ND_low(lca));
00425 }
00426 
00427 static void scan_and_normalize(void)
00428 {
00429     node_t *n;
00430 
00431     Minrank = INT_MAX;
00432     Maxrank = -INT_MAX;
00433     for (n = GD_nlist(G); n; n = ND_next(n)) {
00434         if (ND_node_type(n) == NORMAL) {
00435             Minrank = MIN(Minrank, ND_rank(n));
00436             Maxrank = MAX(Maxrank, ND_rank(n));
00437         }
00438     }
00439     if (Minrank != 0) {
00440         for (n = GD_nlist(G); n; n = ND_next(n))
00441             ND_rank(n) -= Minrank;
00442         Maxrank -= Minrank;
00443         Minrank = 0;
00444     }
00445 }
00446 
00447 static void
00448 freeTreeList (graph_t* g)
00449 {
00450     node_t *n;
00451     for (n = GD_nlist(G); n; n = ND_next(n)) {
00452         free_list(ND_tree_in(n));
00453         free_list(ND_tree_out(n));
00454         ND_mark(n) = FALSE;
00455     }
00456 }
00457 
00458 static void LR_balance(void)
00459 {
00460     int i, delta;
00461     edge_t *e, *f;
00462 
00463     for (i = 0; i < Tree_edge.size; i++) {
00464         e = Tree_edge.list[i];
00465         if (ED_cutvalue(e) == 0) {
00466             f = enter_edge(e);
00467             if (f == NULL)
00468                 continue;
00469             delta = SLACK(f);
00470             if (delta <= 1)
00471                 continue;
00472             if (ND_lim(e->tail) < ND_lim(e->head))
00473                 rerank(e->tail, delta / 2);
00474             else
00475                 rerank(e->head, -delta / 2);
00476         }
00477     }
00478     freeTreeList (G);
00479 }
00480 
00481 static void TB_balance(void)
00482 {
00483     node_t *n;
00484     edge_t *e;
00485     int i, low, high, choice, *nrank;
00486     int inweight, outweight;
00487 
00488     scan_and_normalize();
00489 
00490     /* find nodes that are not tight and move to less populated ranks */
00491     nrank = N_NEW(Maxrank + 1, int);
00492     for (i = 0; i <= Maxrank; i++)
00493         nrank[i] = 0;
00494     for (n = GD_nlist(G); n; n = ND_next(n))
00495         if (ND_node_type(n) == NORMAL)
00496             nrank[ND_rank(n)]++;
00497     for (n = GD_nlist(G); n; n = ND_next(n)) {
00498         if (ND_node_type(n) != NORMAL)
00499             continue;
00500         inweight = outweight = 0;
00501         low = 0;
00502         high = Maxrank;
00503         for (i = 0; (e = ND_in(n).list[i]); i++) {
00504             inweight += ED_weight(e);
00505             low = MAX(low, ND_rank(e->tail) + ED_minlen(e));
00506         }
00507         for (i = 0; (e = ND_out(n).list[i]); i++) {
00508             outweight += ED_weight(e);
00509             high = MIN(high, ND_rank(e->head) - ED_minlen(e));
00510         }
00511         if (low < 0)
00512             low = 0;            /* vnodes can have ranks < 0 */
00513         if (inweight == outweight) {
00514             choice = low;
00515             for (i = low + 1; i <= high; i++)
00516                 if (nrank[i] < nrank[choice])
00517                     choice = i;
00518             nrank[ND_rank(n)]--;
00519             nrank[choice]++;
00520             ND_rank(n) = choice;
00521         }
00522         free_list(ND_tree_in(n));
00523         free_list(ND_tree_out(n));
00524         ND_mark(n) = FALSE;
00525     }
00526     free(nrank);
00527 }
00528 
00529 static int init_graph(graph_t * g)
00530 {
00531     int i, feasible;
00532     node_t *n;
00533     edge_t *e;
00534 
00535     G = g;
00536     N_nodes = N_edges = S_i = 0;
00537     for (n = GD_nlist(g); n; n = ND_next(n)) {
00538         ND_mark(n) = FALSE;
00539         N_nodes++;
00540         for (i = 0; (e = ND_out(n).list[i]); i++)
00541             N_edges++;
00542     }
00543 
00544     Tree_node.list = ALLOC(N_nodes, Tree_node.list, node_t *);
00545     Tree_node.size = 0;
00546     Tree_edge.list = ALLOC(N_nodes, Tree_edge.list, edge_t *);
00547     Tree_edge.size = 0;
00548 
00549     feasible = TRUE;
00550     for (n = GD_nlist(g); n; n = ND_next(n)) {
00551         ND_priority(n) = 0;
00552         for (i = 0; (e = ND_in(n).list[i]); i++) {
00553             ND_priority(n)++;
00554             ED_cutvalue(e) = 0;
00555             ED_tree_index(e) = -1;
00556             if (feasible
00557                 && (ND_rank(e->head) - ND_rank(e->tail) < ED_minlen(e)))
00558                 feasible = FALSE;
00559         }
00560         ND_tree_in(n).list = N_NEW(i + 1, edge_t *);
00561         ND_tree_in(n).size = 0;
00562         for (i = 0; (e = ND_out(n).list[i]); i++);
00563         ND_tree_out(n).list = N_NEW(i + 1, edge_t *);
00564         ND_tree_out(n).size = 0;
00565     }
00566     return feasible;
00567 }
00568 
00569 /* rank:
00570  * Apply network simplex to rank the nodes in a graph.
00571  * Uses ED_minlen as the internode constraint: if a->b with minlen=ml,
00572  * rank b - rank a >= ml.
00573  * Assumes the graph has the following additional structure:
00574  *   A list of all nodes, starting at GD_nlist, and linked using ND_next.
00575  *   Out and in edges lists stored in ND_out and ND_in, even if the node
00576  *  doesn't have any out or in edges.
00577  * The node rank values are stored in ND_rank.
00578  * Returns 0 if successful; returns 1 if not, the latter indicating that
00579  * the graph was not connected.
00580  */
00581 int rank(graph_t * g, int balance, int maxiter)
00582 {
00583     int iter = 0, feasible;
00584     char *s, *ns = "network simplex: ";
00585     edge_t *e, *f;
00586 
00587 #ifdef DEBUG
00588     check_cycles(g);
00589 #endif
00590     if (Verbose)
00591         start_timer();
00592     feasible = init_graph(g);
00593     if (!feasible)
00594         init_rank();
00595     if (maxiter <= 0) {
00596         freeTreeList (g);
00597         return 0;
00598     }
00599 
00600     if ((s = agget(g, "searchsize")))
00601         Search_size = atoi(s);
00602     else
00603         Search_size = SEARCHSIZE;
00604 
00605     if (feasible_tree()) {
00606         freeTreeList (g);
00607         return 1;
00608     }
00609     while ((e = leave_edge())) {
00610         f = enter_edge(e);
00611         update(e, f);
00612         iter++;
00613         if (Verbose && (iter % 100 == 0)) {
00614             if (iter % 1000 == 100)
00615                 fputs(ns, stderr);
00616             fprintf(stderr, "%d ", iter);
00617             if (iter % 1000 == 0)
00618                 fputc('\n', stderr);
00619         }
00620         if (iter >= maxiter)
00621             break;
00622     }
00623     switch (balance) {
00624     case 1:
00625         TB_balance();
00626         break;
00627     case 2:
00628         LR_balance();
00629         break;
00630     default:
00631         scan_and_normalize();
00632         break;
00633     }
00634     if (Verbose) {
00635         if (iter >= 100)
00636             fputc('\n', stderr);
00637         fprintf(stderr, "%s%d nodes %d edges %d iter %.2f sec\n",
00638                 ns, N_nodes, N_edges, iter, elapsed_sec());
00639     }
00640     return 0;
00641 }
00642 
00643 /* set cut value of f, assuming values of edges on one side were already set */
00644 static void x_cutval(edge_t * f)
00645 {
00646     node_t *v;
00647     edge_t *e;
00648     int i, sum, dir;
00649 
00650     /* set v to the node on the side of the edge already searched */
00651     if (ND_par(f->tail) == f) {
00652         v = f->tail;
00653         dir = 1;
00654     } else {
00655         v = f->head;
00656         dir = -1;
00657     }
00658 
00659     sum = 0;
00660     for (i = 0; (e = ND_out(v).list[i]); i++)
00661         sum += x_val(e, v, dir);
00662     for (i = 0; (e = ND_in(v).list[i]); i++)
00663         sum += x_val(e, v, dir);
00664     ED_cutvalue(f) = sum;
00665 }
00666 
00667 static int x_val(edge_t * e, node_t * v, int dir)
00668 {
00669     node_t *other;
00670     int d, rv, f;
00671 
00672     if (e->tail == v)
00673         other = e->head;
00674     else
00675         other = e->tail;
00676     if (!(SEQ(ND_low(v), ND_lim(other), ND_lim(v)))) {
00677         f = 1;
00678         rv = ED_weight(e);
00679     } else {
00680         f = 0;
00681         if (TREE_EDGE(e))
00682             rv = ED_cutvalue(e);
00683         else
00684             rv = 0;
00685         rv -= ED_weight(e);
00686     }
00687     if (dir > 0) {
00688         if (e->head == v)
00689             d = 1;
00690         else
00691             d = -1;
00692     } else {
00693         if (e->tail == v)
00694             d = 1;
00695         else
00696             d = -1;
00697     }
00698     if (f)
00699         d = -d;
00700     if (d < 0)
00701         rv = -rv;
00702     return rv;
00703 }
00704 
00705 static void dfs_cutval(node_t * v, edge_t * par)
00706 {
00707     int i;
00708     edge_t *e;
00709 
00710     for (i = 0; (e = ND_tree_out(v).list[i]); i++)
00711         if (e != par)
00712             dfs_cutval(e->head, e);
00713     for (i = 0; (e = ND_tree_in(v).list[i]); i++)
00714         if (e != par)
00715             dfs_cutval(e->tail, e);
00716     if (par)
00717         x_cutval(par);
00718 }
00719 
00720 static int dfs_range(node_t * v, edge_t * par, int low)
00721 {
00722     edge_t *e;
00723     int i, lim;
00724 
00725     lim = low;
00726     ND_par(v) = par;
00727     ND_low(v) = low;
00728     for (i = 0; (e = ND_tree_out(v).list[i]); i++)
00729         if (e != par)
00730             lim = dfs_range(e->head, e, lim);
00731     for (i = 0; (e = ND_tree_in(v).list[i]); i++)
00732         if (e != par)
00733             lim = dfs_range(e->tail, e, lim);
00734     ND_lim(v) = lim;
00735     return lim + 1;
00736 }
00737 
00738 #ifdef DEBUG
00739 void tchk(void)
00740 {
00741     int i, n_cnt, e_cnt;
00742     node_t *n;
00743     edge_t *e;
00744 
00745     n_cnt = 0;
00746     e_cnt = 0;
00747     for (n = GD_nlist(G); n; n = ND_next(n)) {
00748         n_cnt++;
00749         for (i = 0; (e = ND_tree_out(n).list[i]); i++) {
00750             e_cnt++;
00751             if (SLACK(e) > 0)
00752                 printf("not a tight tree %x", e);
00753         }
00754     }
00755     if ((n_cnt != Tree_node.size) || (e_cnt != Tree_edge.size))
00756         printf("something missing\n");
00757 }
00758 
00759 void check_cutvalues(void)
00760 {
00761     node_t *v;
00762     edge_t *e;
00763     int i, save;
00764 
00765     for (v = GD_nlist(G); v; v = ND_next(v)) {
00766         for (i = 0; (e = ND_tree_out(v).list[i]); i++) {
00767             save = ED_cutvalue(e);
00768             x_cutval(e);
00769             if (save != ED_cutvalue(e))
00770                 abort();
00771         }
00772     }
00773 }
00774 
00775 int check_ranks(void)
00776 {
00777     int i, cost = 0;
00778     node_t *n;
00779     edge_t *e;
00780 
00781     for (n = GD_nlist(G); n; n = ND_next(n)) {
00782         for (i = 0; (e = ND_out(n).list[i]); i++) {
00783             cost += (ED_weight(e)) * abs(LENGTH(e));
00784             if (ND_rank(e->head) - ND_rank(e->tail) - ED_minlen(e) < 0)
00785                 abort();
00786         }
00787     }
00788     fprintf(stderr, "rank cost %d\n", cost);
00789     return cost;
00790 }
00791 
00792 void checktree(void)
00793 {
00794     int i, n = 0, m = 0;
00795     node_t *v;
00796     edge_t *e;
00797 
00798     for (v = GD_nlist(G); v; v = ND_next(v)) {
00799         for (i = 0; (e = ND_tree_out(v).list[i]); i++)
00800             n++;
00801         if (i != ND_tree_out(v).size)
00802             abort();
00803         for (i = 0; (e = ND_tree_in(v).list[i]); i++)
00804             m++;
00805         if (i != ND_tree_in(v).size)
00806             abort();
00807     }
00808     printf("%d %d %d\n", Tree_edge.size, n, m);
00809 }
00810 
00811 void check_fast_node(node_t * n)
00812 {
00813     node_t *nptr;
00814     nptr = GD_nlist(n->graph);
00815     while (nptr && nptr != n)
00816         nptr = ND_next(nptr);
00817     assert(nptr != NULL);
00818 }
00819 
00820 static node_t *checkdfs(node_t * n)
00821 {
00822     int i;
00823     edge_t *e;
00824     node_t *w,*x;
00825 
00826     if (ND_mark(n))
00827         return 0;
00828     ND_mark(n) = TRUE;
00829     ND_onstack(n) = TRUE;
00830     for (i = 0; (e = ND_out(n).list[i]); i++) {
00831         w = e->head;
00832         if (ND_onstack(w)) {
00833             fprintf(stderr, "cycle: last edge %x %s(%x) %s(%x)\n",
00834                 e,n->name,n,w->name,w);
00835             return w;
00836         }
00837         else {
00838             if (ND_mark(w) == FALSE) {
00839                 x = checkdfs(w);
00840                 if (x) {
00841                     fprintf(stderr,"unwind %x %s(%x)\n",e,n->name,n);
00842                     if (x != n) return x;
00843                     fprintf(stderr,"unwound to root\n");
00844                     fflush(stderr);
00845                     abort();
00846                     return 0;
00847                 }
00848             }
00849         }
00850     }
00851     ND_onstack(n) = FALSE;
00852     return 0;
00853 }
00854 
00855 void check_cycles(graph_t * g)
00856 {
00857     node_t *n;
00858     for (n = GD_nlist(g); n; n = ND_next(n))
00859         ND_mark(n) = ND_onstack(n) = FALSE;
00860     for (n = GD_nlist(g); n; n = ND_next(n))
00861         checkdfs(n);
00862 }
00863 #endif                          /* DEBUG */

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