diff --git a/include/sdsl/k2_tree.hpp b/include/sdsl/k2_tree.hpp index 730f742ac..4acfbfe6a 100644 --- a/include/sdsl/k2_tree.hpp +++ b/include/sdsl/k2_tree.hpp @@ -21,6 +21,7 @@ #ifndef INCLUDED_SDSL_K2_TREE #define INCLUDED_SDSL_K2_TREE +#include #include #include #include @@ -73,34 +74,32 @@ class k2_tree std::vector> acc(k_height + 1); k2_tree_ns::_build_from_matrix(matrix, k, - simulated_size, k_height, - 1, 0, 0, acc); + simulated_size, k_height, + 1, 0, 0, acc); size_type t_size = 0; size_type l_size = 0; - for(int i = 1; i < k_height; i++) - for(auto it = acc[i].begin(); it != acc[i].end(); it++) + for (int i = 1; i < k_height; i++) + for (auto it = acc[i].begin(); it != acc[i].end(); it++) t_size += (*it).size(); - for(auto it = acc[k_height].begin(); it != acc[k_height].end(); it++) + for (auto it = acc[k_height].begin(); it != acc[k_height].end(); it++) l_size += (*it).size(); bit_vector k_t_(t_size, 0); bit_vector k_l_(l_size, 0); int n = 0; - for(int j = 1; j < k_height; j++) - for(auto it = acc[j].begin(); it != acc[j].end(); it++) - // TODO erase - for(unsigned i = 0; i < (*it).size(); i++) { + for (int j = 1; j < k_height; j++) + for (auto it = acc[j].begin(); it != acc[j].end(); it++) + for (unsigned i = 0; i < (*it).size(); i++) { // TODO there should be a better way to do this k_t_.set_int(n, (*it).get_int(i, 1), 1); n++; } n = 0; - for(auto it = acc[k_height].begin(); it != acc[k_height].end(); it++) - // TODO erase - for(unsigned i = 0; i < (*it).size(); i++) { + for (auto it = acc[k_height].begin(); it != acc[k_height].end(); it++) + for (unsigned i = 0; i < (*it).size(); i++) { // TODO there should be a better way to do this k_l_.set_int(n * 1, (*it).get_int(i, 1), 1); n++; @@ -124,16 +123,16 @@ class k2_tree void _neigh(size_type n, idx_type row, idx_type col, size_type level, std::vector& acc) const { - if(level >= k_t.size()) { // Last level - if(k_l[level - k_t.size()] == 1) + if (level >= k_t.size()) { // Last level + if (k_l[level - k_t.size()] == 1) acc.push_back(col); return; } - if(k_t[level] == 1) { + if (k_t[level] == 1) { idx_type y = k_t_rank(level + 1) * std::pow(k_k, 2) + - k_k * std::floor(row/static_cast(n)); - for(unsigned j = 0; j < k_k; j++) + k_k * std::floor(row/static_cast(n)); + for (unsigned j = 0; j < k_k; j++) _neigh(n/k_k, row % n, col + n * j, y + j, acc); } } @@ -152,17 +151,17 @@ class k2_tree void _reverse_neigh(size_type n, idx_type row, idx_type col, size_type level, std::vector& acc) const { - if(level >= k_t.size()) { // Last level - if(k_l[level - k_t.size()] == 1) { + if (level >= k_t.size()) { // Last level + if (k_l[level - k_t.size()] == 1) { acc.push_back(row); } return; } - if(k_t[level] == 1) { + if (k_t[level] == 1) { idx_type y = k_t_rank(level + 1) * std::pow(k_k, 2) + - std::floor(col/static_cast(n)); - for(unsigned j = 0; j < k_k; j++) + std::floor(col/static_cast(n)); + for (unsigned j = 0; j < k_k; j++) _reverse_neigh(n/k_k, row + n * j, col % n, y + j * k_k, acc); } @@ -181,12 +180,12 @@ class k2_tree */ k2_tree(std::vector>& matrix) { - if(matrix.size() < 1) { + if (matrix.size() < 1) { throw std::logic_error("Matrix has no elements"); } std::vector t; k_k = k; - if(matrix.size() < k_k) + if (matrix.size() < k_k) k_height = 1; else // height = log_k n k_height = std::ceil(std::log(matrix.size())/std::log(k_k)); @@ -205,11 +204,11 @@ class k2_tree * \param size Size of the graph, all the nodes in edges must be * within 0 and size ([0, size[). */ - k2_tree(std::vector> &edges, + k2_tree(std::vector>& edges, const size_type size) { typedef std::tuple t_part_tuple; + idx_type> t_part_tuple; assert(size > 0); assert(edges.size() > 0); @@ -218,89 +217,82 @@ class k2_tree k_height = std::ceil(std::log(size)/std::log(k_k)); k_height = k_height > 1 ? k_height : 1; // If size == 0 size_type k_2 = std::pow(k_k, 2); - size_type s = std::pow(k_k, k_height); - k_t = t_bv(k_2 * k_height * edges.size(), 0); + bit_vector k_t_ = bit_vector(k_2 * k_height * edges.size(), 0); + bit_vector k_l_; std::queue q; idx_type t = 0, last_level = 0; idx_type i, j, r_0, c_0, it, c, r; - size_type l; - std::vector pos_by_chunk(k_2, 0); - - q.push(t_part_tuple(0, edges.size(), s/k_k, 0, 0)); - - while(!q.empty()) { - std::vector amount_by_chunk(k_2, 0); - std::tie(i, j, l, r_0, c_0) = q.front(); - q.pop(); - // Sorting - // Get size for each chunk - for(it = i; it < j; it++) - amount_by_chunk[k2_tree_ns::get_chunk_idx( - std::get<0>(edges[it]), - std::get<1>(edges[it]), - c_0, r_0, l, k_k)] += 1; - if(l == 1) { - if(last_level == 0) { + size_type l = std::pow(k_k, k_height - 1); + std::vector pos_by_chunk(k_2 + 1, 0); + + q.push(t_part_tuple(0, edges.size(), l, 0, 0)); + + while (!q.empty()) { + std::vector amount_by_chunk(k_2, 0); + std::tie(i, j, l, r_0, c_0) = q.front(); + q.pop(); + // Get size for each chunk + for (it = i; it < j; it++) + amount_by_chunk[k2_tree_ns::get_chunk_idx( + std::get<0>(edges[it]), std::get<1>(edges[it]), + c_0, r_0, l, k_k)] += 1; + if (l == 1) { + if (last_level == 0) { last_level = t; - k_l = t_bv(k_t.size() - last_level, 0); - k_t.resize(last_level); - last_level = 1; // TODO if t was 0 ? - t = 0; - } - for(it = 0; it < k_2; it++) { - if(amount_by_chunk[it] != 0) { - k_l[t] = 1; - } - t++; + k_l_ = bit_vector(k_t_.size() - last_level, 0); + k_t_.resize(last_level); + last_level = 1; // if t was 0 + t = 0; // Restart counter as we're storing at k_l_ now. } + for (it = 0; it < k_2; it++,t++) + if (amount_by_chunk[it] != 0) + k_l_[t] = 1; + // At l == 1 we do not put new elements at the queue. continue; } // Set starting position in the vector for each chunk - pos_by_chunk[0] = i; - for(it = 1; it < k_2; it++) { - pos_by_chunk[it] = - pos_by_chunk[it - 1] + amount_by_chunk[it - 1]; - } - for(it = 0; it < k_2 - 1; it++) { - // If not empty chunk, set bit to 1 - if(amount_by_chunk[it] != 0) { + pos_by_chunk[0] = i; + for (it = 1; it < k_2; it++) + pos_by_chunk[it] = + pos_by_chunk[it - 1] + amount_by_chunk[it - 1]; + // To handle the last case when it = k_2 - 1 + pos_by_chunk[k_2] = j; + // Push to the queue every non zero elements chunk + for (it = 0; it < k_2; it++,t++) + // If not empty chunk, set bit to 1 + if (amount_by_chunk[it] != 0) { r = it / k_k; c = it % k_k; - k_t[t] = 1; + k_t_[t] = 1; q.push(t_part_tuple(pos_by_chunk[it], pos_by_chunk[it + 1], l/k_k, r_0 + r * l, c_0 + c * l)); } - t++; - } - if(amount_by_chunk[k_2 - 1] != 0) { - k_t[t] = 1; - q.push(t_part_tuple(pos_by_chunk[it], - j, - l/k_k, - r_0 + (k_k - 1) * l, - c_0 + (k_k - 1) * l)); - } - t++; idx_type chunk; - for(it = i; it < j; it++) { - chunk = k2_tree_ns::get_chunk_idx(std::get<0>(edges[it]), - std::get<1>(edges[it]), - c_0, r_0, l, k_k); - if(pos_by_chunk[chunk] != it) { - std::iter_swap(edges.begin() + it, - edges.begin() + pos_by_chunk[chunk]); - it--; + // Sort edges' vector + for (unsigned ch = 0; ch < k_2; ch++) { + idx_type be = ch == 0 ? 0 : pos_by_chunk[ch - 1]; + for (it = pos_by_chunk[ch]; it < be + amount_by_chunk[ch];) { + chunk = k2_tree_ns::get_chunk_idx( + std::get<0>(edges[it]), std::get<1>(edges[it]), + c_0, r_0, l, k_k); + + if (pos_by_chunk[chunk] != it) + std::iter_swap(edges.begin() + it, + edges.begin() + pos_by_chunk[chunk]); + else + it++; + pos_by_chunk[chunk]++; } - pos_by_chunk[chunk]++; - } + } } - k_l.resize(t); + k_l_.resize(t); + k2_tree_ns::build_template_vector(k_t_, k_l_, k_t, k_l); k_t_rank = t_rank(&k_t); } @@ -319,7 +311,7 @@ class k2_tree //! Move assignment operator k2_tree& operator=(k2_tree&& tr) { - if(this != &tr) { + if (this != &tr) { k_t = std::move(tr.k_t); k_l = std::move(tr.k_l); k_k = std::move(tr.k_k); @@ -333,7 +325,7 @@ class k2_tree //! Assignment operator k2_tree& operator=(k2_tree& tr) { - if(this != &tr) { + if (this != &tr) { k_t = tr.k_t; k_l = tr.k_l; k_t_rank = tr.k_t_rank; @@ -345,7 +337,7 @@ class k2_tree //! Swap operator void swap(k2_tree& tr) { - if(this != &tr) { + if (this != &tr) { std::swap(k_t, tr.k_t); util::swap_support(k_t_rank, tr.k_t_rank, &k_t, &(tr.k_t)); } @@ -353,20 +345,20 @@ class k2_tree //! Equal operator bool operator==(const k2_tree& tr) const - { - // TODO check the rank support equality? - if(k_k != tr.k_k || k_height != tr.k_height) - return false; - if(k_t.size() != tr.k_t.size() || k_l.size() != tr.k_l.size()) - return false; - for(unsigned i = 0; i < k_t.size(); i++) - if(k_t[i] != tr.k_t[i]) - return false; - for(unsigned i = 0; i < k_l.size(); i++) - if(k_l[i] != tr.k_l[i]) - return false; - return true; - } + { + // TODO check the rank support equality? + if (k_k != tr.k_k || k_height != tr.k_height) + return false; + if (k_t.size() != tr.k_t.size() || k_l.size() != tr.k_l.size()) + return false; + for (unsigned i = 0; i < k_t.size(); i++) + if (k_t[i] != tr.k_t[i]) + return false; + for (unsigned i = 0; i < k_l.size(); i++) + if (k_l[i] != tr.k_l[i]) + return false; + return true; + } t_bv get_t() { @@ -387,7 +379,7 @@ class k2_tree */ bool adj(idx_type i, idx_type j) const { - if(k_t.size() == 0 && k_l.size() == 0) + if (k_t.size() == 0 && k_l.size() == 0) return false; size_type n = std::pow(k_k, k_height - 1); size_type k_2 = std::pow(k_k, 2); @@ -404,8 +396,8 @@ class k2_tree n = n/k_k; idx_type y; - while(level < k_t.size()) { - if(k_t[level] == 0) + while (level < k_t.size()) { + if (k_t[level] == 0) return false; row = std::floor(i/static_cast(n)); col = std::floor(j/static_cast(n)); @@ -426,12 +418,12 @@ class k2_tree std::vectorneigh(idx_type i) const { std::vector acc{}; - if(k_l.size() == 0 && k_t.size() == 0) + if (k_l.size() == 0 && k_t.size() == 0) return acc; size_type n = - static_cast(std::pow(k_k, k_height)) / k_k; + static_cast(std::pow(k_k, k_height)) / k_k; idx_type y = k_k * std::floor(i/static_cast(n)); - for(unsigned j = 0; j < k_k; j++) + for (unsigned j = 0; j < k_k; j++) _neigh(n/k_k, i % n, n * j, y + j, acc); return acc; } @@ -444,13 +436,13 @@ class k2_tree std::vector reverse_neigh(idx_type i) const { std::vector acc{}; - if(k_l.size() == 0 && k_t.size() == 0) + if (k_l.size() == 0 && k_t.size() == 0) return acc; // Size of the first square division size_type n = - static_cast(std::pow(k_k, k_height)) / k_k; + static_cast(std::pow(k_k, k_height)) / k_k; idx_type y = std::floor(i/static_cast(n)); - for(unsigned j = 0; j < k_k; j++) + for (unsigned j = 0; j < k_k; j++) _reverse_neigh(n/k_k, n * j, i % n, y + j * k_k, acc); return acc; @@ -468,7 +460,7 @@ class k2_tree std::string name="") { structure_tree_node* child = structure_tree::add_child( - v, name, util::class_name(*this)); + v, name, util::class_name(*this)); size_type written_bytes = 0; written_bytes += k_t.serialize(out, child, "t"); diff --git a/test/k2_tree_test.cpp b/test/k2_tree_test.cpp index 687c015f0..a274ea388 100644 --- a/test/k2_tree_test.cpp +++ b/test/k2_tree_test.cpp @@ -26,71 +26,74 @@ using testing::Types; namespace k2_tree_test_nm { - template - void check_t_l(t_tree& tree, vector expected_t, - vector expected_l) - { +template +void check_t_l(t_tree& tree, vector expected_t, + vector expected_l) +{ ASSERT_EQ(expected_t.size(), tree.get_t().size()); ASSERT_EQ(expected_l.size(), tree.get_l().size()); - for(unsigned i = 0; i < expected_t.size(); i++) + for (unsigned i = 0; i < expected_t.size(); i++) ASSERT_EQ(expected_t[i], tree.get_t().get_int(i, 1)); - for(unsigned i = 0; i < expected_l.size(); i++) + for (unsigned i = 0; i < expected_l.size(); i++) ASSERT_EQ(expected_l[i], tree.get_l().get_int(i, 1)); - } +} - template - void check_serialize_load(t_tree &tree) - { - auto unserialized_tree = t_tree(); - std::stringstream ss; - tree.serialize(ss); - unserialized_tree.load(ss); - ASSERT_EQ(tree, unserialized_tree); - } +template +void check_serialize_load(t_tree& tree) +{ + auto unserialized_tree = t_tree(); + std::stringstream ss; + tree.serialize(ss); + unserialized_tree.load(ss); + ASSERT_EQ(tree, unserialized_tree); +} }; typedef Types< - k2_tree<2, bit_vector, rank_support_v<>>, - k2_tree<2, bit_vector> - > k_2_implementations; +k2_tree<2, bit_vector, rank_support_v<>>, + k2_tree<2, bit_vector> + > k_2_implementations; typedef Types< - k2_tree<3, bit_vector, rank_support_v<>>, - k2_tree<3, bit_vector> - > k_3_implementations; +k2_tree<3, bit_vector, rank_support_v<>>, + k2_tree<3, bit_vector> + > k_3_implementations; typedef Types< - k2_tree<2, bit_vector>, - k2_tree<3, bit_vector>, - k2_tree<7, bit_vector>, - k2_tree<2, rrr_vector<63>>, - k2_tree<3, rrr_vector<63>>, - k2_tree<5, bit_vector, rank_support_v<>>, - k2_tree<4, bit_vector, rank_support_v<>> - > Implementations; +k2_tree<2, bit_vector>, + k2_tree<3, bit_vector>, + k2_tree<7, bit_vector>, + k2_tree<2, rrr_vector<63>>, + k2_tree<3, rrr_vector<63>>, + k2_tree<5, bit_vector, rank_support_v<>>, + k2_tree<4, bit_vector, rank_support_v<>> + > Implementations; TYPED_TEST_CASE(k2_tree_test_k_2, k_2_implementations); TYPED_TEST(k2_tree_test_k_2, build_from_matrix_test) { vector> mat({{1, 1, 0, 0}, - {0, 1, 0, 0}, - {0, 0, 1, 1}, - {0, 0, 1, 0}}); + {0, 1, 0, 0}, + {0, 0, 1, 1}, + {0, 0, 1, 0} + }); TypeParam tree(mat); vector expected_l = {1,1,0,1,1,1,1,0}; k2_tree_test_nm::check_t_l(tree, {1, 0, 0 ,1}, expected_l); mat = vector> ({{0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}}); + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }); tree = TypeParam(mat); k2_tree_test_nm::check_t_l(tree, {}, {}); mat = vector>({{0, 0}, - {0, 0}}); + {0, 0} + }); tree = TypeParam(mat); ASSERT_TRUE(tree.get_t().empty()); ASSERT_TRUE(tree.get_l().empty()); @@ -107,48 +110,53 @@ TYPED_TEST(k2_tree_test_k_2, build_from_matrix_test) // Size is non a power of k: mat = vector>({{0, 0, 1}, - {0, 1, 0}, - {0, 1, 0}}); + {0, 1, 0}, + {0, 1, 0} + }); tree = TypeParam(mat); expected_l = {0,0,0,1,1,0,0,0,0,1,0,0}; k2_tree_test_nm::check_t_l(tree, {1, 1, 1 ,0}, expected_l); mat = vector>({{0, 0, 0}, - {1, 0, 1}, - {0, 1, 1}}); + {1, 0, 1}, + {0, 1, 1} + }); tree = TypeParam(mat); expected_l = {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0}; k2_tree_test_nm::check_t_l(tree, {1, 1, 1 ,1}, expected_l); // Sample from 'k^2 trees for compact web graph representation' paper mat = vector>({{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0}, - {0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1}, - {0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0}}); + {0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0}, + {0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1}, + {0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0} + }); tree = TypeParam(mat); vector expected_t = {1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, - 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0}; + 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0 + }; expected_l = {0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, - 0, 1, 0, 0}; + 0, 1, 0, 0 + }; k2_tree_test_nm::check_t_l(tree, expected_t, expected_l); } TYPED_TEST(k2_tree_test_k_2, build_from_edges_array) { typedef std::tuple t_tuple; + typename TypeParam::idx_type> t_tuple; vector> e; + typename TypeParam::idx_type>> e; t_tuple a{0, 0}; t_tuple b{0, 1}; @@ -188,33 +196,38 @@ TYPED_TEST_CASE(k2_tree_test_k_3, k_3_implementations); TYPED_TEST(k2_tree_test_k_3, build_from_matrix_test) { vector> mat({{1, 1, 0, 0, 1}, - {0, 1, 0, 0, 0}, - {0, 0, 1, 1, 0}, - {1, 1, 0, 1, 0}, - {0, 0, 1, 0, 0}}); + {0, 1, 0, 0, 0}, + {0, 0, 1, 1, 0}, + {1, 1, 0, 1, 0}, + {0, 0, 1, 0, 0} + }); TypeParam tree(mat); vector expected_t = {1, 1, 0, 1, 1, 0, 0, 0, 0}; vector expected_l = {1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 0}; + 1, 0, 0, 0, 0, 0, 0, 0, 0 + }; k2_tree_test_nm::check_t_l(tree, expected_t, expected_l); mat = vector>({{1, 1, 1, 0}, - {1, 0, 0, 0}, - {0, 0, 0, 0}, - {1, 1, 0, 0}}); + {1, 0, 0, 0}, + {0, 0, 0, 0}, + {1, 1, 0, 0} + }); tree = TypeParam(mat); expected_t = {1, 0, 0, 1, 0, 0, 0, 0, 0}; expected_l = {1, 1, 1, 1, 0, 0, 0, 0, 0, - 1, 1, 0, 0, 0, 0, 0, 0, 0}; + 1, 1, 0, 0, 0, 0, 0, 0, 0 + }; k2_tree_test_nm::check_t_l(tree, expected_t, expected_l); mat = vector>({{0, 0, 0}, - {0, 0, 0}, - {0, 0, 0}}); + {0, 0, 0}, + {0, 0, 0} + }); tree = TypeParam(mat); k2_tree_test_nm::check_t_l(tree, {}, {}); @@ -228,50 +241,56 @@ TYPED_TEST(k2_tree_test_k_3, build_from_matrix_test) k2_tree_test_nm::check_t_l(tree, {}, {1, 0, 0, 0, 0, 0, 0, 0 ,0}); mat = vector>({{1, 0}, - {0, 1}}); + {0, 1} + }); tree = TypeParam(mat); k2_tree_test_nm::check_t_l(tree, {}, {1, 0, 0, 0, 1, 0, 0, 0 ,0}); // Size is a power of k: mat = vector>({{0, 0, 1, 0, 0, 0, 0, 0, 0}, - {1, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0, 0}}); + {1, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 1, 0, 0, 0, 0, 0, 0} + }); tree = TypeParam(mat); expected_t = {1, 0, 0, 0, 0, 0, 1, 0, 0}; expected_l = {0, 0, 1, 1, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1}; + 0, 0, 0, 0, 0, 0, 0, 0, 1 + }; k2_tree_test_nm::check_t_l(tree, expected_t, expected_l); mat = vector>({{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0}, - {0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1}, - {0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0}}); + {0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0}, + {0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1}, + {0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0} + }); tree = TypeParam(mat); expected_t = {1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 0}; + 1, 0, 0, 0, 0, 0, 0, 0, 0 + }; expected_l = {0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, - 0, 1, 0, 1, 0, 0, 0, 0, 0}; + 0, 1, 0, 1, 0, 0, 0, 0, 0 + }; k2_tree_test_nm::check_t_l(tree, expected_t, expected_l); } @@ -279,15 +298,15 @@ TYPED_TEST(k2_tree_test_k_3, build_from_matrix_test) TYPED_TEST(k2_tree_test_k_3, build_from_edges_array) { typedef std::tuple t_tuple; + typename TypeParam::idx_type> t_tuple; vector> e; + typename TypeParam::idx_type>> e; e.push_back(t_tuple {1, 2}); TypeParam tree(e, 4); k2_tree_test_nm::check_t_l(tree, {1, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 0, 0, 0}); + {0, 0, 0, 0, 0, 1, 0, 0, 0}); tree = TypeParam(e, 3); k2_tree_test_nm::check_t_l(tree, {}, {0, 0, 0, 0, 0, 1, 0, 0, 0}); @@ -315,24 +334,69 @@ TYPED_TEST(k2_tree_test_k_3, build_from_edges_array) TYPED_TEST_CASE(k2_tree_test, Implementations); +TYPED_TEST(k2_tree_test, edges_array_exhaustive) +{ + typedef std::tuple t_tuple; + vector> e; + e.push_back(t_tuple {5, 7}); + e.push_back(t_tuple {1, 2}); + e.push_back(t_tuple {3, 9}); + e.push_back(t_tuple {2, 2}); + e.push_back(t_tuple {3, 2}); + e.push_back(t_tuple {7, 5}); + e.push_back(t_tuple {1, 6}); + e.push_back(t_tuple {4, 8}); + e.push_back(t_tuple {4, 1}); + e.push_back(t_tuple {5, 2}); + + TypeParam tree(e, 10); + auto expected_neighbors = vector>(10); + expected_neighbors[0] = vector({}); + expected_neighbors[1] = vector({2, 6}); + expected_neighbors[2] = vector({2}); + expected_neighbors[3] = vector({2, 9}); + expected_neighbors[4] = vector({1, 8}); + expected_neighbors[5] = vector({2, 7}); + expected_neighbors[6] = vector({}); + expected_neighbors[7] = vector({5}); + expected_neighbors[8] = vector({}); + expected_neighbors[9] = vector({}); + for (unsigned i = 0; i < 10; i++) { + auto actual_neighbors = tree.neigh(i); + ASSERT_EQ(expected_neighbors[i].size(), actual_neighbors.size()); + for (unsigned j = 0; i < expected_neighbors[i].size(); i++) + ASSERT_EQ(expected_neighbors[i][j], actual_neighbors[j]); + } + + e.clear(); + e.push_back(t_tuple{0, 0}); + tree = TypeParam(e, 1); + cout << tree.neigh(0) << endl; + ASSERT_EQ(1u, tree.neigh(0).size()); + ASSERT_EQ(0u, tree.neigh(0)[0]); +} + TYPED_TEST(k2_tree_test, neighbors_test) { vector> mat({{1, 1, 0, 0}, - {0, 1, 0, 0}, - {0, 0, 1, 1}, - {0, 0, 1, 0}}); + {0, 1, 0, 0}, + {0, 0, 1, 1}, + {0, 0, 1, 0} + }); TypeParam tree(mat); auto neigh_0 = tree.neigh(0); vectorexpected_neigh_0({0, 1}); ASSERT_EQ(expected_neigh_0.size(), neigh_0.size()); - for(unsigned i = 0; i < neigh_0.size(); i++) + for (unsigned i = 0; i < neigh_0.size(); i++) ASSERT_EQ(expected_neigh_0[i], neigh_0[i]); auto neigh_3 = tree.neigh(3); vectorexpected_neigh_3({2}); ASSERT_EQ(expected_neigh_3.size(), neigh_3.size()); - for(unsigned i = 0; i < neigh_3.size(); i++) + for (unsigned i = 0; i < neigh_3.size(); i++) ASSERT_EQ(expected_neigh_3[i], neigh_3[i]); mat = vector>({{1}}); @@ -342,8 +406,9 @@ TYPED_TEST(k2_tree_test, neighbors_test) ASSERT_EQ(1u, neigh_0.size()); mat = vector>({{0, 0, 0}, - {1, 0, 1}, - {0, 1, 1}}); + {1, 0, 1}, + {0, 1, 1} + }); tree = TypeParam(mat); neigh_0 = tree.neigh(0); ASSERT_EQ(0u, neigh_0.size()); @@ -351,11 +416,12 @@ TYPED_TEST(k2_tree_test, neighbors_test) auto neigh_1 = tree.neigh(1); auto expected_neigh_1 = vector({0, 2}); ASSERT_EQ(expected_neigh_1.size(), neigh_1.size()); - for(unsigned i = 0; i < neigh_1.size(); i++) + for (unsigned i = 0; i < neigh_1.size(); i++) ASSERT_EQ(expected_neigh_1[i], neigh_1[i]); mat = vector>({{0, 0}, - {0, 0}}); + {0, 0} + }); tree = TypeParam(mat); neigh_0 = tree.neigh(0); ASSERT_EQ(0u, neigh_0.size()); @@ -364,10 +430,11 @@ TYPED_TEST(k2_tree_test, neighbors_test) TYPED_TEST(k2_tree_test, reverse_neighbors_test) { vector> mat({{1, 0, 0, 0, 1}, - {0, 0, 0, 0, 0}, - {0, 0, 1, 1, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 1, 0, 1}}); + {0, 0, 0, 0, 0}, + {0, 0, 1, 1, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 1, 0, 1} + }); auto tree = TypeParam(mat); auto r_neigh_0 = tree.reverse_neigh(0); @@ -379,14 +446,15 @@ TYPED_TEST(k2_tree_test, reverse_neighbors_test) ASSERT_EQ(0u, r_neigh_1.size()); ASSERT_EQ(expected_r_neigh_2.size(), r_neigh_2.size()); - for(unsigned i = 0; i < r_neigh_0.size(); i++) + for (unsigned i = 0; i < r_neigh_0.size(); i++) ASSERT_EQ(expected_r_neigh_0[i], r_neigh_0[i]); - for(unsigned i = 0; i < r_neigh_2.size(); i++) + for (unsigned i = 0; i < r_neigh_2.size(); i++) ASSERT_EQ(expected_r_neigh_2[i], r_neigh_2[i]); mat = vector>({{0, 0}, - {0, 0}}); + {0, 0} + }); tree = TypeParam(mat); r_neigh_0 = tree.reverse_neigh(0); r_neigh_1 = tree.reverse_neigh(1); @@ -395,7 +463,8 @@ TYPED_TEST(k2_tree_test, reverse_neighbors_test) mat = vector>({{0, 1}, - {1, 0}}); + {1, 0} + }); tree = TypeParam(mat); r_neigh_0 = tree.reverse_neigh(0); expected_r_neigh_0 = vector({1}); @@ -404,20 +473,21 @@ TYPED_TEST(k2_tree_test, reverse_neighbors_test) ASSERT_EQ(expected_r_neigh_0.size(), r_neigh_0.size()); ASSERT_EQ(expected_r_neigh_1.size(), r_neigh_1.size()); - for(unsigned i = 0; i < r_neigh_0.size(); i++) + for (unsigned i = 0; i < r_neigh_0.size(); i++) ASSERT_EQ(expected_r_neigh_0[i], r_neigh_0[i]); - for(unsigned i = 0; i < r_neigh_1.size(); i++) + for (unsigned i = 0; i < r_neigh_1.size(); i++) ASSERT_EQ(expected_r_neigh_1[i], r_neigh_1[i]); } TYPED_TEST(k2_tree_test, adj_test) { vector> mat({{1, 0, 0, 0, 1}, - {0, 0, 0, 0, 0}, - {0, 0, 1, 1, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 1, 0, 1}}); + {0, 0, 0, 0, 0}, + {0, 0, 1, 1, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 1, 0, 1} + }); auto tree = TypeParam(mat); ASSERT_TRUE(tree.adj(0, 0)); @@ -439,30 +509,33 @@ TYPED_TEST(k2_tree_test, adj_test) TYPED_TEST(k2_tree_test, serialize_test) { vector> mat({{1, 0, 0, 0, 1}, - {0, 0, 0, 0, 0}, - {0, 0, 1, 1, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 1, 0, 1}}); + {0, 0, 0, 0, 0}, + {0, 0, 1, 1, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 1, 0, 1} + }); auto tree = TypeParam(mat); - k2_tree_test_nm::check_serialize_load(tree); + k2_tree_test_nm::check_serialize_load(tree); - mat = vector>({{0}}); + mat = vector>({{0}}); tree = TypeParam(mat); - k2_tree_test_nm::check_serialize_load(tree); + k2_tree_test_nm::check_serialize_load(tree); - tree = TypeParam(); - k2_tree_test_nm::check_serialize_load(tree); + tree = TypeParam(); + k2_tree_test_nm::check_serialize_load(tree); - mat = vector>({{0, 0}, - {0, 0}}); + mat = vector>({{0, 0}, + {0, 0} + }); tree = TypeParam(mat); - k2_tree_test_nm::check_serialize_load(tree); + k2_tree_test_nm::check_serialize_load(tree); - mat = vector>({{1, 1}, - {1, 1}}); + mat = vector>({{1, 1}, + {1, 1} + }); tree = TypeParam(mat); - k2_tree_test_nm::check_serialize_load(tree); + k2_tree_test_nm::check_serialize_load(tree); }