diff --git a/examples/k2_treap_in_mem.cpp b/examples/k2_treap_in_mem.cpp new file mode 100644 index 000000000..7a913b6ac --- /dev/null +++ b/examples/k2_treap_in_mem.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include + +using namespace sdsl; +using namespace std; + +int main() +{ + typedef k2_treap<3,rrr_vector<63>> k2_rrr; + k2_rrr k2treap; + + // Initialize treap with a vector of (x,y,weight) elements + construct_im(k2treap, {{1,2,3},{2,2,6},{4,4,1},{3,3,2},{3,1,8}}); + + cout << "Points in the k2treap: " << k2treap.size() << endl; + + cout << "Points in the rectangle from (2,1) to (3,3): " ; + cout << count(k2treap, {2,1}, {3,3}) << endl; + + cout << "Heaviest points in rectangle from (0,0) to (2,8):" << endl; + auto topk_it = top_k(k2treap, {0,0}, {2,8}); + while (topk_it) { + auto point_weight = *topk_it; + cout << point_weight.first <<" weight: "< m_data; // block data for every level bit_vector m_overflow; // mark non-end bytes rank_support_type m_overflow_rank; // rank for m_overflow - int_vector<64> m_level_pointer_and_rank; + int_vector<64> m_level_pointer_and_rank = int_vector<64>(4,0); uint8_t m_max_level; // maximum level < (log n)/b+1 - void copy(const dac_vector& v) { + void copy(const dac_vector& v) + { m_data = v.m_data; m_overflow = v.m_overflow; m_overflow_rank = v.m_overflow_rank; @@ -91,25 +92,27 @@ class dac_vector } public: - dac_vector() { - m_level_pointer_and_rank = int_vector<64>(4,0); - } + dac_vector() = default; - dac_vector(const dac_vector& v) { + dac_vector(const dac_vector& v) + { copy(v); } - dac_vector(dac_vector&& v) { + dac_vector(dac_vector&& v) + { *this = std::move(v); } - dac_vector& operator=(const dac_vector& v) { + dac_vector& operator=(const dac_vector& v) + { if (this != &v) { copy(v); } return *this; } - dac_vector& operator=(dac_vector&& v) { + dac_vector& operator=(dac_vector&& v) + { if (this != &v) { m_data = std::move(v.m_data); m_overflow = std::move(v.m_overflow); @@ -133,21 +136,25 @@ class dac_vector dac_vector(int_vector_buffer& v_buf); //! The number of elements in the dac_vector. - size_type size()const { + size_type size()const + { return m_level_pointer_and_rank[2]; } //! Return the largest size that this container can ever have. - static size_type max_size() { + static size_type max_size() + { return int_vector<>::max_size()/2; } //! Returns if the dac_vector is empty. - bool empty() const { + bool empty() const + { return 0 == m_level_pointer_and_rank[2]; } //! Swap method for dac_vector - void swap(dac_vector& v) { + void swap(dac_vector& v) + { m_data.swap(v.m_data); m_overflow.swap(v.m_overflow); util::swap_support(m_overflow_rank, v.m_overflow_rank, @@ -158,18 +165,21 @@ class dac_vector } //! Iterator that points to the first element of the dac_vector. - const const_iterator begin()const { + const const_iterator begin()const + { return const_iterator(this, 0); } //! Iterator that points to the position after the last element of the dac_vector. - const const_iterator end()const { + const const_iterator end()const + { return const_iterator(this, size()); } //! []-operator - value_type operator[](size_type i)const { + value_type operator[](size_type i)const + { uint8_t level = 1; uint8_t offset = t_b; size_type result = m_data[i]; @@ -189,7 +199,8 @@ class dac_vector size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const; //! Load from a stream. - void load(std::istream& in) { + void load(std::istream& in) + { m_data.load(in); m_overflow.load(in); m_overflow_rank.load(in, &m_overflow); @@ -209,13 +220,11 @@ dac_vector::dac_vector(const Container& c) if (n == 0) return; // initialize counter - auto _size = std::max(4*bits::hi(2), 2*(((bits::hi(n)+1)+t_b-1) / t_b)); - m_level_pointer_and_rank.resize(_size); - for (size_type i=0; i < m_level_pointer_and_rank.size(); ++i) - m_level_pointer_and_rank[i] = 0; + m_level_pointer_and_rank = int_vector<64>(128, 0); m_level_pointer_and_rank[0] = n; // level 0 has n entries uint8_t level_x_2 = 0; + uint8_t max_level_x_2 = 4; for (size_type i=0; i < n; ++i) { val=c[i]; val >>= t_b; // shift value b bits to the right @@ -225,8 +234,10 @@ dac_vector::dac_vector(const Container& c) ++m_level_pointer_and_rank[level_x_2]; val >>= t_b; // shift value b bits to the right level_x_2 += 2; // increase level by 1 + max_level_x_2 = std::max(max_level_x_2, level_x_2); } } + m_level_pointer_and_rank.resize(max_level_x_2); // (2) Determine maximum level and prefix sums of level counters m_max_level = 0; size_type sum_blocks = 0, last_block_size=0; @@ -286,13 +297,11 @@ dac_vector::dac_vector(int_vector_buffer& v_buf) if (n == 0) return; // initialize counter - auto _size = std::max(4*bits::hi(2), 2*(((bits::hi(n)+1)+t_b-1) / t_b)); - m_level_pointer_and_rank.resize(_size); - for (size_type i=0; i < m_level_pointer_and_rank.size(); ++i) - m_level_pointer_and_rank[i] = 0; + m_level_pointer_and_rank = int_vector<64>(128, 0); m_level_pointer_and_rank[0] = n; // level 0 has n entries uint8_t level_x_2 = 0; + uint8_t max_level_x_2 = 4; for (size_type i=0; i < n; ++i) { val=v_buf[i]; val >>= t_b; // shift value b bits to the right @@ -302,8 +311,10 @@ dac_vector::dac_vector(int_vector_buffer& v_buf) ++m_level_pointer_and_rank[level_x_2]; val >>= t_b; // shift value b bits to the right level_x_2 += 2; // increase level by 1 + max_level_x_2 = std::max(max_level_x_2, level_x_2); } } + m_level_pointer_and_rank.resize(max_level_x_2); // (2) Determine maximum level and prefix sums of level counters m_max_level = 0; size_type sum_blocks = 0, last_block_size=0; diff --git a/include/sdsl/k2_treap.hpp b/include/sdsl/k2_treap.hpp new file mode 100644 index 000000000..111cefc8a --- /dev/null +++ b/include/sdsl/k2_treap.hpp @@ -0,0 +1,447 @@ +/* sdsl - succinct data structures library + Copyright (C) 2014 Simon Gog + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/ . +*/ +/*! \file k2_treap.hpp + \brief k2_treap.hpp contains a compact k^2-treap. + \author Simon Gog +*/ +#ifndef INCLUDED_SDSL_K2_TREAP +#define INCLUDED_SDSL_K2_TREAP + +#include "sdsl/vectors.hpp" +#include "sdsl/bits.hpp" +#include "sdsl/k2_treap_helper.hpp" +#include "sdsl/k2_treap_algorithm.hpp" +#include +#include +#include +#include + +//! Namespace for the succinct data structure library. +namespace sdsl +{ + +//! A k^2-treap. +/*! A k^2-treap is an indexing structure for a set of weighted points. The set + * consists of triples (x,y,w), where the first two components x and y are + * the coordinates of the point and w is the point's weight. + * + * The k^2 treap supports 4-sided range count queries and 4-sided prioritized + * range queries in 2d. Using the latter functionality it is also possible to + * support 6-sided range queries in 3d. An example can be found in + * examples/k2_treap_in_mem.cpp . + * + * The k^2-treap constructed in-place. The construct method expects either + * a vector of std::array elements (each array represent a tuple x,y,w) + * or a file prefix FILE. In the latter case three serialized int_vector<> + * have to be present at FILE.x, FILE.y, and FILE.w. One int_vector<> per + * component. + * + * \par References + * [1] N. Brisaboa, G. de Bernardo, R. Konow, and G. Navarro: + * ,,$K^2$-Treaps: Range Top-$k$ Queries in Compact Space, + * Proceedings of SPIRE 2014. + */ +template> +class k2_treap +{ + static_assert(t_k>1, "t_k has to be larger than 1."); + static_assert(t_k<=16, "t_k has to be smaller than 17."); + + public: + typedef int_vector<>::size_type size_type; + using node_type = k2_treap_ns::node_type; + using point_type = k2_treap_ns::point_type; + using t_p = k2_treap_ns::t_p; + + enum { k = t_k }; + + private: + uint8_t m_t = 0; + t_bv m_bp; + t_rank m_bp_rank; + t_max_vec m_maxval; + std::vector> m_coord; + int_vector<64> m_level_idx; + + template + uint8_t get_t(const t_tv& v) + { + using namespace k2_treap_ns; + if (v.size() == 0) { + return 0; + } + using t_e = typename t_tv::value_type; + auto tupmax = [](t_e a) { + return std::max(std::get<0>(a),std::get<1>(a)); + }; + auto max_it = std::max_element(std::begin(v), std::end(v), [&](t_e a, t_e b) { + return tupmax(a) < tupmax(b); + }); + uint64_t x = tupmax(*max_it); + uint8_t res = 0; + while (precomp::exp(res) <= x) { ++res; } + return res; + } + + public: + uint8_t& t = m_t; + + k2_treap() = default; + + k2_treap(const k2_treap& tr) + { + *this = tr; + } + + k2_treap(k2_treap&& tr) + { + *this = std::move(tr); + } + + //! Move assignment operator + k2_treap& operator=(k2_treap&& tr) + { + if (this != &tr) { + m_t = tr.m_t; + m_bp = std::move(tr.m_bp); + m_bp_rank = std::move(tr.m_bp_rank); + m_bp_rank.set_vector(&m_bp); + m_maxval = std::move(tr.m_maxval); + m_coord = std::move(tr.m_coord); + m_level_idx = std::move(tr.m_level_idx); + } + return *this; + } + + //! Assignment operator + k2_treap& operator=(k2_treap& tr) + { + if (this != &tr) { + m_t = tr.m_t; + m_bp = tr.m_bp; + m_bp_rank = tr.m_bp_rank; + m_bp_rank.set_vector(&m_bp); + m_maxval = tr.m_maxval; + m_coord = tr.m_coord; + m_level_idx = tr.m_level_idx; + } + return *this; + } + + //! Number of points in the 2^k treap + size_type + size() const + { + return m_maxval.size(); + } + + //! Swap operator + void swap(k2_treap& tr) + { + if (this != &tr) { + std::swap(m_t, tr.m_t); + m_bp.swap(tr.m_bp); + util::swap_support(m_bp_rank, tr.m_bp_rank, &m_bp, &(tr.m_bp)); + m_maxval.swap(tr.m_maxval); + m_coord.swap(tr.m_coord); + m_level_idx.swap(tr.m_level_idx); + } + } + + k2_treap(int_vector_buffer<>& buf_x, + int_vector_buffer<>& buf_y, + int_vector_buffer<>& buf_w) + { + using namespace k2_treap_ns; + typedef int_vector_buffer<>* t_buf_p; + std::vector bufs = {&buf_x, &buf_y, &buf_w}; + + auto max_element = [](int_vector_buffer<>& buf) { + uint64_t max_val = 0; + for (auto val : buf) { + max_val = std::max((uint64_t)val, max_val); + } + return max_val; + }; + + auto max_buf_element = [&]() { + uint64_t max_v = 0; + for (auto buf : bufs) { + uint64_t _max_v = max_element(*buf); + max_v = std::max(max_v, _max_v); + } + return max_v; + }; + + uint64_t x = max_buf_element(); + uint8_t res = 0; + while (res <= 64 and precomp::exp(res) <= x) { ++res; } + if (res == 65) { + throw std::logic_error("Maximal element of input is too big."); + } + + if (precomp::exp(res) <= std::numeric_limits::max()) { + auto v = read(bufs); + construct(v, buf_x.filename()); + } else { + auto v = read(bufs); + construct(v, buf_x.filename()); + } + } + + template + std::vector> + read(std::vector*>& bufs) + { + typedef std::vector> t_tuple_vec; + t_tuple_vec v = t_tuple_vec(bufs[0]->size()); + for (uint64_t j=0; j(v[j]) = (*(bufs[0]))[j]; + } + for (uint64_t j=0; j(v[j]) = (*(bufs[1]))[j]; + } + for (uint64_t j=0; j(v[j]) = (*(bufs[2]))[j]; + } + return v; + } + + + template + k2_treap(std::vector>& v, std::string temp_file_prefix="") + { + if (v.size() > 0) { + construct(v, temp_file_prefix); + } + } + + template + void construct(std::vector>& v, std::string temp_file_prefix="") + { + using namespace k2_treap_ns; + using t_e = std::tuple; + m_t = get_t(v); + uint64_t M = precomp::exp(t); + t_e MM = t_e(M,M,M); + + std::string id_part = util::to_string(util::pid()) + + "_" + util::to_string(util::id()); + + m_coord.resize(t); + m_level_idx = int_vector<64>(1+t, 0); + + std::string val_file = temp_file_prefix + "_k2_treap_" + + id_part + ".sdsl"; + std::string bp_file = temp_file_prefix + "_bp_" + id_part + + ".sdsl"; + + { + int_vector_buffer<> val_buf(val_file, std::ios::out); + int_vector_buffer<1> bp_buf(bp_file, std::ios::out); + + auto end = std::end(v); + uint64_t last_level_nodes = 1; + uint64_t level_nodes; + for (uint64_t l=t, cc=0; l+1 > 0; --l) { + if (l > 0) { + m_level_idx[l-1] = m_level_idx[l] + last_level_nodes; + m_coord[l-1] = int_vector<>(2*last_level_nodes,0, bits::hi(precomp::exp(l))+1); + } + level_nodes = 0; + cc = 0; + auto sp = std::begin(v); + for (auto ep = sp; ep != end;) { + ep = std::find_if(sp, end, [&sp,&l](const t_e& e) { + auto x1 = std::get<0>(*sp); + auto y1 = std::get<1>(*sp); + auto x2 = std::get<0>(e); + auto y2 = std::get<1>(e); + return precomp::divexp(x1,l) != precomp::divexp(x2,l) + or precomp::divexp(y1,l) != precomp::divexp(y2,l); + }); + auto max_it = std::max_element(sp, ep, [](t_e a, t_e b) { + if (std::get<2>(a) != std::get<2>(b)) + return std::get<2>(a) < std::get<2>(b); + else if (std::get<0>(a) != std::get<0>(b)) + return std::get<0>(a) > std::get<0>(b); + return std::get<1>(a) > std::get<1>(b); + }); + if (l > 0) { + m_coord[l-1][2*cc] = precomp::modexp(std::get<0>(*max_it), l); + m_coord[l-1][2*cc+1] = precomp::modexp(std::get<1>(*max_it), l); + ++cc; + } + + val_buf.push_back(std::get<2>(*max_it)); + *max_it = MM; + --ep; + std::swap(*max_it, *ep); + if (l > 0) { + auto _sp = sp; + + for (uint8_t i=0; i < t_k; ++i) { + auto _ep = ep; + if (i+1 < t_k) { + _ep = std::partition(_sp, ep, [&i,&l](const t_e& e) { + return precomp::divexp(std::get<0>(e),l-1)%t_k <= i; + }); + } + auto __sp = _sp; + for (uint8_t j=0; j < t_k; ++j) { + auto __ep = _ep; + if (j+1 < t_k) { + __ep = std::partition(__sp, _ep, [&j,&l](const t_e& e) { + return precomp::divexp(std::get<1>(e),l-1)%t_k <= j; + }); + } + bool not_empty = __ep > __sp; + bp_buf.push_back(not_empty); + level_nodes += not_empty; + __sp = __ep; + } + _sp = _ep; + } + } + ++ep; + sp = ep; + } + end = std::remove_if(begin(v), end, [&](t_e e) { + return e == MM; + }); + last_level_nodes = level_nodes; + } + } + bit_vector bp; + load_from_file(bp, bp_file); + { + int_vector_buffer<> val_rw(val_file, std::ios::in | std::ios::out); + int_vector_buffer<> val_r(val_file, std::ios::in); + uint64_t bp_idx = bp.size(); + uint64_t r_idx = m_level_idx[0]; + uint64_t rw_idx = val_rw.size(); + while (bp_idx > 0) { + --r_idx; + for (size_t i=0; i < t_k*t_k; ++i) { + if (bp[--bp_idx]) { + --rw_idx; + val_rw[rw_idx] = val_r[r_idx] - val_rw[rw_idx]; + } + } + } + } + { + int_vector_buffer<> val_r(val_file); + m_maxval = t_max_vec(val_r); + } + { + bit_vector _bp; + _bp.swap(bp); + m_bp = t_bv(_bp); + } + util::init_support(m_bp_rank, &m_bp); + sdsl::remove(bp_file); + sdsl::remove(val_file); + } + + + //! Serializes the data structure into the given ostream + 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 += write_member(m_t, out, child, "t"); + written_bytes += m_bp.serialize(out, child, "bp"); + written_bytes += m_bp_rank.serialize(out, child, "bp_rank"); + written_bytes += serialize_vector(m_coord, out, child, "coord"); + written_bytes += m_maxval.serialize(out, child, "maxval"); + written_bytes += m_level_idx.serialize(out, child, "level_idx"); + structure_tree::add_size(child, written_bytes); + return written_bytes; + } + + //! Loads the data structure from the given istream. + void load(std::istream& in) + { + read_member(m_t, in); + m_bp.load(in); + m_bp_rank.load(in); + m_bp_rank.set_vector(&m_bp); + m_coord.resize(t); + load_vector(m_coord, in); + m_maxval.load(in); + m_level_idx.load(in); + } + + node_type + root() const + { + return node_type(t, t_p(0,0), 0, m_maxval[0], + t_p(m_coord[t-1][0], m_coord[t-1][1])); + } + + bool + is_leaf(const node_type& v) const + { + return v.idx >= m_bp.size(); + } + + std::vector + children(const node_type& v) const + { + using namespace k2_treap_ns; + std::vector res; + if (!is_leaf(v)) { + uint64_t rank = m_bp_rank(v.idx); + auto x = std::real(v.p); + auto y = std::imag(v.p); + + for (size_t i=0; i::exp(v.t-1); + auto _y = y + j*precomp::exp(v.t-1); + + auto _max_v = v.max_v - m_maxval[rank]; + auto _max_p = t_p(_x, _y); + if (v.t > 1) { + auto y = rank-m_level_idx[v.t-1]; + _max_p = t_p(_x+m_coord[v.t-2][2*y], + _y+m_coord[v.t-2][2*y+1]); + } + res.emplace_back(v.t-1, t_p(_x,_y), rank*t_k*t_k, + _max_v, _max_p); + } + } + } + } + return res; + } + +}; + +} +#endif diff --git a/include/sdsl/k2_treap_algorithm.hpp b/include/sdsl/k2_treap_algorithm.hpp new file mode 100644 index 000000000..89a43dd26 --- /dev/null +++ b/include/sdsl/k2_treap_algorithm.hpp @@ -0,0 +1,412 @@ +/* sdsl - succinct data structures library + Copyright (C) 2014 Simon Gog + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/ . +*/ +/*! \file k2_treap_algorithm.hpp + \brief k2_treap_algorithm.hpp contains k^2-treap algorithms. + \author Simon Gog +*/ +#ifndef INCLUDED_SDSL_K2_TREAP_ALGORITHM +#define INCLUDED_SDSL_K2_TREAP_ALGORITHM + +#include "sdsl/vectors.hpp" +#include "sdsl/bits.hpp" +#include "sdsl/k2_treap_helper.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +//! Namespace for the succinct data structure library. +namespace sdsl +{ + +namespace k2_treap_ns +{ + +//! Check if point x is contained in the rectangle (p1,p2) +/*! \param p Point. + * \param Lower left corner of the rectangle. + * \param Upper right corner of the rectangle. + */ +bool +contained(const point_type p, const point_type& p1, const point_type& p2) +{ + return real(p) >= real(p1) and real(p) <= real(p2) and + imag(p) >= imag(p1) and imag(p) <= imag(p2); +} + +//! Check if the rectangle of node v is contained in the rectangle (p1,p2) +template +bool +contained(const point_type& p1, const point_type& p2, const node_type& v) +{ +// uint64_t d = (1ULL << v.t)-1; +// uint64_t d = (1ULL << v.t)-1; + uint64_t d = precomp::exp(v.t)-1; + return real(p1) <= real(v.p) and real(p2) >= real(v.p) + d and + imag(p1) <= imag(v.p) and imag(p2) >= imag(v.p) + d; +} + +//! Check if rectangle (p1,p2) and the area of node v overlap +template +bool +overlap(const point_type& p1, const point_type& p2, const node_type& v) +{ +// uint64_t d = (1ULL << v.t)-1; + uint64_t d = precomp::exp(v.t)-1; + return real(p1) <= real(v.p) + d and real(p2) >= real(v.p) and + imag(p1) <= imag(v.p) + d and imag(p2) >= imag(v.p); +} + +template +class top_k_iterator +{ + public: + typedef void(*t_mfptr)(); + typedef std::pair t_point_val; + + private: + typedef k2_treap_ns::node_type node_type; + typedef std::pair t_nt_b; + + const t_k2_treap* m_treap = nullptr; + std::priority_queue m_pq; + t_point_val m_point_val; + point_type m_p1; + point_type m_p2; + bool m_valid = false; + + public: + top_k_iterator() = default; + top_k_iterator(const top_k_iterator&) = default; + top_k_iterator(top_k_iterator&&) = default; + top_k_iterator& operator=(const top_k_iterator&) = default; + top_k_iterator& operator=(top_k_iterator&&) = default; + top_k_iterator(const t_k2_treap& treap, point_type p1, point_type p2) : + m_treap(&treap), m_p1(p1), m_p2(p2), m_valid(treap.size()>0) + { + if (m_treap->size() > 0) { + m_pq.emplace(m_treap->root(),false); + ++(*this); + } + } + + //! Prefix increment of the iterator + top_k_iterator& operator++() + { + m_valid = false; + while (!m_pq.empty()) { + auto v = std::get<0>(m_pq.top()); + auto is_contained = std::get<1>(m_pq.top()); + m_pq.pop(); + if (is_contained) { + auto nodes = m_treap->children(v); + for (auto node : nodes) + m_pq.emplace(node, true); + m_point_val = t_point_val(v.max_p, v.max_v); + m_valid = true; + break; + } else { + if (contained(m_p1, m_p2, v)) { + m_pq.emplace(v, true); + } else if (overlap(m_p1, m_p2, v)) { + auto nodes = m_treap->children(v); + for (auto node : nodes) + m_pq.emplace(node, false); + if (contained(v.max_p, m_p1, m_p2)) { + m_point_val = t_point_val(v.max_p, v.max_v); + m_valid = true; + break; + } + } + } + } + return *this; + } + + //! Postfix increment of the iterator + top_k_iterator operator++(int) + { + top_k_iterator it = *this; + ++(*this); + return it; + } + + t_point_val operator*() const + { + return m_point_val; + } + + //! Cast to a member function pointer + // Test if there are more elements + // Can be casted to bool but not implicit in an arithmetic experession + // See Alexander C.'s comment on + // http://stackoverflow.com/questions/835590/how-would-stdostringstream-convert-to-bool + operator t_mfptr() const + { + return (t_mfptr)(m_valid); + } +}; + +template +class range_iterator +{ + public: + typedef void(*t_mfptr)(); + typedef std::pair t_point_val; + + private: + typedef k2_treap_ns::node_type node_type; + typedef std::pair t_nt_b; + + const t_k2_treap* m_treap = nullptr; + std::priority_queue m_pq; + t_point_val m_point_val; + point_type m_p1; + point_type m_p2; + range_type m_r; + bool m_valid = false; + + void pq_emplace(node_type v, bool b) + { + if (v.max_v >= real(m_r)) { + m_pq.emplace(v, b); + } + } + + public: + range_iterator() = default; + range_iterator(const range_iterator&) = default; + range_iterator(range_iterator&&) = default; + range_iterator& operator=(const range_iterator&) = default; + range_iterator& operator=(range_iterator&&) = default; + range_iterator(const t_k2_treap& treap, point_type p1, point_type p2, range_type range) : + m_treap(&treap), m_p1(p1), m_p2(p2), m_r(range), m_valid(treap.size()>0) + { + if (m_treap->size() >0) { + pq_emplace(m_treap->root(), false); + ++(*this); + } + } + + //! Prefix increment of the iterator + range_iterator& operator++() + { + m_valid = false; + while (!m_pq.empty()) { + auto v = std::get<0>(m_pq.top()); + auto is_contained = std::get<1>(m_pq.top()); + m_pq.pop(); + if (is_contained) { + auto nodes = m_treap->children(v); + for (auto node : nodes) + pq_emplace(node, true); + if (v.max_v <= imag(m_r)) { + m_point_val = t_point_val(v.max_p, v.max_v); + m_valid = true; + break; + } + } else { + if (contained(m_p1, m_p2, v)) { + m_pq.emplace(v, true); + } else if (overlap(m_p1, m_p2, v)) { + auto nodes = m_treap->children(v); + for (auto node : nodes) + pq_emplace(node, false); + if (contained(v.max_p, m_p1, m_p2) and v.max_v <= imag(m_r)) { + m_point_val = t_point_val(v.max_p, v.max_v); + m_valid = true; + break; + } + } + } + } + return *this; + } + + //! Postfix increment of the iterator + range_iterator operator++(int) + { + range_iterator it = *this; + ++(*this); + return it; + } + + t_point_val operator*() const + { + return m_point_val; + } + + //! Cast to a member function pointer + // Test if there are more elements + operator t_mfptr() const + { + return (t_mfptr)(m_valid); + } +}; + +} // end namespace k2_treap_ns + +//! Get iterator for all heaviest points in rectangle (p1,p2) in decreasing order +/*! \param treap k2-treap + * \param p1 Lower left corner of the rectangle + * \param p2 Upper right corner of the rectangle + * \return Iterator to result in decreasing order. + * \pre real(p1) <= real(p2) and imag(p1)<=imag(p2) + */ +template +k2_treap_ns::top_k_iterator +top_k(const t_k2_treap& t, + k2_treap_ns::point_type p1, + k2_treap_ns::point_type p2) +{ + return k2_treap_ns::top_k_iterator(t, p1, p2); +} + + +//! Get iterator for all points in rectangle (p1,p2) with weights in range +/*! \param treap k2-treap + * \param p1 Lower left corner of the rectangle + * \param p2 Upper right corner of the rectangle + * \param range Range {w1,w2}. + * \return Iterator to list of all points in the range. + * \pre real(p1) <= real(p2) and imag(p1)<=imag(p2) + * real(range) <= imag(range) + */ +template +k2_treap_ns::range_iterator +range_3d(const t_k2_treap& t, + k2_treap_ns::point_type p1, + k2_treap_ns::point_type p2, + k2_treap_ns::range_type range) +{ + return k2_treap_ns::range_iterator(t, p1, p2, range); +} + + +// forward declaration +template +uint64_t __count(const t_k2_treap&, typename t_k2_treap::node_type); + +// forward declaration +template +uint64_t _count(const t_k2_treap&, k2_treap_ns::point_type, + k2_treap_ns::point_type, typename t_k2_treap::node_type); + +//! Count how many points are in the rectangle (p1,p2) +/*! \param treap k2-treap + * \param p1 Lower left corner of the rectangle. + * \param p2 Upper right corner of the rectangle. + * \return The number of points in rectangle (p1,p2). + * \pre real(p1) <= real(p2) and imag(p1)<=imag(p2) + */ +template +uint64_t +count(const t_k2_treap& treap, + k2_treap_ns::point_type p1, + k2_treap_ns::point_type p2) +{ + if (treap.size() > 0) { + return _count(treap, p1, p2, treap.root()); + } + return 0; +} + + +template +uint64_t +_count(const t_k2_treap& treap, + k2_treap_ns::point_type p1, + k2_treap_ns::point_type p2, + typename t_k2_treap::node_type v) +{ + using namespace k2_treap_ns; + if (contained(p1, p2, v)) { + return __count(treap, v); + } else if (overlap(p1, p2, v)) { + uint64_t res = contained(v.max_p, p1, p2); + auto nodes = treap.children(v); + for (auto node : nodes) { + res += _count(treap, p1, p2, node); + } + return res; + } + return 0; +} + + +template +uint64_t +__count(const t_k2_treap& treap, + typename t_k2_treap::node_type v) +{ + uint64_t res = 1; // count the point at the node + auto nodes = treap.children(v); + for (auto node : nodes) + res += __count(treap, node); + return res; +} + + +// forward declaration +template +class k2_treap; + + +//! Specialized version of method ,,construct'' for k2_treaps. +template +void +construct(k2_treap& idx, std::string file) +{ + int_vector_buffer<> buf_x(file+".x", std::ios::in); + int_vector_buffer<> buf_y(file+".y", std::ios::in); + int_vector_buffer<> buf_w(file+".w", std::ios::in); + k2_treap tmp(buf_x, buf_y, buf_w); + tmp.swap(idx); +} + +//! Specialized version of method ,,construct_im'' for k2_treaps. +template +void +construct_im(k2_treap& idx, std::vector> data) +{ + std::string tmp_prefix = ram_file_name("k2_treap_"); + std::vector> d; + for (auto x : data) { + d.push_back(std::make_tuple(x[0],x[1],x[2])); + } + k2_treap tmp(d, tmp_prefix); + tmp.swap(idx); +} + + + +} +#endif diff --git a/include/sdsl/k2_treap_helper.hpp b/include/sdsl/k2_treap_helper.hpp new file mode 100644 index 000000000..40ca5f382 --- /dev/null +++ b/include/sdsl/k2_treap_helper.hpp @@ -0,0 +1,185 @@ +/* sdsl - succinct data structures library + Copyright (C) 2014 Simon Gog + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/ . +*/ +/*! \file k2_treap_helper.hpp + \brief k2_treap_helper.hpp contains helper functions and definitions for a k^2-treap implementation. + \author Simon Gog +*/ +#ifndef INCLUDED_SDSL_K2_TREAP_HELPER +#define INCLUDED_SDSL_K2_TREAP_HELPER + +#include "sdsl/vectors.hpp" +#include "sdsl/bits.hpp" +#include +#include +#include +#include +#include +#include +#include + +//! Namespace for the succinct data structure library. +namespace sdsl +{ + +namespace k2_treap_ns +{ + +// Precomputed value for fast k^2 treap operations +template +struct precomp { + static struct impl { + uint64_t exp[65]; + impl() + { + exp[0] = 1; + for (uint8_t i=1; i<65; ++i) { + exp[i] = t_k * exp[i-1]; + } + } + } data; + + static uint64_t exp(uint8_t l) + { + return data.exp[l]; + } + + static uint64_t divexp(uint64_t x, uint8_t l) + { + return x/data.exp[l]; + } + + static uint64_t modexp(uint64_t x, uint8_t l) + { + return x%data.exp[l]; + } +}; + +template<> +struct precomp<2> { + static uint64_t exp(uint8_t l) + { + return 1ULL<>l; + } + + static uint64_t modexp(uint64_t x, uint8_t l) + { + return x & bits::lo_set[l]; + } +}; + +template<> +struct precomp<4> { + static uint64_t exp(uint8_t l) + { + return 1ULL<<(2*l); + } + + static uint64_t divexp(uint64_t x, uint8_t l) + { + return x>>(2*l); + } + + static uint64_t modexp(uint64_t x, uint8_t l) + { + return x & bits::lo_set[2*l]; + } +}; + +template<> +struct precomp<8> { + static uint64_t exp(uint8_t l) + { + return 1ULL<<(3*l); + } + + static uint64_t divexp(uint64_t x, uint8_t l) + { + return x>>(3*l); + } + + static uint64_t modexp(uint64_t x, uint8_t l) + { + return x & bits::lo_set[3*l]; + } +}; + +template<> +struct precomp<16> { + static uint64_t exp(uint8_t l) + { + return 1ULL<<(4*l); + } + + static uint64_t divexp(uint64_t x, uint8_t l) + { + return x>>(4*l); + } + + static uint64_t modexp(uint64_t x, uint8_t l) + { + return x & bits::lo_set[4*l]; + } +}; + + +template +typename precomp::impl precomp::data; + + + +typedef std::complex t_p; +typedef t_p point_type; +typedef t_p range_type; + +struct node_type { + uint8_t t; // level; size of node 1< real(v.max_p); + } + return imag(max_p) > imag(v.max_p); + } +}; + +} // end namepsace k2_treap_ns + +} // end nomespace sdsl +#endif diff --git a/test/K2TreapTest.config b/test/K2TreapTest.config new file mode 100644 index 000000000..4c0ea2521 --- /dev/null +++ b/test/K2TreapTest.config @@ -0,0 +1,6 @@ +# Inputs which should be used +EMPTY-TEST;test_cases/int-vec-k2t.0.1.0.0.x;test_cases/int-vec-k2t.0.1.0.0.y;test_cases/int-vec-k2t.0.1.0.0.w +SML-TEST;test_cases/int-vec-k2t.100.16.r.42.x;test_cases/int-vec-k2t.100.16.r.23.y;test_cases/int-vec-k2t.100.8.r.81.w +MED-TEST;test_cases/int-vec-k2t.10000.16.r.42.x;test_cases/int-vec-k2t.10000.16.r.23.y;test_cases/int-vec-k2t.10000.8.r.81.w +BIG-TEST;test_cases/int-vec-k2t.100000.39.r.42.x;test_cases/int-vec-k2t.100000.47.r.23.y;test_cases/int-vec-k2t.100000.35.r.81.w +LRG-TEST;test_cases/int-vec-k2t.1000000.52.r.42.x;test_cases/int-vec-k2t.1000000.57.r.23.y;test_cases/int-vec-k2t.1000000.45.r.81.w diff --git a/test/K2TreapTest.cpp b/test/K2TreapTest.cpp new file mode 100644 index 000000000..e2d070600 --- /dev/null +++ b/test/K2TreapTest.cpp @@ -0,0 +1,274 @@ +#include "sdsl/k2_treap.hpp" +#include "sdsl/bit_vectors.hpp" +#include "gtest/gtest.h" +#include +#include +#include +#include // for std::min. std::sort +#include + +namespace +{ + +using namespace sdsl; +using namespace std; + +typedef int_vector<>::size_type size_type; + +string test_file; +string temp_file; +bool in_memory; + +template +class K2TreapTest : public ::testing::Test { }; + +using testing::Types; + +typedef Types< +k2_treap<2, bit_vector>, + k2_treap<2, rrr_vector<63>>, + k2_treap<3, bit_vector>, + k2_treap<4, rrr_vector<63>>, + k2_treap<5, rrr_vector<63>>, + k2_treap<6, rrr_vector<63>>, + k2_treap<16, rrr_vector<63>> + > Implementations; + +TYPED_TEST_CASE(K2TreapTest, Implementations); + +TYPED_TEST(K2TreapTest, CreateAndStoreTest) +{ + TypeParam k2treap; + construct(k2treap, test_file); + ASSERT_TRUE(store_to_file(k2treap, temp_file)); +} + +template +void topk_test( + const t_k2treap& k2treap, + complex min_xy, + complex max_xy, + const int_vector<>& x, + const int_vector<>& y, + const int_vector<>& w) +{ + auto res_it = top_k(k2treap, {real(min_xy),imag(min_xy)}, {real(max_xy),imag(max_xy)}); + typedef tuple t_xyw; + vector vec; + for (uint64_t i = 0; i < x.size(); ++i) { + if (x[i] >= real(min_xy) and x[i] <= real(max_xy) + and y[i] >= imag(min_xy) and y[i] <= imag(max_xy)) { + vec.emplace_back(x[i], y[i], w[i]); + } + } + sort(vec.begin(), vec.end(), [](const t_xyw& a, const t_xyw& b) { + if (get<2>(a) != get<2>(b)) + return get<2>(a) > get<2>(b); + else if (get<0>(a) != get<0>(b)) + return get<0>(a) < get<0>(b); + return get<1>(a) < get<1>(b); + }); + uint64_t cnt = 0; + while (res_it) { + ASSERT_TRUE(cnt < vec.size()); + auto p = *res_it; + ASSERT_EQ(get<2>(vec[cnt]), p.second); + ASSERT_EQ(get<0>(vec[cnt]), real(p.first)); + ASSERT_EQ(get<1>(vec[cnt]), imag(p.first)); + ++res_it; + ++cnt; + } + ASSERT_FALSE(res_it); +} + +TYPED_TEST(K2TreapTest, SizeAndTopk) +{ + TypeParam k2treap; + ASSERT_TRUE(load_from_file(k2treap, temp_file)); + int_vector<> x,y,w; + ASSERT_TRUE(load_from_file(x, test_file+".x")); + ASSERT_TRUE(load_from_file(y, test_file+".y")); + ASSERT_EQ(x.size(), y.size()); + ASSERT_TRUE(load_from_file(w, test_file+".w")); + ASSERT_EQ(x.size(), w.size()); + ASSERT_EQ(x.size(), k2treap.size()); + uint64_t maxx=0, maxy=0; + if (x.size() > 0) { + maxx = *max_element(x.begin(), x.end()); + maxy = *max_element(y.begin(), y.end()); + } + uint64_t minx=0, miny=0; + topk_test(k2treap, {minx,maxx}, {miny,maxy}, x, y, w); + + if (x.size() > 0) { + std::mt19937_64 rng; + std::uniform_int_distribution distribution(0, x.size()-1); + auto dice = bind(distribution, rng); + for (size_t i=0; i<20; ++i) { + auto idx = dice(); + uint64_t xx = x[idx]; + uint64_t yy = y[idx]; + uint64_t dd = 20; + uint64_t minx=0, miny=0, maxx=xx+dd, maxy=yy+dd; + if (xx >= dd) + minx = xx - dd; + if (y >= dd) + miny = yy - dd; + topk_test(k2treap, {minx, miny}, {maxx,maxy}, x, y, w); + } + } +} + +template +void range3d_test( + const t_k2treap& k2treap, + complex min_xy, + complex max_xy, + complex z, + const int_vector<>& x, + const int_vector<>& y, + const int_vector<>& w) +{ + auto res_it = range_3d(k2treap, {real(min_xy),imag(min_xy)}, + {real(max_xy),imag(max_xy)}, + {real(z), imag(z)}); + typedef tuple t_xyw; + vector vec; + for (uint64_t i = 0; i < x.size(); ++i) { + if (x[i] >= real(min_xy) and x[i] <= real(max_xy) + and y[i] >= imag(min_xy) and y[i] <= imag(max_xy)) { + vec.emplace_back(x[i], y[i], w[i]); + } + } + sort(vec.begin(), vec.end(), [](const t_xyw& a, const t_xyw& b) { + if (get<2>(a) != get<2>(b)) + return get<2>(a) > get<2>(b); + else if (get<0>(a) != get<0>(b)) + return get<0>(a) < get<0>(b); + return get<1>(a) < get<1>(b); + }); + uint64_t cnt = 0; + while (res_it) { + ASSERT_TRUE(cnt < vec.size()); + auto p = *res_it; + ASSERT_EQ(get<2>(vec[cnt]), p.second); + ASSERT_EQ(get<0>(vec[cnt]), real(p.first)); + ASSERT_EQ(get<1>(vec[cnt]), imag(p.first)); + ++res_it; + ++cnt; + } + ASSERT_FALSE(res_it); +} + +TYPED_TEST(K2TreapTest, Range3d) +{ + TypeParam k2treap; + ASSERT_TRUE(load_from_file(k2treap, temp_file)); + int_vector<> x,y,w; + ASSERT_TRUE(load_from_file(x, test_file+".x")); + ASSERT_TRUE(load_from_file(y, test_file+".y")); + ASSERT_EQ(x.size(), y.size()); + ASSERT_TRUE(load_from_file(w, test_file+".w")); + ASSERT_EQ(x.size(), w.size()); + ASSERT_EQ(x.size(), k2treap.size()); + if (x.size() > 0) { + std::mt19937_64 rng; + std::uniform_int_distribution distribution(0, x.size()-1); + auto dice = bind(distribution, rng); + for (size_t i=0; i<20; ++i) { + auto idx = dice(); + uint64_t xx = x[idx]; + uint64_t yy = y[idx]; + uint64_t ww = w[idx]; + uint64_t dd = 20; + uint64_t dw = 100; + uint64_t minx=0, miny=0, maxx=xx+dd, maxy=yy+dd, minw=0, maxw=ww+dw; + if (xx >= dd) + minx = xx - dd; + if (yy >= dd) + miny = yy - dd; + if (ww >= dw) + minw = ww - dw; + range3d_test(k2treap, {minx, miny}, {maxx,maxy}, {minw,maxw}, x, y, w); + } + } +} + +template +void count_test( + const t_k2treap& k2treap, + complex min_xy, + complex max_xy, + const int_vector<>& x, + const int_vector<>& y) +{ + uint64_t cnt = 0; + for (uint64_t i = 0; i < x.size(); ++i) { + if (x[i] >= real(min_xy) and x[i] <= real(max_xy) + and y[i] >= imag(min_xy) and y[i] <= imag(max_xy)) { + ++cnt; + } + } + ASSERT_EQ(cnt, count(k2treap, {real(min_xy),imag(min_xy)}, {real(max_xy),imag(max_xy)})); +} + +TYPED_TEST(K2TreapTest, Count) +{ + TypeParam k2treap; + ASSERT_TRUE(load_from_file(k2treap, temp_file)); + int_vector<> x,y; + ASSERT_TRUE(load_from_file(x, test_file+".x")); + ASSERT_TRUE(load_from_file(y, test_file+".y")); + ASSERT_EQ(x.size(), y.size()); + ASSERT_EQ(x.size(), k2treap.size()); + if (x.size() > 0) { + std::mt19937_64 rng; + std::uniform_int_distribution distribution(0, x.size()-1); + auto dice = bind(distribution, rng); + for (size_t i=0; i<3; ++i) { + auto idx1 = dice(); + auto idx2 = dice(); + uint64_t x1 = x[idx1]; + uint64_t y1 = y[idx1]; + uint64_t x2 = x[idx2]; + uint64_t y2 = y[idx2]; + count_test(k2treap, {std::min(x1,x2), std::min(y1,y2)}, {std::max(x1,x2),std::max(y1,y2)}, x, y); + } + } +} + + +} // namespace + +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if (argc < 3) { + // LCOV_EXCL_START + cout << "Usage: " << argv[0] << " file temp_file [in-memory]" << endl; + cout << " (1) Generates a k2-treap out of file.x, file.y, and file.w." << endl; + cout << " Result is stored in temp_file." << endl; + cout << " If `in-memory` is specified, the in-memory construction is tested." << endl; + cout << " (2) Performs tests." << endl; + cout << " (3) Deletes temp_file." << endl; + return 1; + // LCOV_EXCL_STOP + } + test_file = argv[1]; + temp_file = argv[2]; + in_memory = argc > 3; + if (in_memory) { + auto load_and_store_in_mem = [&](string suf) { + int_vector<> data; + string file = temp_file + suf; + load_vector_from_file(data,file); + string ram_file = ram_file_name(file); + store_to_file(data, ram_file); + }; + load_and_store_in_mem("x"); + load_and_store_in_mem("y"); + load_and_store_in_mem("w"); + temp_file = ram_file_name(temp_file); + } + return RUN_ALL_TESTS(); +} diff --git a/test/Makefile b/test/Makefile index 1bd6df9d6..119b88d82 100644 --- a/test/Makefile +++ b/test/Makefile @@ -51,6 +51,9 @@ SA_CONSTRUCT_TESTS:=$(patsubst %,sa-construct-test/%,$(SA_CONSTRUCT_PATHS)) SEARCH_BIDIRECTIONAL_PATHS:=$(call config_column,SearchBidirectionalTest.config,2) SEARCH_BIDIRECTIONAL_TESTS:=$(patsubst %,search-bidirectional-test/%,$(SEARCH_BIDIRECTIONAL_PATHS)) +K2TREAP_TC_PATH:=$(call config_column,K2TreapTest.config,1) +K2TREAP_TESTS:=$(patsubst %,k2treap-test/%,$(K2TREAP_TC_PATH)) + TC_PATHS:= $(WT_BYTE_TC_PATHS) $(WT_INT_TC_PATHS) \ $(CSA_BYTE_TC_PATHS) $(CSA_INT_TC_PATHS) \ $(CST_BYTE_TC_PATHS) $(CST_INT_TC_PATHS) @@ -79,7 +82,8 @@ test: bits-test \ sa-construct-test \ search-bidirectional-test \ sorted-int-stack-test \ - nn-dict-dynamic-test + nn-dict-dynamic-test \ + k2treap-test build-test: $(EXECS) cd ../tutorial; make build-test @@ -127,6 +131,7 @@ sorted-int-stack-test: ./SortedIntStackTest.x nn-dict-dynamic-test: ./NNDictDynamicTest.x @$(PREFIX) ./NNDictDynamicTest.x + bit-vector-test: generators $(BIT_VECTOR_TESTS) rank-support-test: generators $(RANK_SUPPORT_TESTS) @@ -153,6 +158,8 @@ sa-construct-test: generators $(SA_CONSTRUCT_TESTS) search-bidirectional-test: generators $(SEARCH_BIDIRECTIONAL_TESTS) +k2treap-test: ./K2TreapTest.x generators $(K2TREAP_TESTS) + bit-vector-test/test_cases/%: ./BitVectorTest.x test_cases/% @echo "TEST_CASE: test_cases/$*" @$(PREFIX) ./BitVectorTest.x test_cases/$* @@ -221,7 +228,21 @@ search-bidirectional-test/test_cases/%: ./SearchBidirectionalTest.x test_cases/% @echo "TEST_CASE: test_cases/$*" @$(PREFIX) ./SearchBidirectionalTest.x test_cases/$* -# Format: test_cases/int-vec.[LEN].[WIDTH].[DEFAULT] +k2treap-test/%: ./K2TreapTest.x + $(eval X:=$(call config_select,K2TreapTest.config,$*,2)) + $(eval Y:=$(call config_select,K2TreapTest.config,$*,3)) + $(eval W:=$(call config_select,K2TreapTest.config,$*,4)) + make $(X) $(Y) $(W) + @echo "X=$X, Y=$Y, W=$W" + mv $(X) test_cases/K2T.$*.x + mv $(Y) test_cases/K2T.$*.y + mv $(W) test_cases/K2T.$*.w + @echo "TEST_CASE: $* semi-external" + $(PREFIX) ./K2TreapTest.x test_cases/K2T.$* $(TMP_DIR)/K2T.$* + @echo "TEST_CASE: test_cases/$* in-memory" + $(PREFIX) ./K2TreapTest.x test_cases/K2T.$* $(TMP_DIR)/K2T.$* in-memory + +# Format: test_cases/int-vec.[LEN].[WIDTH].[DEFAULT].[SEED] test_cases/int-vec.%: IntVectorGenerator.x @echo "Generate input test_cases/int-vec.$*" $(eval LEN:=$(call dim,1,$*)) @@ -230,7 +251,7 @@ test_cases/int-vec.%: IntVectorGenerator.x $(eval SEED:=$(call dim,4,$*)) @./IntVectorGenerator.x $@ $(LEN) $(WIDTH) $(DEFAULT) $(SEED) -# Format: test_cases/int-vec-sa.[LEN].[WIDTH].[DEFAULT] +# Format: test_cases/int-vec-sa.[LEN].[WIDTH].[DEFAULT].[SEED] test_cases/int-vec-sa.%: IntVectorGenerator.x @echo "Generate input test_cases/int-vec-sa.$*" $(eval LEN:=$(call dim,1,$*)) @@ -240,7 +261,14 @@ test_cases/int-vec-sa.%: IntVectorGenerator.x @./IntVectorGenerator.x $@ $(LEN) $(WIDTH) $(DEFAULT) $(SEED) @./ReplaceIntVectorValue.x $@ 0 1 - +# Format: test_cases/int-vec-k2t.[LEN].[WIDTH].[DEFAULT].[SEED].[x|y|w] +test_cases/int-vec-k2t.%: IntVectorGenerator.x + @echo "Generate input test_cases/int-vec-k2t.$*" + $(eval LEN:=$(call dim,1,$*)) + $(eval WIDTH:=$(call dim,2,$*)) + $(eval DEFAULT:=$(call dim,3,$*)) + $(eval SEED:=$(call dim,4,$*)) + @./IntVectorGenerator.x $@ $(LEN) $(WIDTH) $(DEFAULT) $(SEED) test_cases/bit-vec.%: BitVectorGenerator.x @echo "Generate input test_cases/bit-vec.$*"