SeqAn3  3.0.0
The Modern C++ library for sequence analysis.
aligned_sequence_concept.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2019, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2019, 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>
41  requires Container<container_type<gapped<seq_alph_t>, 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>
58 struct unaligned_seq
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>
86 using unaligned_seq_t = typename unaligned_seq<t>::type;
87 
88 } // namespace seqan3::detail
89 
90 // ---------------------------------------------------------------------------------------------------------------------
91 // AlignedSequence
92 // ---------------------------------------------------------------------------------------------------------------------
93 
94 namespace seqan3
95 {
96 
186 template <typename t>
189 SEQAN3_CONCEPT AlignedSequence =
191  Alphabet<reference_t<t>> &&
192  WeaklyAssignable<reference_t<t>, gap const &> &&
193  requires { typename detail::unaligned_seq_t<t>; } &&
194  requires (t v, detail::unaligned_seq_t<t> unaligned)
195  {
196  { insert_gap(v, v.begin()) } -> typename t::iterator; // global functions for generic usability
197  { insert_gap(v, v.begin(), 2) } -> typename t::iterator;
198  { erase_gap(v, v.begin()) } -> typename t::iterator;
199  { erase_gap(v, v.begin(), v.end()) } -> typename t::iterator;
200  { assign_unaligned(v, unaligned) } -> void;
201  };
203 
204 // ---------------------------------------------------------------------------------------------------------------------
205 // Aligned sequence interface for containers over the seqan3::gapped alphabet
206 // ---------------------------------------------------------------------------------------------------------------------
207 
225 template <SequenceContainer aligned_seq_t>
227  requires detail::is_gapped_alphabet<value_type_t<aligned_seq_t>>
229 inline typename aligned_seq_t::iterator insert_gap(aligned_seq_t & aligned_seq,
230  typename aligned_seq_t::const_iterator pos_it)
231 {
232  return aligned_seq.insert(pos_it, value_type_t<aligned_seq_t>{gap{}});
233 }
234 
248 template <SequenceContainer aligned_seq_t>
250  requires detail::is_gapped_alphabet<value_type_t<aligned_seq_t>>
252 inline typename aligned_seq_t::iterator insert_gap(aligned_seq_t & aligned_seq,
253  typename aligned_seq_t::const_iterator pos_it,
254  typename aligned_seq_t::size_type size)
255 {
256  return aligned_seq.insert(pos_it, size, value_type_t<aligned_seq_t>{gap{}});
257 }
258 
274 template <SequenceContainer aligned_seq_t>
276  requires detail::is_gapped_alphabet<value_type_t<aligned_seq_t>>
278 inline typename aligned_seq_t::iterator erase_gap(aligned_seq_t & aligned_seq,
279  typename aligned_seq_t::const_iterator pos_it)
280 {
281  if (*pos_it != gap{}) // [[unlikely]]
282  throw gap_erase_failure("The position to be erased does not contain a gap.");
283 
284  return aligned_seq.erase(pos_it);
285 }
286 
303 template <SequenceContainer aligned_seq_t>
305  requires detail::is_gapped_alphabet<value_type_t<aligned_seq_t>>
307 inline typename aligned_seq_t::iterator erase_gap(aligned_seq_t & aligned_seq,
308  typename aligned_seq_t::const_iterator first,
309  typename aligned_seq_t::const_iterator last)
310 {
311  for (auto it = first; it != last; ++it)
312  if (*it != gap{}) // [[unlikely]]
313  throw gap_erase_failure("The range to be erased contains at least one non-gap character.");
314 
315  return aligned_seq.erase(first, last);
316 }
317 
340 template <SequenceContainer aligned_seq_t, std::ranges::ForwardRange unaligned_sequence_type>
342  requires detail::is_gapped_alphabet<value_type_t<aligned_seq_t>> &&
343  WeaklyAssignable<reference_t<aligned_seq_t>, reference_t<unaligned_sequence_type>>
345 inline void assign_unaligned(aligned_seq_t & aligned_seq, unaligned_sequence_type && unaligned_seq)
346 {
347  using std::swap;
348  aligned_seq_t tmp;
349  tmp.resize(std::ranges::distance(unaligned_seq));
350  std::copy(std::ranges::begin(unaligned_seq), std::ranges::end(unaligned_seq), std::ranges::begin(tmp));
351  swap(aligned_seq, tmp);
352 }
354 
372 template <typename range_type>
374  requires requires (range_type v)
375  {
376  v.insert_gap(typename range_type::iterator{});
377  v.insert_gap(typename range_type::iterator{}, typename range_type::size_type{});
378  }
380 typename range_type::iterator insert_gap(range_type & rng,
381  typename range_type::iterator const it,
382  typename range_type::size_type const size = 1)
383 {
384  return rng.insert_gap(it, size);
385 }
386 
399 template <typename range_type>
401  requires requires (range_type v) { v.erase_gap(typename range_type::iterator{}); }
403 typename range_type::iterator erase_gap(range_type & rng,
404  typename range_type::iterator const it)
405 {
406  return rng.erase_gap(it);
407 }
408 
423 template <typename range_type>
425  requires requires (range_type v) { v.erase_gap(typename range_type::iterator{}, typename range_type::iterator{}); }
427 typename range_type::iterator erase_gap(range_type & rng,
428  typename range_type::iterator const first,
429  typename range_type::iterator const last)
430 {
431  return rng.erase_gap(first, last);
432 }
434 
435 namespace detail
436 {
437 
445 template<TupleLike alignment_t, size_t ...idx>
446 void stream_alignment(debug_stream_type & stream, alignment_t const & align, std::index_sequence<idx...> const & )
447 {
448  using std::get;
449  size_t const alignment_size = get<0>(align).size();
450 
451  // split alignment into blocks of length 50 and loop over parts
452  for (size_t begin_pos = 0; begin_pos < alignment_size; begin_pos += 50)
453  {
454  size_t const end_pos = std::min(begin_pos + 50, alignment_size);
455 
456  // write header line
457  if (begin_pos != 0)
458  stream << '\n';
459 
460  stream << std::setw(7) << begin_pos << ' ';
461  for (size_t pos = begin_pos + 1; pos <= end_pos; ++pos)
462  {
463  if (pos % 10 == 0)
464  stream << ':';
465  else if (pos % 5 == 0)
466  stream << '.';
467  else
468  stream << ' ';
469  }
470 
471  // write first sequence
472  stream << '\n' << std::setw(8) << "";
473  ranges::for_each(get<0>(align) | view::slice(begin_pos, end_pos) | view::to_char,
474  [&stream] (char ch) { stream << ch; });
475 
476  auto stream_f = [&] (auto const & previous_seq, auto const & aligned_seq)
477  {
478  // write alignment bars
479  stream << '\n' << std::setw(8) << "";
480  ranges::for_each(ranges::zip_view(previous_seq, aligned_seq) | view::slice(begin_pos, end_pos),
481  [&stream] (auto && ch) { stream << (get<0>(ch) == get<1>(ch) ? '|' : ' '); });
482 
483  // write next sequence
484  stream << '\n' << std::setw(8) << "";
485  ranges::for_each(aligned_seq | view::slice(begin_pos, end_pos) | view::to_char,
486  [&stream] (char ch) { stream << ch; });
487  };
488  (stream_f(get<idx>(align), get<idx + 1>(align)), ...);
489  stream << '\n';
490  }
491 }
492 
496 template <typename ...elems>
497 inline bool constexpr all_satisfy_aligned_seq = false;
498 
502 template <typename ...elems>
503 inline bool constexpr all_satisfy_aligned_seq<type_list<elems...>> = (AlignedSequence<elems> && ...);
504 
505 } // namespace detail
506 
514 template <TupleLike tuple_t>
516  requires detail::all_satisfy_aligned_seq<detail::tuple_type_list_t<tuple_t>>
518 inline debug_stream_type & operator<<(debug_stream_type & stream, tuple_t const & alignment)
519 {
520  static_assert(std::tuple_size_v<tuple_t> >= 2, "An alignment requires at least two sequences.");
521  detail::stream_alignment(stream, alignment, std::make_index_sequence<std::tuple_size_v<tuple_t> - 1> {});
522  return stream;
523 }
524 
525 } // namespace seqan
::ranges::distance distance
Alias for ranges::distance. Returns the number of hops from first to last.
Definition: iterator:321
void assign_unaligned(aligned_seq_t &aligned_seq, unaligned_sequence_type &&unaligned_seq)
An implementation of seqan3::AlignedSequence::assign_unaligned_sequence for sequence containers...
Definition: aligned_sequence_concept.hpp:345
typename value_type< t >::type value_type_t
Shortcut for seqan3::value_type (TransformationTrait shortcut).
Definition: pre.hpp:48
T copy(T... args)
aligned_seq_t::iterator insert_gap(aligned_seq_t &aligned_seq, typename aligned_seq_t::const_iterator pos_it)
An implementation of seqan3::AlignedSequence::insert_gap for sequence containers. ...
Definition: aligned_sequence_concept.hpp:229
The alphabet of a gap character &#39;-&#39;.
Definition: gap.hpp:36
T swap(T... args)
::ranges::size size
Alias for ranges::size. Obtains the size of a range whose size can be calculated in constant time...
Definition: ranges:189
The main SeqAn3 namespace.
constexpr auto slice
A view adaptor that returns a half-open interval on the underlying range.
Definition: slice.hpp:144
T setw(T... args)
T min(T... args)
debug_stream_type & operator<<(debug_stream_type &stream, tuple_t const &alignment)
Streaming operator for alignments, which are represented as tuples of aligned sequences.
Definition: aligned_sequence_concept.hpp:518
Provides various type traits.
Provides seqan3::TupleLike.
Adaptations of concepts from the Ranges TS.
::ranges::begin begin
Alias for ranges::begin. Returns an iterator to the beginning of a range.
Definition: ranges:174
Meta-header for the gap submodule; includes all headers from alphabet/gap/.
auto const to_char
A view that calls seqan3::to_char() on each element in the input range.
Definition: to_char.hpp:66
Thrown in function seqan3::erase_gap, if a position does not contain a gap.
Definition: exception.hpp:23
Definition: aligned_sequence_concept.hpp:35
auto const get
A view calling std::get on each element in a range.
Definition: get.hpp:66
aligned_seq_t::iterator erase_gap(aligned_seq_t &aligned_seq, typename aligned_seq_t::const_iterator pos_it)
An implementation of seqan3::AlignedSequence::erase_gap for sequence containers.
Definition: aligned_sequence_concept.hpp:278
Provides seqan3::view::slice.
meta::list< types... > type_list
Type that contains multiple types, an alias for meta::list.
Definition: type_list.hpp:27
Provides seqan3::view::to_char.
Includes customized exception types for the alignment module .
Specifies requirements of a Range type for which begin returns a type that models std::ForwardIterato...
A "pretty printer" for most SeqAn data structures and related types.
Definition: debug_stream.hpp:78
Adaptations of concepts from the standard library.
::ranges::end end
Alias for ranges::end. Returns an iterator to the end of a range.
Definition: ranges:179
Provides seqan3::debug_stream and related types.