SeqAn3 3.1.0
The Modern C++ library for sequence analysis.
edit_distance_trace_matrix_full.hpp
Go to the documentation of this file.
1// -----------------------------------------------------------------------------------------------------
2// Copyright (c) 2006-2021, Knut Reinert & Freie Universität Berlin
3// Copyright (c) 2016-2021, 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
13#pragma once
14
15#include <bitset>
16
20
21namespace seqan3::detail
22{
23
31template <typename word_t, bool is_semi_global, bool use_max_errors>
32class edit_distance_trace_matrix_full
33{
34public:
36 template <std::ranges::viewable_range database_t,
37 std::ranges::viewable_range query_t,
38 typename align_config_t,
39 typename edit_traits>
40 friend class edit_distance_unbanded;
41
45 edit_distance_trace_matrix_full() = default;
46 edit_distance_trace_matrix_full(edit_distance_trace_matrix_full const &) = default;
47 edit_distance_trace_matrix_full(edit_distance_trace_matrix_full &&) = default;
48 edit_distance_trace_matrix_full & operator=(edit_distance_trace_matrix_full const &) = default;
49 edit_distance_trace_matrix_full & operator=(edit_distance_trace_matrix_full &&) = default;
50 ~edit_distance_trace_matrix_full() = default;
51
52 protected:
54 template <typename derived_t, typename edit_traits>
55 friend class edit_distance_unbanded_trace_matrix_policy;
56
60 edit_distance_trace_matrix_full(size_t const rows_size)
61 : rows_size{rows_size}, columns{}
62 {}
64
65private:
66 struct trace_path_iterator;
67
68public:
70 using word_type = word_t;
71
73 static constexpr auto word_size = bits_of<word_type>;
74
76 using value_type = detail::trace_directions;
77
79 using reference = value_type;
80
82 using size_type = size_t;
83
92 void reserve(size_t const new_capacity)
93 {
94 columns.reserve(new_capacity);
95 }
96
97public:
99 reference at(matrix_coordinate const & coordinate) const noexcept
100 {
101 size_t row = coordinate.row;
102 size_t col = coordinate.col;
103
104 assert(row < rows());
105 assert(col < cols());
106
107 column_type const & column = columns[col];
108
109 if constexpr(use_max_errors)
110 if (!(row < column.max_rows))
112
113 if (row == 0u)
114 {
115 if constexpr(is_semi_global)
117
118 if (col == 0u)
120
121 return detail::trace_directions::left;
122 }
123
124 size_t const idx = (row - 1u) / word_size;
125 size_t const offset = (row - 1u) % word_size;
126
127 bool const left = std::bitset<word_size>(column.left[idx])[offset];
128 bool const diagonal = std::bitset<word_size>(column.diagonal[idx])[offset];
129 bool const up = std::bitset<word_size>(column.up[idx])[offset];
130
131 auto const dir = (left ? detail::trace_directions::left : detail::trace_directions::none) |
132 (diagonal ? detail::trace_directions::diagonal : detail::trace_directions::none) |
133 (up ? detail::trace_directions::up : detail::trace_directions::none);
134
135 return dir;
136 }
137
139 size_t rows() const noexcept
140 {
141 return rows_size;
142 }
143
145 size_t cols() const noexcept
146 {
147 return columns.size();
148 }
149
156 auto trace_path(matrix_coordinate const & trace_begin) const
157 {
158 if (trace_begin.row >= rows() || trace_begin.col >= cols())
159 throw std::invalid_argument{"The given coordinate exceeds the matrix in vertical or horizontal direction."};
160
161 using path_t = std::ranges::subrange<trace_path_iterator, std::default_sentinel_t>;
162 return path_t{trace_path_iterator{this, trace_begin}, std::default_sentinel};
163 }
164
165protected:
167 struct max_errors_state
168 {
171 size_t max_rows{};
172 };
173
175 struct trace_matrix_state
176 {
180 std::vector<word_type> diagonal{};
183 };
184
186 struct column_type :
187 enable_state_t<true, trace_matrix_state>,
188 enable_state_t<use_max_errors, max_errors_state>
189 {};
190
198 requires (!use_max_errors)
200 {
201 column_type column{};
202 column.left = std::move(left);
203 column.diagonal = std::move(diagonal);
204 column.up = std::move(up);
205
206 columns.push_back(std::move(column));
207 }
208
216 size_t const max_rows)
218 requires use_max_errors
220 {
221 column_type column{};
222 column.left = std::move(left);
223 column.diagonal = std::move(diagonal);
224 column.up = std::move(up);
225 column.max_rows = max_rows;
226
227 columns.push_back(std::move(column));
228 }
229
230private:
232 size_t rows_size{};
234 std::vector<column_type> columns{};
235};
236
251template <typename word_t, bool is_semi_global, bool use_max_errors>
252struct edit_distance_trace_matrix_full<word_t, is_semi_global, use_max_errors>::trace_path_iterator
253{
258 using iterator_category = std::input_iterator_tag;
260 using value_type = detail::trace_directions;
262 using difference_type = std::ptrdiff_t;
264
266 constexpr static value_type D = value_type::diagonal;
268 constexpr static value_type L = value_type::left;
270 constexpr static value_type U = value_type::up;
272 constexpr static value_type N = value_type::none;
273
278 constexpr value_type operator*() const
279 {
280 value_type dir = parent->at(coordinate());
281
282 if (dir == N)
283 return N;
284
285 if ((dir & L) == L)
286 return L;
287 else if ((dir & U) == U)
288 return U;
289 else
290 return D;
291 }
292
294 [[nodiscard]] constexpr matrix_coordinate const & coordinate() const
295 {
296 return coordinate_;
297 }
299
304 constexpr trace_path_iterator & operator++()
305 {
306 value_type dir = *(*this);
307
308 if ((dir & L) == L)
309 {
310 coordinate_.col = std::max<size_t>(coordinate_.col, 1) - 1;
311 }
312 else if ((dir & U) == U)
313 {
314 coordinate_.row = std::max<size_t>(coordinate_.row, 1) - 1;
315 }
316 else if ((dir & D) == D)
317 {
318 coordinate_.row = std::max<size_t>(coordinate_.row, 1) - 1;
319 coordinate_.col = std::max<size_t>(coordinate_.col, 1) - 1;
320 }
321
322 // seqan3::trace_direction::none in an inner cell of the trace matrix is not possible in
323 // non-local alignments, e.g. global, semi-global, max-error, banded. On the other hand,
324 // this can happen in a cell of the first row or first colomn.
325 assert(dir != N || coordinate_.row == 0 || coordinate_.col == 0);
326
327 return *this;
328 }
329
331 constexpr void operator++(int)
332 {
333 ++(*this);
334 }
336
341 friend bool operator==(trace_path_iterator const & it, std::default_sentinel_t)
342 {
343 return *it == value_type::none;
344 }
345
347 friend bool operator==(std::default_sentinel_t, trace_path_iterator const & it)
348 {
349 return it == std::default_sentinel;
350 }
351
353 friend bool operator!=(trace_path_iterator const & it, std::default_sentinel_t)
354 {
355 return !(it == std::default_sentinel);
356 }
357
359 friend bool operator!=(std::default_sentinel_t, trace_path_iterator const & it)
360 {
361 return it != std::default_sentinel;
362 }
364
366 edit_distance_trace_matrix_full const * parent{nullptr};
368 matrix_coordinate coordinate_{};
369};
370
371} // namespace seqan3::detail
Provides utility functions for bit twiddling.
Forwards for seqan3::edit_distance_unbanded related types.
@ none
No flag is set.
Definition: debug_stream_type.hpp:32
@ offset
Sequence (seqan3::field::seq) relative start position (0-based), unsigned value.
typename decltype(detail::at< idx >(list_t{}))::type at
Return the type at given index from the type list.
Definition: traits.hpp:260
T left(T... args)
T operator!=(T... args)
T size(T... args)
Provides the declaration of seqan3::detail::trace_directions.