SeqAn3  3.2.0
The Modern C++ library for sequence analysis.
search.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2022, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2022, Knut Reinert & MPI für molekulare Genetik
4 // This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
5 // shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
6 // -----------------------------------------------------------------------------------------------------
7 
13 #pragma once
14 
15 #include <algorithm>
16 #include <ranges>
17 
30 
31 namespace seqan3::detail
32 {
36 struct search_configuration_validator
37 {
42  template <typename query_t>
43  static void validate_query_type()
44  {
45  using pure_query_t = std::remove_cvref_t<query_t>;
46  if constexpr (range_dimension_v<pure_query_t> == 1u)
47  {
48  static_assert(std::ranges::random_access_range<pure_query_t>,
49  "The query sequence must model random_access_range.");
50  static_assert(std::ranges::sized_range<pure_query_t>, "The query sequence must model sized_range.");
51  }
52  else
53  {
54  static_assert(std::ranges::forward_range<pure_query_t>, "The query collection must model forward_range.");
55  static_assert(std::ranges::sized_range<pure_query_t>, "The query collection must model sized_range.");
56  static_assert(std::ranges::random_access_range<std::ranges::range_value_t<pure_query_t>>,
57  "Elements of the query collection must model random_access_range.");
58  static_assert(std::ranges::sized_range<std::ranges::range_value_t<pure_query_t>>,
59  "Elements of the query collection must model sized_range.");
60  }
61  }
62 };
63 } // namespace seqan3::detail
64 
65 namespace seqan3
66 {
97 template <typename index_t,
98  std::ranges::forward_range queries_t,
99  typename configuration_t = decltype(search_cfg::default_configuration)>
100  requires std::ranges::forward_range<std::ranges::range_reference_t<queries_t>>
101  && std::same_as<range_innermost_value_t<queries_t>, typename index_t::alphabet_type>
102 inline auto
103 search(queries_t && queries, index_t const & index, configuration_t const & cfg = search_cfg::default_configuration)
104 {
105  auto updated_cfg = detail::search_configurator::add_defaults(cfg);
106 
107  detail::search_configuration_validator::validate_query_type<queries_t>();
108 
109  size_t queries_size = std::ranges::distance(queries);
110  auto indexed_queries = views::zip(std::views::iota(size_t{0}, queries_size), std::forward<queries_t>(queries));
111 
112  using indexed_queries_t = decltype(indexed_queries);
113 
114  using query_t = std::ranges::range_reference_t<indexed_queries_t>;
115  auto [algorithm, complete_config] = detail::search_configurator::configure_algorithm<query_t>(updated_cfg, index);
116 
117  using complete_configuration_t = decltype(complete_config);
118  using traits_t = detail::search_traits<complete_configuration_t>;
119  using algorithm_result_t = typename traits_t::search_result_type;
121  detail::execution_handler_parallel,
122  detail::execution_handler_sequential>;
123 
124  // Select the execution handler for the search configuration.
125  auto select_execution_handler = [parallel = complete_config.get_or(search_cfg::parallel{})]()
126  {
127  if constexpr (std::same_as<execution_handler_t, detail::execution_handler_parallel>)
128  {
129  auto thread_count = parallel.thread_count;
130  if (!thread_count)
131  throw std::runtime_error{"You must configure the number of threads in seqan3::search_cfg::parallel."};
132 
133  return execution_handler_t{*thread_count};
134  }
135  else
136  {
137  return execution_handler_t{};
138  }
139  };
140 
141  // Finally, choose between two way execution returning an algorithm range or calling a user callback on every hit.
142  if constexpr (traits_t::has_user_callback)
143  {
144  select_execution_handler().bulk_execute(algorithm,
145  indexed_queries,
146  get<search_cfg::on_result>(complete_config).callback);
147  }
148  else
149  {
150  using executor_t = detail::algorithm_executor_blocking<indexed_queries_t,
151  decltype(algorithm),
152  algorithm_result_t,
153  execution_handler_t>;
154 
155  return algorithm_result_generator_range{executor_t{std::move(indexed_queries),
156  std::move(algorithm),
157  algorithm_result_t{},
158  select_execution_handler()}};
159  }
160 }
161 
163 // Convert query sequence if it does not match the alphabet type of the index.
165 template <typename index_t,
166  std::ranges::forward_range queries_t,
167  typename configuration_t = decltype(search_cfg::default_configuration)>
168  requires std::ranges::forward_range<std::ranges::range_reference_t<queries_t>>
169  && (!std::same_as<range_innermost_value_t<queries_t>, typename index_t::alphabet_type>)
170 inline auto search(queries_t && queries,
171  index_t const & index,
172  configuration_t const & cfg = search_cfg::default_configuration)
173 {
174  static_assert(std::convertible_to<range_innermost_value_t<queries_t>, typename index_t::alphabet_type>,
175  "The alphabet of the text collection must be convertible to the alphabet of the index.");
176 
177  if constexpr (range_dimension_v<queries_t> == 2u)
178  return search(queries | views::deep{views::convert<typename index_t::alphabet_type>}, index, cfg);
179  else
180  return search(queries | views::convert<typename index_t::alphabet_type>, index, cfg);
181 }
182 
183 // Overload for a single query (not a collection of queries)
185 template <typename index_t,
186  std::ranges::forward_range query_t,
187  typename configuration_t = decltype(search_cfg::default_configuration)>
188 inline auto
189 search(query_t && query, index_t const & index, configuration_t const & cfg = search_cfg::default_configuration)
190 {
191  return search(std::views::single(std::forward<query_t>(query)), index, cfg);
192 }
193 
195 template <typename index_t, typename configuration_t = decltype(search_cfg::default_configuration)>
196 inline auto search(char const * const queries,
197  index_t const & index,
198  configuration_t const & cfg = search_cfg::default_configuration)
199 {
200  return search(std::string_view{queries}, index, cfg);
201 }
202 
204 template <typename index_t, typename configuration_t = decltype(search_cfg::default_configuration)>
205 inline auto search(std::initializer_list<char const * const> const & queries,
206  index_t const & index,
207  configuration_t const & cfg = search_cfg::default_configuration)
208 {
210  query.reserve(std::ranges::size(queries));
211  std::ranges::for_each(queries,
212  [&query](char const * const q)
213  {
214  query.push_back(std::string_view{q});
215  });
216  return search(std::move(query) | detail::persist, index, cfg);
217 }
219 
220 } // namespace seqan3
Provides seqan3::detail::algorithm_executor_blocking.
Provides seqan3::detail::algorithm_result_generator_range.
An input range over the algorithm results generated by the underlying algorithm executor.
Definition: algorithm_result_generator_range.hpp:48
Provides seqan3::configuration and utility functions.
Provides seqan3::views::deep.
Provides the default configuration for the seqan3::search() interface.
requires requires
The rank_type of the semi-alphabet; defined as the return type of seqan3::to_rank....
Definition: alphabet/concept.hpp:164
seqan3::detail::parallel_mode< std::integral_constant< detail::search_config_id, detail::search_config_id::parallel > > parallel
Enables the parallel execution of the search algorithm if possible for the given configuration.
Definition: parallel.hpp:35
constexpr configuration default_configuration
The default configuration: Compute all exact matches.
Definition: default_configuration.hpp:29
@ single
The text is a single range.
Definition: search/fm_index/concept.hpp:93
requires std::ranges::forward_range< std::ranges::range_reference_t< queries_t > > &&std::same_as< range_innermost_value_t< queries_t >, typename index_t::alphabet_type > auto search(queries_t &&queries, index_t const &index, configuration_t const &cfg=search_cfg::default_configuration)
Search a query or a range of queries in an index.
Definition: search.hpp:103
constexpr size_t size
The size of a type pack.
Definition: type_pack/traits.hpp:146
constexpr auto zip
A view adaptor that takes several views and returns tuple-like values from every i-th element of each...
Definition: zip.hpp:573
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
Provides seqan3::search_cfg::on_result.
Provides seqan3::search_cfg::parallel configuration.
Provides seqan3::detail::persist.
T push_back(T... args)
The <ranges> header from C++20's standard library.
T reserve(T... args)
Provides seqan3::detail::search_configurator.
Provides seqan3::detail::search_traits.
Provides seqan3::views::convert.
Provides seqan3::views::zip.