Skip to content

Commit

Permalink
Merge pull request #1873 from rrahn/alignment/banded_implementation_c…
Browse files Browse the repository at this point in the history
…onfig

 [API] The alignment configuration for the band changed to seqan3::align_cfg::band_fixed_size
  • Loading branch information
rrahn committed Jun 11, 2020
2 parents bcceaac + f63e2b9 commit ba70f70
Show file tree
Hide file tree
Showing 32 changed files with 410 additions and 145 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ Note that 3.1.0 will be the first API stable release and interfaces in this rele

## API changes

### Alignment

* The alignment configuration elements were refactored:
* The option `seqan3::align_cfg::band` is now renamed to `seqan3::align_cfg::band_fixed_size` and directly initialised
with a `seqan3::align_cfg::lower_diagonal` and `seqan3::align_cfg::upper_diagonal` instead of `seqan3::static_band`.
It also directly exposes the lower_diagonal and upper_diagonal as public members
([\#1873](https://github.com/seqan/seqan3/pull/1873)).

### Core

* In accordance with the standard, the following concepts are renamed:
* `default_constructible` to `default_initializable`
* `readable` to `indirectly_readable`
Expand Down
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
Loading

0 comments on commit ba70f70

Please sign in to comment.