SeqAn3  3.0.1
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 
30 #include <seqan3/std/ranges>
31 
32 // ---------------------------------------------------------------------------------------------------------------------
33 // unaligned_seq transformation trait
34 // ---------------------------------------------------------------------------------------------------------------------
35 
36 namespace seqan3::detail
37 {
38 
40 template <template <typename ...> typename container_type, typename seq_alph_t, typename ...rest_t>
44 constexpr auto remove_gap_from_value_type(container_type<gapped<seq_alph_t>, rest_t...>)
45  -> container_type<seq_alph_t, rest_t...>;
46 
48 template <template <typename ...> typename container_type,
49  template <typename ...> typename allocator_type,
50  typename seq_alph_t, typename ...rest_t>
52  requires container<container_type<gapped<seq_alph_t>, allocator_type<gapped<seq_alph_t>>, rest_t...>>
54 constexpr auto remove_gap_from_value_type(container_type<gapped<seq_alph_t>, allocator_type<gapped<seq_alph_t>>, rest_t...>)
55  -> container_type<seq_alph_t, allocator_type<seq_alph_t>, rest_t...>;
56 
58 template <typename t>
59 struct unaligned_seq
60 {};
61 
63 template <typename t>
65  requires !requires { typename std::remove_reference_t<t>::unaligned_seq_type; } &&
66  requires { remove_gap_from_value_type(std::declval<t>()); }
68 struct unaligned_seq<t>
69 {
71  using type = decltype(remove_gap_from_value_type(std::declval<t>()));
72 };
73 
74 // customisation point for our gap decorators.
76 template <typename t>
78  requires requires { typename std::remove_reference_t<t>::unaligned_seq_type; }
80 struct unaligned_seq<t>
81 {
83 };
84 
86 template <typename t>
87 using unaligned_seq_t = typename unaligned_seq<t>::type;
88 
89 } // namespace seqan3::detail
90 
91 // ---------------------------------------------------------------------------------------------------------------------
92 // aligned_sequence
93 // ---------------------------------------------------------------------------------------------------------------------
94 
95 namespace seqan3
96 {
97 
202 template <typename t>
205 SEQAN3_CONCEPT aligned_sequence =
206  std::ranges::forward_range<t> &&
209  requires { typename detail::unaligned_seq_t<t>; } &&
210  requires (t v, detail::unaligned_seq_t<t> unaligned)
211  {
212  { insert_gap(v, std::ranges::begin(v)) } -> std::ranges::iterator_t<t>; // global functions for generic usability
213  { insert_gap(v, std::ranges::begin(v), 2) } -> std::ranges::iterator_t<t>;
214  { erase_gap(v, std::ranges::begin(v)) } -> std::ranges::iterator_t<t>;
215  { erase_gap(v, std::ranges::begin(v), std::ranges::end(v)) } -> std::ranges::iterator_t<t>;
216  { assign_unaligned(v, unaligned) } -> void;
217  };
219 
220 // ---------------------------------------------------------------------------------------------------------------------
221 // Aligned sequence interface for containers over the seqan3::gapped alphabet
222 // ---------------------------------------------------------------------------------------------------------------------
223 
244 template <sequence_container aligned_seq_t>
246  requires detail::is_gapped_alphabet<value_type_t<aligned_seq_t>>
248 inline typename aligned_seq_t::iterator insert_gap(aligned_seq_t & aligned_seq,
249  typename aligned_seq_t::const_iterator pos_it)
250 {
251  return aligned_seq.insert(pos_it, value_type_t<aligned_seq_t>{gap{}});
252 }
253 
270 template <sequence_container aligned_seq_t>
272  requires detail::is_gapped_alphabet<value_type_t<aligned_seq_t>>
274 inline typename aligned_seq_t::iterator insert_gap(aligned_seq_t & aligned_seq,
275  typename aligned_seq_t::const_iterator pos_it,
276  typename aligned_seq_t::size_type size)
277 {
278  return aligned_seq.insert(pos_it, size, value_type_t<aligned_seq_t>{gap{}});
279 }
280 
300 template <sequence_container aligned_seq_t>
302  requires detail::is_gapped_alphabet<value_type_t<aligned_seq_t>>
304 inline typename aligned_seq_t::iterator erase_gap(aligned_seq_t & aligned_seq,
305  typename aligned_seq_t::const_iterator pos_it)
306 {
307  if (*pos_it != gap{}) // [[unlikely]]
308  throw gap_erase_failure("The position to be erased does not contain a gap.");
309 
310  return aligned_seq.erase(pos_it);
311 }
312 
333 template <sequence_container aligned_seq_t>
335  requires detail::is_gapped_alphabet<value_type_t<aligned_seq_t>>
337 inline typename aligned_seq_t::iterator erase_gap(aligned_seq_t & aligned_seq,
338  typename aligned_seq_t::const_iterator first,
339  typename aligned_seq_t::const_iterator last)
340 {
341  for (auto it = first; it != last; ++it)
342  if (*it != gap{}) // [[unlikely]]
343  throw gap_erase_failure("The range to be erased contains at least one non-gap character.");
344 
345  return aligned_seq.erase(first, last);
346 }
347 
370 template <sequence_container aligned_seq_t, std::ranges::forward_range unaligned_sequence_type>
372  requires detail::is_gapped_alphabet<value_type_t<aligned_seq_t>> &&
373  weakly_assignable_from<reference_t<aligned_seq_t>, 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 <tuple_like tuple_t, typename char_t>
557  requires detail::all_satisfy_aligned_seq<detail::tuple_type_list_t<tuple_t>>
559 inline debug_stream_type<char_t> & operator<<(debug_stream_type<char_t> & stream, tuple_t const & alignment)
560 {
561  static_assert(std::tuple_size_v<tuple_t> >= 2, "An alignment requires at least two sequences.");
562  detail::stream_alignment(stream, alignment, std::make_index_sequence<std::tuple_size_v<tuple_t> - 1> {});
563  return stream;
564 }
565 
566 } // 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:304
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.
all.hpp
Provides various type traits.
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:248
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::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
slice.hpp
Provides seqan3::views::slice.
seqan3::value_type_t
typename value_type< t >::type value_type_t
Shortcut for seqan3::value_type (transformation_trait shortcut).
Definition: pre.hpp:48
seqan3
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:36
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.
seqan3::operator<<
debug_stream_type< char_t > & operator<<(debug_stream_type< char_t > &stream, tuple_t const &alignment)
Stream operator for alignments, which are represented as tuples of aligned sequences.
Definition: aligned_sequence_concept.hpp:559
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::views::slice
constexpr auto slice
A view adaptor that returns a half-open interval on the underlying range.
Definition: slice.hpp:141
std::setw
T setw(T... args)
all.hpp
Meta-header for the gap submodule; includes all headers from alphabet/gap/.
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
The (pairwise) alignment stored in an seqan3::alignment object.