diff --git a/src/generator.cpp b/src/generator.cpp index d2e6d10..fde98a3 100644 --- a/src/generator.cpp +++ b/src/generator.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -14,15 +15,18 @@ static const char USAGE[] = R"(Random Mealy machine generator Usage: - generator random [-mc] [] + generator random [options] [] generator hopcroft a generator hopcroft b 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 How clustered should the outputs be + --state-cluster And what about states + --single-output-boost 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(m.input_size)); - uniform_int_distribution o_dist(0, m.output_size - 1); - uniform_int_distribution s_dist(0, m.graph_size - 1); + auto o_dist = [&] { + const auto factor = opts.output_spread; + vector 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 dist(probs.begin(), probs.end()); + return dist; + }(); + + auto s_dist = [&] { + const auto factor = opts.state_spread; + vector 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 dist(probs.begin(), probs.end()); + return dist; + }(); + + vector 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(args.at("--output-cluster").asString()); + if (args.at("--state-cluster")) + opts.state_spread = -boost::lexical_cast(args.at("--state-cluster").asString()); + if (args.at("--single-output-boost")) + opts.single_output_boost = boost::lexical_cast(args.at("--single-output-boost").asString()); + auto gen = [&] { if (args.at("")) { auto seed = args.at("").asLong(); @@ -83,7 +121,7 @@ int main(int argc, char * argv[]) { while (constructed < number_of_machines) { auto const m = generate_random_machine(args.at("").asLong(), args.at("").asLong(), - args.at("").asLong(), gen); + args.at("").asLong(), opts, gen); if (args.at("--connected").asBool()) { auto const m2 = reachable_submachine(m, 0);