Skip to content

Commit

Permalink
[FEATURE] Make search work with dynamic mode configuration.
Browse files Browse the repository at this point in the history
Enables the dynamic mode configuration within the search algorithm by transforming it
into a static configuration.
  • Loading branch information
rrahn committed Dec 20, 2019
1 parent 5c23335 commit c467ff9
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 7 deletions.
42 changes: 37 additions & 5 deletions include/seqan3/search/algorithm/detail/search.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@

#pragma once

#include <variant>

#include <seqan3/core/type_traits/pre.hpp>
#include <seqan3/core/type_traits/function.hpp>
#include <seqan3/search/algorithm/detail/search_scheme_algorithm.hpp>
#include <seqan3/search/algorithm/detail/search_trivial.hpp>
#include <seqan3/search/configuration/all.hpp>
Expand Down Expand Up @@ -79,7 +82,7 @@ inline auto search_single(index_t const & index, query_t & query, configuration_
};

// choose mode
if constexpr (cfg_t::template exists<search_cfg::mode<detail::search_mode_best>>())
if constexpr (cfg_t::template exists<internal_search_mode<search_mode_best>>())
{
detail::search_param max_error2{max_error};
max_error2.total = 0;
Expand All @@ -89,7 +92,7 @@ inline auto search_single(index_t const & index, query_t & query, configuration_
max_error2.total++;
}
}
else if constexpr (cfg_t::template exists<search_cfg::mode<detail::search_mode_all_best>>())
else if constexpr (cfg_t::template exists<internal_search_mode<search_mode_all_best>>())
{
detail::search_param max_error2{max_error};
max_error2.total = 0;
Expand All @@ -99,7 +102,7 @@ inline auto search_single(index_t const & index, query_t & query, configuration_
max_error2.total++;
}
}
else if constexpr (cfg_t::template exists<search_cfg::mode<search_cfg::strata>>())
else if constexpr (cfg_t::template exists<internal_search_mode<search_cfg::strata>>())
{
detail::search_param max_error2{max_error};
max_error2.total = 0;
Expand All @@ -111,7 +114,7 @@ inline auto search_single(index_t const & index, query_t & query, configuration_
if (!internal_hits.empty())
{
internal_hits.clear(); // TODO: don't clear when using Optimum Search Schemes with lower error bounds
uint8_t const s = get<search_cfg::mode>(cfg).value;
uint8_t const s = get<internal_search_mode>(cfg).value;
max_error2.total += s - 1;
detail::search_algo<false>(index, query, max_error2, internal_delegate);
}
Expand All @@ -135,7 +138,7 @@ inline auto search_single(index_t const & index, query_t & query, configuration_
typename index_t::size_type>;
std::vector<hit_t> hits;

if constexpr (cfg_t::template exists<search_cfg::mode<detail::search_mode_best>>())
if constexpr (cfg_t::template exists<internal_search_mode<search_mode_best>>())
{
// only one cursor is reported but it might contain more than one text position
if (!internal_hits.empty())
Expand Down Expand Up @@ -177,6 +180,9 @@ inline auto search_single(index_t const & index, query_t & query, configuration_
* specified in `cfg` also has a strong exception guarantee; basic exception guarantee otherwise.
*/
template <typename index_t, typename queries_t, typename configuration_t>
//!\cond
requires configuration_t::template exists<internal_search_mode>()
//!\endcond
inline auto search_all(index_t const & index, queries_t & queries, configuration_t const & cfg)
{
using cfg_t = remove_cvref_t<configuration_t>;
Expand Down Expand Up @@ -209,6 +215,32 @@ inline auto search_all(index_t const & index, queries_t & queries, configuration
}
}

//!\overload
template <typename index_t, typename queries_t, typename configuration_t>
//!\cond
requires !configuration_t::template exists<internal_search_mode>()
//!\endcond
inline auto search_all(index_t const & index, queries_t & queries, configuration_t const & cfg)
{
using seqan3::get;
auto mode_config = get<search_cfg::mode>(cfg);

if constexpr (decltype(mode_config)::has_dynamic_state)
{
return std::visit(multi_invocable
{
[&] (search_mode_all_best) { return search_all(index, queries, cfg | internal_search_mode{search_cfg::all_best}); },
[&] (search_mode_best) { return search_all(index, queries, cfg | internal_search_mode{search_cfg::best}); },
[&] (search_cfg::strata const & strata) { return search_all(index, queries, cfg | internal_search_mode{strata}); },
[&] (auto) { return search_all(index, queries, cfg | internal_search_mode{search_cfg::all}); }
}, mode_config.search_modes());
}
else
{
return search_all(index, queries, cfg | internal_search_mode{mode_config.value});
}
}

//!\}

} // namespace seqan3::detail
28 changes: 26 additions & 2 deletions test/unit/search/search_configuration_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#include <type_traits>

#include <seqan3/search/algorithm/all.hpp>
#include <seqan3/search/configuration/all.hpp>

#include <gtest/gtest.h>

Expand All @@ -20,7 +20,8 @@ class search_configuration_test : public ::testing::Test
using test_types = ::testing::Types<search_cfg::max_error_rate<>,
search_cfg::max_error<>,
search_cfg::mode<detail::search_mode_best>,
search_cfg::output<detail::search_output_text_position>>;
search_cfg::output<detail::search_output_text_position>
>;

TYPED_TEST_CASE(search_configuration_test, test_types);

Expand Down Expand Up @@ -53,6 +54,29 @@ TYPED_TEST(search_configuration_test, configuration_exists)
EXPECT_TRUE(decltype(cfg)::template exists<TypeParam>());
}

TYPED_TEST(search_configuration_test, configuration_exists_constexpr)
{
constexpr configuration cfg{TypeParam{}};
constexpr bool cfg_exists = decltype(cfg)::template exists<TypeParam>();
EXPECT_TRUE(cfg_exists);
}

TEST(search_configuration_mode_test, select_at_runtime)
{
{
seqan3::search_cfg::mode m{seqan3::search_cfg::all};
EXPECT_FALSE(m.has_dynamic_state);
}

{
seqan3::search_cfg::mode m{};
EXPECT_TRUE(m.has_dynamic_state);

m = seqan3::search_cfg::all_best;
EXPECT_TRUE(std::holds_alternative<seqan3::detail::search_mode_all_best>(m.search_modes()));
}
}

// TEST(search_configuration_test, illegal_runtime_configurations)
// {
// std::vector<dna4> text{"ACGT"_dna4}, query{"ACG"_dna4};
Expand Down
36 changes: 36 additions & 0 deletions test/unit/search/search_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,13 @@ TYPED_TEST(search_test, search_strategy_all)
configuration const cfg = max_error{total{1}} | mode{all};
EXPECT_EQ(uniquify(search("ACGT"_dna4, this->index, cfg)), (hits_result_t{0, 1, 4, 5, 8, 9}));
}

{ // Test with dynamic mode.
mode dynamic_mode{};
dynamic_mode = all;
configuration const cfg = max_error{total{1}} | dynamic_mode;
EXPECT_EQ(uniquify(search("ACGT"_dna4, this->index, cfg)), (hits_result_t{0, 1, 4, 5, 8, 9}));
}
}

TYPED_TEST(search_test, search_strategy_best)
Expand All @@ -317,6 +324,18 @@ TYPED_TEST(search_test, search_strategy_best)
EXPECT_EQ(search("AAAA"_dna4, this->index, cfg), (hits_result_t{})); // no hit
}

{ // Test with dynamic mode.
mode dynamic_mode{};
dynamic_mode = best;
configuration const cfg = max_error{total{1}} | dynamic_mode;

hits_result_t result = search("ACGT"_dna4, this->index, cfg);
ASSERT_EQ(result.size(), 1u);
EXPECT_TRUE(std::find(possible_hits.begin(), possible_hits.end(), result[0]) != possible_hits.end());

EXPECT_EQ(search("AAAA"_dna4, this->index, cfg), (hits_result_t{})); // no hit
}

{ // Find best match with 1 insertion at the end.
configuration const cfg = max_error{total{1}, insertion{1}} | mode{best};

Expand Down Expand Up @@ -386,6 +405,16 @@ TYPED_TEST(search_test, search_strategy_all_best)

EXPECT_EQ(search("AAAA"_dna4, this->index, cfg), (hits_result_t{})); // no hit
}

{ // Test with dynamic mode.
mode dynamic_mode{};
dynamic_mode = all_best;
configuration const cfg = max_error{total{1}} | dynamic_mode;

EXPECT_EQ(uniquify(search("ACGT"_dna4, this->index, cfg)), (hits_result_t{0, 4, 8})); // 1, 5, 9 are not best hits

EXPECT_EQ(search("AAAA"_dna4, this->index, cfg), (hits_result_t{})); // no hit
}
}

TYPED_TEST(search_test, search_strategy_strata)
Expand All @@ -397,6 +426,13 @@ TYPED_TEST(search_test, search_strategy_strata)
EXPECT_EQ(uniquify(search("ACGT"_dna4, this->index, cfg)), (hits_result_t{0, 4, 8}));
}

{ // Test with dynamic mode.
mode dynamic_mode{};
dynamic_mode = strata{0};
configuration const cfg = max_error{total{1}} | dynamic_mode;
EXPECT_EQ(uniquify(search("ACGT"_dna4, this->index, cfg)), (hits_result_t{0, 4, 8}));
}

{
configuration const cfg = max_error{total{1}} | mode{strata{1}};
EXPECT_EQ(uniquify(search("ACGT"_dna4, this->index, cfg)), (hits_result_t{0, 1, 4, 5, 8, 9}));
Expand Down

0 comments on commit c467ff9

Please sign in to comment.