SeqAn3  3.2.0
The Modern C++ library for sequence analysis.
translate.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2022, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2022, 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 <concepts>
16 #include <ranges>
17 #include <stdexcept>
18 #include <vector>
19 
28 
29 // ============================================================================
30 // forwards
31 // ============================================================================
32 
33 namespace seqan3::detail
34 {
35 
36 template <std::ranges::view urng_t>
37  requires std::ranges::sized_range<urng_t> && std::ranges::random_access_range<urng_t>
39 class view_translate;
40 
41 template <std::ranges::view urng_t>
42  requires std::ranges::sized_range<urng_t> && std::ranges::random_access_range<urng_t>
44 class view_translate_single;
45 
46 } // namespace seqan3::detail
47 
48 // ============================================================================
49 // translation_frames
50 // ============================================================================
51 
52 namespace seqan3
53 {
54 
61 enum class translation_frames : uint8_t
62 {
63  forward_frame0 = 1,
64  forward_frame1 = 1 << 1,
65  forward_frame2 = 1 << 2,
66  reverse_frame0 = 1 << 3,
67  reverse_frame1 = 1 << 4,
68  reverse_frame2 = 1 << 5,
75 };
76 
80 template <>
81 constexpr bool add_enum_bitwise_operators<translation_frames> = true;
83 
84 } // namespace seqan3
85 
86 namespace seqan3::detail
87 {
88 
89 // ============================================================================
90 // translate_fn (adaptor definition for both views)
91 // ============================================================================
92 
96 template <bool single>
97 struct translate_fn
98 {
100  static constexpr translation_frames default_frames =
102 
104  constexpr auto operator()(translation_frames const tf = default_frames) const
105  {
106  return detail::adaptor_from_functor{*this, tf};
107  }
108 
114  template <std::ranges::range urng_t>
115  constexpr auto operator()(urng_t && urange, translation_frames const tf = default_frames) const
116  {
117  static_assert(std::ranges::viewable_range<urng_t>,
118  "The range parameter to views::translate[_single] cannot be a temporary of a non-view range.");
119  static_assert(std::ranges::sized_range<urng_t>,
120  "The range parameter to views::translate[_single] must model std::ranges::sized_range.");
121  static_assert(std::ranges::random_access_range<urng_t>,
122  "The range parameter to views::translate[_single] must model std::ranges::random_access_range.");
123  static_assert(
124  nucleotide_alphabet<std::ranges::range_reference_t<urng_t>>,
125  "The range parameter to views::translate[_single] must be over elements of seqan3::nucleotide_alphabet.");
126 
127  if constexpr (single)
128  return detail::view_translate_single{std::forward<urng_t>(urange), tf};
129  else
130  return detail::view_translate{std::forward<urng_t>(urange), tf};
131  }
132 
134  template <std::ranges::range urng_t>
135  constexpr friend auto operator|(urng_t && urange, translate_fn const & me)
136  {
137  return me(std::forward<urng_t>(urange));
138  }
139 };
140 
141 // ============================================================================
142 // view_translate_single (range definition)
143 // ============================================================================
144 
151 template <std::ranges::view urng_t>
152  requires std::ranges::sized_range<urng_t> && std::ranges::random_access_range<urng_t>
154 class view_translate_single : public std::ranges::view_base
155 {
156 private:
158  urng_t urange;
162  static constexpr small_string multiple_frame_error{"Error: Invalid type of frame. Choose one out of "
163  "forward_frame0, reverse_frame0, forward_frame1, "
164  "reverse_frame1, forward_frame2 and reverse_frame2."};
165 
166 public:
171  using reference = aa27;
173  using const_reference = aa27;
175  using value_type = aa27;
177  using size_type = std::ranges::range_size_t<urng_t>;
179  using difference_type = std::ranges::range_difference_t<urng_t>;
181  using iterator = detail::random_access_iterator<view_translate_single>;
183  using const_iterator = detail::random_access_iterator<view_translate_single const>;
185 
189  view_translate_single() noexcept = default;
190  constexpr view_translate_single(view_translate_single const & rhs) noexcept = default;
191  constexpr view_translate_single(view_translate_single && rhs) noexcept = default;
192  constexpr view_translate_single & operator=(view_translate_single const & rhs) noexcept = default;
193  constexpr view_translate_single & operator=(view_translate_single && rhs) noexcept = default;
194  ~view_translate_single() noexcept = default;
195 
204  view_translate_single(urng_t _urange, translation_frames const _tf = translation_frames::forward_frame0) :
205  urange{std::move(_urange)},
206  tf{_tf}
207  {
208  if (__builtin_popcount(static_cast<uint8_t>(_tf)) > 1)
209  {
210  throw std::invalid_argument(multiple_frame_error.c_str());
211  }
212  }
213 
222  template <typename rng_t>
223  requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate_single>)
224  && std::ranges::viewable_range<rng_t>
225  && std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
226  view_translate_single(rng_t && _urange, translation_frames const _tf = translation_frames::forward_frame0) :
227  view_translate_single{std::views::all(std::forward<rng_t>(_urange)), _tf}
228  {}
230 
247  iterator begin() noexcept
248  {
249  return {*this, 0};
250  }
251 
253  const_iterator begin() const noexcept
254  {
255  return {*this, 0};
256  }
257 
271  iterator end() noexcept
272  {
273  return {*this, size()};
274  }
275 
277  const_iterator end() const noexcept
278  {
279  return {*this, size()};
280  }
282 
294  size_type size()
295  {
296  switch (tf)
297  {
299  [[fallthrough]];
301  return std::ranges::size(urange) / 3;
302  break;
304  [[fallthrough]];
306  return (std::max<size_type>(std::ranges::size(urange), 1) - 1) / 3;
307  break;
309  [[fallthrough]];
311  return (std::max<size_type>(std::ranges::size(urange), 2) - 2) / 3;
312  break;
313  default:
314  throw std::invalid_argument(multiple_frame_error.c_str());
315  break;
316  }
317  }
318 
320  size_type size() const
321  {
322  switch (tf)
323  {
325  [[fallthrough]];
327  return std::ranges::size(urange) / 3;
328  break;
330  [[fallthrough]];
332  return (std::max<size_type>(std::ranges::size(urange), 1) - 1) / 3;
333  break;
335  [[fallthrough]];
337  return (std::max<size_type>(std::ranges::size(urange), 2) - 2) / 3;
338  break;
339  default:
340  throw std::invalid_argument(multiple_frame_error.c_str());
341  break;
342  }
343  }
344 
363  reference operator[](size_type const n)
364  {
365  // size will throw (only in debug-builds!) if translation_frames is neither (FWD|REV)_FRAME_(0|1|2),
366  // we catch that error in debug-builds to make this function consistent with the behaviour in
367  // release-builds (-DNDEBUG).
368 #ifndef NDEBUG
369  try
370  {
371  assert(n < size());
372  }
373  catch (std::invalid_argument const &)
374  {}
375 #endif
376 
377  switch (tf)
378  {
380  return translate_triplet((urange)[n * 3], (urange)[n * 3 + 1], (urange)[n * 3 + 2]);
381  break;
383  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 1]),
384  complement((urange)[(urange).size() - n * 3 - 2]),
385  complement((urange)[(urange).size() - n * 3 - 3]));
386  break;
388  return translate_triplet((urange)[n * 3 + 1], (urange)[n * 3 + 2], (urange)[n * 3 + 3]);
389  break;
391  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 2]),
392  complement((urange)[(urange).size() - n * 3 - 3]),
393  complement((urange)[(urange).size() - n * 3 - 4]));
394  break;
396  return translate_triplet((urange)[n * 3 + 2], (urange)[n * 3 + 3], (urange)[n * 3 + 4]);
397  break;
399  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 3]),
400  complement((urange)[(urange).size() - n * 3 - 4]),
401  complement((urange)[(urange).size() - n * 3 - 5]));
402  break;
403  default:
404  throw std::invalid_argument(multiple_frame_error.c_str());
405  break;
406  }
407  }
408 
410  const_reference operator[](size_type const n) const
411  {
412  // size will throw (only in debug-builds!) if translation_frames is neither (FWD|REV)_FRAME_(0|1|2),
413  // we catch that error in debug-builds to make this function consistent with the behaviour in
414  // release-builds (-DNDEBUG).
415 #ifndef NDEBUG
416  try
417  {
418  assert(n < size());
419  }
420  catch (std::invalid_argument const &)
421  {}
422 #endif
423 
424  switch (tf)
425  {
427  return translate_triplet((urange)[n * 3], (urange)[n * 3 + 1], (urange)[n * 3 + 2]);
428  break;
430  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 1]),
431  complement((urange)[(urange).size() - n * 3 - 2]),
432  complement((urange)[(urange).size() - n * 3 - 3]));
433  break;
435  return translate_triplet((urange)[n * 3 + 1], (urange)[n * 3 + 2], (urange)[n * 3 + 3]);
436  break;
438  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 2]),
439  complement((urange)[(urange).size() - n * 3 - 3]),
440  complement((urange)[(urange).size() - n * 3 - 4]));
441  break;
443  return translate_triplet((urange)[n * 3 + 2], (urange)[n * 3 + 3], (urange)[n * 3 + 4]);
444  break;
446  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 3]),
447  complement((urange)[(urange).size() - n * 3 - 4]),
448  complement((urange)[(urange).size() - n * 3 - 5]));
449  break;
450  default:
451  throw std::invalid_argument(multiple_frame_error.c_str());
452  break;
453  }
454  }
456 };
457 
459 template <typename urng_t>
460 view_translate_single(urng_t &&, translation_frames const) -> view_translate_single<std::views::all_t<urng_t>>;
461 
463 template <typename urng_t>
464 view_translate_single(urng_t &&) -> view_translate_single<std::views::all_t<urng_t>>;
465 
466 } // namespace seqan3::detail
467 
468 // ============================================================================
469 // translate_single (adaptor object)
470 // ============================================================================
471 
472 namespace seqan3::views
473 {
474 
523 inline constexpr auto translate_single = deep{detail::translate_fn<true>{}};
524 
525 } // namespace seqan3::views
526 
527 // ============================================================================
528 // view_translate (range definition)
529 // ============================================================================
530 
531 namespace seqan3::detail
532 {
533 
542 template <std::ranges::view urng_t>
543  requires std::ranges::sized_range<urng_t> && std::ranges::random_access_range<urng_t>
545 class view_translate : public std::ranges::view_base
546 {
547 private:
549  urng_t urange;
553  small_vector<translation_frames, 6> selected_frames{};
554 
555 public:
560  using reference = view_translate_single<urng_t>;
562  using const_reference = reference;
564  using value_type = reference;
566  using size_type = std::ranges::range_size_t<urng_t>;
568  using difference_type = std::ranges::range_difference_t<urng_t>;
570  using iterator = detail::random_access_iterator<view_translate>;
572  using const_iterator = detail::random_access_iterator<view_translate const>;
574 
575 protected:
582  // unfortunately we cannot specialise the variable template so we have to add an auxiliary here
583  template <typename t>
584  requires (range_dimension_v<t> == range_dimension_v<value_type> + 1)
585  && std::is_same_v<std::remove_cvref_t<range_innermost_value_t<value_type>>,
586  std::remove_cvref_t<range_innermost_value_t<t>>>
587  static constexpr bool is_compatible_this_aux = true;
590 
591 public:
595  view_translate() noexcept = default;
596  constexpr view_translate(view_translate const & rhs) noexcept = default;
597  constexpr view_translate(view_translate && rhs) noexcept = default;
598  constexpr view_translate & operator=(view_translate const & rhs) noexcept = default;
599  constexpr view_translate & operator=(view_translate && rhs) noexcept = default;
600  ~view_translate() noexcept = default;
601 
606  view_translate(urng_t _urange, translation_frames const _tf = translation_frames::six_frames) :
607  urange{std::move(_urange)},
608  tf{_tf}
609  {
611  selected_frames.push_back(translation_frames::forward_frame0);
613  selected_frames.push_back(translation_frames::forward_frame1);
615  selected_frames.push_back(translation_frames::forward_frame2);
617  selected_frames.push_back(translation_frames::reverse_frame0);
619  selected_frames.push_back(translation_frames::reverse_frame1);
621  selected_frames.push_back(translation_frames::reverse_frame2);
622  }
623 
628  template <typename rng_t>
629  requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate>) && std::ranges::viewable_range<rng_t>
630  && std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
631  view_translate(rng_t && _urange, translation_frames const _tf) :
632  view_translate{std::views::all(std::forward<rng_t>(_urange)), _tf}
633  {}
635 
652  iterator begin() noexcept
653  {
654  return {*this, 0};
655  }
656 
658  const_iterator begin() const noexcept
659  {
660  return {*this, 0};
661  }
662 
676  iterator end() noexcept
677  {
678  return {*this, size()};
679  }
680 
682  const_iterator end() const noexcept
683  {
684  return {*this, size()};
685  }
686 
698  size_type size() noexcept
699  {
700  return (size_type)selected_frames.size();
701  }
702 
704  size_type size() const noexcept
705  {
706  return (size_type)selected_frames.size();
707  }
708 
727  reference operator[](size_type const n)
728  {
729  assert(n < size());
730  return urange | views::translate_single(selected_frames[n]);
731  }
732 
734  const_reference operator[](size_type const n) const
735  {
736  assert(n < size());
737  return urange | views::translate_single(selected_frames[n]);
738  }
740 };
741 
743 template <typename urng_t>
744  requires std::ranges::sized_range<urng_t> && std::ranges::random_access_range<urng_t>
746  view_translate(urng_t &&, translation_frames const) -> view_translate<std::views::all_t<urng_t>>;
747 } // namespace seqan3::detail
748 
749 // ============================================================================
750 // translate (adaptor object)
751 // ============================================================================
752 
753 namespace seqan3::views
754 {
803 inline constexpr auto translate = deep{detail::translate_fn<false>{}};
804 
805 } // namespace seqan3::views
Provides seqan3::aa27, container aliases and string literals.
Provides seqan3::detail::adaptor_from_functor.
Provides seqan3::add_enum_bitwise_operators.
T begin(T... args)
A wrapper type around an existing view adaptor that enables "deep view" behaviour for that view.
Definition: deep.hpp:104
The <concepts> header from C++20's standard library.
Provides various transformation traits used by the range module.
Provides seqan3::views::deep.
Provides seqan3::dna5, container aliases and string literals.
T end(T... args)
T forward(T... args)
constexpr aa27 translate_triplet(nucl_type const &n1, nucl_type const &n2, nucl_type const &n3) noexcept
Translate one nucleotide triplet into single amino acid (single nucleotide interface).
Definition: translation.hpp:55
constexpr auto complement
Return the complement of a nucleotide object.
Definition: alphabet/nucleotide/concept.hpp:105
constexpr auto translate
A view that translates nucleotide into aminoacid alphabet with 1, 2, 3 or 6 frames.
Definition: translate.hpp:803
constexpr auto translate_single
A view that translates nucleotide into aminoacid alphabet for one of the six frames.
Definition: translate.hpp:523
requires requires
The rank_type of the semi-alphabet; defined as the return type of seqan3::to_rank....
Definition: alphabet/concept.hpp:164
requires std::common_with< typename std::remove_reference_t< validator1_type >::option_value_type, typename std::remove_reference_t< validator2_type >::option_value_type > auto operator|(validator1_type &&vali1, validator2_type &&vali2)
Enables the chaining of validators.
Definition: validators.hpp:1124
@ single
The text is a single range.
Definition: search/fm_index/concept.hpp:93
constexpr size_t size
The size of a type pack.
Definition: type_pack/traits.hpp:146
A concept that indicates whether an alphabet represents nucleotides.
The SeqAn namespace for views.
Definition: char_strictly_to.hpp:22
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
translation_frames
Specialisation values for single and multiple translation frames.
Definition: translate.hpp:62
@ forward_frame2
The third forward frame starting at position 2.
@ forward_frame0
The first forward frame starting at position 0.
@ reverse_frames
All reverse frames.
@ forward_frames
All forward frames.
@ reverse_frame0
The first reverse frame starting at position 0.
@ forward_reverse2
The first third and third reverse frame.
@ reverse_frame2
The third reverse frame starting at position 2.
@ forward_frame1
The second forward frame starting at position 1.
@ reverse_frame1
The second reverse frame starting at position 1.
@ forward_reverse0
The first forward and first reverse frame.
@ forward_reverse1
The second forward and second reverse frame.
SeqAn specific customisations in the standard namespace.
The <ranges> header from C++20's standard library.
A constexpr string implementation to manipulate string literals at compile time.
Provides functions for translating a triplet of nucleotides into an amino acid.