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