SeqAn3  3.0.2
The Modern C++ library for sequence analysis.
aligned_sequence_concept.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 
14 #pragma once
15 
16 #include <iomanip>
17 #include <tuple>
18 
19 #include <range/v3/algorithm/for_each.hpp>
20 
29 #include <seqan3/std/ranges>
30 
31 // ---------------------------------------------------------------------------------------------------------------------
32 // unaligned_seq transformation trait
33 // ---------------------------------------------------------------------------------------------------------------------
34 
35 namespace seqan3::detail
36 {
37 
39 template <template <typename ...> typename container_type, typename seq_alph_t, typename ...rest_t>
43 constexpr auto remove_gap_from_value_type(container_type<gapped<seq_alph_t>, rest_t...>)
44  -> container_type<seq_alph_t, rest_t...>;
45 
47 template <template <typename ...> typename container_type,
48  template <typename ...> typename allocator_type,
49  typename seq_alph_t, typename ...rest_t>
51  requires container<container_type<gapped<seq_alph_t>, allocator_type<gapped<seq_alph_t>>, rest_t...>>
53 constexpr auto remove_gap_from_value_type(container_type<gapped<seq_alph_t>, allocator_type<gapped<seq_alph_t>>, rest_t...>)
54  -> container_type<seq_alph_t, allocator_type<seq_alph_t>, rest_t...>;
55 
57 template <typename t>
59 {};
60 
62 template <typename t>
64  requires (!requires { typename std::remove_reference_t<t>::unaligned_seq_type; }) &&
65  requires { remove_gap_from_value_type(std::declval<t>()); }
67 struct unaligned_seq<t>
68 {
70  using type = decltype(remove_gap_from_value_type(std::declval<t>()));
71 };
72 
73 // customisation point for our gap decorators.
75 template <typename t>
77  requires requires { typename std::remove_reference_t<t>::unaligned_seq_type; }
79 struct unaligned_seq<t>
80 {
82 };
83 
85 template <typename t>
87 
88 } // namespace seqan3::detail
89 
90 // ---------------------------------------------------------------------------------------------------------------------
91 // aligned_sequence
92 // ---------------------------------------------------------------------------------------------------------------------
93 
94 namespace seqan3
95 {
96 
201 template <typename t>
204 SEQAN3_CONCEPT aligned_sequence =
205  std::ranges::forward_range<t> &&
208  requires { typename detail::unaligned_seq_t<t>; } &&
209  requires (t v, detail::unaligned_seq_t<t> unaligned)
210  {
211  { insert_gap(v, std::ranges::begin(v)) } -> std::ranges::iterator_t<t>; // global functions for generic usability
212  { insert_gap(v, std::ranges::begin(v), 2) } -> std::ranges::iterator_t<t>;
213  { erase_gap(v, std::ranges::begin(v)) } -> std::ranges::iterator_t<t>;
214  { erase_gap(v, std::ranges::begin(v), std::ranges::end(v)) } -> std::ranges::iterator_t<t>;
215  { assign_unaligned(v, unaligned) } -> void;
216  };
218 
219 // ---------------------------------------------------------------------------------------------------------------------
220 // Aligned sequence interface for containers over the seqan3::gapped alphabet
221 // ---------------------------------------------------------------------------------------------------------------------
222 
243 template <sequence_container aligned_seq_t>
245  requires detail::is_gapped_alphabet<std::iter_value_t<aligned_seq_t>>
247 inline typename aligned_seq_t::iterator insert_gap(aligned_seq_t & aligned_seq,
248  typename aligned_seq_t::const_iterator pos_it)
249 {
250  return aligned_seq.insert(pos_it, std::iter_value_t<aligned_seq_t>{gap{}});
251 }
252 
269 template <sequence_container aligned_seq_t>
271  requires detail::is_gapped_alphabet<std::iter_value_t<aligned_seq_t>>
273 inline typename aligned_seq_t::iterator insert_gap(aligned_seq_t & aligned_seq,
274  typename aligned_seq_t::const_iterator pos_it,
275  typename aligned_seq_t::size_type size)
276 {
277  return aligned_seq.insert(pos_it, size, std::iter_value_t<aligned_seq_t>{gap{}});
278 }
279 
299 template <sequence_container aligned_seq_t>
301  requires detail::is_gapped_alphabet<std::iter_value_t<aligned_seq_t>>
303 inline typename aligned_seq_t::iterator erase_gap(aligned_seq_t & aligned_seq,
304  typename aligned_seq_t::const_iterator pos_it)
305 {
306  if (*pos_it != gap{}) // [[unlikely]]
307  throw gap_erase_failure("The position to be erased does not contain a gap.");
308 
309  return aligned_seq.erase(pos_it);
310 }
311 
332 template <sequence_container aligned_seq_t>
334  requires detail::is_gapped_alphabet<std::iter_value_t<aligned_seq_t>>
336 inline typename aligned_seq_t::iterator erase_gap(aligned_seq_t & aligned_seq,
337  typename aligned_seq_t::const_iterator first,
338  typename aligned_seq_t::const_iterator last)
339 {
340  for (auto it = first; it != last; ++it)
341  if (*it != gap{}) // [[unlikely]]
342  throw gap_erase_failure("The range to be erased contains at least one non-gap character.");
343 
344  return aligned_seq.erase(first, last);
345 }
346 
369 template <sequence_container aligned_seq_t, std::ranges::forward_range unaligned_sequence_type>
371  requires detail::is_gapped_alphabet<std::iter_value_t<aligned_seq_t>> &&
373  std::ranges::range_reference_t<unaligned_sequence_type>>
375 inline void assign_unaligned(aligned_seq_t & aligned_seq, unaligned_sequence_type && unaligned_seq)
376 {
377  using std::swap;
378  aligned_seq_t tmp;
379  tmp.resize(std::ranges::distance(unaligned_seq));
380  std::ranges::copy(unaligned_seq, std::ranges::begin(tmp));
381  swap(aligned_seq, tmp);
382 }
384 
405 template <typename range_type>
407  requires requires (range_type v)
408  {
409  v.insert_gap(std::ranges::iterator_t<range_type>{});
410  v.insert_gap(std::ranges::iterator_t<range_type>{}, typename range_type::size_type{});
411  }
413 std::ranges::iterator_t<range_type> insert_gap(range_type & rng,
414  std::ranges::iterator_t<range_type> const pos_it,
415  typename range_type::size_type const size = 1)
416 {
417  return rng.insert_gap(pos_it, size);
418 }
419 
436 template <typename range_type>
438  requires requires (range_type v) { v.erase_gap(std::ranges::iterator_t<range_type>{}); }
440 std::ranges::iterator_t<range_type> erase_gap(range_type & rng,
441  std::ranges::iterator_t<range_type> const pos_it)
442 {
443  return rng.erase_gap(pos_it);
444 }
445 
464 template <typename range_type>
466  requires requires (range_type v) { v.erase_gap(std::ranges::iterator_t<range_type>{}, std::ranges::iterator_t<range_type>{}); }
468 std::ranges::iterator_t<range_type> erase_gap(range_type & rng,
469  std::ranges::iterator_t<range_type> const first,
470  std::ranges::iterator_t<range_type> const last)
471 {
472  return rng.erase_gap(first, last);
473 }
475 
476 namespace detail
477 {
478 
486 template <typename char_t, tuple_like alignment_t, size_t ...idx>
487 void stream_alignment(debug_stream_type<char_t> & stream, alignment_t const & align, std::index_sequence<idx...> const & )
488 {
489  using std::get;
490  size_t const alignment_size = get<0>(align).size();
491 
492  // split alignment into blocks of length 50 and loop over parts
493  for (size_t begin_pos = 0; begin_pos < alignment_size; begin_pos += 50)
494  {
495  size_t const end_pos = std::min(begin_pos + 50, alignment_size);
496 
497  // write header line
498  if (begin_pos != 0)
499  stream << '\n';
500 
501  stream << std::setw(7) << begin_pos << ' ';
502  for (size_t pos = begin_pos + 1; pos <= end_pos; ++pos)
503  {
504  if (pos % 10 == 0)
505  stream << ':';
506  else if (pos % 5 == 0)
507  stream << '.';
508  else
509  stream << ' ';
510  }
511 
512  // write first sequence
513  stream << '\n' << std::setw(8) << "";
514  std::ranges::for_each(get<0>(align) | views::slice(begin_pos, end_pos) | views::to_char,
515  [&stream] (char ch) { stream << ch; });
516 
517  auto stream_f = [&] (auto const & previous_seq, auto const & aligned_seq)
518  {
519  // write alignment bars
520  stream << '\n' << std::setw(8) << "";
521  std::ranges::for_each(views::zip(previous_seq, aligned_seq) | views::slice(begin_pos, end_pos),
522  [&stream] (auto && ch) { stream << (get<0>(ch) == get<1>(ch) ? '|' : ' '); });
523 
524  // write next sequence
525  stream << '\n' << std::setw(8) << "";
526  std::ranges::for_each(aligned_seq | views::slice(begin_pos, end_pos) | views::to_char,
527  [&stream] (char ch) { stream << ch; });
528  };
529  (stream_f(get<idx>(align), get<idx + 1>(align)), ...);
530  stream << '\n';
531  }
532 }
533 
537 template <typename ...elems>
538 inline bool constexpr all_satisfy_aligned_seq = false;
539 
543 template <typename ...elems>
544 inline bool constexpr all_satisfy_aligned_seq<type_list<elems...>> = (aligned_sequence<elems> && ...);
545 
546 } // namespace detail
547 
555 template <typename tuple_t, typename char_t>
557  requires (!std::ranges::input_range<tuple_t>) &&
558  (!alphabet<tuple_t>) && // exclude alphabet_tuple_base
562 inline debug_stream_type<char_t> & operator<<(debug_stream_type<char_t> & stream, tuple_t && alignment)
563 {
564  static_assert(std::tuple_size_v<remove_cvref_t<tuple_t>> >= 2, "An alignment requires at least two sequences.");
566  return stream;
567 }
568 
569 } // namespace seqan
seqan3::gap
The alphabet of a gap character '-'.
Definition: gap.hpp:36
zip.hpp
Provides seqan3::views::zip.
seqan3::erase_gap
aligned_seq_t::iterator erase_gap(aligned_seq_t &aligned_seq, typename aligned_seq_t::const_iterator pos_it)
An implementation of seqan3::aligned_sequence::erase_gap for sequence containers.
Definition: aligned_sequence_concept.hpp:303
seqan3::views::to_char
const auto to_char
A view that calls seqan3::to_char() on each element in the input range.
Definition: to_char.hpp:65
seqan3::type_list
meta::list< types... > type_list
Type that contains multiple types, an alias for meta::list.
Definition: type_list.hpp:31
tuple.hpp
Provides seqan3::tuple_like.
std::index_sequence
seqan3::gap_erase_failure
Thrown in function seqan3::erase_gap, if a position does not contain a gap.
Definition: exception.hpp:23
seqan3::insert_gap
aligned_seq_t::iterator insert_gap(aligned_seq_t &aligned_seq, typename aligned_seq_t::const_iterator pos_it)
An implementation of seqan3::aligned_sequence::insert_gap for sequence containers.
Definition: aligned_sequence_concept.hpp:247
aligned_sequence
The generic concept for an aligned sequence.
concept.hpp
Adaptations of concepts from the standard library.
tuple
debug_stream_type.hpp
Provides seqan3::debug_stream and related types.
exception.hpp
Includes customized exception types for the alignment module .
seqan3::detail::remove_gap_from_value_type
constexpr auto remove_gap_from_value_type(container_type< gapped< seq_alph_t >, rest_t... >) -> container_type< seq_alph_t, rest_t... >
Helper function to deduce the unaligned sequence type from an aligned sequence container.
seqan3::detail::stream_alignment
void stream_alignment(debug_stream_type< char_t > &stream, alignment_t const &align, std::index_sequence< idx... > const &)
Create the formatted alignment output and add it to the provided debug_stream.
Definition: aligned_sequence_concept.hpp:487
seqan3::debug_stream_type
A "pretty printer" for most SeqAn data structures and related types.
Definition: debug_stream_type.hpp:70
seqan3::alphabet_variant
A combined alphabet that can hold values of either of its alternatives.
Definition: alphabet_variant.hpp:129
seqan3::views::get
const auto get
A view calling std::get on each element in a range.
Definition: get.hpp:65
seqan3::detail::unaligned_seq< t >::type
decltype(remove_gap_from_value_type(std::declval< t >())) type
The unaligned sequence type of t.
Definition: aligned_sequence_concept.hpp:70
seqan3::detail::unaligned_seq
Default transformation trait that shall expose the unaligned sequence type of t when specialised.
Definition: aligned_sequence_concept.hpp:58
slice.hpp
Provides seqan3::views::slice.
gapped.hpp
Provides seqan3::gapped.
seqan3::detail::for_each
constexpr void for_each(unary_function_t &&fn, pack_t &&...args)
Applies a function to each element of the given function parameter pack.
Definition: pack_algorithm.hpp:195
seqan3::detail::all_satisfy_aligned_seq
constexpr bool all_satisfy_aligned_seq
True, if each type satisfies aligned_sequence; false otherwise.
Definition: aligned_sequence_concept.hpp:538
seqan3
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:35
seqan3::detail::tuple_type_list_t
typename tuple_type_list< tuple_t >::type tuple_type_list_t
Helper type for seqan3::detail::tuple_type_list.
Definition: tuple.hpp:111
std::iter_value_t
seqan3::pack_traits::size
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:116
tuple_like
Whether a type behaves like a tuple.
std::swap
T swap(T... args)
std::min
T min(T... args)
to_char.hpp
Provides seqan3::views::to_char.
ranges
Adaptations of concepts from the Ranges TS.
std::remove_reference_t
iomanip
alphabet
The generic alphabet concept that covers most data types used in ranges.
container
The (most general) container concept as defined by the standard library.
weakly_assignable_from
Resolves to std::is_assignable_v<t>.
seqan3::detail::unaligned_seq_t
typename unaligned_seq< t >::type unaligned_seq_t
Helper type that delegates to seqan3::detail::unaligned_seq::type.
Definition: aligned_sequence_concept.hpp:86
seqan3::views::slice
constexpr auto slice
A view adaptor that returns a half-open interval on the underlying range.
Definition: slice.hpp:141
std::remove_cv_t
seqan3::detail
The internal SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:35
std::setw
T setw(T... args)
std::tuple_size_v
T tuple_size_v
seqan3::assign_unaligned
void assign_unaligned(aligned_seq_t &aligned_seq, unaligned_sequence_type &&unaligned_seq)
An implementation of seqan3::aligned_sequence::assign_unaligned_sequence for sequence containers.
Definition: aligned_sequence_concept.hpp:375
seqan3::field::alignment
@ alignment
The (pairwise) alignment stored in an seqan3::alignment object.