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)
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)
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;
states[s] = true;
}
const auto root
= lca(separating_sequences, [&states](state z) -> bool { return states[z]; });
const auto roots
= multi_lca(separating_sequences, [&states](state z) -> bool { return states[z]; });
vector<word> stack_of_words;
const function<void(splitting_tree const &)> recursor = [&](splitting_tree const & n) {
if (n.children.empty()) {
// NOTE: this is slightly less efficient than doing the same thing inline in lca(...)
// but I was to lazy to write a dfs again
for (const splitting_tree & n : roots) {
for (state s : n.states) {
if (states[s]) {
for (auto const & w : stack_of_words) {
suffixes[s].insert(w);
suffixes[s].insert(n.separator);
}
}
}
} 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
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);
}
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) {
const auto N = g.graph_size;
const auto P = g.input_size;

View file

@ -12,36 +12,66 @@ struct splitting_tree {
std::vector<splitting_tree> children;
word separator;
size_t depth = 0;
mutable int mark = 0; // used for some algorithms...
};
template <typename Fun> void lca_impl1(splitting_tree const & node, Fun && f) {
node.mark = 0;
if (!node.children.empty()) {
for (auto && c : node.children) {
lca_impl1(c, f);
if (c.mark) node.mark++;
/// \brief the generic lca implementation.
/// It uses \p store to store the relevant nodes (in some bottom up order), the last store is the
/// actual lowest common ancestor (but the other might be relevant as well). The function \p f is
/// the predicate on the states (returns true for the states we want to compute the lca of).
template <typename Fun, typename Store>
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 {
for (auto && s : node.states) {
if (f(s)) node.mark++;
}
}
// otherwise, check our children. If there is a single one giving a node
// 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.
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");
lca_impl1(root, f);
return lca_impl2(root);
splitting_tree const * store = nullptr;
lca_impl(root, f, [&store](splitting_tree const & node) { store = &node; });
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) {
static_assert(std::is_same<decltype(f(0)), bool>::value, "f should return a bool");
lca_impl1(root, f);
return lca_impl2(const_cast<splitting_tree &>(root));
splitting_tree const * store = nullptr;
lca_impl(root, f, [&store](splitting_tree const & node) { store = &node; });
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")
#foreach(source ${sources})
# get_filename_component(exec ${source} NAME_WE)
# add_executable(${exec} ${source})
# target_link_libraries(${exec} common ${libs})
#endforeach()
foreach(source ${sources})
get_filename_component(exec ${source} NAME_WE)
add_executable(${exec} ${source})
target_link_libraries(${exec} common ${libs})
endforeach()
add_executable(main main.cpp)
target_link_libraries(main common ${libs})