SeqAn3  3.0.2
The Modern C++ library for sequence analysis.
aligned_sequence_builder.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 <type_traits>
16 #include <vector>
17 
29 #include <seqan3/std/concepts>
30 #include <seqan3/std/ranges>
31 
32 namespace seqan3::detail
33 {
34 
52 template <std::ranges::viewable_range range_t>
53 struct make_aligned_sequence_type
54 {
55 private:
56  // The following expressions are used to check if the sequence types can be used as template arguments for the
57  // seqan3::gap_decorator. Ranges that do not model std::random_access_range for instance cannot be augmented with
58  // the gap_decorator and need to be copied instead.
59 
61  using unaligned_sequence_type = decltype(std::declval<range_t>() | views::type_reduce | views::slice(0, 1));
62 
63 public:
65  using type = lazy_conditional_t<is_class_template_declarable_with_v<gap_decorator, unaligned_sequence_type>,
66  lazy<gap_decorator, unaligned_sequence_type>,
67  lazy<std::vector, gapped<std::ranges::range_value_t<unaligned_sequence_type>>>>;
68 };
69 
77 template <std::ranges::viewable_range first_sequence_t, std::ranges::viewable_range second_sequence_t>
78 struct make_pairwise_alignment_type
79 {
81  using first_aligned_t = typename make_aligned_sequence_type<first_sequence_t>::type;
83  using second_aligned_t = typename make_aligned_sequence_type<second_sequence_t>::type;
84 
86  "first_aligned_t is required to model seqan3::writable_aligned_sequence!");
88  "second_aligned_t is required to model seqan3::writable_aligned_sequence!");
89 
92 };
93 
115 template <std::ranges::viewable_range fst_sequence_t, std::ranges::viewable_range sec_sequence_t>
116 class aligned_sequence_builder
117 {
118 public:
120  using alignment_type = typename make_pairwise_alignment_type<fst_sequence_t, sec_sequence_t>::type;
121 
123  struct [[nodiscard]] result_type
124  {
126  std::pair<size_t, size_t> first_sequence_slice_positions{};
128  std::pair<size_t, size_t> second_sequence_slice_positions{};
131  alignment_type alignment{};
132  };
133 
137  constexpr aligned_sequence_builder() = default;
138  constexpr aligned_sequence_builder(aligned_sequence_builder const &) = default;
139  constexpr aligned_sequence_builder(aligned_sequence_builder &&) = default;
140  constexpr aligned_sequence_builder & operator=(aligned_sequence_builder const &) = default;
141  constexpr aligned_sequence_builder & operator=(aligned_sequence_builder &&) = default;
142  ~aligned_sequence_builder() = default;
143 
148  constexpr aligned_sequence_builder(fst_sequence_t fst_rng, sec_sequence_t sec_rng) :
149  fst_rng{views::type_reduce(std::forward<fst_sequence_t>(fst_rng))},
150  sec_rng{views::type_reduce(std::forward<sec_sequence_t>(sec_rng))}
151  {}
153 
168  template <std::ranges::input_range trace_path_t>
169  result_type operator()(trace_path_t && trace_path)
170  {
171  static_assert(std::same_as<std::ranges::range_value_t<trace_path_t>, trace_directions>,
172  "The value type of the trace path must be seqan3::detail::trace_directions");
173 
174  result_type res{};
175  auto trace_it = std::ranges::begin(trace_path);
176  std::tie(res.first_sequence_slice_positions.second, res.second_sequence_slice_positions.second) =
177  std::pair<size_t, size_t>{trace_it.coordinate()};
178 
180 
181  while (trace_it != std::ranges::end(trace_path))
182  {
183  trace_directions last_dir = *trace_it;
184  size_t span = 0;
185  for (; trace_it != std::ranges::end(trace_path) && *trace_it == last_dir; ++trace_it, ++span)
186  {}
187 
188  trace_segments.emplace_back(last_dir, span);
189  }
190 
191  std::tie(res.first_sequence_slice_positions.first, res.second_sequence_slice_positions.first) =
192  std::pair<size_t, size_t>{trace_it.coordinate()};
193 
194  assign_unaligned(std::get<0>(res.alignment),
195  std::views::all(fst_rng) | views::slice(res.first_sequence_slice_positions.first,
196  res.first_sequence_slice_positions.second));
197  assign_unaligned(std::get<1>(res.alignment),
198  std::views::all(sec_rng) | views::slice(res.second_sequence_slice_positions.first,
199  res.second_sequence_slice_positions.second));
200 
201  // Now we need to insert the values.
202  fill_aligned_sequence(trace_segments | std::views::reverse,
203  std::get<0>(res.alignment),
204  std::get<1>(res.alignment));
205 
206  return res;
207  }
208 
209 private:
210 
217  template <typename reverse_traces_t, typename fst_aligned_t, typename sec_aligned_t>
218  void fill_aligned_sequence(reverse_traces_t && rev_traces,
219  fst_aligned_t & fst_aligned,
220  sec_aligned_t & sec_aligned) const
221  {
222  if (std::ranges::empty(rev_traces))
223  return;
224 
225  auto fst_it = std::ranges::begin(fst_aligned);
226  auto sec_it = std::ranges::begin(sec_aligned);
227 
228  for (auto const & [dir, span] : rev_traces)
229  {
230  if (dir == trace_directions::up)
231  fst_it = insert_gap(fst_aligned, fst_it, span);
232 
233  if (dir == trace_directions::left)
234  sec_it = insert_gap(sec_aligned, sec_it, span);
235 
236  fst_it += span;
237  sec_it += span;
238  }
239  }
240 
241  type_reduce_view<fst_sequence_t> fst_rng;
242  type_reduce_view<sec_sequence_t> sec_rng;
243 };
244 
249 template <std::ranges::viewable_range fst_sequence_t, std::ranges::viewable_range sec_sequence_t>
251 aligned_sequence_builder(fst_sequence_t &&, sec_sequence_t &&) ->
252  aligned_sequence_builder<fst_sequence_t, sec_sequence_t>;
254 } // namespace seqan3::detail
matrix_coordinate.hpp
Provides seqan3::detail::alignment_coordinate and associated strong types.
std::pair
gap_decorator.hpp
Provides seqan3::gap_decorator.
vector
convert.hpp
Provides seqan3::views::convert.
std::tuple
seqan3::views::type_reduce
constexpr auto type_reduce
A view adaptor that behaves like std::views::all, but type erases certain ranges.
Definition: type_reduce.hpp:158
concept.hpp
Provides the concepts seqan3::transformation_trait and seqan3::unary_type_trait.
concepts
The Concepts library.
std::tie
T tie(T... args)
trace_directions.hpp
Provides the declaration of seqan3::detail::trace_directions.
slice.hpp
Provides seqan3::views::slice.
gapped.hpp
Provides seqan3::gapped.
to.hpp
Provides seqan3::views::to.
type_reduce.hpp
Provides seqan3::views::type_reduce.
aligned_sequence_concept.hpp
Includes the aligned_sequence and the related insert_gap and erase_gap functions to enable stl contai...
ranges
Adaptations of concepts from the Ranges TS.
std::vector::emplace_back
T emplace_back(T... args)
std::ranges::begin
T begin(T... args)
writable_aligned_sequence
The generic concept for an aligned sequence that is writable.
seqan3::views::slice
constexpr auto slice
A view adaptor that returns a half-open interval on the underlying range.
Definition: slice.hpp:141
lazy.hpp
Provides lazy template instantiation traits.