Graphviz 13.0.0~dev.20241220.2304
Loading...
Searching...
No Matches
mincross.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11
12/*
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.
17 */
18
19#include <assert.h>
20#include <cgraph/cgraph.h>
21#include <cgraph/list.h>
22#include <dotgen/dot.h>
23#include <inttypes.h>
24#include <limits.h>
25#include <stdbool.h>
26#include <stdint.h>
27#include <stdlib.h>
28#include <string.h>
29#include <util/agxbuf.h>
30#include <util/alloc.h>
31#include <util/exit.h>
32#include <util/gv_math.h>
33#include <util/streq.h>
34
36 size_t nrows;
37 size_t ncols;
38 char *data;
39};
40
41/* #define DEBUG */
42#define MARK(v) (ND_mark(v))
43#define saveorder(v) (ND_coord(v)).x
44#define flatindex(v) ((size_t)ND_low(v))
45
46 /* forward declarations */
47static bool medians(graph_t * g, int r0, int r1);
48static int nodeposcmpf(const void *, const void *);
49static int edgeidcmpf(const void *, const void *);
50static void flat_breakcycles(graph_t * g);
51static void flat_reorder(graph_t * g);
52static void flat_search(graph_t * g, node_t * v);
53static void init_mincross(graph_t * g);
54static void merge2(graph_t * g);
55static void init_mccomp(graph_t *g, size_t c);
56static void cleanup2(graph_t *g, int64_t nc);
57static int64_t mincross_clust(graph_t *g, ints_t *scratch);
58static int64_t mincross(graph_t *g, int startpass, ints_t *scratch);
59static void mincross_step(graph_t * g, int pass);
60static void mincross_options(graph_t * g);
61static void save_best(graph_t * g);
62static void restore_best(graph_t * g);
63static adjmatrix_t *new_matrix(size_t i, size_t j);
64static void free_matrix(adjmatrix_t * p);
65static int ordercmpf(const void *, const void *);
66static int64_t ncross(ints_t *scratch);
67#ifdef DEBUG
68#if DEBUG > 1
69static int gd_minrank(Agraph_t *g) {return GD_minrank(g);}
70static int gd_maxrank(Agraph_t *g) {return GD_maxrank(g);}
71static rank_t *gd_rank(Agraph_t *g, int r) {return &GD_rank(g)[r];}
72static int nd_order(Agnode_t *v) { return ND_order(v); }
73#endif
74void check_rs(graph_t * g, int null_ok);
75void check_order(void);
76void check_vlists(graph_t * g);
77void node_in_root_vlist(node_t * n);
78#endif
79
80
81 /* mincross parameters */
82static int MinQuit;
83static const double Convergence = .995;
84
85static graph_t *Root;
87static edge_t **TE_list;
88static int *TI_list;
89static bool ReMincross;
90
91#if defined(DEBUG) && DEBUG > 1
92static void indent(graph_t* g)
93{
94 if (g->parent) {
95 fprintf (stderr, " ");
96 indent(g->parent);
97 }
98}
99
100static char* nname(node_t* v)
101{
102 static char buf[1000];
103 if (ND_node_type(v)) {
104 if (ND_ranktype(v) == CLUSTER)
105 snprintf(buf, sizeof(buf), "v%s_%p", agnameof(ND_clust(v)), v);
106 else
107 snprintf(buf, sizeof(buf), "v_%p", v);
108 } else
109 snprintf(buf, sizeof(buf), "%s", agnameof(v));
110 return buf;
111}
112static void dumpg (graph_t* g)
113{
114 int j, i, r;
115 node_t* v;
116 edge_t* e;
117
118 fprintf (stderr, "digraph A {\n");
119 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
120 fprintf (stderr, " subgraph {rank=same ");
121 for (i = 0; i < GD_rank(g)[r].n; i++) {
122 v = GD_rank(g)[r].v[i];
123 if (i > 0)
124 fprintf (stderr, " -> %s", nname(v));
125 else
126 fprintf (stderr, "%s", nname(v));
127 }
128 if (i > 1) fprintf (stderr, " [style=invis]}\n");
129 else fprintf (stderr, " }\n");
130 }
131 for (r = GD_minrank(g); r < GD_maxrank(g); r++) {
132 for (i = 0; i < GD_rank(g)[r].n; i++) {
133 v = GD_rank(g)[r].v[i];
134 for (j = 0; (e = ND_out(v).list[j]); j++) {
135 fprintf (stderr, "%s -> ", nname(v));
136 fprintf (stderr, "%s\n", nname(aghead(e)));
137 }
138 }
139 }
140 fprintf (stderr, "}\n");
141}
142static void dumpr (graph_t* g, int edges)
143{
144 int j, i, r;
145 node_t* v;
146 edge_t* e;
147
148 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
149 fprintf (stderr, "[%d] ", r);
150 for (i = 0; i < GD_rank(g)[r].n; i++) {
151 v = GD_rank(g)[r].v[i];
152 fprintf (stderr, "%s(%.02f,%d) ", nname(v), saveorder(v),ND_order(v));
153 }
154 fprintf (stderr, "\n");
155 }
156 if (edges == 0) return;
157 for (r = GD_minrank(g); r < GD_maxrank(g); r++) {
158 for (i = 0; i < GD_rank(g)[r].n; i++) {
159 v = GD_rank(g)[r].v[i];
160 for (j = 0; (e = ND_out(v).list[j]); j++) {
161 fprintf (stderr, "%s -> ", nname(v));
162 fprintf (stderr, "%s\n", nname(aghead(e)));
163 }
164 }
165 }
166}
167#endif
168
169typedef struct {
171 int x, lo, hi;
173} info_t;
174
175#define ND_x(n) (((info_t*)AGDATA(n))->x)
176#define ND_lo(n) (((info_t*)AGDATA(n))->lo)
177#define ND_hi(n) (((info_t*)AGDATA(n))->hi)
178#define ND_np(n) (((info_t*)AGDATA(n))->np)
179#define ND_idx(n) (ND_order(ND_np(n)))
180
181static void
183{
184 Agnode_t* n;
185 Agnode_t* nxt;
186
187 for (n = agfstnode(sg); n; n = nxt) {
188 nxt = agnxtnode (sg, n);
189 agdelnode(sg,n);
190 }
191}
192
193#define isBackedge(e) (ND_idx(aghead(e)) > ND_idx(agtail(e)))
194
195static Agnode_t*
197{
198 Agnode_t* n;
199
200 for (n = agfstnode(sg); n; n = agnxtnode(sg, n))
201 if (agdegree(g,n,1,0) == 0) return n;
202 return NULL;
203}
204
205static int
207{
208 Agnode_t* n;
209 Agedge_t* e;
210 Agedge_t* nxte;
211 int cnt = 0;
212
213 while ((n = findSource(g, sg))) {
214 arr[cnt++] = ND_np(n);
215 agdelnode(sg, n);
216 for (e = agfstout(g, n); e; e = nxte) {
217 nxte = agnxtout(g, e);
218 agdeledge(g, e);
219 }
220 }
221 return cnt;
222}
223
224static int
225getComp (graph_t* g, node_t* n, graph_t* comp, int* indices)
226{
227 int backedge = 0;
228 Agedge_t* e;
229
230 ND_x(n) = 1;
231 indices[agnnodes(comp)] = ND_idx(n);
232 agsubnode(comp, n, 1);
233 for (e = agfstout(g,n); e; e = agnxtout(g,e)) {
234 if (isBackedge(e)) backedge++;
235 if (!ND_x(aghead(e)))
236 backedge += getComp(g, aghead(e), comp, indices);
237 }
238 for (e = agfstin(g,n); e; e = agnxtin(g,e)) {
239 if (isBackedge(e)) backedge++;
240 if (!ND_x(agtail(e)))
241 backedge += getComp(g, agtail(e), comp, indices);
242 }
243 return backedge;
244}
245
246/* fixLabelOrder:
247 * For each pair of nodes (labels), we add an edge
248 */
249static void
251{
252 int cnt;
253 bool haveBackedge = false;
254 Agraph_t* sg;
255 Agnode_t* n;
256 Agnode_t* nxtp;
257 Agnode_t* v;
258
259 for (n = agfstnode(g); n; n = nxtp) {
260 v = nxtp = agnxtnode(g, n);
261 for (; v; v = agnxtnode(g, v)) {
262 if (ND_hi(v) <= ND_lo(n)) {
263 haveBackedge = true;
264 agedge(g, v, n, NULL, 1);
265 }
266 else if (ND_hi(n) <= ND_lo(v)) {
267 agedge(g, n, v, NULL, 1);
268 }
269 }
270 }
271 if (!haveBackedge) return;
272
273 sg = agsubg(g, "comp", 1);
274 Agnode_t **arr = gv_calloc(agnnodes(g), sizeof(Agnode_t*));
275 int *indices = gv_calloc(agnnodes(g), sizeof(int));
276
277 for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
278 if (ND_x(n) || agdegree(g,n,1,1) == 0) continue;
279 if (getComp(g, n, sg, indices)) {
280 int i, sz = agnnodes(sg);
281 cnt = topsort (g, sg, arr);
282 assert (cnt == sz);
283 qsort(indices, cnt, sizeof(int), ordercmpf);
284 for (i = 0; i < sz; i++) {
285 ND_order(arr[i]) = indices[i];
286 rk->v[indices[i]] = arr[i];
287 }
288 }
289 emptyComp(sg);
290 }
291 free(indices);
292 free (arr);
293}
294
295/* checkLabelOrder:
296 * Check that the ordering of labels for flat edges is consistent.
297 * This is necessary because dot_position will attempt to force the label
298 * to be between the edge's vertices. This can lead to an infeasible problem.
299 *
300 * We check each rank for any flat edge labels (as dummy nodes) and create a
301 * graph with a node for each label. If the graph contains more than 1 node, we
302 * call fixLabelOrder to see if there really is a problem and, if so, fix it.
303 */
304void
306{
307 int j, r, lo, hi;
308 graph_t* lg = NULL;
309 agxbuf buf = {0};
310 rank_t* rk;
311 Agnode_t* u;
312 Agnode_t* n;
313 Agedge_t* e;
314
315 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
316 rk = GD_rank(g)+r;
317 for (j = 0; j < rk->n; j++) {
318 u = rk->v[j];
319 if ((e = ND_alg(u))) {
320 if (!lg) lg = agopen ("lg", Agstrictdirected, 0);
321 agxbprint(&buf, "%d", j);
322 n = agnode(lg, agxbuse(&buf), 1);
323 agbindrec(n, "info", sizeof(info_t), true);
324 lo = ND_order(aghead(ND_out(u).list[0]));
325 hi = ND_order(aghead(ND_out(u).list[1]));
326 if (lo > hi) {
327 int tmp;
328 tmp = lo;
329 lo = hi;
330 hi = tmp;
331 }
332 ND_lo(n) = lo;
333 ND_hi(n) = hi;
334 ND_np(n) = u;
335 }
336 }
337 if (lg) {
338 if (agnnodes(lg) > 1) fixLabelOrder (lg, rk);
339 agclose(lg);
340 lg = NULL;
341 }
342 }
343 agxbfree(&buf);
344}
345
346/* dot_mincross:
347 * Minimize edge crossings
348 * Note that nodes are not placed into GD_rank(g) until mincross()
349 * is called.
350 */
352 int64_t nc;
353 char *s;
354
355 /* check whether malformed input has led to empty cluster that the crossing
356 * functions will not anticipate
357 */
358 {
359 size_t i;
360 for (i = 1; i <= (size_t)GD_n_cluster(g); ) {
361 if (agfstnode(GD_clust(g)[i]) == NULL) {
362 agwarningf("removing empty cluster\n");
363 memmove(&GD_clust(g)[i], &GD_clust(g)[i + 1],
364 ((size_t)GD_n_cluster(g) - i) * sizeof(GD_clust(g)[0]));
365 --GD_n_cluster(g);
366 } else {
367 ++i;
368 }
369 }
370 }
371
372 init_mincross(g);
373
374 ints_t scratch = {0};
375
376 size_t comp;
377 for (nc = 0, comp = 0; comp < GD_comp(g).size; comp++) {
378 init_mccomp(g, comp);
379 nc += mincross(g, 0, &scratch);
380 }
381
382 merge2(g);
383
384 /* run mincross on contents of each cluster */
385 for (int c = 1; c <= GD_n_cluster(g); c++) {
386 nc += mincross_clust(GD_clust(g)[c], &scratch);
387#ifdef DEBUG
388 check_vlists(GD_clust(g)[c]);
389 check_order();
390#endif
391 }
392
393 if (GD_n_cluster(g) > 0 && (!(s = agget(g, "remincross")) || mapbool(s))) {
395 ReMincross = true;
396 nc = mincross(g, 2, &scratch);
397#ifdef DEBUG
398 for (int c = 1; c <= GD_n_cluster(g); c++)
399 check_vlists(GD_clust(g)[c]);
400#endif
401 }
402 ints_free(&scratch);
403 cleanup2(g, nc);
404}
405
406static adjmatrix_t *new_matrix(size_t i, size_t j) {
407 adjmatrix_t *rv = gv_alloc(sizeof(adjmatrix_t));
408 rv->nrows = i;
409 rv->ncols = j;
410 rv->data = gv_calloc(i * j, sizeof(char));
411 return rv;
412}
413
414static void free_matrix(adjmatrix_t * p)
415{
416 if (p) {
417 free(p->data);
418 free(p);
419 }
420}
421
422#define ELT(M,i,j) (M->data[((i)*M->ncols)+(j)])
423
424static void init_mccomp(graph_t *g, size_t c) {
425 int r;
426
427 GD_nlist(g) = GD_comp(g).list[c];
428 if (c > 0) {
429 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
430 GD_rank(g)[r].v = GD_rank(g)[r].v + GD_rank(g)[r].n;
431 GD_rank(g)[r].n = 0;
432 }
433 }
434}
435
436static int betweenclust(edge_t * e)
437{
438 while (ED_to_orig(e))
439 e = ED_to_orig(e);
440 return (ND_clust(agtail(e)) != ND_clust(aghead(e)));
441}
442
443static void do_ordering_node(graph_t *g, node_t *n, bool outflag) {
444 int i, ne;
445 node_t *u, *v;
446 edge_t *e, *f, *fe;
447 edge_t **sortlist = TE_list;
448
449 if (ND_clust(n))
450 return;
451 if (outflag) {
452 for (i = ne = 0; (e = ND_out(n).list[i]); i++)
453 if (!betweenclust(e))
454 sortlist[ne++] = e;
455 } else {
456 for (i = ne = 0; (e = ND_in(n).list[i]); i++)
457 if (!betweenclust(e))
458 sortlist[ne++] = e;
459 }
460 if (ne <= 1)
461 return;
462 /* write null terminator at end of list.
463 requires +1 in TE_list alloccation */
464 sortlist[ne] = 0;
465 qsort(sortlist, ne, sizeof(sortlist[0]), edgeidcmpf);
466 for (ne = 1; (f = sortlist[ne]); ne++) {
467 e = sortlist[ne - 1];
468 if (outflag) {
469 u = aghead(e);
470 v = aghead(f);
471 } else {
472 u = agtail(e);
473 v = agtail(f);
474 }
475 if (find_flat_edge(u, v))
476 return;
477 fe = new_virtual_edge(u, v, NULL);
479 flat_edge(g, fe);
480 }
481}
482
483static void do_ordering(graph_t *g, bool outflag) {
484 /* Order all nodes in graph */
485 node_t *n;
486
487 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
488 do_ordering_node (g, n, outflag);
489 }
490}
491
493{
494 /* Order nodes which have the "ordered" attribute */
495 node_t *n;
496 const char *ordering;
497
498 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
499 if ((ordering = late_string(n, N_ordering, NULL))) {
500 if (streq(ordering, "out"))
501 do_ordering_node(g, n, true);
502 else if (streq(ordering, "in"))
503 do_ordering_node(g, n, false);
504 else if (ordering[0])
505 agerrorf("ordering '%s' not recognized for node '%s'.\n", ordering, agnameof(n));
506 }
507 }
508}
509
510/* ordered_edges:
511 * handle case where graph specifies edge ordering
512 * If the graph does not have an ordering attribute, we then
513 * check for nodes having the attribute.
514 * Note that, in this implementation, the value of G_ordering
515 * dominates the value of N_ordering.
516 */
517static void ordered_edges(graph_t * g)
518{
519 char *ordering;
520
521 if (!G_ordering && !N_ordering)
522 return;
523 if ((ordering = late_string(g, G_ordering, NULL))) {
524 if (streq(ordering, "out"))
525 do_ordering(g, true);
526 else if (streq(ordering, "in"))
527 do_ordering(g, false);
528 else if (ordering[0])
529 agerrorf("ordering '%s' not recognized.\n", ordering);
530 }
531 else
532 {
533 graph_t *subg;
534
535 for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
536 /* clusters are processed by separate calls to ordered_edges */
537 if (!is_cluster(subg))
538 ordered_edges(subg);
539 }
541 }
542}
543
544static int64_t mincross_clust(graph_t *g, ints_t *scratch) {
545 int c;
546
548 ordered_edges(g);
550 flat_reorder(g);
551 int64_t nc = mincross(g, 2, scratch);
552
553 for (c = 1; c <= GD_n_cluster(g); c++)
554 nc += mincross_clust(GD_clust(g)[c], scratch);
555
556 save_vlist(g);
557 return nc;
558}
559
560static bool left2right(graph_t *g, node_t *v, node_t *w) {
561 adjmatrix_t *M;
562
563 /* CLUSTER indicates orig nodes of clusters, and vnodes of skeletons */
564 if (!ReMincross) {
565 if (ND_clust(v) != ND_clust(w) && ND_clust(v) && ND_clust(w)) {
566 /* the following allows cluster skeletons to be swapped */
567 if (ND_ranktype(v) == CLUSTER && ND_node_type(v) == VIRTUAL)
568 return false;
569 if (ND_ranktype(w) == CLUSTER && ND_node_type(w) == VIRTUAL)
570 return false;
571 return true;
572 }
573 } else {
574 if (ND_clust(v) != ND_clust(w))
575 return true;
576 }
577 M = GD_rank(g)[ND_rank(v)].flat;
578 if (M == NULL)
579 return false;
580 if (GD_flip(g)) {
581 node_t *t = v;
582 v = w;
583 w = t;
584 }
585 return ELT(M, flatindex(v), flatindex(w)) != 0;
586}
587
588static int64_t in_cross(node_t *v, node_t *w) {
589 edge_t **e1, **e2;
590 int inv, t;
591 int64_t cross = 0;
592
593 for (e2 = ND_in(w).list; *e2; e2++) {
594 int cnt = ED_xpenalty(*e2);
595
596 inv = ND_order(agtail(*e2));
597
598 for (e1 = ND_in(v).list; *e1; e1++) {
599 t = ND_order(agtail(*e1)) - inv;
600 if (t > 0 || (t == 0 && ED_tail_port(*e1).p.x > ED_tail_port(*e2).p.x))
601 cross += ED_xpenalty(*e1) * cnt;
602 }
603 }
604 return cross;
605}
606
607static int out_cross(node_t * v, node_t * w)
608{
609 edge_t **e1, **e2;
610 int inv, cross = 0, t;
611
612 for (e2 = ND_out(w).list; *e2; e2++) {
613 int cnt = ED_xpenalty(*e2);
614 inv = ND_order(aghead(*e2));
615
616 for (e1 = ND_out(v).list; *e1; e1++) {
617 t = ND_order(aghead(*e1)) - inv;
618 if (t > 0 || (t == 0 && (ED_head_port(*e1)).p.x > (ED_head_port(*e2)).p.x))
619 cross += ED_xpenalty(*e1) * cnt;
620 }
621 }
622 return cross;
623
624}
625
626static void exchange(node_t * v, node_t * w)
627{
628 int vi, wi, r;
629
630 r = ND_rank(v);
631 vi = ND_order(v);
632 wi = ND_order(w);
633 ND_order(v) = wi;
634 GD_rank(Root)[r].v[wi] = v;
635 ND_order(w) = vi;
636 GD_rank(Root)[r].v[vi] = w;
637}
638
639static int64_t transpose_step(graph_t *g, int r, bool reverse) {
640 int i;
641 node_t *v, *w;
642
643 int64_t rv = 0;
644 GD_rank(g)[r].candidate = false;
645 for (i = 0; i < GD_rank(g)[r].n - 1; i++) {
646 v = GD_rank(g)[r].v[i];
647 w = GD_rank(g)[r].v[i + 1];
648 assert(ND_order(v) < ND_order(w));
649 if (left2right(g, v, w))
650 continue;
651 int64_t c0 = 0;
652 int64_t c1 = 0;
653 if (r > 0) {
654 c0 += in_cross(v, w);
655 c1 += in_cross(w, v);
656 }
657 if (GD_rank(g)[r + 1].n > 0) {
658 c0 += out_cross(v, w);
659 c1 += out_cross(w, v);
660 }
661 if (c1 < c0 || (c0 > 0 && reverse && c1 == c0)) {
662 exchange(v, w);
663 rv += c0 - c1;
664 GD_rank(Root)[r].valid = false;
665 GD_rank(g)[r].candidate = true;
666
667 if (r > GD_minrank(g)) {
668 GD_rank(Root)[r - 1].valid = false;
669 GD_rank(g)[r - 1].candidate = true;
670 }
671 if (r < GD_maxrank(g)) {
672 GD_rank(Root)[r + 1].valid = false;
673 GD_rank(g)[r + 1].candidate = true;
674 }
675 }
676 }
677 return rv;
678}
679
680static void transpose(graph_t * g, bool reverse)
681{
682 int r;
683
684 for (r = GD_minrank(g); r <= GD_maxrank(g); r++)
685 GD_rank(g)[r].candidate = true;
686 int64_t delta;
687 do {
688 delta = 0;
689 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
690 if (GD_rank(g)[r].candidate) {
691 delta += transpose_step(g, r, reverse);
692 }
693 }
694 } while (delta >= 1);
695}
696
697static int64_t mincross(graph_t *g, int startpass, ints_t *scratch) {
698 const int endpass = 2;
699 int maxthispass = 0, iter, trying, pass;
700 int64_t cur_cross, best_cross;
701
702 if (startpass > 1) {
703 cur_cross = best_cross = ncross(scratch);
704 save_best(g);
705 } else
706 cur_cross = best_cross = INT64_MAX;
707 for (pass = startpass; pass <= endpass; pass++) {
708 if (pass <= 1) {
709 maxthispass = MIN(4, MaxIter);
710 if (g == dot_root(g))
711 build_ranks(g, pass, scratch);
712 if (pass == 0)
714 flat_reorder(g);
715
716 if ((cur_cross = ncross(scratch)) <= best_cross) {
717 save_best(g);
718 best_cross = cur_cross;
719 }
720 } else {
721 maxthispass = MaxIter;
722 if (cur_cross > best_cross)
723 restore_best(g);
724 cur_cross = best_cross;
725 }
726 trying = 0;
727 for (iter = 0; iter < maxthispass; iter++) {
728 if (Verbose)
729 fprintf(stderr,
730 "mincross: pass %d iter %d trying %d cur_cross %" PRId64 " best_cross %"
731 PRId64 "\n",
732 pass, iter, trying, cur_cross, best_cross);
733 if (trying++ >= MinQuit)
734 break;
735 if (cur_cross == 0)
736 break;
737 mincross_step(g, iter);
738 if ((cur_cross = ncross(scratch)) <= best_cross) {
739 save_best(g);
740 if (cur_cross < Convergence * (double)best_cross)
741 trying = 0;
742 best_cross = cur_cross;
743 }
744 }
745 if (cur_cross == 0)
746 break;
747 }
748 if (cur_cross > best_cross)
749 restore_best(g);
750 if (best_cross > 0) {
751 transpose(g, false);
752 best_cross = ncross(scratch);
753 }
754
755 return best_cross;
756}
757
758static void restore_best(graph_t * g)
759{
760 node_t *n;
761 int i, r;
762
763 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
764 for (i = 0; i < GD_rank(g)[r].n; i++) {
765 n = GD_rank(g)[r].v[i];
766 ND_order(n) = saveorder(n);
767 }
768 }
769 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
770 GD_rank(Root)[r].valid = false;
771 qsort(GD_rank(g)[r].v, GD_rank(g)[r].n, sizeof(GD_rank(g)[0].v[0]),
773 }
774}
775
776static void save_best(graph_t * g)
777{
778 node_t *n;
779 int i, r;
780 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
781 for (i = 0; i < GD_rank(g)[r].n; i++) {
782 n = GD_rank(g)[r].v[i];
783 saveorder(n) = ND_order(n);
784 }
785 }
786}
787
788/* merges the connected components of g */
789static void merge_components(graph_t * g)
790{
791 node_t *u, *v;
792
793 if (GD_comp(g).size <= 1)
794 return;
795 u = NULL;
796 for (size_t c = 0; c < GD_comp(g).size; c++) {
797 v = GD_comp(g).list[c];
798 if (u)
799 ND_next(u) = v;
800 ND_prev(v) = u;
801 while (ND_next(v)) {
802 v = ND_next(v);
803 }
804 u = v;
805 }
806 GD_comp(g).size = 1;
807 GD_nlist(g) = GD_comp(g).list[0];
810}
811
812/* merge connected components, create globally consistent rank lists */
813static void merge2(graph_t * g)
814{
815 int i, r;
816 node_t *v;
817
818 /* merge the components and rank limits */
820
821 /* install complete ranks */
822 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
823 GD_rank(g)[r].n = GD_rank(g)[r].an;
824 GD_rank(g)[r].v = GD_rank(g)[r].av;
825 for (i = 0; i < GD_rank(g)[r].n; i++) {
826 v = GD_rank(g)[r].v[i];
827 if (v == NULL) {
828 if (Verbose)
829 fprintf(stderr,
830 "merge2: graph %s, rank %d has only %d < %d nodes\n",
831 agnameof(g), r, i, GD_rank(g)[r].n);
832 GD_rank(g)[r].n = i;
833 break;
834 }
835 ND_order(v) = i;
836 }
837 }
838}
839
840static void cleanup2(graph_t *g, int64_t nc) {
841 int i, j, r, c;
842 node_t *v;
843 edge_t *e;
844
845 if (TI_list) {
846 free(TI_list);
847 TI_list = NULL;
848 }
849 if (TE_list) {
850 free(TE_list);
851 TE_list = NULL;
852 }
853 /* fix vlists of clusters */
854 for (c = 1; c <= GD_n_cluster(g); c++)
856
857 /* remove node temporary edges for ordering nodes */
858 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
859 for (i = 0; i < GD_rank(g)[r].n; i++) {
860 v = GD_rank(g)[r].v[i];
861 ND_order(v) = i;
862 if (ND_flat_out(v).list) {
863 for (j = 0; (e = ND_flat_out(v).list[j]); j++)
864 if (ED_edge_type(e) == FLATORDER) {
866 free(e->base.data);
867 free(e);
868 j--;
869 }
870 }
871 }
872 free_matrix(GD_rank(g)[r].flat);
873 }
874 if (Verbose)
875 fprintf(stderr, "mincross %s: %" PRId64 " crossings, %.2f secs.\n",
876 agnameof(g), nc, elapsed_sec());
877}
878
879static node_t *neighbor(node_t * v, int dir)
880{
881 node_t *rv;
882
883 rv = NULL;
884assert(v);
885 if (dir < 0) {
886 if (ND_order(v) > 0)
887 rv = GD_rank(Root)[ND_rank(v)].v[ND_order(v) - 1];
888 } else
889 rv = GD_rank(Root)[ND_rank(v)].v[ND_order(v) + 1];
890assert((rv == 0) || (ND_order(rv)-ND_order(v))*dir > 0);
891 return rv;
892}
893
894static bool is_a_normal_node_of(graph_t *g, node_t *v) {
895 return ND_node_type(v) == NORMAL && agcontains(g, v);
896}
897
899 if (ND_node_type(v) == VIRTUAL
900 && ND_in(v).size == 1 && ND_out(v).size == 1) {
901 edge_t *e = ND_out(v).list[0];
902 while (ED_edge_type(e) != NORMAL)
903 e = ED_to_orig(e);
904 if (agcontains(g, e))
905 return true;
906 }
907 return false;
908}
909
910static bool inside_cluster(graph_t *g, node_t *v) {
911 return is_a_normal_node_of(g, v) || is_a_vnode_of_an_edge_of(g, v);
912}
913
914static node_t *furthestnode(graph_t * g, node_t * v, int dir)
915{
916 node_t *u, *rv;
917
918 rv = u = v;
919 while ((u = neighbor(u, dir))) {
920 if (is_a_normal_node_of(g, u))
921 rv = u;
922 else if (is_a_vnode_of_an_edge_of(g, u))
923 rv = u;
924 }
925 return rv;
926}
927
929{
930 int r;
931
932 if (GD_rankleader(g))
933 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
934 GD_rankleader(g)[r] = GD_rank(g)[r].v[0];
935 }
936}
937
939{
940 int c;
941
942 save_vlist(g);
943 for (c = 1; c <= GD_n_cluster(g); c++)
945}
946
947
949{
950 int r, c;
951 node_t *u, *v, *w;
952
953 /* fix vlists of sub-clusters */
954 for (c = 1; c <= GD_n_cluster(g); c++)
956
957 if (GD_rankleader(g))
958 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
959 v = GD_rankleader(g)[r];
960#ifdef DEBUG
961 node_in_root_vlist(v);
962#endif
963 u = furthestnode(g, v, -1);
964 w = furthestnode(g, v, 1);
965 GD_rankleader(g)[r] = u;
966#ifdef DEBUG
967 assert(GD_rank(dot_root(g))[r].v[ND_order(u)] == u);
968#endif
969 GD_rank(g)[r].v = GD_rank(dot_root(g))[r].v + ND_order(u);
970 GD_rank(g)[r].n = ND_order(w) - ND_order(u) + 1;
971 }
972}
973
974/* realFillRanks:
975 * The structures in crossing minimization and positioning require
976 * that clusters have some node on each rank. This function recursively
977 * guarantees this property. It takes into account nodes and edges in
978 * a cluster, the latter causing dummy nodes for intervening ranks.
979 * For any rank without node, we create a real node of small size. This
980 * is stored in the subgraph sg, for easy removal later.
981 *
982 * I believe it is not necessary to do this for the root graph, as these
983 * are laid out one component at a time and these will necessarily have a
984 * node on each rank from source to sink levels.
985 */
986static Agraph_t*
987realFillRanks (Agraph_t* g, int rnks[], int rnks_sz, Agraph_t* sg)
988{
989 int i, c;
990 Agedge_t* e;
991 Agnode_t* n;
992
993 for (c = 1; c <= GD_n_cluster(g); c++)
994 sg = realFillRanks (GD_clust(g)[c], rnks, rnks_sz, sg);
995
996 if (dot_root(g) == g)
997 return sg;
998 memset (rnks, 0, sizeof(int)*rnks_sz);
999 for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
1000 rnks[ND_rank(n)] = 1;
1001 for (e = agfstout(g,n); e; e = agnxtout(g,e)) {
1002 for (i = ND_rank(n)+1; i <= ND_rank(aghead(e)); i++)
1003 rnks[i] = 1;
1004 }
1005 }
1006 for (i = GD_minrank(g); i <= GD_maxrank(g); i++) {
1007 if (rnks[i] == 0) {
1008 if (!sg) {
1009 sg = agsubg (dot_root(g), "_new_rank", 1);
1010 }
1011 n = agnode (sg, NULL, 1);
1012 agbindrec(n, "Agnodeinfo_t", sizeof(Agnodeinfo_t), true);
1013 ND_rank(n) = i;
1014 ND_lw(n) = ND_rw(n) = 0.5;
1015 ND_ht(n) = 1;
1016 ND_UF_size(n) = 1;
1017 alloc_elist(4, ND_in(n));
1018 alloc_elist(4, ND_out(n));
1019 agsubnode (g, n, 1);
1020 }
1021 }
1022 return sg;
1023}
1024
1025static void
1027{
1028 int rnks_sz = GD_maxrank(g) + 2;
1029 int *rnks = gv_calloc(rnks_sz, sizeof(int));
1030 realFillRanks (g, rnks, rnks_sz, NULL);
1031 free (rnks);
1032}
1033
1034static void init_mincross(graph_t * g)
1035{
1036 int size;
1037
1038 if (Verbose)
1039 start_timer();
1040
1041 ReMincross = false;
1042 Root = g;
1043 /* alloc +1 for the null terminator usage in do_ordering() */
1044 size = agnedges(dot_root(g)) + 1;
1045 TE_list = gv_calloc(size, sizeof(edge_t*));
1046 TI_list = gv_calloc(size, sizeof(int));
1048 if (GD_flags(g) & NEW_RANK)
1049 fillRanks (g);
1050 class2(g);
1051 decompose(g, 1);
1052 allocate_ranks(g);
1053 ordered_edges(g);
1056}
1057
1058static void flat_rev(Agraph_t * g, Agedge_t * e)
1059{
1060 int j;
1061 Agedge_t *rev;
1062
1063 if (!ND_flat_out(aghead(e)).list)
1064 rev = NULL;
1065 else
1066 for (j = 0; (rev = ND_flat_out(aghead(e)).list[j]); j++)
1067 if (aghead(rev) == agtail(e))
1068 break;
1069 if (rev) {
1070 merge_oneway(e, rev);
1071 if (ED_edge_type(rev) == FLATORDER && ED_to_orig(rev) == 0)
1072 ED_to_orig(rev) = e;
1074 } else {
1075 rev = new_virtual_edge(aghead(e), agtail(e), e);
1076 if (ED_edge_type(e) == FLATORDER)
1077 ED_edge_type(rev) = FLATORDER;
1078 else
1079 ED_edge_type(rev) = REVERSED;
1080 ED_label(rev) = ED_label(e);
1081 flat_edge(g, rev);
1082 }
1083}
1084
1085static void flat_search(graph_t * g, node_t * v)
1086{
1087 int i;
1088 bool hascl;
1089 edge_t *e;
1090 adjmatrix_t *M = GD_rank(g)[ND_rank(v)].flat;
1091
1092 ND_mark(v) = true;
1093 ND_onstack(v) = true;
1094 hascl = GD_n_cluster(dot_root(g)) > 0;
1095 if (ND_flat_out(v).list)
1096 for (i = 0; (e = ND_flat_out(v).list[i]); i++) {
1097 if (hascl && !(agcontains(g, agtail(e)) && agcontains(g, aghead(e))))
1098 continue;
1099 if (ED_weight(e) == 0)
1100 continue;
1101 if (ND_onstack(aghead(e))) {
1102 assert(flatindex(aghead(e)) < M->nrows);
1103 assert(flatindex(agtail(e)) < M->ncols);
1104 ELT(M, flatindex(aghead(e)), flatindex(agtail(e))) = 1;
1106 i--;
1107 if (ED_edge_type(e) == FLATORDER)
1108 continue;
1109 flat_rev(g, e);
1110 } else {
1111 assert(flatindex(aghead(e)) < M->nrows);
1112 assert(flatindex(agtail(e)) < M->ncols);
1113 ELT(M, flatindex(agtail(e)), flatindex(aghead(e))) = 1;
1114 if (!ND_mark(aghead(e)))
1115 flat_search(g, aghead(e));
1116 }
1117 }
1118 ND_onstack(v) = false;
1119}
1120
1122{
1123 int i, r, flat;
1124 node_t *v;
1125
1126 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
1127 flat = 0;
1128 for (i = 0; i < GD_rank(g)[r].n; i++) {
1129 v = GD_rank(g)[r].v[i];
1130 ND_mark(v) = false;
1131 ND_onstack(v) = false;
1132 ND_low(v) = i;
1133 if (ND_flat_out(v).size > 0 && flat == 0) {
1134 GD_rank(g)[r].flat =
1135 new_matrix((size_t)GD_rank(g)[r].n, (size_t)GD_rank(g)[r].n);
1136 flat = 1;
1137 }
1138 }
1139 if (flat) {
1140 for (i = 0; i < GD_rank(g)[r].n; i++) {
1141 v = GD_rank(g)[r].v[i];
1142 if (!ND_mark(v))
1143 flat_search(g, v);
1144 }
1145 }
1146 }
1147}
1148
1149/* allocate_ranks:
1150 * Allocate rank structure, determining number of nodes per rank.
1151 * Note that no nodes are put into the structure yet.
1152 */
1154{
1155 int r, low, high;
1156 node_t *n;
1157 edge_t *e;
1158
1159 int *cn = gv_calloc(GD_maxrank(g) + 2, sizeof(int)); // must be 0 based, not GD_minrank
1160 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
1161 cn[ND_rank(n)]++;
1162 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
1163 low = ND_rank(agtail(e));
1164 high = ND_rank(aghead(e));
1165 if (low > high) {
1166 int t = low;
1167 low = high;
1168 high = t;
1169 }
1170 for (r = low + 1; r < high; r++)
1171 cn[r]++;
1172 }
1173 }
1174 GD_rank(g) = gv_calloc(GD_maxrank(g) + 2, sizeof(rank_t));
1175 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
1176 GD_rank(g)[r].an = GD_rank(g)[r].n = cn[r] + 1;
1177 GD_rank(g)[r].av = GD_rank(g)[r].v = gv_calloc(cn[r] + 1, sizeof(node_t*));
1178 }
1179 free(cn);
1180}
1181
1182/* install a node at the current right end of its rank */
1184{
1185 int i, r;
1186
1187 r = ND_rank(n);
1188 i = GD_rank(g)[r].n;
1189 if (GD_rank(g)[r].an <= 0) {
1190 agerrorf("install_in_rank, line %d: %s %s rank %d i = %d an = 0\n",
1191 __LINE__, agnameof(g), agnameof(n), r, i);
1192 return;
1193 }
1194
1195 GD_rank(g)[r].v[i] = n;
1196 ND_order(n) = i;
1197 GD_rank(g)[r].n++;
1198 assert(GD_rank(g)[r].n <= GD_rank(g)[r].an);
1199#ifdef DEBUG
1200 {
1201 node_t *v;
1202
1203 for (v = GD_nlist(g); v; v = ND_next(v))
1204 if (v == n)
1205 break;
1206 assert(v != NULL);
1207 }
1208#endif
1209 if (ND_order(n) > GD_rank(Root)[r].an) {
1210 agerrorf("install_in_rank, line %d: ND_order(%s) [%d] > GD_rank(Root)[%d].an [%d]\n",
1211 __LINE__, agnameof(n), ND_order(n), r, GD_rank(Root)[r].an);
1212 return;
1213 }
1214 if (r < GD_minrank(g) || r > GD_maxrank(g)) {
1215 agerrorf("install_in_rank, line %d: rank %d not in rank range [%d,%d]\n",
1216 __LINE__, r, GD_minrank(g), GD_maxrank(g));
1217 return;
1218 }
1219 if (GD_rank(g)[r].v + ND_order(n) >
1220 GD_rank(g)[r].av + GD_rank(Root)[r].an) {
1221 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",
1222 __LINE__, r, agnameof(n),ND_order(n), r, r, GD_rank(Root)[r].an);
1223 return;
1224 }
1225}
1226
1227/* install nodes in ranks. the initial ordering ensure that series-parallel
1228 * graphs such as trees are drawn with no crossings. it tries searching
1229 * in- and out-edges and takes the better of the two initial orderings.
1230 */
1231void build_ranks(graph_t *g, int pass, ints_t *scratch) {
1232 int i, j;
1233 node_t *n, *ns;
1234 edge_t **otheredges;
1235 node_queue_t q = {0};
1236 for (n = GD_nlist(g); n; n = ND_next(n))
1237 MARK(n) = false;
1238
1239#ifdef DEBUG
1240 {
1241 edge_t *e;
1242 for (n = GD_nlist(g); n; n = ND_next(n)) {
1243 for (i = 0; (e = ND_out(n).list[i]); i++)
1244 assert(!MARK(aghead(e)));
1245 for (i = 0; (e = ND_in(n).list[i]); i++)
1246 assert(!MARK(agtail(e)));
1247 }
1248 }
1249#endif
1250
1251 for (i = GD_minrank(g); i <= GD_maxrank(g); i++)
1252 GD_rank(g)[i].n = 0;
1253
1254 const bool walkbackwards = g != agroot(g); // if this is a cluster, need to
1255 // walk GD_nlist backward to
1256 // preserve input node order
1257 if (walkbackwards) {
1258 for (ns = GD_nlist(g); ND_next(ns); ns = ND_next(ns)) {
1259 ;
1260 }
1261 } else {
1262 ns = GD_nlist(g);
1263 }
1264 for (n = ns; n; n = walkbackwards ? ND_prev(n) : ND_next(n)) {
1265 otheredges = pass == 0 ? ND_in(n).list : ND_out(n).list;
1266 if (otheredges[0] != NULL)
1267 continue;
1268 if (!MARK(n)) {
1269 MARK(n) = true;
1270 node_queue_push_back(&q, n);
1271 while (!node_queue_is_empty(&q)) {
1272 node_t *n0 = node_queue_pop_front(&q);
1273 if (ND_ranktype(n0) != CLUSTER) {
1274 install_in_rank(g, n0);
1275 enqueue_neighbors(&q, n0, pass);
1276 } else {
1277 install_cluster(g, n0, pass, &q);
1278 }
1279 }
1280 }
1281 }
1282 assert(node_queue_is_empty(&q));
1283 for (i = GD_minrank(g); i <= GD_maxrank(g); i++) {
1284 GD_rank(Root)[i].valid = false;
1285 if (GD_flip(g) && GD_rank(g)[i].n > 0) {
1286 node_t **vlist = GD_rank(g)[i].v;
1287 int num_nodes_1 = GD_rank(g)[i].n - 1;
1288 int half_num_nodes_1 = num_nodes_1 / 2;
1289 for (j = 0; j <= half_num_nodes_1; j++)
1290 exchange(vlist[j], vlist[num_nodes_1 - j]);
1291 }
1292 }
1293
1294 if (g == dot_root(g) && ncross(scratch) > 0)
1295 transpose(g, false);
1296 node_queue_free(&q);
1297}
1298
1299void enqueue_neighbors(node_queue_t *q, node_t *n0, int pass) {
1300 edge_t *e;
1301
1302 if (pass == 0) {
1303 for (size_t i = 0; i < ND_out(n0).size; i++) {
1304 e = ND_out(n0).list[i];
1305 if (!MARK(aghead(e))) {
1306 MARK(aghead(e)) = true;
1307 node_queue_push_back(q, aghead(e));
1308 }
1309 }
1310 } else {
1311 for (size_t i = 0; i < ND_in(n0).size; i++) {
1312 e = ND_in(n0).list[i];
1313 if (!MARK(agtail(e))) {
1314 MARK(agtail(e)) = true;
1315 node_queue_push_back(q, agtail(e));
1316 }
1317 }
1318 }
1319}
1320
1322 if (ED_weight(e) == 0)
1323 return false;
1324 if (!inside_cluster(g, agtail(e)))
1325 return false;
1326 if (!inside_cluster(g, aghead(e)))
1327 return false;
1328 return true;
1329}
1330
1331DEFINE_LIST(nodes, node_t *)
1332
1333/* construct nodes reachable from 'here' in post-order.
1334* This is the same as doing a topological sort in reverse order.
1335*/
1336static void postorder(graph_t *g, node_t *v, nodes_t *list, int r) {
1337 edge_t *e;
1338 int i;
1339
1340 MARK(v) = true;
1341 if (ND_flat_out(v).size > 0) {
1342 for (i = 0; (e = ND_flat_out(v).list[i]); i++) {
1343 if (!constraining_flat_edge(g, e)) continue;
1344 if (!MARK(aghead(e)))
1345 postorder(g, aghead(e), list, r);
1346 }
1347 }
1348 assert(ND_rank(v) == r);
1349 nodes_append(list, v);
1350}
1351
1352static void flat_reorder(graph_t * g)
1353{
1354 int i, r, local_in_cnt, local_out_cnt, base_order;
1355 node_t *v;
1356 nodes_t temprank = {0};
1357 edge_t *flat_e, *e;
1358
1359 if (!GD_has_flat_edges(g))
1360 return;
1361 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
1362 if (GD_rank(g)[r].n == 0) continue;
1363 base_order = ND_order(GD_rank(g)[r].v[0]);
1364 for (i = 0; i < GD_rank(g)[r].n; i++)
1365 MARK(GD_rank(g)[r].v[i]) = false;
1366 nodes_clear(&temprank);
1367
1368 /* construct reverse topological sort order in temprank */
1369 for (i = 0; i < GD_rank(g)[r].n; i++) {
1370 if (GD_flip(g)) v = GD_rank(g)[r].v[i];
1371 else v = GD_rank(g)[r].v[GD_rank(g)[r].n - i - 1];
1372
1373 local_in_cnt = local_out_cnt = 0;
1374 for (size_t j = 0; j < ND_flat_in(v).size; j++) {
1375 flat_e = ND_flat_in(v).list[j];
1376 if (constraining_flat_edge(g, flat_e)) local_in_cnt++;
1377 }
1378 for (size_t j = 0; j < ND_flat_out(v).size; j++) {
1379 flat_e = ND_flat_out(v).list[j];
1380 if (constraining_flat_edge(g, flat_e)) local_out_cnt++;
1381 }
1382 if ((local_in_cnt == 0) && (local_out_cnt == 0))
1383 nodes_append(&temprank, v);
1384 else {
1385 if (!MARK(v) && local_in_cnt == 0) {
1386 postorder(g, v, &temprank, r);
1387 }
1388 }
1389 }
1390
1391 if (nodes_size(&temprank) > 0) {
1392 if (!GD_flip(g)) {
1393 nodes_reverse(&temprank);
1394 }
1395 for (i = 0; i < GD_rank(g)[r].n; i++) {
1396 v = GD_rank(g)[r].v[i] = nodes_get(&temprank, (size_t)i);
1397 ND_order(v) = i + base_order;
1398 }
1399
1400 /* nonconstraint flat edges must be made LR */
1401 for (i = 0; i < GD_rank(g)[r].n; i++) {
1402 v = GD_rank(g)[r].v[i];
1403 if (ND_flat_out(v).list) {
1404 for (size_t j = 0; (e = ND_flat_out(v).list[j]); j++) {
1405 if ( (!GD_flip(g) && ND_order(aghead(e)) < ND_order(agtail(e))) ||
1406 ( (GD_flip(g)) && (ND_order(aghead(e)) > ND_order(agtail(e)) ))) {
1407 assert(!constraining_flat_edge(g, e));
1409 j--;
1410 flat_rev(g, e);
1411 }
1412 }
1413 }
1414 }
1415 /* postprocess to restore intended order */
1416 }
1417 /* else do no harm! */
1418 GD_rank(Root)[r].valid = false;
1419 }
1420 nodes_free(&temprank);
1421}
1422
1423static void reorder(graph_t * g, int r, bool reverse, bool hasfixed)
1424{
1425 int changed = 0, nelt;
1426 node_t **vlist = GD_rank(g)[r].v;
1427 node_t **lp, **rp, **ep = vlist + GD_rank(g)[r].n;
1428
1429 for (nelt = GD_rank(g)[r].n - 1; nelt >= 0; nelt--) {
1430 lp = vlist;
1431 while (lp < ep) {
1432 /* find leftmost node that can be compared */
1433 while (lp < ep && ND_mval(*lp) < 0)
1434 lp++;
1435 if (lp >= ep)
1436 break;
1437 /* find the node that can be compared */
1438 bool sawclust = false;
1439 bool muststay = false;
1440 for (rp = lp + 1; rp < ep; rp++) {
1441 if (sawclust && ND_clust(*rp))
1442 continue; /* ### */
1443 if (left2right(g, *lp, *rp)) {
1444 muststay = true;
1445 break;
1446 }
1447 if (ND_mval(*rp) >= 0)
1448 break;
1449 if (ND_clust(*rp))
1450 sawclust = true; /* ### */
1451 }
1452 if (rp >= ep)
1453 break;
1454 if (!muststay) {
1455 const double p1 = ND_mval(*lp);
1456 const double p2 = ND_mval(*rp);
1457 if (p1 > p2 || (p1 >= p2 && reverse)) {
1458 exchange(*lp, *rp);
1459 changed++;
1460 }
1461 }
1462 lp = rp;
1463 }
1464 if (!hasfixed && !reverse)
1465 ep--;
1466 }
1467
1468 if (changed) {
1469 GD_rank(Root)[r].valid = false;
1470 if (r > 0)
1471 GD_rank(Root)[r - 1].valid = false;
1472 }
1473}
1474
1475static void mincross_step(graph_t * g, int pass)
1476{
1477 int r, other, first, last, dir;
1478
1479 bool reverse = pass % 4 < 2;
1480
1481 if (pass % 2 == 0) { /* down pass */
1482 first = GD_minrank(g) + 1;
1483 if (GD_minrank(g) > GD_minrank(Root))
1484 first--;
1485 last = GD_maxrank(g);
1486 dir = 1;
1487 } else { /* up pass */
1488 first = GD_maxrank(g) - 1;
1489 last = GD_minrank(g);
1490 if (GD_maxrank(g) < GD_maxrank(Root))
1491 first++;
1492 dir = -1;
1493 }
1494
1495 for (r = first; r != last + dir; r += dir) {
1496 other = r - dir;
1497 bool hasfixed = medians(g, r, other);
1498 reorder(g, r, reverse, hasfixed);
1499 }
1500 transpose(g, !reverse);
1501}
1502
1503static int local_cross(elist l, int dir)
1504{
1505 int i, j;
1506 int cross = 0;
1507 edge_t *e, *f;
1508 bool is_out = dir > 0;
1509 for (i = 0; (e = l.list[i]); i++) {
1510 if (is_out)
1511 for (j = i + 1; (f = l.list[j]); j++) {
1512 if ((ND_order(aghead(f)) - ND_order(aghead(e)))
1513 * (ED_tail_port(f).p.x - ED_tail_port(e).p.x) < 0)
1514 cross += ED_xpenalty(e) * ED_xpenalty(f);
1515 } else
1516 for (j = i + 1; (f = l.list[j]); j++) {
1517 if ((ND_order(agtail(f)) - ND_order(agtail(e)))
1518 * (ED_head_port(f).p.x - ED_head_port(e).p.x) < 0)
1519 cross += ED_xpenalty(e) * ED_xpenalty(f);
1520 }
1521 }
1522 return cross;
1523}
1524
1525static int64_t rcross(graph_t *g, int r, ints_t *Count) {
1526 int top, bot, max, i, k;
1527 node_t **rtop, *v;
1528
1529 int64_t cross = 0;
1530 max = 0;
1531 rtop = GD_rank(g)[r].v;
1532
1533 // discard any data from previous runs
1534 ints_clear(Count);
1535
1536 for (top = 0; top < GD_rank(g)[r].n; top++) {
1537 edge_t *e;
1538 if (max > 0) {
1539 for (i = 0; (e = ND_out(rtop[top]).list[i]); i++) {
1540 for (k = ND_order(aghead(e)) + 1; k <= max; k++)
1541 cross += ints_size(Count) <= (size_t)k
1542 ? 0
1543 : ints_get(Count, (size_t)k) * ED_xpenalty(e);
1544 }
1545 }
1546 for (i = 0; (e = ND_out(rtop[top]).list[i]); i++) {
1547 int inv = ND_order(aghead(e));
1548 if (inv > max)
1549 max = inv;
1550 const size_t inv_z = (size_t)inv;
1551 if (ints_size(Count) <= inv_z) {
1552 ints_resize(Count, inv_z + 1, 0);
1553 }
1554 ints_set(Count, inv_z, ints_get(Count, inv_z) + ED_xpenalty(e));
1555 }
1556 }
1557 for (top = 0; top < GD_rank(g)[r].n; top++) {
1558 v = GD_rank(g)[r].v[top];
1559 if (ND_has_port(v))
1560 cross += local_cross(ND_out(v), 1);
1561 }
1562 for (bot = 0; bot < GD_rank(g)[r + 1].n; bot++) {
1563 v = GD_rank(g)[r + 1].v[bot];
1564 if (ND_has_port(v))
1565 cross += local_cross(ND_in(v), -1);
1566 }
1567 return cross;
1568}
1569
1570static int64_t ncross(ints_t *scratch) {
1571 assert(scratch != NULL);
1572 int r;
1573
1574 graph_t *g = Root;
1575 int64_t count = 0;
1576 for (r = GD_minrank(g); r < GD_maxrank(g); r++) {
1577 if (GD_rank(g)[r].valid)
1578 count += GD_rank(g)[r].cache_nc;
1579 else {
1580 const int64_t nc = GD_rank(g)[r].cache_nc = rcross(g, r, scratch);
1581 count += nc;
1582 GD_rank(g)[r].valid = true;
1583 }
1584 }
1585 return count;
1586}
1587
1588static int ordercmpf(const void *x, const void *y) {
1589 const int *i0 = x;
1590 const int *i1 = y;
1591 if (*i0 < *i1) {
1592 return -1;
1593 }
1594 if (*i0 > *i1) {
1595 return 1;
1596 }
1597 return 0;
1598}
1599
1600/* flat_mval:
1601 * Calculate a mval for nodes with no in or out non-flat edges.
1602 * Assume (ND_out(n).size == 0) && (ND_in(n).size == 0)
1603 * Find flat edge a->n where a has the largest order and set
1604 * n.mval = a.mval+1, assuming a.mval is defined (>=0).
1605 * If there are no flat in edges, find flat edge n->a where a
1606 * has the smallest order and set * n.mval = a.mval-1, assuming
1607 * a.mval is > 0.
1608 * Return true if n.mval is left -1, indicating a fixed node for sorting.
1609 */
1610static bool flat_mval(node_t * n)
1611{
1612 int i;
1613 edge_t *e, **fl;
1614 node_t *nn;
1615
1616 if (ND_flat_in(n).size > 0) {
1617 fl = ND_flat_in(n).list;
1618 nn = agtail(fl[0]);
1619 for (i = 1; (e = fl[i]); i++)
1620 if (ND_order(agtail(e)) > ND_order(nn))
1621 nn = agtail(e);
1622 if (ND_mval(nn) >= 0) {
1623 ND_mval(n) = ND_mval(nn) + 1;
1624 return false;
1625 }
1626 } else if (ND_flat_out(n).size > 0) {
1627 fl = ND_flat_out(n).list;
1628 nn = aghead(fl[0]);
1629 for (i = 1; (e = fl[i]); i++)
1630 if (ND_order(aghead(e)) < ND_order(nn))
1631 nn = aghead(e);
1632 if (ND_mval(nn) > 0) {
1633 ND_mval(n) = ND_mval(nn) - 1;
1634 return false;
1635 }
1636 }
1637 return true;
1638}
1639
1640#define VAL(node,port) (MC_SCALE * ND_order(node) + (port).order)
1641
1642static bool medians(graph_t * g, int r0, int r1)
1643{
1644 int i, j0, lspan, rspan, *list;
1645 node_t *n, **v;
1646 edge_t *e;
1647 bool hasfixed = false;
1648
1649 list = TI_list;
1650 v = GD_rank(g)[r0].v;
1651 for (i = 0; i < GD_rank(g)[r0].n; i++) {
1652 n = v[i];
1653 size_t j = 0;
1654 if (r1 > r0)
1655 for (j0 = 0; (e = ND_out(n).list[j0]); j0++) {
1656 if (ED_xpenalty(e) > 0)
1657 list[j++] = VAL(aghead(e), ED_head_port(e));
1658 } else
1659 for (j0 = 0; (e = ND_in(n).list[j0]); j0++) {
1660 if (ED_xpenalty(e) > 0)
1661 list[j++] = VAL(agtail(e), ED_tail_port(e));
1662 }
1663 switch (j) {
1664 case 0:
1665 ND_mval(n) = -1;
1666 break;
1667 case 1:
1668 ND_mval(n) = list[0];
1669 break;
1670 case 2:
1671 ND_mval(n) = (list[0] + list[1]) / 2;
1672 break;
1673 default:
1674 qsort(list, j, sizeof(int), ordercmpf);
1675 if (j % 2)
1676 ND_mval(n) = list[j / 2];
1677 else {
1678 /* weighted median */
1679 size_t rm = j / 2;
1680 size_t lm = rm - 1;
1681 rspan = list[j - 1] - list[rm];
1682 lspan = list[lm] - list[0];
1683 if (lspan == rspan)
1684 ND_mval(n) = (list[lm] + list[rm]) / 2;
1685 else {
1686 double w = list[lm] * (double)rspan + list[rm] * (double)lspan;
1687 ND_mval(n) = w / (lspan + rspan);
1688 }
1689 }
1690 }
1691 }
1692 for (i = 0; i < GD_rank(g)[r0].n; i++) {
1693 n = v[i];
1694 if ((ND_out(n).size == 0) && (ND_in(n).size == 0))
1695 hasfixed |= flat_mval(n);
1696 }
1697 return hasfixed;
1698}
1699
1700static int nodeposcmpf(const void *x, const void *y) {
1701// Suppress Clang/GCC -Wcast-qual warning. Casting away const here is acceptable
1702// as the later usage is const. We need the cast because the macros use
1703// non-const pointers for genericity.
1704#ifdef __GNUC__
1705#pragma GCC diagnostic push
1706#pragma GCC diagnostic ignored "-Wcast-qual"
1707#endif
1708 node_t **n0 = (node_t **)x;
1709 node_t **n1 = (node_t **)y;
1710#ifdef __GNUC__
1711#pragma GCC diagnostic pop
1712#endif
1713 if (ND_order(*n0) < ND_order(*n1)) {
1714 return -1;
1715 }
1716 if (ND_order(*n0) > ND_order(*n1)) {
1717 return 1;
1718 }
1719 return 0;
1720}
1721
1722static int edgeidcmpf(const void *x, const void *y) {
1723// Suppress Clang/GCC -Wcast-qual warning. Casting away const here is acceptable
1724// as the later usage is const. We need the cast because the macros use
1725// non-const pointers for genericity.
1726#ifdef __GNUC__
1727#pragma GCC diagnostic push
1728#pragma GCC diagnostic ignored "-Wcast-qual"
1729#endif
1730 edge_t **e0 = (edge_t **)x;
1731 edge_t **e1 = (edge_t **)y;
1732#ifdef __GNUC__
1733#pragma GCC diagnostic pop
1734#endif
1735 if (AGSEQ(*e0) < AGSEQ(*e1)) {
1736 return -1;
1737 }
1738 if (AGSEQ(*e0) > AGSEQ(*e1)) {
1739 return 1;
1740 }
1741 return 0;
1742}
1743
1744/* following code deals with weights of edges of "virtual" nodes */
1745#define ORDINARY 0
1746#define SINGLETON 1
1747#define VIRTUALNODE 2
1748#define NTYPES 3
1749
1750#define C_EE 1
1751#define C_VS 2
1752#define C_SS 2
1753#define C_VV 4
1754
1755static int table[NTYPES][NTYPES] = {
1756 /* ordinary */ {C_EE, C_EE, C_EE},
1757 /* singleton */ {C_EE, C_SS, C_VS},
1758 /* virtual */ {C_EE, C_VS, C_VV}
1759};
1760
1761static int endpoint_class(node_t * n)
1762{
1763 if (ND_node_type(n) == VIRTUAL)
1764 return VIRTUALNODE;
1765 if (ND_weight_class(n) <= 1)
1766 return SINGLETON;
1767 return ORDINARY;
1768}
1769
1771{
1772 int t;
1774
1775 /* check whether the upcoming computation will overflow */
1776 assert(t >= 0);
1777 if (INT_MAX / t < ED_weight(e)) {
1778 agerrorf("overflow when calculating virtual weight of edge\n");
1779 graphviz_exit(EXIT_FAILURE);
1780 }
1781
1782 ED_weight(e) *= t;
1783}
1784
1785#ifdef DEBUG
1786void check_rs(graph_t * g, int null_ok)
1787{
1788 int i, r;
1789 node_t *v, *prev;
1790
1791 fprintf(stderr, "\n\n%s:\n", agnameof(g));
1792 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
1793 fprintf(stderr, "%d: ", r);
1794 prev = NULL;
1795 for (i = 0; i < GD_rank(g)[r].n; i++) {
1796 v = GD_rank(g)[r].v[i];
1797 if (v == NULL) {
1798 fprintf(stderr, "NULL\t");
1799 if (!null_ok)
1800 abort();
1801 } else {
1802 fprintf(stderr, "%s(%f)\t", agnameof(v), ND_mval(v));
1803 assert(ND_rank(v) == r);
1804 assert(v != prev);
1805 prev = v;
1806 }
1807 }
1808 fprintf(stderr, "\n");
1809 }
1810}
1811
1812void check_order(void)
1813{
1814 int i, r;
1815 node_t *v;
1816 graph_t *g = Root;
1817
1818 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
1819 assert(GD_rank(g)[r].v[GD_rank(g)[r].n] == NULL);
1820 for (i = 0; (v = GD_rank(g)[r].v[i]); i++) {
1821 assert(ND_rank(v) == r);
1822 assert(ND_order(v) == i);
1823 }
1824 }
1825}
1826#endif
1827
1829{
1830 char *p;
1831 double f;
1832
1833 /* set default values */
1834 MinQuit = 8;
1835 MaxIter = 24;
1836
1837 p = agget(g, "mclimit");
1838 if (p && (f = atof(p)) > 0.0) {
1839 MinQuit = MAX(1, MinQuit * f);
1840 MaxIter = MAX(1, MaxIter * f);
1841 }
1842}
1843
1844#ifdef DEBUG
1845void check_exchange(node_t * v, node_t * w)
1846{
1847 int i, r;
1848 node_t *u;
1849
1850 if (ND_clust(v) == NULL && ND_clust(w) == NULL)
1851 return;
1852 assert(ND_clust(v) == NULL || ND_clust(w) == NULL);
1853 assert(ND_rank(v) == ND_rank(w));
1854 assert(ND_order(v) < ND_order(w));
1855 r = ND_rank(v);
1856
1857 for (i = ND_order(v) + 1; i < ND_order(w); i++) {
1858 u = GD_rank(dot_root(v))[r].v[i];
1859 if (ND_clust(u))
1860 abort();
1861 }
1862}
1863
1864void check_vlists(graph_t * g)
1865{
1866 int c, i, j, r;
1867 node_t *u;
1868
1869 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
1870 for (i = 0; i < GD_rank(g)[r].n; i++) {
1871 u = GD_rank(g)[r].v[i];
1872 j = ND_order(u);
1873 assert(GD_rank(Root)[r].v[j] == u);
1874 }
1875 if (GD_rankleader(g)) {
1876 u = GD_rankleader(g)[r];
1877 j = ND_order(u);
1878 assert(GD_rank(Root)[r].v[j] == u);
1879 }
1880 }
1881 for (c = 1; c <= GD_n_cluster(g); c++)
1882 check_vlists(GD_clust(g)[c]);
1883}
1884
1885void node_in_root_vlist(node_t * n)
1886{
1887 node_t **vptr;
1888
1889 for (vptr = GD_rank(Root)[ND_rank(n)].v; *vptr; vptr++)
1890 if (*vptr == n)
1891 break;
1892 if (*vptr == 0)
1893 abort();
1894}
1895#endif /* DEBUG code */
static agxbuf last
last message
Definition agerror.c:29
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:78
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:234
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:307
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
static void * gv_alloc(size_t size)
Definition alloc.h:47
#define MIN(a, b)
Definition arith.h:28
abstract graph C library, Cgraph API
void class2(graph_t *g)
Definition class2.c:160
#define exchange(h, i, j)
Definition closest.c:85
bool mapbool(const char *p)
Definition utils.c:335
char * late_string(void *obj, attrsym_t *attr, char *defaultValue)
Definition utils.c:78
#define NORMAL
Definition const.h:24
#define FLATORDER
Definition const.h:28
#define NEW_RANK
Definition const.h:257
#define VIRTUAL
Definition const.h:25
#define CLUSTER
Definition const.h:40
#define REVERSED
Definition const.h:27
void decompose(graph_t *g, int pass)
Definition decomp.c:114
Agraph_t * dot_root(void *p)
Definition dotinit.c:496
bool is_cluster(Agraph_t *)
Definition rank.c:460
void flat_edge(Agraph_t *, Agedge_t *)
Definition fastgr.c:217
void merge_oneway(Agedge_t *, Agedge_t *)
Definition fastgr.c:291
Agedge_t * new_virtual_edge(Agnode_t *, Agnode_t *, Agedge_t *)
Definition fastgr.c:131
Agedge_t * find_flat_edge(Agnode_t *, Agnode_t *)
Definition fastgr.c:54
void delete_flat_edge(Agedge_t *)
Definition fastgr.c:224
static NORETURN void graphviz_exit(int status)
Definition exit.h:23
int MaxIter
Definition globals.h:60
Agsym_t * G_ordering
Definition globals.h:70
Agsym_t * N_ordering
Definition globals.h:76
static bool Verbose
Definition gml2gv.c:23
void free(void *)
node NULL
Definition grammar.y:163
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:210
int agnedges(Agraph_t *g)
Definition graph.c:175
int agdegree(Agraph_t *g, Agnode_t *n, int in, int out)
Definition graph.c:237
int agnnodes(Agraph_t *g)
Definition graph.c:169
char * agget(void *obj, char *name)
Definition attr.c:439
#define ED_to_orig(e)
Definition types.h:598
Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
Definition edge.c:260
int agdeledge(Agraph_t *g, Agedge_t *arg_e)
Definition edge.c:334
Agedge_t * agnxtin(Agraph_t *g, Agedge_t *e)
Definition edge.c:69
#define ED_xpenalty(e)
Definition types.h:601
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:24
#define agtail(e)
Definition cgraph.h:880
#define ED_edge_type(e)
Definition types.h:582
#define ED_weight(e)
Definition types.h:603
#define aghead(e)
Definition cgraph.h:881
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:39
#define ED_head_port(e)
Definition types.h:588
Agedge_t * agfstin(Agraph_t *g, Agnode_t *n)
Definition edge.c:55
#define ED_label(e)
Definition types.h:589
#define ED_tail_port(e)
Definition types.h:597
void agwarningf(const char *fmt,...)
Definition agerror.c:173
void agerrorf(const char *fmt,...)
Definition agerror.c:165
#define GD_minrank(g)
Definition types.h:384
#define GD_maxrank(g)
Definition types.h:382
#define GD_clust(g)
Definition types.h:360
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Definition graph.c:102
#define GD_flags(g)
Definition types.h:365
#define GD_rank(g)
Definition types.h:395
#define GD_has_flat_edges(g)
Definition types.h:370
#define GD_nlist(g)
Definition types.h:393
Agdesc_t Agstrictdirected
strict directed. A strict graph cannot have multi-edges or self-arcs.
Definition graph.c:285
#define GD_n_cluster(g)
Definition types.h:389
Agraph_t * agopen(char *name, Agdesc_t desc, Agdisc_t *disc)
creates a new graph with the given name and kind
Definition graph.c:44
#define GD_comp(g)
Definition types.h:362
#define GD_flip(g)
Definition types.h:378
#define GD_rankleader(g)
Definition types.h:396
Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
Definition node.c:145
#define ND_rank(n)
Definition types.h:523
#define ND_prev(n)
Definition types.h:521
#define ND_ht(n)
Definition types.h:500
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:47
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:40
#define ND_has_port(n)
Definition types.h:495
#define ND_next(n)
Definition types.h:510
Agnode_t * agsubnode(Agraph_t *g, Agnode_t *n, int createflag)
Definition node.c:259
#define ND_clust(n)
Definition types.h:489
#define ND_other(n)
Definition types.h:514
#define ND_alg(n)
Definition types.h:484
#define ND_flat_out(n)
Definition types.h:493
#define ND_rw(n)
Definition types.h:525
#define ND_node_type(n)
Definition types.h:511
#define ND_lw(n)
Definition types.h:506
#define ND_mval(n)
Definition types.h:508
int agdelnode(Agraph_t *g, Agnode_t *arg_n)
removes a node from a graph or subgraph.
Definition node.c:195
#define ND_order(n)
Definition types.h:513
#define ND_UF_size(n)
Definition types.h:487
#define ND_weight_class(n)
Definition types.h:535
#define ND_low(n)
Definition types.h:505
#define ND_ranktype(n)
Definition types.h:524
#define ND_flat_in(n)
Definition types.h:492
#define ND_in(n)
Definition types.h:501
#define ND_out(n)
Definition types.h:515
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:158
int agcontains(Agraph_t *, void *obj)
returns non-zero if obj is a member of (sub)graph
Definition obj.c:233
Agraph_t * agroot(void *obj)
Definition obj.c:168
#define AGSEQ(obj)
Definition cgraph.h:225
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
Definition rec.c:89
Agraph_t * agfstsubg(Agraph_t *g)
Definition subg.c:78
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:83
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
Definition subg.c:58
static void indent(int ix)
Definition gv2gml.c:96
bool rm(Agraph_t *g)
Definition gv.cpp:584
Arithmetic helper functions.
$2 u p prev
Definition htmlparse.y:297
static double cross(double *u, double *v)
#define ND_onstack(n)
Definition acyclic.c:29
#define ND_mark(n)
Definition acyclic.c:28
static Agedge_t * top(edge_stack_t *sp)
Definition tred.c:73
void expand_cluster(graph_t *subg)
Definition cluster.c:290
void install_cluster(graph_t *g, node_t *n, int pass, node_queue_t *q)
Definition cluster.c:389
void mark_lowclusters(Agraph_t *root)
Definition cluster.c:404
#define DEFINE_LIST(name, type)
Definition list.h:26
#define neighbor(t, i, edim, elist)
Definition make_map.h:41
#define delta
Definition maze.c:133
#define isBackedge(e)
Definition mincross.c:193
static int betweenclust(edge_t *e)
Definition mincross.c:436
#define ND_hi(n)
Definition mincross.c:177
#define flatindex(v)
Definition mincross.c:44
static void free_matrix(adjmatrix_t *p)
Definition mincross.c:414
static bool ReMincross
Definition mincross.c:89
static bool flat_mval(node_t *n)
Definition mincross.c:1610
static int64_t mincross(graph_t *g, int startpass, ints_t *scratch)
Definition mincross.c:697
static bool inside_cluster(graph_t *g, node_t *v)
Definition mincross.c:910
#define ND_x(n)
Definition mincross.c:175
#define ORDINARY
Definition mincross.c:1745
static int64_t rcross(graph_t *g, int r, ints_t *Count)
Definition mincross.c:1525
static void init_mccomp(graph_t *g, size_t c)
Definition mincross.c:424
static void mincross_step(graph_t *g, int pass)
Definition mincross.c:1475
static int topsort(Agraph_t *g, Agraph_t *sg, Agnode_t **arr)
Definition mincross.c:206
static bool medians(graph_t *g, int r0, int r1)
Definition mincross.c:1642
void build_ranks(graph_t *g, int pass, ints_t *scratch)
Definition mincross.c:1231
static void reorder(graph_t *g, int r, bool reverse, bool hasfixed)
Definition mincross.c:1423
#define VAL(node, port)
Definition mincross.c:1640
static int edgeidcmpf(const void *, const void *)
Definition mincross.c:1722
static void flat_breakcycles(graph_t *g)
Definition mincross.c:1121
static void cleanup2(graph_t *g, int64_t nc)
Definition mincross.c:840
#define MARK(v)
Definition mincross.c:42
static bool is_a_normal_node_of(graph_t *g, node_t *v)
Definition mincross.c:894
static void save_best(graph_t *g)
Definition mincross.c:776
#define C_VS
Definition mincross.c:1751
static void init_mincross(graph_t *g)
Definition mincross.c:1034
#define ND_np(n)
Definition mincross.c:178
static int64_t transpose_step(graph_t *g, int r, bool reverse)
Definition mincross.c:639
static void fixLabelOrder(graph_t *g, rank_t *rk)
Definition mincross.c:250
void virtual_weight(edge_t *e)
Definition mincross.c:1770
static void merge2(graph_t *g)
Definition mincross.c:813
static node_t * furthestnode(graph_t *g, node_t *v, int dir)
Definition mincross.c:914
static int out_cross(node_t *v, node_t *w)
Definition mincross.c:607
static int ordercmpf(const void *, const void *)
Definition mincross.c:1588
void enqueue_neighbors(node_queue_t *q, node_t *n0, int pass)
Definition mincross.c:1299
static void do_ordering(graph_t *g, bool outflag)
Definition mincross.c:483
void checkLabelOrder(graph_t *g)
Definition mincross.c:305
static int64_t mincross_clust(graph_t *g, ints_t *scratch)
Definition mincross.c:544
static int GlobalMinRank
Definition mincross.c:86
static const double Convergence
Definition mincross.c:83
void install_in_rank(graph_t *g, node_t *n)
Definition mincross.c:1183
static adjmatrix_t * new_matrix(size_t i, size_t j)
Definition mincross.c:406
#define SINGLETON
Definition mincross.c:1746
static Agraph_t * realFillRanks(Agraph_t *g, int rnks[], int rnks_sz, Agraph_t *sg)
Definition mincross.c:987
static Agnode_t * findSource(Agraph_t *g, Agraph_t *sg)
Definition mincross.c:196
static int * TI_list
Definition mincross.c:88
void dot_mincross(graph_t *g)
Definition mincross.c:351
void rec_save_vlists(graph_t *g)
Definition mincross.c:938
#define C_EE
Definition mincross.c:1750
static void do_ordering_node(graph_t *g, node_t *n, bool outflag)
Definition mincross.c:443
static int64_t in_cross(node_t *v, node_t *w)
Definition mincross.c:588
static graph_t * Root
Definition mincross.c:85
#define C_VV
Definition mincross.c:1753
static void flat_search(graph_t *g, node_t *v)
Definition mincross.c:1085
static int64_t ncross(ints_t *scratch)
Definition mincross.c:1570
static void ordered_edges(graph_t *g)
Definition mincross.c:517
static void transpose(graph_t *g, bool reverse)
Definition mincross.c:680
#define NTYPES
Definition mincross.c:1748
void rec_reset_vlists(graph_t *g)
Definition mincross.c:948
static void merge_components(graph_t *g)
Definition mincross.c:789
static void mincross_options(graph_t *g)
Definition mincross.c:1828
static int endpoint_class(node_t *n)
Definition mincross.c:1761
static int getComp(graph_t *g, node_t *n, graph_t *comp, int *indices)
Definition mincross.c:225
static int GlobalMaxRank
Definition mincross.c:86
static bool left2right(graph_t *g, node_t *v, node_t *w)
Definition mincross.c:560
static int local_cross(elist l, int dir)
Definition mincross.c:1503
static void flat_reorder(graph_t *g)
Definition mincross.c:1352
#define ELT(M, i, j)
Definition mincross.c:422
#define C_SS
Definition mincross.c:1752
static void flat_rev(Agraph_t *g, Agedge_t *e)
Definition mincross.c:1058
static void emptyComp(graph_t *sg)
Definition mincross.c:182
static bool is_a_vnode_of_an_edge_of(graph_t *g, node_t *v)
Definition mincross.c:898
static void fillRanks(Agraph_t *g)
Definition mincross.c:1026
static void do_ordering_for_nodes(graph_t *g)
Definition mincross.c:492
static void postorder(graph_t *g, node_t *v, nodes_t *list, int r)
Definition mincross.c:1336
static int MinQuit
Definition mincross.c:82
static edge_t ** TE_list
Definition mincross.c:87
void allocate_ranks(graph_t *g)
Definition mincross.c:1153
#define ND_lo(n)
Definition mincross.c:176
static int table[NTYPES][NTYPES]
Definition mincross.c:1755
static void restore_best(graph_t *g)
Definition mincross.c:758
static bool constraining_flat_edge(Agraph_t *g, Agedge_t *e)
Definition mincross.c:1321
#define ND_idx(n)
Definition mincross.c:179
static int nodeposcmpf(const void *, const void *)
Definition mincross.c:1700
#define saveorder(v)
Definition mincross.c:43
void save_vlist(graph_t *g)
Definition mincross.c:928
#define VIRTUALNODE
Definition mincross.c:1747
#define M
Definition randomkit.c:90
static bool streq(const char *a, const char *b)
are a and b equal?
Definition streq.h:11
Agobj_t base
Definition cgraph.h:269
Agrec_t * data
stores programmer-defined data, access with AGDATA
Definition cgraph.h:212
graph or subgraph
Definition cgraph.h:425
Agraph_t * parent
Definition cgraph.h:434
implementation of Agrec_t
Definition cgraph.h:172
size_t nrows
Definition mincross.c:36
char * data
Definition mincross.c:38
size_t ncols
Definition mincross.c:37
Definition types.h:251
edge_t ** list
Definition types.h:252
int hi
Definition mincross.c:171
Agrec_t h
Definition mincross.c:170
Agnode_t * np
Definition mincross.c:172
node_t ** v
Definition types.h:202
int n
Definition types.h:201
double elapsed_sec(void)
Definition timing.c:48
void start_timer(void)
Definition timing.c:43
#define elist_append(item, L)
Definition types.h:261
#define alloc_elist(n, L)
Definition types.h:267
Definition grammar.c:93
#define MAX(a, b)
Definition write.c:31