2 * Copyright (c) 2016-2019, 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 ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT 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;
35 static void handle(int sig
);
41 /* XXX: I'd like to check for SIGINFO here */
52 printf("Usage: %s -s <startfile> -e <endfile>\n", argv0
);
53 printf(" [ -v ] # Be verbose\n");
54 printf(" [ -R ] # Require all non-frozen in sequence\n");
55 printf(" [ -H ] # Test via graph heuristics, not exactness\n");
56 printf(" [ -c <edgecap> ]\n");
57 printf(" [ -f <frozen> [ -f <frozen> [...] ] ]\n");
58 printf(" [ -l <startlen> ] [ -m <maxlen> ]\n");
60 printf(" startfile: a quiver file representing the start "
62 printf(" endfile: a quiver file representing the desired end "
64 printf(" edgecap: ignore mutations if the cause edges with"
65 "weights above this\n");
66 printf(" startlen: start with sequences of this length\n");
67 printf(" maxlen: halt after exhausting sequences of this "
69 printf(" frozen: a vertex with this name will not be "
74 cmp(const void *a
, const void *b
)
76 struct vertex
**va
= (struct vertex
**) a
;
77 struct vertex
**vb
= (struct vertex
**) b
;
79 return strcmp((*va
)->name
, (*vb
)->name
);
82 /* This one just counts the number of edges */
84 dumb_checksum1(struct quiver
const * const q
)
87 struct rational
*r
= 0;
88 struct rational
*s
= 0;
90 for (size_t j
= 0; j
< q
->v_num
; ++j
) {
91 for (size_t k
= 0; k
< j
; ++k
) {
92 r
= &q
->e
[j
* q
->v_len
+ k
];
93 s
= &q
->e
[k
* q
->v_len
+ j
];
105 /* This one counts the number of each p and q */
107 dumb_checksum2(struct quiver
const * const q
)
110 struct rational
*r
= 0;
111 struct rational
*s
= 0;
112 size_t by_p
[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
113 size_t by_q
[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
115 for (size_t j
= 0; j
< q
->v_num
; ++j
) {
116 for (size_t k
= 0; k
< q
->v_num
; ++k
) {
117 r
= &q
->e
[j
* q
->v_len
+ k
];
118 s
= &q
->e
[k
* q
->v_len
+ j
];
119 by_p
[(((4 + r
->p
) % 8) + 8) % 8]++;
121 by_p
[(((4 + s
->p
) % 8) + 8) % 8]++;
126 c
= 8 * 0 + by_p
[0] + 4 * by_q
[0];
127 c
= 8 * c
+ by_p
[1] + 4 * by_q
[1];
128 c
= 8 * c
+ by_p
[2] + 4 * by_q
[2];
129 c
= 8 * c
+ by_p
[3] + 4 * by_q
[3];
130 c
= 8 * c
+ by_p
[4] + 4 * by_q
[4];
131 c
= 8 * c
+ by_p
[5] + 4 * by_q
[5];
132 c
= 8 * c
+ by_p
[6] + 4 * by_q
[6];
133 c
= 8 * c
+ by_p
[7] + 4 * by_q
[7];
138 /* This one counts the number of vertices of each valence */
140 dumb_checksum3(struct quiver
const * const q
)
143 struct rational
*r
= 0;
144 struct rational
*s
= 0;
145 size_t by_v
[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
147 for (size_t j
= 0; j
< q
->v_num
; ++j
) {
150 for (size_t k
= 0; k
< q
->v_num
; ++k
) {
151 r
= &q
->e
[j
* q
->v_len
+ k
];
152 s
= &q
->e
[k
* q
->v_len
+ j
];
160 by_v
[v
% 8] += (1 << q
->v
[j
].fatness
);
175 /* This one counts the valence types (in/out/frozen/non-frozen) mod 4 */
177 dumb_checksum4(struct quiver
const * const q
, size_t num_nonfrozen
)
180 struct rational
*r
= 0;
181 size_t by_i
[4] = { 0, 0, 0, 0 };
182 size_t by_o
[4] = { 0, 0, 0, 0 };
183 size_t by_n
[4] = { 0, 0, 0, 0 };
184 size_t by_f
[4] = { 0, 0, 0, 0 };
186 for (size_t j
= 0; j
< q
->v_num
; ++j
) {
192 for (size_t k
= 0; k
< q
->v_num
; ++k
) {
193 r
= &q
->e
[j
* q
->v_len
+ k
];
197 } else if (r
->p
< 0) {
203 if (j
>= num_nonfrozen
&&
204 k
>= num_nonfrozen
) {
206 } else if (j
< num_nonfrozen
&&
212 by_i
[v_i
% 4] += (1 << q
->v
[j
].fatness
);
213 by_o
[v_o
% 4] += (1 << q
->v
[j
].fatness
);
214 by_n
[v_n
% 4] += (1 << q
->v
[j
].fatness
);
215 by_f
[v_f
% 4] += (1 << q
->v
[j
].fatness
);
220 for (size_t j
= 0; j
< 4; ++j
) {
222 c
= c
+ by_i
[j
] + 4 * (by_o
[j
] + 4 * (by_n
[j
] + 4 * by_f
[j
]));
228 /* This one counts number of floor(p*6/q) */
230 dumb_checksum5(struct quiver
const * const q
)
233 struct rational
*r
= 0;
234 struct rational
*s
= 0;
235 size_t by_e
[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
237 for (size_t j
= 0; j
< q
->v_num
; ++j
) {
238 for (size_t k
= 0; k
< q
->v_num
; ++k
) {
239 r
= &q
->e
[j
* q
->v_len
+ k
];
240 s
= &q
->e
[k
* q
->v_len
+ j
];
241 by_e
[(((((r
->p
* 6) / r
->q
) + 3) % 16) + 16) % 16]++;
242 by_e
[(((((s
->p
* 6) / s
->q
) + 3) % 16) + 16) % 16]++;
258 /* This one computes rk(H_1(G)), so actually takes some effort */
260 dumb_checksum6(struct quiver
const *q
, int oriented
)
263 uint_fast8_t *touched
= 0;
264 size_t *frontier1
= 0;
265 size_t *frontier2
= 0;
269 * This DFS implementation is absolute garbage, for the
270 * sake of simplicity over speed. It's not in a hot path,
273 if (!(touched
= calloc(q
->v_num
, sizeof *touched
))) {
277 if (!(frontier1
= calloc(q
->v_num
+ 1, sizeof *frontier1
))) {
281 if (!(frontier2
= calloc(q
->v_num
+ 1, sizeof *frontier2
))) {
285 for (size_t k
= 0; k
<= q
->v_num
; ++k
) {
286 frontier1
[k
] = (size_t) -1;
287 frontier2
[k
] = (size_t) -1;
290 for (size_t j
= 0; j
< q
->v_num
; ++j
) {
291 int need_another_pass
= 1;
299 frontier1
[1] = (size_t) -1;
301 while (need_another_pass
) {
304 need_another_pass
= 0;
306 for (size_t k
= 0; k
< q
->v_num
; ++k
) {
307 size_t kidx
= frontier1
[k
];
309 if (kidx
== (size_t) -1) {
315 for (size_t l
= 0; l
< q
->v_num
; ++l
) {
320 struct rational
*e
= &q
->e
[kidx
*
323 struct rational
*f
= &q
->e
[l
*
337 need_another_pass
= 1;
345 frontier1
= frontier2
;
351 * Note that r is not actually the rank in the non-oriented
352 * case. We've double-counted every edge exactly once. No
353 * matter, we only care about using this as an invariant.
363 /* Load start/end quivers, figure out frozen vertices, order things, etc. */
365 setup(char *start_file
, char *end_file
, char **frozen
, size_t num_frozen
, struct
366 quiver
*out_qstart
, struct quiver
*out_qend
, size_t *out_num_nonfrozen
)
368 struct quiver a
= { 0 };
369 struct quiver b
= { 0 };
372 const char *errstr
= 0;
374 struct vertex
**averts
= 0;
375 struct vertex
**bverts
= 0;
376 size_t *a_to_start
= 0;
377 size_t *b_to_end
= 0;
381 fprintf(stderr
, L("invalid quivers"));
386 if (out_qstart
->v_num
||
388 fprintf(stderr
, L("output quivers are not empty\n"));
393 if (!(fa
= fopen(start_file
, "r"))) {
396 fprintf(stderr
, "cannot open file %s\n", start_file
);
400 if (!(fb
= fopen(end_file
, "r"))) {
403 fprintf(stderr
, "cannot open file %s\n", end_file
);
407 if ((ret
= quiver_load_from_file(&a
, fa
, &errstr
))) {
408 fprintf(stderr
, "%s\n", errstr
);
412 if ((ret
= quiver_load_from_file(&b
, fb
, &errstr
))) {
413 fprintf(stderr
, "%s\n", errstr
);
417 if (a
.v_num
!= b
.v_num
) {
419 "Quivers do not have same number of vertices\n"));
425 * Make sure there are no duplicate vertices, but don't sort in
426 * place - that would change ordering, and ordering of vertices
427 * must match user input - tuning input so that known prefixes
428 * arise early is sometimes crucial.
430 if (!(averts
= calloc(a
.v_num
, sizeof *averts
))) {
436 if (!(bverts
= calloc(b
.v_num
, sizeof *bverts
))) {
442 for (size_t j
= 0; j
< a
.v_num
; ++j
) {
443 averts
[j
] = &(a
.v
[j
]);
444 bverts
[j
] = &(b
.v
[j
]);
447 qsort(averts
, a
.v_num
, sizeof(averts
[0]), cmp
);
448 qsort(bverts
, b
.v_num
, sizeof(bverts
[0]), cmp
);
450 for (size_t j
= 0; j
< a
.v_num
; ++j
) {
452 !strcmp(averts
[j
]->name
, averts
[j
- 1]->name
)) {
453 fprintf(stderr
, L("Duplicate vertex \"%s\"\n"),
459 int d
= strcmp(averts
[j
]->name
, bverts
[j
]->name
);
462 fprintf(stderr
, L("Vertex \"%s\" not in both files\n"),
469 fprintf(stderr
, L("Vertex \"%s\" not in both files\n"),
475 if (averts
[j
]->fatness
!= bverts
[j
]->fatness
) {
477 "Vertex \"%s\" has inconsistent fatness\n"),
484 /* a_to_s[i] = j <=> "vertex i in a is vertex j in out_qstart" */
485 if (!(a_to_start
= calloc(a
.v_num
, sizeof(*a_to_start
)))) {
491 if (!(b_to_end
= calloc(b
.v_num
, sizeof(*b_to_end
)))) {
498 * Order so that frozen vertices are all at the end - required
499 * for incrementation algorithm
501 for (uint_fast8_t want_frozen
= 0; want_frozen
<= 1; want_frozen
++) {
502 for (size_t j
= 0; j
< a
.v_num
; ++j
) {
503 uint_fast8_t is_frozen
= 0;
505 for (size_t k
= 0; k
< num_frozen
; ++k
) {
506 is_frozen
= is_frozen
||
507 !strcmp(a
.v
[j
].name
, frozen
[k
]);
514 if (is_frozen
!= want_frozen
) {
518 if ((ret
= quiver_add_vertex(out_qstart
,
521 a
.v
[j
].fatness
, 0, 0, 0,
523 fprintf(stderr
, "%s\n", errstr
);
529 *out_num_nonfrozen
= a_to_start
[j
] + 1;
534 if ((ret
= quiver_add_vertex(out_qend
, &tj
, a
.v
[j
].name
,
535 a
.v
[j
].fatness
, 0, 0, 0,
537 fprintf(stderr
, "%s\n", errstr
);
541 for (size_t k
= 0; k
< b
.v_num
; ++k
) {
542 if (!(strcmp(b
.v
[k
].name
,
543 out_qend
->v
[tj
].name
))) {
550 /* Add the edges in correct order */
551 for (size_t j
= 0; j
< a
.v_num
; ++j
) {
552 size_t tj
= a_to_start
[j
];
554 for (size_t k
= 0; k
< a
.v_num
; ++k
) {
555 size_t tk
= a_to_start
[k
];
556 size_t idx_o
= tj
* out_qstart
->v_len
+ tk
;
557 size_t idx_a
= j
* a
.v_len
+ k
;
559 out_qstart
->e
[idx_o
] = a
.e
[idx_a
];
563 for (size_t j
= 0; j
< b
.v_num
; ++j
) {
564 size_t tj
= b_to_end
[j
];
566 for (size_t k
= 0; k
< b
.v_num
; ++k
) {
567 size_t tk
= b_to_end
[k
];
568 size_t idx_o
= tj
* out_qend
->v_len
+ tk
;
569 size_t idx_b
= j
* b
.v_len
+ k
;
571 out_qend
->e
[idx_o
] = b
.e
[idx_b
];
597 main(int argc
, char **argv
)
600 struct quiver q
= { 0 };
601 struct quiver qend
= { 0 };
604 char *start_file
= 0;
606 long start_len_l
= 0;
608 size_t start_len
= 0;
609 size_t max_len
= (size_t) -1;
610 size_t warn_level
= (size_t) -1;
611 struct rational
*target
= 0;
613 const char *errstr
= 0;
614 uint_fast8_t verbose
= 0;
615 uint_fast8_t require_all_nonfrozen
= 0;
616 uint_fast8_t check_heuristics_only
= 0;
617 int *seen_in_seq
= 0;
618 uint_fast8_t desired_dumb_checksum1
= 0;
619 uint64_t desired_dumb_checksum2
= 0;
620 uint64_t desired_dumb_checksum3
= 0;
621 uint64_t desired_dumb_checksum4
= 0;
622 uint64_t desired_dumb_checksum5
= 0;
623 uint8_t desired_dumb_checksum6u
= 0;
624 uint8_t desired_dumb_checksum6o
= 0;
625 uint_fast8_t this_dumb_checksum1
= 0;
626 uint64_t this_dumb_checksum2
= 0;
627 uint64_t this_dumb_checksum3
= 0;
628 uint64_t this_dumb_checksum4
= 0;
629 uint64_t this_dumb_checksum5
= 0;
630 uint8_t this_dumb_checksum6u
= 0;
631 uint8_t this_dumb_checksum6o
= 0;
633 setlocale(LC_ALL
, "");
636 for (int j
= 0; j
< argc
; ++j
) {
640 while ((opt
= getopt(argc
, argv
, "vhRHs:e:c:m:l:f:")) != -1) {
650 require_all_nonfrozen
= 1;
653 check_heuristics_only
= 1;
662 warn_level
= strtoll(optarg
, &p
, 0);
666 fprintf(stderr
, "Invalid edge cap: %s\n",
674 start_len_l
= strtoll(optarg
, &p
, 0);
676 if ((start_len_l
<= 0) ||
679 fprintf(stderr
, "Invalid start length: %s\n",
685 start_len
= start_len_l
;
688 max_len_l
= strtoll(optarg
, &p
, 0);
690 if ((max_len_l
<= 0) ||
693 fprintf(stderr
, "Invalid max length: %s\n",
702 frozen
[fidx
] = optarg
;
719 size_t num_nonfrozen
= 0;
721 if (setup(start_file
, end_file
, frozen
, fidx
, &q
, &qend
,
726 if (warn_level
== (size_t) -1) {
729 for (size_t k
= 0; k
< q
.v_num
; ++k
) {
730 if (warn_level
< q
.v
[k
].fatness
) {
731 warn_level
= q
.v
[k
].fatness
;
735 warn_level
= warn_level
+ 1;
738 if (warn_level
>= UINT_MAX
) {
739 warn_level
= UINT_MAX
- 1;
742 if ((ret
= quiver_set_warning_threshold(&q
, warn_level
, &errstr
))) {
743 fprintf(stderr
, "%s\n", errstr
);
747 /* Save off qend's vertices. XXX: Why not just USE qend? */
748 if ((qend
.v_num
* qend
.v_num
) / qend
.v_num
!= qend
.v_num
) {
749 /* Should never happen - isn't qend.v_num capped? */
750 ret
= errno
= EOVERFLOW
;
755 if (!(target
= calloc(qend
.v_num
* qend
.v_num
, sizeof *target
))) {
761 if (!(seen_in_seq
= calloc(qend
.v_num
+ 1, sizeof *seen_in_seq
))) {
767 for (size_t i
= 0; i
< qend
.v_num
* qend
.v_num
; ++i
) {
768 target
[i
] = (struct rational
) { .p
= 0, .q
= 1 };
771 for (size_t i
= 0; i
< qend
.v_num
; ++i
) {
772 for (size_t j
= 0; j
< qend
.v_num
; ++j
) {
773 target
[i
* qend
.v_num
+ j
] = qend
.e
[i
* qend
.v_len
+ j
];
777 if (check_heuristics_only
) {
778 desired_dumb_checksum1
= dumb_checksum1(&qend
);
779 desired_dumb_checksum2
= dumb_checksum2(&qend
);
780 desired_dumb_checksum3
= dumb_checksum3(&qend
);
781 desired_dumb_checksum4
= dumb_checksum4(&qend
, num_nonfrozen
);
782 desired_dumb_checksum5
= dumb_checksum5(&qend
);
783 desired_dumb_checksum6o
= dumb_checksum6(&qend
, 1);
784 desired_dumb_checksum6u
= dumb_checksum6(&qend
, 0);
787 /* Now, the long haul*/
794 signal(SIGUSR1
, handle
);
798 uint_fast8_t correct
= 0;
799 size_t *sequence
= 0;
801 while (len
< max_len
) {
804 sequence
= calloc(len
+ 1, sizeof *sequence
);
806 for (size_t k
= 0; k
< len
; ++k
) {
810 for (size_t k
= 0; k
< len
; ++k
) {
811 /* This will get pruned, it's okay */
813 seen_in_seq
[sequence
[k
]]++;
819 if (status_requested
) {
820 status_requested
= 0;
821 printf("Current sequence %s", q
.v
[sequence
[0]].name
);
823 for (size_t k
= 1; k
< len
; ++k
) {
824 printf(", %s", q
.v
[sequence
[k
]].name
);
832 * Here, we have computed a full sequence that we want
833 * to check. c_idx is in [0, len - 1], and the quiver
834 * has been mutated following the sequence up to (but
835 * not including) c_idx.
837 * This code is duplicated from increment_sequence
838 * because it is reasonable to start the whole process
839 * with a sequence that may, in fact, produce warnings.
843 while (c_idx
< len
) {
844 /* Prune duplicates (mutations are involutions) */
846 sequence
[c_idx
] == sequence
[c_idx
- 1]) {
847 goto increment_sequence
;
850 /* Proceed one more mutation */
851 quiver_mutate(&q
, sequence
[c_idx
], &warn
, 0);
854 /* That mutation caused a warning: skip it */
855 quiver_mutate(&q
, sequence
[c_idx
], 0, 0);
857 /* And try the sequence, starting at c_idx */
858 goto increment_sequence
;
862 * Skip ... X, Y ... when X > Y and the edge
863 * from X to Y is trivial
866 sequence
[c_idx
] < sequence
[c_idx
- 1]) {
867 size_t x
= sequence
[c_idx
- 1];
868 size_t y
= sequence
[c_idx
];
869 struct rational
*xy
= &(q
.e
[x
* q
.v_len
+ y
]);
870 struct rational
*yx
= &(q
.e
[y
* q
.v_len
+ x
]);
875 quiver_mutate(&q
, sequence
[c_idx
], 0,
878 /* And try the sequence, starting at c_idx */
879 goto increment_sequence
;
887 * If we are looking for a flip, we're probably
888 * going to require that all non-frozen vertices
889 * participate in the mutation.
891 if (require_all_nonfrozen
) {
892 for (size_t k
= 0; k
< num_nonfrozen
; ++k
) {
893 if (!seen_in_seq
[k
]) {
900 * Here, there's a full sequence, and the quiver has
901 * been mutated according to it (all of it). We want
902 * to check if the result matches the target.
904 if (check_heuristics_only
) {
905 /* Take a short-cut */
906 this_dumb_checksum1
= dumb_checksum1(&q
);
908 if (this_dumb_checksum1
!= desired_dumb_checksum1
) {
912 this_dumb_checksum2
= dumb_checksum2(&q
);
914 if (this_dumb_checksum2
!= desired_dumb_checksum2
) {
918 this_dumb_checksum3
= dumb_checksum3(&q
);
920 if (this_dumb_checksum3
!= desired_dumb_checksum3
) {
924 this_dumb_checksum4
= dumb_checksum4(&q
, num_nonfrozen
);
926 if (this_dumb_checksum4
!= desired_dumb_checksum4
) {
930 this_dumb_checksum5
= dumb_checksum5(&q
);
932 if (this_dumb_checksum5
!= desired_dumb_checksum5
) {
936 this_dumb_checksum6o
= dumb_checksum6(&q
, 1);
938 if (this_dumb_checksum6o
!= desired_dumb_checksum6o
) {
942 this_dumb_checksum6u
= dumb_checksum6(&q
, 0);
944 if (this_dumb_checksum6u
!= desired_dumb_checksum6u
) {
953 for (size_t i
= 0; i
< q
.v_num
; ++i
) {
954 for (size_t j
= 0; j
< q
.v_num
; ++j
) {
955 struct rational
*e
= &(q
.e
[i
* q
.v_len
+ j
]);
956 struct rational
*f
= &(target
[i
* q
.v_num
+ j
]);
958 if (e
->p
* f
->q
!= f
->p
* e
->q
) {
969 check_heuristics_only
) {
970 printf("SEQUENCE: %s", q
.v
[sequence
[0]].name
);
972 for (size_t k
= 1; k
< len
; ++k
) {
973 printf(", %s", q
.v
[sequence
[k
]].name
);
982 quiver_mutate(&q
, sequence
[c_idx
], 0, 0);
986 * Here, we have some kind of sequence. The quiver agrees
987 * with it up to (but not including) c_idx, and we want
988 * to increment it at c_idx.
991 seen_in_seq
[sequence
[c_idx
]]--;
993 seen_in_seq
[sequence
[c_idx
]]++;
997 double completed
= sequence
[0] * num_nonfrozen
*
998 num_nonfrozen
+ sequence
[1] *
1001 double total
= num_nonfrozen
* num_nonfrozen
*
1004 printf("Length %zu: completed %.3g%%\n", len
, (100.0 *
1010 /* Skip over repeats: each mutation is an involution */
1012 sequence
[c_idx
] == sequence
[c_idx
- 1]) {
1013 seen_in_seq
[sequence
[c_idx
]]--;
1015 seen_in_seq
[sequence
[c_idx
]]++;
1018 /* Wrap back to 0 */
1019 if (sequence
[c_idx
] >= num_nonfrozen
) {
1025 quiver_mutate(&q
, sequence
[c_idx
], 0, 0);
1026 goto increment_sequence
;
1029 if (c_idx
!= len
- 1) {
1031 * Here, we now have a start of a sequence.
1032 * The quiver agrees with our start up to (but
1033 * not including) c_idx, and we want to possibly
1034 * complete this to a full sequence. First,
1035 * however, we need to make sure that we don't
1036 * introduce any warnings at c_idx.
1038 * This single-mutation testing block could be
1039 * ignored, but I have a vague suspicion it will
1043 quiver_mutate(&q
, sequence
[c_idx
], &warn
, 0);
1046 /* That mutation caused a warning: skip it */
1047 quiver_mutate(&q
, sequence
[c_idx
], 0, 0);
1049 /* And try the sequence, starting at c_idx */
1050 goto increment_sequence
;
1054 * Quivers almost commute: in particular if
1055 * the edge v_i -> v_j is zero, then mutation
1056 * at v_i and v_j commute. So if we're at X, Y
1057 * in the list, and X > Y, then we've actually
1058 * already computed that branch of the tree,
1059 * back when it was Y, X. Therefore, increment X.
1062 sequence
[c_idx
] < sequence
[c_idx
- 1]) {
1063 size_t x
= sequence
[c_idx
- 1];
1064 size_t y
= sequence
[c_idx
];
1065 struct rational
*xy
= &(q
.e
[x
* q
.v_len
+ y
]);
1066 struct rational
*yx
= &(q
.e
[y
* q
.v_len
+ x
]);
1071 quiver_mutate(&q
, sequence
[c_idx
], 0,
1074 /* And try the sequence, starting at c_idx */
1075 goto increment_sequence
;
1080 * Here the quiver agrees with our start up
1081 * to and including c_idx, and we need to fill
1082 * it out into a full sequence so that it can
1083 * be tested. We don't need to perform all the
1084 * mutations of that full sequence, but we do
1085 * need to generate the minimal one.
1087 for (size_t i
= c_idx
+ 1; i
< len
; ++i
) {
1088 seen_in_seq
[sequence
[i
]]--;
1089 sequence
[i
] = 1 - !!((i
- c_idx
) % 2);
1090 seen_in_seq
[sequence
[i
]]++;
1096 goto have_full_sequence
;
1100 * Here, we have c_idx = 0, and the quiver has not been
1101 * mutated by anything in sequence
1103 printf("Exhausted length %zu\n", len
);