16 #define STR(x) STR2(x)
18 #define L(x) __FILE__ ":" STR(__LINE__) ": " x
19 #define SGN(x, y) (((x) < (y)) ? -1 : ((x) > (y) ? 1 : 0))
20 #define UNUSED(x) (void) (sizeof(x))
22 #define BOUNDARY_NODE ((node *) 0)
23 #define NODE_NAME(n) ((n) ? ((n)->name) : ("BOUNDARY"))
24 #define NODE_COLOR(n) ((n) ? ((n)->c) : (C_BOUNDARY))
26 typedef enum { C_BLACK
, C_WHITE
, C_BOUNDARY
} color
;
27 typedef enum { D_LEFT
, D_RIGHT
} dir
;
28 typedef enum { R_AWAY
, R_TO
} relative_dir
;
41 unsigned int fix_depth
;
52 add_new_node(graph
*g
,
63 if (n
> INT_MAX
/ 2) {
64 fprintf(stderr
, "Absurdly long node name\n");
68 if (!strncmp(s
, "BOUNDARY", n
) &&
70 fprintf(stderr
, "The node name `BOUNDARY' is forbidden\n");
74 for (p
= s
; p
< s
+ n
; ++p
) {
80 "Node names are not allowed to contain `[', "
86 for (j
= 0; j
< g
->nodes_num
; ++j
) {
87 if (!strncmp(s
, g
->nodes
[j
].name
, n
) &&
88 g
->nodes
[j
].name_len
== n
) {
89 fprintf(stderr
, "Duplicate node %s\n",
95 if (!(newmem
= realloc(g
->nodes
, (g
->nodes_num
+ 1) *
101 if (!(sd
= strndup(s
, n
+ 1))) {
102 perror(L("strndup"));
108 g
->nodes
[g
->nodes_num
] = (node
) { .name
= sd
, .name_len
= n
, .c
= c
};
120 add_new_edge(graph
*g
,
133 if (n1
> INT_MAX
/ 2 ||
135 fprintf(stderr
, "Absurdly long node name\n");
139 for (j
= 0; j
< g
->nodes_num
; ++j
) {
140 if (!strncmp(s1
, g
->nodes
[j
].name
, n1
) &&
141 g
->nodes
[j
].name_len
== n1
) {
147 for (j
= 0; j
< g
->nodes_num
; ++j
) {
148 if (!strncmp(s2
, g
->nodes
[j
].name
, n2
) &&
149 g
->nodes
[j
].name_len
== n2
) {
156 if (strncmp(s1
, "BOUNDARY", n1
) ||
158 fprintf(stderr
, "Unknown node `%.*s'\n", (int) n1
, s1
);
164 if (strncmp(s2
, "BOUNDARY", n2
) ||
166 fprintf(stderr
, "Unknown node `%.*s'\n", (int) n2
, s2
);
172 fprintf(stderr
, "Illegal node (%s, %s)\n", NODE_NAME(v1
),
177 for (j
= 0; j
< g
->edges_num
; ++j
) {
184 fprintf(stderr
, "Duplicate edge (%s, %s)\n", NODE_NAME(
185 e
->l
), NODE_NAME(e
->r
));
190 if (!(newmem
= realloc(g
->edges
, (g
->edges_num
+ 1) *
191 sizeof *g
->edges
))) {
192 perror(L("realloc"));
197 g
->edges
[g
->edges_num
] = (edge
) { .l
= v1
, .r
= v2
, .fix_depth
= -1 };
208 * Order edges first by their left component, then by their right
209 * component. This ensures that the edges representing boundary nodes
213 comp_edge(const void *a
,
216 edge
*pa
= (edge
*) a
;
217 edge
*pb
= (edge
*) b
;
232 d
= strcmp(pa
->l
->name
, pb
->l
->name
);
239 return strcmp(pa
->r
->name
, pb
->r
->name
);
243 * Returns the address of the first byte of a non-whitespace character
244 * beyond s, or 0 on error, or terminus on exhaustion.
247 next_wchar_of_certain_type(const char *s
,
248 const char *terminus
,
249 char want_whitespace
)
252 mbstate_t ps
= { 0 };
260 while (p
< terminus
) {
261 switch ((e
= mbrtowc(&wc
, p
, (terminus
- p
) + 1, &ps
))) {
264 perror(L("mbrtowc"));
274 if ((!!want_whitespace
== !!iswspace(wc
)) &&
287 read_file(const char *path
,
293 const char *contents_end
= 0;
302 if ((fd
= open(path
, O_RDONLY
)) < 0) {
307 if (fstat(fd
, &sb
) < 0) {
315 fprintf(stderr
, "File is not well-formed\n");
319 if ((contents
= mmap(0, length
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) ==
325 contents_end
= contents
+ (length
- 1);
327 if (!(p
= memchr(contents
, '[', length
)) ||
328 strncmp(p
, "[W]", 3)) {
329 fprintf(stderr
, "File does not contain `[W]' marker\n");
334 r
= memchr(q
, '[', contents_end
- q
);
337 strncmp(r
, "[B]", 3)) {
338 fprintf(stderr
, "File does not contain `[B]' marker\n");
342 p
= next_wchar_of_certain_type(q
, r
, 0);
343 q
= next_wchar_of_certain_type(p
, r
, 1);
348 if (add_new_node(g
, C_WHITE
, p
, q
- p
) < 0) {
353 p
= next_wchar_of_certain_type(q
, contents_end
, 0);
354 q
= next_wchar_of_certain_type(p
, contents_end
, 1);
358 r
= memchr(p
, '[', contents_end
- q
);
361 strncmp(r
, "[E]", 3)) {
362 fprintf(stderr
, "File does not contain `[E]' marker\n");
366 p
= next_wchar_of_certain_type(p
, r
, 0);
367 q
= next_wchar_of_certain_type(p
, r
, 1);
372 if (add_new_node(g
, C_BLACK
, p
, q
- p
) < 0) {
377 p
= next_wchar_of_certain_type(q
, contents_end
, 0);
378 q
= next_wchar_of_certain_type(p
, contents_end
, 1);
384 if (!(p
= memchr(s
, '(', contents_end
- s
))) {
388 if (!(p
= next_wchar_of_certain_type(p
, contents_end
, 0))) {
392 if (!(q
= next_wchar_of_certain_type(p
, contents_end
, 1))) {
396 if (!(r
= next_wchar_of_certain_type(q
, contents_end
, 0))) {
400 if (!(s
= next_wchar_of_certain_type(r
, contents_end
, 1))) {
404 if (!(t
= memchr(r
, ')', contents_end
- r
))) {
410 if (add_new_edge(g
, p
, q
- p
, r
, s
- r
) < 0) {
423 munmap(contents
, length
);
430 * Modify graph g so that all edges containing v point away from (to)
431 * node v when away==1 (0), except the specified exception edge. If a
432 * contradiction is encountered, *proven_wrong is set. If anything is
433 * done, *changed is set.
436 ensure_all_pointing_right_dir(graph
*g
,
453 for (j
= 0; j
< g
->edges_num
; ++j
) {
454 if ((e
= &g
->edges
[j
]) == except
) {
459 if (e
->fix_depth
<= depth
&&
460 e
->d
== (rd
== R_AWAY
? D_LEFT
: D_RIGHT
)) {
466 if (e
->fix_depth
> depth
) {
468 e
->fix_depth
= depth
;
469 e
->d
= (rd
== R_AWAY
? D_RIGHT
: D_LEFT
);
471 } else if (e
->r
== v
) {
472 if (e
->fix_depth
<= depth
&&
473 e
->d
== (rd
== R_AWAY
? D_RIGHT
: D_LEFT
)) {
479 if (e
->fix_depth
> depth
) {
481 e
->fix_depth
= depth
;
482 e
->d
= (rd
== R_AWAY
? D_LEFT
: D_RIGHT
);
489 * Check graph g to ensure that there is at least one edge containing
490 * v which is able to be set to point away from (to) node v when
491 * away==1 (0). If none is found, *proven_wrong is set. If exactly one
492 * is found, it is fixed with the appropriate depth and *changed is
496 ensure_one_left_to_point_right(graph
*g
,
513 for (j
= 0; j
< g
->edges_num
; ++j
) {
516 if (e
->fix_depth
<= depth
) {
518 e
->d
== (rd
== R_AWAY
? D_RIGHT
: D_LEFT
)) &&
520 e
->d
== (rd
== R_AWAY
? D_LEFT
: D_RIGHT
))) {
522 * Ignore fixed nodes that don't have
523 * right orientation and endpoint
529 * We don't just have a candidate, we have an
530 * actual fixed edge. Don't bother checking
531 * for the error case of two edges, or
532 * forcibly setting all other edges to the
533 * right direction, those actions are handled
534 * in ensure_all_pointing_right_dir().
537 } else if (e
->l
== v
||
542 * There are multiple candidates, so
543 * we can't set anything
554 * There's nothing that could save us - this
555 * configuration is impossible.
563 candidate
->fix_depth
= depth
;
565 if ((candidate
->l
== v
&&
567 (candidate
->r
== v
&&
569 candidate
->d
= D_RIGHT
;
571 candidate
->d
= D_LEFT
;
576 update_for_newly_fixed_edge(graph
*g
,
590 switch (NODE_COLOR(e
->l
)) {
592 ensure_all_pointing_right_dir(g
, e
->l
, R_AWAY
, depth
, e
,
593 changed
, proven_wrong
);
596 ensure_one_left_to_point_right(g
, e
->l
, R_AWAY
, depth
,
597 changed
, proven_wrong
);
607 switch (NODE_COLOR(e
->r
)) {
609 ensure_one_left_to_point_right(g
, e
->r
, R_TO
, depth
,
610 changed
, proven_wrong
);
613 ensure_all_pointing_right_dir(g
, e
->r
, R_TO
, depth
, e
,
614 changed
, proven_wrong
);
623 switch (NODE_COLOR(e
->l
)) {
625 ensure_one_left_to_point_right(g
, e
->l
, R_TO
, depth
,
626 changed
, proven_wrong
);
629 ensure_all_pointing_right_dir(g
, e
->l
, R_TO
, depth
, e
,
630 changed
, proven_wrong
);
640 switch (NODE_COLOR(e
->r
)) {
642 ensure_all_pointing_right_dir(g
, e
->r
, R_AWAY
, depth
, e
,
643 changed
, proven_wrong
);
646 ensure_one_left_to_point_right(g
, e
->r
, 1, depth
,
647 changed
, proven_wrong
);
658 * Repeatedly call update_for_newly_fixed_edge on all edges of a given
659 * depth, possibly fixing more choices of edge directions at that
663 update_to_fixed_point(graph
*g
,
666 char allow_scan_below_depth
)
676 for (j
= 0; j
< g
->edges_num
; ++j
) {
679 if (e
->fix_depth
== depth
||
680 (allow_scan_below_depth
&&
681 e
->fix_depth
<= depth
)) {
682 update_for_newly_fixed_edge(g
, e
, depth
,
690 admits_perfect_orientation(graph
*g
,
694 edge
*chosen_to_fix
= 0;
698 if (depth
>= (unsigned int) -3) {
699 fprintf(stderr
, "Absurd depth encountered - bailing\n");
704 for (j
= 0; j
< g
->edges_num
; ++j
) {
707 if (e
->fix_depth
> depth
) {
709 * In the case that some edges were tested
710 * before for other configurations, we wish to
711 * avoid the situation in which such a branch
712 * was tested at depth depth+1, and is not
713 * selected as the unfixed branch here. For
714 * then it would, in any speculation arising
715 * from this position, magically appear to be
716 * fixed, when it really should not be.
718 e
->fix_depth
= (unsigned int) -1;
724 chosen_to_fix
->d
= D_LEFT
;
727 * We start out at depth + 2 so that, if this doesn't
728 * work out, the ramifications will be nicely hidden
729 * by moving to only depth + 1 in the next step
731 chosen_to_fix
->fix_depth
= depth
+ 2;
732 update_to_fixed_point(g
, depth
+ 2, &broken
, 0);
735 admits_perfect_orientation(g
, depth
+ 2)) {
740 * Evidently setting that direction to LEFT resulted
741 * in a contradiction. So we may freely set it to
742 * RIGHT. We could really set the depth to `depth'
743 * here, but that doesn't really gain anything.
745 chosen_to_fix
->d
= D_RIGHT
;
746 chosen_to_fix
->fix_depth
= depth
+ 1;
748 update_to_fixed_point(g
, depth
+ 1, &broken
, 0);
751 admits_perfect_orientation(g
, depth
+ 1)) {
756 * There was a choice we could make, and each choice
757 * led to a contradiction.
763 * At this point, there's nothing we may choose. Just check
764 * whether our choices made sense.
766 for (j
= 0; j
< g
->nodes_num
; ++j
) {
767 g
->nodes
[j
].check_res
= 0;
770 for (j
= 0; j
< g
->edges_num
; ++j
) {
777 e
->l
->c
== C_WHITE
) {
784 e
->r
->c
== C_BLACK
) {
794 e
->l
->c
== C_BLACK
) {
801 e
->r
->c
== C_WHITE
) {
815 for (j
= 0; j
< g
->nodes_num
; ++j
) {
817 !g
->nodes
[j
].check_res
;
823 /*** REIMPLEMENTATION LINE ***/
833 size_t num_edge_nodes
= 0;
835 setlocale(LC_ALL
, "");
838 printf("Usage: %s INPUT_FILE\n", argv
[0]);
843 if (read_file(argv
[1], &g
) < 0) {
847 /* Tidy up the edges */
848 for (j
= 0; j
< g
.edges_num
; ++j
) {
857 strcmp(e
->l
->name
, e
->r
->name
) > 0) {
864 qsort(g
.edges
, g
.edges_num
, sizeof *g
.edges
, comp_edge
);
867 * Now all the border nodes (the 0s) are at the front - how
868 * many are there? While we're here, fix the boundary edges as
869 * LEFT at initial depth 0.
871 for (j
= 0; j
< g
.edges_num
; ++j
) {
879 e
->fix_depth
= (unsigned int) -1;
884 * Count upwards through the possible start source/sink
885 * configurations, in binary
888 for (j
= num_edge_nodes
; j
< g
.edges_num
; ++j
) {
889 g
.edges
[j
].fix_depth
= (unsigned int) -1;
893 update_to_fixed_point(&g
, 0, &broken
, 1);
896 admits_perfect_orientation(&g
, 1)) {
899 for (j
= 0; j
< num_edge_nodes
; ++j
) {
900 if (g
.edges
[j
].d
== D_LEFT
) {
901 printf("%s ", NODE_NAME(g
.edges
[j
].r
));
908 if (g
.edges
[0].d
== D_LEFT
) {
909 g
.edges
[0].d
= D_RIGHT
;
913 while (j
< num_edge_nodes
) {
914 if (g
.edges
[j
].d
== D_RIGHT
) {
915 g
.edges
[j
].d
= D_LEFT
;
917 g
.edges
[j
].d
= D_RIGHT
;
924 if (j
>= num_edge_nodes
) {
925 /* Must have tried all configurations */
933 for (j
= 0; j
< g
.nodes_num
; ++j
) {
934 free(g
.nodes
[j
].name
);