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

Simplified the lca implementation (now without state)

This commit is contained in:
Joshua Moerman 2015-07-10 09:31:39 +02:00
parent 8d9286a0f8
commit a9e3fdfd1c
5 changed files with 63 additions and 54 deletions

View file

@ -1,7 +1,7 @@
project(Yannakakis) project(Yannakakis)
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
find_package(Boost REQUIRED COMPONENTS iostreams program_options filesystem system serialization) find_package(Boost REQUIRED COMPONENTS iostreams program_options filesystem system serialization)
include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) include_directories(SYSTEM ${Boost_INCLUDE_DIRS})

View file

@ -42,29 +42,18 @@ separating_family create_separating_family(const adaptive_distinguishing_sequenc
const auto s = p.second; const auto s = p.second;
states[s] = true; states[s] = true;
} }
const auto root const auto roots
= lca(separating_sequences, [&states](state z) -> bool { return states[z]; }); = multi_lca(separating_sequences, [&states](state z) -> bool { return states[z]; });
vector<word> stack_of_words; // NOTE: this is slightly less efficient than doing the same thing inline in lca(...)
const function<void(splitting_tree const &)> recursor = [&](splitting_tree const & n) { // but I was to lazy to write a dfs again
if (n.children.empty()) { for (const splitting_tree & n : roots) {
for (state s : n.states) { for (state s : n.states) {
if (states[s]) { if (states[s]) {
for (auto const & w : stack_of_words) { suffixes[s].insert(n.separator);
suffixes[s].insert(w);
}
}
} }
} else {
if (n.mark > 1) stack_of_words.push_back(n.separator);
for (auto const & c : n.children) {
recursor(c);
}
if (n.mark > 1) stack_of_words.pop_back();
} }
}; }
recursor(root);
// Finalize the suffixes // Finalize the suffixes
for (auto && p : node.CI) { for (auto && p : node.CI) {

View file

@ -15,14 +15,6 @@ splitting_tree::splitting_tree(size_t N, size_t d) : states(N), depth(d) {
iota(begin(states), end(states), 0); iota(begin(states), end(states), 0);
} }
splitting_tree & lca_impl2(splitting_tree & node) {
if (node.mark > 1) return node;
for (auto && c : node.children) {
if (c.mark > 0) return lca_impl2(c);
}
return node; // this is a leaf
}
result create_splitting_tree(const mealy & g, options opt) { result create_splitting_tree(const mealy & g, options opt) {
const auto N = g.graph_size; const auto N = g.graph_size;
const auto P = g.input_size; const auto P = g.input_size;

View file

@ -12,36 +12,66 @@ struct splitting_tree {
std::vector<splitting_tree> children; std::vector<splitting_tree> children;
word separator; word separator;
size_t depth = 0; size_t depth = 0;
mutable int mark = 0; // used for some algorithms...
}; };
template <typename Fun> void lca_impl1(splitting_tree const & node, Fun && f) { /// \brief the generic lca implementation.
node.mark = 0; /// It uses \p store to store the relevant nodes (in some bottom up order), the last store is the
if (!node.children.empty()) { /// actual lowest common ancestor (but the other might be relevant as well). The function \p f is
for (auto && c : node.children) { /// the predicate on the states (returns true for the states we want to compute the lca of).
lca_impl1(c, f); template <typename Fun, typename Store>
if (c.mark) node.mark++; size_t lca_impl(splitting_tree const & node, Fun && f, Store && store) {
static_assert(std::is_same<decltype(f(state(0))), bool>::value, "f should return a bool");
if (node.children.empty()) {
// if it is a leaf, we search for the states
// if it contains a state, return this leaf
for (auto s : node.states) {
if (f(s)) {
store(node);
return 1;
}
} }
// did not contain the leaf => nullptr
return 0;
} else { } else {
for (auto && s : node.states) { // otherwise, check our children. If there is a single one giving a node
if (f(s)) node.mark++; // we return this (it's the lca), if more children return a non-nil
// node, then we are the lca
size_t count = 0;
for (auto & c : node.children) {
auto inner_count = lca_impl(c, f, store);
if (inner_count > 0) count++;
} }
}
}
splitting_tree & lca_impl2(splitting_tree & node); if (count >= 2) {
store(node);
}
return count;
}
throw std::logic_error("unreachable code");
}
/// \brief Find the lowest common ancestor of elements on which \p f returns true. /// \brief Find the lowest common ancestor of elements on which \p f returns true.
template <typename Fun> splitting_tree & lca(splitting_tree & root, Fun && f) { template <typename Fun> splitting_tree & lca(splitting_tree & root, Fun && f) {
static_assert(std::is_same<decltype(f(0)), bool>::value, "f should return a bool"); splitting_tree const * store = nullptr;
lca_impl1(root, f); lca_impl(root, f, [&store](splitting_tree const & node) { store = &node; });
return lca_impl2(root); return const_cast<splitting_tree &>(*store); // NOTE: this const_cast is safe
} }
template <typename Fun> const splitting_tree & lca(const splitting_tree & root, Fun && f) { template <typename Fun> const splitting_tree & lca(const splitting_tree & root, Fun && f) {
static_assert(std::is_same<decltype(f(0)), bool>::value, "f should return a bool"); splitting_tree const * store = nullptr;
lca_impl1(root, f); lca_impl(root, f, [&store](splitting_tree const & node) { store = &node; });
return lca_impl2(const_cast<splitting_tree &>(root)); return *store;
}
/// \brief Find "all" lca's of elements on which \p f returns true.
/// This can be used to collect all the separating sequences for the subset of states.
template <typename Fun>
std::vector<std::reference_wrapper<const splitting_tree>> multi_lca(const splitting_tree & root,
Fun && f) {
std::vector<std::reference_wrapper<const splitting_tree>> ret;
lca_impl(root, f, [&ret](splitting_tree const & node) { ret.emplace_back(node); });
return ret;
} }

View file

@ -3,11 +3,9 @@ set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
file(GLOB sources "*.cpp") file(GLOB sources "*.cpp")
#foreach(source ${sources}) foreach(source ${sources})
# get_filename_component(exec ${source} NAME_WE) get_filename_component(exec ${source} NAME_WE)
# add_executable(${exec} ${source}) add_executable(${exec} ${source})
# target_link_libraries(${exec} common ${libs}) target_link_libraries(${exec} common ${libs})
#endforeach() endforeach()
add_executable(main main.cpp)
target_link_libraries(main common ${libs})