SeqAn3  3.1.0-rc.1
The Modern C++ library for sequence analysis.
search.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2021, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2021, 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 <seqan3/std/algorithm>
16 #include <seqan3/std/ranges>
17 
30 
31 namespace seqan3::detail
32 {
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)>
101  requires std::ranges::forward_range<std::ranges::range_reference_t<queries_t>> &&
102  std::same_as<range_innermost_value_t<queries_t>, typename index_t::alphabet_type>
104 inline auto search(queries_t && queries,
105  index_t const & index,
106  configuration_t const & cfg = search_cfg::default_configuration)
107 {
108  auto updated_cfg = detail::search_configurator::add_defaults(cfg);
109 
110  detail::search_configuration_validator::validate_query_type<queries_t>();
111 
112  size_t queries_size = std::ranges::distance(queries);
113  auto indexed_queries = views::zip(std::views::iota(size_t{0}, queries_size), queries);
114 
115  using indexed_queries_t = decltype(indexed_queries);
116 
117  using query_t = std::ranges::range_reference_t<indexed_queries_t>;
118  auto [algorithm, complete_config] = detail::search_configurator::configure_algorithm<query_t>(updated_cfg, index);
119 
120  using complete_configuration_t = decltype(complete_config);
122  using algorithm_result_t = typename traits_t::search_result_type;
123  using execution_handler_t = std::conditional_t<
124  complete_configuration_t::template exists<search_cfg::parallel>(),
127 
128  // Select the execution handler for the search configuration.
129  auto select_execution_handler = [&] ()
130  {
131  if constexpr (std::same_as<execution_handler_t, detail::execution_handler_parallel>)
132  {
133  auto thread_count = get<search_cfg::parallel>(complete_config).thread_count;
134  if (!thread_count)
135  throw std::runtime_error{"You must configure the number of threads in seqan3::search_cfg::parallel."};
136 
137  return execution_handler_t{*thread_count};
138  }
139  else
140  {
141  return execution_handler_t{};
142  }
143  };
144 
145  // Finally, choose between two way execution returning an algorithm range or calling a user callback on every hit.
146  if constexpr (traits_t::has_user_callback)
147  {
148  select_execution_handler().bulk_execute(algorithm,
149  indexed_queries,
150  get<search_cfg::on_result>(complete_config).callback);
151  }
152  else
153  {
154  using executor_t = detail::algorithm_executor_blocking<indexed_queries_t,
155  decltype(algorithm),
156  algorithm_result_t,
157  execution_handler_t>;
158 
159  return algorithm_result_generator_range{executor_t{std::move(indexed_queries),
160  std::move(algorithm),
161  algorithm_result_t{},
162  select_execution_handler()}};
163  }
164 }
165 
167 // Convert query sequence if it does not match the alphabet type of the index.
169 template <typename index_t,
170  std::ranges::forward_range queries_t,
171  typename configuration_t = decltype(search_cfg::default_configuration)>
172  requires std::ranges::forward_range<std::ranges::range_reference_t<queries_t>> &&
173  (!std::same_as<range_innermost_value_t<queries_t>, typename index_t::alphabet_type>)
174 inline auto search(queries_t && queries,
175  index_t const & index,
176  configuration_t const & cfg = search_cfg::default_configuration)
177 {
178  static_assert(std::convertible_to<range_innermost_value_t<queries_t>, typename index_t::alphabet_type>,
179  "The alphabet of the text collection must be convertible to the alphabet of the index.");
180 
181  if constexpr (range_dimension_v<queries_t> == 2u)
182  return search(queries | views::deep{views::convert<typename index_t::alphabet_type>}, index, cfg);
183  else
184  return search(queries | views::convert<typename index_t::alphabet_type>, index, cfg);
185 }
186 
187 // Overload for a single query (not a collection of queries)
189 template <typename index_t,
190  std::ranges::forward_range query_t,
191  typename configuration_t = decltype(search_cfg::default_configuration)>
192 inline auto search(query_t && query,
193  index_t const & index,
194  configuration_t const & cfg = search_cfg::default_configuration)
195 {
196  return search(std::views::single(std::forward<query_t>(query)), index, cfg);
197 }
198 
200 template <typename index_t, typename configuration_t = decltype(search_cfg::default_configuration)>
201 inline auto search(char const * const queries,
202  index_t const & index,
203  configuration_t const & cfg = search_cfg::default_configuration)
204 {
205  return search(std::string_view{queries}, index, cfg);
206 }
207 
209 template <typename index_t, typename configuration_t = decltype(search_cfg::default_configuration)>
211  index_t const & index,
212  configuration_t const & cfg = search_cfg::default_configuration)
213 {
215  query.reserve(std::ranges::size(queries));
216  std::ranges::for_each(queries, [&query] (char const * const q) { query.push_back(std::string_view{q}); });
217  return search(std::move(query) | detail::persist, index, cfg);
218 }
220 
221 } // namespace seqan3
Provides seqan3::detail::algorithm_executor_blocking.
Provides seqan3::detail::algorithm_result_generator_range.
Adaptations of algorithms from the Ranges TS.
An input range over the algorithm results generated by the underlying algorithm executor.
Definition: algorithm_result_generator_range.hpp:44
A blocking algorithm executor for algorithms.
Definition: algorithm_executor_blocking.hpp:64
Handles the parallel execution of algorithms.
Definition: execution_handler_parallel.hpp:55
static auto add_defaults(configuration_t const &cfg)
Adds default configurations if they were not set by the user.
Definition: search_configurator.hpp:140
Provides seqan3::configuration and utility functions.
Provides seqan3::views::deep.
Provides the default configuration for the seqan3::search() interface.
typename range_innermost_value< t >::type range_innermost_value_t
Shortcut for seqan3::range_innermost_value (transformation_trait shortcut).
Definition: type_traits.hpp:91
constexpr void for_each(unary_function_t &&fn, pack_t &&...args)
Applies a function to each element of the given function parameter pack.
Definition: pack_algorithm.hpp:196
constexpr auto persist
[adaptor_def]
Definition: persist_view.hpp:224
const configuration default_configuration
The default configuration: Compute all exact matches.
Definition: default_configuration.hpp:32
@ single
The text is a single range.
Definition: concept.hpp:74
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:104
constexpr simd_t iota(typename simd_traits< simd_t >::scalar_type const offset)
Fills a seqan3::simd::simd_type vector with the scalar values offset, offset+1, offset+2,...
Definition: algorithm.hpp:299
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:151
constexpr auto zip
A zip view.
Definition: zip.hpp:29
The internal SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
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)
Adaptations of concepts from the Ranges TS.
T reserve(T... args)
Provides seqan3::detail::search_configurator.
Provides seqan3::detail::search_traits.
Handles the sequential execution of algorithms.
Definition: execution_handler_sequential.hpp:34
Class used to validate the search configuration.
Definition: search.hpp:37
static void validate_query_type()
Validates the query type to model std::ranges::random_access_range and std::ranges::sized_range.
Definition: search.hpp:43
A collection of traits extracted from the search configuration.
Definition: search_traits.hpp:34
Provides seqan3::views::convert.
Provides seqan3::views::zip.