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 Mar 17, 2020
1 parent ec19ec8 commit 9f83164
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 69 deletions.
34 changes: 33 additions & 1 deletion 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_traits.hpp>
#include <seqan3/search/algorithm/detail/search_trivial.hpp>
Expand Down Expand Up @@ -112,7 +115,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 Down Expand Up @@ -178,6 +181,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 @@ -210,6 +216,32 @@ inline auto search_all(index_t const & index, queries_t && queries, configuratio
}
}

//!\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, std::forward<queries_t>(queries), cfg | internal_search_mode{mode_config.value});
}
}

//!\}

} // namespace seqan3::detail
19 changes: 11 additions & 8 deletions include/seqan3/search/algorithm/detail/search_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,24 @@ struct search_traits

//!\brief A flag indicating whether search should find all hits.
static constexpr bool search_all_hits =
search_configuration_t::template exists<search_cfg::mode<detail::search_mode_all>>();
search_configuration_t::template exists<search_cfg::mode<detail::search_mode_all>>() |
search_configuration_t::template exists<detail::internal_search_mode<detail::search_mode_all>>();
//!\brief A flag indicating whether search should find best hits.
static constexpr bool search_best_hits =
search_configuration_t::template exists<search_cfg::mode<detail::search_mode_best>>();
search_configuration_t::template exists<search_cfg::mode<detail::search_mode_best>>() |
search_configuration_t::template exists<detail::internal_search_mode<detail::search_mode_best>>();
//!\brief A flag indicating whether search should find all best hits.
static constexpr bool search_all_best_hits =
search_configuration_t::template exists<search_cfg::mode<detail::search_mode_all_best>>();
search_configuration_t::template exists<search_cfg::mode<detail::search_mode_all_best>>() |
search_configuration_t::template exists<detail::internal_search_mode<detail::search_mode_all_best>>();
//!\brief A flag indicating whether search should find strata hits.
static constexpr bool search_strata_hits =
search_configuration_t::template exists<search_cfg::mode<search_cfg::strata>>();
search_configuration_t::template exists<search_cfg::mode<search_cfg::strata>>() |
search_configuration_t::template exists<detail::internal_search_mode<search_cfg::strata>>();
//!\brief A flag indicating whether mode configuration was set in the search configuration.
static constexpr bool has_mode_configuration = search_all_hits |
search_best_hits |
search_all_best_hits |
search_strata_hits;
static constexpr bool has_mode_configuration =
search_configuration_t::template exists<search_cfg::mode>() |
search_configuration_t::template exists<detail::internal_search_mode>();

//!\brief A flag indicating whether search should return the index cursor.
static constexpr bool search_return_index_cursor =
Expand Down
2 changes: 1 addition & 1 deletion include/seqan3/search/algorithm/search.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ namespace seqan3
*
* \include test/snippet/search/algorithm/search.cpp
*/
template <fm_index_specialisation index_t, typename queries_t, typename configuration_t = decltype(search_cfg::default_configuration)>
template <typename queries_t, fm_index_specialisation index_t, typename configuration_t = decltype(search_cfg::default_configuration)>
inline auto search(queries_t && queries,
index_t const & index,
configuration_t const & cfg = search_cfg::default_configuration)
Expand Down
54 changes: 27 additions & 27 deletions include/seqan3/search/configuration/mode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ struct search_mode_all_best {};
//!\brief Type for the "best" value for the configuration element "mode".
//!\ingroup search_configuration
struct search_mode_best {};

} // namespace seqan3::detail

namespace seqan3::search_cfg
Expand All @@ -61,9 +60,21 @@ struct strata : detail::strong_type<uint8_t, strata, detail::strong_type_skill::
using detail::strong_type<uint8_t, strata, detail::strong_type_skill::convert>::strong_type;
};

//!\brief A helper variable template to check if the given mode type is a valid search mode.
//!\ingroup search_configuration
//!\hideinitializer
template <typename search_mode_t>
inline constexpr bool is_valid_search_mode_v = std::same_as<search_mode_t, detail::search_mode_all> ||
std::same_as<search_mode_t, detail::search_mode_all_best> ||
std::same_as<search_mode_t, detail::search_mode_best> ||
std::same_as<search_mode_t, strata>;

/*!\brief Configuration element to determine the search mode.
* \ingroup search_configuration
*
* \tparam search_mode_t The type of the search mode to use; seqan3::search_cfg::is_valid_mode_type must evaluate to
* `true` or must be of type seqan3::dynamic_state.
*
* \details
*
* This configuration element can be used to determine which hits are supported.
Expand Down Expand Up @@ -92,11 +103,7 @@ struct strata : detail::strong_type<uint8_t, strata, detail::strong_type_skill::
*/
template <typename search_mode_t>
//!\cond
requires std::same_as<search_mode_t, detail::search_mode_all> ||
std::same_as<search_mode_t, detail::search_mode_all_best> ||
std::same_as<search_mode_t, detail::search_mode_best> ||
std::same_as<search_mode_t, strata> ||
std::same_as<search_mode_t, dynamic_state>
requires is_valid_search_mode_v<search_mode_t> || std::same_as<search_mode_t, dynamic_state>
//!\endcond
class mode : public pipeable_config_element<mode<search_mode_t>, search_mode_t>
{
Expand All @@ -121,6 +128,8 @@ class mode : public pipeable_config_element<mode<search_mode_t>, search_mode_t>
~mode() = default; //!< Defaulted.

/*!\brief Construction of a fixed search mode with the given mode option.
*
* \tparam new_search_mode_t The type of the search mode to set.
*
* \param[in] new_search_mode The instance of the search mode option to use.
*
Expand All @@ -131,30 +140,25 @@ class mode : public pipeable_config_element<mode<search_mode_t>, search_mode_t>
*/
template <typename new_search_mode_t>
//!\cond
requires !std::same_as<new_search_mode_t, mode> &&
(std::same_as<new_search_mode_t, detail::search_mode_all> ||
std::same_as<new_search_mode_t, detail::search_mode_all_best> ||
std::same_as<new_search_mode_t, detail::search_mode_best> ||
std::same_as<new_search_mode_t, strata>)
requires !std::same_as<new_search_mode_t, mode> && is_valid_search_mode_v<new_search_mode_t>
//!\endcond
explicit constexpr mode(new_search_mode_t new_search_mode) : base_t{std::move(new_search_mode)}
{}

/*!\brief Assigns a new mode option to the search mode.
*
* \tparam new_search_mode_t The type of the search mode to set.
*
* \param[in] new_search_mode The instance of the search mode option to use.
*
* \details
*
* Note this assignment operator is only available if the search mode was default constructed.
* Note this assignment operator is only available if the search mode was default constructed, i.e. `search_mode_t`
* is deduced as seqan3::dynamic_state.
*/
template <typename new_search_mode_t>
//!\cond
requires !std::same_as<new_search_mode_t, mode> &&
(std::same_as<new_search_mode_t, detail::search_mode_all> ||
std::same_as<new_search_mode_t, detail::search_mode_all_best> ||
std::same_as<new_search_mode_t, detail::search_mode_best> ||
std::same_as<new_search_mode_t, strata>)
requires !std::same_as<new_search_mode_t, mode> && is_valid_search_mode_v<new_search_mode_t>
//!\endcond
constexpr mode & operator=(new_search_mode_t new_search_mode)
{
Expand All @@ -166,6 +170,9 @@ class mode : public pipeable_config_element<mode<search_mode_t>, search_mode_t>
}
//!\}

//!\brief Evaluates to `true` if the search mode can be configured at runtime, otherwise `false`.
static constexpr bool has_dynamic_state = std::same_as<search_mode_t, dynamic_state>;

//!\privatesection
//!\brief Internal id to check for consistent configuration settings.
static constexpr detail::search_config_id id{detail::search_config_id::mode};
Expand All @@ -179,9 +186,6 @@ class mode : public pipeable_config_element<mode<search_mode_t>, search_mode_t>
return search_mode_variant;
}

//!\brief Evaluates to `true` if the search mode can be configured at runtime, otherwise `false`.
static constexpr bool has_dynamic_state = std::same_as<search_mode_t, dynamic_state>;

private:
//!\brief Stores the dynamically selected search mode option.
search_modes_t search_mode_variant{};
Expand All @@ -205,9 +209,8 @@ namespace seqan3::detail
/*!\brief An internal representation of the associated seqan3::search_cfg::mode.
* \ingroup search_configuration
*
* \tparam search_mode_t The type of the search mode option; must be one of seqan3::detail::search_mode_all,
* seqan3::detail::search_mode_best, seqan3::detail::search_mode_all_best, or
* seqan3::detail::search_mode_strata.
* \tparam search_mode_t The type of the search mode option; seqan3::search_cfg::is_valid_search_mode_v must evaluate to
* `true`;
*
* \details
*
Expand All @@ -220,10 +223,7 @@ namespace seqan3::detail
*/
template <typename search_mode_t>
//!\cond
requires std::same_as<search_mode_t, search_mode_all> ||
std::same_as<search_mode_t, search_mode_all_best> ||
std::same_as<search_mode_t, search_mode_best> ||
std::same_as<search_mode_t, search_cfg::strata>
requires search_cfg::is_valid_search_mode_v<search_mode_t>
//!\endcond
struct internal_search_mode : public pipeable_config_element<internal_search_mode<search_mode_t>, search_mode_t>
{
Expand Down
8 changes: 4 additions & 4 deletions test/snippet/search/configuration_modes_dynamic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ int main()
{
seqan3::search_cfg::mode my_mode{}; // Enables the dynamic configuration, defaults to seqan3::search_cfg::all.

my_mode = seqan3::search_cfg::best; // Now the best mode is selected.

my_mode = seqan3::search_cfg::strata{2}; // Now the strata mode is selected.

if (true)
my_mode = seqan3::search_cfg::best; // The best mode is selected.
else
my_mode = seqan3::search_cfg::strata{2}; // The strata mode is selected.

// Combine the dynamically configured mode with other search configurations.
seqan3::configuration const cfg = my_mode |
Expand Down
4 changes: 2 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 Down Expand Up @@ -57,7 +57,7 @@ TYPED_TEST(search_configuration_test, configuration_exists)
// See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93034
TYPED_TEST(search_configuration_test, configuration_exists_constexpr)
{
constexpr configuration cfg{TypeParam{}};
constexpr seqan3::configuration cfg{TypeParam{}};
constexpr bool cfg_exists = decltype(cfg)::template exists<TypeParam>();
EXPECT_TRUE(cfg_exists);
}
Expand Down
Loading

0 comments on commit 9f83164

Please sign in to comment.