Skip to content

Commit

Permalink
[API] The alignment configuration for the band changed to seqan3::ali…
Browse files Browse the repository at this point in the history
…gn_cfg::band_fixed_size

* Rename the existing band to align_cfg::band_fixed_size
* Introducing strong types for setting lower and upper diagonal
* Direct access of the members via the config.
* Adjust the tutorial and all snippets
* Adjust the API documentation
* Remove all references to the old static_band mechanism
* Fix all dependent classes and tests
  • Loading branch information
rrahn committed Jun 11, 2020
1 parent f33e648 commit 1192bca
Show file tree
Hide file tree
Showing 26 changed files with 260 additions and 140 deletions.
4 changes: 2 additions & 2 deletions doc/tutorial/pairwise_alignment/configurations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
//! [include_result]

//! [include_band]
#include <seqan3/alignment/band/static_band.hpp>
#include <seqan3/alignment/configuration/align_config_band.hpp>
//! [include_band]

Expand Down Expand Up @@ -92,7 +91,8 @@ auto cfg = seqan3::align_cfg::result{seqan3::with_score};
//! [band]

// Configure a banded alignment.
auto cfg = seqan3::align_cfg::band{seqan3::static_band{seqan3::lower_bound{-4}, seqan3::upper_bound{4}}};
auto cfg = seqan3::align_cfg::band_fixed_size{seqan3::align_cfg::lower_diagonal{-4},
seqan3::align_cfg::upper_diagonal{4}};
//! [band]
(void) cfg;
}
Expand Down
6 changes: 3 additions & 3 deletions doc/tutorial/pairwise_alignment/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,14 +267,14 @@ In many situations it is not necessary to compute the entire alignment matrix bu
positive impacts on the performance. To limit the computation space the alignment matrix can be bounded by a band.
Thus, only the alignment is computed that fits in this band. Note that this must not be the optimal alignment but in
many cases we can give a rough bound on how similar the sequences will be and therefor use the banded alignment.
To do so, you can use a seqan3::static_band. It will be initialised with a seqan3::lower_bound and a
seqan3::upper_bound. To configure the banded alignment you need to use the seqan3::align_cfg::band configuration.
To do so, you can configure the alignment using the seqan3::align_cfg::band_fixed_size option. This configuration
element will be initialised with a seqan3::align_cfg::lower_diagonal and seqan3::align_cfg::upper_diagonal.

\snippet doc/tutorial/pairwise_alignment/configurations.cpp include_band
\snippet doc/tutorial/pairwise_alignment/configurations.cpp band

\assignment{Assignment 5}
Use the example from assignment 4 and compute it in a band with lower bound set to `-3` and upper bound set to `8`.
Use the example from assignment 4 and compute it in a band with lower diagonal set to `-3` and upper diagonal set to `8`.
How does the result change?

\endassignment
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include <utility>

#include <seqan3/alignment/band/static_band.hpp>
#include <seqan3/alignment/pairwise/align_pairwise.hpp>
#include <seqan3/alignment/scoring/nucleotide_scoring_scheme.hpp>
#include <seqan3/alphabet/nucleotide/dna4.hpp>
Expand All @@ -20,7 +19,8 @@ int main()
seqan3::align_cfg::gap{seqan3::gap_scheme{seqan3::gap_score{-4}}} |
seqan3::align_cfg::aligned_ends{seqan3::free_ends_all} |
seqan3::align_cfg::result{seqan3::with_alignment} |
seqan3::align_cfg::band{seqan3::static_band{seqan3::lower_bound{-3}, seqan3::upper_bound{8}}};
seqan3::align_cfg::band_fixed_size{seqan3::align_cfg::lower_diagonal{-3},
seqan3::align_cfg::upper_diagonal{8}};

for (auto const & res : seqan3::align_pairwise(std::tie(seq1, seq2), config))
{
Expand Down
14 changes: 7 additions & 7 deletions include/seqan3/alignment/all.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
* | **Config** | **0** | **1** | **2** | **3** | **4** | **5** | **6** | **7** | **8** | **9** |
* | --------------------------------------------------------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
* | \ref seqan3::align_cfg::aligned_ends "0: Aligned ends" | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
* | \ref seqan3::align_cfg::band "1: Band" | | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
* | \ref seqan3::align_cfg::band_fixed_size "1: Band" | | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
* | \ref seqan3::align_cfg::gap "2: Gap scheme" | | | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
* | \ref seqan3::global_alignment "3: Global alignment" | | | | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ |
* | \ref seqan3::local_alignment "4: Local alignment" | | | | | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ |
Expand Down Expand Up @@ -171,12 +171,12 @@
*
* SeqAn offers the computation of banded alignments to reduce the running time of the algorithm. This can be
* helpful if the region in which the optimal alignment exists is known a priori. To specify the banded alignment
* the developer can use the seqan3::align_cfg::band option initialised with a seqan3::static_band.
* The seqan3::static_band is constructed with a lower bound and an upper bound. The upper bound must always be greater
* than or equal to the lower bound. To position the band, imagine a rectangle where the first sequence is written on
* top and the second sequence along the left vertical side. A negative bound implies a start of the band within the
* vertical part while a positive bound implies a start within the top part of this rectangle at the respective
* position.
* the developer can use the seqan3::align_cfg::band_fixed_size option.
* This band configuration is initialised with a seqan3::align_cfg::lower_diagonal and an
* seqan3::align_cfg::upper_diagonal. The upper diagonal must always be greater than or equal to the lower diagonal.
* To choose the correct band parameters, imagine a matrix with the first sequence written on top and the second sequence
* along the left vertical side. A negative value reflects a start of the diagonal within the vertical part while a
* positive value implies a start within the top part of this matrix at the respective position.
*
* ## Global and local alignments
*
Expand Down
109 changes: 81 additions & 28 deletions include/seqan3/alignment/configuration/align_config_band.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,51 +14,104 @@
#pragma once

#include <seqan3/alignment/configuration/detail.hpp>
#include <seqan3/alignment/band/static_band.hpp>
#include <seqan3/alignment/exception.hpp>
#include <seqan3/core/algorithm/pipeable_config_element.hpp>
#include <seqan3/core/detail/empty_type.hpp>
#include <seqan3/core/detail/strong_type.hpp>

namespace seqan3::align_cfg
{

/*!\brief Configuration element for setting the band.
/*!\brief A strong type representing the lower diagonal of the seqan3::align_cfg::band_fixed_size.
* \ingroup alignment_configuration
*/
struct lower_diagonal : public seqan3::detail::strong_type<int32_t, lower_diagonal>
{
//!\brief The type of the strong type base class.
using base_t = seqan3::detail::strong_type<int32_t, lower_diagonal>;
// Import the base class constructors
using base_t::base_t;
};

/*!\brief A strong type representing the upper diagonal of the seqan3::align_cfg::band_fixed_size.
* \ingroup alignment_configuration
*/
struct upper_diagonal : public seqan3::detail::strong_type<int32_t, upper_diagonal>
{
//!\brief The type of the strong type base class.
using base_t = seqan3::detail::strong_type<int32_t, upper_diagonal>;
// Import the base class constructors
using base_t::base_t;
};

/*!\brief Configuration element for setting a fixed size band.
* \ingroup alignment_configuration
*
* \tparam band_t The type of the band.
*
* \details
*
* Configures the banded alignment algorithm. Currently only seqan3::static_band is allowed as argument.
* If no band is configured for the alignment algorithm the full alignment matrix will be computed.
* Before executing the algorithm the band is tested for valid settings, e.g. that the upper bound is not smaller than
* the lower bound, or the band is not shifted out of the alignment matrix. If an invalid setting is detected, a
* seqan3::invalid_alignment_configuration exception will be thrown.
* Configures the banded alignment algorithm. Currently only a fixed size band is allowed.
* The band is given in form of a seqan3::align_cfg::lower_diagonal and a seqan3::align_cfg::upper_diagonal.
* A diagonal represents the cells in the alignment matrix that are not crossed by the alignment either downwards by
* the lower diagonal or rightwards by the upper diagonal. Thus any computed alignment will be inside the area defined
* by the lower and the upper diagonal.
*
* If this configuration is default constructed or not set during the algorithm configuration the full alignment
* matrix will be computed.
*
* During the construction of this configuration element or before the execution of the alignment algorithm the
* band configuration is validated. If the user provided an invalid band, e.g. the upper diagonal is smaller than
* the lower diagonal, the alignment matrix would be ill configured such that the requested alignment method cannot
* be computed (because the global alignment requires the first cell and the last cell of the matrix to be reachable),
* then a seqan3::invalid_alignment_configuration will be thrown.
*
* ### Example
*
* \include test/snippet/alignment/configuration/align_cfg_band_example.cpp
*/
template <typename band_t>
//!\cond
requires std::same_as<band_t, static_band>
//!\endcond
struct band : public pipeable_config_element<band<band_t>, band_t>
class band_fixed_size : public pipeable_config_element<band_fixed_size>
{
private:
//!\brief The base class type.
using base_t = pipeable_config_element<band_fixed_size>;

public:
//!\brief The selected lower diagonal. Defaults to `std::%numeric_limits<int32_t>::%lowest()`.
seqan3::align_cfg::lower_diagonal lower_diagonal{std::numeric_limits<int32_t>::lowest()};
//!\brief The selected upper diagonal. Defaults to `std::%numeric_limits<int32_t>::%max()`.
seqan3::align_cfg::upper_diagonal upper_diagonal{std::numeric_limits<int32_t>::max()};

/*!\name Constructor, destructor and assignment
* \{
*/
constexpr band_fixed_size() = default; //!< Defaulted.
constexpr band_fixed_size(band_fixed_size const &) = default; //!< Defaulted.
constexpr band_fixed_size(band_fixed_size &&) = default; //!< Defaulted.
constexpr band_fixed_size & operator=(band_fixed_size const &) = default; //!< Defaulted.
constexpr band_fixed_size & operator=(band_fixed_size &&) = default; //!< Defaulted.
~band_fixed_size() = default; //!< Defaulted.

/*!\brief Initialises the fixed size band by setting the lower and the upper matrix diagonal.
*
* \param lower_diagonal \copybrief seqan3::align_cfg::band_fixed_size::lower_diagonal
* \param upper_diagonal \copybrief seqan3::align_cfg::band_fixed_size::upper_diagonal
*
* \details
*
* The lower diagonal represents the lower bound of the banded matrix, i.e. the alignment cannot pass below this
* diagonal. Similar, the upper diagonal represents the upper bound of the alignment. During the alignment
* configuration and execution the band parameters will be checked and an exception will be thrown in case of
* an invalid configuration.
*/
constexpr band_fixed_size(seqan3::align_cfg::lower_diagonal const lower_diagonal,
seqan3::align_cfg::upper_diagonal const upper_diagonal) :
lower_diagonal{std::move(lower_diagonal)},
upper_diagonal{std::move(upper_diagonal)}
{}
//!\}

//!\privatesection
//!\brief Internal id to check for consistent configuration settings.
static constexpr detail::align_config_id id{detail::align_config_id::band};
};

/*!\name Type deduction guides
* \brief Deduces the template parameter from the argument.
* \relates seqan3::align_cfg::band
* \{
*/
/*!
* \brief Deduces the underlying band type.
* \tparam band_t The underlying type of the band.
*/
template <typename band_t>
band(band_t) -> band<band_t>;
//!\}

} // namespace seqan3::detail
} // namespace seqan3::align_cfg
2 changes: 1 addition & 1 deletion include/seqan3/alignment/configuration/detail.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ enum struct align_config_id : uint8_t
//!\brief ID for the \ref seqan3::align_cfg::alignment_result_capture "alignment_result_capture" option.
alignment_result_capture,
aligned_ends, //!< ID for the \ref seqan3::align_cfg::aligned_ends "aligned_ends" option.
band, //!< ID for the \ref seqan3::align_cfg::band "band" option.
band, //!< ID for the \ref seqan3::align_cfg::band_fixed_size "band" option.
debug, //!< ID for the \ref seqan3::align_cfg::debug "debug" option.
gap, //!< ID for the \ref seqan3::align_cfg::gap "gap" option.
global, //!< ID for the \ref seqan3::global_alignment "global alignment" option.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include <vector>

#include <seqan3/alignment/aligned_sequence/aligned_sequence_concept.hpp>
#include <seqan3/alignment/band/static_band.hpp>
#include <seqan3/alignment/matrix/detail/matrix_coordinate.hpp>
#include <seqan3/alignment/matrix/trace_directions.hpp>
#include <seqan3/alphabet/gap/gapped.hpp>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

#pragma once

#include <seqan3/alignment/band/static_band.hpp>
#include <seqan3/alignment/configuration/align_config_band.hpp>
#include <seqan3/alignment/matrix/detail/alignment_matrix_column_major_range_base.hpp>
#include <seqan3/alignment/matrix/detail/alignment_score_matrix_one_column_base.hpp>
#include <seqan3/alignment/matrix/detail/alignment_score_matrix_proxy.hpp>
Expand Down Expand Up @@ -99,7 +99,7 @@ class alignment_score_matrix_one_column_banded :
*
* \param[in] first The first range.
* \param[in] second The second range.
* \param[in] band The seqan3::static_band in which to calculate the alignment.
* \param[in] band The seqan3::align_cfg::band_fixed_size in which to calculate the alignment.
* \param[in] initial_value The value to initialise the matrix with. Default initialised if not specified.
*
* \details
Expand All @@ -111,14 +111,14 @@ class alignment_score_matrix_one_column_banded :
std::ranges::forward_range second_sequence_t>
constexpr alignment_score_matrix_one_column_banded(first_sequence_t && first,
second_sequence_t && second,
static_band const & band,
align_cfg::band_fixed_size const & band,
score_t const initial_value = score_t{})
{
matrix_base_t::num_cols = static_cast<size_type>(std::ranges::distance(first) + 1);
matrix_base_t::num_rows = static_cast<size_type>(std::ranges::distance(second) + 1);

band_col_index = std::min<int32_t>(std::max<int32_t>(band.upper_bound, 0), matrix_base_t::num_cols - 1);
band_row_index = std::min<int32_t>(std::abs(std::min<int32_t>(band.lower_bound, 0)),
band_col_index = std::min<int32_t>(std::max<int32_t>(band.upper_diagonal.get(), 0), matrix_base_t::num_cols - 1);
band_row_index = std::min<int32_t>(std::abs(std::min<int32_t>(band.lower_diagonal.get(), 0)),
matrix_base_t::num_rows - 1);

band_size = band_col_index + band_row_index + 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

#pragma once

#include <seqan3/alignment/band/static_band.hpp>
#include <seqan3/alignment/configuration/align_config_band.hpp>
#include <seqan3/alignment/matrix/detail/alignment_matrix_column_major_range_base.hpp>
#include <seqan3/alignment/matrix/detail/alignment_trace_matrix_base.hpp>
#include <seqan3/alignment/matrix/detail/alignment_trace_matrix_proxy.hpp>
Expand Down Expand Up @@ -115,7 +115,7 @@ class alignment_trace_matrix_full_banded :
*
* \param[in] first The first range.
* \param[in] second The second range.
* \param[in] band The seqan3::static_band in which to calculate the alignment.
* \param[in] band The seqan3::align_cfg::band_fixed_size in which to calculate the alignment.
* \param[in] initial_value The value to initialise the matrix with. Default initialised if not specified.
*
* \details
Expand All @@ -127,14 +127,16 @@ class alignment_trace_matrix_full_banded :
template <std::ranges::forward_range first_sequence_t, std::ranges::forward_range second_sequence_t>
constexpr alignment_trace_matrix_full_banded(first_sequence_t && first,
second_sequence_t && second,
static_band const & band,
align_cfg::band_fixed_size const & band,
[[maybe_unused]] trace_t const initial_value = trace_t{})
{
matrix_base_t::num_cols = static_cast<size_type>(std::ranges::distance(first) + 1);
matrix_base_t::num_rows = static_cast<size_type>(std::ranges::distance(second) + 1);

band_col_index = std::min<int32_t>(std::max<int32_t>(band.upper_bound, 0), matrix_base_t::num_cols - 1);
band_row_index = std::min<int32_t>(std::abs(std::min<int32_t>(band.lower_bound, 0)), matrix_base_t::num_rows - 1);
band_col_index = std::min<int32_t>(std::max<int32_t>(band.upper_diagonal.get(), 0),
matrix_base_t::num_cols - 1);
band_row_index = std::min<int32_t>(std::abs(std::min<int32_t>(band.lower_diagonal.get(), 0)),
matrix_base_t::num_rows - 1);
band_size = band_col_index + band_row_index + 1;

// Reserve one more cell to deal with last cell in the banded column which needs only the diagonal and up cell.
Expand Down
17 changes: 9 additions & 8 deletions include/seqan3/alignment/pairwise/alignment_algorithm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,9 @@ class alignment_algorithm :

if constexpr (traits_t::is_banded)
{
using seqan3::get;
// Get the band and check if band configuration is valid.
auto const & band = seqan3::get<align_cfg::band>(*cfg_ptr).value;
auto const & band = get<align_cfg::band_fixed_size>(*cfg_ptr);
check_valid_band_parameter(sequence1, sequence2, band);
auto && [subsequence1, subsequence2] = this->slice_sequences(sequence1, sequence2, band);
// It would be great to use this interface here instead
Expand Down Expand Up @@ -325,27 +326,27 @@ class alignment_algorithm :
template <typename sequence1_t, typename sequence2_t>
constexpr void check_valid_band_parameter(sequence1_t && sequence1,
sequence2_t && sequence2,
static_band const & band)
align_cfg::band_fixed_size const & band)
{
static_assert(config_t::template exists<align_cfg::band>(),
static_assert(config_t::template exists<align_cfg::band_fixed_size>(),
"The band configuration is required for the banded alignment algorithm.");

using diff_type = std::iter_difference_t<std::ranges::iterator_t<sequence1_t>>;
static_assert(std::is_signed_v<diff_type>, "Only signed types can be used to test the band parameters.");

if (static_cast<diff_type>(band.lower_bound) > std::ranges::distance(sequence1))
if (static_cast<diff_type>(band.lower_diagonal.get()) > std::ranges::distance(sequence1))
{
throw invalid_alignment_configuration
{
"Invalid band error: The lower bound excludes the whole alignment matrix."
"Invalid band error: The lower diagonal excludes the whole alignment matrix."
};
}

if (static_cast<diff_type>(band.upper_bound) < -std::ranges::distance(sequence2))
if (static_cast<diff_type>(band.upper_diagonal.get()) < -std::ranges::distance(sequence2))
{
throw invalid_alignment_configuration
{
"Invalid band error: The upper bound excludes the whole alignment matrix."
"Invalid band error: The upper diagonal excludes the whole alignment matrix."
};
}
}
Expand Down Expand Up @@ -411,7 +412,7 @@ class alignment_algorithm :

//!\overload
template <typename sequence1_t, typename sequence2_t>
void compute_matrix(sequence1_t & sequence1, sequence2_t & sequence2, static_band const & band)
void compute_matrix(sequence1_t & sequence1, sequence2_t & sequence2, align_cfg::band_fixed_size const & band)
//!\cond
requires traits_t::is_banded
//!\endcond
Expand Down

0 comments on commit 1192bca

Please sign in to comment.