25 #define MARK(v) (ND_mark(v))
26 #define saveorder(v) (ND_coord(v)).x
27 #define flatindex(v) ND_low(v)
30 static boolean medians(
graph_t * g,
int r0,
int r1);
33 static void flat_breakcycles(
graph_t * g);
34 static void flat_reorder(
graph_t * g);
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);
41 static int mincross(
graph_t * g,
int startpass,
int endpass,
int);
42 static void mincross_step(
graph_t * g,
int pass);
43 static void mincross_options(
graph_t * g);
44 static void save_best(
graph_t * g);
45 static void restore_best(
graph_t * g);
48 static int ordercmpf(
int *i0,
int *i1);
56 void check_rs(
graph_t * g,
int null_ok);
57 void check_order(
void);
59 void node_in_root_vlist(
node_t * n);
65 static double Convergence;
68 static int GlobalMinRank, GlobalMaxRank;
71 static boolean ReMincross;
77 fprintf (stderr,
" ");
82 static char* nname(
node_t* v)
84 static char buf[1000];
89 sprintf (buf,
"v_%p", v);
100 fprintf (stderr,
"digraph A {\n");
102 fprintf (stderr,
" subgraph {rank=same ");
103 for (i = 0; i <
GD_rank(g)[r].n; i++) {
106 fprintf (stderr,
" -> %s", nname(v));
108 fprintf (stderr,
"%s", nname(v));
110 if (i > 1) fprintf (stderr,
" [style=invis]}\n");
111 else fprintf (stderr,
" }\n");
114 for (i = 0; i <
GD_rank(g)[r].n; i++) {
116 for (j = 0; (e =
ND_out(v).list[j]); j++) {
117 fprintf (stderr,
"%s -> ", nname(v));
118 fprintf (stderr,
"%s\n", nname(
aghead(e)));
122 fprintf (stderr,
"}\n");
124 static void dumpr (
graph_t* g,
int edges)
131 fprintf (stderr,
"[%d] ", r);
132 for (i = 0; i <
GD_rank(g)[r].n; i++) {
136 fprintf (stderr,
"\n");
138 if (edges == 0)
return;
140 for (i = 0; i <
GD_rank(g)[r].n; i++) {
142 for (j = 0; (e =
ND_out(v).list[j]); j++) {
143 fprintf (stderr,
"%s -> ", nname(v));
144 fprintf (stderr,
"%s\n", nname(
aghead(e)));
157 #define ND_x(n) (((info_t*)AGDATA(n))->x)
158 #define ND_lo(n) (((info_t*)AGDATA(n))->lo)
159 #define ND_hi(n) (((info_t*)AGDATA(n))->hi)
160 #define ND_np(n) (((info_t*)AGDATA(n))->np)
161 #define ND_idx(n) (ND_order(ND_np(n)))
175 #define isBackedge(e) (ND_idx(aghead(e)) > ND_idx(agtail(e)))
183 if (
agdegree(g,n,1,0) == 0)
return n;
195 while ((n = findSource(g, sg))) {
196 arr[cnt++] =
ND_np(n);
198 for (e =
agfstout(g, n); e; e = nxte) {
218 backedge += getComp(g,
aghead(e), comp, indices);
223 backedge += getComp(g,
agtail(e), comp, indices);
234 int cnt, haveBackedge =
FALSE;
254 if (!haveBackedge)
return;
256 sg =
agsubg(g,
"comp", 1);
262 if (getComp(g, n, sg, indices)) {
264 cnt = topsort (g, sg, arr);
266 qsort(indices, cnt,
sizeof(
int), (
qsort_cmpf)ordercmpf);
267 for (i = 0; i < sz; i++) {
269 rk->
v[indices[i]] = arr[i];
299 for (j = 0; j < rk->
n; j++) {
303 sprintf (buf,
"%d", j);
320 if (
agnnodes(lg) > 1) fixLabelOrder (lg, rk);
339 for (nc = c = 0; c <
GD_comp(g).size; c++) {
341 nc += mincross(g, 0, 2, doBalance);
348 nc += mincross_clust(g,
GD_clust(g)[c], doBalance);
359 nc = mincross(g, 2, 2, doBalance);
385 #define ELT(M,i,j) (M->data[((i)*M->ncols)+(j)])
387 static void init_mccomp(
graph_t * g,
int c)
400 static int betweenclust(
edge_t * e)
407 static void do_ordering_node (
graph_t * g,
node_t* n,
int outflag)
412 edge_t **sortlist = TE_list;
417 for (i = ne = 0; (e =
ND_out(n).list[i]); i++)
418 if (!betweenclust(e))
421 for (i = ne = 0; (e =
ND_in(n).list[i]); i++)
422 if (!betweenclust(e))
430 qsort(sortlist, ne,
sizeof(sortlist[0]), (
qsort_cmpf) edgeidcmpf);
431 for (ne = 1; (f = sortlist[ne]); ne++) {
432 e = sortlist[ne - 1];
448 static void do_ordering(
graph_t * g,
int outflag)
454 do_ordering_node (g, n, outflag);
458 static void do_ordering_for_nodes(
graph_t * g)
462 const char *ordering;
466 if (
streq(ordering,
"out"))
467 do_ordering_node(g, n,
TRUE);
468 else if (
streq(ordering,
"in"))
469 do_ordering_node(g, n,
FALSE);
470 else if (ordering[0])
483 static void ordered_edges(
graph_t * g)
490 if (
streq(ordering,
"out"))
491 do_ordering(g,
TRUE);
492 else if (
streq(ordering,
"in"))
493 do_ordering(g,
FALSE);
494 else if (ordering[0])
495 agerr(
AGERR,
"ordering '%s' not recognized.\n", ordering);
510 static int mincross_clust(
graph_t * par,
graph_t * g,
int doBalance)
518 nc = mincross(g, 2, 2, doBalance);
521 nc += mincross_clust(g,
GD_clust(g)[c], doBalance);
533 if (ReMincross ==
FALSE) {
565 register edge_t **e1, **e2;
566 register int inv, cross = 0, t;
568 for (e2 =
ND_in(w).list; *e2; e2++) {
573 for (e1 =
ND_in(v).list; *e1; e1++) {
586 register edge_t **e1, **e2;
587 register int inv, cross = 0, t;
589 for (e2 =
ND_out(w).list; *e2; e2++) {
593 for (e1 =
ND_out(v).list; *e1; e1++) {
623 int cntDummy = 0, cntOri = 0;
624 int k = 0, m = 0, k1 = 0, m1 = 0, i = 0;
631 for (i = 0; i <
GD_rank(g)[r].n; i++) {
638 if (cntOri < cntDummy) {
651 for (i = 0; i <
GD_rank(g)[r].n; i++) {
661 for (i = sepIndex - 1; i >= 0; i--) {
668 for (i = sepIndex + 1; i <
GD_rank(g)[r].n; i++) {
680 for (i = 0; i <
GD_rank(g)[r].n; i++) {
688 for (i = sepIndex - 1; i >= 0; i--) {
695 for (i = sepIndex + 1; i <
GD_rank(g)[r].n; i++) {
702 if (abs(k1 - m1) > abs(k - m)) {
707 static int balance(
graph_t * g)
718 for (i = 0; i <
GD_rank(g)[r].n - 1; i++) {
722 if (left2right(g, v, w))
726 c0 += in_cross(v, w);
727 c1 += in_cross(w, v);
731 c0 += out_cross(v, w);
732 c1 += out_cross(w, v);
735 if ((c1 < c0) || ((c0 > 0) && reverse && (c1 == c0))) {
753 balanceNodes(g, r, v, w);
760 static int transpose_step(
graph_t * g,
int r,
int reverse)
767 for (i = 0; i <
GD_rank(g)[r].n - 1; i++) {
771 if (left2right(g, v, w))
775 c0 += in_cross(v, w);
776 c1 += in_cross(w, v);
779 c0 += out_cross(v, w);
780 c1 += out_cross(w, v);
782 if ((c1 < c0) || ((c0 > 0) && reverse && (c1 == c0))) {
801 static void transpose(
graph_t * g,
int reverse)
815 delta += transpose_step(g, r, reverse);
819 delta += transpose_step(g, r, reverse);
823 }
while (delta >= 1);
826 static int mincross(
graph_t * g,
int startpass,
int endpass,
int doBalance)
828 int maxthispass, iter, trying, pass;
829 int cur_cross, best_cross;
832 cur_cross = best_cross =
ncross(g);
835 cur_cross = best_cross =
INT_MAX;
836 for (pass = startpass; pass <= endpass; pass++) {
845 if ((cur_cross =
ncross(g)) <= best_cross) {
847 best_cross = cur_cross;
852 if (cur_cross > best_cross)
854 cur_cross = best_cross;
857 for (iter = 0; iter < maxthispass; iter++) {
860 "mincross: pass %d iter %d trying %d cur_cross %d best_cross %d\n",
861 pass, iter, trying, cur_cross, best_cross);
862 if (trying++ >= MinQuit)
866 mincross_step(g, iter);
867 if ((cur_cross =
ncross(g)) <= best_cross) {
869 if (cur_cross < Convergence * best_cross)
871 best_cross = cur_cross;
877 if (cur_cross > best_cross)
879 if (best_cross > 0) {
884 for (iter = 0; iter < maxthispass; iter++)
891 static void restore_best(
graph_t * g)
899 for (i = 0; i <
GD_rank(g)[r].n; i++) {
911 static void save_best(
graph_t * g)
918 for (i = 0; i <
GD_rank(g)[r].n; i++) {
926 static void merge_components(
graph_t * g)
934 for (c = 0; c <
GD_comp(g).size; c++) {
951 static void merge2(
graph_t * g)
963 for (i = 0; i <
GD_rank(g)[r].n; i++) {
968 "merge2: graph %s, rank %d has only %d < %d nodes\n",
978 static void cleanup2(
graph_t * g,
int nc)
998 for (i = 0; i <
GD_rank(g)[r].n; i++) {
1011 free_matrix(
GD_rank(g)[r].flat);
1014 fprintf(stderr,
"mincross %s: %d crossings, %.2f secs.\n",
1038 static int is_a_vnode_of_an_edge_of(
graph_t * g,
node_t * v)
1041 && (
ND_in(v).size == 1) && (
ND_out(v).size == 1)) {
1053 return (is_a_normal_node_of(g, v) | is_a_vnode_of_an_edge_of(g, v));
1061 while ((u = neighbor(u, dir))) {
1062 if (is_a_normal_node_of(g, u))
1064 else if (is_a_vnode_of_an_edge_of(g, u))
1103 node_in_root_vlist(v);
1105 u = furthestnode(g, v, -1);
1106 w = furthestnode(g, v, 1);
1136 sg = realFillRanks (
GD_clust(g)[c], rnks, rnks_sz, sg);
1140 memset (rnks, 0,
sizeof(
int)*rnks_sz);
1172 int* rnks =
N_NEW(rnks_sz,
int);
1173 sg = realFillRanks (g, rnks, rnks_sz,
NULL);
1177 static void init_mincross(
graph_t * g)
1191 TI_list =
N_NEW(size,
int);
1192 mincross_options(g);
1264 flat_search(g,
aghead(e));
1270 static void flat_breakcycles(
graph_t * g)
1277 for (i = 0; i <
GD_rank(g)[r].n; i++) {
1288 for (i = 0; i <
GD_rank(g)[r].n; i++) {
1303 int r, low, high, *cn;
1318 for (r = low + 1; r < high; r++)
1338 agerr(
AGERR,
"install_in_rank, line %d: %s %s rank %d i = %d an = 0\n",
1358 agerr(
AGERR,
"install_in_rank, line %d: ND_order(%s) [%d] > GD_rank(Root)[%d].an [%d]\n",
1363 agerr(
AGERR,
"install_in_rank, line %d: rank %d not in rank range [%d,%d]\n",
1369 agerr(
AGERR,
"install_in_rank, line %d: GD_rank(g)[%d].v + ND_order(%s) [%d] > GD_rank(g)[%d].av + GD_rank(Root)[%d].an [%d]\n",
1394 for (i = 0; (e =
ND_out(n).list[i]); i++)
1396 for (i = 0; (e =
ND_in(n).list[i]); i++)
1406 otheredges = ((pass == 0) ?
ND_in(n).list :
ND_out(n).list);
1407 if (otheredges[0] !=
NULL)
1431 for (j = 0; j <= ndiv2; j++)
1437 transpose(g,
FALSE);
1447 for (i = 0; i <
ND_out(n0).size; i++) {
1455 for (i = 0; i <
ND_in(n0).size; i++) {
1456 e =
ND_in(n0).list[i];
1485 if (!constraining_flat_edge(g,v,e))
continue;
1487 cnt += postorder(g,
aghead(e), list + cnt, r);
1495 static void flat_reorder(
graph_t * g)
1497 int i, j, r, pos, n_search, local_in_cnt, local_out_cnt, base_order;
1505 if (
GD_rank(g)[r].n == 0)
continue;
1507 for (i = 0; i <
GD_rank(g)[r].n; i++)
1513 for (i = 0; i <
GD_rank(g)[r].n; i++) {
1517 local_in_cnt = local_out_cnt = 0;
1520 if (constraining_flat_edge(g,v,flat_e)) local_in_cnt++;
1524 if (constraining_flat_edge(g,v,flat_e)) local_out_cnt++;
1526 if ((local_in_cnt == 0) && (local_out_cnt == 0))
1527 temprank[pos++] = v;
1529 if ((
MARK(v) ==
FALSE) && (local_in_cnt == 0)) {
1530 left = temprank + pos;
1531 n_search = postorder(g, v, left, r);
1540 right = temprank + pos - 1;
1541 while (left < right) {
1549 for (i = 0; i <
GD_rank(g)[r].n; i++) {
1550 v =
GD_rank(g)[r].v[i] = temprank[i];
1555 for (i = 0; i <
GD_rank(g)[r].n; i++) {
1578 static void reorder(
graph_t * g,
int r,
int reverse,
int hasfixed)
1580 int changed = 0, nelt;
1581 boolean muststay, sawclust;
1585 for (nelt =
GD_rank(g)[r].n - 1; nelt >= 0; nelt--) {
1589 while ((lp < ep) && (
ND_mval(*lp) < 0))
1594 sawclust = muststay =
FALSE;
1595 for (rp = lp + 1; rp < ep; rp++) {
1598 if (left2right(g, *lp, *rp)) {
1609 if (muststay ==
FALSE) {
1610 register int p1 = (
ND_mval(*lp));
1611 register int p2 = (
ND_mval(*rp));
1612 if ((p1 > p2) || ((p1 == p2) && (reverse))) {
1619 if ((hasfixed ==
FALSE) && (reverse ==
FALSE))
1630 static void mincross_step(
graph_t * g,
int pass)
1632 int r, other, first, last, dir;
1633 int hasfixed, reverse;
1648 if (pass % 2 == 0) {
1662 for (r = first; r != last + dir; r += dir) {
1664 hasfixed = medians(g, r, other);
1665 reorder(g, r, reverse, hasfixed);
1667 transpose(g,
NOT(reverse));
1670 static int local_cross(
elist l,
int dir)
1679 for (i = 0; (e = l.
list[i]); i++) {
1681 for (j = i + 1; (f = l.
list[j]); j++) {
1686 for (j = i + 1; (f = l.
list[j]); j++) {
1695 static int rcross(
graph_t * g,
int r)
1697 static int *Count,
C;
1698 int top, bot, cross,
max, i, k;
1705 if (C <=
GD_rank(Root)[r + 1].n) {
1706 C =
GD_rank(Root)[r + 1].n + 1;
1707 Count =
ALLOC(C, Count,
int);
1710 for (i = 0; i <
GD_rank(g)[r + 1].n; i++)
1713 for (top = 0; top <
GD_rank(g)[r].n; top++) {
1716 for (i = 0; (e =
ND_out(rtop[top]).list[i]); i++) {
1721 for (i = 0; (e =
ND_out(rtop[top]).list[i]); i++) {
1728 for (top = 0; top <
GD_rank(g)[r].n; top++) {
1731 cross += local_cross(
ND_out(v), 1);
1733 for (bot = 0; bot <
GD_rank(g)[r + 1].n; bot++) {
1736 cross += local_cross(
ND_in(v), -1);
1749 count +=
GD_rank(g)[r].cache_nc;
1751 nc =
GD_rank(g)[r].cache_nc = rcross(g, r);
1759 static int ordercmpf(
int *i0,
int *i1)
1761 return (*i0) - (*i1);
1774 static int flat_mval(
node_t * n)
1783 for (i = 1; (e = fl[i]); i++)
1793 for (i = 1; (e = fl[i]); i++)
1804 #define VAL(node,port) (MC_SCALE * ND_order(node) + (port).order)
1806 static boolean medians(
graph_t * g,
int r0,
int r1)
1808 int i, j, j0, lm,
rm, lspan, rspan, *list;
1811 boolean hasfixed =
FALSE;
1815 for (i = 0; i <
GD_rank(g)[r0].n; i++) {
1819 for (j0 = 0; (e =
ND_out(n).list[j0]); j0++) {
1823 for (j0 = 0; (e =
ND_in(n).list[j0]); j0++) {
1835 ND_mval(n) = (list[0] + list[1]) / 2;
1838 qsort(list, j,
sizeof(
int), (
qsort_cmpf) ordercmpf);
1845 rspan = list[j - 1] - list[
rm];
1846 lspan = list[lm] - list[0];
1850 int w = list[lm] * rspan + list[
rm] * lspan;
1851 ND_mval(n) = w / (lspan + rspan);
1856 for (i = 0; i <
GD_rank(g)[r0].n; i++) {
1858 if ((
ND_out(n).size == 0) && (
ND_in(n).size == 0))
1859 hasfixed |= flat_mval(n);
1877 #define VIRTUALNODE 2
1891 static int endpoint_class(
node_t * n)
1903 t = table[endpoint_class(
agtail(e))][endpoint_class(
aghead(e))];
1908 void check_rs(
graph_t * g,
int null_ok)
1913 fprintf(stderr,
"\n\n%s:\n",
agnameof(g));
1915 fprintf(stderr,
"%d: ", r);
1917 for (i = 0; i <
GD_rank(g)[r].n; i++) {
1920 fprintf(stderr,
"NULL\t");
1921 if (null_ok ==
FALSE)
1930 fprintf(stderr,
"\n");
1934 void check_order(
void)
1942 for (i = 0; (v =
GD_rank(g)[r].v[i]); i++) {
1950 static void mincross_options(
graph_t * g)
1960 p =
agget(g,
"mclimit");
1961 if (p && ((f = atof(p)) > 0.0)) {
1962 MinQuit =
MAX(1, MinQuit * f);
1987 void check_vlists(
graph_t * g)
1993 for (i = 0; i <
GD_rank(g)[r].n; i++) {
2008 void node_in_root_vlist(
node_t * n)
CGRAPH_API int agdeledge(Agraph_t *g, Agedge_t *arg_e)
CGRAPH_API Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
CGRAPH_API Agraph_t * agopen(char *name, Agdesc_t desc, Agdisc_t *disc)
#define elist_append(item, L)
CGRAPH_API int agdegree(Agraph_t *g, Agnode_t *n, int in, int out)
CGRAPH_API int agdelnode(Agraph_t *g, Agnode_t *arg_n)
Agedge_t * find_flat_edge(Agnode_t *, Agnode_t *)
#define exchange(h, i, j)
CGRAPH_API Agedge_t * agfstin(Agraph_t *g, Agnode_t *n)
#define ALLOC(size, ptr, type)
void rec_reset_vlists(Agraph_t *)
void decompose(graph_t *g, int pass)
EXTERN Agsym_t * G_ordering
void checkLabelOrder(graph_t *g)
#define GD_has_flat_edges(g)
void build_ranks(Agraph_t *, int)
void delete_flat_edge(Agedge_t *)
#define alloc_elist(n, L)
int agerr(agerrlevel_t level, const char *fmt,...)
CGRAPH_API Agraph_t * agfstsubg(Agraph_t *g)
CGRAPH_API int agcontains(Agraph_t *, void *)
CGRAPH_API Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
void enqueue(nodequeue *q, node_t *n)
void allocate_ranks(Agraph_t *)
int is_cluster(Agraph_t *)
char * agget(void *obj, char *name)
CGRAPH_API Agraph_t * agnxtsubg(Agraph_t *subg)
CGRAPH_API Agnode_t * agtail(Agedge_t *e)
nodequeue * new_queue(int sz)
CGRAPH_API Agdesc_t Agstrictdirected
CGRAPH_API Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
CGRAPH_API Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
CGRAPH_API Agnode_t * aghead(Agedge_t *e)
CGRAPH_API int agclose(Agraph_t *g)
CGRAPH_API char * agnameof(void *)
void mark_lowclusters(Agraph_t *root)
void flat_rev(Agraph_t *g, Agedge_t *e)
void merge_oneway(Agedge_t *, Agedge_t *)
int(* qsort_cmpf)(const void *, const void *)
node_t * dequeue(nodequeue *q)
CGRAPH_API Agnode_t * agfstnode(Agraph_t *g)
Agraph_t * dot_root(void *p)
void rec_save_vlists(Agraph_t *)
void free_queue(nodequeue *q)
void flat_edge(Agraph_t *, Agedge_t *)
Agedge_t * new_virtual_edge(Agnode_t *, Agnode_t *, Agedge_t *)
void save_vlist(Agraph_t *)
EXTERN unsigned char Verbose
CGRAPH_API int agnnodes(Agraph_t *g)
CGRAPH_API Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
EXTERN Agsym_t * N_ordering
CGRAPH_API void * agbindrec(void *obj, char *name, unsigned int size, int move_to_front)
void install_in_rank(Agraph_t *, Agnode_t *)
CGRAPH_API Agedge_t * agnxtin(Agraph_t *g, Agedge_t *e)
void virtual_weight(Agedge_t *)
char * late_string(void *obj, attrsym_t *attr, char *def)
#define ND_weight_class(n)
CGRAPH_API int agnedges(Agraph_t *g)
void enqueue_neighbors(nodequeue *q, node_t *n0, int pass)
CGRAPH_API Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
void expand_cluster(graph_t *subg)
CGRAPH_API Agnode_t * agsubnode(Agraph_t *g, Agnode_t *n, int createflag)
void dot_mincross(Agraph_t *, int)
void install_cluster(graph_t *g, node_t *n, int pass, nodequeue *q)