diff --git a/lib/test_suite.cpp b/lib/test_suite.cpp index 148901549b4c639fca750c5684a6ee440552731e..59e3f49b326b0595b74e2f1924c14e9571933a00 100644 --- a/lib/test_suite.cpp +++ b/lib/test_suite.cpp @@ -9,9 +9,13 @@ using namespace std; void test(const mealy & specification, const transfer_sequences & prefixes, const separating_family & separating_family, size_t k_max, const writer & output) { vector<word> all_sequences(1); + test(specification, prefixes, all_sequences, separating_family, k_max, output); +} - for (size_t k = 0; k <= k_max; ++k) { - // clog << "*** K = " << k << endl; +void test(const mealy & specification, const transfer_sequences & prefixes, + vector<word> & all_sequences, const separating_family & separating_family, + size_t k_max, const writer & output) { + for (size_t k = 0; k < k_max; ++k) { for (state s = 0; s < specification.graph_size; ++s) { const auto prefix = prefixes[s]; diff --git a/lib/test_suite.hpp b/lib/test_suite.hpp index 23ddda03b2a1177a5479cfaaf6004bf1b1cd0304..2057a543a2bf125a25766bb14bd99e8dcd927a55 100644 --- a/lib/test_suite.hpp +++ b/lib/test_suite.hpp @@ -6,16 +6,21 @@ #include "types.hpp" #include <functional> +#include <vector> struct writer { std::function<void(word)> apply; // store a part of a word std::function<bool(void)> reset; // flush, if flase is returned, testing is stopped }; -/// \brief Performs exhaustive tests with \p k_max extra states (harmonized, e.g. HSI / DS) +/// \brief Performs exhaustive tests with mid sequences < \p k_max (harmonized, e.g. HSI / DS) void test(mealy const & specification, transfer_sequences const & prefixes, separating_family const & separating_family, size_t k_max, writer const & output); +void test(const mealy & specification, const transfer_sequences & prefixes, + std::vector<word> & all_sequences, const separating_family & separating_family, + size_t k_max, const writer & output); + /// \brief Performs random non-exhaustive tests for more states (harmonized, e.g. HSI / DS) void randomized_test(mealy const & specification, transfer_sequences const & prefixes, separating_family const & separating_family, size_t min_k, size_t rnd_length, diff --git a/src/main.cpp b/src/main.cpp index 75e67e16e1a73e99c2a183ccccca8e3ceb591d7e..268d4753a366480a8a14402c0984345929ea39f6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -47,8 +47,10 @@ static const char USAGE[] = -p <arg> How to generate prefixes: minimal, lexmin, buggy, longest -s <arg> How to generate suffixes: hsi, hads, none -k <num> Number of extra states to check for (minus 1) + -l <num> (l <= k) Redundancy free part of tests -r <num> Expected length of random infix word -x <seed> 32 bits seeds for deterministic execution (0 is not valid) + -e More memory efficient -f <filename> Input filename ('-' or don't specify for stdin) -o <filename> Output filename ('-' or don't specify for stdout) )"; @@ -61,11 +63,14 @@ struct main_options { bool help = false; bool version = false; + bool skip_dup = true; + Mode mode = ALL; PrefixMode prefix_mode = MIN; SuffixMode suffix_mode = HADS; unsigned long k_max = 3; // 3 means 2 extra states + unsigned long l = 2; // length 0, 1 will be redundancy free unsigned long rnd_length = 8; // in addition to k_max unsigned long seed = 0; // 0 for unset/noise @@ -85,7 +90,7 @@ main_options parse_options(int argc, char ** argv) { try { int c; - while ((c = getopt(argc, argv, "hvm:p:s:k:r:x:f:o:")) != -1) { + while ((c = getopt(argc, argv, "hvem:p:s:k:l:r:x:f:o:")) != -1) { switch (c) { case 'h': // show help message opts.help = true; @@ -105,12 +110,18 @@ main_options parse_options(int argc, char ** argv) { case 'k': // select extra states / k-value opts.k_max = stoul(optarg); break; + case 'l': // + opts.l = stoul(optarg); + break; case 'r': // expected random length opts.rnd_length = stoul(optarg); break; case 'x': // seed opts.seed = stoul(optarg); break; + case 'e': + opts.skip_dup = false; + break; case 'f': // input filename opts.input_filename = optarg; break; @@ -130,6 +141,7 @@ main_options parse_options(int argc, char ** argv) { exit(2); } + opts.l = min(opts.l, opts.k_max); return opts; } @@ -302,7 +314,9 @@ int main(int argc, char * argv[]) try { // For the exhaustive/preset part we first collect all words // (while removing redundant ones) before outputting them. time_logger t("outputting all preset tests"); - test(machine, transfer_sequences, separating_family, args.k_max, + + vector<word> mid_sequences(1); + test(machine, transfer_sequences, mid_sequences, separating_family, args.l + 1, {[&buffer](auto const & w) { buffer.insert(buffer.end(), w.begin(), w.end()); }, [&buffer, &test_suite]() { test_suite.insert(buffer); @@ -310,7 +324,21 @@ int main(int argc, char * argv[]) try { return true; }}); - test_suite.for_each(output_word); + auto first_suite = flatten(test_suite); + mt19937 g; + shuffle(first_suite.begin(), first_suite.end(), g); + for (auto const & w : first_suite) output_word(w); + first_suite.clear(); + + test(machine, transfer_sequences, mid_sequences, separating_family, args.k_max - args.l, + {[&buffer](auto const & w) { buffer.insert(buffer.end(), w.begin(), w.end()); }, + [&buffer, &test_suite, &output_word, &args]() { + if (!args.skip_dup || test_suite.insert(buffer)) { + output_word(buffer); + } + buffer.clear(); + return bool(cout); + }}); } if (random_part) { @@ -323,9 +351,9 @@ int main(int argc, char * argv[]) try { randomized_test( machine, transfer_sequences, separating_family, k_max_, args.rnd_length, {[&buffer](auto const & w) { buffer.insert(buffer.end(), w.begin(), w.end()); }, - [&buffer, &test_suite, &output_word]() { + [&buffer, &test_suite, &output_word, &args]() { // TODO: probably we want to bound the size of the prefix tree - if (test_suite.insert(buffer)) { + if (!args.skip_dup || test_suite.insert(buffer)) { output_word(buffer); } buffer.clear();