Graphviz 12.0.1~dev.20240715.2254
Loading...
Searching...
No Matches
ns.c
Go to the documentation of this file.
1
7/*************************************************************************
8 * Copyright (c) 2011 AT&T Intellectual Property
9 * All rights reserved. This program and the accompanying materials
10 * are made available under the terms of the Eclipse Public License v1.0
11 * which accompanies this distribution, and is available at
12 * https://www.eclipse.org/legal/epl-v10.html
13 *
14 * Contributors: Details at https://graphviz.org
15 *************************************************************************/
16
17#include <assert.h>
18#include <cgraph/alloc.h>
19#include <cgraph/exit.h>
20#include <cgraph/overflow.h>
21#include <cgraph/prisize_t.h>
22#include <cgraph/queue.h>
23#include <cgraph/streq.h>
24#include <common/render.h>
25#include <limits.h>
26#include <stdbool.h>
27#include <stddef.h>
28#include <stdint.h>
29#include <stdio.h>
30
31static void dfs_cutval(node_t * v, edge_t * par);
32static int dfs_range_init(node_t * v, edge_t * par, int low);
33static int dfs_range(node_t * v, edge_t * par, int low);
34static int x_val(edge_t * e, node_t * v, int dir);
35#ifdef DEBUG
36static void check_cycles(graph_t * g);
37#endif
38
39#define LENGTH(e) (ND_rank(aghead(e)) - ND_rank(agtail(e)))
40#define SLACK(e) (LENGTH(e) - ED_minlen(e))
41#define SEQ(a,b,c) ((a) <= (b) && (b) <= (c))
42#define TREE_EDGE(e) (ED_tree_index(e) >= 0)
43
44static graph_t *G;
45static size_t N_nodes, N_edges;
46static size_t S_i; /* search index for enter_edge */
47static int Search_size;
48#define SEARCHSIZE 30
51
52static int add_tree_edge(edge_t * e)
53{
54 node_t *n;
55 if (TREE_EDGE(e)) {
56 agerrorf("add_tree_edge: missing tree edge\n");
57 return -1;
58 }
59 assert(Tree_edge.size <= INT_MAX);
62 if (!ND_mark(agtail(e)))
64 if (!ND_mark(aghead(e)))
66 n = agtail(e);
67 ND_mark(n) = true;
68 ND_tree_out(n).list[ND_tree_out(n).size++] = e;
69 ND_tree_out(n).list[ND_tree_out(n).size] = NULL;
70 if (ND_out(n).list[ND_tree_out(n).size - 1] == 0) {
71 agerrorf("add_tree_edge: empty outedge list\n");
72 return -1;
73 }
74 n = aghead(e);
75 ND_mark(n) = true;
76 ND_tree_in(n).list[ND_tree_in(n).size++] = e;
77 ND_tree_in(n).list[ND_tree_in(n).size] = NULL;
78 if (ND_in(n).list[ND_tree_in(n).size - 1] == 0) {
79 agerrorf("add_tree_edge: empty inedge list\n");
80 return -1;
81 }
82 return 0;
83}
84
90static void invalidate_path(node_t *lca, node_t *to_node) {
91 while (true) {
92 if (ND_low(to_node) == -1)
93 break;
94
95 ND_low(to_node) = -1;
96
97 edge_t *e = ND_par(to_node);
98 if (e == NULL)
99 break;
100
101 if (ND_lim(to_node) >= ND_lim(lca)) {
102 if (to_node != lca)
103 agerrorf("invalidate_path: skipped over LCA\n");
104 break;
105 }
106
107 if (ND_lim(agtail(e)) > ND_lim(aghead(e)))
108 to_node = agtail(e);
109 else
110 to_node = aghead(e);
111 }
112}
113
114static void exchange_tree_edges(edge_t * e, edge_t * f)
115{
116 node_t *n;
117
120 ED_tree_index(e) = -1;
121
122 n = agtail(e);
123 size_t i = --ND_tree_out(n).size;
124 size_t j;
125 for (j = 0; j <= i; j++)
126 if (ND_tree_out(n).list[j] == e)
127 break;
128 ND_tree_out(n).list[j] = ND_tree_out(n).list[i];
129 ND_tree_out(n).list[i] = NULL;
130 n = aghead(e);
131 i = --ND_tree_in(n).size;
132 for (j = 0; j <= i; j++)
133 if (ND_tree_in(n).list[j] == e)
134 break;
135 ND_tree_in(n).list[j] = ND_tree_in(n).list[i];
136 ND_tree_in(n).list[i] = NULL;
137
138 n = agtail(f);
139 ND_tree_out(n).list[ND_tree_out(n).size++] = f;
140 ND_tree_out(n).list[ND_tree_out(n).size] = NULL;
141 n = aghead(f);
142 ND_tree_in(n).list[ND_tree_in(n).size++] = f;
143 ND_tree_in(n).list[ND_tree_in(n).size] = NULL;
144}
145
146static
147void init_rank(void)
148{
149 int i;
150 node_t *v;
151 edge_t *e;
152
154 size_t ctr = 0;
155
156 for (v = GD_nlist(G); v; v = ND_next(v)) {
157 if (ND_priority(v) == 0)
158 queue_push(&Q, v);
159 }
160
161 while ((v = queue_pop(&Q))) {
162 ND_rank(v) = 0;
163 ctr++;
164 for (i = 0; (e = ND_in(v).list[i]); i++)
165 ND_rank(v) = MAX(ND_rank(v), ND_rank(agtail(e)) + ED_minlen(e));
166 for (i = 0; (e = ND_out(v).list[i]); i++) {
167 if (--ND_priority(aghead(e)) <= 0)
168 queue_push(&Q, aghead(e));
169 }
170 }
171 if (ctr != N_nodes) {
172 agerrorf("trouble in init_rank\n");
173 for (v = GD_nlist(G); v; v = ND_next(v))
174 if (ND_priority(v))
175 agerr(AGPREV, "\t%s %d\n", agnameof(v), ND_priority(v));
176 }
177 queue_free(&Q);
178}
179
180static edge_t *leave_edge(void)
181{
182 edge_t *f, *rv = NULL;
183 int cnt = 0;
184
185 size_t j = S_i;
186 while (S_i < Tree_edge.size) {
187 if (ED_cutvalue(f = Tree_edge.list[S_i]) < 0) {
188 if (rv) {
189 if (ED_cutvalue(rv) > ED_cutvalue(f))
190 rv = f;
191 } else
192 rv = Tree_edge.list[S_i];
193 if (++cnt >= Search_size)
194 return rv;
195 }
196 S_i++;
197 }
198 if (j > 0) {
199 S_i = 0;
200 while (S_i < j) {
201 if (ED_cutvalue(f = Tree_edge.list[S_i]) < 0) {
202 if (rv) {
203 if (ED_cutvalue(rv) > ED_cutvalue(f))
204 rv = f;
205 } else
206 rv = Tree_edge.list[S_i];
207 if (++cnt >= Search_size)
208 return rv;
209 }
210 S_i++;
211 }
212 }
213 return rv;
214}
215
216static edge_t *Enter;
217static int Low, Lim, Slack;
218
219static void dfs_enter_outedge(node_t * v)
220{
221 int i, slack;
222 edge_t *e;
223
224 for (i = 0; (e = ND_out(v).list[i]); i++) {
225 if (!TREE_EDGE(e)) {
226 if (!SEQ(Low, ND_lim(aghead(e)), Lim)) {
227 slack = SLACK(e);
228 if (slack < Slack || Enter == NULL) {
229 Enter = e;
230 Slack = slack;
231 }
232 }
233 } else if (ND_lim(aghead(e)) < ND_lim(v))
235 }
236 for (i = 0; (e = ND_tree_in(v).list[i]) && (Slack > 0); i++)
237 if (ND_lim(agtail(e)) < ND_lim(v))
239}
240
241static void dfs_enter_inedge(node_t * v)
242{
243 int i, slack;
244 edge_t *e;
245
246 for (i = 0; (e = ND_in(v).list[i]); i++) {
247 if (!TREE_EDGE(e)) {
248 if (!SEQ(Low, ND_lim(agtail(e)), Lim)) {
249 slack = SLACK(e);
250 if (slack < Slack || Enter == NULL) {
251 Enter = e;
252 Slack = slack;
253 }
254 }
255 } else if (ND_lim(agtail(e)) < ND_lim(v))
257 }
258 for (i = 0; (e = ND_tree_out(v).list[i]) && Slack > 0; i++)
259 if (ND_lim(aghead(e)) < ND_lim(v))
261}
262
264{
265 node_t *v;
266 bool outsearch;
267
268 /* v is the down node */
269 if (ND_lim(agtail(e)) < ND_lim(aghead(e))) {
270 v = agtail(e);
271 outsearch = false;
272 } else {
273 v = aghead(e);
274 outsearch = true;
275 }
276 Enter = NULL;
277 Slack = INT_MAX;
278 Low = ND_low(v);
279 Lim = ND_lim(v);
280 if (outsearch)
282 else
284 return Enter;
285}
286
287static void init_cutvalues(void)
288{
291}
292
293/* functions for initial tight tree construction */
294// borrow field from network simplex - overwritten in init_cutvalues() forgive me
295#define ND_subtree(n) (subtree_t*)ND_par(n)
296#define ND_subtree_set(n,value) (ND_par(n) = (edge_t*)value)
297
298typedef struct subtree_s {
299 node_t *rep; /* some node in the tree */
300 int size; /* total tight tree size */
301 size_t heap_index;
302 struct subtree_s *par; /* union find */
304
306static bool on_heap(const subtree_t *tree) {
307 return tree->heap_index != SIZE_MAX;
308}
309
310/* find initial tight subtrees */
312{
313 Agedge_t *e;
314 int i;
315 int rv;
316
317 rv = 1;
318 ND_subtree_set(v,st);
319 for (i = 0; (e = ND_in(v).list[i]); i++) {
320 if (TREE_EDGE(e)) continue;
321 if (ND_subtree(agtail(e)) == 0 && SLACK(e) == 0) {
322 if (add_tree_edge(e) != 0) {
323 return -1;
324 }
325 rv += tight_subtree_search(agtail(e),st);
326 }
327 }
328 for (i = 0; (e = ND_out(v).list[i]); i++) {
329 if (TREE_EDGE(e)) continue;
330 if (ND_subtree(aghead(e)) == 0 && SLACK(e) == 0) {
331 if (add_tree_edge(e) != 0) {
332 return -1;
333 }
334 rv += tight_subtree_search(aghead(e),st);
335 }
336 }
337 return rv;
338}
339
341{
342 subtree_t *rv;
343 rv = gv_alloc(sizeof(subtree_t));
344 rv->rep = v;
345 rv->size = tight_subtree_search(v,rv);
346 if (rv->size < 0) {
347 free(rv);
348 return NULL;
349 }
350 rv->par = rv;
351 return rv;
352}
353
354typedef struct STheap_s {
356 size_t size;
358
360{
361 subtree_t *s0 = ND_subtree(n0);
362 while (s0->par && s0->par != s0) {
363 if (s0->par->par) {s0->par = s0->par->par;} /* path compression for the code weary */
364 s0 = s0->par;
365 }
366 return s0;
367}
368
370{
371 subtree_t *r0, *r1, *r;
372
373 for (r0 = s0; r0->par && r0->par != r0; r0 = r0->par);
374 for (r1 = s1; r1->par && r1->par != r1; r1 = r1->par);
375 if (r0 == r1) return r0; /* safety code but shouldn't happen */
376 assert(on_heap(r0) || on_heap(r1));
377 if (!on_heap(r1)) r = r0;
378 else if (!on_heap(r0)) r = r1;
379 else if (r1->size < r0->size) r = r0;
380 else r = r1;
381
382 r0->par = r1->par = r;
383 r->size = r0->size + r1->size;
384 assert(on_heap(r));
385 return r;
386}
387
388/* find tightest edge to another tree incident on the given tree */
390{
391 int i;
392 Agedge_t *e;
393 subtree_t *ts = STsetFind(v);
394 if (best && SLACK(best) == 0) return best;
395 for (i = 0; (e = ND_out(v).list[i]); i++) {
396 if (TREE_EDGE(e)) {
397 if (aghead(e) == from) continue; // do not search back in tree
398 best = inter_tree_edge_search(aghead(e),v,best); // search forward in tree
399 }
400 else {
401 if (STsetFind(aghead(e)) != ts) { // encountered candidate edge
402 if (best == 0 || SLACK(e) < SLACK(best)) best = e;
403 }
404 /* else ignore non-tree edge between nodes in the same tree */
405 }
406 }
407 /* the following code must mirror the above, but for in-edges */
408 for (i = 0; (e = ND_in(v).list[i]); i++) {
409 if (TREE_EDGE(e)) {
410 if (agtail(e) == from) continue;
411 best = inter_tree_edge_search(agtail(e),v,best);
412 }
413 else {
414 if (STsetFind(agtail(e)) != ts) {
415 if (best == 0 || SLACK(e) < SLACK(best)) best = e;
416 }
417 }
418 }
419 return best;
420}
421
423{
424 Agedge_t *rv;
426 return rv;
427}
428
429static size_t STheapsize(const STheap_t *heap) { return heap->size; }
430
431static void STheapify(STheap_t *heap, size_t i) {
432 subtree_t **elt = heap->elt;
433 do {
434 const size_t left = 2 * (i + 1) - 1;
435 const size_t right = 2 * (i + 1);
436 size_t smallest = i;
437 if (left < heap->size && elt[left]->size < elt[smallest]->size) smallest = left;
438 if (right < heap->size && elt[right]->size < elt[smallest]->size) smallest = right;
439 if (smallest != i) {
440 subtree_t *temp;
441 temp = elt[i];
442 elt[i] = elt[smallest];
443 elt[smallest] = temp;
444 elt[i]->heap_index = i;
445 elt[smallest]->heap_index = smallest;
446 i = smallest;
447 }
448 else break;
449 } while (i < heap->size);
450}
451
452static STheap_t *STbuildheap(subtree_t **elt, size_t size) {
453 STheap_t *heap = gv_alloc(sizeof(STheap_t));
454 heap->elt = elt;
455 heap->size = size;
456 for (size_t i = 0; i < heap->size; i++) heap->elt[i]->heap_index = i;
457 for (size_t i = heap->size / 2; i != SIZE_MAX; i--)
458 STheapify(heap,i);
459 return heap;
460}
461
462static
464{
465 subtree_t *rv;
466 rv = heap->elt[0];
467 rv->heap_index = SIZE_MAX;
468 // mark this as not participating in the heap anymore
469 heap->elt[0] = heap->elt[heap->size - 1];
470 heap->elt[0]->heap_index = 0;
471 heap->elt[heap->size -1] = rv; /* needed to free storage later */
472 heap->size--;
473 STheapify(heap,0);
474 return rv;
475}
476
477static
478void tree_adjust(Agnode_t *v, Agnode_t *from, int delta)
479{
480 int i;
481 Agedge_t *e;
482 Agnode_t *w;
483 ND_rank(v) = ND_rank(v) + delta;
484 for (i = 0; (e = ND_tree_in(v).list[i]); i++) {
485 w = agtail(e);
486 if (w != from)
487 tree_adjust(w, v, delta);
488 }
489 for (i = 0; (e = ND_tree_out(v).list[i]); i++) {
490 w = aghead(e);
491 if (w != from)
492 tree_adjust(w, v, delta);
493 }
494}
495
496static
497subtree_t *merge_trees(Agedge_t *e) /* entering tree edge */
498{
499 int delta;
500 subtree_t *t0, *t1, *rv;
501
502 assert(!TREE_EDGE(e));
503
504 t0 = STsetFind(agtail(e));
505 t1 = STsetFind(aghead(e));
506
507 if (!on_heap(t0)) { // move t0
508 delta = SLACK(e);
509 if (delta != 0)
511 }
512 else { // move t1
513 delta = -SLACK(e);
514 if (delta != 0)
516 }
517 if (add_tree_edge(e) != 0) {
518 return NULL;
519 }
520 rv = STsetUnion(t0,t1);
521
522 return rv;
523}
524
525/* Construct initial tight tree. Graph must be connected, feasible.
526 * Adjust ND_rank(v) as needed. add_tree_edge() on tight tree edges.
527 * trees are basically lists of nodes stored in nodequeues.
528 * Return 1 if input graph is not connected; 0 on success.
529 */
530static
532{
533 Agedge_t *ee;
534 size_t subtree_count = 0;
535 STheap_t *heap = NULL;
536 int error = 0;
537
538 /* initialization */
539 for (Agnode_t *n = GD_nlist(G); n != NULL; n = ND_next(n)) {
540 ND_subtree_set(n,0);
541 }
542
543 subtree_t **tree = gv_calloc(N_nodes, sizeof(subtree_t *));
544 /* given init_rank, find all tight subtrees */
545 for (Agnode_t *n = GD_nlist(G); n != NULL; n = ND_next(n)) {
546 if (ND_subtree(n) == 0) {
547 tree[subtree_count] = find_tight_subtree(n);
548 if (tree[subtree_count] == NULL) {
549 error = 2;
550 goto end;
551 }
552 subtree_count++;
553 }
554 }
555
556 /* incrementally merge subtrees */
557 heap = STbuildheap(tree,subtree_count);
558 while (STheapsize(heap) > 1) {
559 subtree_t *tree0 = STextractmin(heap);
560 if (!(ee = inter_tree_edge(tree0))) {
561 error = 1;
562 break;
563 }
564 subtree_t *tree1 = merge_trees(ee);
565 if (tree1 == NULL) {
566 error = 2;
567 break;
568 }
569 STheapify(heap,tree1->heap_index);
570 }
571
572end:
573 free(heap);
574 for (size_t i = 0; i < subtree_count; i++) free(tree[i]);
575 free(tree);
576 if (error) return error;
577 assert(Tree_edge.size == N_nodes - 1);
579 return 0;
580}
581
582/* walk up from v to LCA(v,w), setting new cutvalues. */
583static Agnode_t *treeupdate(Agnode_t * v, Agnode_t * w, int cutvalue, int dir)
584{
585 edge_t *e;
586 int d;
587
588 while (!SEQ(ND_low(v), ND_lim(w), ND_lim(v))) {
589 e = ND_par(v);
590 if (v == agtail(e))
591 d = dir;
592 else
593 d = !dir;
594 if (d)
595 ED_cutvalue(e) += cutvalue;
596 else
597 ED_cutvalue(e) -= cutvalue;
598 if (ND_lim(agtail(e)) > ND_lim(aghead(e)))
599 v = agtail(e);
600 else
601 v = aghead(e);
602 }
603 return v;
604}
605
606static void rerank(Agnode_t * v, int delta)
607{
608 int i;
609 edge_t *e;
610
611 ND_rank(v) -= delta;
612 for (i = 0; (e = ND_tree_out(v).list[i]); i++)
613 if (e != ND_par(v))
614 rerank(aghead(e), delta);
615 for (i = 0; (e = ND_tree_in(v).list[i]); i++)
616 if (e != ND_par(v))
617 rerank(agtail(e), delta);
618}
619
620/* e is the tree edge that is leaving and f is the nontree edge that
621 * is entering. compute new cut values, ranks, and exchange e and f.
622 */
623static int
625{
626 int cutvalue, delta;
627 Agnode_t *lca;
628
629 delta = SLACK(f);
630 /* "for (v = in nodes in tail side of e) do ND_rank(v) -= delta;" */
631 if (delta > 0) {
632 size_t s = ND_tree_in(agtail(e)).size + ND_tree_out(agtail(e)).size;
633 if (s == 1)
634 rerank(agtail(e), delta);
635 else {
636 s = ND_tree_in(aghead(e)).size + ND_tree_out(aghead(e)).size;
637 if (s == 1)
638 rerank(aghead(e), -delta);
639 else {
640 if (ND_lim(agtail(e)) < ND_lim(aghead(e)))
641 rerank(agtail(e), delta);
642 else
643 rerank(aghead(e), -delta);
644 }
645 }
646 }
647
648 cutvalue = ED_cutvalue(e);
649 lca = treeupdate(agtail(f), aghead(f), cutvalue, 1);
650 if (treeupdate(aghead(f), agtail(f), cutvalue, 0) != lca) {
651 agerrorf("update: mismatched lca in treeupdates\n");
652 return 2;
653 }
654
655 // invalidate paths from LCA till affected nodes:
656 int lca_low = ND_low(lca);
657 invalidate_path(lca, aghead(f));
658 invalidate_path(lca, agtail(f));
659
660 ED_cutvalue(f) = -cutvalue;
661 ED_cutvalue(e) = 0;
663 dfs_range(lca, ND_par(lca), lca_low);
664 return 0;
665}
666
667static int scan_and_normalize(void) {
668 node_t *n;
669
670 int Minrank = INT_MAX;
671 int Maxrank = INT_MIN;
672 for (n = GD_nlist(G); n; n = ND_next(n)) {
673 if (ND_node_type(n) == NORMAL) {
674 Minrank = MIN(Minrank, ND_rank(n));
675 Maxrank = MAX(Maxrank, ND_rank(n));
676 }
677 }
678 for (n = GD_nlist(G); n; n = ND_next(n))
679 ND_rank(n) -= Minrank;
680 Maxrank -= Minrank;
681 return Maxrank;
682}
683
684static void reset_lists(void) {
685
687 Tree_node = (nlist_t){0};
688
690 Tree_edge = (elist){0};
691}
692
693static void
695{
696 node_t *n;
697 for (n = GD_nlist(g); n; n = ND_next(n)) {
700 ND_mark(n) = false;
701 }
702 reset_lists();
703}
704
705static void LR_balance(void)
706{
707 int delta;
708 edge_t *e, *f;
709
710 for (size_t i = 0; i < Tree_edge.size; i++) {
711 e = Tree_edge.list[i];
712 if (ED_cutvalue(e) == 0) {
713 f = enter_edge(e);
714 if (f == NULL)
715 continue;
716 delta = SLACK(f);
717 if (delta <= 1)
718 continue;
719 if (ND_lim(agtail(e)) < ND_lim(aghead(e)))
720 rerank(agtail(e), delta / 2);
721 else
722 rerank(aghead(e), -delta / 2);
723 }
724 }
725 freeTreeList (G);
726}
727
728static int decreasingrankcmpf(const void *x, const void *y) {
729// Suppress Clang/GCC -Wcast-qual warning. Casting away const here is acceptable
730// as the later usage is const. We need the cast because the macros use
731// non-const pointers for genericity.
732#ifdef __GNUC__
733#pragma GCC diagnostic push
734#pragma GCC diagnostic ignored "-Wcast-qual"
735#endif
736 node_t **n0 = (node_t**)x;
737 node_t **n1 = (node_t**)y;
738#ifdef __GNUC__
739#pragma GCC diagnostic pop
740#endif
741 if (ND_rank(*n1) < ND_rank(*n0)) {
742 return -1;
743 }
744 if (ND_rank(*n1) > ND_rank(*n0)) {
745 return 1;
746 }
747 return 0;
748}
749
750static int increasingrankcmpf(const void *x, const void *y) {
751// Suppress Clang/GCC -Wcast-qual warning. Casting away const here is acceptable
752// as the later usage is const. We need the cast because the macros use
753// non-const pointers for genericity.
754#ifdef __GNUC__
755#pragma GCC diagnostic push
756#pragma GCC diagnostic ignored "-Wcast-qual"
757#endif
758 node_t **n0 = (node_t **)x;
759 node_t **n1 = (node_t **)y;
760#ifdef __GNUC__
761#pragma GCC diagnostic pop
762#endif
763 if (ND_rank(*n0) < ND_rank(*n1)) {
764 return -1;
765 }
766 if (ND_rank(*n0) > ND_rank(*n1)) {
767 return 1;
768 }
769 return 0;
770}
771
772static void TB_balance(void)
773{
774 node_t *n;
775 edge_t *e;
776 int low, high, choice;
777 int inweight, outweight;
778 int adj = 0;
779 char *s;
780
781 const int Maxrank = scan_and_normalize();
782
783 /* find nodes that are not tight and move to less populated ranks */
784 assert(Maxrank >= 0);
785 int *nrank = gv_calloc((size_t)Maxrank + 1, sizeof(int));
786 if ( (s = agget(G,"TBbalance")) ) {
787 if (streq(s,"min")) adj = 1;
788 else if (streq(s,"max")) adj = 2;
789 if (adj) for (n = GD_nlist(G); n; n = ND_next(n))
790 if (ND_node_type(n) == NORMAL) {
791 if (ND_in(n).size == 0 && adj == 1) {
792 ND_rank(n) = 0;
793 }
794 if (ND_out(n).size == 0 && adj == 2) {
795 ND_rank(n) = Maxrank;
796 }
797 }
798 }
799 size_t ii;
800 for (ii = 0, n = GD_nlist(G); n; ii++, n = ND_next(n)) {
801 Tree_node.list[ii] = n;
802 }
803 Tree_node.size = ii;
804 qsort(Tree_node.list, Tree_node.size, sizeof(Tree_node.list[0]),
806 for (size_t i = 0; i < Tree_node.size; i++) {
807 n = Tree_node.list[i];
808 if (ND_node_type(n) == NORMAL)
809 nrank[ND_rank(n)]++;
810 }
811 for (ii = 0; ii < Tree_node.size; ii++) {
812 n = Tree_node.list[ii];
813 if (ND_node_type(n) != NORMAL)
814 continue;
815 inweight = outweight = 0;
816 low = 0;
817 high = Maxrank;
818 for (size_t i = 0; (e = ND_in(n).list[i]); i++) {
819 inweight += ED_weight(e);
820 low = MAX(low, ND_rank(agtail(e)) + ED_minlen(e));
821 }
822 for (size_t i = 0; (e = ND_out(n).list[i]); i++) {
823 outweight += ED_weight(e);
824 high = MIN(high, ND_rank(aghead(e)) - ED_minlen(e));
825 }
826 if (low < 0)
827 low = 0; /* vnodes can have ranks < 0 */
828 if (adj) {
829 if (inweight == outweight)
830 ND_rank(n) = (adj == 1? low : high);
831 }
832 else {
833 if (inweight == outweight) {
834 choice = low;
835 for (int i = low + 1; i <= high; i++)
836 if (nrank[i] < nrank[choice])
837 choice = i;
838 nrank[ND_rank(n)]--;
839 nrank[choice]++;
840 ND_rank(n) = choice;
841 }
842 }
845 ND_mark(n) = false;
846 }
847 free(nrank);
848}
849
850static bool init_graph(graph_t *g) {
851 node_t *n;
852 edge_t *e;
853
854 G = g;
855 N_nodes = N_edges = S_i = 0;
856 for (n = GD_nlist(g); n; n = ND_next(n)) {
857 ND_mark(n) = false;
858 N_nodes++;
859 for (size_t i = 0; (e = ND_out(n).list[i]); i++)
860 N_edges++;
861 }
862
863 Tree_node.list = gv_calloc(N_nodes, sizeof(node_t *));
864 Tree_edge.list = gv_calloc(N_nodes, sizeof(edge_t *));
865
866 bool feasible = true;
867 for (n = GD_nlist(g); n; n = ND_next(n)) {
868 ND_priority(n) = 0;
869 size_t i;
870 for (i = 0; (e = ND_in(n).list[i]); i++) {
871 ND_priority(n)++;
872 ED_cutvalue(e) = 0;
873 ED_tree_index(e) = -1;
874 if (ND_rank(aghead(e)) - ND_rank(agtail(e)) < ED_minlen(e))
875 feasible = false;
876 }
877 ND_tree_in(n).list = gv_calloc(i + 1, sizeof(edge_t *));
878 ND_tree_in(n).size = 0;
879 for (i = 0; (e = ND_out(n).list[i]); i++);
880 ND_tree_out(n).list = gv_calloc(i + 1, sizeof(edge_t *));
881 ND_tree_out(n).size = 0;
882 }
883 return feasible;
884}
885
886/* graphSize:
887 * Compute no. of nodes and edges in the graph
888 */
889static void
890graphSize (graph_t * g, int* nn, int* ne)
891{
892 int i, nnodes, nedges;
893 node_t *n;
894 edge_t *e;
895
896 nnodes = nedges = 0;
897 for (n = GD_nlist(g); n; n = ND_next(n)) {
898 nnodes++;
899 for (i = 0; (e = ND_out(n).list[i]); i++) {
900 nedges++;
901 }
902 }
903 *nn = nnodes;
904 *ne = nedges;
905}
906
907/* rank:
908 * Apply network simplex to rank the nodes in a graph.
909 * Uses ED_minlen as the internode constraint: if a->b with minlen=ml,
910 * rank b - rank a >= ml.
911 * Assumes the graph has the following additional structure:
912 * A list of all nodes, starting at GD_nlist, and linked using ND_next.
913 * Out and in edges lists stored in ND_out and ND_in, even if the node
914 * doesn't have any out or in edges.
915 * The node rank values are stored in ND_rank.
916 * Returns 0 if successful; returns 1 if the graph was not connected;
917 * returns 2 if something seriously wrong;
918 */
919int rank2(graph_t * g, int balance, int maxiter, int search_size)
920{
921 int iter = 0;
922 char *ns = "network simplex: ";
923 edge_t *e, *f;
924
925#ifdef DEBUG
926 check_cycles(g);
927#endif
928 if (Verbose) {
929 int nn, ne;
930 graphSize (g, &nn, &ne);
931 fprintf(stderr, "%s %d nodes %d edges maxiter=%d balance=%d\n", ns,
932 nn, ne, maxiter, balance);
933 start_timer();
934 }
935 bool feasible = init_graph(g);
936 if (!feasible)
937 init_rank();
938
939 if (search_size >= 0)
940 Search_size = search_size;
941 else
943
944 {
945 int err = feasible_tree();
946 if (err != 0) {
947 freeTreeList (g);
948 return err;
949 }
950 }
951 if (maxiter <= 0) {
952 freeTreeList (g);
953 return 0;
954 }
955
956 while ((e = leave_edge())) {
957 int err;
958 f = enter_edge(e);
959 err = update(e, f);
960 if (err != 0) {
961 freeTreeList (g);
962 return err;
963 }
964 iter++;
965 if (Verbose && iter % 100 == 0) {
966 if (iter % 1000 == 100)
967 fputs(ns, stderr);
968 fprintf(stderr, "%d ", iter);
969 if (iter % 1000 == 0)
970 fputc('\n', stderr);
971 }
972 if (iter >= maxiter)
973 break;
974 }
975 switch (balance) {
976 case 1:
977 TB_balance();
978 reset_lists();
979 break;
980 case 2:
981 LR_balance();
982 break;
983 default:
984 (void)scan_and_normalize();
985 freeTreeList (G);
986 break;
987 }
988 if (Verbose) {
989 if (iter >= 100)
990 fputc('\n', stderr);
991 fprintf(stderr, "%s%" PRISIZE_T " nodes %" PRISIZE_T " edges %d iter %.2f sec\n",
992 ns, N_nodes, N_edges, iter, elapsed_sec());
993 }
994 return 0;
995}
996
997int rank(graph_t * g, int balance, int maxiter)
998{
999 char *s;
1000 int search_size;
1001
1002 if ((s = agget(g, "searchsize")))
1003 search_size = atoi(s);
1004 else
1005 search_size = SEARCHSIZE;
1006
1007 return rank2 (g, balance, maxiter, search_size);
1008}
1009
1010/* set cut value of f, assuming values of edges on one side were already set */
1011static void x_cutval(edge_t * f)
1012{
1013 node_t *v;
1014 edge_t *e;
1015 int i, sum, dir;
1016
1017 /* set v to the node on the side of the edge already searched */
1018 if (ND_par(agtail(f)) == f) {
1019 v = agtail(f);
1020 dir = 1;
1021 } else {
1022 v = aghead(f);
1023 dir = -1;
1024 }
1025
1026 sum = 0;
1027 for (i = 0; (e = ND_out(v).list[i]); i++)
1028 if (sadd_overflow(sum, x_val(e, v, dir), &sum)) {
1029 agerrorf("overflow when computing edge weight sum\n");
1030 graphviz_exit(EXIT_FAILURE);
1031 }
1032 for (i = 0; (e = ND_in(v).list[i]); i++)
1033 if (sadd_overflow(sum, x_val(e, v, dir), &sum)) {
1034 agerrorf("overflow when computing edge weight sum\n");
1035 graphviz_exit(EXIT_FAILURE);
1036 }
1037 ED_cutvalue(f) = sum;
1038}
1039
1040static int x_val(edge_t * e, node_t * v, int dir)
1041{
1042 node_t *other;
1043 int d, rv, f;
1044
1045 if (agtail(e) == v)
1046 other = aghead(e);
1047 else
1048 other = agtail(e);
1049 if (!(SEQ(ND_low(v), ND_lim(other), ND_lim(v)))) {
1050 f = 1;
1051 rv = ED_weight(e);
1052 } else {
1053 f = 0;
1054 if (TREE_EDGE(e))
1055 rv = ED_cutvalue(e);
1056 else
1057 rv = 0;
1058 rv -= ED_weight(e);
1059 }
1060 if (dir > 0) {
1061 if (aghead(e) == v)
1062 d = 1;
1063 else
1064 d = -1;
1065 } else {
1066 if (agtail(e) == v)
1067 d = 1;
1068 else
1069 d = -1;
1070 }
1071 if (f)
1072 d = -d;
1073 if (d < 0)
1074 rv = -rv;
1075 return rv;
1076}
1077
1078static void dfs_cutval(node_t * v, edge_t * par)
1079{
1080 int i;
1081 edge_t *e;
1082
1083 for (i = 0; (e = ND_tree_out(v).list[i]); i++)
1084 if (e != par)
1085 dfs_cutval(aghead(e), e);
1086 for (i = 0; (e = ND_tree_in(v).list[i]); i++)
1087 if (e != par)
1088 dfs_cutval(agtail(e), e);
1089 if (par)
1090 x_cutval(par);
1091}
1092
1093/*
1094* Initializes DFS range attributes (par, low, lim) over tree nodes such that:
1095* ND_par(n) - parent tree edge
1096* ND_low(n) - min DFS index for nodes in sub-tree (>= 1)
1097* ND_lim(n) - max DFS index for nodes in sub-tree
1098*/
1099static int dfs_range_init(node_t *v, edge_t *par, int low) {
1100 int i, lim;
1101
1102 lim = low;
1103 ND_par(v) = par;
1104 ND_low(v) = low;
1105
1106 for (i = 0; ND_tree_out(v).list[i]; i++) {
1107 edge_t *e = ND_tree_out(v).list[i];
1108 if (e != par) {
1109 lim = dfs_range_init(aghead(e), e, lim);
1110 }
1111 }
1112
1113 for (i = 0; ND_tree_in(v).list[i]; i++) {
1114 edge_t *e = ND_tree_in(v).list[i];
1115 if (e != par) {
1116 lim = dfs_range_init(agtail(e), e, lim);
1117 }
1118 }
1119
1120 ND_lim(v) = lim;
1121
1122 return lim + 1;
1123}
1124
1125/*
1126 * Incrementally updates DFS range attributes
1127 */
1128static int dfs_range(node_t * v, edge_t * par, int low)
1129{
1130 edge_t *e;
1131 int i, lim;
1132
1133 if (ND_par(v) == par && ND_low(v) == low) {
1134 return ND_lim(v) + 1;
1135 }
1136
1137 lim = low;
1138 ND_par(v) = par;
1139 ND_low(v) = low;
1140 for (i = 0; (e = ND_tree_out(v).list[i]); i++)
1141 if (e != par)
1142 lim = dfs_range(aghead(e), e, lim);
1143 for (i = 0; (e = ND_tree_in(v).list[i]); i++)
1144 if (e != par)
1145 lim = dfs_range(agtail(e), e, lim);
1146 ND_lim(v) = lim;
1147 return lim + 1;
1148}
1149
1150#ifdef DEBUG
1151void tchk(void)
1152{
1153 int i;
1154 node_t *n;
1155 edge_t *e;
1156
1157 size_t n_cnt = 0;
1158 size_t e_cnt = 0;
1159 for (n = agfstnode(G); n; n = agnxtnode(G, n)) {
1160 n_cnt++;
1161 for (i = 0; (e = ND_tree_out(n).list[i]); i++) {
1162 e_cnt++;
1163 if (SLACK(e) > 0)
1164 fprintf(stderr, "not a tight tree %p", e);
1165 }
1166 }
1167 if (n_cnt != Tree_node.size || e_cnt != Tree_edge.size)
1168 fprintf(stderr, "something missing\n");
1169}
1170
1171void check_fast_node(node_t * n)
1172{
1173 node_t *nptr;
1174 nptr = GD_nlist(agraphof(n));
1175 while (nptr && nptr != n)
1176 nptr = ND_next(nptr);
1177 assert(nptr != NULL);
1178}
1179
1180static void dump_node(FILE *sink, node_t *n) {
1181 if (ND_node_type(n)) {
1182 fprintf(sink, "%p", n);
1183 }
1184 else
1185 fputs(agnameof(n), sink);
1186}
1187
1188static void dump_graph (graph_t* g)
1189{
1190 int i;
1191 edge_t *e;
1192 node_t *n,*w;
1193 FILE* fp = fopen ("ns.gv", "w");
1194 fprintf (fp, "digraph \"%s\" {\n", agnameof(g));
1195 for (n = GD_nlist(g); n; n = ND_next(n)) {
1196 fputs(" \"", fp);
1197 dump_node(fp, n);
1198 fputs("\"\n", fp);
1199 }
1200 for (n = GD_nlist(g); n; n = ND_next(n)) {
1201 for (i = 0; (e = ND_out(n).list[i]); i++) {
1202 fputs(" \"", fp);
1203 dump_node(fp, n);
1204 fputs("\"", fp);
1205 w = aghead(e);
1206 fputs(" -> \"", fp);
1207 dump_node(fp, w);
1208 fputs("\"\n", fp);
1209 }
1210 }
1211
1212 fprintf (fp, "}\n");
1213 fclose (fp);
1214}
1215
1216static node_t *checkdfs(graph_t* g, node_t * n)
1217{
1218 edge_t *e;
1219 node_t *w,*x;
1220 int i;
1221
1222 if (ND_mark(n))
1223 return 0;
1224 ND_mark(n) = true;
1225 ND_onstack(n) = true;
1226 for (i = 0; (e = ND_out(n).list[i]); i++) {
1227 w = aghead(e);
1228 if (ND_onstack(w)) {
1229 dump_graph (g);
1230 fprintf(stderr, "cycle: last edge %lx %s(%lx) %s(%lx)\n",
1231 (uint64_t)e,
1232 agnameof(n), (uint64_t)n,
1233 agnameof(w), (uint64_t)w);
1234 return w;
1235 }
1236 else {
1237 if (!ND_mark(w)) {
1238 x = checkdfs(g, w);
1239 if (x) {
1240 fprintf(stderr,"unwind %lx %s(%lx)\n",
1241 (uint64_t)e,
1242 agnameof(n), (uint64_t)n);
1243 if (x != n) return x;
1244 fprintf(stderr,"unwound to root\n");
1245 fflush(stderr);
1246 abort();
1247 return 0;
1248 }
1249 }
1250 }
1251 }
1252 ND_onstack(n) = false;
1253 return 0;
1254}
1255
1256void check_cycles(graph_t * g)
1257{
1258 node_t *n;
1259 for (n = GD_nlist(g); n; n = ND_next(n)) {
1260 ND_mark(n) = false;
1261 ND_onstack(n) = false;
1262 }
1263 for (n = GD_nlist(g); n; n = ND_next(n))
1264 checkdfs(g, n);
1265}
1266#endif /* DEBUG */
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
#define right(i)
Definition closest.c:77
#define NORMAL
Definition const.h:24
static char * err
Definition delaunay.c:746
#define left
Definition dthdr.h:12
void error(int level, const char *s,...)
Definition error.c:83
static NORETURN void graphviz_exit(int status)
Definition exit.h:23
static tctype tchk[][2]
Definition gdefs.h:87
static int Verbose
Definition gml2gv.c:22
void free(void *)
#define SIZE_MAX
Definition gmlscan.c:347
node NULL
Definition grammar.y:149
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:199
char * agget(void *obj, char *name)
Definition attr.c:442
#define ED_tree_index(e)
Definition types.h:600
#define ED_minlen(e)
Definition types.h:592
#define agtail(e)
Definition cgraph.h:889
#define ED_weight(e)
Definition types.h:603
#define ED_cutvalue(e)
Definition types.h:581
#define aghead(e)
Definition cgraph.h:890
void agerrorf(const char *fmt,...)
Definition agerror.c:165
int agerr(agerrlevel_t level, const char *fmt,...)
Definition agerror.c:155
@ AGPREV
Definition cgraph.h:858
#define GD_nlist(g)
Definition types.h:393
#define ND_tree_in(n)
Definition types.h:533
#define ND_rank(n)
Definition types.h:523
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_lim(n)
Definition types.h:504
#define ND_next(n)
Definition types.h:510
#define ND_par(n)
Definition types.h:518
#define ND_node_type(n)
Definition types.h:511
#define ND_tree_out(n)
Definition types.h:534
#define ND_low(n)
Definition types.h:505
#define ND_in(n)
Definition types.h:501
#define ND_out(n)
Definition types.h:515
#define ND_priority(n)
Definition types.h:522
Agraph_t * agraphof(void *obj)
Definition obj.c:184
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:158
@ tree
Definition gvgen.c:33
#define ND_onstack(n)
Definition acyclic.c:29
#define ND_mark(n)
Definition acyclic.c:28
#define delta
Definition maze.c:133
NEATOPROCS_API void s1(graph_t *, node_t *)
Definition stuff.c:671
static void freeTreeList(graph_t *g)
Definition ns.c:694
static int update(edge_t *e, edge_t *f)
Definition ns.c:624
static int x_val(edge_t *e, node_t *v, int dir)
Definition ns.c:1040
static size_t S_i
Definition ns.c:46
static void init_cutvalues(void)
Definition ns.c:287
static nlist_t Tree_node
Definition ns.c:49
static subtree_t * STextractmin(STheap_t *heap)
Definition ns.c:463
static int feasible_tree(void)
Definition ns.c:531
int rank(graph_t *g, int balance, int maxiter)
Definition ns.c:997
#define SEARCHSIZE
Definition ns.c:48
static int dfs_range_init(node_t *v, edge_t *par, int low)
Definition ns.c:1099
static subtree_t * merge_trees(Agedge_t *e)
Definition ns.c:497
static int dfs_range(node_t *v, edge_t *par, int low)
Definition ns.c:1128
static void reset_lists(void)
Definition ns.c:684
static void TB_balance(void)
Definition ns.c:772
static void dfs_enter_inedge(node_t *v)
Definition ns.c:241
static int Lim
Definition ns.c:217
static int increasingrankcmpf(const void *x, const void *y)
Definition ns.c:750
static subtree_t * find_tight_subtree(Agnode_t *v)
Definition ns.c:340
static void dfs_cutval(node_t *v, edge_t *par)
Definition ns.c:1078
static bool on_heap(const subtree_t *tree)
is this subtree stored in an STheap?
Definition ns.c:306
static bool init_graph(graph_t *g)
Definition ns.c:850
struct STheap_s STheap_t
static size_t STheapsize(const STheap_t *heap)
Definition ns.c:429
static STheap_t * STbuildheap(subtree_t **elt, size_t size)
Definition ns.c:452
static edge_t * enter_edge(edge_t *e)
Definition ns.c:263
static int decreasingrankcmpf(const void *x, const void *y)
Definition ns.c:728
static graph_t * G
Definition ns.c:44
static void init_rank(void)
Definition ns.c:147
#define SEQ(a, b, c)
Definition ns.c:41
static int scan_and_normalize(void)
Definition ns.c:667
static size_t N_edges
Definition ns.c:45
#define ND_subtree_set(n, value)
Definition ns.c:296
#define TREE_EDGE(e)
Definition ns.c:42
static Agnode_t * treeupdate(Agnode_t *v, Agnode_t *w, int cutvalue, int dir)
Definition ns.c:583
static int Slack
Definition ns.c:217
static void graphSize(graph_t *g, int *nn, int *ne)
Definition ns.c:890
#define ND_subtree(n)
Definition ns.c:295
static subtree_t * STsetFind(Agnode_t *n0)
Definition ns.c:359
static void rerank(Agnode_t *v, int delta)
Definition ns.c:606
static void LR_balance(void)
Definition ns.c:705
static size_t N_nodes
Definition ns.c:45
struct subtree_s subtree_t
static void x_cutval(edge_t *f)
Definition ns.c:1011
static int add_tree_edge(edge_t *e)
Definition ns.c:52
static Agedge_t * inter_tree_edge_search(Agnode_t *v, Agnode_t *from, Agedge_t *best)
Definition ns.c:389
static void exchange_tree_edges(edge_t *e, edge_t *f)
Definition ns.c:114
static elist Tree_edge
Definition ns.c:50
static edge_t * leave_edge(void)
Definition ns.c:180
static edge_t * Enter
Definition ns.c:216
static void invalidate_path(node_t *lca, node_t *to_node)
Definition ns.c:90
static void tree_adjust(Agnode_t *v, Agnode_t *from, int delta)
Definition ns.c:478
#define SLACK(e)
Definition ns.c:40
static subtree_t * STsetUnion(subtree_t *s0, subtree_t *s1)
Definition ns.c:369
static int tight_subtree_search(Agnode_t *v, subtree_t *st)
Definition ns.c:311
static int Search_size
Definition ns.c:47
static void STheapify(STheap_t *heap, size_t i)
Definition ns.c:431
int rank2(graph_t *g, int balance, int maxiter, int search_size)
Definition ns.c:919
static int Low
Definition ns.c:217
static void dfs_enter_outedge(node_t *v)
Definition ns.c:219
static Agedge_t * inter_tree_edge(subtree_t *tree)
Definition ns.c:422
arithmetic overflow helpers
static bool sadd_overflow(int a, int b, int *res)
Definition overflow.h:21
#define PRISIZE_T
PRIu64 alike for printing size_t
Definition prisize_t.h:27
generic first-in-first-out buffer (queue)
static queue_t queue_new(size_t hint)
Definition queue.h:39
static void queue_free(queue_t *q)
Definition queue.h:108
static void queue_push(queue_t *q, void *item)
Definition queue.h:52
static void * queue_pop(queue_t *q)
Definition queue.h:90
static int nedges
total no. of edges used in routing
Definition routespl.c:31
static bool streq(const char *a, const char *b)
are a and b equal?
Definition streq.h:11
graph or subgraph
Definition cgraph.h:425
Definition ns.c:354
size_t size
Definition ns.c:356
subtree_t ** elt
Definition ns.c:355
Definition types.h:251
edge_t ** list
Definition types.h:252
size_t size
Definition types.h:253
node_t ** list
Definition types.h:247
size_t size
Definition types.h:248
node_t * rep
Definition ns.c:299
struct subtree_s * par
Definition ns.c:302
size_t heap_index
required to find non-min elts when merged
Definition ns.c:301
int size
Definition ns.c:300
double elapsed_sec(void)
Definition timing.c:48
void start_timer(void)
Definition timing.c:43
#define free_list(L)
Definition types.h:272
Definition grammar.c:93
#define MAX(a, b)
Definition write.c:31