SeqAn3
aligned_sequence_concept.hpp
Go to the documentation of this file.
1 // ============================================================================
2 // SeqAn - The Library for Sequence Analysis
3 // ============================================================================
4 //
5 // Copyright (c) 2006-2018, Knut Reinert & Freie Universitaet Berlin
6 // Copyright (c) 2016-2018, Knut Reinert & MPI Molekulare Genetik
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // * Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
14 // * Redistributions in binary form must reproduce the above copyright
15 // notice, this list of conditions and the following disclaimer in the
16 // documentation and/or other materials provided with the distribution.
17 // * Neither the name of Knut Reinert or the FU Berlin nor the names of
18 // its contributors may be used to endorse or promote products derived
19 // from this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
25 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 // DAMAGE.
32 //
33 // ============================================================================
34 
41 #pragma once
42 
43 #include <iomanip>
44 #include <tuple>
45 
46 #include <range/v3/algorithm/for_each.hpp>
47 #include <range/v3/view/slice.hpp>
48 
56 #include <seqan3/std/ranges>
57 
58 namespace seqan3
59 {
60 
61 // -----------------------------------------------------------------------------
62 // aligned_sequence_concept
63 // -----------------------------------------------------------------------------
64 
146 template <typename t>
149 concept aligned_sequence_concept =
153  requires (t v)
154  {
155  { insert_gap(v, v.begin()) } -> typename t::iterator; // global functions for generic usability
156  { insert_gap(v, v.begin(), 2) } -> typename t::iterator;
157  { erase_gap(v, v.begin()) } -> typename t::iterator;
158  { erase_gap(v, v.begin(), v.end()) } -> typename t::iterator;
159  };
161 
162 // -----------------------------------------------------------------------------
163 // Functions that make sequence containers model aligned_sequence_concept
164 // -----------------------------------------------------------------------------
165 
187 template <sequence_container_concept seq_type>
191 inline typename seq_type::iterator insert_gap(seq_type & seq, typename seq_type::const_iterator pos_it)
192 {
193  return seq.insert(pos_it, value_type_t<seq_type>{gap::GAP});
194 }
195 
212 template <sequence_container_concept seq_type>
214  requires weakly_assignable_concept<reference_t<seq_type>, gap const &>
216 inline typename seq_type::iterator insert_gap(seq_type & seq,
217  typename seq_type::const_iterator pos_it,
218  typename seq_type::size_type size)
219 {
220  return seq.insert(pos_it, size, value_type_t<seq_type>{gap::GAP});
221 }
222 
241 template <sequence_container_concept seq_type>
243  requires weakly_assignable_concept<reference_t<seq_type>, gap const &>
245 inline typename seq_type::iterator erase_gap(seq_type & seq, typename seq_type::const_iterator pos_it)
246 {
247  if (*pos_it != gap::GAP) // [[unlikely]]
248  throw gap_erase_failure("The position to be erased does not contain a gap.");
249 
250  return seq.erase(pos_it);
251 }
252 
272 template <sequence_container_concept seq_type>
274  requires weakly_assignable_concept<reference_t<seq_type>, gap const &>
276 inline typename seq_type::iterator erase_gap(seq_type & seq,
277  typename seq_type::const_iterator first,
278  typename seq_type::const_iterator last)
279 {
280  for (auto it = first; it != last; ++it)
281  if (*it != gap::GAP) // [[unlikely]]
282  throw gap_erase_failure("The range to be erased contains at least one non-gap character.");
283 
284  return seq.erase(first, last);
285 }
287 
288 namespace detail
289 {
290 
298 template<tuple_like_concept alignment_t, size_t ...idx>
299 void stream_alignment(debug_stream_type & stream, alignment_t const & align, std::index_sequence<idx...> const & )
300 {
301  using std::get;
302  size_t const alignment_size = get<0>(align).size();
303 
304  // split alignment into blocks of length 50 and loop over parts
305  for (size_t begin_pos = 0; begin_pos < alignment_size; begin_pos += 50)
306  {
307  size_t const end_pos = std::min(begin_pos + 50, alignment_size);
308 
309  // write header line
310  if (begin_pos != 0)
311  stream << '\n';
312 
313  stream << std::setw(7) << begin_pos << ' ';
314  for (size_t pos = begin_pos + 1; pos <= end_pos; ++pos)
315  {
316  if (pos % 10 == 0)
317  stream << ':';
318  else if (pos % 5 == 0)
319  stream << '.';
320  else
321  stream << ' ';
322  }
323 
324  // write first sequence
325  stream << '\n' << std::setw(8) << "";
326  ranges::for_each(get<0>(align) | ranges::view::slice(begin_pos, end_pos) | view::to_char,
327  [&stream] (char ch) { stream << ch; });
328 
329  auto stream_f = [&] (auto const & previous_seq, auto const & aligned_seq)
330  {
331  // write alignment bars
332  stream << '\n' << std::setw(8) << "";
333  ranges::for_each(ranges::zip_view(previous_seq, aligned_seq) | ranges::view::slice(begin_pos, end_pos),
334  [&stream] (auto && ch) { stream << (get<0>(ch) == get<1>(ch) ? '|' : ' '); });
335 
336  // write next sequence
337  stream << '\n' << std::setw(8) << "";
338  ranges::for_each(aligned_seq | ranges::view::slice(begin_pos, end_pos) | view::to_char,
339  [&stream] (char ch) { stream << ch; });
340  };
341  (stream_f(get<idx>(align), get<idx + 1>(align)), ...);
342  stream << '\n';
343  }
344 }
345 
349 template <typename ...elems>
350 inline bool constexpr all_satisfy_aligned_seq = false;
351 
355 template <typename ...elems>
356 inline bool constexpr all_satisfy_aligned_seq<type_list<elems...>> = (aligned_sequence_concept<elems> && ...);
357 
358 } // namespace detail
359 
366 template <tuple_like_concept tuple_t>
368  requires detail::all_satisfy_aligned_seq<detail::tuple_type_list_t<tuple_t>>
370 inline debug_stream_type & operator<<(debug_stream_type & stream, tuple_t const & alignment)
371 {
372  static_assert(std::tuple_size_v<tuple_t> >= 2, "An alignment requires at least two sequences.");
373  detail::stream_alignment(stream, alignment, std::make_index_sequence<std::tuple_size_v<tuple_t> - 1> {});
374  return stream;
375 }
376 
377 } // namespace seqan
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:370
seq_type::iterator erase_gap(seq_type &seq, typename seq_type::const_iterator first, typename seq_type::const_iterator last)
An implementation of seqan3::aligned_sequence_concept::erase_gap for sequence containers.
Definition: aligned_sequence_concept.hpp:276
The alphabet of a gap character &#39;-&#39;.
Definition: gap.hpp:62
The generic concept for an aligned sequence.This concept describes the requirements a sequence must f...
Whether a type behaves like a tuple.
Resolves to std::is_assignable_v<t>.
Provides various metafunctions.
::ranges::size size
Alias for ranges::size. Obtains the size of a range whose size can be calculated in constant time...
Definition: ranges:195
The generic alphabet concept that covers most data types used in ranges.This is the core alphabet con...
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:58
seq_type::iterator erase_gap(seq_type &seq, typename seq_type::const_iterator pos_it)
An implementation of seqan3::aligned_sequence_concept::erase_gap for sequence containers.
Definition: aligned_sequence_concept.hpp:245
seq_type::iterator insert_gap(seq_type &seq, typename seq_type::const_iterator pos_it, typename seq_type::size_type size)
An implementation of seqan3::aligned_sequence_concept::insert_gap for sequence containers.
Definition: aligned_sequence_concept.hpp:216
Provides seqan3::tuple_like_concept.
Adaptations of concepts from the Ranges TS.
Meta-header for the gap submodule; includes all headers from alphabet/gap/.
seq_type::iterator insert_gap(seq_type &seq, typename seq_type::const_iterator pos_it)
An implementation of seqan3::aligned_sequence_concept::insert_gap for sequence containers.
Definition: aligned_sequence_concept.hpp:191
auto const to_char
A view that calls seqan3::to_char() on each element in the input range.
Definition: to_char.hpp:88
Thrown in function seqan3::erase_gap, if a position does not contain a gap.
Definition: exception.hpp:50
Specifies requirements of a Range type for which begin returns a type that models std::ForwardIterato...
auto const get
A view calling std::get on each element in a range.
Definition: get.hpp:88
meta::list< types... > type_list
Type that contains multiple types, an alias for meta::list.
Definition: type_list.hpp:54
Provides seqan3::view::to_char.
typename value_type< t >::type value_type_t
Type metafunction shortcut for seqan3::value_type.
Definition: pre.hpp:72
Includes customized exception types for the alignment module .
A "pretty printer" for most SeqAn data structures and related types.
Definition: debug_stream.hpp:104
Adaptations of concepts from the standard library.
Provides seqan3::debug_stream and related types.