diff --git a/.gitignore b/.gitignore index b6931c6..a9376ac 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ *.pdf *_seq *splitting_tree +*test_suite diff --git a/lib/splitting_tree.cpp b/lib/splitting_tree.cpp index 93fa93f..f7b0474 100644 --- a/lib/splitting_tree.cpp +++ b/lib/splitting_tree.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include using namespace std; @@ -41,6 +42,12 @@ result create_splitting_tree(const mealy& g, options opt){ queue> work; size_t days_without_progress = 0; + /* List of inputs, will be shuffled in case of randomizations */ + vector all_inputs(g.input_size); + iota(begin(all_inputs), end(all_inputs), 0); + random_device rd; + mt19937 generator(rd()); + // Some lambda functions capturing some state, makes the code a bit easier :) const auto add_push_new_block = [&work](auto new_blocks, auto & boom) { boom.children.assign(new_blocks.size(), splitting_tree(0, boom.depth + 1)); @@ -83,8 +90,12 @@ result create_splitting_tree(const mealy& g, options opt){ if(boom.states.size() == 1) continue; + if(opt.randomized){ + shuffle(begin(all_inputs), end(all_inputs), generator); + } + // First try to split on output - for(input symbol = 0; symbol < P; ++symbol){ + for(input symbol : all_inputs){ const auto new_blocks = partition_(begin(boom.states), end(boom.states), [symbol, depth, &g, &update_succession](state state){ const auto ret = apply(g, state, symbol); update_succession(state, ret.to, depth); @@ -105,7 +116,7 @@ result create_splitting_tree(const mealy& g, options opt){ } // Then try to split on state - for(input symbol = 0; symbol < P; ++symbol){ + for(input symbol : all_inputs){ vector successor_states(N, false); for(auto && state : boom.states){ successor_states[apply(g, state, symbol).to.base()] = true; diff --git a/lib/splitting_tree.hpp b/lib/splitting_tree.hpp index 05206e2..5955c21 100644 --- a/lib/splitting_tree.hpp +++ b/lib/splitting_tree.hpp @@ -58,11 +58,13 @@ const splitting_tree & lca(const splitting_tree & root, Fun && f){ struct options { bool check_validity = true; bool cache_succesors = true; + bool randomized = false; }; -constexpr options lee_yannakakis_style{true, true}; -constexpr options hopcroft_style{false, false}; - +constexpr options lee_yannakakis_style{true, true, false}; +constexpr options hopcroft_style{false, false, false}; +constexpr options randomized_lee_yannakakis_style{true, true, true}; +constexpr options randomized_hopcroft_style{false, false, true}; /* * The algorithm to create a splitting tree also produces some other useful diff --git a/lib/transfer_sequences.cpp b/lib/transfer_sequences.cpp index 9a3d36c..aae7deb 100644 --- a/lib/transfer_sequences.cpp +++ b/lib/transfer_sequences.cpp @@ -2,7 +2,10 @@ #include "mealy.hpp" +#include +#include #include +#include using namespace std; @@ -10,10 +13,12 @@ transfer_sequences create_transfer_sequences(const mealy& machine, state s){ vector visited(machine.graph_size, false); vector words(machine.graph_size); - queue work; - work.push(s); + priority_queue> work; + work.push({0, s}); while(!work.empty()){ - const auto u = work.front(); + const auto p = work.top(); + const auto u = p.second; + const auto d = p.first - 1; work.pop(); if(visited[u.base()]) continue; @@ -26,17 +31,44 @@ transfer_sequences create_transfer_sequences(const mealy& machine, state s){ words[v.base()] = words[u.base()]; words[v.base()].push_back(i); - work.push(v); + work.push({d, v}); } } return words; } -std::vector create_all_transfer_sequences(const mealy& machine){ - vector transfer_sequences(machine.graph_size); - for(state s = 0; s < machine.graph_size; ++s){ - transfer_sequences[s.base()] = create_transfer_sequences(machine, s); +transfer_sequences create_randomized_transfer_sequences(const mealy & machine, state s){ + random_device rd; + mt19937 generator(rd()); + + vector visited(machine.graph_size, false); + vector words(machine.graph_size); + vector all_inputs(machine.input_size); + iota(begin(all_inputs), end(all_inputs), input(0)); + + priority_queue> work; + work.push({0, s}); + while(!work.empty()){ + const auto p = work.top(); + const auto u = p.second; + const auto d = p.first - 1; + work.pop(); + + if(visited[u.base()]) continue; + + visited[u.base()] = true; + + shuffle(begin(all_inputs), end(all_inputs), generator); + for(input i : all_inputs){ + const auto v = apply(machine, u, i).to; + if(visited[v.base()]) continue; + + words[v.base()] = words[u.base()]; + words[v.base()].push_back(i); + work.push({d, v}); + } } - return transfer_sequences; + + return words; } diff --git a/lib/transfer_sequences.hpp b/lib/transfer_sequences.hpp index 95e2d36..df346a5 100644 --- a/lib/transfer_sequences.hpp +++ b/lib/transfer_sequences.hpp @@ -7,4 +7,4 @@ struct mealy; using transfer_sequences = std::vector; transfer_sequences create_transfer_sequences(mealy const & machine, state s); -std::vector create_all_transfer_sequences(mealy const & machine); +transfer_sequences create_randomized_transfer_sequences(mealy const & machine, state s); diff --git a/src/main.cpp b/src/main.cpp index 1b4e9f9..4ce3d0b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -33,6 +33,11 @@ int main(int argc, char *argv[]){ const bool statistics = mode == "stats"; const bool compress_suite = mode == "compr"; + const bool use_relevances = true; + const bool randomize_prefixes = true; + const bool randomize_hopcroft = true; + const bool randomize_lee_yannakakis = true; + const auto machine = [&]{ time_logger t("reading file " + filename); if(use_stdio){ @@ -45,7 +50,7 @@ int main(int argc, char *argv[]){ auto all_pair_seperating_sequences_fut = async([&]{ const auto splitting_tree_hopcroft = [&]{ time_logger t("creating hopcroft splitting tree"); - return create_splitting_tree(machine, hopcroft_style); + return create_splitting_tree(machine, randomize_hopcroft ? randomized_hopcroft_style : hopcroft_style); }(); const auto all_pair_seperating_sequences = [&]{ @@ -59,7 +64,7 @@ int main(int argc, char *argv[]){ auto sequence_fut = async([&]{ const auto splitting_tree = [&]{ time_logger t("Lee & Yannakakis I"); - return create_splitting_tree(machine, lee_yannakakis_style); + return create_splitting_tree(machine, randomize_lee_yannakakis ? randomized_lee_yannakakis_style : lee_yannakakis_style); }(); const auto sequence = [&]{ @@ -72,7 +77,11 @@ int main(int argc, char *argv[]){ auto transfer_sequences_fut = std::async([&]{ time_logger t("determining transfer sequences"); - return create_transfer_sequences(machine, 0); + if(randomize_prefixes){ + return create_randomized_transfer_sequences(machine, 0); + } else { + return create_transfer_sequences(machine, 0); + } }); auto inputs_fut = std::async([&]{ @@ -84,11 +93,13 @@ int main(int argc, char *argv[]){ vector> distributions(machine.graph_size); for(state s = 0; s < machine.graph_size; ++s){ - vector r_cache(machine.input_size, 0); - for(input i = 0; i < machine.input_size; ++i){ - const auto test1 = apply(machine, s, i).output != machine.output_indices.at("quiescence"); - const auto test2 = apply(machine, s, i).to != s; - r_cache[i.base()] = test1 + test2; + vector r_cache(machine.input_size, 1); + if(use_relevances){ + for(input i = 0; i < machine.input_size; ++i){ + //const auto test1 = apply(machine, s, i).output != machine.output_indices.at("quiescence"); + const auto test2 = apply(machine, s, i).to != s; + r_cache[i.base()] = 0.1 + test2; + } } distributions[s.base()] = discrete_distribution(begin(r_cache), end(r_cache)); @@ -185,7 +196,7 @@ int main(int argc, char *argv[]){ std::mt19937 generator(rd()); uniform_int_distribution prefix_selection(0, transfer_sequences.size()); - uniform_int_distribution<> fair_coin(0, 1); + uniform_int_distribution<> unfair_coin(0, 2); // expected flips is p / (p-1)^2, where p is succes probability uniform_int_distribution suffix_selection; auto relevant_inputs = relevant_inputs_fut.get(); @@ -200,7 +211,7 @@ int main(int argc, char *argv[]){ vector m; m.reserve(k_max + 2); size_t minimal_size = k_max + 1; - while(minimal_size || fair_coin(generator)){ + while(minimal_size || unfair_coin(generator)){ input i = relevant_inputs[current_state.base()](generator); m.push_back(i); current_state = apply(machine, current_state, i).to;