SeqAn3  3.0.2
The Modern C++ library for sequence analysis.
pairwise_alignment_algorithm.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2020, 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 
24 
25 namespace seqan3::detail
26 {
27 
44 template <typename alignment_configuration_t, typename ...policies_t>
46  requires is_type_specialisation_of_v<alignment_configuration_t, configuration>
48 class pairwise_alignment_algorithm : protected policies_t...
49 {
50 protected:
52  using traits_type = alignment_configuration_traits<alignment_configuration_t>;
54  using score_type = typename traits_type::score_type;
56  using alignment_result_type = typename traits_type::alignment_result_type;
57 
58  static_assert(!std::same_as<alignment_result_type, empty_type>, "Alignment result type was not configured.");
59 
60 
61 public:
65  pairwise_alignment_algorithm() = default;
66  pairwise_alignment_algorithm(pairwise_alignment_algorithm const &) = default;
67  pairwise_alignment_algorithm(pairwise_alignment_algorithm &&) = default;
68  pairwise_alignment_algorithm & operator=(pairwise_alignment_algorithm const &) = default;
69  pairwise_alignment_algorithm & operator=(pairwise_alignment_algorithm &&) = default;
70  ~pairwise_alignment_algorithm() = default;
71 
79  pairwise_alignment_algorithm(alignment_configuration_t const & config) : policies_t(config)...
80  {}
82 
128  template <indexed_sequence_pair_range indexed_sequence_pairs_t, typename callback_t>
130  requires std::invocable<callback_t, alignment_result_type>
132  void operator()(indexed_sequence_pairs_t && indexed_sequence_pairs, callback_t && callback)
133  {
134  using std::get;
135 
136  for (auto && [sequence_pair, idx] : indexed_sequence_pairs)
137  {
138  size_t const sequence1_size = std::ranges::distance(get<0>(sequence_pair));
139  size_t const sequence2_size = std::ranges::distance(get<1>(sequence_pair));
140 
141  auto && [alignment_matrix, index_matrix] = this->acquire_matrices(sequence1_size, sequence2_size);
142 
143  compute_matrix(get<0>(sequence_pair), get<1>(sequence_pair), alignment_matrix, index_matrix);
144  this->make_result_and_invoke(std::forward<decltype(sequence_pair)>(sequence_pair),
145  std::move(idx),
146  this->optimal_score,
147  this->optimal_coordinate,
148  callback);
149  }
150  }
152 
154  template <indexed_sequence_pair_range indexed_sequence_pairs_t, typename callback_t>
156  requires traits_type::is_vectorised && std::invocable<callback_t, alignment_result_type>
158  auto operator()(indexed_sequence_pairs_t && indexed_sequence_pairs, callback_t && callback)
159  {
160  using simd_collection_t = std::vector<score_type, aligned_allocator<score_type, alignof(score_type)>>;
161  using original_score_t = typename traits_type::original_score_type;
162 
163  // Extract the batch of sequences for the first and the second sequence.
164  auto seq1_collection = indexed_sequence_pairs | views::get<0> | views::get<0>;
165  auto seq2_collection = indexed_sequence_pairs | views::get<0> | views::get<1>;
166 
167  this->initialise_tracker(seq1_collection, seq2_collection);
168 
169  // Convert batch of sequences to sequence of simd vectors.
170  thread_local simd_collection_t simd_seq1_collection{};
171  thread_local simd_collection_t simd_seq2_collection{};
172 
173  convert_batch_of_sequences_to_simd_vector(simd_seq1_collection, seq1_collection, traits_type::padding_symbol);
174  convert_batch_of_sequences_to_simd_vector(simd_seq2_collection, seq2_collection, traits_type::padding_symbol);
175 
176  size_t const sequence1_size = std::ranges::distance(simd_seq1_collection);
177  size_t const sequence2_size = std::ranges::distance(simd_seq2_collection);
178 
179  auto && [alignment_matrix, index_matrix] = this->acquire_matrices(sequence1_size, sequence2_size);
180 
181  compute_matrix(simd_seq1_collection, simd_seq2_collection, alignment_matrix, index_matrix);
182 
183  size_t index = 0;
184  for (auto && [sequence_pair, idx] : indexed_sequence_pairs)
185  {
186  original_score_t score = this->optimal_score[index] -
187  (this->padding_offsets[index] * this->scoring_scheme.padding_match_score());
188  matrix_coordinate coordinate{row_index_type{size_t{this->optimal_coordinate.row[index]}},
189  column_index_type{size_t{this->optimal_coordinate.col[index]}}};
190  this->make_result_and_invoke(std::forward<decltype(sequence_pair)>(sequence_pair),
191  std::move(idx),
192  std::move(score),
193  std::move(coordinate),
194  callback);
195  ++index;
196  }
197  }
198 
199 protected:
219  template <typename simd_sequence_t,
220  std::ranges::forward_range sequence_collection_t,
221  arithmetic padding_symbol_t>
223  requires std::ranges::output_range<simd_sequence_t, score_type>
225  void convert_batch_of_sequences_to_simd_vector(simd_sequence_t & simd_sequence,
226  sequence_collection_t & sequences,
227  padding_symbol_t const & padding_symbol)
228  {
229  assert(static_cast<size_t>(std::ranges::distance(sequences)) <= traits_type::alignments_per_vector);
230 
231  simd_sequence.clear();
232  for (auto && simd_vector_chunk : sequences | views::to_simd<score_type>(padding_symbol))
233  std::ranges::move(simd_vector_chunk, std::cpp20::back_inserter(simd_sequence));
234  }
235 
249  template <std::ranges::forward_range sequence1_t,
250  std::ranges::forward_range sequence2_t,
251  std::ranges::input_range alignment_matrix_t,
252  std::ranges::input_range index_matrix_t>
254  requires std::ranges::forward_range<std::ranges::range_reference_t<alignment_matrix_t>> &&
255  std::ranges::forward_range<std::ranges::range_reference_t<index_matrix_t>>
257  void compute_matrix(sequence1_t && sequence1,
258  sequence2_t && sequence2,
259  alignment_matrix_t && alignment_matrix,
260  index_matrix_t && index_matrix)
261  {
262  // ---------------------------------------------------------------------
263  // Initialisation phase: allocate memory and initialise first column.
264  // ---------------------------------------------------------------------
265 
266  this->reset_optimum(); // Reset the tracker for the new alignment computation.
267 
268  auto alignment_matrix_it = alignment_matrix.begin();
269  auto indexed_matrix_it = index_matrix.begin();
270 
271  initialise_column(*alignment_matrix_it, *indexed_matrix_it, sequence2);
272 
273  // ---------------------------------------------------------------------
274  // Iteration phase: compute column-wise the alignment matrix.
275  // ---------------------------------------------------------------------
276 
277  for (auto sequence1_value : sequence1)
278  compute_column(*++alignment_matrix_it, *++indexed_matrix_it, sequence1_value, sequence2);
279 
280  // ---------------------------------------------------------------------
281  // Final phase: track score of last column
282  // ---------------------------------------------------------------------
283 
284  auto && alignment_column = *alignment_matrix_it;
285  auto && cell_index_column = *indexed_matrix_it;
286 
287  auto alignment_column_it = alignment_column.begin();
288  auto cell_index_column_it = cell_index_column.begin();
289 
290  this->track_last_column_cell(*alignment_column_it, *cell_index_column_it);
291 
292  for ([[maybe_unused]] auto && unused : sequence2)
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 
316  template <std::ranges::input_range alignment_column_t,
317  std::ranges::input_range cell_index_column_t,
318  std::ranges::input_range sequence2_t>
319  void initialise_column(alignment_column_t && alignment_column,
320  cell_index_column_t && cell_index_column,
321  sequence2_t && sequence2)
322  {
323  // ---------------------------------------------------------------------
324  // Initial phase: prepare column and initialise first cell
325  // ---------------------------------------------------------------------
326 
327  auto first_column_it = alignment_column.begin();
328  auto cell_index_column_it = cell_index_column.begin();
329  *first_column_it = this->track_cell(this->initialise_origin_cell(), *cell_index_column_it);
330 
331  // ---------------------------------------------------------------------
332  // Iteration phase: iterate over column and compute each cell
333  // ---------------------------------------------------------------------
334 
335  for ([[maybe_unused]] auto const & unused : sequence2)
336  {
337  ++first_column_it;
338  *first_column_it = this->track_cell(this->initialise_first_column_cell(*first_column_it),
339  *++cell_index_column_it);
340  }
341 
342  // ---------------------------------------------------------------------
343  // Final phase: track last cell of initial column
344  // ---------------------------------------------------------------------
345 
346  this->track_last_row_cell(*first_column_it, *cell_index_column_it);
347  }
348 
367  template <std::ranges::input_range alignment_column_t,
368  std::ranges::input_range cell_index_column_t,
369  typename sequence1_value_t,
370  std::ranges::input_range sequence2_t>
372  requires semialphabet<sequence1_value_t> || simd_concept<sequence1_value_t>
374  void compute_column(alignment_column_t && alignment_column,
375  cell_index_column_t && cell_index_column,
376  sequence1_value_t const & sequence1_value,
377  sequence2_t && sequence2)
378  {
379  using score_type = typename traits_type::score_type;
380 
381  // ---------------------------------------------------------------------
382  // Initial phase: prepare column and initialise first cell
383  // ---------------------------------------------------------------------
384 
385  auto alignment_column_it = alignment_column.begin();
386  auto cell_index_column_it = cell_index_column.begin();
387 
388  auto cell = *alignment_column_it;
389  score_type diagonal = cell.best_score();
390  *alignment_column_it = this->track_cell(this->initialise_first_row_cell(cell), *cell_index_column_it);
391 
392  // ---------------------------------------------------------------------
393  // Iteration phase: iterate over column and compute each cell
394  // ---------------------------------------------------------------------
395 
396  for (auto const & sequence2_value : sequence2)
397  {
398  auto cell = *++alignment_column_it;
399  score_type next_diagonal = cell.best_score();
400  *alignment_column_it = this->track_cell(
401  this->compute_inner_cell(diagonal, cell, this->scoring_scheme.score(sequence1_value, sequence2_value)),
402  *++cell_index_column_it);
403  diagonal = next_diagonal;
404  }
405 
406  // ---------------------------------------------------------------------
407  // Final phase: track last cell
408  // ---------------------------------------------------------------------
409 
410  this->track_last_row_cell(*alignment_column_it, *cell_index_column_it);
411  }
412 };
413 
414 } // namespace seqan3::detail
view_to_simd.hpp
Provides seqan3::detail::to_simd view.
type_traits.hpp
Provides helper type traits for the configuration and execution of the alignment algorithm.
std::vector
seqan3::views::get
auto const get
A view calling std::get on each element in a range.
Definition: get.hpp:65
concepts
The Concepts library.
seqan3::views::move
auto const move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:68
std::forward
T forward(T... args)
aligned_allocator.hpp
Provides seqan3::aligned_allocator.
ranges
Adaptations of concepts from the Ranges TS.
empty_type.hpp
Provides seqan3::detail::empty_type.
type_inspection.hpp
Provides traits to inspect some information of a type, for example its name.
arithmetic
A type that satisfies std::is_arithmetic_v<t>.
semialphabet
The basis for seqan3::alphabet, but requires only rank interface (not char).
get.hpp
Provides seqan3::views::get.