@@ -942,6 +942,62 @@ FUZZ_TARGET(clusterlin_linearization_chunking)
942942 assert (chunking.NumChunksLeft () == 0 );
943943}
944944
945+ FUZZ_TARGET (clusterlin_simple_linearize)
946+ {
947+ // Verify the behavior of SimpleLinearize(). Note that SimpleLinearize is only used in tests;
948+ // the purpose of this fuzz test is to establish confidence in SimpleLinearize, so that it can
949+ // be used to test the real Linearize function in the fuzz test below.
950+
951+ // Retrieve an iteration count and a depgraph from the fuzz input.
952+ SpanReader reader (buffer);
953+ uint64_t iter_count{0 };
954+ DepGraph<TestBitSet> depgraph;
955+ try {
956+ reader >> VARINT (iter_count) >> Using<DepGraphFormatter>(depgraph);
957+ } catch (const std::ios_base::failure&) {}
958+ iter_count %= MAX_SIMPLE_ITERATIONS;
959+
960+ // Invoke SimpleLinearize().
961+ auto [linearization, optimal] = SimpleLinearize (depgraph, iter_count);
962+ SanityCheck (depgraph, linearization);
963+ auto simple_chunking = ChunkLinearization (depgraph, linearization);
964+
965+ // If the iteration count is sufficiently high, an optimal linearization must be found.
966+ // SimpleLinearize on k transactions can take up to 2^(k-1) iterations (one per non-empty
967+ // connected topologically valid subset), which sums over k=1..n to (2^n)-1.
968+ const uint64_t n = depgraph.TxCount ();
969+ if (n <= 63 && (iter_count >> n)) {
970+ assert (optimal);
971+ }
972+
973+ // If SimpleLinearize claims optimal result, and the cluster is sufficiently small (there are
974+ // n! linearizations), test that the result is as good as every valid linearization.
975+ if (optimal && depgraph.TxCount () <= 7 ) {
976+ std::vector<DepGraphIndex> perm_linearization;
977+ // Initialize with the lexicographically-first linearization.
978+ for (DepGraphIndex i : depgraph.Positions ()) perm_linearization.push_back (i);
979+ // Iterate over all valid permutations.
980+ do {
981+ // Determine whether perm_linearization is topological.
982+ TestBitSet perm_done;
983+ bool perm_is_topo{true };
984+ for (auto i : perm_linearization) {
985+ perm_done.Set (i);
986+ if (!depgraph.Ancestors (i).IsSubsetOf (perm_done)) {
987+ perm_is_topo = false ;
988+ break ;
989+ }
990+ }
991+ // If so, verify that the obtained linearization is as good as the permutation.
992+ if (perm_is_topo) {
993+ auto perm_chunking = ChunkLinearization (depgraph, perm_linearization);
994+ auto cmp = CompareChunks (simple_chunking, perm_chunking);
995+ assert (cmp >= 0 );
996+ }
997+ } while (std::next_permutation (perm_linearization.begin (), perm_linearization.end ()));
998+ }
999+ }
1000+
9451001FUZZ_TARGET (clusterlin_linearize)
9461002{
9471003 // Verify the behavior of Linearize().
@@ -1017,31 +1073,6 @@ FUZZ_TARGET(clusterlin_linearize)
10171073 // If SimpleLinearize finds the optimal result too, they must be equal (if not,
10181074 // SimpleLinearize is broken).
10191075 if (simple_optimal) assert (cmp == 0 );
1020-
1021- // Only for very small clusters, test every topologically-valid permutation.
1022- if (depgraph.TxCount () <= 7 ) {
1023- std::vector<DepGraphIndex> perm_linearization;
1024- for (DepGraphIndex i : depgraph.Positions ()) perm_linearization.push_back (i);
1025- // Iterate over all valid permutations.
1026- do {
1027- // Determine whether perm_linearization is topological.
1028- TestBitSet perm_done;
1029- bool perm_is_topo{true };
1030- for (auto i : perm_linearization) {
1031- perm_done.Set (i);
1032- if (!depgraph.Ancestors (i).IsSubsetOf (perm_done)) {
1033- perm_is_topo = false ;
1034- break ;
1035- }
1036- }
1037- // If so, verify that the obtained linearization is as good as the permutation.
1038- if (perm_is_topo) {
1039- auto perm_chunking = ChunkLinearization (depgraph, perm_linearization);
1040- auto cmp = CompareChunks (chunking, perm_chunking);
1041- assert (cmp >= 0 );
1042- }
1043- } while (std::next_permutation (perm_linearization.begin (), perm_linearization.end ()));
1044- }
10451076 }
10461077}
10471078
0 commit comments