@@ -458,6 +458,7 @@ FUZZ_TARGET(clusterlin_ancestor_finder)
458458 while (todo.Any ()) {
459459 // Call the ancestor finder's FindCandidateSet for what remains of the graph.
460460 assert (!anc_finder.AllDone ());
461+ assert (todo.Count () == anc_finder.NumRemaining ());
461462 auto best_anc = anc_finder.FindCandidateSet ();
462463 // Sanity check the result.
463464 assert (best_anc.transactions .Any ());
@@ -489,6 +490,7 @@ FUZZ_TARGET(clusterlin_ancestor_finder)
489490 anc_finder.MarkDone (del_set);
490491 }
491492 assert (anc_finder.AllDone ());
493+ assert (anc_finder.NumRemaining () == 0 );
492494}
493495
494496static constexpr auto MAX_SIMPLE_ITERATIONS = 300000 ;
@@ -523,6 +525,7 @@ FUZZ_TARGET(clusterlin_search_finder)
523525 assert (!smp_finder.AllDone ());
524526 assert (!exh_finder.AllDone ());
525527 assert (!anc_finder.AllDone ());
528+ assert (anc_finder.NumRemaining () == todo.Count ());
526529
527530 // For each iteration, read an iteration count limit from the fuzz input.
528531 uint64_t max_iterations = 1 ;
@@ -605,6 +608,7 @@ FUZZ_TARGET(clusterlin_search_finder)
605608 assert (smp_finder.AllDone ());
606609 assert (exh_finder.AllDone ());
607610 assert (anc_finder.AllDone ());
611+ assert (anc_finder.NumRemaining () == 0 );
608612}
609613
610614FUZZ_TARGET (clusterlin_linearization_chunking)
@@ -775,11 +779,16 @@ FUZZ_TARGET(clusterlin_linearize)
775779 if (n <= 19 && iter_count > (uint64_t {1 } << n)) {
776780 assert (optimal);
777781 }
778- // Additionally, if the assumption of sqrt(2^k)+1 iterations per step holds, the maximum number
779- // of iterations is also bounded by (2 + sqrt(2)) * (sqrt(2^n) - 1) + n, which is less than
780- // (2 + sqrt(2)) * sqrt(2^n) + n. Subtracting n and squaring gives
781- // (6 + 4 * sqrt(2)) * 2^n < 12 * 2^n.
782- if (n <= 35 && iter_count > n && (iter_count - n) * (iter_count - n) >= uint64_t {12 } << n) {
782+ // Additionally, if the assumption of sqrt(2^k)+1 iterations per step holds, plus ceil(k/4)
783+ // start-up cost per step, plus ceil(n^2/64) start-up cost overall, we can compute the upper
784+ // bound for a whole linearization (summing for k=1..n) using the Python expression
785+ // [sum((k+3)//4 + int(math.sqrt(2**k)) + 1 for k in range(1, n + 1)) + (n**2 + 63) // 64 for n in range(0, 35)]:
786+ static constexpr uint64_t MAX_OPTIMAL_ITERS[] = {
787+ 0 , 4 , 8 , 12 , 18 , 26 , 37 , 51 , 70 , 97 , 133 , 182 , 251 , 346 , 480 , 666 , 927 , 1296 , 1815 , 2545 ,
788+ 3576 , 5031 , 7087 , 9991 , 14094 , 19895 , 28096 , 39690 , 56083 , 79263 , 112041 , 158391 , 223936 ,
789+ 316629 , 447712
790+ };
791+ if (n < std::size (MAX_OPTIMAL_ITERS) && iter_count >= MAX_OPTIMAL_ITERS[n]) {
783792 Assume (optimal);
784793 }
785794
0 commit comments