SeqAn3  3.0.3
The Modern C++ library for sequence analysis.
pairwise_alignment_algorithm_banded.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/concepts>
16 #include <seqan3/std/ranges>
17 
21 
22 namespace seqan3::detail
23 {
24 
30 template <typename alignment_configuration_t, typename ...policies_t>
32  requires is_type_specialisation_of_v<alignment_configuration_t, configuration>
34 class pairwise_alignment_algorithm_banded :
35  protected pairwise_alignment_algorithm<alignment_configuration_t, policies_t...>
36 {
37 protected:
39  using base_algorithm_t = pairwise_alignment_algorithm<alignment_configuration_t, policies_t...>;
40 
41  // Import types from base class.
42  using typename base_algorithm_t::traits_type;
43  using typename base_algorithm_t::alignment_result_type;
44  using typename base_algorithm_t::score_type;
45 
46  static_assert(!std::same_as<alignment_result_type, empty_type>, "Alignment result type was not configured.");
47  static_assert(traits_type::is_banded, "Alignment configuration must have band configured.");
48 
49 public:
53  pairwise_alignment_algorithm_banded() = default;
54  pairwise_alignment_algorithm_banded(pairwise_alignment_algorithm_banded const &) = default;
55  pairwise_alignment_algorithm_banded(pairwise_alignment_algorithm_banded &&) = default;
56  pairwise_alignment_algorithm_banded & operator=(pairwise_alignment_algorithm_banded const &) = default;
57  pairwise_alignment_algorithm_banded & operator=(pairwise_alignment_algorithm_banded &&) = default;
58  ~pairwise_alignment_algorithm_banded() = default;
59 
69  pairwise_alignment_algorithm_banded(alignment_configuration_t const & config) : base_algorithm_t(config)
70  {}
72 
77  template <indexed_sequence_pair_range indexed_sequence_pairs_t, typename callback_t>
79  requires std::invocable<callback_t, alignment_result_type>
81  void operator()(indexed_sequence_pairs_t && indexed_sequence_pairs, callback_t && callback)
82  {
83  using std::get;
84 
85  for (auto && [sequence_pair, idx] : indexed_sequence_pairs)
86  {
87  size_t sequence1_size = std::ranges::distance(get<0>(sequence_pair));
88  size_t const sequence2_size = std::ranges::distance(get<1>(sequence_pair));
89 
90  auto && [alignment_matrix, index_matrix] = this->acquire_matrices(sequence1_size,
91  sequence2_size,
92  this->lowest_viable_score());
93 
94  // Initialise the cell updater with the dimensions of the regular matrix.
95  this->compare_and_set_optimum.set_target_indices(row_index_type{sequence2_size},
96  column_index_type{sequence1_size});
97 
98  // Shrink the first sequence if the band ends before its actual end.
99  sequence1_size = std::min(sequence1_size, this->upper_diagonal + sequence2_size);
100 
101  using sequence1_difference_t = std::ranges::range_difference_t<decltype(get<0>(sequence_pair))>;
102 
103  compute_matrix(std::views::take(get<0>(sequence_pair), static_cast<sequence1_difference_t>(sequence1_size)),
104  get<1>(sequence_pair),
105  alignment_matrix,
106  index_matrix);
107  this->make_result_and_invoke(std::forward<decltype(sequence_pair)>(sequence_pair),
108  std::move(idx),
109  this->optimal_score,
110  this->optimal_coordinate,
111  alignment_matrix,
112  callback);
113  }
114  }
115 
117  template <indexed_sequence_pair_range indexed_sequence_pairs_t, typename callback_t>
119  requires traits_type::is_vectorised && std::invocable<callback_t, alignment_result_type>
121  auto operator()(indexed_sequence_pairs_t && indexed_sequence_pairs, callback_t && callback)
122  {
123  using simd_collection_t = std::vector<score_type, aligned_allocator<score_type, alignof(score_type)>>;
124  using original_score_t = typename traits_type::original_score_type;
125 
126  // Extract the batch of sequences for the first and the second sequence.
127  auto seq1_collection = indexed_sequence_pairs | views::elements<0> | views::elements<0>;
128  auto seq2_collection = indexed_sequence_pairs | views::elements<0> | views::elements<1>;
129 
130  this->initialise_tracker(seq1_collection, seq2_collection);
131 
132  // Convert batch of sequences to sequence of simd vectors.
133  thread_local simd_collection_t simd_seq1_collection{};
134  thread_local simd_collection_t simd_seq2_collection{};
135 
136  this->convert_batch_of_sequences_to_simd_vector(simd_seq1_collection,
137  seq1_collection,
138  this->scoring_scheme.padding_symbol);
139  this->convert_batch_of_sequences_to_simd_vector(simd_seq2_collection,
140  seq2_collection,
141  this->scoring_scheme.padding_symbol);
142 
143  size_t const sequence1_size = std::ranges::distance(simd_seq1_collection);
144  size_t const sequence2_size = std::ranges::distance(simd_seq2_collection);
145 
146  auto && [alignment_matrix, index_matrix] = this->acquire_matrices(sequence1_size,
147  sequence2_size,
148  this->lowest_viable_score());
149 
150  compute_matrix(simd_seq1_collection, simd_seq2_collection, alignment_matrix, index_matrix);
151 
152  size_t index = 0;
153  for (auto && [sequence_pair, idx] : indexed_sequence_pairs)
154  {
155  original_score_t score = this->optimal_score[index] -
156  (this->padding_offsets[index] * this->scoring_scheme.padding_match_score());
157  matrix_coordinate coordinate{row_index_type{size_t{this->optimal_coordinate.row[index]}},
158  column_index_type{size_t{this->optimal_coordinate.col[index]}}};
159  this->make_result_and_invoke(std::forward<decltype(sequence_pair)>(sequence_pair),
160  std::move(idx),
161  std::move(score),
162  std::move(coordinate),
163  alignment_matrix,
164  callback);
165  ++index;
166  }
167  }
169 
170 protected:
223  template <std::ranges::forward_range sequence1_t,
224  std::ranges::forward_range sequence2_t,
225  std::ranges::input_range alignment_matrix_t,
226  std::ranges::input_range index_matrix_t>
228  requires std::ranges::forward_range<std::ranges::range_reference_t<alignment_matrix_t>> &&
229  std::ranges::forward_range<std::ranges::range_reference_t<index_matrix_t>>
231  void compute_matrix(sequence1_t && sequence1,
232  sequence2_t && sequence2,
233  alignment_matrix_t && alignment_matrix,
234  index_matrix_t && index_matrix)
235  {
236  // ---------------------------------------------------------------------
237  // Initialisation phase: allocate memory and initialise first column.
238  // ---------------------------------------------------------------------
239 
240  this->reset_optimum(); // Reset the tracker for the new alignment computation.
241 
242  auto alignment_matrix_it = alignment_matrix.begin();
243  auto indexed_matrix_it = index_matrix.begin();
244 
245  using row_index_t = std::ranges::range_difference_t<sequence2_t>; // row_size = |sequence2| + 1
246  using column_index_t = std::ranges::range_difference_t<sequence1_t>; // column_size = |sequence1| + 1
247 
248  row_index_t row_size = std::max<int32_t>(0, -this->lower_diagonal);
249  column_index_t const column_size = std::max<int32_t>(0, this->upper_diagonal);
250  this->initialise_column(*alignment_matrix_it, *indexed_matrix_it, std::views::take(sequence2, row_size));
251 
252  // ---------------------------------------------------------------------
253  // 1st recursion phase: band intersects with the first row.
254  // ---------------------------------------------------------------------
255 
256  for (auto alphabet1 : std::views::take(sequence1, column_size))
257  {
258  this->compute_column(*++alignment_matrix_it,
259  *++indexed_matrix_it,
260  alphabet1,
261  std::views::take(sequence2, ++row_size));
262  }
263 
264  // ---------------------------------------------------------------------
265  // 2nd recursion phase: iterate until the end of the matrix.
266  // ---------------------------------------------------------------------
267 
268  row_index_t first_row_index = 0u;
269  for (auto alphabet1 : std::views::drop(sequence1, column_size))
270  {
271  compute_band_column(*++alignment_matrix_it,
272  std::views::drop(*++indexed_matrix_it, first_row_index + 1),
273  alphabet1,
274  views::slice(sequence2, first_row_index, ++row_size));
275  ++first_row_index;
276  }
277 
278  // ---------------------------------------------------------------------
279  // Final phase: track score of last column
280  // ---------------------------------------------------------------------
281 
282  auto alignment_column = *alignment_matrix_it;
283  auto cell_index_column = std::views::drop(*indexed_matrix_it, first_row_index);
284 
285  auto alignment_column_it = alignment_column.begin();
286  auto cell_index_column_it = cell_index_column.begin();
287 
288  this->track_last_column_cell(*alignment_column_it, *cell_index_column_it);
289 
290  for (row_index_t last_row = std::min<row_index_t>(std::ranges::distance(sequence2), row_size);
291  first_row_index < last_row;
292  ++first_row_index)
293  this->track_last_column_cell(*++alignment_column_it, *++cell_index_column_it);
294 
295  this->track_final_cell(*alignment_column_it, *cell_index_column_it);
296  }
297 
349  template <std::ranges::forward_range alignment_column_t,
350  std::ranges::input_range cell_index_column_t,
351  typename alphabet1_t,
352  std::ranges::input_range sequence2_t>
353  void compute_band_column(alignment_column_t && alignment_column,
354  cell_index_column_t && cell_index_column,
355  alphabet1_t const & alphabet1,
356  sequence2_t && sequence2)
357  {
358  // ---------------------------------------------------------------------
359  // Initial phase: prepare column and initialise first cell
360  // ---------------------------------------------------------------------
361 
362  auto current_alignment_column_it = alignment_column.begin();
363  auto cell_index_column_it = cell_index_column.begin();
364 
365  // Points to the last valid cell in the column.
366  decltype(current_alignment_column_it) next_alignment_column_it{current_alignment_column_it};
367  auto cell = *current_alignment_column_it;
368  cell = this->track_cell(
369  this->initialise_band_first_cell(cell.best_score(),
370  *++next_alignment_column_it,
371  this->scoring_scheme.score(alphabet1, *std::ranges::begin(sequence2))),
372  *cell_index_column_it);
373 
374  // ---------------------------------------------------------------------
375  // Iteration phase: iterate over column and compute each cell
376  // ---------------------------------------------------------------------
377 
378  for (auto && alphabet2 : sequence2 | std::views::drop(1))
379  {
380  current_alignment_column_it = next_alignment_column_it;
381  auto cell = *current_alignment_column_it;
382  cell = this->track_cell(
383  this->compute_inner_cell(cell.best_score(),
384  *++next_alignment_column_it,
385  this->scoring_scheme.score(alphabet1, alphabet2)),
386  *++cell_index_column_it);
387  }
388 
389  // ---------------------------------------------------------------------
390  // Final phase: track last cell
391  // ---------------------------------------------------------------------
392 
393  this->track_last_row_cell(*current_alignment_column_it, *cell_index_column_it);
394  }
395 };
396 
397 } // namespace seqan3::detail
The Concepts library.
T forward(T... args)
typename decltype(detail::split_after< i >(list_t{}))::first_type take
Return a seqan3::type_list of the first n types in the input type list.
Definition: traits.hpp:368
typename decltype(detail::split_after< i >(list_t{}))::second_type drop
Return a seqan3::type_list of the types in the input type list, except the first n.
Definition: traits.hpp:388
constexpr auto get
A view calling get on each element in a range.
Definition: elements.hpp:114
constexpr auto slice
A view adaptor that returns a half-open interval on the underlying range.
Definition: slice.hpp:189
auto const move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:74
T min(T... args)
Provides seqan3::detail::pairwise_alignment_algorithm.
Adaptations of concepts from the Ranges TS.
[DEPRECATED] Provides seqan3::views::take.
Provides seqan3::views::slice.