25 #include <seqan3/alignment/pairwise/policy/all.hpp>
42 namespace seqan3::detail
52 template <
typename config_t>
54 requires is_type_specialisation_of_v<config_t, configuration> && config_t::template exists<align_cfg::result>()
56 struct align_config_result_score
64 using type =
typename result_config_t::score_type;
76 template <
typename range_type,
77 typename alignment_config_type>
78 struct alignment_contract
87 using first_seq_t = std::tuple_element_t<0, value_type_t<std::ranges::iterator_t<unref_range_type>>>;
89 using second_seq_t = std::tuple_element_t<1, value_type_t<std::ranges::iterator_t<unref_range_type>>>;
94 constexpr
static bool expects_tuple_like_value_type()
97 std::tuple_size_v<value_type_t<std::ranges::iterator_t<unref_range_type>>> == 2;
101 constexpr
static bool expects_valid_scoring_scheme()
103 if constexpr (alignment_config_type::template exists<align_cfg::scoring>())
106 decltype(get<align_cfg::scoring>(std::declval<alignment_config_type>()).value)
109 value_type_t<first_seq_t>,
110 value_type_t<second_seq_t>>);
119 constexpr
static bool expects_alignment_configuration()
121 return alignment_config_type::template exists<align_cfg::mode>();
129 struct alignment_configurator
136 template <
typename traits_t>
137 struct select_matrix_policy
141 static constexpr
bool only_coordinates = traits_t::result_type_rank < with_front_coordinate_type::rank;
145 alignment_score_matrix_one_column_banded<typename traits_t::score_t>,
146 alignment_score_matrix_one_column<typename traits_t::score_t>>;
149 alignment_trace_matrix_full_banded<
typename traits_t::trace_t,
151 alignment_trace_matrix_full<
typename traits_t::trace_t,
156 using type = deferred_crtp_base<alignment_matrix_policy, score_matrix_t, trace_matrix_t>;
162 template <
typename traits_t>
163 struct select_gap_policy
167 using score_t =
typename traits_t::score_t;
174 deferred_crtp_base<simd_affine_gap_policy, score_t, is_local_t>,
175 deferred_crtp_base<affine_gap_policy, score_t, is_local_t>>;
184 template <
typename traits_t,
typename policy_traits_t>
185 struct select_find_optimum_policy
189 using score_t =
typename traits_t::score_t;
191 static constexpr
bool is_global_alignment = traits_t::is_global && !traits_t::is_aligned_ends;
196 deferred_crtp_base<simd_find_optimum_policy,
200 deferred_crtp_base<find_optimum_policy, policy_traits_t>>;
229 template <align_pairwise_range_input sequences_t,
typename config_t>
231 requires is_type_specialisation_of_v<config_t, configuration>
233 static constexpr
auto configure(config_t
const & cfg)
236 if constexpr (!config_t::template exists<align_cfg::result>())
239 return configure<sequences_t>(cfg | align_cfg::result{with_score});
247 using first_seq_t = std::tuple_element_t<0, value_type_t<sequences_t>>;
248 using second_seq_t = std::tuple_element_t<1, value_type_t<sequences_t>>;
250 using wrapped_first_t = type_reduce_view<first_seq_t &>;
251 using wrapped_second_t = type_reduce_view<second_seq_t &>;
254 using indexed_sequence_pair_range_t =
typename chunked_indexed_sequence_pairs<sequences_t>::type;
255 using indexed_sequence_pair_chunk_t = std::ranges::range_value_t<indexed_sequence_pair_range_t>;
258 using result_t = alignment_result<typename align_result_selector<std::remove_reference_t<wrapped_first_t>,
265 using function_wrapper_t =
std::function<result_collection_t(indexed_sequence_pair_chunk_t)>;
271 using alignment_contract_t = alignment_contract<sequences_t, config_t>;
273 static_assert(alignment_contract_t::expects_alignment_configuration(),
274 "Alignment configuration error: "
275 "The alignment can only be configured with alignment configurations.");
277 static_assert(alignment_contract_t::expects_tuple_like_value_type(),
278 "Alignment configuration error: "
279 "The value type of the sequence ranges must model the seqan3::tuple_like "
280 "and must contain exactly 2 elements.");
282 static_assert(alignment_contract_t::expects_valid_scoring_scheme(),
283 "Alignment configuration error: "
284 "Either the scoring scheme was not configured or the given scoring scheme cannot be invoked with "
285 "the value types of the passed sequences.");
292 auto const & gaps = cfg.template value_or<align_cfg::gap>(gap_scheme{gap_score{-1}});
294 auto align_ends_cfg = cfg.template value_or<align_cfg::aligned_ends>(free_ends_none);
296 if constexpr (config_t::template exists<align_cfg::mode<detail::global_alignment_type>>())
299 if (gaps.get_gap_open_score() == 0 &&
300 !(align_ends_cfg[2] || align_ends_cfg[3]) &&
301 align_ends_cfg[0] == align_ends_cfg[1])
306 nucleotide_scoring_scheme>)
310 return std::pair{configure_edit_distance<function_wrapper_t>(cfg), cfg};
320 if (config_t::template exists<align_cfg::max_error>())
321 throw invalid_alignment_configuration{
"The align_cfg::max_error configuration is only allowed for "
322 "the specific edit distance computation."};
324 return std::pair{configure_scoring_scheme<function_wrapper_t>(cfg), cfg};
334 template <
typename function_wrapper_t,
typename config_t>
335 static constexpr function_wrapper_t configure_edit_distance(config_t
const & cfg)
337 using traits_t = alignment_configuration_traits<config_t>;
343 if constexpr (traits_t::is_banded)
344 throw invalid_alignment_configuration{
"Banded alignments are yet not supported."};
351 auto align_ends_cfg = cfg.template value_or<align_cfg::aligned_ends>(free_ends_none);
352 using align_ends_cfg_t =
remove_cvref_t<decltype(align_ends_cfg)>;
354 auto configure_edit_traits = [&] (
auto is_semi_global)
356 struct edit_traits_type
358 using is_semi_global_type [[maybe_unused]] =
remove_cvref_t<decltype(is_semi_global)>;
361 edit_distance_algorithm<remove_cvref_t<config_t>, edit_traits_type> algorithm{cfg};
362 return function_wrapper_t{
std::move(algorithm)};
366 auto has_free_ends_trailing = [&] (
auto first) constexpr
368 if constexpr (!decltype(first)::value)
372 else if constexpr (align_ends_cfg_t::template is_static<1>())
374 #if defined(__GNUC__) && __GNUC__ >= 9
375 constexpr
bool free_ends_trailing = align_ends_cfg_t::template get_static<1>();
377 #else // ^^^ workaround / no workaround vvv
379 #endif // defined(__GNUC__) && __GNUC__ >= 9
383 if (align_ends_cfg[1])
392 if constexpr (align_ends_cfg_t::template is_static<0>())
393 return has_free_ends_trailing(
std::integral_constant<
bool, align_ends_cfg_t::template get_static<0>()>{});
396 if (align_ends_cfg[0])
419 template <
typename function_wrapper_t,
typename ...policies_t,
typename config_t>
420 static constexpr function_wrapper_t configure_free_ends_initialisation(config_t
const & cfg);
438 template <
typename function_wrapper_t,
typename ...policies_t,
typename config_t>
439 static constexpr function_wrapper_t configure_free_ends_optimum_search(config_t
const & cfg);
457 template <
typename function_wrapper_t,
typename config_t>
458 static constexpr function_wrapper_t configure_scoring_scheme(config_t
const & cfg);
474 template <
typename function_wrapper_t,
typename ...policies_t,
typename config_t>
475 static constexpr function_wrapper_t make_algorithm(config_t
const & cfg)
477 using traits_t = alignment_configuration_traits<config_t>;
478 using matrix_policy_t =
typename select_matrix_policy<traits_t>::type;
479 using gap_policy_t =
typename select_gap_policy<traits_t>::type;
481 return alignment_algorithm<config_t, matrix_policy_t, gap_policy_t, policies_t...>{cfg};
486 template <
typename function_wrapper_t,
typename config_t>
487 constexpr function_wrapper_t alignment_configurator::configure_scoring_scheme(config_t
const & cfg)
489 using traits_t = alignment_configuration_traits<config_t>;
491 using alignment_scoring_scheme_t =
492 lazy_conditional_t<traits_t::is_vectorised,
493 lazy<simd_match_mismatch_scoring_scheme,
494 typename traits_t::score_t,
495 typename traits_t::scoring_scheme_alphabet_t,
496 typename traits_t::alignment_mode_t>,
497 typename traits_t::scoring_scheme_t>;
499 using scoring_scheme_policy_t = deferred_crtp_base<scoring_scheme_policy, alignment_scoring_scheme_t>;
500 return configure_free_ends_initialisation<function_wrapper_t, scoring_scheme_policy_t>(cfg);
505 template <
typename function_wrapper_t,
typename ...policies_t,
typename config_t>
506 constexpr function_wrapper_t alignment_configurator::configure_free_ends_initialisation(config_t
const & cfg)
508 using traits_t = alignment_configuration_traits<config_t>;
510 auto align_ends_cfg = cfg.template value_or<align_cfg::aligned_ends>(free_ends_none);
511 using align_ends_cfg_t = decltype(align_ends_cfg);
515 auto configure_leading_both = [&] (
auto first_seq,
auto second_seq) constexpr
518 struct policy_trait_type
520 using free_first_leading_t [[maybe_unused]] = decltype(first_seq);
521 using free_second_leading_t [[maybe_unused]] = decltype(second_seq);
525 using gap_init_policy_t = deferred_crtp_base<affine_gap_init_policy, policy_trait_type>;
526 return configure_free_ends_optimum_search<function_wrapper_t, policies_t..., gap_init_policy_t>(cfg);
529 if constexpr (traits_t::is_local)
537 auto configure_leading_second = [&] (
auto first) constexpr
540 if constexpr (align_ends_cfg_t::template is_static<2>())
543 return configure_leading_both(first, second_t{});
547 if (align_ends_cfg[2])
557 if constexpr (align_ends_cfg_t::template is_static<0>())
560 return configure_leading_second(first_t{});
564 if (align_ends_cfg[0])
576 template <
typename function_wrapper_t,
typename ...policies_t,
typename config_t>
577 constexpr function_wrapper_t alignment_configurator::configure_free_ends_optimum_search(config_t
const & cfg)
579 using traits_t = alignment_configuration_traits<config_t>;
582 auto align_ends_cfg = cfg.template value_or<align_cfg::aligned_ends>(free_ends_none);
583 using align_ends_cfg_t = decltype(align_ends_cfg);
587 auto configure_trailing_both = [&] (
auto first_seq,
auto second_seq) constexpr
589 struct policy_trait_type
592 using find_in_last_row_type [[maybe_unused]] = decltype(first_seq);
593 using find_in_last_column_type [[maybe_unused]] = decltype(second_seq);
597 using find_optimum_t =
typename select_find_optimum_policy<traits_t, policy_trait_type>::type;
598 return make_algorithm<function_wrapper_t, policies_t..., find_optimum_t>(cfg);
601 if constexpr (traits_t::is_local)
609 auto configure_trailing_second = [&] (
auto first) constexpr
612 if constexpr (align_ends_cfg_t::template is_static<3>())
615 return configure_trailing_both(first, second_t{});
619 if (align_ends_cfg[3])
629 if constexpr (align_ends_cfg_t::template is_static<1>())
632 return configure_trailing_second(first_t{});
636 if (align_ends_cfg[1])