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