15 #include <type_traits>
24 namespace seqan3::detail
36 class 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;
67 search_scheme_algorithm(configuration_t
const & cfg, index_t
const & index) : policies_t{cfg}...
69 stratum = cfg.get_or(search_cfg::hit_strata{0}).stratum;
94 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>
100 void operator()(indexed_query_t && indexed_query, callback_t && callback)
102 auto && [query_idx, query] = indexed_query;
103 auto error_state = this->max_error_counts(query);
107 auto on_hit_delegate = [&internal_hits] (
auto const & it)
112 perform_search_by_hit_strategy(internal_hits, query, error_state, on_hit_delegate);
115 this->make_results(
std::move(internal_hits), query_idx, callback);
120 index_t
const * index_ptr{
nullptr};
126 template <
bool abort_on_hit,
typename query_t,
typename delegate_t>
127 inline void search_algo_bi(query_t & query, search_param
const error_left, delegate_t && delegate);
136 template <
typename query_t,
typename delegate_t>
139 search_param error_state,
140 delegate_t
const & on_hit_delegate)
142 if constexpr (!traits_t::search_all_hits)
144 auto max_total = error_state.total;
145 error_state.total = 0;
146 while (internal_hits.
empty() && error_state.total <= max_total)
154 constexpr
bool abort_on_hit = !traits_t::search_all_best_hits;
155 search_algo_bi<abort_on_hit>(query, error_state, on_hit_delegate);
158 if constexpr (traits_t::search_strata_hits)
160 if (!internal_hits.
empty())
162 internal_hits.
clear();
163 error_state.total += stratum - 1;
164 search_algo_bi<false>(query, error_state, on_hit_delegate);
172 search_algo_bi<false>(query, error_state, on_hit_delegate);
216 template <
typename search_scheme_t>
217 inline auto search_scheme_block_info(search_scheme_t
const & search_scheme,
size_t const query_length)
219 using blocks_length_type =
typename search_scheme_t::value_type::blocks_length_type;
221 bool constexpr is_dyn_scheme = std::same_as<search_scheme_t, search_scheme_dyn_type>;
227 transformation_trait_or_t<std::tuple_size<search_scheme_t>,
231 if constexpr (is_dyn_scheme)
232 result.resize(search_scheme.size());
234 uint8_t
const blocks {search_scheme[0].blocks()};
235 size_t const block_length{query_length / blocks};
236 uint8_t
const rest {
static_cast<uint8_t
>(query_length % blocks)};
238 blocks_length_type blocks_length;
241 if constexpr (is_dyn_scheme)
242 blocks_length.resize(blocks, block_length);
244 blocks_length.fill(block_length);
246 for (uint8_t block_id = 0; block_id < rest; ++block_id)
247 ++blocks_length[block_id];
249 for (uint8_t search_id = 0; search_id < search_scheme.size(); ++search_id)
251 auto const &
search = search_scheme[search_id];
253 auto & [search_blocks_length, start_pos] = result[search_id];
257 if constexpr (is_dyn_scheme)
258 search_blocks_length.resize(blocks);
259 search_blocks_length[0] = blocks_length[
search.pi[0] - 1];
260 for (uint8_t i = 1; i < blocks; ++i)
262 search_blocks_length[i] = blocks_length[
search.pi[i] - 1] + search_blocks_length[i - 1];
264 start_pos += search_blocks_length[i] - search_blocks_length[i - 1];
273 template <
bool abort_on_hit,
typename cursor_t,
typename query_t,
typename search_t,
typename blocks_length_t,
275 inline bool search_ss(cursor_t cur, query_t & query,
276 typename cursor_t::size_type
const lb,
typename cursor_t::size_type
const rb,
277 uint8_t
const errors_spent, uint8_t
const block_id,
bool const go_right, search_t
const &
search,
278 blocks_length_t
const & blocks_length, search_param
const error_left, delegate_t && delegate);
311 template <
bool abort_on_hit,
typename cursor_t,
typename query_t,
typename search_t,
typename blocks_length_t,
313 inline bool search_ss_exact(cursor_t cur, query_t & query,
314 typename cursor_t::size_type
const lb,
typename cursor_t::size_type
const rb,
315 uint8_t
const errors_spent, uint8_t
const block_id,
bool const go_right,
316 search_t
const &
search, blocks_length_t
const & blocks_length,
317 search_param
const error_left, delegate_t && delegate)
319 using size_type =
typename cursor_t::size_type;
321 uint8_t
const block_id2 = std::min<uint8_t>(block_id + 1,
search.blocks() - 1);
322 bool const go_right2 = (block_id <
search.blocks() - 1) && (
search.pi[block_id + 1] >
search.pi[block_id]);
326 size_type
const infix_lb = rb - 1;
327 size_type
const infix_rb = lb + blocks_length[block_id] - 1;
329 if (!cur.extend_right(query |
views::slice(infix_lb, infix_rb + 1)))
332 if (search_ss<abort_on_hit>(cur, query, lb, infix_rb + 2, errors_spent, block_id2, go_right2,
search,
333 blocks_length, error_left, delegate) && abort_on_hit)
340 size_type
const infix_lb = rb - blocks_length[block_id] - 1;
341 size_type
const infix_rb = lb - 1;
343 if (!cur.extend_left(query |
views::slice(infix_lb, infix_rb + 1)))
346 if (search_ss<abort_on_hit>(cur, query, infix_lb, rb, errors_spent, block_id2, go_right2,
search, blocks_length,
347 error_left, delegate) && abort_on_hit)
360 template <
bool abort_on_hit,
typename cursor_t,
typename query_t,
typename search_t,
typename blocks_length_t,
362 inline bool search_ss_deletion(cursor_t cur, query_t & query,
363 typename cursor_t::size_type
const lb,
typename cursor_t::size_type
const rb,
364 uint8_t
const errors_spent, uint8_t
const block_id,
bool const go_right,
365 search_t
const &
search, blocks_length_t
const & blocks_length,
366 search_param
const error_left, delegate_t && delegate)
368 uint8_t
const max_error_left_in_block =
search.u[block_id] - errors_spent;
369 uint8_t
const min_error_left_in_block =
std::max(
search.l[block_id] - errors_spent, 0);
372 if (min_error_left_in_block == 0)
374 uint8_t
const block_id2 = std::min<uint8_t>(block_id + 1,
search.blocks() - 1);
375 bool const go_right2 = block_id2 == 0 ? true :
search.pi[block_id2] >
search.pi[block_id2 - 1];
377 if (search_ss<abort_on_hit>(cur, query, lb, rb, errors_spent, block_id2, go_right2,
search, blocks_length,
378 error_left, delegate) && abort_on_hit)
387 if (!(
search.pi[block_id] == 1 && !go_right) &&
388 !(
search.pi[block_id] ==
search.blocks() && go_right) &&
389 max_error_left_in_block > 0 && error_left.total > 0 && error_left.deletion > 0 &&
390 ((go_right && cur.extend_right()) || (!go_right && cur.extend_left())))
392 search_param error_left2{error_left};
394 error_left2.deletion--;
397 if (search_ss_deletion<abort_on_hit>(cur, query, lb, rb, errors_spent + 1, block_id, go_right,
search,
398 blocks_length, error_left2, delegate) && abort_on_hit)
402 }
while ((go_right && cur.cycle_back()) || (!go_right && cur.cycle_front()));
414 template <
bool abort_on_hit,
typename cursor_t,
typename query_t,
typename search_t,
typename blocks_length_t,
416 inline bool search_ss_children(cursor_t cur, query_t & query,
417 typename cursor_t::size_type
const lb,
typename cursor_t::size_type
const rb,
418 uint8_t
const errors_spent, uint8_t
const block_id,
bool const go_right,
419 uint8_t
const min_error_left_in_block, search_t
const &
search,
420 blocks_length_t
const & blocks_length, search_param
const error_left,
421 delegate_t && delegate)
423 using size_type =
typename cursor_t::size_type;
424 if ((go_right && cur.extend_right()) || (!go_right && cur.extend_left()))
426 size_type
const chars_left = blocks_length[block_id] - (rb - lb - 1);
428 size_type lb2 = lb - !go_right;
429 size_type rb2 = rb + go_right;
433 bool const delta = cur.last_rank() !=
to_rank(query[(go_right ? rb : lb) - 1]);
439 if (error_left.deletion == 0 && chars_left + delta < min_error_left_in_block + 1u)
442 if (!delta || error_left.substitution > 0)
444 search_param error_left2{error_left};
445 error_left2.total -= delta;
446 error_left2.substitution -= delta;
449 if (rb - lb == blocks_length[block_id])
453 if (error_left.deletion > 0)
455 if (search_ss_deletion<abort_on_hit>(cur, query, lb2, rb2, errors_spent + delta, block_id,
456 go_right,
search, blocks_length, error_left2, delegate) &&
464 uint8_t
const block_id2 = std::min<uint8_t>(block_id + 1,
search.blocks() - 1);
465 bool const go_right2 = block_id2 == 0 ? true :
search.pi[block_id2] >
search.pi[block_id2 - 1];
467 if (search_ss<abort_on_hit>(cur, query, lb2, rb2, errors_spent + delta, block_id2, go_right2,
468 search, blocks_length, error_left2, delegate) &&
477 if (search_ss<abort_on_hit>(cur, query, lb2, rb2, errors_spent + delta, block_id, go_right,
search,
478 blocks_length, error_left2, delegate) && abort_on_hit)
489 if (error_left.deletion > 0 &&
493 search_param error_left3{error_left};
495 error_left3.deletion--;
496 search_ss<abort_on_hit>(cur, query, lb, rb, errors_spent + 1, block_id, go_right,
search, blocks_length,
497 error_left3, delegate);
499 }
while ((go_right && cur.cycle_back()) || (!go_right && cur.cycle_front()));
508 template <
bool abort_on_hit,
typename cursor_t,
typename query_t,
typename search_t,
509 typename blocks_length_t,
typename delegate_t>
510 inline bool search_ss(cursor_t cur, query_t & query,
511 typename cursor_t::size_type
const lb,
typename cursor_t::size_type
const rb,
512 uint8_t
const errors_spent, uint8_t
const block_id,
bool const go_right, search_t
const &
search,
513 blocks_length_t
const & blocks_length, search_param
const error_left, delegate_t && delegate)
515 uint8_t
const max_error_left_in_block =
search.u[block_id] - errors_spent;
516 uint8_t
const min_error_left_in_block =
std::max(
search.l[block_id] - errors_spent, 0);
519 if (min_error_left_in_block == 0 && lb == 0 && rb ==
std::ranges::size(query) + 1)
525 else if (((max_error_left_in_block == 0) && (rb - lb - 1 != blocks_length[block_id])) ||
526 (error_left.total == 0 && min_error_left_in_block == 0))
528 if (search_ss_exact<abort_on_hit>(cur, query, lb, rb, errors_spent, block_id, go_right,
search, blocks_length,
529 error_left, delegate) && abort_on_hit)
536 else if (error_left.total > 0)
539 if (error_left.insertion > 0)
541 using size_type =
typename cursor_t::size_type;
543 size_type
const lb2 = lb - !go_right;
544 size_type
const rb2 = rb + go_right;
546 search_param error_left2{error_left};
548 error_left2.insertion--;
550 if (rb - lb == blocks_length[block_id])
557 if (search_ss_deletion<abort_on_hit>(cur, query, lb2, rb2, errors_spent + 1, block_id, go_right,
search,
558 blocks_length, error_left2, delegate) && abort_on_hit)
565 if (search_ss<abort_on_hit>(cur, query, lb2, rb2, errors_spent + 1, block_id, go_right,
search,
566 blocks_length, error_left2, delegate) && abort_on_hit)
572 if (search_ss_children<abort_on_hit>(cur, query, lb, rb, errors_spent, block_id, go_right,
573 min_error_left_in_block,
search, blocks_length, error_left, delegate) &&
603 template <
bool abort_on_hit,
typename index_t,
typename query_t,
typename search_scheme_t,
typename delegate_t>
604 inline void search_ss(index_t
const & index, query_t & query, search_param
const error_left,
605 search_scheme_t
const & search_scheme, delegate_t && delegate)
608 auto const block_info = search_scheme_block_info(search_scheme,
std::ranges::size(query));
610 for (uint8_t search_id = 0; search_id < search_scheme.size(); ++search_id)
612 auto const &
search = search_scheme[search_id];
613 auto const & [blocks_length, start_pos] = block_info[search_id];
615 bool const hit = search_ss<abort_on_hit>(
618 start_pos, start_pos + 1,
628 if (abort_on_hit && hit)
650 template <
typename configuration_t,
typename index_t,
typename ...policies_t>
651 template <
bool abort_on_hit,
typename query_t,
typename delegate_t>
652 inline void search_scheme_algorithm<configuration_t, index_t, policies_t...>::search_algo_bi(
654 search_param
const error_left,
655 delegate_t && delegate)
657 switch (error_left.total)
660 search_ss<abort_on_hit>(*index_ptr, query, error_left, optimum_search_scheme<0, 0>, delegate);
663 search_ss<abort_on_hit>(*index_ptr, query, error_left, optimum_search_scheme<0, 1>, delegate);
666 search_ss<abort_on_hit>(*index_ptr, query, error_left, optimum_search_scheme<0, 2>, delegate);
669 search_ss<abort_on_hit>(*index_ptr, query, error_left, optimum_search_scheme<0, 3>, delegate);
672 auto const & search_scheme{compute_ss(0, error_left.total)};
673 search_ss<abort_on_hit>(*index_ptr, query, error_left, search_scheme, delegate);