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