2 * Covpyright (c) 2016, 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;
245 if ((ret
= quiver_add_vertex(out_qend
, 0, a
.v
[j
].name
,
246 a
.v
[j
].fatness
, 0, 0,
248 fprintf(stderr
, "%s\n", errstr
);
252 for (size_t k
= 0; k
< b
.v_num
; ++k
) {
253 if (!(strcmp(b
.v
[k
].name
, a
.v
[j
].name
))) {
260 /* Add the edges in correct order */
261 for (size_t j
= 0; j
< a
.v_num
; ++j
) {
262 size_t tj
= a_to_start
[j
];
264 for (size_t k
= 0; k
< a
.v_num
; ++k
) {
265 size_t tk
= a_to_start
[k
];
266 size_t idx_o
= tj
* out_qstart
->v_len
+ tk
;
267 size_t idx_a
= j
* a
.v_len
+ k
;
269 out_qstart
->e
[idx_o
] = a
.e
[idx_a
];
273 for (size_t j
= 0; j
< b
.v_num
; ++j
) {
274 size_t tj
= b_to_end
[j
];
276 for (size_t k
= 0; k
< b
.v_num
; ++k
) {
277 size_t tk
= b_to_end
[k
];
278 size_t idx_o
= tj
* out_qend
->v_len
+ tk
;
279 size_t idx_b
= j
* b
.v_len
+ k
;
281 out_qend
->e
[idx_o
] = b
.e
[idx_b
];
299 int main(int argc
, char **argv
)
302 struct quiver q
= { 0 };
303 struct quiver qend
= { 0 };
306 char *start_file
= 0;
308 long start_len_l
= 0;
310 size_t start_len
= 0;
311 size_t max_len
= (size_t) -1;
312 size_t warn_level
= (size_t) -1;
313 struct rational
*target
= 0;
315 const char *errstr
= 0;
316 uint_fast8_t verbose
= 0;
318 setlocale(LC_ALL
, "");
321 for (int j
= 0; j
< argc
; ++j
) {
325 while ((opt
= getopt(argc
, argv
, "vhs:e:c:m:l:f:")) != -1) {
341 warn_level
= strtoll(optarg
, &p
, 0);
345 fprintf(stderr
, "Invalid edge cap: %s\n",
353 start_len_l
= strtoll(optarg
, &p
, 0);
355 if ((start_len_l
<= 0) ||
358 fprintf(stderr
, "Invalid start length: %s\n",
364 start_len
= start_len_l
;
367 max_len_l
= strtoll(optarg
, &p
, 0);
369 if ((max_len_l
<= 0) ||
372 fprintf(stderr
, "Invalid max length: %s\n",
381 frozen
[fidx
] = optarg
;
398 size_t num_nonfrozen
= 0;
400 if (setup(start_file
, end_file
, frozen
, fidx
, &q
, &qend
,
405 if (warn_level
== (size_t) -1) {
408 for (size_t k
= 0; k
< q
.v_num
; ++k
) {
409 if (warn_level
< q
.v
[k
].fatness
) {
410 warn_level
= q
.v
[k
].fatness
;
414 warn_level
= warn_level
+ 1;
417 if (warn_level
>= UINT_MAX
) {
418 warn_level
= UINT_MAX
- 1;
421 if ((ret
= quiver_set_warning_threshold(&q
, warn_level
, &errstr
))) {
422 fprintf(stderr
, "%s\n", errstr
);
426 /* Save off qend's vertices. XXX: Why not just USE qend? */
427 if (!(target
= malloc(sizeof *target
* qend
.v_num
* qend
.v_num
))) {
433 for (size_t i
= 0; i
< qend
.v_num
* qend
.v_num
; ++i
) {
434 target
[i
] = (struct rational
) { .p
= 0, .q
= 1 };
437 for (size_t i
= 0; i
< qend
.v_num
; ++i
) {
438 for (size_t j
= 0; j
< qend
.v_num
; ++j
) {
439 target
[i
* qend
.v_num
+ j
] = qend
.e
[i
* qend
.v_len
+ j
];
443 /* Now, the long haul*/
450 signal(SIGUSR1
, handle
);
454 uint_fast8_t correct
= 0;
456 while (len
< max_len
) {
458 size_t sequence
[len
];
460 for (size_t k
= 0; k
< len
; ++k
) {
461 /* This will get pruned, it's okay */
468 if (status_requested
) {
469 status_requested
= 0;
470 printf("Current sequence %s", q
.v
[sequence
[0]].name
);
472 for (size_t k
= 1; k
< len
; ++k
) {
473 printf(", %s", q
.v
[sequence
[k
]].name
);
481 * Here, we have computed a full sequence that we want
482 * to check. c_idx is in [0, len - 1], and the quiver
483 * has been mutated following the sequence up to (but
484 * not including) c_idx.
486 * This code is duplicated from increment_sequence
487 * because it is reasonable to start the whole process
488 * with a sequence that may, in fact, produce warnings.
492 while (c_idx
< len
) {
493 /* Prune duplicates (involutions) */
495 sequence
[c_idx
] == sequence
[c_idx
- 1]) {
496 goto increment_sequence
;
499 /* Proceed one more mutation */
500 quiver_mutate(&q
, sequence
[c_idx
], &warn
, 0);
503 /* That mutation caused a warning: skip it */
504 quiver_mutate(&q
, sequence
[c_idx
], &warn
, 0);
506 /* And try the sequence, starting at c_idx */
507 goto increment_sequence
;
511 * Skip ... X, Y ... when X > Y and the edge
512 * from X to Y is trivial
515 sequence
[c_idx
] < sequence
[c_idx
- 1]) {
516 size_t x
= sequence
[c_idx
- 1];
517 size_t y
= sequence
[c_idx
];
518 struct rational
*xy
= &(q
.e
[x
* q
.v_len
+ y
]);
519 struct rational
*yx
= &(q
.e
[y
* q
.v_len
+ x
]);
524 quiver_mutate(&q
, sequence
[c_idx
], 0,
527 /* And try the sequence, starting at c_idx */
528 goto increment_sequence
;
536 * Here, there's a full sequence, and the quiver has
537 * been mutated according to it (all of it). We want
538 * to check if the result matches the target.
542 for (size_t i
= 0; i
< q
.v_num
; ++i
) {
543 for (size_t j
= 0; j
< q
.v_num
; ++j
) {
544 struct rational
*e
= &(q
.e
[i
* q
.v_len
+ j
]);
545 struct rational
*f
= &(target
[i
* q
.v_num
+ j
]);
547 if (e
->p
* f
->q
!= f
->p
* e
->q
) {
556 printf("SEQUENCE: %s", q
.v
[sequence
[0]].name
);
558 for (size_t k
= 1; k
< len
; ++k
) {
559 printf(", %s", q
.v
[sequence
[k
]].name
);
567 quiver_mutate(&q
, sequence
[c_idx
], 0, 0);
571 * Here, we have some kind of sequence. The quiver agrees
572 * with it up to (but not including) c_idx, and we want
573 * to increment it at c_idx.
580 double completed
= sequence
[0] * num_nonfrozen
*
581 num_nonfrozen
+ sequence
[1] *
584 double total
= num_nonfrozen
* num_nonfrozen
*
587 printf("Length %zu: completed %.3g%%\n", len
, (100.0 *
593 /* Skip over repeats: each mutation is an involution */
595 sequence
[c_idx
] == sequence
[c_idx
- 1]) {
600 if (sequence
[c_idx
] >= num_nonfrozen
) {
606 quiver_mutate(&q
, sequence
[c_idx
], 0, 0);
607 goto increment_sequence
;
610 if (c_idx
!= len
- 1) {
612 * Here, we now have a start of a sequence.
613 * The quiver agrees with our start up to (but
614 * not including) c_idx, and we want to possibly
615 * complete this to a full sequence. First,
616 * however, we need to make sure that we don't
617 * introduce any warnings at c_idx.
619 * This single-mutation testing block could be
620 * ignored, but I have a vague suspicion it will
624 quiver_mutate(&q
, sequence
[c_idx
], &warn
, 0);
627 /* That mutation caused a warning: skip it */
628 quiver_mutate(&q
, sequence
[c_idx
], &warn
, 0);
630 /* And try the sequence, starting at c_idx */
631 goto increment_sequence
;
635 * Quivers almost commute: in particular if
636 * the edge v_i -> v_j is zero, then mutation
637 * at v_i and v_j commute. So if we're at X, Y
638 * in the list, and X > Y, then we've actually
639 * already computed that branch of the tree,
640 * back when it was Y, X. Therefore, increment X.
643 sequence
[c_idx
] < sequence
[c_idx
- 1]) {
644 size_t x
= sequence
[c_idx
- 1];
645 size_t y
= sequence
[c_idx
];
646 struct rational
*xy
= &(q
.e
[x
* q
.v_len
+ y
]);
647 struct rational
*yx
= &(q
.e
[y
* q
.v_len
+ x
]);
652 quiver_mutate(&q
, sequence
[c_idx
], 0,
655 /* And try the sequence, starting at c_idx */
656 goto increment_sequence
;
661 * Here the quiver agrees with our start up
662 * to and including c_idx, and we need to fill
663 * it out into a full sequence so that it can
664 * be tested. We don't need to perform all the
665 * mutations of that full sequence, but we do
666 * need to generate the minimal one.
668 for (size_t i
= c_idx
+ 1; i
< len
; ++i
) {
669 sequence
[i
] = 1 - !!((i
- c_idx
) % 2);
675 goto have_full_sequence
;
679 * Here, we have c_idx = 0, and the quiver has not been
680 * mutated by anything in sequence
682 printf("Exhausted length %zu\n", len
);