SeqAn3 3.4.0-rc.1
The Modern C++ library for sequence analysis.
Loading...
Searching...
No Matches
edit_distance_trace_matrix_full.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2006-2024 Knut Reinert & Freie Universität Berlin
2// SPDX-FileCopyrightText: 2016-2024 Knut Reinert & MPI für molekulare Genetik
3// SPDX-License-Identifier: BSD-3-Clause
4
10#pragma once
11
12#include <bitset>
13
17
18namespace seqan3::detail
19{
20
28template <typename word_t, bool is_semi_global, bool use_max_errors>
29class edit_distance_trace_matrix_full
30{
31public:
33 template <std::ranges::viewable_range database_t,
34 std::ranges::viewable_range query_t,
35 typename align_config_t,
36 typename edit_traits>
37 friend class edit_distance_unbanded;
38
42 edit_distance_trace_matrix_full() = default;
43 edit_distance_trace_matrix_full(edit_distance_trace_matrix_full const &) = default;
44 edit_distance_trace_matrix_full(edit_distance_trace_matrix_full &&) = default;
45 edit_distance_trace_matrix_full & operator=(edit_distance_trace_matrix_full const &) = default;
46 edit_distance_trace_matrix_full & operator=(edit_distance_trace_matrix_full &&) = default;
47 ~edit_distance_trace_matrix_full() = default;
48
49protected:
51 template <typename derived_t, typename edit_traits>
52 friend class edit_distance_unbanded_trace_matrix_policy;
53
57 edit_distance_trace_matrix_full(size_t const rows_size) : rows_size{rows_size}, columns{}
58 {}
60
61private:
62 struct trace_path_iterator;
63
64public:
66 using word_type = word_t;
67
69 static constexpr auto word_size = bits_of<word_type>;
70
72 using value_type = detail::trace_directions;
73
75 using reference = value_type;
76
78 using size_type = size_t;
79
88 void reserve(size_t const new_capacity)
89 {
90 columns.reserve(new_capacity);
91 }
92
93public:
95 reference at(matrix_coordinate const & coordinate) const noexcept
96 {
97 size_t row = coordinate.row;
98 size_t col = coordinate.col;
99
100 assert(row < rows());
101 assert(col < cols());
102
103 column_type const & column = columns[col];
104
105 if constexpr (use_max_errors)
106 if (!(row < column.max_rows))
107 return detail::trace_directions::none;
108
109 if (row == 0u)
110 {
111 if constexpr (is_semi_global)
112 return detail::trace_directions::none;
113
114 if (col == 0u)
115 return detail::trace_directions::none;
116
117 return detail::trace_directions::left;
118 }
119
120 size_t const idx = (row - 1u) / word_size;
121 size_t const offset = (row - 1u) % word_size;
122
123 bool const left = std::bitset<word_size>(column.left[idx])[offset];
124 bool const diagonal = std::bitset<word_size>(column.diagonal[idx])[offset];
125 bool const up = std::bitset<word_size>(column.up[idx])[offset];
126
127 auto const dir = (left ? detail::trace_directions::left : detail::trace_directions::none)
128 | (diagonal ? detail::trace_directions::diagonal : detail::trace_directions::none)
129 | (up ? detail::trace_directions::up : detail::trace_directions::none);
130
131 return dir;
132 }
133
135 size_t rows() const noexcept
136 {
137 return rows_size;
138 }
139
141 size_t cols() const noexcept
142 {
143 return columns.size();
144 }
145
152 auto trace_path(matrix_coordinate const & trace_begin) const
153 {
154 if (trace_begin.row >= rows() || trace_begin.col >= cols())
155 throw std::invalid_argument{"The given coordinate exceeds the matrix in vertical or horizontal direction."};
156
157 using path_t = std::ranges::subrange<trace_path_iterator, std::default_sentinel_t>;
158 return path_t{trace_path_iterator{this, trace_begin}, std::default_sentinel};
159 }
160
161protected:
163 struct max_errors_state
164 {
167 size_t max_rows{};
168 };
169
171 struct trace_matrix_state
172 {
176 std::vector<word_type> diagonal{};
179 };
180
182 struct column_type : enable_state_t<true, trace_matrix_state>, enable_state_t<use_max_errors, max_errors_state>
183 {};
184
191 requires (!use_max_errors)
192 {
193 column_type column{};
194 column.left = std::move(left);
195 column.diagonal = std::move(diagonal);
196 column.up = std::move(up);
197
198 columns.push_back(std::move(column));
199 }
200
207 void add_column(std::vector<word_type> left,
208 std::vector<word_type> diagonal,
210 size_t const max_rows)
211 requires use_max_errors
212 {
213 column_type column{};
214 column.left = std::move(left);
215 column.diagonal = std::move(diagonal);
216 column.up = std::move(up);
217 column.max_rows = max_rows;
218
219 columns.push_back(std::move(column));
220 }
221
222private:
224 size_t rows_size{};
226 std::vector<column_type> columns{};
227};
228
243template <typename word_t, bool is_semi_global, bool use_max_errors>
244struct edit_distance_trace_matrix_full<word_t, is_semi_global, use_max_errors>::trace_path_iterator
245{
250 using iterator_category = std::input_iterator_tag;
252 using value_type = detail::trace_directions;
254 using difference_type = std::ptrdiff_t;
256
258 static constexpr value_type D = value_type::diagonal;
260 static constexpr value_type L = value_type::left;
262 static constexpr value_type U = value_type::up;
264 static constexpr value_type N = value_type::none;
265
270 constexpr value_type operator*() const
271 {
272 value_type dir = parent->at(coordinate());
273
274 if (dir == N)
275 return N;
276
277 if ((dir & L) == L)
278 return L;
279 else if ((dir & U) == U)
280 return U;
281 else
282 return D;
283 }
284
286 [[nodiscard]] constexpr matrix_coordinate const & coordinate() const
287 {
288 return coordinate_;
289 }
291
296 constexpr trace_path_iterator & operator++()
297 {
298 value_type dir = *(*this);
299
300 if ((dir & L) == L)
301 {
302 coordinate_.col = std::max<size_t>(coordinate_.col, 1) - 1;
303 }
304 else if ((dir & U) == U)
305 {
306 coordinate_.row = std::max<size_t>(coordinate_.row, 1) - 1;
307 }
308 else if ((dir & D) == D)
309 {
310 coordinate_.row = std::max<size_t>(coordinate_.row, 1) - 1;
311 coordinate_.col = std::max<size_t>(coordinate_.col, 1) - 1;
312 }
313
314 // seqan3::trace_direction::none in an inner cell of the trace matrix is not possible in
315 // non-local alignments, e.g. global, semi-global, max-error, banded. On the other hand,
316 // this can happen in a cell of the first row or first colomn.
317 assert(dir != N || coordinate_.row == 0 || coordinate_.col == 0);
318
319 return *this;
320 }
321
323 constexpr void operator++(int)
324 {
325 ++(*this);
326 }
328
333 friend bool operator==(trace_path_iterator const & it, std::default_sentinel_t)
334 {
335 return *it == value_type::none;
336 }
337
339 friend bool operator==(std::default_sentinel_t, trace_path_iterator const & it)
340 {
341 return it == std::default_sentinel;
342 }
343
345 friend bool operator!=(trace_path_iterator const & it, std::default_sentinel_t)
346 {
347 return !(it == std::default_sentinel);
348 }
349
351 friend bool operator!=(std::default_sentinel_t, trace_path_iterator const & it)
352 {
353 return it != std::default_sentinel;
354 }
356
358 edit_distance_trace_matrix_full const * parent{nullptr};
360 matrix_coordinate coordinate_{};
361};
362
363} // 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:29
@ 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 type_list/traits.hpp:276
T left(T... args)
T operator!=(T... args)
T size(T... args)
Provides the declaration of seqan3::detail::trace_directions.
Hide me