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)
|
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})
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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})
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue