diff --git a/.gitignore b/.gitignore index 658c4c6a4..3d96a4691 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,6 @@ Make.helper +.vscode +.idea/* +cmake-build-debug/ +CMakeModules/* +*/.idea/* diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..5c98b4288 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,2 @@ +# Default ignored files +/workspace.xml \ No newline at end of file diff --git a/include/sdsl/int_vector.hpp b/include/sdsl/int_vector.hpp index 2b2a3a343..9c3563670 100644 --- a/include/sdsl/int_vector.hpp +++ b/include/sdsl/int_vector.hpp @@ -387,7 +387,7 @@ class int_vector //! The number of elements in the int_vector. /*! \sa max_size, bit_size, capacity */ - size_type size() const + inline size_type size() const { return m_size/m_width; } diff --git a/include/sdsl/k2_tree.hpp b/include/sdsl/k2_tree.hpp index f8b8f6e78..cf7378206 100644 --- a/include/sdsl/k2_tree.hpp +++ b/include/sdsl/k2_tree.hpp @@ -21,15 +21,20 @@ #ifndef INCLUDED_SDSL_K2_TREE #define INCLUDED_SDSL_K2_TREE -#include #include #include #include +#include +#include #include "sdsl/bit_vectors.hpp" #include "sdsl/k2_tree_helper.hpp" +#include "sdsl/k2_tree_iterator.hpp" #include "sdsl/int_vector_buffer.hpp" +#include +// #include +// #include //! Namespace for the succint data structure library namespace sdsl { @@ -45,72 +50,94 @@ namespace sdsl * (pp. 18-30). Springer Berlin Heidelberg. */ -template +template class k2_tree { - public: - typedef k2_tree_ns::idx_type idx_type; - typedef k2_tree_ns::size_type size_type; - - private: - //! Bit array to store all the bits of the tree, except those in the - //! last level. - t_bv k_t; - //! Bit array to store the last level of the tree. - t_bv k_l; - - t_rank k_t_rank; - - uint8_t k_k; - uint16_t k_height; - - protected: - - void build_from_matrix(const std::vector>& matrix) - { - // Makes the size a power of k. - int simulated_size = std::pow(k, k_height); - std::vector> acc(k_height + 1); - - k2_tree_ns::_build_from_matrix(matrix, k, - 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++) - t_size += (*it).size(); - - 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++) - 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++) - for (unsigned i = 0; i < (*it).size(); i++) { +public: + typedef k2_tree_ns::idx_type idx_type; + typedef k2_tree_ns::size_type size_type; + using edg_iterator = edge_iterator>; + using nod_iterator = node_iterator>; + using neigh_iterator = neighbour_iterator>; + + t_bv k_t; + uint k_t_size = 0; + uint k_l_size = 0; + //! Bit array to store the last level of the tree. + t_bv k_l; + + t_rank k_t_rank; + + uint16_t k_k; + uint16_t k_height = 0; + +protected: + //! Bit array to store all the bits of the tree, except those in the + //! last level. + uint64_t n_marked_edges = 0; + uint64_t n_edges = 0; + size_t n_vertices = 0; + + std::vector pointerL; + std::vector div_level_table; + uint16_t max_level; + uint last_level_rank = 0; + + edg_iterator it_e_begin, it_e_end; + neigh_iterator it_neigh_begin, it_neigh_end = neigh_iterator().end(); + + void build_from_matrix(const std::vector> &matrix) + { + // Makes the size a power of k. + int simulated_size = std::pow(k, k_height); + std::vector> acc(k_height + 1); + + k2_tree_ns::_build_from_matrix(matrix, k, + 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++) + t_size += (*it).size(); + + 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++) + 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); + 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++) + 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++; + if((*it).get_int(i, 1) == 1) + ++n_edges; + } - k2_tree_ns::build_template_vector(k_t_, k_l_, k_t, k_l); - } - + k2_tree_ns::build_template_vector(k_t_, k_l_, k_t, k_l); + k_t_rank = t_rank(&k_t); + + k_t_size = k_t.size(); + k_l_size = k_l.size(); + } - /*! Recursive function to retrieve list of neighbors. + /*! Recursive function to retrieve list of neighbors. * * \param n Size of the submatrix in the next recursive step. * \param row Row of interest in the current submatrix, this is the @@ -121,24 +148,76 @@ class k2_tree * or leaf being processed at this step. * \param acc Accumulator to store the neighbors found. */ - void _neigh(size_type n, idx_type row, idx_type col, size_type level, - std::vector& acc) const + 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) + acc.push_back(col); + return; + } + + 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++) + _neigh(n / k_k, row % n, col + n * j, y + j, acc); + } + } + + void _neigh_rec(size_type n, idx_type row, idx_type col, size_type level, + std::function func) const { + if (level >= k_t.size()) + { // Last level + if (k_l[level - k_t.size()] == 1) + func(col); + return; + } + + if (k_t[level] == 1) { - if (level >= k_t.size()) { // Last level - if (k_l[level - k_t.size()] == 1) - acc.push_back(col); - return; + 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++) + _neigh_rec(n / k_k, row % n, col + n * j, y + j, func); + } + } + + void _edge_it_rec(uint64_t dp, uint64_t dq, int64_t x, int16_t l, std::function func) { + + if(l == max_level) { + if(k_l[x] == 1) { + func(dp, dq); } + } - 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++) - _neigh(n/k_k, row % n, col + n * j, y + j, acc); + if(((l == max_level-1) && (x != -1) && k_t[x] == 1)) { + uint64_t y = pointerL[l+1]; + pointerL[l+1] += k_k*k_k; + + for(uint i = 0; i < k_k; i++) { + for(uint j = 0; j < k_k; j++) { + _edge_it_rec(dp+i, dq+j, y+k_k*i+j, l+1, func); + } } } - /*! Recursive function to retrieve list of reverse neighbors. + if((x == -1) || ((l < max_level-1) && (k_t[x] == 1) )) { + uint64_t y = pointerL[l+1]; + pointerL[l+1] += k_k*k_k; + + uint64_t div_level = div_level_table[l+1]; + for(uint i = 0; i < k_k; i++) { + for(uint j = 0; j < k_k; j++) { + _edge_it_rec(dp+div_level*i, dq+div_level*j, y+k_k*i+j, l+1, func); + } + } + } + } + + /*! Recursive function to retrieve list of reverse neighbors. * * \param n Size of the submatrix in the next recursive step. * \param row Row offset of the current submatrix in the global matrix. @@ -149,27 +228,30 @@ class k2_tree * or leaf being processed at this step. * \param acc Accumulator to store the neighbors found. */ - 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) { - acc.push_back(row); - } - return; + 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) + { + acc.push_back(row); } + return; + } - 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++) - _reverse_neigh(n/k_k, row + n * j, col % n, - y + j * k_k, acc); - } + 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++) + _reverse_neigh(n / k_k, row + n * j, col % n, + y + j * k_k, acc); } + } - //! Build a tree from an edges collection - /*! This method takes a vector of edges describing the graph + //! Build a tree from an edges collection + /*! This method takes a vector of edges describing the graph * and the graph size. And takes linear time over the amount of * edges to build the k_2 representation. * \param edges A vector with all the edges of the graph, it can @@ -177,128 +259,159 @@ class k2_tree * \param size Size of the graph, all the nodes in edges must be * within 0 and size ([0, size[). */ - void build_from_edges(std::vector>& edges, - const size_type size) - { - - typedef std::tuple t_part_tuple; - - k_k = k; - 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); - 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::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_ = 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; + void build_from_edges(std::vector> &edges, + const size_type size) + { + + typedef std::tuple + t_part_tuple; + + k_k = k; + 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); + 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::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_ = 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. } - - // 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]; - // 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 + for (it = 0; it < k_2; it++, t++) if (amount_by_chunk[it] != 0) { - r = it / k_k; - c = it % k_k; - 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)); + k_l_[t] = 1; + ++n_edges; } - idx_type chunk; - - // Sort edges' vector - for (unsigned ch = 0; ch < k_2; ch++) { - idx_type be = ch == 0 ? i : 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]++; - } - } + // At l == 1 we do not put new elements at the queue. + continue; } - 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); - } - - public: - - k2_tree() = default; - - //! Constructor - /*! This constructos takes the graph adjacency matrix. + // 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]; + // 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; + 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)); + } + idx_type chunk; + + // Sort edges' vector + for (unsigned ch = 0; ch < k_2; ch++) + { + idx_type be = ch == 0 ? i : 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]++; + } + } + } + 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); + k_t_size = k_t.size(); + k_l_size = k_l.size(); + } + +public: + k2_tree() + { + k_k = k; + k_t = bit_vector(0, 0); + k_l = bit_vector(0, 0); + k_t_rank = t_rank(&k_t); + } + + k2_tree(uint n_vertices) : n_vertices(n_vertices) + { + k_k = k; + k_t = bit_vector(0, 0); + k_l = bit_vector(0, 0); + k_t_rank = t_rank(&k_t); + } + + //! Constructor + /*! This constructos takes the graph adjacency matrix. * The time complexity for this constructor is linear in the matrix * size * \param matrix Adjacency matrix of the graph. It must be a binary * square matrix. */ - k2_tree(const std::vector> &matrix) + k2_tree(const 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) - k_height = 1; - else // height = log_k n - k_height = std::ceil(std::log(matrix.size())/std::log(k_k)); - - build_from_matrix(matrix); - - k_t_rank = t_rank(&k_t); + throw std::logic_error("Matrix has no elements"); } - - //! Constructor - /*! This constructos takes a vector of edges describing the graph + std::vector t; + k_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)); + + build_from_matrix(matrix); + this->n_vertices = matrix.size(); + + max_level = floor(log(n_vertices)/log(k_k)); + if(max_level != 0 && floor(log(n_vertices)/log(k_k)) == (log(n_vertices)/log(k_k))) + max_level = max_level-1; + + div_level_table = std::vector(max_level+1); + for(int64_t i = 0; i <= max_level; i++) + div_level_table[i] = exp_pow(k_k, max_level-i); + } + + //! Constructor + /*! This constructos takes a vector of edges describing the graph * and the graph size. And takes linear time over the amount of * edges to build the k_2 representation. * \param edges A vector with all the edges of the graph, it can @@ -306,17 +419,26 @@ 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, - const size_type size) - { - assert(size > 0); - assert(edges.size() > 0); - - build_from_edges(edges, size); - } - - //! Constructor - /*! This constructos expects a filename prefix. Two serialized + k2_tree(std::vector> &edges, + const size_type size) + { + assert(size > 0); + assert(edges.size() > 0); + + build_from_edges(edges, size); + this->n_vertices = size; + + max_level = floor(log(n_vertices)/log(k_k)); + if(max_level != 0 && floor(log(n_vertices)/log(k_k)) == (log(n_vertices)/log(k_k))) + max_level = max_level-1; + + div_level_table = std::vector(max_level+1); + for(int64_t i = 0; i <= max_level; i++) + div_level_table[i] = exp_pow(k_k, max_level-i); + } + + //! Constructor + /*! This constructos expects a filename prefix. Two serialized * int_vectors have to be present at filename.x and filename.y. * Each pair x,y describes an edge of the graph, from the node x * to the node y. @@ -328,283 +450,807 @@ class k2_tree * size==0, the size will be taken as the max node * in the edges. */ - k2_tree(std::string filename, size_type size=0) - { - int_vector_buffer<> buf_x(filename + ".x", std::ios::in); - int_vector_buffer<> buf_y(filename + ".y", std::ios::in); + k2_tree(std::string filename, size_type size = 0) + { + int_vector_buffer<> buf_x(filename + ".x", std::ios::in); + int_vector_buffer<> buf_y(filename + ".y", std::ios::in); - assert(buf_x.size() == buf_y.size()); - assert(buf_x.size() > 0); + assert(buf_x.size() == buf_y.size()); + assert(buf_x.size() > 0); - std::vector>edges; - edges.reserve(buf_x.size()); + std::vector> edges; + edges.reserve(buf_x.size()); - if(size==0) { - size_type max = 0; - for(auto v : buf_x) - max = std::max(static_cast(v), max); - for(auto v : buf_y) - max = std::max(static_cast(v), max); - size = max + 1; - } + if (size == 0) + { + size_type max = 0; + for (auto v : buf_x) + max = std::max(static_cast(v), max); + for (auto v : buf_y) + max = std::max(static_cast(v), max); + size = max + 1; + } - for(uint64_t i = 0; i < buf_x.size(); i++) - edges.push_back( - std::tuple {buf_x[i], buf_y[i]}); + for (uint64_t i = 0; i < buf_x.size(); i++) + edges.push_back( + std::tuple{buf_x[i], buf_y[i]}); + + build_from_edges(edges, size); + n_vertices = size; + + max_level = floor(log(n_vertices)/log(k_k)); + if(max_level != 0 && floor(log(n_vertices)/log(k_k)) == (log(n_vertices)/log(k_k))) + max_level = max_level-1; + + div_level_table = std::vector(max_level+1); + for(int64_t i = 0; i <= max_level; i++) + div_level_table[i] = exp_pow(k_k, max_level-i); + } + + k2_tree(k2_tree &tr) + { + *this = tr; + } + + k2_tree(k2_tree &&tr) + { + *this = std::move(tr); + } + + size_t t_size() const { + return k_t_size; + } + + size_t l_size() const { + return k_l_size; + } + + size_t get_int_t(size_t i) { + assert(i < k_t_size); + return k_t[i]; + } + + size_t get_int_l(size_t i) { + assert(i < k_l_size); + return k_l[i]; + } + + bool t_empty() { + return k_t.empty(); + } + + bool l_empty() { + return k_l.empty(); + } + + uint64_t get_marked_edges() const + { + return n_marked_edges; + } + + uint64_t get_number_edges() const + { + return n_edges - n_marked_edges; + } + + size_type get_number_nodes() const + { + return n_vertices; + } + + typedef struct union_node { + uint16_t level; + uint8_t rA, rB; + } union_node; + + //! Union Operation + /*! Performs the union operation between two tree. This operations requires both + * trees to have the same number of nodes. + * \param k2_B a k2_tree with the same number of nodes + * \par References + * [2] Brisaboa, Nieves R., et al. "Efficient Set Operations over + * k2-Trees." 2015 Data Compression Conference. IEEE, 2015. + */ + void unionOp(shared_ptr k2_B) + { + if(k2_B == nullptr) + return; + + if(k2_B->get_number_edges() == 0) + return; + + if (get_number_edges() == 0) { + *this = *k2_B; + return; + } + assert(k_k == k2_B->k_k); - build_from_edges(edges, size); - } + if (n_vertices != k2_B->n_vertices) + throw std::logic_error("Trees must have the same number of nodes."); + if (k_height != k2_B->k_height) + throw std::logic_error("Trees must have the same height."); + const uint16_t max_height = k_height; - k2_tree(const k2_tree& tr) - { - *this = tr; - } + const uint64_t t_size_A = k_t.size(); + const uint64_t t_size_B = k2_B->k_t.size(); + + const uint64_t l_size_A = k_l.size(); + const uint64_t l_size_B = k2_B->k_l.size(); - k2_tree(k2_tree&& tr) + // C Initialization + uint64_t calc = 1; + uint64_t max_bits = 0; + for (uint64_t i = 0; i < max_height; i++) { - *this = std::move(tr); + calc *= k_k*k_k; + max_bits += calc; } - //! Move assignment operator - k2_tree& operator=(k2_tree&& 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); - k_height = std::move(tr.k_height); - k_t_rank = std::move(tr.k_t_rank); - k_t_rank.set_vector(&k_t); + uint64_t C_t_size = max_bits < t_size_A + t_size_B ? max_bits : t_size_A + t_size_B; + bit_vector C_t(C_t_size); + + calc *= k_k*k_k; + max_bits += calc; + + uint64_t C_l_size = max_bits < l_size_A + l_size_B ? max_bits : l_size_A + l_size_B; + bit_vector C_l(C_l_size); + //////// + + // Q Initialization + std::queue Q; + Q.push({0, 1, 1}); + //////// + + union_node next; + uint8_t bA, bB; + uint64_t pA, pB, idx_t, idx_l; + pA = 0; + pB = 0; + idx_l = 0; + idx_t = 0; + + int n_total_edges = 0; + while (!Q.empty()) { + next = Q.front(); + Q.pop(); + ++next.level; + for (auto i = 0; i < k_k * k_k; ++i) { + bA = 0; + bB = 0; + if (next.rA == 1) { + if (next.level < max_height) + bA = k_t[pA]; + else + bA = k_l[pA - t_size_A]; + ++pA; + } + if (next.rB == 1) { + if (next.level < max_height) + bB = k2_B->k_t[pB]; + else + bB = k2_B->k_l[pB - t_size_B]; + ++pB; + } + + if(bA || bB) { + if(next.level < max_height) { + Q.push({next.level, bA, bB}); + C_t[idx_t] = 1; + } else { + C_l[idx_l] = 1; + ++n_total_edges; + } + } + next.level < max_height ? ++idx_t : ++idx_l; } - return *this; } - - //! Assignment operator - k2_tree& operator=(k2_tree& tr) + assert(C_t_size >= idx_t); + C_t.resize(idx_t); + + assert(C_l_size >= idx_l); + C_l.resize(idx_l); + + k_t.swap(C_t); + k_l.swap(C_l); + k_t_rank = t_rank(&k_t); + k_height = max_height; + n_marked_edges = 0; + n_edges = n_total_edges; + k_t_size = idx_t; + k_l_size = idx_l; + } + + //! Move 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; - k_t_rank.set_vector(&k_t); - k_k = tr.k_k; - k_height = tr.k_height; - } - return *this; + k_t = std::move(tr.k_t); + k_l = std::move(tr.k_l); + k_k = std::move(tr.k_k); + k_height = std::move(tr.k_height); + k_t_rank = t_rank(&k_t); + n_vertices = std::move(tr.n_vertices); + n_marked_edges = std::move(tr.n_marked_edges); + n_edges = std::move(tr.n_edges); + max_level = std::move(tr.max_level); + div_level_table = std::move(tr.div_level_table); + last_level_rank = std::move(tr.last_level_rank); + k_t_size = std::move(tr.k_t_size); + k_l_size = std::move(tr.k_l_size); } + return *this; + } - //! Swap operator - void swap(k2_tree& tr) + //! Assignment operator + k2_tree &operator=(k2_tree &tr) + { + if (this != &tr) { - if (this != &tr) { - std::swap(k_t, tr.k_t); - std::swap(k_l, tr.k_l); - util::swap_support(k_t_rank, tr.k_t_rank, &k_t, &(tr.k_t)); - std::swap(k_k, tr.k_k); - std::swap(k_height, tr.k_height); - } + k_t = tr.k_t; + k_l = tr.k_l; + k_k = tr.k_k; + k_height = tr.k_height; + k_t_rank = t_rank(&k_t); + n_vertices = tr.n_vertices; + n_marked_edges = tr.n_marked_edges; + n_edges = tr.n_edges; + max_level = tr.max_level; + div_level_table = tr.div_level_table; + last_level_rank = tr.last_level_rank; + k_t_size = tr.k_t_size; + k_l_size = tr.k_l_size; + } + return *this; + } + + bool equal(const k2_tree &tr) const { + bool result = true; + + result &= n_vertices == tr.n_vertices; + result &= k_k == tr.k_k; + result &= k_height == tr.k_height; + + if(k_t.size() != tr.k_t.size()) + return false; + else { + for(unsigned int i = 0; i < k_t.size(); ++i) + result &= k_t[i] == tr.k_t[i]; } - //! 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; + if(k_l.size() != tr.k_l.size()) + return false; + else { + for(unsigned int i = 0; i < k_l.size(); ++i) + result &= k_l[i] == tr.k_l[i]; } + return result; + } - t_bv get_t() + //! Swap operator + void swap(k2_tree &tr) + { + if (this != &tr) { - return k_t; + std::swap(k_t, tr.k_t); + std::swap(k_l, tr.k_l); + util::swap_support(k_t_rank, tr.k_t_rank, &k_t, &(tr.k_t)); + std::swap(k_k, tr.k_k); + std::swap(k_height, tr.k_height); + std::swap(n_vertices, tr.n_vertices); + std::swap(n_marked_edges, tr.n_marked_edges); + std::swap(n_edges, tr.n_edges); + std::swap(max_level, tr.max_level); + std::swap(div_level_table, tr.div_level_table); + std::swap(last_level_rank, tr.last_level_rank); + std::swap(k_t_size, tr.k_t_size); + std::swap(k_l_size, tr.k_l_size); + } + } + + //! 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; + } - t_bv get_l() + bool operator!=(const k2_tree &tr) const + { + return !(*this == tr); + } + + + //! Indicates whether node j is adjacent to node i or not. + /*! + * \param i Node i. + * \param j Node j. + * \returns true if there is an edge going from node i to node j, + * false otherwise. + */ + bool adj(idx_type i, idx_type j) const + { + uint t_size = k_t.size(); + if (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); + idx_type col, row; + + // This is duplicated to avoid an extra if at the loop. As idx_type + // is unsigned and rank has an offset of one, is not possible to run + // k_t_rank with zero as parameter at the first iteration. + row = std::floor(i / static_cast(n)); + col = std::floor(j / static_cast(n)); + i = i % n; + j = j % n; + idx_type level = k_k * row + col; + n = n / k_k; + + while (level < t_size) { - return k_l; + if (k_t[level] == 0) + return false; + row = std::floor(i / static_cast(n)); + col = std::floor(j / static_cast(n)); + i = i % n; + j = j % n; + level = k_t_rank(level + 1) * k_2 + k_k * row + col; + n = n / k_k; } + return k_l[level - t_size] == 1; + } + - //! Indicates whether node j is adjacent to node i or not. - /*! + //! Indicates whether node j is adjacent to node i or not, and makes + // it adjacent if possible. + /*! * \param i Node i. * \param j Node j. * \returns true if there is an edge going from node i to node j, * false otherwise. */ - bool adj(idx_type i, idx_type j) const + bool adj_forced(idx_type i, idx_type j) + { + uint t_size = k_t.size(); + if (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); + idx_type col, row; + + // This is duplicated to avoid an extra if at the loop. As idx_type + // is unsigned and rank has an offset of one, is not possible to run + // k_t_rank with zero as parameter at the first iteration. + row = std::floor(i / static_cast(n)); + col = std::floor(j / static_cast(n)); + i = i % n; + j = j % n; + idx_type level = k_k * row + col; + n = n / k_k; + + while (level < t_size) { - if (k_t.size() == 0 && k_l.size() == 0) + if (k_t[level] == 0) return false; - size_type n = std::pow(k_k, k_height - 1); - size_type k_2 = std::pow(k_k, 2); - idx_type col, row; - - // This is duplicated to avoid an extra if at the loop. As idx_type - // is unsigned and rank has an offset of one, is not possible to run - // k_t_rank with zero as parameter at the first iteration. - row = std::floor(i/static_cast(n)); - col = std::floor(j/static_cast(n)); + row = std::floor(i / static_cast(n)); + col = std::floor(j / static_cast(n)); i = i % n; j = j % n; - idx_type level = k_k * row + col; - n = n/k_k; - - 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)); - i = i % n; - j = j % n; - level = k_t_rank(level + 1) * k_2 + k_k * row + col; - n = n/k_k; + level = k_t_rank(level + 1) * k_2 + k_k * row + col; + n = n / k_k; + } + k_l[level - t_size] = 1; + return true; + } + + + bool contains(uint p, uint q) + { + if(k_l.size() > 0) { + max_level = floor(log(n_vertices)/log(k_k)); + if(max_level != 0 && floor(log(n_vertices)/log(k_k)) == (log(n_vertices)/log(k_k))) + max_level = max_level-1; + + div_level_table = std::vector(max_level+1); + for(int64_t i = 0; i <= max_level; i++) + div_level_table[i] = exp_pow(k_k, max_level-i); + + std::vector pL (max_level+1); + pL[0] = 0; + pL[1] = k_k*k_k; + + for(int16_t i = 2; i < max_level; i++) { + pL[i] = (k_t_rank(pL[i-1])+1)*k_k*k_k; } + pL[max_level] = 0; - return k_l[level - k_t.size()] == 1; + if(max_level > 0) + last_level_rank = pL[max_level-1] == 0? 0 : k_t_rank(pL[max_level-1]); + else + last_level_rank = 0; + + return adj_rec(p, q, 0, 0); } + return false; + } + + bool adj_rec(uint p, uint q, uint64_t node, int level) + { + int div_level = div_level_table[level]; + uint64_t newnode = p / div_level * k_k + q / div_level; + newnode += node; - //! Returns a list of neighbors of node i. - /*! + if(level == max_level && k_l[newnode]) { + return true; + } + else if (level < max_level - 1 && k_t[newnode]) + { + return adj_rec(p % div_level, q % div_level, k_t_rank(newnode+1) * k_k * k_k, level + 1); + } + else if(level == max_level - 1 && k_t[newnode]) + { + uint64_t posInf = (k_t_rank(newnode) - last_level_rank) * k_k * k_k; + uint64_t shift = (q % k_k + (p % k_k) * k_k); + return k_l[posInf + shift]; + } + return false; + } + + //! Returns a list of neighbors of node i. + /*! * \param i Node to get neighbors from. * \returns A list of neighbors of node i. */ - std::vector neigh(idx_type i) const - { - std::vector acc{}; - if (k_l.size() == 0 && k_t.size() == 0) - return acc; - // n = k^h / k - // k^h - dimension n of matrix nxn - // /k - to calculate div only once and not for for all parameter again, always (n/k) - size_type n = - static_cast(std::pow(k_k, k_height)) / k_k; - // y = k * i/n - idx_type y = k_k * std::floor(i/static_cast(n)); - for (unsigned j = 0; j < k_k; j++) - _neigh(n/k_k, i % n, n * j, y + j, acc); + std::vector neigh(idx_type i) const + { + std::vector acc{}; + if (k_l.size() == 0 && k_t.size() == 0) return acc; + // n = k^h / k + // k^h - dimension n of matrix nxn + // /k - to calculate div only once and not for for all parameter again, always (n/k) + size_type n = + static_cast(std::pow(k_k, k_height)) / k_k; + // y = k * i/n + idx_type y = k_k * std::floor(i / static_cast(n)); + for (unsigned j = 0; j < k_k; j++) { + _neigh(n / k_k, i % n, n * j, y + j, acc); } + return acc; + } - //! Returns a list of reverse neighbors of node i. - /*! + //! Returns a list of reverse neighbors of node i. + /*! * \param i Node to get reverse neighbors from. * \returns A list of reverse neighbors of node i. */ - std::vector reverse_neigh(idx_type i) const + std::vector reverse_neigh(idx_type i) const + { + std::vector acc{}; + 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; + idx_type y = std::floor(i / static_cast(n)); + for (unsigned j = 0; j < k_k; j++) + _reverse_neigh(n / k_k, n * j, i % n, y + j * k_k, acc); + + return acc; + } + + std::vector> range( + idx_type row1, idx_type row2, + idx_type col1, idx_type col2) const + { + std::vector> res; + + size_type n = static_cast(std::pow(k_k, k_height)) / k_k; + struct state { - std::vector acc{}; - 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; - idx_type y = std::floor(i/static_cast(n)); - for (unsigned j = 0; j < k_k; j++) - _reverse_neigh(n/k_k, n * j, i % n, y + j * k_k, acc); + idx_type n, row1, row2, col1, col2, dr, dc, z; + state(idx_type n, idx_type row1, idx_type row2, idx_type col1, idx_type col2, + idx_type dr, idx_type dc, idx_type z) + : n(n), row1(row1), row2(row2), col1(col1), col2(col2), dr(dr), dc(dc), z(z) {} + }; + std::vector states; + states.reserve(k_height); // minimum + states.emplace_back(n, row1, row2, col1, col2, 0, 0, std::numeric_limits::max()); - return acc; + while (!states.empty()) + { + state s = states.back(); + states.pop_back(); + + //TODO: peel first loop where z==-1 atm + if (s.z != std::numeric_limits::max() && s.z >= k_t.size()) + { // Last level + if (k_l[s.z - k_t.size()] == 1) + { + res.emplace_back(s.dr, s.dc); + } + } + else if (s.z == std::numeric_limits::max() || k_t[s.z] == 1) + { + + auto y = k_t_rank(s.z + 1) * k_k * k_k; + + for (idx_type i = s.row1 / s.n; i <= s.row2 / s.n; ++i) + { + idx_type row1new, row2new; + //TODO: loop peeling, first iteration and last iteration special + if (i == s.row1 / s.n) + row1new = s.row1 % s.n; + else + row1new = 0; + if (i == s.row2 / s.n) + row2new = s.row2 % s.n; + else + row2new = s.n - 1; + + for (idx_type j = s.col1 / s.n; j <= s.col2 / s.n; ++j) + { + idx_type col1new, col2new; + //TODO: loop peeling, first iteration and last iteration special + if (j == s.col1 / s.n) + col1new = s.col1 % s.n; + else + col1new = 0; + if (j == s.col2 / s.n) + col2new = s.col2 % s.n; + else + col2new = s.n - 1; + + states.emplace_back(s.n / k_k, row1new, row2new, col1new, col2new, + s.dr + s.n * i, s.dc + s.n * j, y + k_k * i + j); + } + } + } } - std::vector> range( - idx_type row1, idx_type row2, - idx_type col1, idx_type col2 - ) const { - std::vector> res; - - size_type n = static_cast(std::pow(k_k, k_height)) / k_k; - struct state{ - idx_type n, row1, row2, col1, col2, dr, dc, z; - state(idx_type n, idx_type row1, idx_type row2, idx_type col1, idx_type col2, - idx_type dr, idx_type dc, idx_type z) - : n(n), row1(row1), row2(row2), col1(col1), col2(col2), dr(dr), dc(dc), z(z) {} - }; - std::vector states; - states.reserve(k_height); // minimum - states.emplace_back(n, row1, row2, col1, col2, 0, 0, std::numeric_limits::max()); - - while(!states.empty()){ - state s = states.back(); - states.pop_back(); - - //TODO: peel first loop where z==-1 atm - if(s.z!=std::numeric_limits::max() && s.z >= k_t.size()){ // Last level - if(k_l[s.z - k_t.size()] == 1){ - res.emplace_back(s.dr, s.dc); - } - }else if(s.z==std::numeric_limits::max() || k_t[s.z]==1){ - - auto y = k_t_rank(s.z+1) * k_k * k_k; - - for(idx_type i=s.row1/s.n; i<=s.row2/s.n; ++i){ - idx_type row1new, row2new; - //TODO: loop peeling, first iteration and last iteration special - if(i==s.row1/s.n) row1new = s.row1 % s.n; else row1new = 0; - if(i==s.row2/s.n) row2new = s.row2 % s.n; else row2new = s.n - 1; - - for(idx_type j=s.col1/s.n; j<=s.col2/s.n; ++j){ - idx_type col1new, col2new; - //TODO: loop peeling, first iteration and last iteration special - if(j==s.col1/s.n) col1new = s.col1 % s.n; else col1new = 0; - if(j==s.col2/s.n) col2new = s.col2 % s.n; else col2new = s.n - 1; - - states.emplace_back(s.n/k_k, row1new, row2new, col1new, col2new, - s.dr + s.n*i, s.dc + s.n*j, y + k_k*i+j); - } - } - } - } - - return res; - }; + return res; + }; - //! Serialize to a stream - /*! Serialize the k2_tree data structure + //! Serialize to a stream + /*! Serialize the k2_tree data structure * \param out Outstream to write the k2_tree. * \param v * \param string_name * \returns The number of written bytes. */ - size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, - std::string name="") const + size_type serialize(std::ostream &out, structure_tree_node *v = nullptr, + std::string name = "") const + { + structure_tree_node *child = structure_tree::add_child( + v, name, util::class_name(*this)); + size_type written_bytes = 0; + + written_bytes += k_t.serialize(out, child, "t"); + written_bytes += k_l.serialize(out, child, "l"); + written_bytes += k_t_rank.serialize(out, child, "t_rank"); + written_bytes += write_member(k_k, out, child, "k"); + written_bytes += write_member(k_height, out, child, "height"); + written_bytes += write_member(n_vertices, out, child, "n_vertices"); + written_bytes += write_member(n_marked_edges, out, child, "n_marked_edges"); + written_bytes += write_member(n_edges, out, child, "n_edges"); + + structure_tree::add_size(child, written_bytes); + return written_bytes; + } + + //! Load from istream + /*! Serialize the k2_tree from the given istream. + * \param istream Stream to load the k2_tree from. + */ + void load(std::istream &in) + { + k_t.load(in); + k_l.load(in); + k_t_rank.load(in); + k_t_rank.set_vector(&k_t); + read_member(k_k, in); + read_member(k_height, in); + read_member(n_vertices, in); + read_member(n_marked_edges, in); + read_member(n_edges, in); + + max_level = floor(log(n_vertices)/log(k_k)); + if(max_level != 0 && floor(log(n_vertices)/log(k_k)) == (log(n_vertices)/log(k_k))) + max_level = max_level-1; + + div_level_table = std::vector(max_level+1); + for(int64_t i = 0; i <= max_level; i++) + div_level_table[i] = exp_pow(k_k, max_level-i); + k_t_size = k_t.size(); + k_l_size = k_l.size(); + + } + + bool erase(idx_type i, idx_type j) + { + 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); + idx_type col, row; + + // This is duplicated to avoid an extra if at the loop. As idx_type + // is unsigned and rank has an offset of one, is not possible to run + // k_t_rank with zero as parameter at the first iteration. + row = std::floor(i / static_cast(n)); + col = std::floor(j / static_cast(n)); + i = i % n; + j = j % n; + idx_type level = k_k * row + col; + n = n / k_k; + + while (level < k_t.size()) { - structure_tree_node* child = structure_tree::add_child( - v, name, util::class_name(*this)); - size_type written_bytes = 0; - - written_bytes += k_t.serialize(out, child, "t"); - written_bytes += k_l.serialize(out, child, "l"); - written_bytes += k_t_rank.serialize(out, child, "t_rank"); - written_bytes += write_member(k_k, out, child, "k"); - written_bytes += write_member(k_height, out, child, "height"); - structure_tree::add_size(child, written_bytes); - return written_bytes; + if (k_t[level] == 0) + return false; + row = std::floor(i / static_cast(n)); + col = std::floor(j / static_cast(n)); + i = i % n; + j = j % n; + level = k_t_rank(level + 1) * k_2 + k_k * row + col; + n = n / k_k; } + if(k_l[level - k_t.size()] == 1) + { + k_l[level - k_t.size()] = 0; + n_marked_edges++; + return true; + } + return false; + } + + edg_iterator &edge_begin() + { + it_e_begin = edg_iterator(this); + it_e_end = it_e_begin.end(); + return it_e_begin; + } + + edg_iterator &edge_end() + { + return it_e_end; + } + + nod_iterator node_begin() + { + return nod_iterator(this); + } + + nod_iterator node_end() + { + return nod_iterator(this).end(); + } + + neigh_iterator &neighbour_begin(idx_type node) { + it_neigh_begin = neigh_iterator(this, node); + return it_neigh_begin; + } + + neigh_iterator &neighbour_end() { + return it_neigh_end; + } + + + uint exp_pow(uint base, uint pow) + { + uint i, result = 1; + for (i = 0; i < pow; i++) + result *= base; + + return result; + } + + void edge_it(std::function func) { + if(k_l.size() > 0) { + max_level = floor(log(n_vertices)/log(k_k)); + if(max_level != 0 && floor(log(n_vertices)/log(k_k)) == (log(n_vertices)/log(k_k))) + max_level = max_level-1; + + div_level_table = std::vector(max_level+1); + for(int64_t i = 0; i <= max_level; i++) + div_level_table[i] = exp_pow(k_k, max_level-i); + + pointerL = std::vector(max_level+1); + pointerL[0] = 0; + pointerL[1] = k_k*k_k; + + for(size_t i = 2; i < max_level; i++) { + pointerL[i] = (k_t_rank(pointerL[i-1])+1)*k_k*k_k; + } + pointerL[max_level] = 0; + _edge_it_rec(0, 0, -1, -1, func); + } + } + + void set_edges(uint64_t edges) { n_edges = edges;} + uint64_t total_edges() { return n_edges;} + + void neigh_it(uint64_t i, std::function func) { + if (k_l.size() == 0 && k_t.size() == 0) + return; + // n = k^h / k + // k^h - dimension n of matrix nxn + // /k - to calculate div only once and not for for all parameter again, always (n/k) + size_type n = + static_cast(std::pow(k_k, k_height)) / k_k; + // y = k * i/n + idx_type y = k_k * std::floor(i / static_cast(n)); + for (unsigned j = 0; j < k_k; j++) { + _neigh_rec(n / k_k, i % n, n * j, y + j, func); + } + } - //! Load from istream - /*! Serialize the k2_tree from the given istream. - * \param istream Stream to load the k2_tree from. - */ - void load(std::istream& in) + std::vector neigh_test(idx_type i) const { - k_t.load(in); - k_l.load(in); - k_t_rank.load(in); - k_t_rank.set_vector(&k_t); - read_member(k_k, in); - read_member(k_height, in); + std::deque q; + std::vector acc{}; + + if (k_l.size() == 0 && k_t.size() == 0) + return acc; + + size_type n = + static_cast(std::pow(k_k, k_height)) / k_k; + // y = k * i/n + idx_type y = k_k * std::floor(i / static_cast(n)); + + for (unsigned j = 0; j < k_k; j++) { + q.emplace_front(tree_node2(n / k_k, i % n, n * j, y + j)); + } + + /// + while (!q.empty()) + { + tree_node2 s = q.front(); + q.pop_front(); + + if (s.level >= k_t.size()) + { + if (k_l[s.level - k_t.size()] == 1) + acc.push_back(s.col); + continue; // + } + + if (k_t[s.level] == 1) + { + idx_type y = k_t_rank(s.level + 1) * std::pow(k_k, 2) + + k_k * std::floor(s.row / static_cast(s.n)); + for (unsigned j = 0; j < k_k; j++) + q.emplace_front(tree_node2(s.n / k_k, s.row % s.n, s.col + s.n * j, y + j)); + } + + } + return acc; } + class tree_node2 + { + public: + size_type n; + idx_type row, col, level; + + tree_node2() {} + tree_node2(size_type n, idx_type row, idx_type col, size_type level) : n(n), row(row), col(col), level(level){} + }; }; -} +} // namespace sdsl #endif diff --git a/include/sdsl/k2_tree_iterator.hpp b/include/sdsl/k2_tree_iterator.hpp new file mode 100644 index 000000000..48ac91b6a --- /dev/null +++ b/include/sdsl/k2_tree_iterator.hpp @@ -0,0 +1,803 @@ +#ifndef INCLUDED_SDSL_K2_TREE_ITERATOR +#define INCLUDED_SDSL_K2_TREE_ITERATOR + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +namespace sdsl +{ + using idx_type = k2_tree_ns::idx_type; + using size_type = k2_tree_ns::size_type; + using edge = std::tuple; + + // typedef struct tree_node + // { + // int node; + // size_type n; + // unsigned row, col; + // idx_type level; + // unsigned j; + // size_type y; + // } tree_node; + + // template + // class edge_iterator + // { + // public: + // using value_type = edge; + // using pointer = shared_ptr; + // using reference = edge &; + // using iterator_category = std::forward_iterator_tag; + + // edge_iterator() {} + + // edge_iterator(const k_tree *tree) + // { + // this->tree = tree; + // this->k = tree->k_k; + // _initialize(); + // } + + // idx_type x() { + // return get<0>(_ptr); + // } + + // idx_type y() { + // return get<1>(_ptr); + // } + + // value_type operator*() + // { + // return _ptr; + // } + + // bool operator==(const edge_iterator &rhs) const + // { + // return equal_edge(rhs._ptr, _ptr); + // } + + // bool operator!=(const edge_iterator &rhs) const + // { + // return !(*this == rhs); + // } + + // void print() + // { + // cout << "_ptr " << std::get<0>(_ptr) << ", " << std::get<1>(_ptr) << endl; + // cout << "_node " << _node << endl; + // cout << "_level " << _level << endl; + // cout << "_row " << _row << endl; + // cout << "st " << endl; + + // for (tree_node st_i : st) + // { + + // cout << " node: " << st_i.node << endl; + // cout << " row: " << st_i.row << endl; + // cout << " n: " << st_i.n << endl; + // cout << " level: " << st_i.level << endl; + // cout << " j: " << st_i.j << endl; + // cout << " y: " << st_i.y << endl; + // cout << endl; + // } + // } + + // edge_iterator &operator++(int) + // { + // operator++(); + // return *this; + // } + + // edge_iterator &operator++() + // { + // while (!st.empty()) // did not go until the end of the subtree + // { + // tree_node &last_found = st.back(); + // last_found.j++; + // idx_type neigh; + // if (last_found.n == _n / k && last_found.j < k) + // { + // if (_find_next_recursive(last_found.n / k, + // last_found.row % last_found.n, + // last_found.col + last_found.n * last_found.j, + // last_found.y + last_found.j, + // neigh, 0)) + // { + // _ptr = edge(last_found.node, neigh); + // return *this; + // } + // } + // if (last_found.j < k) + // { + // if (_find_next_recursive(last_found.n / k, + // last_found.row % last_found.n, + // last_found.col + last_found.n * last_found.j, + // last_found.y + last_found.j, + // neigh, last_found.j)) + // { + // _ptr = edge(last_found.node, neigh); + // return *this; + // } + // } + // st.pop_back(); + + // } // move to another subtree + // _row++; + // if (_row >= k) + // { + // _row = 0; + // _node++; + // _level = k * std::floor(_node / static_cast(_n)); + // } + // _ptr = _find_next(); + // return *this; + // } + + // edge_iterator end() + // { + // edge_iterator it = *this; + // it._ptr = edge(size, size); //end node + + // it._node = size - 1; + // it._level = k * std::floor(it._node / static_cast(it._n)); + // it._row = k; + + // return it; + // } + + // friend void swap(edge_iterator &rhs, edge_iterator &lhs) + // { + // if (&rhs != &lhs) + // { + // std::swap(rhs.tree, lhs.tree); + // std::swap(rhs.k, lhs.k); + + // std::swap(rhs._ptr, lhs._ptr); + // std::swap(rhs.size, lhs.size); + // std::swap(rhs._node, lhs._node); + // std::swap(rhs._level, lhs._level); + // std::swap(rhs._row, lhs._row); + // } + // } + + // private: + // bool equal_edge(const edge &e1, const edge &e2) const + // { + // idx_type e1_x = std::get<0>(e1); + // idx_type e1_y = std::get<1>(e1); + + // idx_type e2_x = std::get<0>(e2); + // idx_type e2_y = std::get<1>(e2); + + // return e1_x == e2_x && e1_y == e2_y; + // } + + // value_type _ptr; + // // container + // const k_tree *tree; + // uint8_t k = 2; + // // + // // iterator state // + // deque st; + // size_type _n; + // idx_type _level; + // int _row, _node, size; + // // + + // void + // _initialize() + // { + // _n = static_cast(std::pow(k, tree->k_height) / k; + // _node = 0; + // _row = 0; + // _level = k * std::floor(_node / static_cast(_n)); + // size = std::pow(k, tree->k_height; + + // if (tree->l_size() > 0) + // { + // _ptr = _find_next(); + // } + // else + // { + // // if its empty the begin == end + // _ptr = edge(size, size); //end node + // } + // } + + // edge _find_next() + // { + // idx_type neigh; + // if (_node < size) + // { + // for (; _row < k; _row++) + // { + // neigh = size; + // _find_next_recursive(_n / k, _node % _n, _n * _row, _level + _row, neigh, 0); + // if (neigh < (idx_type)size) + // { + // return edge(_node, neigh); + // } + // assert(st.empty()); + // } + // _row = 0; + // _node++; + // _level = k * std::floor(_node / static_cast(_n)); + // return _find_next(); + // } + // return edge(size, size); // end node + // } + + // bool _find_next_recursive(size_type n, unsigned row, unsigned col, size_type level, + // idx_type &neigh, unsigned initial_j) + // { + // if (level >= tree->t().size()) + // { // Last level + // if (tree->l()[level - tree->t().size()] == 1) + // { + // neigh = col; + // return true; + // } + // return false; + // } + + // if (tree->t()[level] == 1) + // { + // size_type y = tree->rank_t()(level + 1) * k * k + + // k * std::floor(row / static_cast(n)); + + // for (unsigned j = initial_j; j < k; j++) + // { + // tree_node next_node = {_node, n, row, col, level, j, y}; + // st.push_back(next_node); + // if (_find_next_recursive(n / k, row % n, col + n * j, y + j, neigh, 0)) + // return true; + // st.pop_back(); + // } + // } + // return false; + // } + // }; + /////////////////////////////////////////////////////////////////////////////////////////////// + template + class edge_iterator + { + public: + using value_type = edge; + using pointer = shared_ptr; + using reference = edge &; + using iterator_category = std::forward_iterator_tag; + + edge_iterator() = default; + + edge_iterator(const k_tree *tree) + { + this->tree = tree; + this->k = tree->k_k; + nodes = tree->get_number_nodes(); + _initialize(); + } + + idx_type x() + { + return get<0>(_ptr); + } + + idx_type y() + { + return get<1>(_ptr); + } + + value_type operator*() + { + return _ptr; + } + + bool operator==(const edge_iterator &rhs) const + { + return equal_edge(rhs._ptr, _ptr); + } + + bool operator!=(const edge_iterator &rhs) const + { + return !(*this == rhs); + } + + edge_iterator &operator++(int) + { + operator++(); + return *this; + } + + edge_iterator &operator++() + { + edge e(nodes, nodes); + while (!st.empty()) // did not go until the end of the subtree + { + struct edge_node last_found = st.back(); + st.pop_back(); + + int type = last_found.type; + uint i = last_found.i; + uint j = last_found.j; + + uint64_t dp = last_found.dp; + uint64_t dq = last_found.dq; + int64_t y = last_found.y; + int l = last_found.l; + // + + j++; + if (j < k) + { + if (_find_next_rec(dp, dq, y, l, type, i, j, e)) + break; + } + else + { + j = 0; + i++; + if (i < k) + { + if (_find_next_rec(dp, dq, y, l, type, i, j, e)) + break; + } + } + } + _ptr = e; + return *this; + } + + edge_iterator end() + { + edge_iterator it; + it._ptr = edge(nodes, nodes); //end node + return it; + } + + friend void swap(edge_iterator &rhs, edge_iterator &lhs) + { + if (&rhs != &lhs) + { + std::swap(rhs.tree, lhs.tree); + std::swap(rhs.k, lhs.k); + + std::swap(rhs._ptr, lhs._ptr); + std::swap(rhs.nodes, lhs.nodes); + std::swap(rhs.max_level, lhs.max_level); + std::swap(rhs.div_level_table, lhs.div_level_table); + std::swap(rhs.st, lhs.st); + } + } + + private: + bool equal_edge(const edge &e1, const edge &e2) const + { + idx_type e1_x = std::get<0>(e1); + idx_type e1_y = std::get<1>(e1); + + idx_type e2_x = std::get<0>(e2); + idx_type e2_y = std::get<1>(e2); + + return e1_x == e2_x && e1_y == e2_y; + } + + value_type _ptr; + // container + const k_tree *tree; + uint8_t k = 2; + // + // iterator state // + class edge_node + { + public: + uint64_t dp, dq, i, j; + int64_t y; + int type, l; + + edge_node() {} + edge_node(uint64_t dp, uint64_t dq, int64_t y, uint64_t i, uint64_t j, int type, int l) : dp(dp), dq(dq), + i(i), j(j), y(y), type(type), l(l) {} + }; + std::deque st; + uint32_t max_level; + uint64_t nodes; + std::vector div_level_table; + std::vector pointerL; + // + + uint exp_pow(uint base, uint pow) + { + uint i, result = 1; + for (i = 0; i < pow; i++) + result *= base; + + return result; + } + + void + _initialize() + { + if (tree->l_size() > 0) + { + max_level = floor(log(nodes) / log(k)); + if (floor(log(nodes) / log(k)) == (log(nodes) / log(k))) + max_level = max_level - 1; + + div_level_table = std::vector(max_level + 1); + for (uint i = 0; i <= max_level; i++) + div_level_table[i] = exp_pow(k, max_level - i); + + pointerL = std::vector(max_level + 1); + + pointerL[0] = 0; + pointerL[1] = k * k; + + for (uint64_t i = 2; i < max_level; i++) + { + pointerL[i] = (tree->k_t_rank(pointerL[i - 1]) + 1) * k * k; + } + pointerL[max_level] = 0; + + edge e = edge(nodes, nodes); + _find_next(0, 0, -1, -1, e); + _ptr = e; + } + else + { + // if its empty the begin == end + _ptr = edge(nodes, nodes); //end node + } + } + + bool _find_next(uint64_t dp, uint64_t dq, int64_t x, int l, edge &e) + { + if (l == (int64_t)max_level) + { + if (tree->k_l[x]) + { + e = edge(dp, dq); + return true; + } + return false; + } + + if ((l == (int64_t)max_level - 1) && tree->k_t[x]) + { + int64_t y = pointerL[l + 1]; + pointerL[l + 1] += k * k; + + for (uint64_t i = 0; i < k; i++) + { + for (uint64_t j = 0; j < k; j++) + { + st.push_back(edge_node(dp, dq, y, i, j, 1, l)); + if (_find_next(dp + i, dq + j, y + k * i + j, l + 1, e)) + return true; + st.pop_back(); + } + } + return false; + } + if ((x == -1) || ((l < (int64_t)max_level - 1) && tree->k_t[x])) + { + int64_t y = pointerL[l + 1]; + pointerL[l + 1] += k * k; + + uint64_t div_level = div_level_table[l + 1]; + + for (uint64_t i = 0; i < k; i++) + { + for (uint64_t j = 0; j < k; j++) + { + st.push_back(edge_node(dp, dq, y, i, j, 2, l)); + if (_find_next(dp + div_level * i, dq + div_level * j, y + k * i + j, l + 1, e)) + return true; + st.pop_back(); + } + } + return false; + } + + return false; + } + + bool _find_next_rec(uint64_t dp, uint64_t dq, int64_t y, int l, int type, uint64_t i, uint64_t j, edge &e) + { + if (type == 1) + { + st.push_back(edge_node(dp, dq, y, i, j, 1, l)); + return _find_next(dp + i, dq + j, y + k * i + j, l + 1, e); + } + else if (type == 2) + { + uint64_t div_level = div_level_table[l + 1]; + st.push_back(edge_node(dp, dq, y, i, j, 2, l)); + return _find_next(dp + div_level * i, dq + div_level * j, y + k * i + j, l + 1, e); + } + return false; + } + }; + ////////////////////////////////////////////////////////////////////////////////////////////// + + template + class node_iterator + { + using node_type = k2_tree_ns::idx_type; + using size_type = k2_tree_ns::size_type; + + public: + using value_type = node_type; + using pointer = shared_ptr; + using reference = node_type &; + using iterator_category = std::forward_iterator_tag; + + node_iterator() {} + + node_iterator(const k2_tree *k_tree) + { + this->tree = k_tree; + + if (tree->get_number_edges() == 0) + { + value_type num_nodes = tree->get_number_nodes(); + _ptr = num_nodes; + curr_i = num_nodes; + curr_j = num_nodes; + return; + } + + for (value_type i = 0; i < tree->get_number_nodes(); i++) + { + for (value_type j = i; j < tree->get_number_nodes(); j++) + if (tree->adj(i, j)) + { + _ptr = i; + curr_i = i; + curr_j = j; + return; + } + for (value_type j = i; j < tree->get_number_nodes(); j++) + if (tree->adj(j, i)) + { + _ptr = i; + curr_i = i + 1; + curr_j = i; + return; + } + } + } + + node_iterator(node_iterator *other) + { + this->_ptr = other->_ptr; + this->tree = other->tree; + this->curr_i = other->curr_i; + this->curr_j = other->curr_j; + } + + ~node_iterator() {} + + value_type operator*() const + { + return _ptr; + } + + node_iterator &operator=(const node_iterator &other) + { + if (this != &other) + { + tree = other.tree; + _ptr = other._ptr; + curr_i = other.curr_i; + curr_j = other.curr_j; + } + return *this; + } + + bool operator==(const node_iterator &rhs) const + { + return rhs._ptr == _ptr; + } + + bool operator!=(const node_iterator &rhs) const + { + return !(*this == rhs); + } + + node_iterator &operator++() + { + for (value_type i = curr_i; i < tree->get_number_nodes(); i++) + { + for (value_type j = curr_j; j < tree->get_number_nodes(); j++) + if (tree->adj(i, j)) + return update_state(i); + for (value_type j = 0; j < tree->get_number_nodes(); j++) + { + if (j == i) + continue; + if (tree->adj(j, i)) + return update_state(i); + } + curr_j = 0; + } + return *this; + } + + node_iterator &operator++(int) + { + if (_ptr == tree->get_number_nodes() - 1) + { + *this = end(); + return *this; + } + value_type prev = _ptr; + operator++(); + if (_ptr == prev) + this->end(); + return *this; + } + + node_iterator end() + { + if (tree == NULL) + return *this; + node_iterator it = *this; + value_type num_nodes = it.tree->get_number_nodes(); + it._ptr = num_nodes; //end node + it.curr_i = num_nodes; + it.curr_j = num_nodes; + return it; + } + + private: + value_type _ptr; + const k2_tree *tree = NULL; + value_type curr_i, curr_j; + + node_iterator &update_state(node_type i) + { + _ptr = i; + curr_i = i + 1; + curr_j = 0; + + return *this; + } + }; + + template + class neighbour_iterator + { + using idx_type = k2_tree_ns::idx_type; + using size_type = k2_tree_ns::size_type; + + public: + using value_type = size_type; + using pointer = shared_ptr; + using reference = size_type &; + using iterator_category = std::forward_iterator_tag; + + neighbour_iterator() + { + _is_end = true; + } + + neighbour_iterator(const k_tree *tree, value_type i) + { + this->tree = tree; + this->k = tree->k_k; + this->t_size = tree->k_t.size(); + + if (tree->k_l.size() == 0 && t_size == 0) { + end(); + } + + size_type n = + static_cast(std::pow(k, tree->k_height)) / k; + // y = k * i/n + idx_type y = k * std::floor(i / static_cast(n)); + + for (unsigned j = 0; j < k; j++) { + q.push(neigh_state(n / k, i % n, n * j, y + j)); + } + operator++(); + } + + value_type operator*() + { + return _ptr; + } + + neighbour_iterator &operator++(int) + { + if (!_is_end) + operator++(); + return *this; + } + + neighbour_iterator &operator++() + { + while (!q.empty()) + { + neigh_state s = q.top(); + q.pop(); + + if (s.level >= t_size) + { + if (tree->k_l[s.level - t_size] == 1) { + _ptr = s.col; + return *this; + } + continue; + } + + if (tree->k_t[s.level] == 1) + { + idx_type y = tree->k_t_rank(s.level + 1) * std::pow(k, 2) + + k * std::floor(s.row / static_cast(s.n)); + for (unsigned j = 0; j < k; j++) + q.push(neigh_state(s.n / k, s.row % s.n, s.col + s.n * j, y + j)); + } + } + end(); + return *this; + } + + bool operator==(neighbour_iterator &rhs) const + { + return rhs._ptr == _ptr && _is_end == rhs._is_end; + } + + bool operator!=(neighbour_iterator &rhs) const + { + return !(*this == rhs); + } + + const neighbour_iterator &end() + { + _ptr = 0; + _is_end = true; + return *this; + } + + friend void swap(neighbour_iterator &rhs, neighbour_iterator &lhs) + { + std::swap(rhs._ptr, lhs._ptr); + std::swap(rhs._is_end, lhs._is_end); + std::swap(rhs.tree, lhs.tree); + std::swap(rhs.k, lhs.k); + std::swap(rhs.t_size, lhs.t_size); + std::swap(rhs.q, lhs.q); + } + + private: + size_type _ptr; + bool _is_end = false; + const k_tree *tree; + uint16_t k = 2; + uint t_size = 0; + + // iterator state // + class neigh_state + { + public: + size_type n, level; + idx_type row, col; + + neigh_state() {} + neigh_state(size_type n, idx_type row, idx_type col, size_type level) : n(n), level(level), row(row), col(col) {} + }; + std::stack q; + // + }; +} // namespace sdsl + +#endif \ No newline at end of file diff --git a/test/k2_tree_test.cpp b/test/k2_tree_test.cpp index 35358c752..1596bd82f 100644 --- a/test/k2_tree_test.cpp +++ b/test/k2_tree_test.cpp @@ -1,5 +1,5 @@ -#include "sdsl/k2_tree.hpp" #include "gtest/gtest.h" +#include "sdsl/k2_tree.hpp" #include #include @@ -10,93 +10,115 @@ namespace using namespace sdsl; using namespace std; +using namespace k2_tree_ns; typedef int_vector<>::size_type size_type; -template -class k2_tree_test_k_2 : public ::testing::Test { }; +template +class k2_tree_test_k_2 : public ::testing::Test{}; -template -class k2_tree_test_k_3 : public ::testing::Test { }; +template +class k2_tree_test_k_3 : public ::testing::Test{}; -template -class k2_tree_test : public ::testing::Test { }; +template +class k2_tree_test : public ::testing::Test{}; + +template +class k2_tree_test_marked : public ::testing::Test{}; using testing::Types; namespace k2_tree_test_nm { -template -void check_t_l(t_tree& tree, vector expected_t, +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()); + ASSERT_EQ(expected_t.size(), tree.t_size()); + ASSERT_EQ(expected_l.size(), tree.l_size()); for (unsigned i = 0; i < expected_t.size(); i++) - ASSERT_EQ(expected_t[i], tree.get_t().get_int(i, 1)); + ASSERT_EQ(expected_t[i], tree.get_int_t(i)); for (unsigned i = 0; i < expected_l.size(); i++) - ASSERT_EQ(expected_l[i], tree.get_l().get_int(i, 1)); + ASSERT_EQ(expected_l[i], tree.get_int_l(i)); +} + +template +void assert_eq_tree(t_tree &tree1, t_tree &tree2) +{ + ASSERT_EQ(tree1.t_size(), tree2.t_size()); + ASSERT_EQ(tree1.l_size(), tree2.l_size()); + for (unsigned i = 0; i < tree1.t_size(); i++) + ASSERT_EQ(tree1.get_int_t(i), tree2.get_int_t(i)); + + for (unsigned i = 0; i < tree1.l_size(); i++) + ASSERT_EQ(tree1.get_int_l(i), tree2.get_int_l(i)); } -template -void check_serialize_load(t_tree& 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); + ASSERT_TRUE(tree.equal(unserialized_tree)); } -}; +}; // namespace k2_tree_test_nm 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; + +typedef Types< + k2_tree<2, bit_vector>, + k2_tree<3, bit_vector>, + k2_tree<7, bit_vector>, + k2_tree<5, bit_vector, rank_support_v<>>, + k2_tree<4, bit_vector, rank_support_v<>>> + Implementations_bit_vector; 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} - }); + vector> mat({{1, 1, 0, 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} - }); + 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}}); 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()); + ASSERT_TRUE(tree.t_empty()); + ASSERT_TRUE(tree.l_empty()); // Size is minor than k: mat = vector>({{0}}); @@ -107,127 +129,519 @@ TYPED_TEST(k2_tree_test_k_2, build_from_matrix_test) tree = TypeParam(mat); k2_tree_test_nm::check_t_l(tree, {}, {1, 0, 0, 0}); - // 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); + expected_l = {0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0}; + + ASSERT_EQ(tree.get_number_edges(), 3); + 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} - }); + mat = vector>({{0, 0, 0}, + {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); + 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 - }; - - 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 - }; + 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}; + + 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}; 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}; t_tuple c{1, 0}; t_tuple d{1, 1}; - e.push_back(t_tuple {1, 2}); + e.push_back(t_tuple{1, 2}); TypeParam tree(e, 4); - k2_tree_test_nm::check_t_l(tree, {0, 1, 0 ,0}, {0, 0, 1, 0}); + k2_tree_test_nm::check_t_l(tree, {0, 1, 0, 0}, {0, 0, 1, 0}); tree = TypeParam(e, 3); - k2_tree_test_nm::check_t_l(tree, {0, 1, 0 ,0}, {0, 0, 1, 0}); + k2_tree_test_nm::check_t_l(tree, {0, 1, 0, 0}, {0, 0, 1, 0}); - e.push_back(t_tuple {1, 2}); + e.push_back(t_tuple{1, 2}); tree = TypeParam(e, 3); - k2_tree_test_nm::check_t_l(tree, {0, 1, 0 ,0}, {0, 0, 1, 0}); + k2_tree_test_nm::check_t_l(tree, {0, 1, 0, 0}, {0, 0, 1, 0}); e.clear(); - e.push_back(t_tuple {0, 0}); + e.push_back(t_tuple{0, 0}); tree = TypeParam(e, 1); k2_tree_test_nm::check_t_l(tree, {}, {1, 0, 0, 0}); - e.push_back(t_tuple {0, 1}); - e.push_back(t_tuple {1, 0}); - e.push_back(t_tuple {1, 1}); + e.push_back(t_tuple{0, 1}); + e.push_back(t_tuple{1, 0}); + e.push_back(t_tuple{1, 1}); tree = TypeParam(e, 2); k2_tree_test_nm::check_t_l(tree, {}, {1, 1, 1, 1}); - e.push_back(t_tuple {2, 2}); + e.push_back(t_tuple{2, 2}); tree = TypeParam(e, 3); - k2_tree_test_nm::check_t_l(tree, {1, 0, 0, 1}, {1, 1, 1, 1, 1, 0, 0, 0}); + k2_tree_test_nm::check_t_l(tree, {1, 0, 0, 1}, {1, 1, 1, 1, 1, 0, 0, 0}); + ASSERT_EQ(e.size(), (size_t)5); + ASSERT_EQ(tree.total_edges(), (uint64_t)5); } +TYPED_TEST(k2_tree_test_k_2, union_operation_test_happy_path) +{ + vector> mat({{1, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 0, 1, 1}, + {0, 0, 1, 0}}); + // T 1 0 0 1 + // L 1 1 0 1 1 1 1 0 + TypeParam tree_A(mat); + mat = vector>({{0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 1}}); + // T 0 0 0 1 + // L 0 0 0 1 + shared_ptr tree_B = make_shared(mat); + + tree_A.unionOp(tree_B); + + k2_tree_test_nm::check_t_l(tree_A, {1, 0, 0, 1}, {1, 1, 0, 1, 1, 1, 1, 1}); +} + +TYPED_TEST(k2_tree_test_k_2, empty_union_operation) +{ + vector> mat({{1, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 0, 1, 1}, + {0, 0, 1, 0}}); + + shared_ptr tree_A = make_shared(mat); + shared_ptr tree_B = make_shared(); + + shared_ptr tree_A_copy = tree_A; + shared_ptr tree_B_copy = tree_B; + + tree_A_copy->unionOp(tree_B); + k2_tree_test_nm::check_t_l(*tree_A_copy, {1, 0, 0, 1}, {1, 1, 0, 1, 1, 1, 1, 0}); + + tree_B_copy->unionOp(tree_A); + k2_tree_test_nm::check_t_l(*tree_B_copy, {1, 0, 0, 1}, {1, 1, 0, 1, 1, 1, 1, 0}); + + tree_B->unionOp(tree_B); + k2_tree_test_nm::assert_eq_tree(*tree_B, *tree_B); +} + +TYPED_TEST(k2_tree_test_k_2, union_operation_test) +{ + vector> mat({{1, 1}, + {0, 1}}); + TypeParam tree_A(mat); + + mat = vector>({{0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 1}}); + shared_ptr tree_B = make_shared(mat); + + ASSERT_THROW(tree_A.unionOp(tree_B), std::logic_error); +} +TYPED_TEST(k2_tree_test_k_2, edge_iterator_empty_test) { + + TypeParam tree; + ASSERT_EQ(tree.edge_begin(), tree.edge_end()); + + vector> mat1({{0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}}); + + TypeParam emptyTree(mat1); + ASSERT_EQ(emptyTree.edge_begin().x(), (uint)4); + ASSERT_EQ(emptyTree.edge_begin().y(), (uint)4); +} + + +TYPED_TEST(k2_tree_test_k_2, edge_iterator_test_star) { + vector> mat({ + {0, 0, 0, 0, 0, 0, 0}, + {0, 0, 1, 1, 1, 1, 1}, + {0, 1, 0, 0, 1, 0, 0}, + {0, 1, 0, 0, 0, 1, 0}, + {0, 1, 1, 0, 0, 0, 0}, + {0, 1, 0, 1, 0, 0, 1}, + {0, 1, 0, 0, 0, 1, 0}, + }); + TypeParam tree(mat); + auto it = tree.edge_begin(); + + ASSERT_EQ(it.x(), (size_t) 1); + ASSERT_EQ(it.y(), (size_t) 2); + it++; + ASSERT_EQ(it.x(), (size_t) 1); + ASSERT_EQ(it.y(), (size_t) 3); + it++; + ASSERT_EQ(it.x(), (size_t) 2); + ASSERT_EQ(it.y(), (size_t) 1); + it++; + ASSERT_EQ(it.x(), (size_t) 3); + ASSERT_EQ(it.y(), (size_t) 1); + it++; + ASSERT_EQ(it.x(), (size_t) 1); + ASSERT_EQ(it.y(), (size_t) 4); + it++; + ASSERT_EQ(it.x(), (size_t) 1); + ASSERT_EQ(it.y(), (size_t) 5); + it++; + ASSERT_EQ(it.x(), (size_t) 1); + ASSERT_EQ(it.y(), (size_t) 6); + it++; + ASSERT_EQ(it.x(), (size_t) 2); + ASSERT_EQ(it.y(), (size_t) 4); + it++; + ASSERT_EQ(it.x(), (size_t) 3); + ASSERT_EQ(it.y(), (size_t) 5); + it++; + ASSERT_EQ(it.x(), (size_t) 4); + ASSERT_EQ(it.y(), (size_t) 1); + it++; + ASSERT_EQ(it.x(), (size_t) 5); + ASSERT_EQ(it.y(), (size_t) 1); + it++; + ASSERT_EQ(it.x(), (size_t) 4); + ASSERT_EQ(it.y(), (size_t) 2); + it++; + ASSERT_EQ(it.x(), (size_t) 5); + ASSERT_EQ(it.y(), (size_t) 3); + it++; + ASSERT_EQ(it.x(), (size_t) 6); + ASSERT_EQ(it.y(), (size_t) 1); + it++; + ASSERT_EQ(it.x(), (size_t) 5); + ASSERT_EQ(it.y(), (size_t) 6); + it++; + ASSERT_EQ(it.x(), (size_t) 6); + ASSERT_EQ(it.y(), (size_t) 5); +} + + +TYPED_TEST(k2_tree_test_k_2, edge_iterator_test) +{ + //forward iterator + vector> mat({{1, 1, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 1, 0}, + {0, 0, 1, 0}}); + TypeParam tree(mat); + auto edge_iterator = tree.edge_begin(); + ASSERT_EQ(edge_iterator.x(), (size_t)0); + ASSERT_EQ(edge_iterator.y(), (size_t)0); + + // OPERATOR ASSIGNMENT + auto another_edge_iterator = edge_iterator; + ASSERT_FALSE(&another_edge_iterator == &edge_iterator); + ASSERT_EQ(another_edge_iterator.x(), (size_t) 0); + ASSERT_EQ(another_edge_iterator.y(), (size_t) 0); + + // //OPERATOR INCREMENT + // // ++edge_iterator; // also works + edge_iterator++; + ASSERT_EQ(edge_iterator.x(), (size_t) 0); + ASSERT_EQ(edge_iterator.y(), (size_t) 1); + + edge_iterator++; + ASSERT_EQ(edge_iterator.x(), (size_t) 2); + ASSERT_EQ(edge_iterator.y(), (size_t) 2); + edge_iterator++; + ASSERT_EQ(edge_iterator.x(), (size_t) 3); + ASSERT_EQ(edge_iterator.y(), (size_t) 2); + edge_iterator++; + + //find last + auto last = tree.edge_end(); + ASSERT_EQ(last.x(), tree.get_number_nodes()); + ASSERT_EQ(last.y(), tree.get_number_nodes()); + + // OPERATOR EQUALS + ASSERT_TRUE(edge_iterator == tree.edge_end()); + // OPERATOR INEQUALS + ASSERT_TRUE(edge_iterator != tree.edge_begin()); + + //Intensive test + vector> mat2({{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 1, 0, 1, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 0, 0, 1, 0, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 0, 0, 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}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}}); + TypeParam treeIntensive(mat2); + + auto it = treeIntensive.edge_begin(); + + ASSERT_EQ(it.x(), (size_t) 1); + ASSERT_EQ(it.y(), (size_t) 2); + it++; + ASSERT_EQ(it.x(), (size_t) 3); + ASSERT_EQ(it.y(), (size_t) 1); + it++; + ASSERT_EQ(it.x(), (size_t) 1); + ASSERT_EQ(it.y(), (size_t) 4); + it++; + ASSERT_EQ(it.x(), (size_t) 3); + ASSERT_EQ(it.y(), (size_t) 4); + it++; + ASSERT_EQ(it.x(), (size_t) 5); + ASSERT_EQ(it.y(), (size_t) 0); + it++; + ASSERT_EQ(it.x(), (size_t) 5); + ASSERT_EQ(it.y(), (size_t) 1); + it++; + ASSERT_EQ(it.x(), (size_t) 6); + ASSERT_EQ(it.y(), (size_t) 0); + it++; + ASSERT_EQ(it.x(), (size_t) 7); + ASSERT_EQ(it.y(), (size_t) 0); + it++; + ASSERT_EQ(it.x(), (size_t) 3); + ASSERT_EQ(it.y(), (size_t) 9); + it++; + ASSERT_EQ(it.x(), (size_t) 9); + ASSERT_EQ(it.y(), (size_t) 0); + + //OPERATION SWAP + swap(last, another_edge_iterator); + ASSERT_EQ(last.x(), (size_t) 0); + ASSERT_EQ(last.y(), (size_t) 0); + ASSERT_EQ(another_edge_iterator.x(), tree.get_number_nodes()); + ASSERT_EQ(another_edge_iterator.y(), tree.get_number_nodes()); +} + +TYPED_TEST(k2_tree_test_k_2, edge_iterator_test_union) { + vector> mat({{1, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 0, 1, 1}, + {0, 0, 1, 0}}); + + shared_ptr tree_A = make_shared(mat); + + mat = vector>({{0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 1, 0}, + {1, 1, 0, 1}}); + shared_ptr tree_B = make_shared(mat); + + tree_A->unionOp(tree_B); + + auto it = tree_A->edge_begin(); + + ASSERT_EQ(it.x(), (size_t) 0); + ASSERT_EQ(it.y(), (size_t) 0); + it++; + ASSERT_EQ(it.x(), (size_t) 0); + ASSERT_EQ(it.y(), (size_t) 1); + it++; + ASSERT_EQ(it.x(), (size_t) 1); + ASSERT_EQ(it.y(), (size_t) 1); + it++; + ASSERT_EQ(it.x(), (size_t) 3); + ASSERT_EQ(it.y(), (size_t) 0); + it++; + ASSERT_EQ(it.x(), (size_t) 3); + ASSERT_EQ(it.y(), (size_t) 1); + it++; + ASSERT_EQ(it.x(), (size_t) 2); + ASSERT_EQ(it.y(), (size_t) 2); + it++; + ASSERT_EQ(it.x(), (size_t) 2); + ASSERT_EQ(it.y(), (size_t) 3); + it++; + ASSERT_EQ(it.x(), (size_t) 3); + ASSERT_EQ(it.y(), (size_t) 2); + it++; + ASSERT_EQ(it.x(), (size_t) 3); + ASSERT_EQ(it.y(), (size_t) 3); + it++; + ASSERT_EQ(it, tree_A->edge_end()); +} + +TYPED_TEST(k2_tree_test_k_2, node_iterator_test) { + vector> mat({{0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 1, 0}, + {1, 1, 1, 0}}); + TypeParam tree(mat); + auto node_iterator = tree.node_begin(); + ASSERT_EQ(*node_iterator, (size_t)0); + + node_iterator++; + ASSERT_EQ(*node_iterator, (size_t)1); + + node_iterator++; + ASSERT_EQ(*node_iterator, (size_t)2); + + node_iterator++; + ASSERT_EQ(*node_iterator, (size_t)3); + + node_iterator++; + ASSERT_EQ(*node_iterator, *tree.node_end()); + + auto other_iterator = tree.node_begin(); + swap(other_iterator, node_iterator); + ASSERT_EQ(*node_iterator, *tree.node_begin()); + ASSERT_EQ(*other_iterator, *tree.node_end()); +} + +TYPED_TEST(k2_tree_test_k_2, neighbour_iterator_test_empty) { + vector> mat({{0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 1, 0}, + {1, 1, 1, 0}}); + TypeParam tree(mat); +} + +TYPED_TEST(k2_tree_test_k_2, neighbour_iterator_test) { + vector> mat({{0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 1, 0}, + {1, 1, 1, 0}}); + TypeParam tree(mat); + auto neighbour_iterator = tree.neighbour_begin(2); + ASSERT_EQ(*neighbour_iterator, 2); + + neighbour_iterator++; + ASSERT_EQ(*neighbour_iterator, *tree.neighbour_end()); + neighbour_iterator++; + ASSERT_EQ(*neighbour_iterator, *tree.neighbour_end()); + + neighbour_iterator = tree.neighbour_begin(3); + ASSERT_EQ(*neighbour_iterator, 2); + neighbour_iterator++; + ASSERT_EQ(*neighbour_iterator, 1); + neighbour_iterator++; + ASSERT_EQ(*neighbour_iterator, 0); + neighbour_iterator++; + ASSERT_EQ(*neighbour_iterator, *tree.neighbour_end()); + + auto other_iterator = tree.neighbour_begin(2); + swap(other_iterator, neighbour_iterator); + ASSERT_EQ(*neighbour_iterator, *tree.neighbour_begin(2)); + ASSERT_EQ(*other_iterator, *tree.neighbour_end()); + + ASSERT_EQ(*tree.neighbour_begin(0), *tree.neighbour_end()); +} + +TYPED_TEST(k2_tree_test_k_2, neighbour_it_test) { + std::vector expected_x{0,1,2}; + uint i = 0; + + std::function func = [&](uint64_t x) { + ASSERT_EQ(x, expected_x[i]); + ++i; + }; + + vector> mat({{0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 1, 0}, + {1, 1, 1, 0}}); + TypeParam tree(mat); + + tree.neigh_it(3, func); +} + +TYPED_TEST(k2_tree_test_k_2, neighbour_iterator_test_star) { + vector> mat({ + {0, 0, 0, 0, 0, 0, 0}, + {0, 0, 1, 1, 1, 1, 1}, + {0, 1, 0, 0, 1, 0, 0}, + {0, 1, 0, 0, 0, 1, 0}, + {0, 1, 1, 0, 0, 0, 0}, + {0, 1, 0, 1, 0, 0, 1}, + {0, 1, 0, 0, 0, 1, 0}, + }); + TypeParam tree(mat); + auto neighbour_iterator = tree.neighbour_begin(1); + ASSERT_EQ(*neighbour_iterator, 6); + + neighbour_iterator++; + ASSERT_EQ(*neighbour_iterator, 5); + neighbour_iterator++; + ASSERT_EQ(*neighbour_iterator, 4); + neighbour_iterator++; + ASSERT_EQ(*neighbour_iterator, 3); + neighbour_iterator++; + ASSERT_EQ(*neighbour_iterator, 2); +} + +TYPED_TEST(k2_tree_test_k_2, node_iterator_empty) { + TypeParam empty_tree; + ASSERT_EQ(*empty_tree.node_begin(), *empty_tree.node_end()); +} 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} - }); + 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}}); TypeParam tree(mat); + + // cout << "ALGORIOTHM" << endl; + // cout << all_of(tree.l().begin(), tree.l().end(), [](int i) { return i % 2 == 0; }) << endl; + 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, {}, {}); @@ -238,118 +652,164 @@ TYPED_TEST(k2_tree_test_k_3, build_from_matrix_test) mat = vector>({{1}}); tree = TypeParam(mat); - k2_tree_test_nm::check_t_l(tree, {}, {1, 0, 0, 0, 0, 0, 0, 0 ,0}); + 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}); + 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); } - 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}); + 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}); - e.push_back(t_tuple {1, 2}); + e.push_back(t_tuple{1, 2}); tree = TypeParam(e, 3); k2_tree_test_nm::check_t_l(tree, {}, {0, 0, 0, 0, 0, 1, 0, 0, 0}); e.clear(); - e.push_back(t_tuple {0, 0}); + e.push_back(t_tuple{0, 0}); tree = TypeParam(e, 1); k2_tree_test_nm::check_t_l(tree, {}, {1, 0, 0, 0, 0, 0, 0, 0, 0}); - e.push_back(t_tuple {0, 1}); - e.push_back(t_tuple {1, 0}); - e.push_back(t_tuple {1, 1}); + e.push_back(t_tuple{0, 1}); + e.push_back(t_tuple{1, 0}); + e.push_back(t_tuple{1, 1}); tree = TypeParam(e, 2); k2_tree_test_nm::check_t_l(tree, {}, {1, 1, 0, 1, 1, 0, 0, 0, 0}); e.clear(); - e.push_back(t_tuple {2, 2}); + e.push_back(t_tuple{2, 2}); tree = TypeParam(e, 3); k2_tree_test_nm::check_t_l(tree, {}, {0, 0, 0, 0, 0, 0, 0, 0, 1}); } +TYPED_TEST(k2_tree_test_k_3, union_operation_test) +{ + vector> mat({{1, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 0, 1, 1}, + {0, 0, 1, 0}}); + + TypeParam tree_A(mat); + + mat = vector>({{0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 1}}); + shared_ptr tree_B = make_shared(mat); + + tree_A.unionOp(tree_B); + k2_tree_test_nm::check_t_l(tree_A, {1, 1, 0, 1, 1, 0, 0, 0, 0}, {1, 1, 0, 0, 1, 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}); +} + +TYPED_TEST(k2_tree_test_k_3, empty_union_operation) +{ + 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}}); + + 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}; + shared_ptr tree_A = make_shared(mat); + shared_ptr tree_B = make_shared(); + + shared_ptr tree_A_copy = tree_A; + shared_ptr tree_B_copy = tree_B; + + + tree_A_copy->unionOp(tree_B); + k2_tree_test_nm::check_t_l(*tree_A_copy, expected_t, expected_l); + + tree_B_copy->unionOp(tree_A); + k2_tree_test_nm::check_t_l(*tree_B_copy, expected_t, expected_l); + + tree_B->unionOp(tree_B); + k2_tree_test_nm::assert_eq_tree(*tree_B, *tree_B); +} + TYPED_TEST_CASE(k2_tree_test, Implementations); TYPED_TEST(k2_tree_test, edges_array_exhaustive) { typedef std::tuple t_tuple; + typename TypeParam::idx_type> + 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}); + typename TypeParam::idx_type>> + 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); @@ -363,7 +823,8 @@ TYPED_TEST(k2_tree_test, edges_array_exhaustive) expected_neighbors[7] = vector({5}); expected_neighbors[8] = vector({}); expected_neighbors[9] = vector({}); - for (unsigned i = 0; i < 10; i++) { + 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++) @@ -379,35 +840,33 @@ TYPED_TEST(k2_tree_test, edges_array_exhaustive) 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} - }); + vector> mat({{1, 1, 0, 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}); + vector expected_neigh_0({0, 1}); ASSERT_EQ(expected_neigh_0.size(), neigh_0.size()); 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}); + vector expected_neigh_3({2}); ASSERT_EQ(expected_neigh_3.size(), neigh_3.size()); for (unsigned i = 0; i < neigh_3.size(); i++) ASSERT_EQ(expected_neigh_3[i], neigh_3[i]); - mat = vector>({{1}}); + mat = vector>({{1}}); tree = TypeParam(mat); neigh_0 = tree.neigh(0); ASSERT_EQ(0u, neigh_0[0]); ASSERT_EQ(1u, neigh_0.size()); - mat = vector>({{0, 0, 0}, - {1, 0, 1}, - {0, 1, 1} - }); + mat = vector>({{0, 0, 0}, + {1, 0, 1}, + {0, 1, 1}}); tree = TypeParam(mat); neigh_0 = tree.neigh(0); ASSERT_EQ(0u, neigh_0.size()); @@ -418,9 +877,8 @@ TYPED_TEST(k2_tree_test, neighbors_test) for (unsigned i = 0; i < neigh_1.size(); i++) ASSERT_EQ(expected_neigh_1[i], neigh_1[i]); - mat = vector>({{0, 0}, - {0, 0} - }); + mat = vector>({{0, 0}, + {0, 0}}); tree = TypeParam(mat); neigh_0 = tree.neigh(0); ASSERT_EQ(0u, neigh_0.size()); @@ -428,12 +886,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} - }); + 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}}); auto tree = TypeParam(mat); auto r_neigh_0 = tree.reverse_neigh(0); @@ -451,19 +908,16 @@ TYPED_TEST(k2_tree_test, reverse_neighbors_test) 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} - }); + mat = vector>({{0, 0}, + {0, 0}}); tree = TypeParam(mat); r_neigh_0 = tree.reverse_neigh(0); r_neigh_1 = tree.reverse_neigh(1); ASSERT_EQ(0u, r_neigh_0.size()); ASSERT_EQ(0u, r_neigh_1.size()); - - mat = vector>({{0, 1}, - {1, 0} - }); + mat = vector>({{0, 1}, + {1, 0}}); tree = TypeParam(mat); r_neigh_0 = tree.reverse_neigh(0); expected_r_neigh_0 = vector({1}); @@ -481,90 +935,93 @@ TYPED_TEST(k2_tree_test, reverse_neighbors_test) TYPED_TEST(k2_tree_test, range_test) { - static const vector> mat{ - // 0 1 2 3 4 5 6 7 8 9 10 - /* 0*/{0,1,0,0, 0,0,0,0, 0,0,0}, - /* 1*/{0,0,1,1, 1,0,0,0, 0,0,0}, - /* 2*/{0,0,0,0, 0,0,0,0, 0,0,0}, - /* 3*/{0,0,0,0, 0,0,0,0, 0,0,0}, - - /* 4*/{0,0,0,0, 0,0,0,0, 0,0,0}, - /* 5*/{0,0,0,0, 0,0,0,0, 0,0,0}, - /* 6*/{0,0,0,0, 0,0,0,0, 0,0,0}, - /* 7*/{0,0,0,0, 0,0,1,0, 0,0,0}, - - /* 8*/{0,0,0,0, 0,0,1,0, 0,1,0}, - /* 9*/{0,0,0,0, 0,0,1,0, 1,0,1}, - /*10*/{0,0,0,0, 0,0,1,0, 0,1,0}, - }; - TypeParam tree(mat); - - auto result = tree.range(7,9, 5,9); - static const decltype(result) expected{ - {7,6}, - {8,6}, {8,9}, - {9,6}, {9,8} - }; - sort(result.begin(), result.end()); - ASSERT_EQ(expected, result); - - auto all = tree.range(0,10, 0,10); - static const decltype(all) expectedAll{ - {0,1}, - {1,2}, {1,3}, {1,4}, - {7,6}, - {8,6}, {8,9}, - {9,6}, {9,8}, {9,10}, - {10,6},{10,9} - }; - sort(all.begin(), all.end()); - ASSERT_EQ(expectedAll, all); - - auto single = tree.range(1,1, 3,3); - static const decltype(single) expectedSingle{ - {1,3} - }; - ASSERT_EQ(expectedSingle, single); - - auto empty = tree.range(0,6, 5,10); - static const decltype(empty) expectedEmpty{}; - ASSERT_EQ(expectedEmpty, empty); + static const vector> mat{ + // 0 1 2 3 4 5 6 7 8 9 10 + /* 0*/ {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* 1*/ {0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0}, + /* 2*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* 3*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + + /* 4*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* 5*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* 6*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* 7*/ {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, + + /* 8*/ {0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0}, + /* 9*/ {0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1}, + /*10*/ {0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0}, + }; + TypeParam tree(mat); + + auto result = tree.range(7, 9, 5, 9); + static const decltype(result) expected{ + {7, 6}, + {8, 6}, + {8, 9}, + {9, 6}, + {9, 8}}; + sort(result.begin(), result.end()); + ASSERT_EQ(expected, result); + + auto all = tree.range(0, 10, 0, 10); + static const decltype(all) expectedAll{ + {0, 1}, + {1, 2}, + {1, 3}, + {1, 4}, + {7, 6}, + {8, 6}, + {8, 9}, + {9, 6}, + {9, 8}, + {9, 10}, + {10, 6}, + {10, 9}}; + sort(all.begin(), all.end()); + ASSERT_EQ(expectedAll, all); + + auto single = tree.range(1, 1, 3, 3); + static const decltype(single) expectedSingle{ + {1, 3}}; + ASSERT_EQ(expectedSingle, single); + + auto empty = tree.range(0, 6, 5, 10); + static const decltype(empty) expectedEmpty{}; + ASSERT_EQ(expectedEmpty, empty); } 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} - }); + 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}}); auto tree = TypeParam(mat); - ASSERT_TRUE(tree.adj(0, 0)); - ASSERT_TRUE(tree.adj(0, 4)); - ASSERT_FALSE(tree.adj(4, 0)); - ASSERT_TRUE(tree.adj(4, 4)); - ASSERT_FALSE(tree.adj(1, 1)); - ASSERT_TRUE(tree.adj(2, 2)); - ASSERT_TRUE(tree.adj(2, 3)); - - mat = vector>({{0}}); + ASSERT_TRUE(tree.contains(0, 0)); + ASSERT_TRUE(tree.contains(0, 4)); + ASSERT_FALSE(tree.contains(4, 0)); + ASSERT_TRUE(tree.contains(4, 4)); + ASSERT_FALSE(tree.contains(1, 1)); + ASSERT_TRUE(tree.contains(2, 2)); + ASSERT_TRUE(tree.contains(2, 3)); + + mat = vector>({{0}}); tree = TypeParam(mat); - ASSERT_FALSE(tree.adj(0,0)); - mat = vector>({{1}}); + ASSERT_FALSE(tree.contains(0, 0)); + mat = vector>({{1}}); tree = TypeParam(mat); - ASSERT_TRUE(tree.adj(0,0)); + ASSERT_TRUE(tree.contains(0, 0)); } 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} - }); + 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}}); auto tree = TypeParam(mat); k2_tree_test_nm::check_serialize_load(tree); @@ -577,22 +1034,80 @@ TYPED_TEST(k2_tree_test, serialize_test) k2_tree_test_nm::check_serialize_load(tree); mat = vector>({{0, 0}, - {0, 0} - }); + {0, 0}}); tree = TypeParam(mat); k2_tree_test_nm::check_serialize_load(tree); mat = vector>({{1, 1}, - {1, 1} - }); + {1, 1}}); tree = TypeParam(mat); k2_tree_test_nm::check_serialize_load(tree); +} + +TYPED_TEST_CASE(k2_tree_test_marked, Implementations_bit_vector); +TYPED_TEST(k2_tree_test_marked, marked_edges) +{ + 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}}); + auto tree = TypeParam(mat); + + ASSERT_EQ(tree.get_marked_edges(), (uint64_t)0); + ASSERT_EQ(tree.get_number_edges(), 6); + ASSERT_EQ(tree.total_edges(), (uint64_t)6); + + ASSERT_TRUE(tree.erase(0, 0)); + ASSERT_EQ(tree.get_marked_edges(), (uint64_t)1); + ASSERT_EQ(tree.get_number_edges(), 5); + + ASSERT_TRUE(tree.erase(0, 4)); + ASSERT_EQ(tree.get_marked_edges(), (uint64_t)2); + ASSERT_EQ(tree.get_number_edges(), 4); + + ASSERT_FALSE(tree.erase(0, 4)); + ASSERT_EQ(tree.get_marked_edges(), (uint64_t)2); + ASSERT_EQ(tree.get_number_edges(), 4); + + ASSERT_FALSE(tree.erase(1, 2)); + ASSERT_EQ(tree.get_marked_edges(), (uint64_t)2); + ASSERT_EQ(tree.get_number_edges(), 4); + + ASSERT_TRUE(tree.erase(2, 2)); + ASSERT_EQ(tree.get_marked_edges(), (uint64_t)3); + ASSERT_EQ(tree.get_number_edges(), 3); + + ASSERT_TRUE(tree.erase(2, 3)); + ASSERT_EQ(tree.get_marked_edges(), (uint64_t)4); + ASSERT_EQ(tree.get_number_edges(), 2); + + ASSERT_TRUE(tree.erase(4, 2)); + ASSERT_EQ(tree.get_marked_edges(), (uint64_t)5); + ASSERT_EQ(tree.get_number_edges(), 1); + + ASSERT_TRUE(tree.erase(4, 4)); + ASSERT_EQ(tree.get_marked_edges(), (uint64_t)6); + ASSERT_EQ(tree.get_number_edges(), 0); + +} + +TYPED_TEST(k2_tree_test_marked, edge_it) { + 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}}); + + auto tree = TypeParam(mat); + TypeParam t = tree; + tree.edge_it([t] (uint64_t i, uint64_t j)-> void { ASSERT_TRUE(t.adj(i,j)); }); } -} // namespace +} // namespace -int main(int argc, char** argv) +int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv);