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