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
* dot_mincross(g) takes a ranked graphs, and finds an ordering
14
* that avoids edge crossings. clusters are expanded.
15
* N.B. the rank structure is global (not allocated per cluster)
16
* because mincross may compare nodes in different clusters.
25
#define MARK(v) ((v)->u.mark)
26
#define saveorder(v) ((v)->u.coord.x)
27
#define flatindex(v) ((v)->u.low)
29
/* forward declarations */
30
static boolean medians(graph_t *g, int r0, int r1);
31
static int nodeposcmpf(node_t **n0, node_t **n1);
32
static int edgeidcmpf(edge_t **e0, edge_t **e1);
33
static void flat_breakcycles(graph_t* g);
34
static void flat_reorder(graph_t* g);
35
static void flat_search(graph_t* g, node_t* v);
36
static void init_mincross(graph_t* g);
37
static void merge2(graph_t* g);
38
static void init_mccomp(graph_t* g, int c);
39
static void cleanup2(graph_t* g, int nc);
40
static int mincross_clust(graph_t *par, graph_t *g);
41
static int mincross(graph_t *g, int startpass, int endpass);
42
static void init_mincross(graph_t* g);
43
static void mincross_step(graph_t* g, int pass);
44
static void mincross_options(graph_t* g);
45
static void save_best(graph_t* g);
46
static void restore_best(graph_t* g);
47
static adjmatrix_t* new_matrix(int i, int j);
48
static void free_matrix(adjmatrix_t* p);
50
/* mincross parameters */
52
static double Convergence;
55
static int GlobalMinRank,GlobalMaxRank;
56
static edge_t **TE_list;
58
static boolean ReMincross;
60
void dot_mincross(graph_t* g)
67
for (nc = c = 0; c < g->u.comp.size; c++) {
69
nc += mincross(g,0,2);
74
/* run mincross on contents of each cluster */
75
for (c = 1; c <= g->u.n_cluster; c++) {
76
nc += mincross_clust(g,g->u.clust[c]);
78
check_vlists(g->u.clust[c]);
83
if ((g->u.n_cluster > 0) && (!(s = agget(g,"remincross")) || (mapbool(s)))) {
88
for (c = 1; c <= g->u.n_cluster; c++)
89
check_vlists(g->u.clust[c]);
95
static adjmatrix_t* new_matrix(int i, int j)
97
adjmatrix_t *rv = NEW(adjmatrix_t);
98
rv->nrows = i; rv->ncols = j;
99
rv->data = N_NEW(i*j,char);
103
static void free_matrix(adjmatrix_t* p)
105
if (p) {free(p->data); free(p);}
107
#define ELT(M,i,j) (M->data[((i)*M->ncols)+(j)])
109
static void init_mccomp(graph_t* g, int c)
113
g->u.nlist = g->u.comp.list[c];
115
for (r = g->u.minrank; r <= g->u.maxrank; r++) {
116
g->u.rank[r].v = g->u.rank[r].v + g->u.rank[r].n;
122
static int mincross_clust(graph_t *par, graph_t *g)
130
nc = mincross(g,2,2);
132
for (c = 1; c <= g->u.n_cluster; c++)
133
nc += mincross_clust(g,g->u.clust[c]);
139
static int mincross(graph_t *g, int startpass, int endpass)
141
int maxthispass,iter,trying,pass;
142
int cur_cross,best_cross;
145
cur_cross = best_cross = ncross(g);
148
else cur_cross = best_cross = MAXINT;
149
for (pass = startpass; pass <= endpass; pass++) {
151
maxthispass = MIN(4,MaxIter);
152
if (g == g->root) build_ranks(g,pass);
153
if (pass == 0) flat_breakcycles(g);
156
if ((cur_cross = ncross(g)) <= best_cross) {
158
best_cross = cur_cross;
163
maxthispass = MaxIter;
164
if (cur_cross > best_cross) restore_best(g);
165
cur_cross = best_cross;
168
for (iter = 0; iter < maxthispass; iter++) {
169
if (Verbose) fprintf(stderr,"mincross: pass %d iter %d trying %d cur_cross %d best_cross %d\n",pass,iter,trying,cur_cross,best_cross);
170
if (trying++ >= MinQuit) break;
171
if (cur_cross == 0) break;
172
mincross_step(g,iter);
173
if ((cur_cross = ncross(g)) <= best_cross) {
175
if (cur_cross < Convergence*best_cross) trying = 0;
176
best_cross = cur_cross;
179
if (cur_cross == 0) break;
181
if (cur_cross > best_cross) restore_best(g);
182
if (best_cross > 0) {transpose(g,FALSE); best_cross= ncross(g);}
186
static void restore_best(graph_t* g)
191
for (n = g->u.nlist; n; n = n->u.next) n->u.order = saveorder(n);
192
for (r = g->u.minrank; r <= g->u.maxrank; r++) {
193
g->u.rank[r].valid = FALSE;
194
qsort(g->u.rank[r].v,g->u.rank[r].n,sizeof(g->u.rank[0].v[0]),(qsort_cmpf)nodeposcmpf);
198
static void save_best(graph_t* g)
201
for (n = g->u.nlist; n; n = n->u.next) saveorder(n) = n->u.order;
204
/* merge connected components, create globally consistent rank lists */
205
static void merge2(graph_t* g)
210
/* merge the components and rank limits */
213
/* install complete ranks */
214
for (r = g->u.minrank; r <= g->u.maxrank; r++) {
215
g->u.rank[r].n = g->u.rank[r].an;
216
g->u.rank[r].v = g->u.rank[r].av;
217
for (i = 0; i < g->u.rank[r].n; i++) {
218
v = g->u.rank[r].v[i];
220
if (Verbose) fprintf(stderr,"merge2: graph %s, rank %d has only %d < %d nodes\n",g->name,r,i,g->u.rank[r].n);
229
static void cleanup2(graph_t* g, int nc)
235
free(TI_list); free(TE_list);
236
/* fix vlists of clusters */
237
for (c = 1; c <= g->u.n_cluster; c++)
238
rec_reset_vlists(g->u.clust[c]);
240
/* remove node temporary edges for ordering nodes */
241
for (r = g->u.minrank; r <= g->u.maxrank; r++) {
242
for (i = 0; i < g->u.rank[r].n; i++) {
243
v = g->u.rank[r].v[i];
245
if (v->u.flat_out.list) {
246
for (j = 0; (e = v->u.flat_out.list[j]); j++)
247
if (e->u.edge_type == FLATORDER) {
254
free_matrix(g->u.rank[r].flat);
256
if (Verbose) fprintf(stderr,"mincross %s: %d crossings, %.2f secs.\n",
257
g->name,nc,elapsed_sec());
260
static node_t* neighbor(node_t* v, int dir)
266
if (v->u.order > 0) rv = Root->u.rank[v->u.rank].v[v->u.order - 1];
268
else rv = Root->u.rank[v->u.rank].v[v->u.order + 1];
272
int inside_cluster(graph_t* g, node_t* v)
274
return (is_a_normal_node_of(g,v) | is_a_vnode_of_an_edge_of(g,v));
277
int is_a_normal_node_of(graph_t* g, node_t* v)
279
return ((v->u.node_type == NORMAL) && agcontains(g,v));
282
int is_a_vnode_of_an_edge_of(graph_t* g, node_t* v)
284
if ((v->u.node_type == VIRTUAL)
285
&& (v->u.in.size == 1) && (v->u.out.size == 1) ) {
286
edge_t *e = v->u.out.list[0];
287
while (e->u.edge_type != NORMAL) e = e->u.to_orig;
288
if (agcontains(g,e)) return TRUE;
293
static node_t *furthestnode(graph_t* g, node_t* v, int dir)
298
while ((u = neighbor(u,dir))) {
299
if (is_a_normal_node_of(g,u)) rv = u;
300
else if (is_a_vnode_of_an_edge_of(g,u)) rv = u;
305
void save_vlist(graph_t* g)
310
for (r = g->u.minrank; r <= g->u.maxrank; r++) {
311
g->u.rankleader[r] = g->u.rank[r].v[0];
315
void rec_save_vlists(graph_t* g)
320
for (c = 1; c <= g->u.n_cluster; c++)
321
rec_save_vlists(g->u.clust[c]);
325
void rec_reset_vlists(graph_t* g)
330
/* fix vlists of sub-clusters */
331
for (c = 1; c <= g->u.n_cluster; c++)
332
rec_reset_vlists(g->u.clust[c]);
335
for (r = g->u.minrank; r <= g->u.maxrank; r++) {
336
v = g->u.rankleader[r];
338
assert(node_in_root_vlist(v));
340
u = furthestnode(g,v,-1);
341
w = furthestnode(g,v, 1);
342
g->u.rankleader[r] = u;
344
assert(g->root->u.rank[r].v[u->u.order] == u);
346
g->u.rank[r].v = g->root->u.rank[r].v + u->u.order;
347
g->u.rank[r].n = w->u.order - u->u.order + 1;
351
static void init_mincross(graph_t* g)
353
if (Verbose) start_timer();
357
TE_list = N_NEW(agnedges(g->root),edge_t*);
358
TI_list = N_NEW(agnedges(g->root),int);
365
GlobalMinRank = g->u.minrank; GlobalMaxRank = g->u.maxrank;
368
static void flat_search(graph_t* g, node_t* v)
373
adjmatrix_t *M = g->u.rank[v->u.rank].flat;
377
hascl = (g->root->u.n_cluster > 0);
378
if (v->u.flat_out.list) for (i = 0; (e = v->u.flat_out.list[i]); i++) {
379
if (hascl && NOT(agcontains(g,e->tail) && agcontains(g,e->head)))
381
if (e->u.weight == 0) continue;
382
if (e->head->u.onstack == TRUE) {
383
assert(flatindex(e->head) < M->nrows);
384
assert(flatindex(e->tail) < M->ncols);
385
ELT(M,flatindex(e->head),flatindex(e->tail)) = 1;
388
if (e->u.edge_type == FLATORDER) continue;
389
for (j = 0; (rev = e->head->u.flat_out.list[j]); j++)
390
if (rev->head == e->tail) break;
393
elist_append(e,e->tail->u.other);
396
rev = new_virtual_edge(e->head,e->tail,e);
397
rev->u.edge_type = REVERSED;
402
assert(flatindex(e->head) < M->nrows);
403
assert(flatindex(e->tail) < M->ncols);
404
ELT(M,flatindex(e->tail),flatindex(e->head)) = 1;
405
if (e->head->u.mark == FALSE) flat_search(g,e->head);
408
v->u.onstack = FALSE;
411
static void flat_breakcycles(graph_t* g)
416
for (r = g->u.minrank; r <= g->u.maxrank; r++) {
418
for (i = 0; i < g->u.rank[r].n; i++) {
419
v = g->u.rank[r].v[i];
420
v->u.mark = v->u.onstack = FALSE;
422
if ((v->u.flat_out.size > 0) && (flat == 0)) {
423
g->u.rank[r].flat = new_matrix(g->u.rank[r].n,g->u.rank[r].n);
428
for (i = 0; i < g->u.rank[r].n; i++) {
429
v = g->u.rank[r].v[i];
430
if (v->u.mark == FALSE) flat_search(g,v);
436
int left2right(graph_t *g, node_t *v, node_t *w)
441
/* CLUSTER indicates orig nodes of clusters, and vnodes of skeletons */
442
if (ReMincross == FALSE) {
443
if ((v->u.clust != w->u.clust) && (v->u.clust) && (w->u.clust)) {
444
/* the following allows cluster skeletons to be swapped */
445
if ((v->u.ranktype == CLUSTER) && (v->u.node_type == VIRTUAL)) return FALSE;
446
if ((w->u.ranktype == CLUSTER) && (w->u.node_type == VIRTUAL)) return FALSE;
448
/*return ((v->u.ranktype != CLUSTER) && (w->u.ranktype != CLUSTER));*/
452
if ((v->u.clust) != (w->u.clust)) return TRUE;
454
M = g->u.rank[v->u.rank].flat;
455
if (M == NULL) rv = FALSE;
457
if (g->u.left_to_right) {node_t *t = v; v = w; w = t;}
458
rv = ELT(M,flatindex(v),flatindex(w));
463
static void clust_count_ranks(graph_t* g, int* count)
468
for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
469
assert (n->u.UF_size > 0);
470
count[n->u.rank] += n->u.UF_size;
471
for (e = agfstout(g->root,n); e; e = agnxtout(g->root,e)) {
472
low = e->tail->u.rank; high = e->head->u.rank;
473
if (low > high) {int t = low; low = high; high = t;}
475
for (j = low + 1; j <= high - 1; j++) count[j] += e->u.xpenalty;
480
/* should combine with previous, just need to count rankleaders */
481
static void count_ranks(graph_t* g, int** c0)
489
count = ALLOC(Root->u.maxrank+1,count,int);
490
for (c = 0; c <= g->u.maxrank; c++) count[c] = 0;
492
for (c = 0; c < g->u.comp.size; c++) {
493
for (n = g->u.comp.list[c]; n; n = n->u.next) {
494
assert (n->u.UF_size > 0);
495
count[n->u.rank] += n->u.UF_size;
496
for (i = 0; (e = n->u.out.list[i]); i++) {
497
low = e->tail->u.rank; high = e->head->u.rank;
499
for (j = low + 1; j <= high - 1; j++) count[j] += e->u.xpenalty;
503
for (c = 1; c <= g->u.n_cluster; c++)
504
clust_count_ranks(g->u.clust[c],count);
508
/* allocates ranks, with enough space for all nodes expanded */
509
void allocate_ranks(graph_t* g)
514
g->u.rank = N_NEW(g->u.maxrank+2,rank_t);
515
for (r = g->u.minrank; r <= g->u.maxrank; r++) {
516
g->u.rank[r].an = g->u.rank[r].n = cn[r];
517
g->u.rank[r].av = g->u.rank[r].v = N_NEW(cn[r]+1,node_t*);
521
/* install a node at the current right end of its rank */
522
void install_in_rank(graph_t* g, node_t* n)
528
if (g->u.rank[r].an <= 0) {
529
fprintf(stderr,"install_in_rank %s %s rank %d i = %d an = 0\n",
530
g->name,n->name,r,i);
534
g->u.rank[r].v[i] = n;
537
assert(g->u.rank[r].n <= g->u.rank[r].an);
542
for (v = g->u.nlist; v; v = v->u.next)
547
if (n->u.order > Root->u.rank[r].an) abort();
548
if ((r < g->u.minrank) || (r > g->u.maxrank)) abort();
549
if (g->u.rank[r].v + n->u.order > g->u.rank[r].av + Root->u.rank[r].an) abort();
552
/* install nodes in ranks. the initial ordering ensure that series-parallel
553
* graphs such as trees are drawn with no crossings. it tries searching
554
* in- and out-edges and takes the better of the two initial orderings.
556
void build_ranks(graph_t* g, int pass)
564
q = new_queue(g->u.n_nodes);
565
for (n = g->u.nlist; n; n = n->u.next) MARK(n) = FALSE;
570
for (n = g->u.nlist; n; n = n->u.next) {
571
for (i = 0; (e = n->u.out.list[i]); i++)
572
assert(MARK(e->head) == FALSE);
573
for (i = 0; (e = n->u.in.list[i]); i++)
574
assert(MARK(e->tail) == FALSE);
579
for (i = g->u.minrank; i <= g->u.maxrank; i++) g->u.rank[i].n = 0;
581
for (n = g->u.nlist; n; n = n->u.next) {
582
otheredges = ((pass == 0)? n->u.in.list : n->u.out.list);
583
if (otheredges[0] != NULL) continue;
584
if (MARK(n) == FALSE) {
587
while ((n0 = dequeue(q))) {
588
if (n0->u.ranktype != CLUSTER) {
589
install_in_rank(g,n0);
590
enqueue_neighbors(q,n0,pass);
593
install_cluster(g,n0,pass,q);
598
if (dequeue(q)) fprintf(stderr,"surprise\n");
599
for (i = g->u.minrank; i <= g->u.maxrank; i++) {
600
g->u.rank[i].valid = FALSE;
601
if (g->u.left_to_right && (g->u.rank[i].n > 0)) {
603
node_t **vlist = g->u.rank[i].v;
604
n = g->u.rank[i].n - 1; ndiv2 = n / 2;
605
for (j = 0; j <= ndiv2; j++)
606
exchange(vlist[j],vlist[n - j]);
610
if ((g == g->root) && ncross(g) > 0) transpose(g,FALSE);
614
void enqueue_neighbors(queue* q, node_t* n0, int pass)
620
for (i = 0; i < n0->u.out.size ; i++) {
621
e = n0->u.out.list[i];
622
if ((MARK(e->head)) == FALSE) {
623
MARK(e->head) = TRUE;
629
for (i = 0; i < n0->u.in.size ; i++) {
630
e = n0->u.in.list[i];
631
if ((MARK(e->tail)) == FALSE) {
632
MARK(e->tail) = TRUE;
639
/* construct nodes reachable from 'here' in post-order.
640
* This is the same as doing a topological sort in reverse order.
642
static int postorder(graph_t *g, node_t *v, node_t **list)
648
if (v->u.flat_out.size > 0) {
649
for (i = 0; (e = v->u.flat_out.list[i]); i++) {
650
if ((e->head->u.node_type == NORMAL) &
651
(NOT(agcontains(g,e->head)))) continue;
652
if (e->head->u.clust != e->tail->u.clust) continue;
654
if (MARK(e->head) == FALSE)
655
cnt += postorder(g,e->head,list+cnt);
662
static void flat_reorder(graph_t* g)
664
int i,j,r,pos,n_search,local_in_cnt, local_out_cnt;
665
node_t *v,**left,**right,*t;
666
node_t **temprank = NULL;
669
if (g->u.has_flat_edges == FALSE) return;
670
for (r = g->u.minrank; r <= g->u.maxrank; r++) {
671
for (i = 0; i < g->u.rank[r].n; i++) MARK(g->u.rank[r].v[i]) = FALSE;
672
temprank = ALLOC(i+1,temprank,node_t*);
674
for (i = 0; i < g->u.rank[r].n; i++) {
675
v = g->u.rank[r].v[i];
677
local_in_cnt = local_out_cnt = 0;
678
for (j = 0; j < v->u.flat_in.size; j++) {
679
flat_e = v->u.flat_in.list[j];
680
if (inside_cluster(g,flat_e->tail)) local_in_cnt++;
682
for (j = 0; j < v->u.flat_out.size; j++) {
683
flat_e = v->u.flat_out.list[j];
684
if (inside_cluster(g,flat_e->head)) local_out_cnt++;
686
if ((local_in_cnt == 0) && (local_out_cnt == 0))
689
if ((MARK(v) == FALSE) && (local_in_cnt == 0)) {
690
left = temprank + pos;
691
n_search = postorder(g,v,left);
692
if (g->u.left_to_right == FALSE) {
693
right = left + n_search - 1;
694
while (left < right) {
695
t = *left; *left = *right; *right = t;
703
for (i = 0; i < g->u.rank[r].n; i++){
704
v = g->u.rank[r].v[i] = temprank[i];
705
v->u.order = i + (g->u.rank[r].v - Root->u.rank[r].v);
707
g->u.rank[r].valid = FALSE;
709
if (temprank) free(temprank);
712
static void mincross_step(graph_t* g, int pass)
714
int r,other,first,last,dir;
715
int hasfixed,reverse;
717
if ((pass % 4) < 2) reverse = TRUE; else reverse = FALSE;
718
if (pass % 2) { r = g->u.maxrank - 1; dir = -1; } /* up pass */
719
else { r = 1; dir = 1; } /* down pass */
721
if (pass % 2 == 0) { /* down pass */
722
first = g->u.minrank + 1;
723
if (g->u.minrank > Root->u.minrank) first--;
728
first = g->u.maxrank - 1;
730
if (g->u.maxrank < Root->u.maxrank) first++;
734
for (r = first; r != last + dir; r += dir) {
736
hasfixed = medians(g,r,other);
737
reorder(g,r,reverse,hasfixed);
739
transpose(g,NOT(reverse));
742
void transpose(graph_t* g, int reverse)
746
for (r = g->u.minrank; r <= g->u.maxrank; r++)
747
g->u.rank[r].candidate = TRUE;
751
/* don't run both the upward and downward passes- they cancel.
752
i tried making it depend on whether an odd or even pass,
753
but that didn't help. */
754
for (r = g->u.maxrank; r >= g->u.minrank; r--)
755
if (g->u.rank[r].candidate) delta += transpose_step(g,r,reverse);
757
for (r = g->u.minrank; r <= g->u.maxrank; r++)
758
if (g->u.rank[r].candidate) delta += transpose_step(g,r,reverse);
759
/*} while (delta > ncross(g)*(1.0 - Convergence));*/
760
} while (delta >= 1);
763
int local_cross(elist l, int dir)
768
if (dir > 0) is_out = TRUE; else is_out = FALSE;
769
for (i = 0; (e = l.list[i]); i++) {
770
if (is_out) for (j = i+1; (f = l.list[j]); j++) {
771
if ((f->head->u.order - e->head->u.order) * (f->u.tail_port.p.x - e->u.tail_port.p.x) < 0)
772
cross += e->u.xpenalty * f->u.xpenalty;
774
else for (j = i+1; (f = l.list[j]); j++) {
775
if ((f->tail->u.order - e->tail->u.order) * (f->u.head_port.p.x - e->u.head_port.p.x) < 0)
776
cross += e->u.xpenalty * f->u.xpenalty;
782
int rcross(graph_t* g, int r)
785
int top,bot,cross,max,i,k;
790
rtop = g->u.rank[r].v;
792
if (C <= Root->u.rank[r+1].n) {
793
C = Root->u.rank[r+1].n + 1;
794
Count = ALLOC(C,Count,int);
797
for (i = 0; i < g->u.rank[r+1].n; i++) Count[i] = 0;
799
for (top = 0; top < g->u.rank[r].n; top++) {
802
for (i = 0; (e = rtop[top]->u.out.list[i]); i++) {
803
for (k = e->head->u.order + 1; k <= max; k++)
804
cross += Count[k] * e->u.xpenalty;
807
for (i = 0; (e = rtop[top]->u.out.list[i]); i++) {
808
register int inv = e->head->u.order;
809
if (inv > max) max = inv;
810
Count[inv] += e->u.xpenalty;
813
for (top = 0; top < g->u.rank[r].n; top++) {
814
v = g->u.rank[r].v[top];
815
if (v->u.has_port) cross += local_cross(v->u.out,1);
817
for (bot = 0; bot < g->u.rank[r+1].n; bot++) {
818
v = g->u.rank[r+1].v[bot];
819
if (v->u.has_port) cross += local_cross(v->u.in,-1);
824
int ncross(graph_t* g)
830
for (r = g->u.minrank; r < g->u.maxrank; r++) {
831
if (g->u.rank[r].valid) count += g->u.rank[r].cache_nc;
834
nc = g->u.rank[r].cache_nc = rcross(g,r);
836
g->u.rank[r].valid = TRUE;
842
int ordercmpf(int *i0, int *i1)
844
return (*i0) - (*i1);
847
int out_cross(node_t *v, node_t *w)
849
register edge_t **e1,**e2;
850
register int inv, cross = 0,t;
852
for (e2 = w->u.out.list; *e2; e2++) {
853
register int cnt = (*e2)->u.xpenalty;
854
inv = ((*e2)->head)->u.order;
856
for (e1 = v->u.out.list; *e1; e1++) {
857
t = ((*e1)->head)->u.order - inv;
859
|| ((t == 0) && ((*e1)->u.head_port.p.x > (*e2)->u.head_port.p.x)))
860
cross += (*e1)->u.xpenalty * cnt;
867
int in_cross(node_t *v,node_t *w)
869
register edge_t **e1,**e2;
870
register int inv, cross = 0, t;
872
for (e2 = w->u.in.list; *e2; e2++) {
873
register int cnt = (*e2)->u.xpenalty;
874
inv = ((*e2)->tail)->u.order;
876
for (e1 = v->u.in.list; *e1; e1++) {
877
t = ((*e1)->tail)->u.order - inv;
879
|| ((t == 0) && ((*e1)->u.tail_port.p.x > (*e2)->u.tail_port.p.x)))
880
cross += (*e1)->u.xpenalty * cnt;
886
#define VAL(node,port) (MC_SCALE * (node)->u.order + (port).order)
888
static boolean medians(graph_t *g, int r0, int r1)
890
int i,j,lm,rm,lspan,rspan,*list;
893
boolean hasfixed = FALSE;
897
for (i = 0; i < g->u.rank[r0].n; i++) {
899
if (r1 > r0) for (j = 0; (e = n->u.out.list[j]); j++)
900
list[j] = VAL(e->head,e->u.head_port);
901
else for (j = 0; (e = n->u.in.list[j]); j++)
902
list[j] = VAL(e->tail,e->u.tail_port);
911
n->u.mval = (list[0] + list[1])/2;
914
qsort(list,j,sizeof(int),(qsort_cmpf)ordercmpf);
915
if (j % 2) n->u.mval = list[j/2];
917
/* weighted median */
920
rspan = list[j-1] - list[rm];
921
lspan = list[lm] - list[0];
923
n->u.mval = (list[lm] + list[rm])/2;
925
int w = list[lm]*rspan + list[rm]*lspan;
926
n->u.mval = w / (lspan + rspan);
931
for (i = 0; i < g->u.rank[r0].n; i++) {
933
if ((n->u.out.size == 0) && (n->u.in.size == 0))
934
hasfixed |= flat_mval(n);
939
int transpose_step(graph_t* g, int r, int reverse)
945
g->u.rank[r].candidate = FALSE;
946
for (i = 0; i < g->u.rank[r].n - 1; i++) {
947
v = g->u.rank[r].v[i];
948
w = g->u.rank[r].v[i+1];
949
assert (v->u.order < w->u.order);
950
if (left2right(g,v,w)) continue;
956
if (g->u.rank[r+1].n > 0) {
957
c0 += out_cross(v,w);
958
c1 += out_cross(w,v);
960
if ((c1 < c0) || ((c0 > 0) && reverse && (c1 == c0))) {
963
g->u.rank[r].valid = FALSE;
964
g->u.rank[r].candidate = TRUE;
966
if (r > g->u.minrank) {
967
g->u.rank[r-1].valid = FALSE;
968
g->u.rank[r-1].candidate = TRUE;
970
if (r < g->u.maxrank) {
971
g->u.rank[r+1].valid = FALSE;
972
g->u.rank[r+1].candidate = TRUE;
979
void exchange(node_t *v, node_t *w)
987
Root->u.rank[r].v[wi] = v;
989
Root->u.rank[r].v[vi] = w;
992
void reorder(graph_t *g, int r, int reverse, int hasfixed)
994
int changed = 0, nelt;
995
boolean muststay,sawclust;
996
node_t **vlist = g->u.rank[r].v;
997
node_t **lp,**rp,**ep = vlist + g->u.rank[r].n;
999
for (nelt = g->u.rank[r].n - 1; nelt >= 0; nelt--) {
1002
/* find leftmost node that can be compared */
1003
while ((lp < ep) && ((*lp)->u.mval < 0)) lp++;
1004
if (lp >= ep) break;
1005
/* find the node that can be compared */
1006
sawclust = muststay = FALSE;
1007
for (rp = lp + 1; rp < ep; rp++) {
1008
if (sawclust && (*rp)->u.clust) continue; /* ### */
1009
if (left2right(g,*lp,*rp)) { muststay = TRUE; break; }
1010
if ((*rp)->u.mval >= 0) break;
1011
if ((*rp)->u.clust) sawclust = TRUE; /* ### */
1013
if (rp >= ep) break;
1014
if (muststay == FALSE) {
1015
register int p1 = ((*lp)->u.mval);
1016
register int p2 = ((*rp)->u.mval);
1017
if ((p1 > p2) || ((p1 == p2) && (reverse))) {
1024
if ((hasfixed == FALSE) && (reverse == FALSE)) ep--;
1028
g->u.rank[r].valid = FALSE;
1029
if (r > 0) g->u.rank[r-1].valid = FALSE;
1033
static int nodeposcmpf(node_t **n0, node_t **n1)
1035
return ((*n0)->u.order - (*n1)->u.order);
1038
static int edgeidcmpf(edge_t **e0, edge_t **e1)
1040
return ((*e0)->id - (*e1)->id);
1043
/* following code deals with weights of edges of "virtual" nodes */
1046
#define VIRTUALNODE 2
1054
static int table[NTYPES][NTYPES] = {
1055
/* ordinary */ {C_EE, C_EE, C_EE},
1056
/* singleton */ {C_EE, C_SS, C_VS},
1057
/* virtual */ {C_EE, C_VS, C_VV}
1060
static int endpoint_class(node_t* n)
1062
if (n->u.node_type == VIRTUAL) return VIRTUALNODE;
1063
if (n->u.weight_class <= 1) return SINGLETON;
1067
void virtual_weight(edge_t* e)
1070
t = table[endpoint_class(e->tail)][endpoint_class(e->head)];
1074
void ordered_edges(graph_t* g)
1078
ordering = agget(g,"ordering");
1079
if (ordering && streq(ordering,"out")) do_ordering(g);
1081
/* search meta-graph to find subgraphs that may be ordered */
1088
for (me = agfstout(mg,mm); me; me = agnxtout(mg,me)) {
1090
subg = agusergraph(mn);
1091
/* clusters are processed by seperate calls to ordered_edges */
1092
if (!is_cluster(subg)) ordered_edges(subg);
1097
/* creates flat edges for ordered edges of g.
1098
* follows virtual edge chains where necessary.
1100
void do_ordering(graph_t* g)
1102
int i,j,ri,ne,ei,nranks;
1103
node_t *n,**lpath,**rpath,*u,*v;
1104
edge_t *e,*f,*le,*re,**sortlist;
1107
lpath = rpath = NULL;
1109
nranks = g->root->u.maxrank - g->root->u.minrank + 2;
1110
lpath = N_NEW(nranks,node_t*); rpath = N_NEW(nranks,node_t*);
1112
for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
1113
if (n->u.clust) continue;
1116
/* make a list of the forward edges */
1117
for (ne = 0, e = agfstout(g,n); e; e = agnxtout(g,e)) {
1118
if (e->head->u.clust) continue;
1119
if (e->head->u.rank > e->tail->u.rank) sortlist[ne++] = e;
1122
if (ne == 0) continue;
1123
qsort(sortlist,ne,sizeof(sortlist[0]),(qsort_cmpf)edgeidcmpf);
1124
for (ei = 0; ei < ne; ei++) {
1126
for (re = e; re->u.to_virt; re = re->u.to_virt);
1128
/* get path of right edge */
1130
while (ri < nranks) {
1131
rpath[ri++] = re->head;
1132
if (re->head->u.node_type == NORMAL) break;
1133
if (re->head->u.out.size != 1) break;
1134
re = re->head->u.out.list[0];
1139
for (i = 0; i < ri; i++) {
1140
if (lpath[i] == NULL) break;
1141
u = lpath[i]; v = rpath[i];
1143
if ((u->u.node_type == NORMAL)
1144
&& (v->u.node_type == NORMAL)) {
1145
for (j = 0; (f = u->u.flat_out.list[j]); j++)
1146
if (f->head == v) break;
1148
if (f != NULL) break;
1149
f = new_virtual_edge(UF_find(lpath[i]),rpath[i],NULL);
1150
f->u.edge_type = FLATORDER;
1156
for (i = 0; i <= ri; i++) lpath[i] = rpath[i];
1159
if (lpath) { free(lpath); free(rpath); }
1162
/* merges the connected components of g */
1163
void merge_components(graph_t* g)
1168
if (g->u.comp.size <= 1) return;
1170
for (c = 0; c < g->u.comp.size; c++) {
1171
v = g->u.comp.list[c];
1172
if (u) u->u.next = v;
1180
g->u.nlist = g->u.comp.list[0];
1181
g->u.minrank = GlobalMinRank;
1182
g->u.maxrank = GlobalMaxRank;
1186
void check_rs(graph_t* g, int null_ok)
1191
fprintf(stderr,"\n\n%s:\n",g->name);
1192
for (r = g->u.minrank; r <= g->u.maxrank; r++) {
1193
fprintf(stderr,"%d: ",r);
1195
for (i = 0; i < g->u.rank[r].n; i++) {
1196
v = g->u.rank[r].v[i];
1198
fprintf(stderr,"NULL\t");
1199
if(null_ok==FALSE)abort();
1202
fprintf(stderr,"%s\t",v->name);
1203
assert(v->u.rank == r);
1208
fprintf(stderr,"\n");
1212
void check_order(void)
1218
for (r = g->u.minrank; r <= g->u.maxrank; r++) {
1219
assert(g->u.rank[r].v[g->u.rank[r].n] == NULL);
1220
for (i = 0; v = g->u.rank[r].v[i]; i++)
1221
assert (v->u.order == i);
1226
static void mincross_options(graph_t* g)
1231
/* set default values */
1236
p = agget(g,"mclimit");
1237
if (p && ((f = atof(p)) > 0.0)) {
1238
MinQuit = MAX(1,MinQuit * f);
1239
MaxIter = MAX(1,MaxIter * f);
1243
int flat_mval(node_t* n)
1249
if ((n->u.in.size == 0) && (n->u.out.size == 0)) {
1250
if (n->u.flat_in.size > 0) {
1251
fl = n->u.flat_in.list;
1253
for (i = 1; (e = fl[i]); i++)
1254
if (e->tail->u.order > nn->u.order) nn = e->tail;
1255
n->u.mval = nn->u.mval + 1;
1258
else if (n->u.flat_out.size > 0) {
1259
fl = n->u.flat_out.list;
1261
for (i = 1; (e = fl[i]); i++)
1262
if (e->head->u.order < nn->u.order) nn = e->head;
1263
n->u.mval = nn->u.mval - 1;
1271
void check_exchange(node_t *v, node_t *w)
1276
if ((v->u.clust == NULL) && (w->u.clust == NULL)) return;
1277
assert ((v->u.clust == NULL) || (w->u.clust == NULL));
1278
assert(v->u.rank == w->u.rank);
1279
assert(v->u.order < w->u.order);
1282
for (i = v->u.order + 1; i < w->u.order; i++) {
1283
u = v->graph->u.rank[r].v[i];
1284
if (u->u.clust) abort();
1288
void check_vlists(graph_t* g)
1293
for (r = g->u.minrank; r <= g->u.maxrank; r++) {
1294
for (i = 0; i < g->u.rank[r].n; i++) {
1295
u = g->u.rank[r].v[i];
1297
assert (Root->u.rank[r].v[j] == u);
1299
if (g->u.rankleader) {
1300
u = g->u.rankleader[r];
1302
assert (Root->u.rank[r].v[j] == u);
1305
for (c = 1; c <= g->u.n_cluster; c++)
1306
check_vlists(g->u.clust[c]);
1309
void node_in_root_vlist(node_t* n)
1313
for (vptr = Root->u.rank[n->u.rank].v; *vptr; vptr++)
1314
if (*vptr == n) break;
1315
if (*vptr == 0) abort();
1317
#endif /* DEBUG code */