diff --git a/lib/read_mealy.cpp b/lib/read_mealy.cpp index c19429e4a631aa2583dec7d14d5f335356844c4f..c1ec122529f4f3a88e04cbd2a0654eceee1df59d 100644 --- a/lib/read_mealy.cpp +++ b/lib/read_mealy.cpp @@ -15,7 +15,7 @@ static string easy_substr(string const & s, size_t begin, size_t end){ return s.substr(begin, end - begin); } -mealy read_mealy_from_txt(std::istream & in) { +mealy read_mealy_from_txt(std::istream & in, bool check) { mealy m; state max_state = 0; @@ -54,16 +54,16 @@ mealy read_mealy_from_txt(std::istream & in) { if (m.graph_size == 0) throw runtime_error("Empty state set"); if (m.input_size == 0) throw runtime_error("Empty input set"); if (m.output_size == 0) throw runtime_error("Empty output set"); - if (!is_complete(m)) throw runtime_error("Partial machine"); + if (check && !is_complete(m)) throw runtime_error("Partial machine"); return m; } -mealy read_mealy_from_txt(const std::string & filename) { +mealy read_mealy_from_txt(const std::string & filename, bool check) { std::ifstream file(filename); - return read_mealy_from_txt(file); + return read_mealy_from_txt(file, check); } -mealy read_mealy_from_dot(std::istream & in, translation & t){ +mealy read_mealy_from_dot(std::istream & in, translation & t, bool check){ mealy m; std::unordered_map<std::string, state> state_indices; @@ -116,27 +116,27 @@ mealy read_mealy_from_dot(std::istream & in, translation & t){ if(m.graph_size == 0) throw runtime_error("Empty state set"); if(m.input_size == 0) throw runtime_error("Empty input set"); if(m.output_size == 0) throw runtime_error("Empty output set"); - if(!is_complete(m)) throw runtime_error("Partial machine"); + if(check && !is_complete(m)) throw runtime_error("Partial machine"); return m; } -mealy read_mealy_from_dot(const string & filename, translation & t){ +mealy read_mealy_from_dot(const string & filename, translation & t, bool check){ ifstream file(filename); - return read_mealy_from_dot(file, t); + return read_mealy_from_dot(file, t, check); } -std::pair<mealy, translation> read_mealy_from_dot(istream & in){ +std::pair<mealy, translation> read_mealy_from_dot(istream & in, bool check){ translation t; - const auto m = read_mealy_from_dot(in, t); + const auto m = read_mealy_from_dot(in, t, check); return {move(m), move(t)}; } -std::pair<mealy, translation> read_mealy_from_dot(const string & filename){ +std::pair<mealy, translation> read_mealy_from_dot(const string & filename, bool check){ translation t; - const auto m = read_mealy_from_dot(filename, t); + const auto m = read_mealy_from_dot(filename, t, check); return {move(m), move(t)}; } diff --git a/lib/read_mealy.hpp b/lib/read_mealy.hpp index a1725826588b61090a72a5d0cb01d6489f233d9c..ebfd938fb1dd7571fc8733ba516d3aaf332c91ca 100644 --- a/lib/read_mealy.hpp +++ b/lib/read_mealy.hpp @@ -12,18 +12,18 @@ struct translation; /// \brief reads a mealy machine from plain txt file as provided by A. T. Endo /// States, inputs and outputs in these files are already integral, so no need for translation -mealy read_mealy_from_txt(std::istream & in); -mealy read_mealy_from_txt(std::string const & filename); +mealy read_mealy_from_txt(std::istream & in, bool check = true); +mealy read_mealy_from_txt(std::string const & filename, bool check = true); /// \brief reads a mealy machine from dot files as generated by learnlib /// Here we need a translation, which is extended during parsing -mealy read_mealy_from_dot(std::istream & in, translation & t); -mealy read_mealy_from_dot(std::string const & filename, translation & t); +mealy read_mealy_from_dot(std::istream & in, translation & t, bool check = true); +mealy read_mealy_from_dot(std::string const & filename, translation & t, bool check = true); /// \brief reads a mealy machine from dot files as generated by learnlib /// Here the translation starts out empty and is returned in the end -std::pair<mealy, translation> read_mealy_from_dot(std::istream & in); -std::pair<mealy, translation> read_mealy_from_dot(std::string const & filename); +std::pair<mealy, translation> read_mealy_from_dot(std::istream & in, bool check = true); +std::pair<mealy, translation> read_mealy_from_dot(std::string const & filename, bool check = true); /// \brief For non-integral formats we use a translation to integers diff --git a/src/complete.cpp b/src/complete.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b483c2775b1b5a91b95311e50fe1ae8d3ae90590 --- /dev/null +++ b/src/complete.cpp @@ -0,0 +1,100 @@ +#include <adaptive_distinguishing_sequence.hpp> +#include <read_mealy.hpp> +#include <separating_family.hpp> +#include <splitting_tree.hpp> +#include <test_suite.hpp> +#include <transfer_sequences.hpp> +#include <trie.hpp> + +#include <docopt.h> + +#include <future> +#include <iostream> +#include <random> +#include <string> + +using namespace std; + +static const char USAGE[] = + R"(FSM-completer (only dot), also renames the state names + + Usage: + methods [options] <file> + + Options: + -h, --help Show current help + --version Show version + --sink Completion with sink + --loop Completion with self loops (default) + --output <out> Output for new transitions (leave empty for fresh output) +)"; + +void write_mealy_to_dot(const mealy & m, const translation & translation, std::ostream & out) { + const auto inputs = create_reverse_map(translation.input_indices); + const auto output = create_reverse_map(translation.output_indices); + + out << "digraph {\n"; + + for (state s = 0; s < m.graph_size; ++s) { + for (input i = 0; i < m.input_size; ++i) { + if (!defined(m, s, i)) continue; + const auto ret = apply(m, s, i); + out << s << " -> " << ret.to << " [label=\"" << inputs[i] << " / " << output[ret.out] + << "\"]\n"; + } + } + + out << "}\n"; +} + +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(); + + auto mt = read_mealy_from_dot(filename, false); + auto & machine = mt.first; + auto & translation = mt.second; + + if (!is_complete(machine)) { + const auto out = [&]() -> output { + if (args.at("--output")) { + const string out_str = args.at("--output").asString(); + if (translation.output_indices.count(out_str)) { + // reuse old output + return translation.output_indices[out_str]; + } + } + // else: grab a new one + string newo = "SILENT"; + while(translation.output_indices.count(newo)) newo += '0'; + return translation.output_indices[newo] = machine.output_size++; + }(); + + + if (args.at("--sink").asBool()) { + // add sink + const auto new_state = machine.graph_size++; + machine.graph.resize(machine.graph_size); + + for (state s = 0; s < machine.graph_size; ++s) { + machine.graph[s].resize(machine.input_size); + for (input i = 0; i < machine.input_size; ++i) { + if (defined(machine, s, i)) continue; + machine.graph[s][i] = mealy::edge(new_state, out); + } + } + } else { + // add self loops + for (state s = 0; s < machine.graph_size; ++s) { + machine.graph[s].resize(machine.input_size); + for (input i = 0; i < machine.input_size; ++i) { + if (defined(machine, s, i)) continue; + machine.graph[s][i] = mealy::edge(s, out); + } + } + } + } + + write_mealy_to_dot(machine, translation, cout); +}