2 * Copyright (c) 2017, S. Gilles <sgilles@math.umd.edu>
4 * Permission to use, copy, modify, and/or distribute this software
5 * for any purpose with or without fee is hereby granted, provided
6 * that the above copyright notice and this permission notice appear
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS *ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING AL*L IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EV*ENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
14 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
31 /* Flag for whether to print info */
32 static volatile sig_atomic_t status_requested
= 0;
39 static void handle(int sig
)
41 /* XXX: I'd like to check for SIGINFO here */
49 static void usage(char *argv0
)
51 printf("Usage: %s -s <startfile> -e <endfile>\n", argv0
);
52 printf(" [ -v ] # Be verbose\n");
53 printf(" [ -c <edgecap> ]\n");
54 printf(" [ -f <frozen> [ -f <frozen> [...] ] ]\n");
55 printf(" [ -l <startlen> ] [ -m <maxlen> ]\n");
57 printf(" startfile: a quiver file representing the start "
59 printf(" endfile: a quiver file representing the desired end "
61 printf(" edgecap: ignore mutations if the cause edges with"
62 "weights above this\n");
63 printf(" startlen: start with sequences of this length\n");
64 printf(" maxlen: halt after exhausting sequences of this "
66 printf(" frozen: a vertex with this name will not be "
70 static int cmp(const void *a
, const void *b
)
72 struct vertex
**va
= (struct vertex
**) a
;
73 struct vertex
**vb
= (struct vertex
**) b
;
75 return strcmp((*va
)->name
, (*vb
)->name
);
78 /* Load start/end quivers, figure out frozen vertices, order things, etc. */
79 static int setup(char *start_file
, char *end_file
, char **frozen
, size_t
80 num_frozen
, struct quiver
*out_qstart
, struct quiver
*out_qend
,
81 size_t *out_num_nonfrozen
)
83 struct quiver a
= { 0 };
84 struct quiver b
= { 0 };
87 const char *errstr
= 0;
89 struct vertex
**averts
= 0;
90 struct vertex
**bverts
= 0;
91 size_t *a_to_start
= 0;
96 fprintf(stderr
, L("invalid quivers"));
101 if (out_qstart
->v_num
||
103 fprintf(stderr
, L("output quivers are not empty\n"));
108 if (!(fa
= fopen(start_file
, "r"))) {
114 if (!(fb
= fopen(end_file
, "r"))) {
120 if ((ret
= quiver_load_from_file(&a
, fa
, &errstr
))) {
121 fprintf(stderr
, "%s\n", errstr
);
125 if ((ret
= quiver_load_from_file(&b
, fb
, &errstr
))) {
126 fprintf(stderr
, "%s\n", errstr
);
130 if (a
.v_num
!= b
.v_num
) {
132 "Quivers do not have same number of vertices\n"));
138 * Make sure there are no duplicate vertices, but don't sort in
139 * place - that would change ordering, and ordering of vertices
140 * must match user input - tuning input so that known prefixes
141 * arise early is sometimes crucial.
143 if (!(averts
= malloc(a
.v_num
* sizeof(*averts
)))) {
149 if (!(bverts
= malloc(b
.v_num
* sizeof(*bverts
)))) {
155 for (size_t j
= 0; j
< a
.v_num
; ++j
) {
156 averts
[j
] = &(a
.v
[j
]);
157 bverts
[j
] = &(b
.v
[j
]);
160 qsort(averts
, a
.v_num
, sizeof(averts
[0]), cmp
);
161 qsort(bverts
, b
.v_num
, sizeof(bverts
[0]), cmp
);
163 for (size_t j
= 0; j
< a
.v_num
; ++j
) {
165 !strcmp(averts
[j
]->name
, averts
[j
- 1]->name
)) {
166 fprintf(stderr
, L("Duplicate vertex \"%s\"\n"),
172 int d
= strcmp(averts
[j
]->name
, bverts
[j
]->name
);
175 fprintf(stderr
, L("Vertex \"%s\" not in both files\n"),
182 fprintf(stderr
, L("Vertex \"%s\" not in both files\n"),
188 if (averts
[j
]->fatness
!= bverts
[j
]->fatness
) {
190 "Vertex \"%s\" has inconsistent fatness\n"),
197 /* a_to_s[i] = j <=> "vertex i in a is vertex j in out_qstart" */
198 if (!(a_to_start
= malloc(a
.v_num
* sizeof(*a_to_start
)))) {
204 if (!(b_to_end
= malloc(b
.v_num
* sizeof(*b_to_end
)))) {
211 * Order so that frozen vertices are all at the end - required
212 * for incrementation algorithm
214 for (uint_fast8_t want_frozen
= 0; want_frozen
<= 1; want_frozen
++) {
215 for (size_t j
= 0; j
< a
.v_num
; ++j
) {
216 uint_fast8_t is_frozen
= 0;
218 for (size_t k
= 0; k
< num_frozen
; ++k
) {
219 is_frozen
= is_frozen
||
220 !strcmp(a
.v
[j
].name
, frozen
[k
]);
227 if (is_frozen
!= want_frozen
) {
231 if ((ret
= quiver_add_vertex(out_qstart
,
234 a
.v
[j
].fatness
, 0, 0,
236 fprintf(stderr
, "%s\n", errstr
);
242 *out_num_nonfrozen
= a_to_start
[j
] + 1;
247 if ((ret
= quiver_add_vertex(out_qend
, &tj
, a
.v
[j
].name
,
248 a
.v
[j
].fatness
, 0, 0,
250 fprintf(stderr
, "%s\n", errstr
);
254 for (size_t k
= 0; k
< b
.v_num
; ++k
) {
255 if (!(strcmp(b
.v
[k
].name
,
256 out_qend
->v
[tj
].name
))) {
263 /* Add the edges in correct order */
264 for (size_t j
= 0; j
< a
.v_num
; ++j
) {
265 size_t tj
= a_to_start
[j
];
267 for (size_t k
= 0; k
< a
.v_num
; ++k
) {
268 size_t tk
= a_to_start
[k
];
269 size_t idx_o
= tj
* out_qstart
->v_len
+ tk
;
270 size_t idx_a
= j
* a
.v_len
+ k
;
272 out_qstart
->e
[idx_o
] = a
.e
[idx_a
];
276 for (size_t j
= 0; j
< b
.v_num
; ++j
) {
277 size_t tj
= b_to_end
[j
];
279 for (size_t k
= 0; k
< b
.v_num
; ++k
) {
280 size_t tk
= b_to_end
[k
];
281 size_t idx_o
= tj
* out_qend
->v_len
+ tk
;
282 size_t idx_b
= j
* b
.v_len
+ k
;
284 out_qend
->e
[idx_o
] = b
.e
[idx_b
];
302 int main(int argc
, char **argv
)
305 struct quiver q
= { 0 };
306 struct quiver qend
= { 0 };
309 char *start_file
= 0;
311 long start_len_l
= 0;
313 size_t start_len
= 0;
314 size_t max_len
= (size_t) -1;
315 size_t warn_level
= (size_t) -1;
316 struct rational
*target
= 0;
318 const char *errstr
= 0;
319 uint_fast8_t verbose
= 0;
321 setlocale(LC_ALL
, "");
324 for (int j
= 0; j
< argc
; ++j
) {
328 while ((opt
= getopt(argc
, argv
, "vhs:e:c:m:l:f:")) != -1) {
344 warn_level
= strtoll(optarg
, &p
, 0);
348 fprintf(stderr
, "Invalid edge cap: %s\n",
356 start_len_l
= strtoll(optarg
, &p
, 0);
358 if ((start_len_l
<= 0) ||
361 fprintf(stderr
, "Invalid start length: %s\n",
367 start_len
= start_len_l
;
370 max_len_l
= strtoll(optarg
, &p
, 0);
372 if ((max_len_l
<= 0) ||
375 fprintf(stderr
, "Invalid max length: %s\n",
384 frozen
[fidx
] = optarg
;
401 size_t num_nonfrozen
= 0;
403 if (setup(start_file
, end_file
, frozen
, fidx
, &q
, &qend
,
408 if (warn_level
== (size_t) -1) {
411 for (size_t k
= 0; k
< q
.v_num
; ++k
) {
412 if (warn_level
< q
.v
[k
].fatness
) {
413 warn_level
= q
.v
[k
].fatness
;
417 warn_level
= warn_level
+ 1;
420 if (warn_level
>= UINT_MAX
) {
421 warn_level
= UINT_MAX
- 1;
424 if ((ret
= quiver_set_warning_threshold(&q
, warn_level
, &errstr
))) {
425 fprintf(stderr
, "%s\n", errstr
);
429 /* Save off qend's vertices. XXX: Why not just USE qend? */
430 if (!(target
= malloc(sizeof *target
* qend
.v_num
* qend
.v_num
))) {
436 for (size_t i
= 0; i
< qend
.v_num
* qend
.v_num
; ++i
) {
437 target
[i
] = (struct rational
) { .p
= 0, .q
= 1 };
440 for (size_t i
= 0; i
< qend
.v_num
; ++i
) {
441 for (size_t j
= 0; j
< qend
.v_num
; ++j
) {
442 target
[i
* qend
.v_num
+ j
] = qend
.e
[i
* qend
.v_len
+ j
];
446 /* Now, the long haul*/
453 signal(SIGUSR1
, handle
);
457 uint_fast8_t correct
= 0;
459 while (len
< max_len
) {
461 size_t sequence
[len
];
463 for (size_t k
= 0; k
< len
; ++k
) {
464 /* This will get pruned, it's okay */
471 if (status_requested
) {
472 status_requested
= 0;
473 printf("Current sequence %s", q
.v
[sequence
[0]].name
);
475 for (size_t k
= 1; k
< len
; ++k
) {
476 printf(", %s", q
.v
[sequence
[k
]].name
);
484 * Here, we have computed a full sequence that we want
485 * to check. c_idx is in [0, len - 1], and the quiver
486 * has been mutated following the sequence up to (but
487 * not including) c_idx.
489 * This code is duplicated from increment_sequence
490 * because it is reasonable to start the whole process
491 * with a sequence that may, in fact, produce warnings.
495 while (c_idx
< len
) {
496 /* Prune duplicates (involutions) */
498 sequence
[c_idx
] == sequence
[c_idx
- 1]) {
499 goto increment_sequence
;
502 /* Proceed one more mutation */
503 quiver_mutate(&q
, sequence
[c_idx
], &warn
, 0);
506 /* That mutation caused a warning: skip it */
507 quiver_mutate(&q
, sequence
[c_idx
], &warn
, 0);
509 /* And try the sequence, starting at c_idx */
510 goto increment_sequence
;
514 * Skip ... X, Y ... when X > Y and the edge
515 * from X to Y is trivial
518 sequence
[c_idx
] < sequence
[c_idx
- 1]) {
519 size_t x
= sequence
[c_idx
- 1];
520 size_t y
= sequence
[c_idx
];
521 struct rational
*xy
= &(q
.e
[x
* q
.v_len
+ y
]);
522 struct rational
*yx
= &(q
.e
[y
* q
.v_len
+ x
]);
527 quiver_mutate(&q
, sequence
[c_idx
], 0,
530 /* And try the sequence, starting at c_idx */
531 goto increment_sequence
;
539 * Here, there's a full sequence, and the quiver has
540 * been mutated according to it (all of it). We want
541 * to check if the result matches the target.
545 for (size_t i
= 0; i
< q
.v_num
; ++i
) {
546 for (size_t j
= 0; j
< q
.v_num
; ++j
) {
547 struct rational
*e
= &(q
.e
[i
* q
.v_len
+ j
]);
548 struct rational
*f
= &(target
[i
* q
.v_num
+ j
]);
550 if (e
->p
* f
->q
!= f
->p
* e
->q
) {
559 printf("SEQUENCE: %s", q
.v
[sequence
[0]].name
);
561 for (size_t k
= 1; k
< len
; ++k
) {
562 printf(", %s", q
.v
[sequence
[k
]].name
);
570 quiver_mutate(&q
, sequence
[c_idx
], 0, 0);
574 * Here, we have some kind of sequence. The quiver agrees
575 * with it up to (but not including) c_idx, and we want
576 * to increment it at c_idx.
583 double completed
= sequence
[0] * num_nonfrozen
*
584 num_nonfrozen
+ sequence
[1] *
587 double total
= num_nonfrozen
* num_nonfrozen
*
590 printf("Length %zu: completed %.3g%%\n", len
, (100.0 *
596 /* Skip over repeats: each mutation is an involution */
598 sequence
[c_idx
] == sequence
[c_idx
- 1]) {
603 if (sequence
[c_idx
] >= num_nonfrozen
) {
609 quiver_mutate(&q
, sequence
[c_idx
], 0, 0);
610 goto increment_sequence
;
613 if (c_idx
!= len
- 1) {
615 * Here, we now have a start of a sequence.
616 * The quiver agrees with our start up to (but
617 * not including) c_idx, and we want to possibly
618 * complete this to a full sequence. First,
619 * however, we need to make sure that we don't
620 * introduce any warnings at c_idx.
622 * This single-mutation testing block could be
623 * ignored, but I have a vague suspicion it will
627 quiver_mutate(&q
, sequence
[c_idx
], &warn
, 0);
630 /* That mutation caused a warning: skip it */
631 quiver_mutate(&q
, sequence
[c_idx
], &warn
, 0);
633 /* And try the sequence, starting at c_idx */
634 goto increment_sequence
;
638 * Quivers almost commute: in particular if
639 * the edge v_i -> v_j is zero, then mutation
640 * at v_i and v_j commute. So if we're at X, Y
641 * in the list, and X > Y, then we've actually
642 * already computed that branch of the tree,
643 * back when it was Y, X. Therefore, increment X.
646 sequence
[c_idx
] < sequence
[c_idx
- 1]) {
647 size_t x
= sequence
[c_idx
- 1];
648 size_t y
= sequence
[c_idx
];
649 struct rational
*xy
= &(q
.e
[x
* q
.v_len
+ y
]);
650 struct rational
*yx
= &(q
.e
[y
* q
.v_len
+ x
]);
655 quiver_mutate(&q
, sequence
[c_idx
], 0,
658 /* And try the sequence, starting at c_idx */
659 goto increment_sequence
;
664 * Here the quiver agrees with our start up
665 * to and including c_idx, and we need to fill
666 * it out into a full sequence so that it can
667 * be tested. We don't need to perform all the
668 * mutations of that full sequence, but we do
669 * need to generate the minimal one.
671 for (size_t i
= c_idx
+ 1; i
< len
; ++i
) {
672 sequence
[i
] = 1 - !!((i
- c_idx
) % 2);
678 goto have_full_sequence
;
682 * Here, we have c_idx = 0, and the quiver has not been
683 * mutated by anything in sequence
685 printf("Exhausted length %zu\n", len
);