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

Refactors a bit

This commit is contained in:
Joshua Moerman 2015-05-21 14:13:04 +02:00
parent 8871040c03
commit f5108ceb43
14 changed files with 74 additions and 135 deletions

View file

@ -39,7 +39,7 @@ adaptive_distinguishing_sequence create_adaptive_distinguishing_sequence(const r
if(oboom.children.empty()) continue; if(oboom.children.empty()) continue;
node.word = oboom.seperator; node.word = oboom.separator;
for(auto && c : oboom.children){ for(auto && c : oboom.children){
adaptive_distinguishing_sequence new_c(0, node.depth + 1); adaptive_distinguishing_sequence new_c(0, node.depth + 1);

View file

@ -1,29 +0,0 @@
#pragma once
#include "adaptive_distinguishing_sequence.hpp"
#include "separating_matrix.hpp"
#include "types.hpp"
/// \brief From the LY algorithm we generate characterizations sets (as in the Chow framework)
/// If the adaptive distinguihsing sequence is complete, then we do not need to augment the LY
/// result. This results in a separating family, which is stronger than a characterization set.
/// However, if it is not complete, we augment it with sequences from the Wp-method.
/// \brief A set (belonging to some state) of characterizing sequences
/// It contains global_suffixes which should be used for testing whether the state is correct. Once
/// we know the states make sense, we can test the transitions with the smaller set local_suffixes.
/// There is some redundancy in this struct, but we have plenty of memory at our disposal.
/// Note that even the global_suffixes may really on the state (because of the adaptiveness of the
/// LY distinguishing sequence).
struct characterization_set {
std::vector<word> global_suffixes;
std::vector<word> local_suffixes;
};
/// \brief A family (indexed by states) of characterizations
using characterization_family = std::vector<characterization_set>;
/// \brief Creates the characterization family from the results of the LY algorithm
/// If the sequence is complete, we do not need the separating_matrix
characterization_family create_seperating_family(const adaptive_distinguishing_sequence & sequence,
const splitting_tree & separating_sequences);

View file

@ -27,10 +27,10 @@ mealy read_mealy_from_txt(std::istream & in) {
state from, to; state from, to;
input i; input i;
output o; output o;
string seperator; string separator;
stringstream ss(line); stringstream ss(line);
ss >> from >> seperator >> i >> seperator >> o >> seperator >> to; ss >> from >> separator >> i >> separator >> o >> separator >> to;
if (from >= max_state) max_state = from + 1; if (from >= max_state) max_state = from + 1;
if (to >= max_state) max_state = to + 1; if (to >= max_state) max_state = to + 1;

View file

@ -1,4 +1,6 @@
#include "characterization_family.hpp" #include "separating_family.hpp"
#include "adaptive_distinguishing_sequence.hpp"
#include "splitting_tree.hpp"
#include "trie.hpp" #include "trie.hpp"
#include <boost/range/algorithm.hpp> #include <boost/range/algorithm.hpp>
@ -10,12 +12,12 @@
using namespace std; using namespace std;
characterization_family create_seperating_family(const adaptive_distinguishing_sequence & sequence, separating_family create_separating_family(const adaptive_distinguishing_sequence & sequence,
const splitting_tree & separating_sequences) { const splitting_tree & separating_sequences) {
const auto N = sequence.CI.size(); const auto N = sequence.CI.size();
vector<trie> suffixes(N); vector<trie> suffixes(N);
characterization_family ret(N); separating_family ret(N);
// First we accumulate the kind-of-UIOs and the separating words we need. We will do this with a // First we accumulate the kind-of-UIOs and the separating words we need. We will do this with a
// breath first search. If we encouter a set of states which is not a singleton, we add // breath first search. If we encouter a set of states which is not a singleton, we add
@ -40,7 +42,8 @@ characterization_family create_seperating_family(const adaptive_distinguishing_s
const auto s = p.second; const auto s = p.second;
states[s] = true; states[s] = true;
} }
const auto root = lca(separating_sequences, [&states](auto z) -> bool { return states[z]; }); const auto root
= lca(separating_sequences, [&states](auto z) -> bool { return states[z]; });
vector<word> stack_of_words; vector<word> stack_of_words;
const function<void(splitting_tree const &)> recursor = [&](splitting_tree const & n) { const function<void(splitting_tree const &)> recursor = [&](splitting_tree const & n) {
@ -53,7 +56,7 @@ characterization_family create_seperating_family(const adaptive_distinguishing_s
} }
} }
} else { } else {
if (n.mark > 1) stack_of_words.push_back(n.seperator); if (n.mark > 1) stack_of_words.push_back(n.separator);
for (auto const & c : n.children) { for (auto const & c : n.children) {
recursor(c); recursor(c);
} }
@ -68,9 +71,7 @@ characterization_family create_seperating_family(const adaptive_distinguishing_s
const auto s = p.second; const auto s = p.second;
auto & current_suffixes = suffixes[s]; auto & current_suffixes = suffixes[s];
// they are the same (FIXME)
ret[s].local_suffixes = flatten(current_suffixes); ret[s].local_suffixes = flatten(current_suffixes);
ret[s].global_suffixes = flatten(current_suffixes);
current_suffixes.clear(); current_suffixes.clear();
} }

26
lib/separating_family.hpp Normal file
View file

@ -0,0 +1,26 @@
#pragma once
#include "types.hpp"
struct adaptive_distinguishing_sequence;
struct splitting_tree;
/// \brief From the LY algorithm we generate a separating family
/// If the adaptive distinguihsing sequence is complete, then we do not need to augment the LY
/// result. If it is not complete, we augment it with sequences from the HSI-method. In both cases
/// the result is a separating family (as defined in LY).
/// \brief A set (belonging to some state) of separating sequences
/// It only has local_suffixes, as all suffixes are "harmonized", meaning that sequences share
/// prefixes among the family. With this structure we can define the HSI-method and DS-method. Our
/// method is a hybrid one. Families are always indexed by state.
struct separating_set {
std::vector<word> local_suffixes;
};
using separating_family = std::vector<separating_set>;
/// \brief Creates the separating family from the results of the LY algorithm
/// If the sequence is complete, we do not need the sequences in the splitting tree.
separating_family create_separating_family(const adaptive_distinguishing_sequence & sequence,
const splitting_tree & separating_sequences);

View file

@ -1,53 +0,0 @@
#include "separating_matrix.hpp"
#include <cassert>
#include <functional>
#include <queue>
using namespace std;
separating_matrix create_all_pair_seperating_sequences(const splitting_tree & root){
const auto N = root.states.size();
separating_matrix all_pair_seperating_sequences(N, separating_row(N));
queue<reference_wrapper<const splitting_tree>> work;
work.push(root);
// total complexity is O(n^2), as we're visiting each pair only once :)
while(!work.empty()){
const splitting_tree & node = work.front();
work.pop();
auto it = begin(node.children);
auto ed = end(node.children);
while(it != ed){
auto jt = next(it);
while(jt != ed){
for(auto && s : it->states){
for(auto && t : jt->states){
assert(all_pair_seperating_sequences[t][s].empty());
assert(all_pair_seperating_sequences[s][t].empty());
all_pair_seperating_sequences[t][s] = node.seperator;
all_pair_seperating_sequences[s][t] = node.seperator;
}
}
jt++;
}
it++;
}
for(auto && c : node.children){
work.push(c);
}
}
for(size_t i = 0; i < N; ++i){
for(size_t j = 0; j < N; ++j){
if(i == j) continue;
assert(!all_pair_seperating_sequences[i][j].empty());
}
}
return all_pair_seperating_sequences;
}

View file

@ -1,13 +0,0 @@
#pragma once
#include "types.hpp"
#include "splitting_tree.hpp"
/// A separating matrix is a matrix indexed by states, which assigns to each
/// pair of (inequivalent) states a separating sequences. This can be done by
/// the classical Hopcroft or Moore algorithm
using separating_row = std::vector<word>;
using separating_matrix = std::vector<separating_row>;
separating_matrix create_all_pair_seperating_sequences(splitting_tree const & root);

View file

@ -112,7 +112,7 @@ result create_splitting_tree(const mealy & g, options opt) {
if (opt.check_validity && !is_valid(new_blocks, symbol)) continue; if (opt.check_validity && !is_valid(new_blocks, symbol)) continue;
// a succesful split, update partition and add the children // a succesful split, update partition and add the children
boom.seperator = {symbol}; boom.separator = {symbol};
add_push_new_block(new_blocks, boom); add_push_new_block(new_blocks, boom);
goto has_split; goto has_split;
@ -135,10 +135,10 @@ result create_splitting_tree(const mealy & g, options opt) {
if (oboom.children.empty()) continue; if (oboom.children.empty()) continue;
// If we want to enforce the right order, we should :D // If we want to enforce the right order, we should :D
if (opt.assert_minimal_order && oboom.seperator.size() != current_order) continue; if (opt.assert_minimal_order && oboom.separator.size() != current_order) continue;
// possibly a succesful split, construct the children // possibly a succesful split, construct the children
const vector<input> word = concat(vector<input>(1, symbol), oboom.seperator); const vector<input> word = concat(vector<input>(1, symbol), oboom.separator);
const auto new_blocks = partition_( const auto new_blocks = partition_(
begin(boom.states), begin(boom.states),
end(boom.states), [word, depth, &g, &update_succession](state state) { end(boom.states), [word, depth, &g, &update_succession](state state) {
@ -153,7 +153,7 @@ result create_splitting_tree(const mealy & g, options opt) {
assert(new_blocks.size() > 1); assert(new_blocks.size() > 1);
// update partition and add the children // update partition and add the children
boom.seperator = word; boom.separator = word;
add_push_new_block(new_blocks, boom); add_push_new_block(new_blocks, boom);
goto has_split; goto has_split;

View file

@ -10,7 +10,7 @@ struct splitting_tree {
std::vector<state> states; std::vector<state> states;
std::vector<splitting_tree> children; std::vector<splitting_tree> children;
word seperator; word separator;
size_t depth = 0; size_t depth = 0;
mutable int mark = 0; // used for some algorithms... mutable int mark = 0; // used for some algorithms...
}; };

View file

@ -7,7 +7,7 @@
using namespace std; using namespace std;
void test(const mealy & specification, const transfer_sequences & prefixes, void test(const mealy & specification, const transfer_sequences & prefixes,
const characterization_family & separating_family, size_t k_max, const writer & output) { const separating_family & separating_family, size_t k_max, const writer & output) {
vector<word> all_sequences(1); vector<word> all_sequences(1);
for (size_t k = 0; k <= k_max; ++k) { for (size_t k = 0; k <= k_max; ++k) {
@ -33,7 +33,7 @@ void test(const mealy & specification, const transfer_sequences & prefixes,
} }
void randomized_test(const mealy & specification, const transfer_sequences & prefixes, void randomized_test(const mealy & specification, const transfer_sequences & prefixes,
const characterization_family & separating_family, size_t min_k, const separating_family & separating_family, size_t min_k,
const writer & output) { const writer & output) {
clog << "*** K >= " << min_k << endl; clog << "*** K >= " << min_k << endl;

View file

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "characterization_family.hpp"
#include "mealy.hpp" #include "mealy.hpp"
#include "separating_family.hpp"
#include "transfer_sequences.hpp" #include "transfer_sequences.hpp"
#include "types.hpp" #include "types.hpp"
@ -14,11 +14,11 @@ struct writer {
/// \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)
void test(mealy const & specification, transfer_sequences const & prefixes, void test(mealy const & specification, transfer_sequences const & prefixes,
characterization_family const & separating_family, size_t k_max, writer const & output); separating_family const & separating_family, size_t k_max, writer const & output);
/// \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)
[[noreturn]] void randomized_test(mealy const & specification, transfer_sequences const & prefixes, [[noreturn]] void randomized_test(mealy const & specification, transfer_sequences const & prefixes,
characterization_family const & separating_family, size_t min_k, separating_family const & separating_family, size_t min_k,
writer const & output); writer const & output);
/// \brief returns a writer which simply writes everything to cout (via inputs) /// \brief returns a writer which simply writes everything to cout (via inputs)

View file

@ -24,9 +24,9 @@ static const auto id = [](auto x) { return x; };
void write_splitting_tree_to_dot(const splitting_tree & root, ostream & out_) { void write_splitting_tree_to_dot(const splitting_tree & root, ostream & out_) {
write_tree_to_dot(root, [](const splitting_tree & node, ostream & out) { write_tree_to_dot(root, [](const splitting_tree & node, ostream & out) {
print_vec(out, node.states, " ", id); print_vec(out, node.states, " ", id);
if (!node.seperator.empty()) { if (!node.separator.empty()) {
out << "\\n"; out << "\\n";
print_vec(out, node.seperator, " ", id); print_vec(out, node.separator, " ", id);
} }
}, out_); }, out_);
} }

View file

@ -3,8 +3,7 @@
#include <mealy.hpp> #include <mealy.hpp>
#include <reachability.hpp> #include <reachability.hpp>
#include <read_mealy.hpp> #include <read_mealy.hpp>
#include <characterization_family.hpp> #include <separating_family.hpp>
#include <separating_matrix.hpp>
#include <splitting_tree.hpp> #include <splitting_tree.hpp>
#include <test_suite.hpp> #include <test_suite.hpp>
#include <transfer_sequences.hpp> #include <transfer_sequences.hpp>
@ -58,7 +57,7 @@ int main(int argc, char *argv[]) try {
const auto & machine = reachable_submachine(move(machine_and_translation.first), 0); const auto & machine = reachable_submachine(move(machine_and_translation.first), 0);
const auto & translation = machine_and_translation.second; const auto & translation = machine_and_translation.second;
auto all_pair_seperating_sequences = [&]{ auto all_pair_separating_sequences = [&]{
const auto splitting_tree_hopcroft = [&]{ const auto splitting_tree_hopcroft = [&]{
time_logger t("creating hopcroft splitting tree"); time_logger t("creating hopcroft splitting tree");
return create_splitting_tree(machine, randomize_hopcroft ? randomized_hopcroft_style : hopcroft_style); return create_splitting_tree(machine, randomize_hopcroft ? randomized_hopcroft_style : hopcroft_style);
@ -102,9 +101,9 @@ int main(int argc, char *argv[]) try {
// const auto all_pair_seperating_sequences = all_pair_seperating_sequences_fut.get(); // const auto all_pair_seperating_sequences = all_pair_seperating_sequences_fut.get();
// const auto sequence = sequence_fut.get(); // const auto sequence = sequence_fut.get();
const auto seperating_family = [&]{ const auto separating_family = [&]{
time_logger t("making seperating family"); time_logger t("making seperating family");
return create_seperating_family(sequence, all_pair_seperating_sequences); return create_separating_family(sequence, all_pair_separating_sequences);
}(); }();
// const auto transfer_sequences = transfer_sequences_fut.get(); // const auto transfer_sequences = transfer_sequences_fut.get();
@ -112,12 +111,12 @@ int main(int argc, char *argv[]) try {
if(streaming){ if(streaming){
time_logger t("outputting all preset tests"); time_logger t("outputting all preset tests");
test(machine, transfer_sequences, seperating_family, k_max, default_writer(inputs)); test(machine, transfer_sequences, separating_family, k_max, default_writer(inputs));
} }
if(random_part){ if(random_part){
time_logger t("outputting all random tests"); time_logger t("outputting all random tests");
randomized_test(machine, transfer_sequences, seperating_family, k_max+1, default_writer(inputs)); randomized_test(machine, transfer_sequences, separating_family, k_max+1, default_writer(inputs));
} }
} catch (exception const & e) { } catch (exception const & e) {

View file

@ -1,10 +1,9 @@
#include <adaptive_distinguishing_sequence.hpp> #include <adaptive_distinguishing_sequence.hpp>
#include <read_mealy.hpp> #include <read_mealy.hpp>
#include <characterization_family.hpp> #include <separating_family.hpp>
#include <separating_matrix.hpp>
#include <trie.hpp>
#include <splitting_tree.hpp> #include <splitting_tree.hpp>
#include <transfer_sequences.hpp> #include <transfer_sequences.hpp>
#include <trie.hpp>
#include <future> #include <future>
#include <string> #include <string>
@ -12,6 +11,17 @@
using namespace std; using namespace std;
enum Method {
hsi_method,
ds_plus_method,
};
static Method parse_method(string const & s) {
if (s == "--W-method") return hsi_method;
if (s == "--DS-method") return ds_plus_method;
throw runtime_error("No valid method specified");
}
int main(int argc, char * argv[]) { int main(int argc, char * argv[]) {
if (argc != 4) { if (argc != 4) {
cerr << "usage: methods <file> <mode> <k_max>\n"; cerr << "usage: methods <file> <mode> <k_max>\n";
@ -19,11 +29,10 @@ int main(int argc, char * argv[]) {
} }
const string filename = argv[1]; const string filename = argv[1];
const string mode = argv[2]; const Method method = parse_method(argv[2]);
const bool use_no_LY = mode == "--W-method";
const size_t k_max = std::stoul(argv[3]); const size_t k_max = std::stoul(argv[3]);
const auto machine = [&]{ const auto machine = [&] {
if (filename.find(".txt") != string::npos) { if (filename.find(".txt") != string::npos) {
return read_mealy_from_txt(filename); return read_mealy_from_txt(filename);
} else if (filename.find(".dot") != string::npos) { } else if (filename.find(".dot") != string::npos) {
@ -35,7 +44,7 @@ int main(int argc, char * argv[]) {
}(); }();
auto sequence_fut = async([&] { auto sequence_fut = async([&] {
if (use_no_LY) { if (method == hsi_method) {
return create_adaptive_distinguishing_sequence(result(machine.graph_size)); return create_adaptive_distinguishing_sequence(result(machine.graph_size));
} }
const auto tree = create_splitting_tree(machine, randomized_lee_yannakakis_style); const auto tree = create_splitting_tree(machine, randomized_lee_yannakakis_style);
@ -63,7 +72,7 @@ int main(int argc, char * argv[]) {
clog << "getting sequence and pairs" << endl; clog << "getting sequence and pairs" << endl;
auto suffixes_fut = async([&] { auto suffixes_fut = async([&] {
return create_seperating_family(sequence_fut.get(), pairs_fut.get()); return create_separating_family(sequence_fut.get(), pairs_fut.get());
}); });
clog << "getting prefixes, middles and suffixes" << endl; clog << "getting prefixes, middles and suffixes" << endl;
@ -81,8 +90,7 @@ int main(int argc, char * argv[]) {
for (auto && m : middles) { for (auto && m : middles) {
const state s2 = apply(machine, s1, begin(m), end(m)).to; const state s2 = apply(machine, s1, begin(m), end(m)).to;
const word w2 = concat(w1, m); const word w2 = concat(w1, m);
const auto & suffixes_for_state = (m.size() == k_max) ? suffixes[s2].local_suffixes const auto & suffixes_for_state = suffixes[s2].local_suffixes;
: suffixes[s2].global_suffixes;
for (auto && s : suffixes_for_state) { for (auto && s : suffixes_for_state) {
word test = concat(w2, s); word test = concat(w2, s);
test_suite.insert(test); test_suite.insert(test);