SeqAn3  3.0.2
The Modern C++ library for sequence analysis.
translate.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 <vector>
16 #include <stdexcept>
17 
27 #include <seqan3/std/concepts>
28 #include <seqan3/std/ranges>
30 
31 // ============================================================================
32 // forwards
33 // ============================================================================
34 
35 namespace seqan3::detail
36 {
37 
38 template <std::ranges::view urng_t>
40  requires std::ranges::sized_range<urng_t> &&
41  std::ranges::random_access_range<urng_t> &&
44 class view_translate;
45 
46 template <std::ranges::view urng_t>
48  requires std::ranges::sized_range<urng_t> &&
49  std::ranges::random_access_range<urng_t> &&
52 class view_translate_single;
53 
54 } // namespace seqan3::detail
55 
56 // ============================================================================
57 // translation_frames
58 // ============================================================================
59 
60 namespace seqan3
61 {
62 
64 enum class translation_frames : uint8_t
65 {
66  FWD_FRAME_0 = 1,
67  FWD_FRAME_1 = 1 << 1,
68  FWD_FRAME_2 = 1 << 2,
69  REV_FRAME_0 = 1 << 3,
70  REV_FRAME_1 = 1 << 4,
71  REV_FRAME_2 = 1 << 5,
72  FWD_REV_0 = FWD_FRAME_0 | REV_FRAME_0,
73  FWD_REV_1 = FWD_FRAME_1 | REV_FRAME_1,
74  FWD_REV_2 = FWD_FRAME_2 | REV_FRAME_2,
75  FWD = FWD_FRAME_0 | FWD_FRAME_1 | FWD_FRAME_2,
76  REV = REV_FRAME_0 | REV_FRAME_1 | REV_FRAME_2,
77  SIX_FRAME = FWD | REV
78 };
79 
81 template <>
83 
84 }
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 = single ?
101  translation_frames::FWD_FRAME_0 :
103 
105  constexpr auto operator()(translation_frames const tf = default_frames) const
106  {
107  return detail::adaptor_from_functor{*this, tf};
108  }
109 
115  template <std::ranges::range urng_t>
116  constexpr auto operator()(urng_t && urange, translation_frames const tf = default_frames) const
117  {
118  static_assert(std::ranges::viewable_range<urng_t>,
119  "The range parameter to views::translate[_single] cannot be a temporary of a non-view range.");
120  static_assert(std::ranges::sized_range<urng_t>,
121  "The range parameter to views::translate[_single] must model std::ranges::sized_range.");
122  static_assert(std::ranges::random_access_range<urng_t>,
123  "The range parameter to views::translate[_single] must model std::ranges::random_access_range.");
124  static_assert(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>
153  requires std::ranges::sized_range<urng_t> &&
154  std::ranges::random_access_range<urng_t> &&
157 class view_translate_single : public std::ranges::view_base
158 {
159 private:
161  urng_t urange;
165  static constexpr small_string multiple_frame_error{"Error: Invalid type of frame. Choose one out of FWD_FRAME_0, "
166  "REV_FRAME_0, FWD_FRAME_1, REV_FRAME_1, FWD_FRAME_2 and "
167  "REV_FRAME_2."};
168 public:
172  using reference = aa27;
175  using const_reference = aa27;
177  using value_type = aa27;
179  using size_type = std::ranges::range_size_t<urng_t>;
181  using difference_type = std::ranges::range_difference_t<urng_t>;
183  using iterator = detail::random_access_iterator<view_translate_single>;
185  using const_iterator = detail::random_access_iterator<view_translate_single const>;
187 
191  view_translate_single() noexcept = default;
192  constexpr view_translate_single(view_translate_single const & rhs) noexcept = default;
193  constexpr view_translate_single(view_translate_single && rhs) noexcept = default;
194  constexpr view_translate_single & operator=(view_translate_single const & rhs) noexcept = default;
195  constexpr view_translate_single & operator=(view_translate_single && rhs) noexcept = default;
196  ~view_translate_single() noexcept = default;
197 
198 
207  view_translate_single(urng_t _urange, translation_frames const _tf = translation_frames::FWD_FRAME_0)
208  : urange{std::move(_urange)}, tf{_tf}
209  {
210  if (__builtin_popcount(static_cast<uint8_t>(_tf)) > 1)
211  {
212  throw std::invalid_argument(multiple_frame_error.c_str());
213  }
214  }
215 
224  template <typename rng_t>
226  requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate_single>) &&
227  std::ranges::viewable_range<rng_t> &&
228  std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
230  view_translate_single(rng_t && _urange, translation_frames const _tf = translation_frames::FWD_FRAME_0)
231  : view_translate_single{std::views::all(std::forward<rng_t>(_urange)), _tf}
232  {}
234 
251  iterator begin() noexcept
252  {
253  return {*this, 0};
254  }
255 
257  const_iterator begin() const noexcept
258  {
259  return {*this, 0};
260  }
261 
275  iterator end() noexcept
276  {
277  return {*this, size()};
278  }
279 
281  const_iterator end() const noexcept
282  {
283  return {*this, size()};
284  }
286 
298  size_type size()
299  {
300  switch (tf)
301  {
302  case translation_frames::FWD_FRAME_0:
303  [[fallthrough]];
304  case translation_frames::REV_FRAME_0:
305  return std::ranges::size(urange) / 3;
306  break;
307  case translation_frames::FWD_FRAME_1:
308  [[fallthrough]];
309  case translation_frames::REV_FRAME_1:
310  return (std::max<size_type>(std::ranges::size(urange), 1) - 1) / 3;
311  break;
312  case translation_frames::FWD_FRAME_2:
313  [[fallthrough]];
314  case translation_frames::REV_FRAME_2:
315  return (std::max<size_type>(std::ranges::size(urange), 2) - 2) / 3;
316  break;
317  default:
318  throw std::invalid_argument(multiple_frame_error.c_str());
319  break;
320  }
321  }
322 
324  size_type size() const
325  {
326  switch (tf)
327  {
328  case translation_frames::FWD_FRAME_0:
329  [[fallthrough]];
330  case translation_frames::REV_FRAME_0:
331  return std::ranges::size(urange) / 3;
332  break;
333  case translation_frames::FWD_FRAME_1:
334  [[fallthrough]];
335  case translation_frames::REV_FRAME_1:
336  return (std::max<size_type>(std::ranges::size(urange), 1) - 1) / 3;
337  break;
338  case translation_frames::FWD_FRAME_2:
339  [[fallthrough]];
340  case translation_frames::REV_FRAME_2:
341  return (std::max<size_type>(std::ranges::size(urange), 2) - 2) / 3;
342  break;
343  default:
344  throw std::invalid_argument(multiple_frame_error.c_str());
345  break;
346  }
347  }
348 
367  reference operator[](size_type const n)
368  {
369  assert(n < size());
370  switch (tf)
371  {
372  case translation_frames::FWD_FRAME_0:
373  return translate_triplet((urange)[n * 3], (urange)[n * 3 + 1], (urange)[n * 3 + 2]);
374  break;
375  case translation_frames::REV_FRAME_0:
376  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 1]), complement((urange)[(urange).size() - n * 3 - 2]), complement((urange)[(urange).size() - n * 3 - 3]));
377  break;
378  case translation_frames::FWD_FRAME_1:
379  return translate_triplet((urange)[n * 3 + 1], (urange)[n * 3 + 2], (urange)[n * 3 + 3]);
380  break;
381  case translation_frames::REV_FRAME_1:
382  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 2]), complement((urange)[(urange).size() - n * 3 - 3]), complement((urange)[(urange).size() - n * 3 - 4]));
383  break;
384  case translation_frames::FWD_FRAME_2:
385  return translate_triplet((urange)[n * 3 + 2], (urange)[n * 3 + 3], (urange)[n * 3 + 4]);
386  break;
387  case translation_frames::REV_FRAME_2:
388  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 3]), complement((urange)[(urange).size() - n * 3 - 4]), complement((urange)[(urange).size() - n * 3 - 5]));
389  break;
390  default:
391  throw std::invalid_argument(multiple_frame_error.c_str());
392  break;
393  }
394  }
395 
397  const_reference operator[](size_type const n) const
398  {
399  assert(n < size());
400  switch (tf)
401  {
402  case translation_frames::FWD_FRAME_0:
403  return translate_triplet((urange)[n * 3], (urange)[n * 3 + 1], (urange)[n * 3 + 2]);
404  break;
405  case translation_frames::REV_FRAME_0:
406  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 1]), complement((urange)[(urange).size() - n * 3 - 2]), complement((urange)[(urange).size() - n * 3 - 3]));
407  break;
408  case translation_frames::FWD_FRAME_1:
409  return translate_triplet((urange)[n * 3 + 1], (urange)[n * 3 + 2], (urange)[n * 3 + 3]);
410  break;
411  case translation_frames::REV_FRAME_1:
412  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 2]), complement((urange)[(urange).size() - n * 3 - 3]), complement((urange)[(urange).size() - n * 3 - 4]));
413  break;
414  case translation_frames::FWD_FRAME_2:
415  return translate_triplet((urange)[n * 3 + 2], (urange)[n * 3 + 3], (urange)[n * 3 + 4]);
416  break;
417  case translation_frames::REV_FRAME_2:
418  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 3]), complement((urange)[(urange).size() - n * 3 - 4]), complement((urange)[(urange).size() - n * 3 - 5]));
419  break;
420  default:
421  throw std::invalid_argument(multiple_frame_error.c_str());
422  break;
423  }
424  }
426 };
427 
429 template <typename urng_t>
430 view_translate_single(urng_t &&, translation_frames const) -> view_translate_single<std::views::all_t<urng_t>>;
431 
432 
434 template <typename urng_t>
435 view_translate_single(urng_t &&) -> view_translate_single<std::views::all_t<urng_t>>;
436 
437 } // namespace seqan3::detail
438 
439 // ============================================================================
440 // translate_single (adaptor object)
441 // ============================================================================
442 
443 namespace seqan3::views
444 {
445 
492 inline constexpr auto translate_single = deep{detail::translate_fn<true>{}};
493 
494 } // seqan3::views
495 
496 // ============================================================================
497 // view_translate (range definition)
498 // ============================================================================
499 
500 namespace seqan3::detail
501 {
502 
511 template <std::ranges::view urng_t>
513  requires std::ranges::sized_range<urng_t> &&
514  std::ranges::random_access_range<urng_t> &&
517 class view_translate : public std::ranges::view_base
518 {
519 private:
521  urng_t urange;
525  small_vector<translation_frames, 6> selected_frames{};
526 
527 public:
531  using reference = view_translate_single<urng_t>;
534  using const_reference = reference;
536  using value_type = reference;
538  using size_type = std::ranges::range_size_t<urng_t>;
540  using difference_type = std::ranges::range_difference_t<urng_t>;
542  using iterator = detail::random_access_iterator<view_translate>;
544  using const_iterator = detail::random_access_iterator<view_translate const>;
546 
547 protected:
552  // unfortunately we cannot specialise the variable template so we have to add an auxiliary here
554  template <typename t>
555  requires (range_dimension_v<t> == range_dimension_v<value_type> + 1) &&
556  std::is_same_v<std::remove_cvref_t<range_innermost_value_t<value_type>>,
558  static constexpr bool is_compatible_this_aux = true;
561 
562 public:
563 
567  view_translate() noexcept = default;
568  constexpr view_translate(view_translate const & rhs) noexcept = default;
569  constexpr view_translate(view_translate && rhs) noexcept = default;
570  constexpr view_translate & operator=(view_translate const & rhs) noexcept = default;
571  constexpr view_translate & operator=(view_translate && rhs) noexcept = default;
572  ~view_translate() noexcept = default;
573 
578  view_translate(urng_t _urange, translation_frames const _tf = translation_frames::SIX_FRAME)
579  : urange{std::move(_urange)}, tf{_tf}
580  {
581  if ((_tf & translation_frames::FWD_FRAME_0) == translation_frames::FWD_FRAME_0)
582  selected_frames.push_back(translation_frames::FWD_FRAME_0);
583  if ((_tf & translation_frames::FWD_FRAME_1) == translation_frames::FWD_FRAME_1)
584  selected_frames.push_back(translation_frames::FWD_FRAME_1);
585  if ((_tf & translation_frames::FWD_FRAME_2) == translation_frames::FWD_FRAME_2)
586  selected_frames.push_back(translation_frames::FWD_FRAME_2);
587  if ((_tf & translation_frames::REV_FRAME_0) == translation_frames::REV_FRAME_0)
588  selected_frames.push_back(translation_frames::REV_FRAME_0);
589  if ((_tf & translation_frames::REV_FRAME_1) == translation_frames::REV_FRAME_1)
590  selected_frames.push_back(translation_frames::REV_FRAME_1);
591  if ((_tf & translation_frames::REV_FRAME_2) == translation_frames::REV_FRAME_2)
592  selected_frames.push_back(translation_frames::REV_FRAME_2);
593  }
594 
599  template <typename rng_t>
601  requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate>) &&
602  std::ranges::viewable_range<rng_t> &&
603  std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
605  view_translate(rng_t && _urange, translation_frames const _tf = translation_frames::SIX_FRAME)
606  : view_translate{std::views::all(std::forward<rng_t>(_urange)), _tf}
607  {}
609 
626  iterator begin() noexcept
627  {
628  return {*this, 0};
629  }
630 
632  const_iterator begin() const noexcept
633  {
634  return {*this, 0};
635  }
636 
650  iterator end() noexcept
651  {
652  return {*this, size()};
653  }
654 
656  const_iterator end() const noexcept
657  {
658  return {*this, size()};
659  }
660 
672  size_type size() noexcept
673  {
674  return (size_type) selected_frames.size();
675  }
676 
678  size_type size() const noexcept
679  {
680  return (size_type) selected_frames.size();
681  }
682 
701  reference operator[](size_type const n)
702  {
703  assert(n < size());
704  return urange | views::translate_single(selected_frames[n]);
705  }
706 
708  const_reference operator[](size_type const n) const
709  {
710  assert(n < size());
711  return urange | views::translate_single(selected_frames[n]);
712  }
714 };
715 
717 template <typename urng_t>
719  requires std::ranges::sized_range<urng_t> &&
720  std::ranges::random_access_range<urng_t> &&
723 view_translate(urng_t &&, translation_frames const = translation_frames{}) -> view_translate<std::views::all_t<urng_t>>;
724 
725 } // namespace seqan3::detail
726 
727 // ============================================================================
728 // translate (adaptor object)
729 // ============================================================================
730 
731 namespace seqan3::views
732 {
733 
780 inline constexpr auto translate = deep{detail::translate_fn<false>{}};
782 
783 } // namespace seqan3::views
seqan3::single
@ single
The text is a single range.
Definition: concept.hpp:84
seqan3::views
The SeqAn namespace for views.
Definition: view_iota_simd.hpp:218
seqan3::add_enum_bitwise_operators< translation_frames >
constexpr bool add_enum_bitwise_operators< translation_frames >
Enable bitwise operators for enum translation_frames.
Definition: translate.hpp:82
vector
concept.hpp
Adaptations of concepts from the standard library.
seqan3::translate_triplet
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:53
seqan3::operator|
auto operator|(validator1_type &&vali1, validator2_type &&vali2)
Enables the chaining of validators.
Definition: validators.hpp:1037
concepts
The Concepts library.
stdexcept
seqan3::views::deep
A wrapper type around an existing view adaptor that enables "deep view" behaviour for that view.
Definition: deep.hpp:102
random_access_iterator.hpp
Provides the seqan3::detail::random_access_iterator class.
translation.hpp
Provides functions for translating a triplet of nucleotides into an amino acid.
seqan3::views::translate
constexpr auto translate
A view that translates nucleotide into aminoacid alphabet with 1, 2, 3 or 6 frames.
Definition: translate.hpp:780
aa27.hpp
Provides seqan3::aa27, container aliases and string literals.
nucleotide_alphabet
A concept that indicates whether an alphabet represents nucleotides.
seqan3::views::move
auto const move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:68
small_string.hpp
A constexpr string implementation to manipulate string literals at compile time.
range.hpp
Provides various transformation traits used by the range module.
dna5.hpp
Provides seqan3::dna5, container aliases and string literals.
seqan3
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
std::invalid_argument
seqan3::pack_traits::size
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:116
ranges
Adaptations of concepts from the Ranges TS.
deep.hpp
Provides seqan3::views::deep.
add_enum_bitwise_operators.hpp
Provides seqan3::add_enum_bitwise_operators.
std::begin
T begin(T... args)
std::remove_cvref_t
seqan3::complement
constexpr auto complement
Return the complement of a nucleotide object.
Definition: concept.hpp:95
std::end
T end(T... args)
seqan3::translation_frames
translation_frames
Specialisation values for single and multiple translation frames.
Definition: translate.hpp:65
seqan3::translation_frames::FWD_FRAME_0
@ FWD_FRAME_0
The first forward frame starting at position 0.
detail.hpp
Auxiliary header for the views submodule .
seqan3::views::translate_single
constexpr auto translate_single
A view that translates nucleotide into aminoacid alphabet for one of the six frames.
Definition: translate.hpp:492