|
Graphviz
2.29.20120524.0446
|
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 */
1.7.5