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