Loading...
Searching...
No Matches
translate.hpp
Go to the documentation of this file.
// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: BSD-3-Clause
#pragma once
#include <concepts>
#include <ranges>
#include <stdexcept>
#include <vector>
#include <seqan3/alphabet/aminoacid/aa27.hpp>
#include <seqan3/alphabet/aminoacid/translation.hpp>
#include <seqan3/alphabet/nucleotide/dna5.hpp>
#include <seqan3/core/add_enum_bitwise_operators.hpp>
#include <seqan3/core/range/detail/adaptor_from_functor.hpp>
#include <seqan3/core/range/type_traits.hpp>
#include <seqan3/utility/container/small_string.hpp>
#include <seqan3/utility/views/deep.hpp>
// ============================================================================
// forwards
// ============================================================================
namespace seqan3::detail
{
template <std::ranges::view urng_t>
requires std::ranges::sized_range<urng_t> && std::ranges::random_access_range<urng_t>
&& nucleotide_alphabet<std::ranges::range_reference_t<urng_t>>
class view_translate;
template <std::ranges::view urng_t>
requires std::ranges::sized_range<urng_t> && std::ranges::random_access_range<urng_t>
&& nucleotide_alphabet<std::ranges::range_reference_t<urng_t>>
class view_translate_single;
} // namespace seqan3::detail
// ============================================================================
// translation_frames
// ============================================================================
namespace seqan3
{
enum class translation_frames : uint8_t
{
forward_frame0 = 1,
forward_frame1 = 1 << 1,
forward_frame2 = 1 << 2,
reverse_frame0 = 1 << 3,
reverse_frame1 = 1 << 4,
reverse_frame2 = 1 << 5,
forward_reverse0 = forward_frame0 | reverse_frame0,
forward_reverse1 = forward_frame1 | reverse_frame1,
forward_reverse2 = forward_frame2 | reverse_frame2,
forward_frames = forward_frame0 | forward_frame1 | forward_frame2,
reverse_frames = reverse_frame0 | reverse_frame1 | reverse_frame2,
six_frames = forward_frames | reverse_frames
};
template <>
inline constexpr bool add_enum_bitwise_operators<translation_frames> = true;
} // namespace seqan3
namespace seqan3::detail
{
// ============================================================================
// translate_fn (adaptor definition for both views)
// ============================================================================
template <bool single>
struct translate_fn
{
static constexpr translation_frames default_frames =
single ? translation_frames::forward_frame0 : translation_frames::six_frames;
constexpr auto operator()(translation_frames const tf = default_frames) const
{
return detail::adaptor_from_functor{*this, tf};
}
template <std::ranges::range urng_t>
constexpr auto operator()(urng_t && urange, translation_frames const tf = default_frames) const
{
static_assert(std::ranges::viewable_range<urng_t>,
"The range parameter to views::translate[_single] cannot be a temporary of a non-view range.");
static_assert(std::ranges::sized_range<urng_t>,
"The range parameter to views::translate[_single] must model std::ranges::sized_range.");
static_assert(std::ranges::random_access_range<urng_t>,
"The range parameter to views::translate[_single] must model std::ranges::random_access_range.");
static_assert(
nucleotide_alphabet<std::ranges::range_reference_t<urng_t>>,
"The range parameter to views::translate[_single] must be over elements of seqan3::nucleotide_alphabet.");
if constexpr (single)
return detail::view_translate_single{std::forward<urng_t>(urange), tf};
else
return detail::view_translate{std::forward<urng_t>(urange), tf};
}
template <std::ranges::range urng_t>
constexpr friend auto operator|(urng_t && urange, translate_fn const & me)
{
return me(std::forward<urng_t>(urange));
}
};
// ============================================================================
// view_translate_single (range definition)
// ============================================================================
template <std::ranges::view urng_t>
requires std::ranges::sized_range<urng_t> && std::ranges::random_access_range<urng_t>
&& nucleotide_alphabet<std::ranges::range_reference_t<urng_t>>
class view_translate_single : public std::ranges::view_base
{
private:
urng_t urange;
translation_frames tf;
static constexpr small_string multiple_frame_error{"Error: Invalid type of frame. Choose one out of "
"forward_frame0, reverse_frame0, forward_frame1, "
"reverse_frame1, forward_frame2 and reverse_frame2."};
public:
using reference = aa27;
using const_reference = aa27;
using value_type = aa27;
using size_type = std::ranges::range_size_t<urng_t>;
using difference_type = std::ranges::range_difference_t<urng_t>;
using iterator = detail::random_access_iterator<view_translate_single>;
using const_iterator = detail::random_access_iterator<view_translate_single const>;
view_translate_single() noexcept = default;
constexpr view_translate_single(view_translate_single const & rhs) noexcept = default;
constexpr view_translate_single(view_translate_single && rhs) noexcept = default;
constexpr view_translate_single & operator=(view_translate_single const & rhs) noexcept = default;
constexpr view_translate_single & operator=(view_translate_single && rhs) noexcept = default;
~view_translate_single() noexcept = default;
view_translate_single(urng_t _urange, translation_frames const _tf = translation_frames::forward_frame0) :
urange{std::move(_urange)},
tf{_tf}
{
if (__builtin_popcount(static_cast<uint8_t>(_tf)) > 1)
{
throw std::invalid_argument(multiple_frame_error.c_str());
}
}
template <typename rng_t>
requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate_single>)
&& std::ranges::viewable_range<rng_t>
&& std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
view_translate_single(rng_t && _urange, translation_frames const _tf = translation_frames::forward_frame0) :
view_translate_single{std::views::all(std::forward<rng_t>(_urange)), _tf}
{}
iterator begin() noexcept
{
return {*this, 0};
}
const_iterator begin() const noexcept
{
return {*this, 0};
}
iterator end() noexcept
{
return {*this, size()};
}
const_iterator end() const noexcept
{
return {*this, size()};
}
size_type size()
{
switch (tf)
{
case translation_frames::forward_frame0:
[[fallthrough]];
case translation_frames::reverse_frame0:
return std::ranges::size(urange) / 3;
break;
case translation_frames::forward_frame1:
[[fallthrough]];
case translation_frames::reverse_frame1:
return (std::max<size_type>(std::ranges::size(urange), 1) - 1) / 3;
break;
case translation_frames::forward_frame2:
[[fallthrough]];
case translation_frames::reverse_frame2:
return (std::max<size_type>(std::ranges::size(urange), 2) - 2) / 3;
break;
default:
throw std::invalid_argument(multiple_frame_error.c_str());
break;
}
}
size_type size() const
{
switch (tf)
{
case translation_frames::forward_frame0:
[[fallthrough]];
case translation_frames::reverse_frame0:
return std::ranges::size(urange) / 3;
break;
case translation_frames::forward_frame1:
[[fallthrough]];
case translation_frames::reverse_frame1:
return (std::max<size_type>(std::ranges::size(urange), 1) - 1) / 3;
break;
case translation_frames::forward_frame2:
[[fallthrough]];
case translation_frames::reverse_frame2:
return (std::max<size_type>(std::ranges::size(urange), 2) - 2) / 3;
break;
default:
throw std::invalid_argument(multiple_frame_error.c_str());
break;
}
}
reference operator[](size_type const n)
{
// size will throw (only in debug-builds!) if translation_frames is neither (FWD|REV)_FRAME_(0|1|2),
// we catch that error in debug-builds to make this function consistent with the behaviour in
// release-builds (-DNDEBUG).
#ifndef NDEBUG
try
{
assert(n < size());
}
catch (std::invalid_argument const &)
{}
#endif
switch (tf)
{
case translation_frames::forward_frame0:
return translate_triplet((urange)[n * 3], (urange)[n * 3 + 1], (urange)[n * 3 + 2]);
break;
case translation_frames::reverse_frame0:
return translate_triplet(complement((urange)[(urange).size() - n * 3 - 1]),
complement((urange)[(urange).size() - n * 3 - 2]),
complement((urange)[(urange).size() - n * 3 - 3]));
break;
case translation_frames::forward_frame1:
return translate_triplet((urange)[n * 3 + 1], (urange)[n * 3 + 2], (urange)[n * 3 + 3]);
break;
case translation_frames::reverse_frame1:
return translate_triplet(complement((urange)[(urange).size() - n * 3 - 2]),
complement((urange)[(urange).size() - n * 3 - 3]),
complement((urange)[(urange).size() - n * 3 - 4]));
break;
case translation_frames::forward_frame2:
return translate_triplet((urange)[n * 3 + 2], (urange)[n * 3 + 3], (urange)[n * 3 + 4]);
break;
case translation_frames::reverse_frame2:
return translate_triplet(complement((urange)[(urange).size() - n * 3 - 3]),
complement((urange)[(urange).size() - n * 3 - 4]),
complement((urange)[(urange).size() - n * 3 - 5]));
break;
default:
throw std::invalid_argument(multiple_frame_error.c_str());
break;
}
}
const_reference operator[](size_type const n) const
{
// size will throw (only in debug-builds!) if translation_frames is neither (FWD|REV)_FRAME_(0|1|2),
// we catch that error in debug-builds to make this function consistent with the behaviour in
// release-builds (-DNDEBUG).
#ifndef NDEBUG
try
{
assert(n < size());
}
catch (std::invalid_argument const &)
{}
#endif
switch (tf)
{
case translation_frames::forward_frame0:
return translate_triplet((urange)[n * 3], (urange)[n * 3 + 1], (urange)[n * 3 + 2]);
break;
case translation_frames::reverse_frame0:
return translate_triplet(complement((urange)[(urange).size() - n * 3 - 1]),
complement((urange)[(urange).size() - n * 3 - 2]),
complement((urange)[(urange).size() - n * 3 - 3]));
break;
case translation_frames::forward_frame1:
return translate_triplet((urange)[n * 3 + 1], (urange)[n * 3 + 2], (urange)[n * 3 + 3]);
break;
case translation_frames::reverse_frame1:
return translate_triplet(complement((urange)[(urange).size() - n * 3 - 2]),
complement((urange)[(urange).size() - n * 3 - 3]),
complement((urange)[(urange).size() - n * 3 - 4]));
break;
case translation_frames::forward_frame2:
return translate_triplet((urange)[n * 3 + 2], (urange)[n * 3 + 3], (urange)[n * 3 + 4]);
break;
case translation_frames::reverse_frame2:
return translate_triplet(complement((urange)[(urange).size() - n * 3 - 3]),
complement((urange)[(urange).size() - n * 3 - 4]),
complement((urange)[(urange).size() - n * 3 - 5]));
break;
default:
throw std::invalid_argument(multiple_frame_error.c_str());
break;
}
}
};
template <typename urng_t>
view_translate_single(urng_t &&, translation_frames const) -> view_translate_single<std::views::all_t<urng_t>>;
template <typename urng_t>
view_translate_single(urng_t &&) -> view_translate_single<std::views::all_t<urng_t>>;
} // namespace seqan3::detail
// ============================================================================
// translate_single (adaptor object)
// ============================================================================
namespace seqan3::views
{
inline constexpr auto translate_single = deep{detail::translate_fn<true>{}};
} // namespace seqan3::views
// ============================================================================
// view_translate (range definition)
// ============================================================================
namespace seqan3::detail
{
template <std::ranges::view urng_t>
requires std::ranges::sized_range<urng_t> && std::ranges::random_access_range<urng_t>
&& nucleotide_alphabet<std::ranges::range_reference_t<urng_t>>
class view_translate : public std::ranges::view_base
{
private:
urng_t urange;
translation_frames tf;
small_vector<translation_frames, 6> selected_frames{};
public:
using reference = view_translate_single<urng_t>;
using const_reference = reference;
using value_type = reference;
using size_type = std::ranges::range_size_t<urng_t>;
using difference_type = std::ranges::range_difference_t<urng_t>;
using iterator = detail::random_access_iterator<view_translate>;
using const_iterator = detail::random_access_iterator<view_translate const>;
protected:
// unfortunately we cannot specialise the variable template so we have to add an auxiliary here
template <typename t>
requires (range_dimension_v<t> == range_dimension_v<value_type> + 1)
&& std::is_same_v<std::remove_cvref_t<range_innermost_value_t<value_type>>,
std::remove_cvref_t<range_innermost_value_t<t>>>
static constexpr bool is_compatible_this_aux = true;
public:
view_translate() noexcept = default;
constexpr view_translate(view_translate const & rhs) noexcept = default;
constexpr view_translate(view_translate && rhs) noexcept = default;
constexpr view_translate & operator=(view_translate const & rhs) noexcept = default;
constexpr view_translate & operator=(view_translate && rhs) noexcept = default;
~view_translate() noexcept = default;
view_translate(urng_t _urange, translation_frames const _tf = translation_frames::six_frames) :
urange{std::move(_urange)},
tf{_tf}
{
if ((_tf & translation_frames::forward_frame0) == translation_frames::forward_frame0)
selected_frames.push_back(translation_frames::forward_frame0);
if ((_tf & translation_frames::forward_frame1) == translation_frames::forward_frame1)
selected_frames.push_back(translation_frames::forward_frame1);
if ((_tf & translation_frames::forward_frame2) == translation_frames::forward_frame2)
selected_frames.push_back(translation_frames::forward_frame2);
if ((_tf & translation_frames::reverse_frame0) == translation_frames::reverse_frame0)
selected_frames.push_back(translation_frames::reverse_frame0);
if ((_tf & translation_frames::reverse_frame1) == translation_frames::reverse_frame1)
selected_frames.push_back(translation_frames::reverse_frame1);
if ((_tf & translation_frames::reverse_frame2) == translation_frames::reverse_frame2)
selected_frames.push_back(translation_frames::reverse_frame2);
}
template <typename rng_t>
requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate>) && std::ranges::viewable_range<rng_t>
&& std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
view_translate(rng_t && _urange, translation_frames const _tf) :
view_translate{std::views::all(std::forward<rng_t>(_urange)), _tf}
{}
iterator begin() noexcept
{
return {*this, 0};
}
const_iterator begin() const noexcept
{
return {*this, 0};
}
iterator end() noexcept
{
return {*this, size()};
}
const_iterator end() const noexcept
{
return {*this, size()};
}
size_type size() noexcept
{
return (size_type)selected_frames.size();
}
size_type size() const noexcept
{
return (size_type)selected_frames.size();
}
reference operator[](size_type const n)
{
assert(n < size());
return urange | views::translate_single(selected_frames[n]);
}
const_reference operator[](size_type const n) const
{
assert(n < size());
return urange | views::translate_single(selected_frames[n]);
}
};
template <typename urng_t>
requires std::ranges::sized_range<urng_t> && std::ranges::random_access_range<urng_t>
&& nucleotide_alphabet<std::ranges::range_reference_t<urng_t>>
view_translate(urng_t &&, translation_frames const) -> view_translate<std::views::all_t<urng_t>>;
} // namespace seqan3::detail
// ============================================================================
// translate (adaptor object)
// ============================================================================
namespace seqan3::views
{
inline constexpr auto translate = deep{detail::translate_fn<false>{}};
} // namespace seqan3::views
aa27.hpp
Provides seqan3::aa27, container aliases and string literals.
adaptor_from_functor.hpp
Provides seqan3::detail::adaptor_from_functor.
add_enum_bitwise_operators.hpp
Provides seqan3::add_enum_bitwise_operators.
seqan3::small_string::small_string
small_string(char const(&)[N]) -> small_string< N - 1 >
Deduces small_string from string literals.
seqan3::views::deep
A wrapper type around an existing view adaptor that enables "deep view" behaviour for that view.
Definition deep.hpp:101
type_traits.hpp
Provides various transformation traits used by the range module.
deep.hpp
Provides seqan3::views::deep.
dna5.hpp
Provides seqan3::dna5, container aliases and string literals.
std::forward
T forward(T... args)
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:52
seqan3::complement
constexpr auto complement
Return the complement of a nucleotide object.
Definition alphabet/nucleotide/concept.hpp:102
seqan3::views::translate
constexpr auto translate
A view that translates nucleotide into aminoacid alphabet with 1, 2, 3 or 6 frames.
Definition translate.hpp:800
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:520
seqan3::range_innermost_value_t
typename range_innermost_value< t >::type range_innermost_value_t
Shortcut for seqan3::range_innermost_value (transformation_trait shortcut).
Definition core/range/type_traits.hpp:95
seqan3::range_dimension_v
constexpr size_t range_dimension_v
Returns the number of times you can call seqan3::value_type_t recursively on t (type trait).
Definition core/range/type_traits.hpp:112
seqan3::single
@ single
The text is a single range.
Definition search/fm_index/concept.hpp:71
nucleotide_alphabet
A concept that indicates whether an alphabet represents nucleotides.
std::is_same_v
T is_same_v
std::max
T max(T... args)
seqan3::views
The SeqAn namespace for views.
Definition char_strictly_to.hpp:19
seqan3
The main SeqAn3 namespace.
Definition aligned_sequence_concept.hpp:26
seqan3::small_vector
small_vector(value_type const (&array)[capacity2]) -> small_vector< value_type, capacity2 >
Deducts the size and value type from an built-in array on construction.
seqan3::translation_frames
translation_frames
Specialisation values for single and multiple translation frames.
Definition translate.hpp:59
seqan3::translation_frames::forward_frame2
@ forward_frame2
The third forward frame starting at position 2.
Definition translate.hpp:62
seqan3::translation_frames::forward_frame0
@ forward_frame0
The first forward frame starting at position 0.
Definition translate.hpp:60
seqan3::translation_frames::reverse_frames
@ reverse_frames
All reverse frames.
Definition translate.hpp:70
seqan3::translation_frames::forward_frames
@ forward_frames
All forward frames.
Definition translate.hpp:69
seqan3::translation_frames::six_frames
@ six_frames
All frames.
Definition translate.hpp:71
seqan3::translation_frames::reverse_frame0
@ reverse_frame0
The first reverse frame starting at position 0.
Definition translate.hpp:63
seqan3::translation_frames::forward_reverse2
@ forward_reverse2
The first third and third reverse frame.
Definition translate.hpp:68
seqan3::translation_frames::reverse_frame2
@ reverse_frame2
The third reverse frame starting at position 2.
Definition translate.hpp:65
seqan3::translation_frames::forward_frame1
@ forward_frame1
The second forward frame starting at position 1.
Definition translate.hpp:61
seqan3::translation_frames::reverse_frame1
@ reverse_frame1
The second reverse frame starting at position 1.
Definition translate.hpp:64
seqan3::translation_frames::forward_reverse0
@ forward_reverse0
The first forward and first reverse frame.
Definition translate.hpp:66
seqan3::translation_frames::forward_reverse1
@ forward_reverse1
The second forward and second reverse frame.
Definition translate.hpp:67
small_string.hpp
A constexpr string implementation to manipulate string literals at compile time.
stdexcept
translation.hpp
Provides functions for translating a triplet of nucleotides into an amino acid.
vector
Hide me