52 const size_t index =
row * me->
ncols + col;
53 const size_t byte_index = index / 8;
54 const size_t bit_index = index % 8;
59 return (me->
data[byte_index] >> bit_index) & 1;
71 const size_t index =
row * me->
ncols + col;
72 const size_t byte_index = index / 8;
73 const size_t bit_index = index % 8;
80 me->
data[byte_index] |= (uint8_t)(UINT8_C(1) << bit_index);
84#define MARK(v) (ND_mark(v))
85#define saveorder(v) (ND_coord(v)).x
86#define flatindex(v) ((size_t)ND_low(v))
91static int edgeidcmpf(
const void *,
const void *);
109static int ordercmpf(
const void *,
const void *);
110static int64_t
ncross(ints_t *scratch);
112void check_rs(
graph_t * g,
int null_ok);
113void check_order(
void);
115void node_in_root_vlist(
node_t * n);
129#if defined(DEBUG) && DEBUG > 1
133 fprintf (stderr,
" ");
139static void nname(
node_t *v, FILE *stream) {
144 fprintf(stream,
"v_%p", v);
154 fprintf (stderr,
"digraph A {\n");
156 fprintf (stderr,
" subgraph {rank=same ");
157 for (i = 0; i <
GD_rank(g)[r].n; i++) {
160 fputs(
" -> ", stderr);
163 if (i > 1) fprintf (stderr,
" [style=invis]}\n");
164 else fprintf (stderr,
" }\n");
167 for (i = 0; i <
GD_rank(g)[r].n; i++) {
169 for (j = 0; (e =
ND_out(v).list[j]); j++) {
171 fputs(
" -> ", stderr);
177 fprintf (stderr,
"}\n");
179static void dumpr (
graph_t* g,
int edges)
186 fprintf (stderr,
"[%d] ", r);
187 for (i = 0; i <
GD_rank(g)[r].n; i++) {
192 fprintf (stderr,
"\n");
194 if (edges == 0)
return;
196 for (i = 0; i <
GD_rank(g)[r].n; i++) {
198 for (j = 0; (e =
ND_out(v).list[j]); j++) {
200 fputs(
" -> ", stderr);
215#define ND_x(n) (((info_t*)AGDATA(n))->x)
216#define ND_lo(n) (((info_t*)AGDATA(n))->lo)
217#define ND_hi(n) (((info_t*)AGDATA(n))->hi)
218#define ND_np(n) (((info_t*)AGDATA(n))->np)
219#define ND_idx(n) (ND_order(ND_np(n)))
233#define isBackedge(e) (ND_idx(aghead(e)) > ND_idx(agtail(e)))
241 if (
agdegree(g,n,1,0) == 0)
return n;
256 for (e =
agfstout(g, n); e; e = nxte) {
291 bool haveBackedge =
false;
309 if (!haveBackedge)
return;
311 sg =
agsubg(g,
"comp", 1);
317 if (
getComp(g, n, sg, indices)) {
322 for (i = 0; i < sz; i++) {
324 rk->
v[indices[i]] = arr[i];
353 for (j = 0; j < rk->
n; j++) {
404 ints_t scratch = {0};
407 for (nc = 0, comp = 0; comp <
GD_comp(g).size; comp++) {
409 const int64_t mc =
mincross(g, 0, &scratch);
436 const int64_t mc =
mincross(g, 2, &scratch);
495 for (i = ne = 0; (e =
ND_out(n).list[i]); i++)
499 for (i = ne = 0; (e =
ND_in(n).list[i]); i++)
508 qsort(sortlist, ne,
sizeof(sortlist[0]),
edgeidcmpf);
509 for (ne = 1; (f = sortlist[ne]); ne++) {
510 e = sortlist[ne - 1];
539 const char *ordering;
543 if (
streq(ordering,
"out"))
545 else if (
streq(ordering,
"in"))
547 else if (ordering[0])
548 agerrorf(
"ordering '%s' not recognized for node '%s'.\n", ordering,
agnameof(n));
566 if (
streq(ordering,
"out"))
568 else if (
streq(ordering,
"in"))
570 else if (ordering[0])
571 agerrorf(
"ordering '%s' not recognized.\n", ordering);
595 int64_t nc =
mincross(g, 2, scratch);
641 for (e2 =
ND_in(w).list; *e2; e2++) {
646 for (e1 =
ND_in(v).list; *e1; e1++) {
658 int inv,
cross = 0, t;
660 for (e2 =
ND_out(w).list; *e2; e2++) {
664 for (e1 =
ND_out(v).list; *e1; e1++) {
692 GD_rank(g)[r].candidate =
false;
693 for (i = 0; i <
GD_rank(g)[r].n - 1; i++) {
709 if (c1 < c0 || (c0 > 0 && reverse && c1 == c0)) {
713 GD_rank(g)[r].candidate =
true;
717 GD_rank(g)[r - 1].candidate =
true;
721 GD_rank(g)[r + 1].candidate =
true;
733 GD_rank(g)[r].candidate =
true;
742 }
while (
delta >= 1);
746 const int endpass = 2;
747 int maxthispass = 0, iter, trying, pass;
748 int64_t cur_cross, best_cross;
751 cur_cross = best_cross =
ncross(scratch);
754 cur_cross = best_cross = INT64_MAX;
755 for (pass = startpass; pass <= endpass; pass++) {
766 if ((cur_cross =
ncross(scratch)) <= best_cross) {
768 best_cross = cur_cross;
772 if (cur_cross > best_cross)
774 cur_cross = best_cross;
777 for (iter = 0; iter < maxthispass; iter++) {
780 "mincross: pass %d iter %d trying %d cur_cross %" PRId64
" best_cross %"
782 pass, iter, trying, cur_cross, best_cross);
788 if ((cur_cross =
ncross(scratch)) <= best_cross) {
792 best_cross = cur_cross;
798 if (cur_cross > best_cross)
800 if (best_cross > 0) {
802 best_cross =
ncross(scratch);
814 for (i = 0; i <
GD_rank(g)[r].n; i++) {
831 for (i = 0; i <
GD_rank(g)[r].n; i++) {
846 for (
size_t c = 0; c <
GD_comp(g).size; c++) {
875 for (i = 0; i <
GD_rank(g)[r].n; i++) {
880 "merge2: graph %s, rank %d has only %d < %d nodes\n",
909 for (i = 0; i <
GD_rank(g)[r].n; i++) {
925 fprintf(stderr,
"mincross %s: %" PRId64
" crossings, %.2f secs.\n",
1007 node_in_root_vlist(v);
1043 memset (rnks, 0,
sizeof(
int)*rnks_sz);
1074 int *rnks =
gv_calloc(rnks_sz,
sizeof(
int));
1173 for (i = 0; i <
GD_rank(g)[r].n; i++) {
1185 for (i = 0; i <
GD_rank(g)[r].n; i++) {
1212 for (r = low + 1; r < high; r++)
1231 agerrorf(
"install_in_rank, line %d: %s %s rank %d i = %d an = 0\n",
1251 agerrorf(
"install_in_rank, line %d: ND_order(%s) [%d] > GD_rank(Root)[%d].an [%d]\n",
1256 agerrorf(
"install_in_rank, line %d: rank %d not in rank range [%d,%d]\n",
1262 agerrorf(
"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",
1277 node_queue_t q = {0};
1285 for (i = 0; (e =
ND_out(n).list[i]); i++)
1287 for (i = 0; (e =
ND_in(n).list[i]); i++)
1296 const bool walkbackwards = g !=
agroot(g);
1299 if (walkbackwards) {
1307 otheredges = pass == 0 ?
ND_in(n).list :
ND_out(n).list;
1308 if (otheredges[0] !=
NULL)
1312 node_queue_push_back(&q, n);
1313 while (!node_queue_is_empty(&q)) {
1314 node_t *n0 = node_queue_pop_front(&q);
1317 node_queue_free(&q);
1324 node_queue_free(&q);
1331 assert(node_queue_is_empty(&q));
1336 int num_nodes_1 =
GD_rank(g)[i].n - 1;
1337 int half_num_nodes_1 = num_nodes_1 / 2;
1338 for (j = 0; j <= half_num_nodes_1; j++)
1339 exchange(vlist[j], vlist[num_nodes_1 - j]);
1345 node_queue_free(&q);
1353 for (
size_t i = 0; i <
ND_out(n0).size; i++) {
1357 node_queue_push_back(q,
aghead(e));
1361 for (
size_t i = 0; i <
ND_in(n0).size; i++) {
1362 e =
ND_in(n0).list[i];
1365 node_queue_push_back(q,
agtail(e));
1399 nodes_append(list, v);
1404 int i, r, local_in_cnt, local_out_cnt, base_order;
1406 nodes_t temprank = {0};
1412 if (
GD_rank(g)[r].n == 0)
continue;
1414 for (i = 0; i <
GD_rank(g)[r].n; i++)
1416 nodes_clear(&temprank);
1419 for (i = 0; i <
GD_rank(g)[r].n; i++) {
1423 local_in_cnt = local_out_cnt = 0;
1424 for (
size_t j = 0; j <
ND_flat_in(v).size; j++) {
1428 for (
size_t j = 0; j <
ND_flat_out(v).size; j++) {
1432 if (local_in_cnt == 0 && local_out_cnt == 0)
1433 nodes_append(&temprank, v);
1435 if (!
MARK(v) && local_in_cnt == 0) {
1441 if (nodes_size(&temprank) > 0) {
1443 nodes_reverse(&temprank);
1445 for (i = 0; i <
GD_rank(g)[r].n; i++) {
1446 v =
GD_rank(g)[r].v[i] = nodes_get(&temprank, (
size_t)i);
1451 for (i = 0; i <
GD_rank(g)[r].n; i++) {
1454 for (
size_t j = 0; (e =
ND_flat_out(v).list[j]); j++) {
1470 nodes_free(&temprank);
1475 int changed = 0, nelt;
1479 for (nelt =
GD_rank(g)[r].n - 1; nelt >= 0; nelt--) {
1483 while (lp < ep &&
ND_mval(*lp) < 0)
1488 bool sawclust =
false;
1489 bool muststay =
false;
1490 for (rp = lp + 1; rp < ep; rp++) {
1505 const double p1 =
ND_mval(*lp);
1506 const double p2 =
ND_mval(*rp);
1507 if (p1 > p2 || (p1 >= p2 && reverse)) {
1514 if (!hasfixed && !reverse)
1527 int r, other, first,
last, dir;
1529 bool reverse = pass % 4 < 2;
1531 if (pass % 2 == 0) {
1545 for (r = first; r !=
last + dir; r += dir) {
1547 bool hasfixed =
medians(g, r, other);
1548 reorder(g, r, reverse, hasfixed);
1558 bool is_out = dir > 0;
1559 for (i = 0; (e = l.
list[i]); i++) {
1561 for (j = i + 1; (f = l.
list[j]); j++) {
1566 for (j = i + 1; (f = l.
list[j]); j++) {
1576 int top, bot, max, i, k;
1589 for (i = 0; (e =
ND_out(rtop[
top]).list[i]); i++) {
1591 cross += ints_size(Count) <= (size_t)k
1596 for (i = 0; (e =
ND_out(rtop[
top]).list[i]); i++) {
1600 const size_t inv_z = (size_t)inv;
1601 if (ints_size(Count) <= inv_z) {
1602 ints_resize(Count, inv_z + 1, 0);
1604 ints_set(Count, inv_z, ints_get(Count, inv_z) +
ED_xpenalty(e));
1612 for (bot = 0; bot <
GD_rank(g)[r + 1].n; bot++) {
1621 assert(scratch !=
NULL);
1628 count +=
GD_rank(g)[r].cache_nc;
1630 const int64_t nc =
GD_rank(g)[r].cache_nc =
rcross(g, r, scratch);
1668 for (i = 1; (e = fl[i]); i++)
1678 for (i = 1; (e = fl[i]); i++)
1689#define VAL(node,port) (MC_SCALE * ND_order(node) + (port).order)
1693 int i, j0, lspan, rspan, *list;
1696 bool hasfixed =
false;
1700 for (i = 0; i <
GD_rank(g)[r0].n; i++) {
1704 for (j0 = 0; (e =
ND_out(n).list[j0]); j0++) {
1708 for (j0 = 0; (e =
ND_in(n).list[j0]); j0++) {
1720 ND_mval(n) = (list[0] + list[1]) / 2;
1730 rspan = list[j - 1] - list[
rm];
1731 lspan = list[lm] - list[0];
1735 double w = list[lm] * (double)rspan + list[
rm] * (
double)lspan;
1736 ND_mval(n) = w / (lspan + rspan);
1741 for (i = 0; i <
GD_rank(g)[r0].n; i++) {
1743 if ((
ND_out(n).size == 0) && (
ND_in(n).size == 0))
1754#pragma GCC diagnostic push
1755#pragma GCC diagnostic ignored "-Wcast-qual"
1760#pragma GCC diagnostic pop
1776#pragma GCC diagnostic push
1777#pragma GCC diagnostic ignored "-Wcast-qual"
1782#pragma GCC diagnostic pop
1796#define VIRTUALNODE 2
1827 agerrorf(
"overflow when calculating virtual weight of edge\n");
1835void check_rs(
graph_t * g,
int null_ok)
1840 fprintf(stderr,
"\n\n%s:\n",
agnameof(g));
1842 fprintf(stderr,
"%d: ", r);
1844 for (i = 0; i <
GD_rank(g)[r].n; i++) {
1847 fprintf(stderr,
"NULL\t");
1857 fprintf(stderr,
"\n");
1861void check_order(
void)
1869 for (i = 0; (v =
GD_rank(g)[r].v[i]); i++) {
1886 p =
agget(g,
"mclimit");
1887 if (p && (f = atof(p)) > 0.0) {
1919 for (i = 0; i <
GD_rank(g)[r].n; i++) {
1934void node_in_root_vlist(
node_t * n)
static agxbuf last
last message
Memory allocation wrappers that exit on failure.
static void * gv_recalloc(void *ptr, size_t old_nmemb, size_t new_nmemb, size_t size)
static void * gv_calloc(size_t nmemb, size_t size)
static void * gv_alloc(size_t size)
abstract graph C library, Cgraph API
#define exchange(h, i, j)
bool mapbool(const char *p)
char * late_string(void *obj, attrsym_t *attr, char *defaultValue)
void decompose(graph_t *g, int pass)
Agraph_t * dot_root(void *p)
bool is_cluster(Agraph_t *)
void flat_edge(Agraph_t *, Agedge_t *)
void merge_oneway(Agedge_t *, Agedge_t *)
Agedge_t * new_virtual_edge(Agnode_t *, Agnode_t *, Agedge_t *)
Agedge_t * find_flat_edge(Agnode_t *, Agnode_t *)
void delete_flat_edge(Agedge_t *)
static NORETURN void graphviz_exit(int status)
static int cnt(Dict_t *d, Dtlink_t **set)
int agnedges(Agraph_t *g)
int agdegree(Agraph_t *g, Agnode_t *n, int in, int out)
int agnnodes(Agraph_t *g)
char * agget(void *obj, char *name)
Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
int agdeledge(Agraph_t *g, Agedge_t *arg_e)
Agedge_t * agnxtin(Agraph_t *g, Agedge_t *e)
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Agedge_t * agfstin(Agraph_t *g, Agnode_t *n)
void agwarningf(const char *fmt,...)
void agerrorf(const char *fmt,...)
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
#define GD_has_flat_edges(g)
Agdesc_t Agstrictdirected
strict directed. A strict graph cannot have multi-edges or self-arcs.
Agraph_t * agopen(char *name, Agdesc_t desc, Agdisc_t *disc)
creates a new graph with the given name and kind
Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Agnode_t * agfstnode(Agraph_t *g)
Agnode_t * agsubnode(Agraph_t *g, Agnode_t *n, int createflag)
int agdelnode(Agraph_t *g, Agnode_t *arg_n)
removes a node from a graph or subgraph.
#define ND_weight_class(n)
char * agnameof(void *)
returns a string descriptor for the object.
int agcontains(Agraph_t *, void *obj)
returns non-zero if obj is a member of (sub)graph
Agraph_t * agroot(void *obj)
void * agbindrec(void *obj, const char *name, unsigned int recsize, int move_to_front)
attaches a new record of the given size to the object
Agraph_t * agfstsubg(Agraph_t *g)
Agraph_t * agnxtsubg(Agraph_t *subg)
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
static void indent(int ix)
Arithmetic helper functions.
static int scale_clamp(int original, double scale)
scale up or down a non-negative integer, clamping to [0, INT_MAX]
static double cross(double *u, double *v)
static Agedge_t * top(edge_stack_t *sp)
int install_cluster(graph_t *g, node_t *n, int pass, node_queue_t *q)
int expand_cluster(graph_t *subg)
void mark_lowclusters(Agraph_t *root)
#define DEFINE_LIST(name, type)
#define neighbor(t, i, edim, elist)
static int betweenclust(edge_t *e)
int build_ranks(graph_t *g, int pass, ints_t *scratch)
static void free_matrix(adjmatrix_t *p)
static bool flat_mval(node_t *n)
static int64_t mincross(graph_t *g, int startpass, ints_t *scratch)
static bool inside_cluster(graph_t *g, node_t *v)
static int64_t rcross(graph_t *g, int r, ints_t *Count)
static void init_mccomp(graph_t *g, size_t c)
static void mincross_step(graph_t *g, int pass)
static int topsort(Agraph_t *g, Agraph_t *sg, Agnode_t **arr)
static bool medians(graph_t *g, int r0, int r1)
static void reorder(graph_t *g, int r, bool reverse, bool hasfixed)
static int edgeidcmpf(const void *, const void *)
static void flat_breakcycles(graph_t *g)
static void cleanup2(graph_t *g, int64_t nc)
static bool is_a_normal_node_of(graph_t *g, node_t *v)
static void save_best(graph_t *g)
static void init_mincross(graph_t *g)
static int64_t transpose_step(graph_t *g, int r, bool reverse)
static void fixLabelOrder(graph_t *g, rank_t *rk)
for each pair of nodes (labels), we add an edge
void virtual_weight(edge_t *e)
static void merge2(graph_t *g)
static node_t * furthestnode(graph_t *g, node_t *v, int dir)
static int out_cross(node_t *v, node_t *w)
static int ordercmpf(const void *, const void *)
void enqueue_neighbors(node_queue_t *q, node_t *n0, int pass)
static void do_ordering(graph_t *g, bool outflag)
static void matrix_set(adjmatrix_t *me, size_t row, size_t col)
void checkLabelOrder(graph_t *g)
static int64_t mincross_clust(graph_t *g, ints_t *scratch)
static const double Convergence
static adjmatrix_t * new_matrix(size_t i, size_t j)
static Agraph_t * realFillRanks(Agraph_t *g, int rnks[], int rnks_sz, Agraph_t *sg)
static Agnode_t * findSource(Agraph_t *g, Agraph_t *sg)
void rec_save_vlists(graph_t *g)
static void do_ordering_node(graph_t *g, node_t *n, bool outflag)
static int64_t in_cross(node_t *v, node_t *w)
static void flat_search(graph_t *g, node_t *v)
static int64_t ncross(ints_t *scratch)
static void ordered_edges(graph_t *g)
static void transpose(graph_t *g, bool reverse)
void rec_reset_vlists(graph_t *g)
static void merge_components(graph_t *g)
int dot_mincross(graph_t *g)
static void mincross_options(graph_t *g)
static int endpoint_class(node_t *n)
static int getComp(graph_t *g, node_t *n, graph_t *comp, int *indices)
static bool left2right(graph_t *g, node_t *v, node_t *w)
static int local_cross(elist l, int dir)
static void flat_reorder(graph_t *g)
static void flat_rev(Agraph_t *g, Agedge_t *e)
static void emptyComp(graph_t *sg)
static bool is_a_vnode_of_an_edge_of(graph_t *g, node_t *v)
static void fillRanks(Agraph_t *g)
static void do_ordering_for_nodes(graph_t *g)
static void postorder(graph_t *g, node_t *v, nodes_t *list, int r)
void allocate_ranks(graph_t *g)
static int table[NTYPES][NTYPES]
static void restore_best(graph_t *g)
static bool matrix_get(adjmatrix_t *me, size_t row, size_t col)
static bool constraining_flat_edge(Agraph_t *g, Agedge_t *e)
static int nodeposcmpf(const void *, const void *)
void save_vlist(graph_t *g)
int install_in_rank(graph_t *g, node_t *n)
static bool streq(const char *a, const char *b)
are a and b equal?
Agrec_t * data
stores programmer-defined data, access with AGDATA
implementation of Agrec_t
uint8_t * data
bit-packed backing memory
size_t allocated
how many bytes have been allocated backing data?
#define elist_append(item, L)
#define alloc_elist(n, L)