mirror of
https://github.com/Jaxan/hybrid-ads.git
synced 2025-04-27 06:57:44 +02:00
Reduces memory usage a bit by using smaller types.
This commit is contained in:
parent
f5108ceb43
commit
1856602e3c
10 changed files with 40 additions and 45 deletions
|
@ -18,9 +18,9 @@
|
|||
struct mealy {
|
||||
struct edge {
|
||||
edge() = default;
|
||||
edge(state t, output o) : to(t), output(o) {}
|
||||
edge(state t, output o) : to(t), out(o) {}
|
||||
state to = state(-1);
|
||||
output output = size_t(-1);
|
||||
output out = output(-1);
|
||||
};
|
||||
|
||||
// state -> input -> (output, state)
|
||||
|
@ -34,7 +34,7 @@ struct mealy {
|
|||
inline bool is_complete(const mealy & m){
|
||||
for(state n = 0; n < m.graph_size; ++n){
|
||||
if(m.graph[n].size() != m.input_size) return false;
|
||||
for(auto && e : m.graph[n]) if(e.to == state(-1) || e.output == output(-1)) return false;
|
||||
for(auto && e : m.graph[n]) if(e.to == state(-1) || e.out == output(-1)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ inline bool is_complete(const mealy & m){
|
|||
inline bool defined(mealy const & m, state s, input i) {
|
||||
if (s >= m.graph.size()) return false;
|
||||
if (i >= m.graph[s].size()) return false;
|
||||
if (m.graph[s][i].to == state(-1) || m.graph[s][i].output == output(-1)) return false;
|
||||
if (m.graph[s][i].to == state(-1) || m.graph[s][i].out == output(-1)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ mealy reachable_submachine(const mealy& in, state start) {
|
|||
|
||||
for (input i = 0; i < in.input_size; ++i) {
|
||||
const auto ret = apply(in, s, i);
|
||||
const output o = ret.output;
|
||||
const output o = ret.out;
|
||||
const state t = ret.to;
|
||||
|
||||
if (!new_state.count(t)) new_state[t] = max_state++;
|
||||
|
|
|
@ -16,7 +16,7 @@ separating_family create_separating_family(const adaptive_distinguishing_sequenc
|
|||
const splitting_tree & separating_sequences) {
|
||||
const auto N = sequence.CI.size();
|
||||
|
||||
vector<trie> suffixes(N);
|
||||
vector<trie<input>> suffixes(N);
|
||||
separating_family ret(N);
|
||||
|
||||
// First we accumulate the kind-of-UIOs and the separating words we need. We will do this with a
|
||||
|
|
|
@ -102,7 +102,7 @@ result create_splitting_tree(const mealy & g, options opt) {
|
|||
end(boom.states), [symbol, depth, &g, &update_succession](state state) {
|
||||
const auto r = apply(g, state, symbol);
|
||||
update_succession(state, r.to, depth);
|
||||
return r.output;
|
||||
return r.out;
|
||||
}, Q);
|
||||
|
||||
// no split -> continue with other input symbols
|
||||
|
@ -144,7 +144,7 @@ result create_splitting_tree(const mealy & g, options opt) {
|
|||
end(boom.states), [word, depth, &g, &update_succession](state state) {
|
||||
const mealy::edge r = apply(g, state, word.begin(), word.end());
|
||||
update_succession(state, r.to, depth);
|
||||
return r.output;
|
||||
return r.out;
|
||||
}, Q);
|
||||
|
||||
// not a valid split -> continue
|
||||
|
|
17
lib/trie.cpp
17
lib/trie.cpp
|
@ -1,17 +0,0 @@
|
|||
#include "trie.hpp"
|
||||
|
||||
std::vector<std::vector<size_t>> flatten(const trie & t) {
|
||||
std::vector<std::vector<size_t>> ret;
|
||||
t.for_each([&ret](auto && w) { ret.push_back(w); });
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::pair<size_t, size_t> total_size(const trie & t) {
|
||||
size_t count = 0;
|
||||
size_t total_count = 0;
|
||||
t.for_each([&count, &total_count](auto && w) {
|
||||
++count;
|
||||
total_count += w.size();
|
||||
});
|
||||
return {count, total_count};
|
||||
}
|
38
lib/trie.hpp
38
lib/trie.hpp
|
@ -10,10 +10,10 @@
|
|||
///
|
||||
/// \brief A Trie datastructure used to remove prefixes in a set of words
|
||||
///
|
||||
/// The datastructure only works for words over size_t. In principle the symbols
|
||||
/// can be unbounded, however having very large symbols degrades the performance
|
||||
/// a lot. Some random testing shows that for symbols <= 50 the performance is
|
||||
/// similar to std::set (which is solving a different problem).
|
||||
/// The datastructure only works for words over integral unsigned types. In principle the symbols
|
||||
/// can be unbounded, however having very large symbols degrades the performance a lot. Some random
|
||||
/// testing shows that for symbols <= 50 the performance is similar to std::set (which is solving a
|
||||
/// different problem).
|
||||
///
|
||||
/// Tests : 1M words, avg words length 4 (geometric dist.), alphabet 50 symbols
|
||||
/// trie reduction 58% in 1.15s
|
||||
|
@ -23,7 +23,9 @@
|
|||
/// There are, however, "internal iterators" exposed as a for_each() member
|
||||
/// function (if only we had coroutines already...)
|
||||
///
|
||||
struct trie {
|
||||
template <typename T> struct trie {
|
||||
static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, "");
|
||||
|
||||
/// \brief Inserts a word (given by iterators \p begin and \p end)
|
||||
/// \returns true if the element was inserted, false if already there
|
||||
template <typename Iterator> bool insert(Iterator && begin, Iterator && end) {
|
||||
|
@ -46,19 +48,17 @@ struct trie {
|
|||
|
||||
/// \brief Applies \p function to all word (not to the prefixes)
|
||||
template <typename Fun> void for_each(Fun && function) const {
|
||||
std::vector<size_t> word;
|
||||
std::vector<T> word;
|
||||
return for_each_impl(std::forward<Fun>(function), word);
|
||||
}
|
||||
|
||||
/// \brief Empties the complete set
|
||||
void clear() {
|
||||
branches.clear();
|
||||
}
|
||||
void clear() { branches.clear(); }
|
||||
|
||||
private:
|
||||
template <typename Fun> void for_each_impl(Fun && function, std::vector<size_t> & word) const {
|
||||
template <typename Fun> void for_each_impl(Fun && function, std::vector<T> & word) const {
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < branches.size(); ++i) {
|
||||
for (T i = 0; i < branches.size(); ++i) {
|
||||
auto const & b = branches[i];
|
||||
if (b) {
|
||||
++count;
|
||||
|
@ -80,7 +80,19 @@ struct trie {
|
|||
|
||||
/// \brief Flattens a trie \p t
|
||||
/// \returns an array of words (without the prefixes)
|
||||
std::vector<std::vector<size_t>> flatten(trie const & t);
|
||||
template <typename T> std::vector<std::vector<T>> flatten(trie<T> const & t) {
|
||||
std::vector<std::vector<T>> ret;
|
||||
t.for_each([&ret](auto && w) { ret.push_back(w); });
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// \brief Returns size and total sum of symbols
|
||||
std::pair<size_t, size_t> total_size(trie const & t);
|
||||
template <typename T> std::pair<size_t, size_t> total_size(trie<T> const & t) {
|
||||
size_t count = 0;
|
||||
size_t total_count = 0;
|
||||
t.for_each([&count, &total_count](auto && w) {
|
||||
++count;
|
||||
total_count += w.size();
|
||||
});
|
||||
return {count, total_count};
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
#include <vector>
|
||||
|
||||
// We use size_ts for fast indexing. Note that there is little type safety here
|
||||
using state = size_t;
|
||||
using input = size_t;
|
||||
using output = size_t;
|
||||
using state = uint16_t;
|
||||
using input = uint16_t;
|
||||
using output = uint16_t;
|
||||
|
||||
using word = std::vector<input>;
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ int main(int argc, char * argv[]) {
|
|||
auto q1 = apply(m1, s1, i);
|
||||
auto q2 = apply(m2, s2, i);
|
||||
|
||||
if (q1.output != q2.output) {
|
||||
if (q1.out != q2.out) {
|
||||
current_counterexamples++;
|
||||
}
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ int main(int argc, char * argv[]) {
|
|||
const auto prefixes = prefixes_fut.get();
|
||||
const auto middles = middles_fut.get();
|
||||
const auto suffixes = suffixes_fut.get();
|
||||
trie test_suite;
|
||||
trie<input> test_suite;
|
||||
|
||||
clog << "start testing" << endl;
|
||||
const state start = 0;
|
||||
|
|
|
@ -24,7 +24,7 @@ static void test() {
|
|||
word w5 = {5, 5, 3};
|
||||
word w6 = {5, 5, 3, 1};
|
||||
|
||||
trie t;
|
||||
trie<unsigned> t;
|
||||
check(t.insert(w1));
|
||||
check(!t.insert(w1));
|
||||
check(t.insert(w2));
|
||||
|
@ -77,7 +77,7 @@ static void performance() {
|
|||
using seconds = std::chrono::duration<double>;
|
||||
|
||||
auto t_start = clock::now();
|
||||
trie t;
|
||||
trie<unsigned> t;
|
||||
for (auto&& w : corpus) t.insert(w);
|
||||
auto t_end = clock::now();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue