diff --git a/src/generator.cpp b/src/generator.cpp index d2e6d101afb1422178390497fd87338ba71a8fcc..fde98a3c9c8e7222a9b3387390ad534be9474db0 100644 --- a/src/generator.cpp +++ b/src/generator.cpp @@ -3,6 +3,7 @@ #include <splitting_tree.hpp> #include <docopt.h> +#include <boost/lexical_cast.hpp> #include <iostream> #include <random> @@ -14,15 +15,18 @@ static const char USAGE[] = R"(Random Mealy machine generator Usage: - generator random [-mc] <states> <inputs> <outputs> <machines> [<seed>] + generator random [options] <states> <inputs> <outputs> <machines> [<seed>] generator hopcroft a <states> generator hopcroft b <states> Options: - -h, --help Show this screen - --version Show version - -m, --minimal Only generate minimal machines - -c, --connected Only generate reachable machines + -h, --help Show this screen + --version Show version + -m, --minimal Only generate minimal machines + -c, --connected Only generate reachable machines + --output-cluster <factor> How clustered should the outputs be + --state-cluster <factor> And what about states + --single-output-boost <fctr> Boost for a single output (e.g. quiescence) )"; static size_t number_of_leaves(splitting_tree const & root) { @@ -32,7 +36,13 @@ static size_t number_of_leaves(splitting_tree const & root) { [](auto const & l, auto const & r) { return l + number_of_leaves(r); }); } -static mealy generate_random_machine(size_t N, size_t P, size_t Q, mt19937 & gen) { +struct random_options { + double output_spread = 0; + double state_spread = 0; + double single_output_boost = 1; +}; + +static mealy generate_random_machine(size_t N, size_t P, size_t Q, random_options opts, mt19937 & gen) { mealy m; m.graph_size = N; @@ -41,12 +51,32 @@ static mealy generate_random_machine(size_t N, size_t P, size_t Q, mt19937 & gen m.graph.assign(m.graph_size, vector<mealy::edge>(m.input_size)); - uniform_int_distribution<output> o_dist(0, m.output_size - 1); - uniform_int_distribution<state> s_dist(0, m.graph_size - 1); + auto o_dist = [&] { + const auto factor = opts.output_spread; + vector<double> probs(m.output_size); + for (output o = 0; o < m.output_size; ++o) + probs[o] = exp(factor * o / double(m.output_size - 1)); + probs[0] *= opts.single_output_boost; + discrete_distribution<output> dist(probs.begin(), probs.end()); + return dist; + }(); + + auto s_dist = [&] { + const auto factor = opts.state_spread; + vector<double> probs(m.graph_size); + for (output o = 0; o < m.graph_size; ++o) + probs[o] = exp(factor * o / double(m.graph_size - 1)); + discrete_distribution<state> dist(probs.begin(), probs.end()); + return dist; + }(); + + vector<state> states(m.graph_size); + iota(states.begin(), states.end(), 0); for (state s = 0; s < m.graph_size; ++s) { + shuffle(states.begin(), states.end(), gen); for (input i = 0; i < m.input_size; ++i) { - m.graph[s][i] = {s_dist(gen), o_dist(gen)}; + m.graph[s][i] = {states[s_dist(gen)], o_dist(gen)}; } } @@ -68,6 +98,14 @@ int main(int argc, char * argv[]) { const auto args = docopt::docopt(USAGE, {argv + 1, argv + argc}, true, __DATE__ __TIME__); if (args.at("random").asBool()) { + random_options opts; + if (args.at("--output-cluster")) + opts.output_spread = -boost::lexical_cast<double>(args.at("--output-cluster").asString()); + if (args.at("--state-cluster")) + opts.state_spread = -boost::lexical_cast<double>(args.at("--state-cluster").asString()); + if (args.at("--single-output-boost")) + opts.single_output_boost = boost::lexical_cast<double>(args.at("--single-output-boost").asString()); + auto gen = [&] { if (args.at("<seed>")) { auto seed = args.at("<seed>").asLong(); @@ -83,7 +121,7 @@ int main(int argc, char * argv[]) { while (constructed < number_of_machines) { auto const m = generate_random_machine(args.at("<states>").asLong(), args.at("<inputs>").asLong(), - args.at("<outputs>").asLong(), gen); + args.at("<outputs>").asLong(), opts, gen); if (args.at("--connected").asBool()) { auto const m2 = reachable_submachine(m, 0);