Skip to content

Commit

Permalink
[MISC] introduce new concepts seqan3::detail::(writable_)pairwise_ali…
Browse files Browse the repository at this point in the history
…gnment

This PR finishes task seqan/product_backlog#60
by implementing seqan3::detail::(writable_)pairwise_alignment.
  • Loading branch information
marehr committed Jan 28, 2021
1 parent e285c14 commit b64e766
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -510,16 +510,4 @@ inline bool constexpr all_model_aligned_seq = (aligned_sequence<elems> && ...);
*/
template <typename ...elems>
inline bool constexpr all_model_aligned_seq<type_list<elems...>> = all_model_aligned_seq<elems...>;

/*!\brief True, if each type models seqan3::writable_aligned_sequence; false otherwise.
* \tparam elems The pack of types to be tested.
*/
template <typename ...elems>
inline bool constexpr all_model_writable_aligned_seq = (writable_aligned_sequence<elems> && ...);

/*!\brief True, if each type in the seqan3::type_list models seqan3::writable_aligned_sequence; false otherwise.
* \tparam elems The pack of types to be tested.
*/
template <typename ...elems>
inline bool constexpr all_model_writable_aligned_seq<type_list<elems...>> = all_model_writable_aligned_seq<elems...>;
} // namespace seqan3::detail
54 changes: 54 additions & 0 deletions include/seqan3/alignment/detail/pairwise_alignment_concept.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
// Copyright (c) 2016-2020, Knut Reinert & MPI für molekulare Genetik
// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
// shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
// -----------------------------------------------------------------------------------------------------

/*!\file
* \brief Provides seqan3::detail::pairwise_alignment and seqan3::detail::writable_pairwise_alignment.
* \author Marcel Ehrhardt <marcel.ehrhardt AT fu-berlin.de>
*/

#pragma once

#include <seqan3/alignment/aligned_sequence/aligned_sequence_concept.hpp>

namespace seqan3::detail
{

/*!\interface seqan3::detail::pairwise_alignment < >
* \extends seqan3::pair_like
* \ingroup alignment
* \brief A concept that models a pairwise alignment type.
*
* \details
*
* A pairwise alignment is a seqan3::pair_like of two seqan3::aligned_sequence's.
*/
//!\cond
template <typename pairwise_alignment_t>
SEQAN3_CONCEPT pairwise_alignment =
pair_like<pairwise_alignment_t> &&
aligned_sequence<std::tuple_element_t<0, std::remove_reference_t<pairwise_alignment_t>>> &&
aligned_sequence<std::tuple_element_t<1, std::remove_reference_t<pairwise_alignment_t>>>;
//!\endcond

/*!\interface seqan3::detail::writable_pairwise_alignment < >
* \extends seqan3::detail::pairwise_alignment
* \ingroup alignment
* \brief A concept that models a writable pairwise alignment type.
*
* \details
*
* A writable pairwise alignment is a seqan3::pair_like of two seqan3::writable_aligned_sequence's.
*/
//!\cond
template <typename pairwise_alignment_t>
SEQAN3_CONCEPT writable_pairwise_alignment =
pairwise_alignment<pairwise_alignment_t> &&
writable_aligned_sequence<std::tuple_element_t<0, std::remove_reference_t<pairwise_alignment_t>>> &&
writable_aligned_sequence<std::tuple_element_t<1, std::remove_reference_t<pairwise_alignment_t>>>;
//!\endcond

} // namespace seqan3::detail
57 changes: 17 additions & 40 deletions include/seqan3/io/alignment_file/detail.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#include <seqan3/std/ranges>
#include <sstream>

#include <seqan3/alignment/aligned_sequence/aligned_sequence_concept.hpp>
#include <seqan3/alignment/detail/pairwise_alignment_concept.hpp>
#include <seqan3/alphabet/cigar/cigar.hpp>
#include <seqan3/core/debug_stream/detail/to_string.hpp>
#include <seqan3/range/views/single_pass_input.hpp>
Expand All @@ -41,7 +41,7 @@ struct view_equality_fn
}
};

/*!\brief Compares two aligned sequence values and returns their cigar operation.
/*!\brief Compares two seqan3::aligned_sequence values and returns their cigar operation.
* \ingroup alignment_file
* \tparam reference_char_type Must be equality comparable to seqan3::gap.
* \tparam query_char_type Must be equality comparable to seqan3::gap.
Expand Down Expand Up @@ -97,11 +97,11 @@ template <typename reference_char_type, typename query_char_type>
return assign_char_to(operators[key], cigar_op{});
}

/*!\brief Creates a cigar string (SAM format) given an alignment represented by two aligned sequences.
/*!\brief Creates a cigar string (SAM format) given a seqan3::detail::pairwise_alignment represented by two
* seqan3::aligned_sequence's.
* \ingroup alignment_file
*
* \tparam alignment_type Must model the seqan3::tuple_like and must have std::tuple_size 2.
* Each tuple element must be a range over values comparable to seqan3::gap.
* \tparam alignment_type Must model seqan3::detail::pairwise_alignment.
* \param alignment The alignment, represented by a pair of aligned sequences,
* to be transformed into cigar vector based on the
* second (query) sequence.
Expand All @@ -110,7 +110,7 @@ template <typename reference_char_type, typename query_char_type>
* \param query_end_pos The end position of the alignment in the query
* sequence indicating soft-clipping.
* \param extended_cigar Whether to print the extended cigar alphabet or not. See cigar operation.
* \returns An std::vector<seqan3::cigar> representing the alignment.
* \returns An std::vector\<seqan3::cigar\> representing the alignment.
*
* \details
*
Expand All @@ -134,14 +134,11 @@ template <typename reference_char_type, typename query_char_type>
*
* \sa seqan3::aligned_sequence
*/
template <tuple_like alignment_type>
template <seqan3::detail::pairwise_alignment alignment_type>
[[nodiscard]] inline std::vector<cigar> get_cigar_vector(alignment_type && alignment,
uint32_t const query_start_pos = 0,
uint32_t const query_end_pos = 0,
bool const extended_cigar = false)
//!\cond
requires (std::tuple_size_v<std::remove_cvref_t<alignment_type>> == 2)
//!\endcond
{
using std::get;

Expand Down Expand Up @@ -197,10 +194,6 @@ template <tuple_like alignment_type>
* \ingroup alignment_file
* \param cigar_vector The std::vector of seqan3::cigar elements to be transformed into a std::string.
* \returns The cigar string (std::string).
*
* \details
*
* The transformation is done by printing the vector with the seqan3::debug_stream.
*/
[[nodiscard]] inline std::string get_cigar_string(std::vector<cigar> const & cigar_vector)
{
Expand All @@ -209,12 +202,11 @@ template <tuple_like alignment_type>
return result;
}

/*!\brief Creates a cigar string (SAM format) given an alignment represented by two aligned sequences.
/*!\brief Creates a cigar string (SAM format) given a seqan3::detail::pairwise_alignment.
* \ingroup alignment_file
*
* \tparam alignment_type Must model the seqan3::tuple_like and must have std::tuple_size 2.
* Each tuple element must be a range over values comparable to seqan3::gap.
* \param alignment The alignment, represented by a pair of aligned sequences,
* \tparam alignment_type Must model seqan3::detail::pairwise_alignment.
* \param alignment The alignment, represented by a seqan3::pair_like of seqan3::aligned_sequence's,
* to be transformed into cigar vector based on the
* second (query) sequence.
* \param query_start_pos The start position of the alignment in the query
Expand Down Expand Up @@ -243,26 +235,20 @@ template <tuple_like alignment_type>
* string would look like this: "3=1X2I3=1X1=2D1=".
* \sa seqan3::aligned_sequence
*/
template <tuple_like alignment_type>
template <seqan3::detail::pairwise_alignment alignment_type>
[[nodiscard]] inline std::string get_cigar_string(alignment_type && alignment,
uint32_t const query_start_pos = 0,
uint32_t const query_end_pos = 0,
bool const extended_cigar = false)
//!\cond
requires (std::tuple_size_v<std::remove_cvref_t<alignment_type>> == 2)
//!\endcond
{
return get_cigar_string(get_cigar_vector(alignment, query_start_pos, query_end_pos, extended_cigar));
}

/*!\brief Transforms an alignment represented by two aligned sequences into the
* corresponding cigar string.
/*!\brief Transforms an alignment represented by two seqan3::aligned_sequence's into the corresponding cigar string.
* \ingroup alignment_file
*
* \tparam ref_seq_type Must model std::ranges::forward_range. The value_type must
* be equality comparable to seqan3::gap.
* \tparam query_seq_type Must model std::ranges::forward_range. The value_type must
* be equality comparable to seqan3::gap.
* \tparam ref_seq_type Must model seqan3::aligned_sequence.
* \tparam query_seq_type Must model seqan3::aligned_sequence.
* \param ref_seq The reference sequence to compare against the query sequence.
* \param query_seq The query sequence to build the cigar string for.
* \param query_start_pos The start position of the alignment in the query
Expand Down Expand Up @@ -291,25 +277,20 @@ template <tuple_like alignment_type>
*
* \sa seqan3::aligned_sequence
*/
template <std::ranges::forward_range ref_seq_type, std::ranges::forward_range query_seq_type>
template <seqan3::aligned_sequence ref_seq_type, seqan3::aligned_sequence query_seq_type>
[[nodiscard]] inline std::string get_cigar_string(ref_seq_type && ref_seq,
query_seq_type && query_seq,
uint32_t const query_start_pos = 0,
uint32_t const query_end_pos = 0,
bool const extended_cigar = false)
//!\cond
requires seqan3::detail::weakly_equality_comparable_with<gap, std::ranges::range_reference_t<ref_seq_type>> &&
seqan3::detail::weakly_equality_comparable_with<gap, std::ranges::range_reference_t<query_seq_type>>
//!\endcond
{
return get_cigar_string(std::tie(ref_seq, query_seq), query_start_pos, query_end_pos, extended_cigar);
}

/*!\brief Transforms a std::vector of operation-count pairs (representing the cigar string).
* \ingroup alignment_file
*
* \tparam alignment_type The type of alignment; must model seqan3::tuple_like and all tuple element types
* must model seqan3::writable_aligned_sequence.
* \tparam alignment_type The type of alignment; must model seqan3::detail::writable_pairwise_alignment.
*
* \param[in,out] alignment The alignment to fill with gaps according to the cigar information.
* \param[in] cigar_vector The cigar information given as a std::vector over seqan3::cigar.
Expand All @@ -328,11 +309,7 @@ template <std::ranges::forward_range ref_seq_type, std::ranges::forward_range qu
* ATGCCCCGTTG--C
* ```
*/
template <tuple_like alignment_type>
//!\cond
requires (std::tuple_size_v<std::remove_cvref_t<alignment_type>> == 2) &&
detail::all_model_writable_aligned_seq<detail::tuple_type_list_t<alignment_type>>
//!\endcond
template <seqan3::detail::writable_pairwise_alignment alignment_type>
inline void alignment_from_cigar(alignment_type & alignment, std::vector<cigar> const & cigar_vector)
{
using std::get;
Expand Down
2 changes: 1 addition & 1 deletion include/seqan3/io/record.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ enum class field
comment, //!< Comment field of arbitrary content, usually a string.

// Fields unique to alignment io ...........................................
alignment, //!< The (pairwise) alignment stored in an seqan3::alignment object.
alignment, //!< The (pairwise) alignment stored in an object that models seqan3::detail::pairwise_alignment.
ref_id, //!< The identifier of the (reference) sequence that SEQ was aligned to.
ref_seq, //!< The (reference) "sequence" information, usually a range of nucleotides or amino acids.
ref_offset, //!< Sequence (REF_SEQ) relative start position (0-based), unsigned value.
Expand Down
1 change: 1 addition & 0 deletions test/unit/alignment/detail/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
seqan3_test(pairwise_alignment_concept_test.cpp)
109 changes: 109 additions & 0 deletions test/unit/alignment/detail/pairwise_alignment_concept_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
// Copyright (c) 2016-2020, Knut Reinert & MPI für molekulare Genetik
// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
// shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
// -----------------------------------------------------------------------------------------------------

#include <gtest/gtest.h>

#include <seqan3/alignment/detail/pairwise_alignment_concept.hpp>
#include <seqan3/alphabet/gap/gapped.hpp>
#include <seqan3/alphabet/nucleotide/dna4.hpp>
#include <seqan3/alphabet/nucleotide/dna5.hpp>

TEST(pairwise_alignment_concept, std_pair_gapped_sequences)
{
using gapped_sequence1_t = std::vector<seqan3::gapped<seqan3::dna4>>;
using gapped_sequence2_t = std::vector<seqan3::gapped<seqan3::dna4>>;
using alignment_t = std::pair<gapped_sequence1_t, gapped_sequence2_t>;

EXPECT_FALSE((seqan3::detail::pairwise_alignment<gapped_sequence1_t>));
EXPECT_FALSE((seqan3::detail::pairwise_alignment<gapped_sequence2_t>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t const>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t &>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t const &>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t &&>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t const &&>));
}

TEST(pairwise_alignment_concept, std_tuple_gapped_sequences)
{
using gapped_sequence1_t = std::vector<seqan3::gapped<seqan3::dna4>> const;
using gapped_sequence2_t = std::vector<seqan3::gapped<seqan3::dna5>>;
using alignment_t = std::tuple<gapped_sequence1_t, gapped_sequence2_t>;

EXPECT_FALSE((seqan3::detail::pairwise_alignment<gapped_sequence1_t>));
EXPECT_FALSE((seqan3::detail::pairwise_alignment<gapped_sequence2_t>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t const>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t &>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t const &>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t &&>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t const &&>));
}

TEST(pairwise_alignment_concept, std_tuple_gap_sequence)
{
using gap_sequence1_t = std::vector<seqan3::gap> const;
using gap_sequence2_t = std::vector<seqan3::gap>;
using alignment_t = std::tuple<gap_sequence1_t, gap_sequence2_t>;

EXPECT_FALSE((seqan3::detail::pairwise_alignment<gap_sequence1_t>));
EXPECT_FALSE((seqan3::detail::pairwise_alignment<gap_sequence2_t>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t const>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t &>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t const &>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t &&>));
EXPECT_TRUE((seqan3::detail::pairwise_alignment<alignment_t const &&>));
}

TEST(writable_pairwise_alignment_concept, std_pair_gapped_sequences)
{
using gapped_sequence1_t = std::vector<seqan3::gapped<seqan3::dna4>>;
using gapped_sequence2_t = std::vector<seqan3::gapped<seqan3::dna4>>;
using alignment_t = std::pair<gapped_sequence1_t, gapped_sequence2_t>;

EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<gapped_sequence1_t>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<gapped_sequence2_t>));
EXPECT_TRUE((seqan3::detail::writable_pairwise_alignment<alignment_t>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<alignment_t const>));
EXPECT_TRUE((seqan3::detail::writable_pairwise_alignment<alignment_t &>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<alignment_t const &>));
EXPECT_TRUE((seqan3::detail::writable_pairwise_alignment<alignment_t &&>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<alignment_t const &&>));
}

TEST(writable_pairwise_alignment_concept, std_tuple_gapped_sequences)
{
using gapped_sequence1_t = std::vector<seqan3::gapped<seqan3::dna4>>;
using gapped_sequence2_t = std::vector<seqan3::gapped<seqan3::dna5>> const;
using alignment_t = std::tuple<gapped_sequence1_t, gapped_sequence2_t>;

EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<gapped_sequence1_t>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<gapped_sequence2_t>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<alignment_t>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<alignment_t const>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<alignment_t &>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<alignment_t const &>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<alignment_t &&>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<alignment_t const &&>));
}

TEST(writable_pairwise_alignment_concept, std_tuple_gap_sequence)
{
using gap_sequence1_t = std::vector<seqan3::gap>;
using gap_sequence2_t = std::vector<seqan3::gap> const;
using alignment_t = std::tuple<gap_sequence1_t, gap_sequence2_t>;

EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<gap_sequence1_t>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<gap_sequence2_t>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<alignment_t>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<alignment_t const>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<alignment_t &>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<alignment_t const &>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<alignment_t &&>));
EXPECT_FALSE((seqan3::detail::writable_pairwise_alignment<alignment_t const &&>));
}

0 comments on commit b64e766

Please sign in to comment.