1
Fork 0
mirror of https://github.com/Jaxan/hybrid-ads.git synced 2025-04-27 15:07:45 +02:00

Adds a test method without suffixes. Rewrites methods.cpp to use these functions.

This commit is contained in:
Joshua Moerman 2015-10-13 14:32:42 +02:00
parent e9ffbd3be8
commit 09c65377e7
4 changed files with 139 additions and 42 deletions

View file

@ -23,7 +23,7 @@ void test(const mealy & specification, const transfer_sequences & prefixes,
output.apply(prefix); output.apply(prefix);
output.apply(middle); output.apply(middle);
output.apply(suffix); 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)]; const auto & prefix = prefixes[prefix_selection(generator)];
current_state = apply(specification, current_state, begin(prefix), end(prefix)).to; current_state = apply(specification, current_state, begin(prefix), end(prefix)).to;
vector<input> middle; word middle;
middle.reserve(min_k + 1); middle.reserve(min_k + 1);
size_t minimal_size = min_k; size_t minimal_size = min_k;
while (minimal_size || unfair_coin(generator)) { 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(prefix);
output.apply(middle); output.apply(middle);
output.apply(suffix); 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<pair<state, word>> 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<vector<pair<input, state>>> 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<state> suffix_selection(0, all_suffixes.size() - 1);
uniform_int_distribution<size_t> 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<std::string> const & inputs) { writer default_writer(std::vector<std::string> const & inputs) {
static const auto print_word = [&](word w) { for (auto && x : w) cout << inputs[x] << ' '; }; static const auto print_word = [&](word w) {
static const auto reset = [&] { cout << endl; }; for (auto && x : w) cout << inputs[x] << ' ';
};
static const auto reset = [&] {
cout << endl;
return bool(cout);
};
return {print_word, reset}; return {print_word, reset};
} }

View file

@ -9,7 +9,7 @@
struct writer { struct writer {
std::function<void(word)> apply; // store a part of a word std::function<void(word)> apply; // store a part of a word
std::function<void(void)> reset; // flush 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 \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) /// \brief Performs random non-exhaustive tests for more states (harmonized, e.g. HSI / DS)
void randomized_test(mealy const & specification, transfer_sequences const & prefixes, void randomized_test(mealy const & specification, transfer_sequences const & prefixes,
separating_family const & separating_family, size_t min_k, separating_family const & separating_family, size_t min_k, size_t rnd_length,
size_t rnd_length, writer const & output, uint_fast32_t random_seed); 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) /// \brief returns a writer which simply writes everything to cout (via inputs)
writer default_writer(const std::vector<std::string> & inputs); writer default_writer(const std::vector<std::string> & inputs);

View file

@ -31,6 +31,7 @@ R"(Generate a test suite
--no-ds Only use the classical algorithm (hsi) --no-ds Only use the classical algorithm (hsi)
--random-ds Choose randomly between the ds method or hsi method --random-ds Choose randomly between the ds method or hsi method
--no-suffix Dont calculate anything smart, just do the random stuff --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; 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 streaming = args.at("all").asBool() || args.at("fixed").asBool();
const bool random_part = args.at("all").asBool() || args.at("random").asBool(); const bool random_part = args.at("all").asBool() || args.at("random").asBool();
const bool no_suffix = args.at("--no-suffix").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 bool seed_provided = bool(args.at("--seed"));
const uint_fast32_t seed = seed_provided ? args.at("--seed").asLong() : 0; 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){ if(random_part){
time_logger t("outputting all random tests"); time_logger t("outputting all random tests");
const auto k_max_ = streaming ? k_max + 1 : 0; 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) { } catch (exception const & e) {

View file

@ -2,6 +2,7 @@
#include <read_mealy.hpp> #include <read_mealy.hpp>
#include <separating_family.hpp> #include <separating_family.hpp>
#include <splitting_tree.hpp> #include <splitting_tree.hpp>
#include <test_suite.hpp>
#include <transfer_sequences.hpp> #include <transfer_sequences.hpp>
#include <trie.hpp> #include <trie.hpp>
@ -15,7 +16,7 @@
using namespace std; using namespace std;
static const char USAGE[] = static const char USAGE[] =
R"(FSM-based test methods R"(FSM-based test methods
Usage: Usage:
methods (hsi|ads) [options] <file> methods (hsi|ads) [options] <file>
@ -25,14 +26,15 @@ R"(FSM-based test methods
--version Show version --version Show version
-s <seed>, --seed <seed> Specify a seed -s <seed>, --seed <seed> Specify a seed
--non-random Iterate inputs in specified order (as occurring in input file) --non-random Iterate inputs in specified order (as occurring in input file)
-k <states> Testing extra states [default: 0] -k <states> Testing extra states [default: 1]
--print-suite Prints the whole test suite
)"; )";
int main(int argc, char * argv[]) { int main(int argc, char * argv[]) {
const auto args = docopt::docopt(USAGE, {argv + 1, argv + argc}, true, __DATE__ __TIME__); const auto args = docopt::docopt(USAGE, {argv + 1, argv + argc}, true, __DATE__ __TIME__);
const string filename = args.at("<file>").asString(); const string filename = args.at("<file>").asString();
const size_t k_max = args.at("-k").asLong() + 1; const size_t k_max = args.at("-k").asLong();
const auto machine = [&] { const auto machine = [&] {
if (filename.find(".txt") != string::npos) { if (filename.find(".txt") != string::npos) {
@ -61,54 +63,71 @@ int main(int argc, char * argv[]) {
if (args.at("hsi").asBool()) { if (args.at("hsi").asBool()) {
return create_adaptive_distinguishing_sequence(result(machine.graph_size)); return create_adaptive_distinguishing_sequence(result(machine.graph_size));
} }
const auto tree const auto tree = create_splitting_tree(machine, args.at("--non-random").asBool()
= create_splitting_tree(machine, args.at("--non-random").asBool() ? lee_yannakakis_style : randomized_lee_yannakakis_style, random_seeds[0]); ? lee_yannakakis_style
: randomized_lee_yannakakis_style,
random_seeds[0]);
return create_adaptive_distinguishing_sequence(tree); return create_adaptive_distinguishing_sequence(tree);
}); });
auto pairs_fut = async([&] { auto pairs_fut = async([&] {
const auto tree const auto tree = create_splitting_tree(machine, args.at("--non-random").asBool()
= create_splitting_tree(machine, args.at("--non-random").asBool() ? min_hopcroft_style : randomized_min_hopcroft_style, random_seeds[1]); ? min_hopcroft_style
: randomized_min_hopcroft_style,
random_seeds[1]);
return tree.root; return tree.root;
}); });
auto prefixes_fut auto prefixes_fut = async([&] {
= async([&] { return create_randomized_transfer_sequences(machine, 0, random_seeds[2]); }); return create_transfer_sequences(args.at("--non-random").asBool()
? canonical_transfer_sequences
auto middles_fut = async([&] { : randomized_transfer_sequences,
vector<word> all_sequences(1); machine, 0, random_seeds[2]);
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 suffixes_fut auto suffixes_fut
= async([&] { return create_separating_family(sequence_fut.get(), pairs_fut.get()); }); = 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<input> test_suite; trie<input> test_suite;
word buffer;
const state start = 0; const auto suffixes = suffixes_fut.get();
const word empty = {}; for(state s = 0; s < suffixes.size(); ++s){
for (auto && p : prefixes) { clog << "suffixes for " << s << endl;
const state s1 = apply(machine, start, begin(p), end(p)).to; for(auto s : suffixes[s].local_suffixes) {
const word w1 = concat(empty, p); for(auto x : s){
for (auto && m : middles) { clog << x;
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);
} }
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); const auto p = total_size(test_suite);
cout << p.first << '\t' << p.second << '\t' << p.first + p.second << endl; 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;
});
}
} }