2
This software may only be used by you under license from AT&T Corp.
3
("AT&T"). A copy of AT&T's Source Code Agreement is available at
4
AT&T's Internet website having the URL:
5
<http://www.research.att.com/sw/tools/graphviz/license/source.html>
6
If you received this software without first entering into a license
7
with AT&T, you have an infringing copy of this software and cannot use
8
it without violating AT&T's intellectual property rights.
13
* Network Simplex Algorithm for Ranking Nodes of a DAG
22
static int init_graph(graph_t *);
24
#define LENGTH(e) ((e)->head->u.rank - (e)->tail->u.rank)
25
#define SLACK(e) (LENGTH(e) - (e)->u.minlen)
26
#define SEQ(a,b,c) (((a) <= (b)) && ((b) <= (c)))
27
#define TREE_EDGE(e) (e->u.tree_index >= 0)
30
static int N_nodes,N_edges;
31
static int Minrank,Maxrank;
32
static int S_i; /* search index for enter_edge */
33
static int Search_size;
35
static nlist_t Tree_node;
36
static elist Tree_edge;
38
void add_tree_edge(edge_t* e)
41
if (TREE_EDGE(e)) abort();
42
e->u.tree_index = Tree_edge.size;
43
Tree_edge.list[Tree_edge.size++] = e;
44
if (e->tail->u.mark == FALSE) Tree_node.list[Tree_node.size++] = e->tail;
45
if (e->head->u.mark == FALSE) Tree_node.list[Tree_node.size++] = e->head;
48
n->u.tree_out.list[n->u.tree_out.size++] = e;
49
n->u.tree_out.list[n->u.tree_out.size] = NULL;
50
if (n->u.out.list[n->u.tree_out.size-1] == 0) abort();
53
n->u.tree_in.list[n->u.tree_in.size++] = e;
54
n->u.tree_in.list[n->u.tree_in.size] = NULL;
55
if (n->u.in.list[n->u.tree_in.size-1] == 0) abort();
58
void exchange_tree_edges(edge_t *e,edge_t *f)
63
f->u.tree_index = e->u.tree_index;
64
Tree_edge.list[e->u.tree_index] = f;
68
i = --(n->u.tree_out.size);
69
for (j = 0; j <= i; j++) if (n->u.tree_out.list[j] == e) break;
70
n->u.tree_out.list[j] = n->u.tree_out.list[i];
71
n->u.tree_out.list[i] = NULL;
73
i = --(n->u.tree_in.size);
74
for (j = 0; j <= i; j++) if (n->u.tree_in.list[j] == e) break;
75
n->u.tree_in.list[j] = n->u.tree_in.list[i];
76
n->u.tree_in.list[i] = NULL;
79
n->u.tree_out.list[n->u.tree_out.size++] = f;
80
n->u.tree_out.list[n->u.tree_out.size] = NULL;
82
n->u.tree_in.list[n->u.tree_in.size++] = f;
83
n->u.tree_in.list[n->u.tree_in.size] = NULL;
93
Q = new_queue(N_nodes);
96
for (v = G->u.nlist; v; v = v->u.next) {
97
if (v->u.priority == 0) enqueue(Q,v);
100
while ((v = dequeue(Q))) {
103
for (i = 0; (e = v->u.in.list[i]); i++)
104
v->u.rank = MAX(v->u.rank,e->tail->u.rank + e->u.minlen);
105
for (i = 0; (e = v->u.out.list[i]); i++) {
106
if (--(e->head->u.priority) <= 0) enqueue(Q,e->head);
109
if (ctr != N_nodes) {
110
fprintf(stderr,"trouble in init_rank\n");
111
for (v = G->u.nlist; v; v = v->u.next)
113
fprintf(stderr,"\t%s %d\n",v->name,v->u.priority);
121
if (e->tail->u.mark) {
122
if (e->head->u.mark == FALSE)
135
edge_t *f,*rv = NULL;
139
while (S_i < Tree_edge.size) {
140
if ((f = Tree_edge.list[S_i])->u.cutvalue < 0) {
142
if (rv->u.cutvalue > f->u.cutvalue) rv = f;
144
else rv = Tree_edge.list[S_i];
145
if (++cnt >= Search_size) return rv;
152
if ((f = Tree_edge.list[S_i])->u.cutvalue < 0) {
154
if (rv->u.cutvalue > f->u.cutvalue) rv = f;
156
else rv = Tree_edge.list[S_i];
157
if (++cnt >= Search_size) return rv;
165
static edge_t *Enter;
166
static int Low,Lim,Slack;
168
void dfs_enter_outedge(node_t* v)
173
for (i = 0; (e = v->u.out.list[i]); i++) {
174
if (TREE_EDGE(e) == FALSE) {
175
if (!SEQ(Low,e->head->u.lim,Lim)) {
177
if ((slack < Slack) || (Enter == NULL)) {
183
else if (e->head->u.lim < v->u.lim) dfs_enter_outedge(e->head);
185
for (i = 0; (e = v->u.tree_in.list[i]) && (Slack > 0); i++)
186
if (e->tail->u.lim < v->u.lim) dfs_enter_outedge(e->tail);
189
void dfs_enter_inedge(node_t* v)
194
for (i = 0; (e = v->u.in.list[i]); i++) {
195
if (TREE_EDGE(e) == FALSE) {
196
if (!SEQ(Low,e->tail->u.lim,Lim)) {
198
if ((slack < Slack) || (Enter == NULL)) {
204
else if (e->tail->u.lim < v->u.lim) dfs_enter_inedge(e->tail);
206
for (i = 0; (e = v->u.tree_out.list[i]) && (Slack > 0); i++)
207
if (e->head->u.lim < v->u.lim) dfs_enter_inedge(e->head);
211
enter_edge(edge_t* e)
216
/* v is the down node */
217
if (e->tail->u.lim < e->head->u.lim) {v = e->tail; outsearch = FALSE;}
218
else {v = e->head;outsearch = TRUE;}
223
if (outsearch) dfs_enter_outedge(v);
224
else dfs_enter_inedge(v);
228
int treesearch(node_t* v)
233
for (i = 0; (e = v->u.out.list[i]); i++) {
234
if ((e->head->u.mark == FALSE) && (SLACK(e) == 0)) {
236
if ((Tree_edge.size == N_nodes-1) || treesearch(e->head)) return TRUE;
239
for (i = 0; (e = v->u.in.list[i]); i++) {
240
if ((e->tail->u.mark == FALSE) && (SLACK(e) == 0)) {
242
if ((Tree_edge.size == N_nodes-1) || treesearch(e->tail)) return TRUE;
254
for (n = G->u.nlist; n; n = n->u.next) {
256
n->u.tree_in.list[0] = n->u.tree_out.list[0] = NULL;
257
n->u.tree_in.size = n->u.tree_out.size = 0;
259
for (i = 0; i < Tree_edge.size; i++) Tree_edge.list[i]->u.tree_index = -1;
261
Tree_node.size = Tree_edge.size = 0;
262
for (n = G->u.nlist; n && (Tree_edge.size == 0); n = n->u.next) treesearch(n);
263
return Tree_node.size;
266
void init_cutvalues(void)
268
dfs_range(G->u.nlist,NULL,1);
269
dfs_cutval(G->u.nlist,NULL);
272
void feasible_tree(void)
278
if (N_nodes <= 1) return;
279
while (tight_tree() < N_nodes) {
281
for (n = G->u.nlist; n; n = n->u.next) {
282
for (i = 0; (f = n->u.out.list[i]); i++) {
283
if ((TREE_EDGE(f) == FALSE) && incident(f) && ((e == NULL)
284
|| (SLACK(f) < SLACK(e)))) e = f;
290
if (incident(e) == e->head) delta = -delta;
291
for (i = 0; i < Tree_node.size; i++)
292
Tree_node.list[i]->u.rank += delta;
297
fprintf(stderr,"not in tight tree:\n");
298
for (n = G->u.nlist; n; n = n->u.next) {
299
for (i = 0; i < Tree_node.size; i++)
300
if (Tree_node.list[i] == n) break;
301
if (i >= Tree_node.size) fprintf(stderr,"\t%s\n",n->name);
310
/* walk up from v to LCA(v,w), setting new cutvalues. */
312
treeupdate(node_t *v, node_t *w, int cutvalue, int dir)
317
while (!SEQ(v->u.low,w->u.lim,v->u.lim)) {
319
if (v == e->tail) d = dir; else d = NOT(dir);
320
if (d) e->u.cutvalue += cutvalue; else e->u.cutvalue -= cutvalue;
321
if (e->tail->u.lim > e->head->u.lim) v = e->tail; else v = e->head;
326
void rerank(node_t* v, int delta)
332
for (i = 0; (e = v->u.tree_out.list[i]); i++)
333
if (e != v->u.par) rerank(e->head,delta);
334
for (i = 0; (e = v->u.tree_in.list[i]); i++)
335
if (e != v->u.par) rerank(e->tail,delta);
338
/* e is the tree edge that is leaving and f is the nontree edge that
339
* is entering. compute new cut values, ranks, and exchange e and f.
341
void update(edge_t *e, edge_t *f)
347
/* "for (v = in nodes in tail side of e) do v->u.rank -= delta;" */
350
s = e->tail->u.tree_in.size + e->tail->u.tree_out.size;
351
if (s == 1) rerank(e->tail,delta);
353
s = e->head->u.tree_in.size + e->head->u.tree_out.size;
354
if (s == 1) rerank(e->head,-delta);
356
if (e->tail->u.lim < e->head->u.lim) rerank(e->tail,delta);
357
else rerank(e->head,-delta);
362
cutvalue = e->u.cutvalue;
363
lca = treeupdate(f->tail,f->head,cutvalue,1);
364
if (treeupdate(f->head,f->tail,cutvalue,0) != lca) abort();
365
f->u.cutvalue = -cutvalue;
367
exchange_tree_edges(e,f);
368
dfs_range(lca,lca->u.par,lca->u.low);
371
void scan_result(void)
377
for (n = G->u.nlist; n; n = n->u.next) {
378
if (n->u.node_type == NORMAL) {
379
Minrank = MIN(Minrank,n->u.rank);
380
Maxrank = MAX(Maxrank,n->u.rank);
385
void LR_balance(void)
391
for (i = 0; i < Tree_edge.size; i++) {
392
e = Tree_edge.list[i];
393
if (e->u.cutvalue == 0) {
395
if (f == NULL) continue;
397
if (delta <= 1) continue;
398
if (e->tail->u.lim < e->head->u.lim) rerank(e->tail,delta/2);
399
else rerank(e->head,-delta/2);
402
for (n = G->u.nlist; n; n = n->u.next) {
403
free_list(n->u.tree_in);
404
free_list(n->u.tree_out);
409
void TB_balance(void)
413
int i,low,high,choice,*nrank;
414
int inweight,outweight;
418
for (n = G->u.nlist; n; n = n->u.next) n->u.rank -= Minrank;
423
/* find nodes that are not tight and move to less populated ranks */
424
nrank = N_NEW(Maxrank+1,int);
425
for (i = 0; i <= Maxrank; i++) nrank[i] = 0;
426
for (n = G->u.nlist; n; n = n->u.next)
427
if (n->u.node_type == NORMAL) nrank[n->u.rank]++;
428
for (n = G->u.nlist; n; n = n->u.next) {
429
if (n->u.node_type != NORMAL) continue;
430
inweight = outweight = 0;
433
for (i = 0; (e = n->u.in.list[i]); i++) {
434
inweight += e->u.weight;
435
low = MAX(low,e->tail->u.rank + e->u.minlen);
437
for (i = 0; (e = n->u.out.list[i]); i++) {
438
outweight += e->u.weight;
439
high = MIN(high,e->head->u.rank - e->u.minlen);
441
if (low < 0) low = 0; /* vnodes can have ranks < 0 */
442
if (inweight == outweight) {
444
for (i = low + 1; i <= high; i++)
445
if (nrank[i] < nrank[choice]) choice = i;
446
nrank[n->u.rank]--; nrank[choice]++;
449
free_list(n->u.tree_in);
450
free_list(n->u.tree_out);
457
init_graph(graph_t* g)
464
N_nodes = N_edges = S_i = 0;
465
for (n = g->u.nlist; n; n = n->u.next) {
468
for (i = 0; (e = n->u.out.list[i]); i++) N_edges++;
471
Tree_node.list = ALLOC(N_nodes,Tree_node.list,node_t*);
473
Tree_edge.list = ALLOC(N_nodes,Tree_edge.list,edge_t*);
477
for (n = g->u.nlist; n; n = n->u.next) {
479
for (i = 0; (e = n->u.in.list[i]); i++) {
482
e->u.tree_index = -1;
483
if (feasible && (e->head->u.rank - e->tail->u.rank < e->u.minlen))
486
n->u.tree_in.list = N_NEW(i+1,edge_t*);
487
n->u.tree_in.size = 0;
488
for (i = 0; (e = n->u.out.list[i]); i++);
489
n->u.tree_out.list = N_NEW(i+1,edge_t*);
490
n->u.tree_out.size = 0;
495
void rank(graph_t *g, int tb_mode, int maxiter)
497
int iter = 0,feasible;
498
char *s,*ns = "network simplex: ";
501
if (Verbose) start_timer();
502
feasible = init_graph(g);
503
if (!feasible) init_rank();
504
if (maxiter <= 0) return;
506
if ((s = agget(g,"searchsize"))) Search_size = atoi(s);
507
else Search_size = SEARCHSIZE;
510
while ((e = leave_edge())) {
514
if (Verbose && (iter % 100 == 0)) {
515
if (iter % 1000 == 100) fputs(ns,stderr);
516
fprintf(stderr,"%d ",iter);
517
if (iter % 1000 == 0) fputc('\n',stderr);
518
if (iter >= maxiter) break;
521
if (tb_mode) TB_balance();
524
if (iter >= 100) fputc('\n',stderr);
525
fprintf(stderr,"%s%d nodes %d edges %d iter %.2f sec\n",
526
ns,N_nodes,N_edges,iter,elapsed_sec());
530
/* set cut value of f, assuming values of edges on one side were already set */
531
void x_cutval(edge_t* f)
537
/* set v to the node on the side of the edge already searched */
538
if (f->tail->u.par == f) { v = f->tail; dir = 1; }
539
else { v = f->head; dir = -1; }
542
for (i = 0; (e = v->u.out.list[i]); i++) sum += x_val(e,v,dir);
543
for (i = 0; (e = v->u.in.list[i]); i++) sum += x_val(e,v,dir);
547
int x_val(edge_t* e, node_t* v, int dir)
552
if (e->tail == v) other = e->head; else other = e->tail;
553
if (!(SEQ(v->u.low,other->u.lim,v->u.lim))) {f = 1; rv = e->u.weight;}
556
if (TREE_EDGE(e)) rv = e->u.cutvalue;
560
if (dir > 0) {if (e->head == v) d = 1; else d = -1;}
561
else {if (e->tail == v) d = 1; else d = -1; }
567
void dfs_cutval(node_t* v, edge_t* par)
572
for (i = 0; (e = v->u.tree_out.list[i]); i++)
573
if (e != par) dfs_cutval(e->head,e);
574
for (i = 0; (e = v->u.tree_in.list[i]); i++)
575
if (e != par) dfs_cutval(e->tail,e);
576
if (par) x_cutval(par);
579
int dfs_range(node_t* v, edge_t* par, int low)
587
for (i = 0; (e = v->u.tree_out.list[i]); i++)
588
if (e != par) lim = dfs_range(e->head,e,lim);
589
for (i = 0; (e = v->u.tree_in.list[i]); i++)
590
if (e != par) lim = dfs_range(e->tail,e,lim);
604
for (n = G->u.nlist; n; n = n->u.next) {
606
for (i = 0; e = n->u.tree_out.list[i]; i++) {
609
printf("not a tight tree %x",e);
612
if ((n_cnt != Tree_node.size) || (e_cnt != Tree_edge.size))
613
printf("something missing\n");
616
void check_cutvalues(void)
622
for (v = G->u.nlist; v; v = v->u.next) {
623
for (i = 0; (e = v->u.tree_out.list[i]); i++) {
624
save = e->u.cutvalue;
626
if (save != e->u.cutvalue) abort();
638
for (n = G->u.nlist; n; n = n->u.next) {
639
for (i = 0; (e = n->u.out.list[i]); i++) {
640
cost += (e->u.weight)*abs(LENGTH(e));
641
if (e->head->u.rank - e->tail->u.rank - e->u.minlen < 0) abort();
644
fprintf(stderr,"rank cost %d\n",cost);
654
for (v = G->u.nlist; v; v = v->u.next) {
655
for (i = 0; (e = v->u.tree_out.list[i]); i++) n++;
656
if (i != v->u.tree_out.size) abort();
657
for (i = 0; (e = v->u.tree_in.list[i]); i++) m++;
658
if (i != v->u.tree_in.size) abort();
660
printf("%d %d %d\n",Tree_edge.size,n,m);
663
void check_fast_node(node_t* n)
666
nptr = n->graph->u.nlist;
667
while (nptr && nptr != n) nptr = nptr->u.next;
668
assert (nptr != NULL);
671
void checkdfs(node_t* n)
677
if (n->u.mark) return;
680
for (i = 0; (e = n->u.out.list[i]); i++) {
683
fprintf(stderr,"cycle involving %s %s\n",n->name,w->name);
685
if (w->u.mark == FALSE) checkdfs(w);
688
n->u.onstack = FALSE;
691
void check_cycles(graph_t* g)
694
for (n = g->u.nlist; n; n = n->u.next) n->u.mark = n->u.onstack = FALSE;
695
for (n = g->u.nlist; n; n = n->u.next) checkdfs(n);