25namespace seqan3::detail
34template <
typename configuration_t,
typename index_t,
typename... policies_t>
35 requires (template_specialisation_of<typename index_t::cursor_type, bi_fm_index_cursor>)
36class search_scheme_algorithm :
protected policies_t...
40 using traits_t = search_traits<configuration_t>;
42 using search_result_type =
typename traits_t::search_result_type;
44 static_assert(!std::same_as<search_result_type, empty_type>,
"The search result type was not configured.");
50 search_scheme_algorithm() =
default;
51 search_scheme_algorithm(search_scheme_algorithm
const &) =
default;
52 search_scheme_algorithm(search_scheme_algorithm &&) =
default;
53 search_scheme_algorithm & operator=(search_scheme_algorithm
const &) =
default;
54 search_scheme_algorithm & operator=(search_scheme_algorithm &&) =
default;
55 ~search_scheme_algorithm() =
default;
68 search_scheme_algorithm(configuration_t
const & cfg, index_t
const & index) : policies_t{cfg}...
70 stratum = cfg.get_or(search_cfg::hit_strata{0}).stratum;
95 template <tuple_like indexed_query_t,
typename callback_t>
96 requires (std::tuple_size_v<indexed_query_t> == 2)
97 && std::ranges::forward_range<std::tuple_element_t<1, indexed_query_t>>
98 && std::invocable<callback_t, search_result_type>
99 void operator()(indexed_query_t && indexed_query, callback_t && callback)
101 auto && [query_idx, query] = indexed_query;
102 auto error_state = this->max_error_counts(query);
106 auto on_hit_delegate = [&internal_hits](
auto const & it)
111 perform_search_by_hit_strategy(internal_hits, query, error_state, on_hit_delegate);
114 this->make_results(std::move(internal_hits), query_idx, callback);
119 index_t
const * index_ptr{
nullptr};
125 template <
bool abort_on_hit,
typename query_t,
typename delegate_t>
126 inline void search_algo_bi(query_t & query, search_param
const error_left, delegate_t && delegate);
135 template <
typename query_t,
typename delegate_t>
138 search_param error_state,
139 delegate_t
const & on_hit_delegate)
141 if constexpr (!traits_t::search_all_hits)
143 auto max_total = error_state.total;
144 error_state.total = 0;
145 while (internal_hits.
empty() && error_state.total <= max_total)
153 constexpr bool abort_on_hit = !traits_t::search_all_best_hits;
154 search_algo_bi<abort_on_hit>(query, error_state, on_hit_delegate);
157 if constexpr (traits_t::search_strata_hits)
159 if (!internal_hits.
empty())
161 internal_hits.
clear();
162 error_state.total += stratum - 1;
163 search_algo_bi<false>(query, error_state, on_hit_delegate);
171 search_algo_bi<false>(query, error_state, on_hit_delegate);
217template <
typename search_scheme_t>
218inline auto search_scheme_block_info(search_scheme_t
const & search_scheme,
size_t const query_length)
220 using blocks_length_type =
typename search_scheme_t::value_type::blocks_length_type;
222 constexpr bool is_dyn_scheme = std::same_as<search_scheme_t, search_scheme_dyn_type>;
229 transformation_trait_or_t<std::tuple_size<search_scheme_t>,
std::false_type>::value>>;
232 if constexpr (is_dyn_scheme)
233 result.resize(search_scheme.size());
235 uint8_t
const blocks{search_scheme[0].blocks()};
236 size_t const block_length{query_length / blocks};
237 uint8_t
const rest{
static_cast<uint8_t
>(query_length % blocks)};
239 blocks_length_type blocks_length;
242 if constexpr (is_dyn_scheme)
243 blocks_length.resize(blocks, block_length);
245 blocks_length.fill(block_length);
247 for (uint8_t block_id = 0; block_id < rest; ++block_id)
248 ++blocks_length[block_id];
250 for (uint8_t search_id = 0; search_id < search_scheme.size(); ++search_id)
252 auto const &
search = search_scheme[search_id];
254 auto & [search_blocks_length, start_pos] = result[search_id];
258 if constexpr (is_dyn_scheme)
259 search_blocks_length.resize(blocks);
260 search_blocks_length[0] = blocks_length[
search.pi[0] - 1];
261 for (uint8_t i = 1; i < blocks; ++i)
263 search_blocks_length[i] = blocks_length[
search.pi[i] - 1] + search_blocks_length[i - 1];
265 start_pos += search_blocks_length[i] - search_blocks_length[i - 1];
274template <
bool abort_on_hit,
278 typename blocks_length_t,
280inline bool search_ss(cursor_t cur,
282 typename cursor_t::size_type
const lb,
283 typename cursor_t::size_type
const rb,
284 uint8_t
const errors_spent,
285 uint8_t
const block_id,
288 blocks_length_t
const & blocks_length,
289 search_param
const error_left,
290 delegate_t && delegate);
324template <
bool abort_on_hit,
328 typename blocks_length_t,
330inline bool search_ss_exact(cursor_t cur,
332 typename cursor_t::size_type
const lb,
333 typename cursor_t::size_type
const rb,
334 uint8_t
const errors_spent,
335 uint8_t
const block_id,
338 blocks_length_t
const & blocks_length,
339 search_param
const error_left,
340 delegate_t && delegate)
342 using size_type =
typename cursor_t::size_type;
344 uint8_t
const block_id2 = std::min<uint8_t>(block_id + 1,
search.blocks() - 1);
345 bool const go_right2 = (block_id <
search.blocks() - 1) && (
search.pi[block_id + 1] >
search.pi[block_id]);
349 size_type
const infix_lb = rb - 1;
350 size_type
const infix_rb = lb + blocks_length[block_id] - 1;
352 if (!cur.extend_right(query |
views::slice(infix_lb, infix_rb + 1)))
355 if (search_ss<abort_on_hit>(cur,
373 size_type
const infix_lb = rb - blocks_length[block_id] - 1;
374 size_type
const infix_rb = lb - 1;
376 if (!cur.extend_left(query |
views::slice(infix_lb, infix_rb + 1)))
379 if (search_ss<abort_on_hit>(cur,
404template <
bool abort_on_hit,
408 typename blocks_length_t,
410inline bool search_ss_deletion(cursor_t cur,
412 typename cursor_t::size_type
const lb,
413 typename cursor_t::size_type
const rb,
414 uint8_t
const errors_spent,
415 uint8_t
const block_id,
418 blocks_length_t
const & blocks_length,
419 search_param
const error_left,
420 delegate_t && delegate)
422 uint8_t
const max_error_left_in_block =
search.u[block_id] - errors_spent;
423 uint8_t
const min_error_left_in_block =
std::max(
search.l[block_id] - errors_spent, 0);
426 if (min_error_left_in_block == 0)
428 uint8_t
const block_id2 = std::min<uint8_t>(block_id + 1,
search.blocks() - 1);
429 bool const go_right2 = block_id2 == 0 ? true :
search.pi[block_id2] >
search.pi[block_id2 - 1];
431 if (search_ss<abort_on_hit>(cur,
451 if (!(
search.pi[block_id] == 1 && !go_right) && !(
search.pi[block_id] ==
search.blocks() && go_right)
452 && max_error_left_in_block > 0 && error_left.total > 0 && error_left.deletion > 0
453 && ((go_right && cur.extend_right()) || (!go_right && cur.extend_left())))
455 search_param error_left2{error_left};
457 error_left2.deletion--;
460 if (search_ss_deletion<abort_on_hit>(cur,
476 while ((go_right && cur.cycle_back()) || (!go_right && cur.cycle_front()));
489template <
bool abort_on_hit,
493 typename blocks_length_t,
495inline bool search_ss_children(cursor_t cur,
497 typename cursor_t::size_type
const lb,
498 typename cursor_t::size_type
const rb,
499 uint8_t
const errors_spent,
500 uint8_t
const block_id,
502 uint8_t
const min_error_left_in_block,
504 blocks_length_t
const & blocks_length,
505 search_param
const error_left,
506 delegate_t && delegate)
508 using size_type =
typename cursor_t::size_type;
509 if ((go_right && cur.extend_right()) || (!go_right && cur.extend_left()))
511 size_type
const chars_left = blocks_length[block_id] - (rb - lb - 1);
513 size_type lb2 = lb - !go_right;
514 size_type rb2 = rb + go_right;
518 bool const delta = cur.last_rank() !=
to_rank(query[(go_right ? rb : lb) - 1]);
524 if (error_left.deletion == 0 && chars_left + delta < min_error_left_in_block + 1u)
527 if (!delta || error_left.substitution > 0)
529 search_param error_left2{error_left};
530 error_left2.total -= delta;
531 error_left2.substitution -= delta;
534 if (rb - lb == blocks_length[block_id])
538 if (error_left.deletion > 0)
540 if (search_ss_deletion<abort_on_hit>(cur,
544 errors_spent + delta,
558 uint8_t
const block_id2 = std::min<uint8_t>(block_id + 1,
search.blocks() - 1);
559 bool const go_right2 = block_id2 == 0 ? true :
search.pi[block_id2] >
search.pi[block_id2 - 1];
561 if (search_ss<abort_on_hit>(cur,
565 errors_spent + delta,
580 if (search_ss<abort_on_hit>(cur,
584 errors_spent + delta,
602 if (error_left.deletion > 0 && !(go_right && (rb == 1 || rb ==
std::ranges::size(query) + 1))
605 search_param error_left3{error_left};
607 error_left3.deletion--;
608 search_ss<abort_on_hit>(cur,
621 while ((go_right && cur.cycle_back()) || (!go_right && cur.cycle_front()));
631template <
bool abort_on_hit,
635 typename blocks_length_t,
637inline bool search_ss(cursor_t cur,
639 typename cursor_t::size_type
const lb,
640 typename cursor_t::size_type
const rb,
641 uint8_t
const errors_spent,
642 uint8_t
const block_id,
645 blocks_length_t
const & blocks_length,
646 search_param
const error_left,
647 delegate_t && delegate)
649 uint8_t
const max_error_left_in_block =
search.u[block_id] - errors_spent;
650 uint8_t
const min_error_left_in_block =
std::max(
search.l[block_id] - errors_spent, 0);
653 if (min_error_left_in_block == 0 && lb == 0 && rb ==
std::ranges::size(query) + 1)
659 else if (((max_error_left_in_block == 0) && (rb - lb - 1 != blocks_length[block_id]))
660 || (error_left.total == 0 && min_error_left_in_block == 0))
662 if (search_ss_exact<abort_on_hit>(cur,
680 else if (error_left.total > 0)
683 if (error_left.insertion > 0)
685 using size_type =
typename cursor_t::size_type;
687 size_type
const lb2 = lb - !go_right;
688 size_type
const rb2 = rb + go_right;
690 search_param error_left2{error_left};
692 error_left2.insertion--;
694 if (rb - lb == blocks_length[block_id])
701 if (search_ss_deletion<abort_on_hit>(cur,
719 if (search_ss<abort_on_hit>(cur,
736 if (search_ss_children<abort_on_hit>(cur,
743 min_error_left_in_block,
779template <
bool abort_on_hit,
typename index_t,
typename query_t,
typename search_scheme_t,
typename delegate_t>
780inline void search_ss(index_t
const & index,
782 search_param
const error_left,
783 search_scheme_t
const & search_scheme,
784 delegate_t && delegate)
787 auto const block_info = search_scheme_block_info(search_scheme,
std::ranges::size(query));
789 for (uint8_t search_id = 0; search_id < search_scheme.size(); ++search_id)
791 auto const &
search = search_scheme[search_id];
792 auto const & [blocks_length, start_pos] = block_info[search_id];
794 bool const hit = search_ss<abort_on_hit>(index.cursor(),
808 if (abort_on_hit && hit)
831template <
typename configuration_t,
typename index_t,
typename... policies_t>
832 requires (template_specialisation_of<typename index_t::cursor_type, bi_fm_index_cursor>)
833template <bool abort_on_hit, typename query_t, typename delegate_t>
834inline void search_scheme_algorithm<configuration_t, index_t, policies_t...>::search_algo_bi(
836 search_param
const error_left,
837 delegate_t && delegate)
839 switch (error_left.total)
842 search_ss<abort_on_hit>(*index_ptr, query, error_left, optimum_search_scheme<0, 0>, delegate);
845 search_ss<abort_on_hit>(*index_ptr, query, error_left, optimum_search_scheme<0, 1>, delegate);
848 search_ss<abort_on_hit>(*index_ptr, query, error_left, optimum_search_scheme<0, 2>, delegate);
851 search_ss<abort_on_hit>(*index_ptr, query, error_left, optimum_search_scheme<0, 3>, delegate);
854 auto const & search_scheme{compute_ss(0, error_left.total)};
855 search_ss<abort_on_hit>(*index_ptr, query, error_left, search_scheme, delegate);
Provides the bidirectional seqan3::bi_fm_index.
constexpr auto to_rank
Return the rank representation of a (semi-)alphabet object.
Definition: concept.hpp:155
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: traits.hpp:146
constexpr auto slice
A view adaptor that returns a half-open interval on the underlying range.
Definition: slice.hpp:178
Provides the concept for seqan3::detail::sdsl_index.
Provides data structures used by different search algorithms.
Provides the data structures and precomputed instances for (optimum) search schemes.
Provides seqan3::detail::search_traits.
Provides seqan3::views::slice.