mirror of
https://github.com/Jaxan/hybrid-ads.git
synced 2025-04-27 06:57:44 +02:00
Adds a test method without suffixes. Rewrites methods.cpp to use these functions.
This commit is contained in:
parent
e9ffbd3be8
commit
09c65377e7
4 changed files with 139 additions and 42 deletions
|
@ -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<input> 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<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) {
|
||||
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};
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
struct writer {
|
||||
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)
|
||||
|
@ -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<std::string> & inputs);
|
||||
|
|
11
src/main.cpp
11
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) {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <read_mealy.hpp>
|
||||
#include <separating_family.hpp>
|
||||
#include <splitting_tree.hpp>
|
||||
#include <test_suite.hpp>
|
||||
#include <transfer_sequences.hpp>
|
||||
#include <trie.hpp>
|
||||
|
||||
|
@ -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] <file>
|
||||
|
@ -25,14 +26,15 @@ R"(FSM-based test methods
|
|||
--version Show version
|
||||
-s <seed>, --seed <seed> Specify a seed
|
||||
--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[]) {
|
||||
const auto args = docopt::docopt(USAGE, {argv + 1, argv + argc}, true, __DATE__ __TIME__);
|
||||
|
||||
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 = [&] {
|
||||
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<word> 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<input> 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue