From 8346469945fee722b53cfe81ac12f89dab249ca3 Mon Sep 17 00:00:00 2001 From: Dmitrii Kamaldinov Date: Sat, 18 May 2019 19:40:16 +0300 Subject: [PATCH] use generated int vectors as params for rmq, improve rmq tests --- pysdsl/__init__.cpp | 2 +- pysdsl/test/test_rmq.py | 44 ------------------------- pysdsl/types/rmq.hpp | 44 ++++++++++++------------- pysdsl/util/tupletricks.hpp | 4 +-- tests/test_rmq.py | 65 +++++++++++++++++++++++++++++++++++++ 5 files changed, 89 insertions(+), 70 deletions(-) delete mode 100644 pysdsl/test/test_rmq.py create mode 100644 tests/test_rmq.py diff --git a/pysdsl/__init__.cpp b/pysdsl/__init__.cpp index b883c15..8f31801 100644 --- a/pysdsl/__init__.cpp +++ b/pysdsl/__init__.cpp @@ -44,7 +44,7 @@ PYBIND11_MODULE(pysdsl, m) auto csa_classes = add_csa(m); - auto rmq_classes_tuple = add_rmq_classes(m); + auto rmq_classes_tuple = add_rmq_classes(m, iv_classes_as_params); auto& rmq_sparse_tables = std::get<0>(rmq_classes_tuple); auto& rmq_sada = std::get<1>(rmq_classes_tuple); auto& rmq_sct = std::get<2>(rmq_classes_tuple); diff --git a/pysdsl/test/test_rmq.py b/pysdsl/test/test_rmq.py deleted file mode 100644 index 59c08f2..0000000 --- a/pysdsl/test/test_rmq.py +++ /dev/null @@ -1,44 +0,0 @@ -import random - -from pysdsl import IntVector, Int16Vector - -from pysdsl import rmq_sada, rmq_sct, rmq_sparse_tables - - - -def _test_rmq(rmq_class, container_class, target): - cont = container_class(50) - a = [] - - for i in range(50): - a.append(random.randint(0, 50)) - cont[i] = a[i] - - rmq = rmq_class(cont) - - for _ in range(50): - l = random.randint(0, 49) - r = random.randint(l, 49) - - i = rmq(l, r) - - assert cont[i] == target(a[l:r+1]) - - -def test_rmq_sada(): - _test_rmq(rmq_sada['Min'], IntVector, min) - _test_rmq(rmq_sada['Max'], IntVector, max) - _test_rmq(rmq_sada['Min'], Int16Vector, min) - _test_rmq(rmq_sada['Max'], Int16Vector, max) - -def test_rmq_sct(): - _test_rmq(rmq_sct['Min'], IntVector, min) - _test_rmq(rmq_sct['Max'], IntVector, max) - _test_rmq(rmq_sct['Min'], Int16Vector, min) - _test_rmq(rmq_sct['Max'], Int16Vector, max) - -def test_rmq_sparse_table(): - _test_rmq(rmq_sparse_tables['Min_in_IntVector'], IntVector, min) - _test_rmq(rmq_sparse_tables['Max_in_IntVector'], IntVector, max) - _test_rmq(rmq_sparse_tables['Min_in_Int16Vector'], Int16Vector, min) - _test_rmq(rmq_sparse_tables['Max_in_Int16Vector'], Int16Vector, max) diff --git a/pysdsl/types/rmq.hpp b/pysdsl/types/rmq.hpp index 4a9ab3a..552f036 100644 --- a/pysdsl/types/rmq.hpp +++ b/pysdsl/types/rmq.hpp @@ -35,7 +35,7 @@ void add_rac_constructor(PybindClass& cls) } // namespace details -// containers names +// containers names for sparse namespace RAC_names { constexpr char INT_VECTOR_NAME[] = "IntVector", INT16_VECTOR_NAME[] = "Int16Vector"; @@ -80,7 +80,8 @@ struct add_rmq_sparse_table_functor { std::string key = std::string(t_min ? "Min" : "Max") + "_in_" + rac_name; m.attr("rmq_sparse_tables").attr("__setitem__")(key, cls); - m.attr("all_rmq_classes").attr("append")(cls); + m.attr((std::string("all_range_") + (t_min ? "min" : "max") + "_classes").c_str()) + .attr("append")(cls); return cls; } @@ -111,7 +112,7 @@ struct add_rmq_sada_functor { .def("__call__", (size_type (RMQClass::*)(size_type, size_type) const)& RMQClass::operator(), (std::string("Returns an index of the ") + (t_min ? "minimal" : "maximal") + - " value on the segment [l,r].").c_str());; + " value on the segment [l,r].").c_str());; detail::add_rac_constructor(cls); @@ -122,7 +123,8 @@ struct add_rmq_sada_functor { cls.doc() = doc; m.attr("rmq_sada").attr("__setitem__")(t_min ? "Min" : "Max", cls); - m.attr("all_rmq_classes").attr("append")(cls); + m.attr((std::string("all_range_") + (t_min ? "min" : "max") + "_classes").c_str()) + .attr("append")(cls); return cls; } @@ -165,7 +167,8 @@ struct add_rmq_sct_functor { cls.doc() = doc; m.attr("rmq_sct").attr("__setitem__")(t_min ? "Min" : "Max", cls); - m.attr("all_rmq_classes").attr("append")(cls); + m.attr((std::string("all_range_") + (t_min ? "min" : "max") + "_classes").c_str()) + .attr("append")(cls); return cls; } @@ -190,12 +193,21 @@ using general_rmq_sct = py::class_< typename sdsl::range_maximum_sct<>::type>::type>; -inline auto add_rmq_classes(py::module& m) +template +static +auto make_rmq_params(const std::tuple&...>& params) { + return std::tuple, std::integral_constant>, + std::tuple, std::integral_constant>>(); +} + + +inline auto add_rmq_classes(py::module& m, auto params) { m.attr("rmq_sparse_tables") = py::dict(); m.attr("rmq_sada") = py::dict(); m.attr("rmq_sct") = py::dict(); - m.attr("all_rmq_classes") = py::list(); + m.attr("all_range_min_classes") = py::list(); + m.attr("all_range_max_classes") = py::list(); using rmq_support_sparse_table_params = std::tuple< std::tuple, @@ -212,25 +224,11 @@ inline auto add_rmq_classes(py::module& m) std::integral_constant> >; - using rmq_sada_params = std::tuple< - std::tuple, sdsl::int_vector<16>>, - std::integral_constant>, - std::tuple, sdsl::int_vector<16>>, - std::integral_constant> - >; - - using rmq_sct_params = std::tuple< - std::tuple, sdsl::int_vector<16>>, - std::integral_constant>, - std::tuple, sdsl::int_vector<16>>, - std::integral_constant> - >; - auto rmq_sparse_tables = for_each_in_tuple(rmq_support_sparse_table_params(), add_rmq_sparse_table_functor(m, doc_rmq_sparse_table)); - auto rmq_sada_classes = for_each_in_tuple(rmq_sada_params(), + auto rmq_sada_classes = for_each_in_tuple(make_rmq_params(params), add_rmq_sada_functor(m, doc_rmq_sada)); - auto rmq_sct_classes = for_each_in_tuple(rmq_sct_params(), + auto rmq_sct_classes = for_each_in_tuple(make_rmq_params(params), add_rmq_sct_functor(m, doc_rmq_sct)); return std::make_tuple(rmq_sparse_tables, rmq_sada_classes, rmq_sct_classes); diff --git a/pysdsl/util/tupletricks.hpp b/pysdsl/util/tupletricks.hpp index 283d66a..7e75823 100644 --- a/pysdsl/util/tupletricks.hpp +++ b/pysdsl/util/tupletricks.hpp @@ -24,7 +24,7 @@ decltype(auto) for_each(const std::tuple& t, Function&& f) { template constexpr -decltype(auto) for_each(std::tuple& t, Function&& f) { +decltype(auto) for_each(std::tuple&& t, Function&& f) { return for_each_impl(t, f, std::index_sequence_for{}); } template @@ -58,7 +58,7 @@ decltype(auto) for_each_in_tuple(const std::tuple &t, F f) { template constexpr -decltype(auto) for_each_in_tuple(std::tuple &t, F f) { +decltype(auto) for_each_in_tuple(std::tuple &&t, F f) { return detail::for_each(t, f); } template diff --git a/tests/test_rmq.py b/tests/test_rmq.py new file mode 100644 index 0000000..b4ebc69 --- /dev/null +++ b/tests/test_rmq.py @@ -0,0 +1,65 @@ +import random +import pytest + +from pysdsl import Int8Vector, Int64Vector +from pysdsl import rmq_sada, rmq_sct + + + + +def _test_rmq(rmq_class, container_class, target): + cont = container_class(50) + a = [] + + for i in range(50): + a.append(random.randint(0, 50)) + cont[i] = a[i] + + rmq = rmq_class(cont) + + for _ in range(50): + l = random.randint(0, 49) + r = random.randint(l, 49) + + i = rmq(l, r) + + assert cont[i] == target(a[l:r+1]) + + + +@pytest.mark.parametrize('container_class', (Int8Vector, Int64Vector)) +def test_rmq_sada(container_class): + _test_rmq(rmq_sada['Min'], container_class, min) + _test_rmq(rmq_sada['Max'], container_class, max) + + +@pytest.mark.parametrize('container_class', (Int8Vector, Int64Vector)) +def test_rmq_sct(container_class): + _test_rmq(rmq_sct['Min'], container_class, min) + _test_rmq(rmq_sct['Max'], container_class, max) + + + +@pytest.mark.parametrize("rmq_class", list(rmq_sada.values()) + list(rmq_sct.values())) +def test_rmq_on_container_remove(rmq_class): + cont = Int64Vector(3) + + cont[0] = 1 + cont[1] = 2 + cont[2] = 3 + + rmq = rmq_class(cont) + + ans1 = rmq(0, 2) + + cont[0] = 3 + cont[1] = 2 + cont[2] = 1 + + ans2 = rmq(0, 2) + assert ans1 == ans2 + + cont = None + + ans2 = rmq(0, 2) + assert ans1 == ans2