diff --git a/lib/test_suite.cpp b/lib/test_suite.cpp
index b74521f..f33a53f 100644
--- a/lib/test_suite.cpp
+++ b/lib/test_suite.cpp
@@ -23,7 +23,7 @@ void test(const mealy & specification, const transfer_sequences & prefixes,
output.apply(prefix);
output.apply(middle);
output.apply(suffix);
- output.reset();
+ if(!output.reset()) return;
}
}
}
@@ -51,7 +51,7 @@ void randomized_test(const mealy & specification, const transfer_sequences & pre
const auto & prefix = prefixes[prefix_selection(generator)];
current_state = apply(specification, current_state, begin(prefix), end(prefix)).to;
- vector middle;
+ word middle;
middle.reserve(min_k + 1);
size_t minimal_size = min_k;
while (minimal_size || unfair_coin(generator)) {
@@ -68,12 +68,77 @@ void randomized_test(const mealy & specification, const transfer_sequences & pre
output.apply(prefix);
output.apply(middle);
output.apply(suffix);
- output.reset();
+ if(!output.reset()) return;
+ }
+}
+
+void randomized_test_suffix(const mealy & specification, const transfer_sequences & prefixes,
+ const separating_family & separating_family, size_t min_k,
+ size_t rnd_length, const writer & output, uint_fast32_t random_seed) {
+ vector> all_suffixes;
+ for (state s = 0; s < separating_family.size(); ++s) {
+ for (auto const & w : separating_family[s].local_suffixes) {
+ all_suffixes.emplace_back(s, w);
+ }
+ }
+
+ // state -> [(input, state)]
+ vector>> reverse_machine(specification.graph_size);
+ for (state s = 0; s < specification.graph_size; ++s) {
+ for (input i = 0; i < specification.input_size; ++i) {
+ const auto t = apply(specification, s, i).to;
+ reverse_machine[t].emplace_back(i, s);
+ }
+ }
+
+ std::mt19937 generator(random_seed);
+
+ // https://en.wikipedia.org/wiki/Geometric_distribution we have the random variable Y here
+ uniform_int_distribution<> unfair_coin(0, rnd_length);
+ uniform_int_distribution suffix_selection(0, all_suffixes.size() - 1);
+ uniform_int_distribution input_selection;
+
+ while (true) {
+ const auto & state_suffix = all_suffixes[suffix_selection(generator)];
+ const auto & suffix = state_suffix.second;
+ state current_state = state_suffix.first;
+
+ word middle;
+ middle.reserve(min_k + 1);
+ size_t minimal_size = min_k;
+ while (minimal_size || unfair_coin(generator)) {
+ const auto & preds = reverse_machine[current_state];
+ if(preds.empty()) {
+ cerr << "ERROR: no predecessors for this state!\n";
+ break;
+ }
+
+ using params = decltype(input_selection)::param_type;
+ const auto & input_state
+ = preds[input_selection(generator, params{0, preds.size() - 1})];
+
+ current_state = input_state.second;
+ middle.insert(middle.begin(), input_state.first);
+
+ if (minimal_size) minimal_size--;
+ }
+
+ const auto & prefix = prefixes[current_state];
+
+ output.apply(prefix);
+ output.apply(middle);
+ output.apply(suffix);
+ if(!output.reset()) return;
}
}
writer default_writer(std::vector const & inputs) {
- static const auto print_word = [&](word w) { for (auto && x : w) cout << inputs[x] << ' '; };
- static const auto reset = [&] { cout << endl; };
+ static const auto print_word = [&](word w) {
+ for (auto && x : w) cout << inputs[x] << ' ';
+ };
+ static const auto reset = [&] {
+ cout << endl;
+ return bool(cout);
+ };
return {print_word, reset};
}
diff --git a/lib/test_suite.hpp b/lib/test_suite.hpp
index d797b58..768d4c6 100644
--- a/lib/test_suite.hpp
+++ b/lib/test_suite.hpp
@@ -9,7 +9,7 @@
struct writer {
std::function apply; // store a part of a word
- std::function reset; // flush
+ std::function reset; // flush, if flase is returned, testing is stopped
};
/// \brief Performs exhaustive tests with \p k_max extra states (harmonized, e.g. HSI / DS)
@@ -18,8 +18,12 @@ void test(mealy const & specification, transfer_sequences const & prefixes,
/// \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, writer const & output, uint_fast32_t random_seed);
+ separating_family const & separating_family, size_t min_k, size_t rnd_length,
+ writer const & output, uint_fast32_t random_seed);
+
+void randomized_test_suffix(mealy const & specification, transfer_sequences const & prefixes,
+ separating_family const & separating_family, size_t min_k,
+ size_t rnd_length, writer const & output, uint_fast32_t random_seed);
/// \brief returns a writer which simply writes everything to cout (via inputs)
writer default_writer(const std::vector & inputs);
diff --git a/src/main.cpp b/src/main.cpp
index 07364fb..ba0705d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -31,6 +31,7 @@ R"(Generate a test suite
--no-ds Only use the classical algorithm (hsi)
--random-ds Choose randomly between the ds method or hsi method
--no-suffix Dont calculate anything smart, just do the random stuff
+ --suffix-based Only applies in random mode. Chooses suffix first, and not prefix first
)";
using time_logger = silent_timer;
@@ -47,6 +48,7 @@ int main(int argc, char *argv[]) try {
const bool streaming = args.at("all").asBool() || args.at("fixed").asBool();
const bool random_part = args.at("all").asBool() || args.at("random").asBool();
const bool no_suffix = args.at("--no-suffix").asBool();
+ const bool suffix_based = args.at("--suffix-based").asBool();
const bool seed_provided = bool(args.at("--seed"));
const uint_fast32_t seed = seed_provided ? args.at("--seed").asLong() : 0;
@@ -153,7 +155,14 @@ int main(int argc, char *argv[]) try {
if(random_part){
time_logger t("outputting all random tests");
const auto k_max_ = streaming ? k_max + 1 : 0;
- randomized_test(machine, transfer_sequences, separating_family, k_max_, rnd_length, default_writer(inputs), random_seeds[3]);
+
+ if (suffix_based) {
+ randomized_test_suffix(machine, transfer_sequences, separating_family, k_max_,
+ rnd_length, default_writer(inputs), random_seeds[3]);
+ } else {
+ randomized_test(machine, transfer_sequences, separating_family, k_max_, rnd_length,
+ default_writer(inputs), random_seeds[3]);
+ }
}
} catch (exception const & e) {
diff --git a/src/methods.cpp b/src/methods.cpp
index 03463be..be75b37 100644
--- a/src/methods.cpp
+++ b/src/methods.cpp
@@ -2,6 +2,7 @@
#include
#include
#include
+#include
#include
#include
@@ -15,7 +16,7 @@
using namespace std;
static const char USAGE[] =
-R"(FSM-based test methods
+ R"(FSM-based test methods
Usage:
methods (hsi|ads) [options]
@@ -25,14 +26,15 @@ R"(FSM-based test methods
--version Show version
-s , --seed Specify a seed
--non-random Iterate inputs in specified order (as occurring in input file)
- -k Testing extra states [default: 0]
+ -k Testing extra states [default: 1]
+ --print-suite Prints the whole test suite
)";
int main(int argc, char * argv[]) {
const auto args = docopt::docopt(USAGE, {argv + 1, argv + argc}, true, __DATE__ __TIME__);
const string filename = args.at("").asString();
- const size_t k_max = args.at("-k").asLong() + 1;
+ const size_t k_max = args.at("-k").asLong();
const auto machine = [&] {
if (filename.find(".txt") != string::npos) {
@@ -61,54 +63,71 @@ int main(int argc, char * argv[]) {
if (args.at("hsi").asBool()) {
return create_adaptive_distinguishing_sequence(result(machine.graph_size));
}
- const auto tree
- = create_splitting_tree(machine, args.at("--non-random").asBool() ? lee_yannakakis_style : randomized_lee_yannakakis_style, random_seeds[0]);
+ const auto tree = create_splitting_tree(machine, args.at("--non-random").asBool()
+ ? lee_yannakakis_style
+ : randomized_lee_yannakakis_style,
+ random_seeds[0]);
return create_adaptive_distinguishing_sequence(tree);
});
auto pairs_fut = async([&] {
- const auto tree
- = create_splitting_tree(machine, args.at("--non-random").asBool() ? min_hopcroft_style : randomized_min_hopcroft_style, random_seeds[1]);
+ const auto tree = create_splitting_tree(machine, args.at("--non-random").asBool()
+ ? min_hopcroft_style
+ : randomized_min_hopcroft_style,
+ random_seeds[1]);
return tree.root;
});
- auto prefixes_fut
- = async([&] { return create_randomized_transfer_sequences(machine, 0, random_seeds[2]); });
-
- auto middles_fut = async([&] {
- vector all_sequences(1);
- for (size_t k = 0; k < k_max; ++k) {
- const auto new_sequences = all_seqs(0, machine.input_size, all_sequences);
- all_sequences.reserve(all_sequences.size() + new_sequences.size());
- copy(begin(new_sequences), end(new_sequences), back_inserter(all_sequences));
- }
- return all_sequences;
+ auto prefixes_fut = async([&] {
+ return create_transfer_sequences(args.at("--non-random").asBool()
+ ? canonical_transfer_sequences
+ : randomized_transfer_sequences,
+ machine, 0, random_seeds[2]);
});
auto suffixes_fut
= async([&] { return create_separating_family(sequence_fut.get(), pairs_fut.get()); });
- const auto prefixes = prefixes_fut.get();
- const auto middles = middles_fut.get();
- const auto suffixes = suffixes_fut.get();
trie test_suite;
+ word buffer;
- const state start = 0;
- const word empty = {};
- for (auto && p : prefixes) {
- const state s1 = apply(machine, start, begin(p), end(p)).to;
- const word w1 = concat(empty, p);
- for (auto && m : middles) {
- const state s2 = apply(machine, s1, begin(m), end(m)).to;
- const word w2 = concat(w1, m);
- const auto & suffixes_for_state = suffixes[s2].local_suffixes;
- for (auto && s : suffixes_for_state) {
- word test = concat(w2, s);
- test_suite.insert(test);
+ const auto suffixes = suffixes_fut.get();
+ for(state s = 0; s < suffixes.size(); ++s){
+ clog << "suffixes for " << s << endl;
+ for(auto s : suffixes[s].local_suffixes) {
+ for(auto x : s){
+ clog << x;
}
+ clog << endl;
}
}
+ const auto prefixes = prefixes_fut.get();
+ for(state s = 0; s < prefixes.size(); ++s) {
+ clog << "prefix for " << s << endl;
+ for(auto x : prefixes[s]) {
+ clog << x;
+ }
+ clog << endl;
+ }
+
+ test(machine, prefixes, suffixes, k_max,
+ {[&buffer](auto const & w) { buffer.insert(buffer.end(), w.begin(), w.end()); },
+ [&buffer, &test_suite]() {
+ test_suite.insert(buffer);
+ buffer.clear();
+ return true;
+ }});
+
const auto p = total_size(test_suite);
cout << p.first << '\t' << p.second << '\t' << p.first + p.second << endl;
+
+ if(args.at("--print-suite").asBool()){
+ test_suite.for_each([](const auto & w){
+ for(const auto & x : w) {
+ cout << x;
+ }
+ cout << endl;
+ });
+ }
}