15 #include <range/v3/algorithm/for_each.hpp> 16 #include <range/v3/view/drop_exactly.hpp> 17 #include <range/v3/view/zip.hpp> 75 template <
typename config_t,
typename ...algorithm_policies_t>
76 class alignment_algorithm :
77 public invoke_deferred_crtp_base<algorithm_policies_t, alignment_algorithm<config_t, algorithm_policies_t...>>...
88 constexpr alignment_algorithm() =
default;
89 constexpr alignment_algorithm(alignment_algorithm
const &) =
default;
90 constexpr alignment_algorithm(alignment_algorithm &&) =
default;
91 constexpr alignment_algorithm & operator=(alignment_algorithm
const &) =
default;
92 constexpr alignment_algorithm & operator=(alignment_algorithm &&) =
default;
93 ~alignment_algorithm() =
default;
102 explicit constexpr alignment_algorithm(config_t
const & cfg) : cfg_ptr{
new config_t(cfg)}
133 template <std::ranges::ForwardRange first_range_t, std::ranges::ForwardRange second_range_t>
134 auto operator()(
size_t const idx, first_range_t && first_range, second_range_t && second_range)
137 assert(cfg_ptr !=
nullptr);
144 this->allocate_matrix(first_range, second_range);
147 auto cache = this->make_cache(cfg_ptr->template value_or<align_cfg::gap>(gap_scheme{gap_score{-1},
148 gap_open_score{-10}}));
150 initialise_matrix(cache);
156 compute_matrix(first_range, second_range, cache);
162 using result_t =
typename align_result_selector<first_range_t, second_range_t, config_t>::type;
167 if constexpr (config_t::template exists<align_cfg::result<with_score_type>>())
169 res.score = get<3>(cache).score;
171 if constexpr (config_t::template exists<align_cfg::result<with_back_coordinate_type>>())
173 res.score = get<3>(cache).score;
174 res.back_coordinate = get<3>(cache).coordinate;
176 if constexpr (config_t::template exists<align_cfg::result<with_front_coordinate_type>>())
180 res.score = get<3>(cache).score;
181 res.back_coordinate = get<3>(cache).coordinate;
182 res.front_coordinate = get<0>(compute_traceback(first_range,
184 get<3>(cache).coordinate));
186 if constexpr (config_t::template exists<align_cfg::result<with_alignment_type>>())
188 res.score = get<3>(cache).score;
189 res.back_coordinate = get<3>(cache).coordinate;
190 std::tie(res.front_coordinate, res.alignment) = compute_traceback(first_range,
192 get<3>(cache).coordinate);
194 return alignment_result{res};
225 template <std::ranges::ForwardRange first_range_t, std::ranges::ForwardRange second_range_t>
226 auto operator()(
size_t const idx, first_range_t && first_range, second_range_t && second_range)
229 assert(cfg_ptr !=
nullptr);
233 static_assert(config_t::template exists<align_cfg::band>(),
234 "The band configuration is required for the banded alignment algorithm.");
235 auto const & band = get<align_cfg::band>(*cfg_ptr).value;
242 static_assert(std::is_signed_v<diff_type>,
"Only signed types can be used to test the band parameters.");
246 throw invalid_alignment_configuration
248 "Invalid band error: The lower bound excludes the whole alignment matrix." 254 throw invalid_alignment_configuration
256 "Invalid band error: The upper bound excludes the whole alignment matrix." 265 auto [trimmed_first_range, trimmed_second_range] =
266 this->trim_sequences(first_range, second_range, band);
268 this->allocate_matrix(trimmed_first_range, trimmed_second_range, band);
271 auto const & gap = cfg_ptr->template value_or<align_cfg::gap>(gap_scheme{gap_score{-1}, gap_open_score{-10}});
274 auto cache = this->make_cache(gap);
276 initialise_matrix(cache);
282 compute_banded_matrix(trimmed_first_range, trimmed_second_range, cache);
288 using result_t =
typename align_result_selector<first_range_t, second_range_t, config_t>::type;
294 this->balance_leading_gaps(get<3>(cache), band, gap);
296 this->balance_trailing_gaps(get<3>(cache),
297 this->dimension_first_range,
298 this->dimension_second_range,
302 if constexpr (config_t::template exists<align_cfg::result<detail::with_score_type>>())
304 res.score = get<3>(cache).score;
306 if constexpr (config_t::template exists<align_cfg::result<with_back_coordinate_type>>())
308 res.score = get<3>(cache).score;
309 res.back_coordinate = this->map_banded_coordinate_to_range_position(get<3>(cache).coordinate);
311 if constexpr (config_t::template exists<align_cfg::result<with_front_coordinate_type>>())
315 res.score = get<3>(cache).score;
316 res.back_coordinate = this->map_banded_coordinate_to_range_position(get<3>(cache).coordinate);
317 res.front_coordinate =
318 get<0>(compute_traceback(first_range,
320 get<3>(cache).coordinate));
322 if constexpr (config_t::template exists<align_cfg::result<with_alignment_type>>())
324 res.score = get<3>(cache).score;
325 res.back_coordinate = this->map_banded_coordinate_to_range_position(get<3>(cache).coordinate);
326 std::tie(res.front_coordinate, res.alignment) = compute_traceback(first_range,
328 get<3>(cache).coordinate);
330 return alignment_result{res};
338 template <
typename cache_t>
339 void initialise_matrix(cache_t & cache)
342 auto col = this->current_column();
346 ranges::for_each(col | ranges::view::drop_exactly(1), [&cache,
this](
auto && cell)
348 this->init_column_cell(
std::forward<decltype(cell)>(cell), cache);
353 if constexpr (is_banded)
355 alignment_optimum current{get<0>(get<0>(std::move(cell))),
static_cast<alignment_coordinate
>(coordinate)};
356 this->check_score_last_row(current, get<3>(cache));
360 alignment_optimum current{get<0>(std::move(cell)), static_cast<alignment_coordinate>(coordinate)};
361 this->check_score_last_row(current, get<3>(cache));
373 template <
typename first_range_t,
374 typename second_range_t,
376 void compute_matrix(first_range_t & first_range,
377 second_range_t & second_range,
381 auto const & score_scheme = get<align_cfg::scoring>(*cfg_ptr).value;
382 ranges::for_each(first_range, [&,
this](
auto seq1_value)
385 this->go_next_column();
387 auto col = this->current_column();
391 ranges::for_each(col | ranges::view::drop_exactly(1), [&,
this] (
auto && cell)
393 this->compute_cell(cell, cache, score_scheme.score(seq1_value, *second_range_it));
400 alignment_optimum current{get<0>(std::move(cell)), static_cast<alignment_coordinate>(coordinate)};
401 this->check_score_last_row(current, get<3>(cache));
408 return std::tuple{get<0>(std::forward<decltype(entry)>(entry)),
409 get<1>(std::forward<decltype(entry)>(entry))};
411 this->check_score_last_column(last_column_view, get<3>(cache));
422 template <
typename first_range_t,
423 typename second_range_t,
425 void compute_banded_matrix(first_range_t & first_range,
426 second_range_t & second_range,
429 auto const & score_scheme = get<align_cfg::scoring>(*cfg_ptr).value;
434 ranges::for_each(first_range |
view::take_exactly(this->band_column_index), [&,
this](
auto first_range_value)
436 this->go_next_column();
437 auto col = this->current_column();
441 ranges::for_each(col | ranges::view::drop_exactly(1), [&,
this] (
auto && cell)
445 score_scheme.score(first_range_value, *second_range_it));
449 if (this->band_touches_last_row())
453 alignment_optimum current{get<0>(get<0>(std::move(cell))),
454 static_cast<alignment_coordinate
>(coordinate)};
455 this->check_score_last_row(current, get<3>(cache));
464 ranges::for_each(first_range | ranges::view::drop_exactly(this->band_column_index),
465 [&,
this](
auto first_range_value)
467 this->go_next_column();
468 auto col = this->current_column();
477 score_scheme.score(first_range_value, *second_range_it));
481 ranges::for_each(col | ranges::view::drop_exactly(1), [&,
this] (
auto && cell)
485 score_scheme.score(first_range_value, *second_range_it));
489 if (this->band_touches_last_row())
493 alignment_optimum current{get<0>(get<0>(std::move(cell))),
494 static_cast<alignment_coordinate
>(coordinate)};
495 this->check_score_last_row(current, get<3>(cache));
501 return std::tuple{get<0>(get<0>(std::forward<decltype(entry)>(entry))),
504 this->check_score_last_column(last_column_view, get<3>(cache));
519 template <
typename first_range_t,
typename second_range_t>
520 auto compute_traceback(first_range_t & first_range,
521 second_range_t & second_range,
522 alignment_coordinate back_coordinate)
525 auto [front_coordinate, first_gap_segments, second_gap_segments] = this->parse_traceback(back_coordinate);
527 using result_type =
typename align_result_selector<first_range_t, second_range_t, config_t>::type;
528 using aligned_seq_type = decltype(result_type{}.alignment);
533 auto fill_aligned_sequence = [] (
auto & aligned_sequence,
auto & gap_segments,
size_t const normalise)
538 for (
auto const & gap_elem : gap_segments)
542 insert_gap(aligned_sequence, it, gap_elem.size);
543 offset += gap_elem.size;
549 if constexpr (is_banded)
550 back_coordinate = this->map_banded_coordinate_to_range_position(back_coordinate);
553 auto first_subrange =
view::slice(first_range, front_coordinate.first, back_coordinate.first);
556 auto second_subrange =
view::slice(second_range, front_coordinate.second, back_coordinate.second);
559 aligned_seq_type aligned_seq;
562 fill_aligned_sequence(std::get<0>(aligned_seq), first_gap_segments, front_coordinate.first);
563 fill_aligned_sequence(std::get<1>(aligned_seq), second_gap_segments, front_coordinate.second);
565 return std::tuple{front_coordinate, aligned_seq};
569 return std::tuple{front_coordinate, std::ignore};
Provides seqan3::view::get.
::ranges::distance distance
Alias for ranges::distance. Returns the number of hops from first to last.
Definition: iterator:321
void assign_unaligned(aligned_seq_t &aligned_seq, unaligned_sequence_type &&unaligned_seq)
An implementation of seqan3::AlignedSequence::assign_unaligned_sequence for sequence containers...
Definition: aligned_sequence_concept.hpp:345
aligned_seq_t::iterator insert_gap(aligned_seq_t &aligned_seq, typename aligned_seq_t::const_iterator pos_it)
An implementation of seqan3::AlignedSequence::insert_gap for sequence containers. ...
Definition: aligned_sequence_concept.hpp:229
::ranges::prev prev
Alias for ranges::prev. Returns the nth predecessor of the given iterator.
Definition: iterator:326
Meta-header for the alignment configuration module .
Includes the AlignedSequence and the related insert_gap and erase_gap functions to enable stl contain...
Provides C++20 additions to the <iterator> header.
Provides seqan3::gap_scheme.
constexpr auto slice
A view adaptor that returns a half-open interval on the underlying range.
Definition: slice.hpp:144
Provides seqan3::detail::deferred_crtp_base.
Provides seqan3::detail::unbanded_score_dp_matrix_policy.
Provides seqan3::TupleLike.
auto constexpr take_exactly
A view adaptor that returns the first size elements from the underlying range (or less if the underly...
Definition: take_exactly.hpp:80
Provides seqan3::detail::affine_gap_init_policy.
Adaptations of concepts from the Ranges TS.
::ranges::begin begin
Alias for ranges::begin. Returns an iterator to the beginning of a range.
Definition: ranges:174
::ranges::advance advance
Alias for ranges::advance. Advances the iterator by the given distance.
Definition: iterator:316
Provides seqan3::detail::affine_gap_policy.
Definition: aligned_sequence_concept.hpp:35
auto const get
A view calling std::get on each element in a range.
Definition: get.hpp:66
Provides seqan3::detail::align_result_selector.
Provides seqan3::scoring_scheme_base.
Provides seqan3::view::slice.
::ranges::empty empty
Alias for ranges::empty. Checks whether a range is empty.
Definition: ranges:194
Includes customized exception types for the alignment module .
::ranges::end end
Alias for ranges::end. Returns an iterator to the end of a range.
Definition: ranges:179
constexpr auto transform
A range adaptor that takes a invocable and returns a view of the elements with the invocable applied...
Definition: ranges:911
Provides seqan3::debug_stream and related types.
Provides seqan3::view::take_exactly and seqan3::view::take_exactly_or_throw.
Whether a type behaves like a tuple.