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:
parent
8d9286a0f8
commit
a9e3fdfd1c
5 changed files with 63 additions and 54 deletions
|
@ -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})
|
||||
|
|
|
@ -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()) {
|
||||
for (state s : n.states) {
|
||||
if (states[s]) {
|
||||
for (auto const & w : stack_of_words) {
|
||||
suffixes[s].insert(w);
|
||||
}
|
||||
}
|
||||
// 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]) {
|
||||
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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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})
|
||||
|
|
Loading…
Add table
Reference in a new issue