SeqAn3 3.4.0-rc.1
The Modern C++ library for sequence analysis.
Loading...
Searching...
No Matches
debug_matrix.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 <iomanip>
13
22
23namespace seqan3::detail
24{
25
57template <matrix matrix_t, typename first_sequence_t = std::nullopt_t, typename second_sequence_t = std::nullopt_t>
58class debug_matrix
59{
60protected:
62 static constexpr bool has_first_sequence = !std::is_same_v<std::decay_t<first_sequence_t>, std::nullopt_t>;
64 static constexpr bool has_second_sequence = !std::is_same_v<std::decay_t<second_sequence_t>, std::nullopt_t>;
66 using entry_t = typename std::remove_reference_t<matrix_t>::value_type;
68 static constexpr bool is_traceback_matrix = std::is_same_v<std::decay_t<entry_t>, trace_directions>;
71 static constexpr bool is_optional_score = is_type_specialisation_of_v<entry_t, std::optional>;
72
73public:
80 using reference = value_type;
82 using const_reference = reference;
84 using size_type = typename std::remove_reference_t<matrix_t>::size_type;
86
90 debug_matrix() = default;
91 debug_matrix(debug_matrix const &) = default;
92 debug_matrix(debug_matrix &&) = default;
93 debug_matrix & operator=(debug_matrix const &) = default;
94 debug_matrix & operator=(debug_matrix &&) = default;
95 ~debug_matrix() = default;
96
100 debug_matrix(matrix_t matrix) : debug_matrix(std::forward<matrix_t>(matrix), std::nullopt, std::nullopt)
101 {}
102
108 debug_matrix(matrix_t matrix, first_sequence_t first_sequence, second_sequence_t second_sequence) :
109 _matrix{std::forward<matrix_t>(matrix)},
110 _first_sequence{std::forward<first_sequence_t>(first_sequence)},
111 _second_sequence{std::forward<second_sequence_t>(second_sequence)}
112 {
113 if constexpr (has_first_sequence)
114 {
115 assert(_matrix.cols() <= _first_sequence.size() + 1u);
116 }
117
118 if constexpr (has_second_sequence)
119 {
120 assert(_matrix.rows() <= _second_sequence.size() + 1u);
121 }
122 }
124
126 size_t rows() const noexcept
127 {
128 if (!_transpose)
129 return _rows.value_or(_matrix.rows());
130 else
131 return _cols.value_or(_matrix.cols());
132 }
133
135 size_t cols() const noexcept
136 {
137 if (!_transpose)
138 return _cols.value_or(_matrix.cols());
139 else
140 return _rows.value_or(_matrix.rows());
141 }
142
144 first_sequence_t const & first_sequence() const noexcept
145 {
146 if (!_transpose)
147 return _first_sequence;
148 else
149 return _second_sequence;
150 }
151
153 second_sequence_t const & second_sequence() const noexcept
154 {
155 if (!_transpose)
156 return _second_sequence;
157 else
158 return _first_sequence;
159 }
160
162 const_reference at(matrix_coordinate const & coordinate) const noexcept
163 {
164 size_t row = coordinate.row;
165 size_t col = coordinate.col;
166
167 assert(row < rows() && col < cols());
168
169 row_index_type const _row{!_transpose ? row : col};
170 column_index_type const _col{!_transpose ? col : row};
171 row_index_type const _mask_row{_transpose == _transpose_mask ? row : col};
172 column_index_type const _mask_col{_transpose == _transpose_mask ? col : row};
173
174 if (!_masking_matrix.has_value() || _masking_matrix.value().at({_mask_row, _mask_col}))
175 {
176 entry_t const & entry = _matrix.at({_row, _col});
177
178 if (!is_traceback_matrix || !_transpose)
179 return entry;
180
181 if constexpr (is_traceback_matrix)
182 {
183 trace_directions reverse{};
184 if ((entry & trace_directions::left) == trace_directions::left)
185 reverse |= trace_directions::up;
186 if ((entry & trace_directions::up) == trace_directions::up)
187 reverse |= trace_directions::left;
188 if ((entry & trace_directions::diagonal) == trace_directions::diagonal)
189 reverse |= trace_directions::diagonal;
190 return reverse;
191 }
192 }
193
194 if constexpr (is_traceback_matrix)
195 return trace_directions::none;
196 else
197 return std::nullopt;
198 }
199
206 debug_matrix & mask_matrix(row_wise_matrix<bool> masking_matrix) noexcept
207 {
208 assert(masking_matrix.rows() == rows());
209 assert(masking_matrix.cols() == cols());
210 _transpose_mask = _transpose;
211 _masking_matrix = std::move(masking_matrix);
212 return *this;
213 }
214
219 debug_matrix & mask_matrix(std::vector<bool> masking_vector) noexcept
220 {
221 return mask_matrix(row_wise_matrix<bool>{number_rows{rows()}, number_cols{cols()}, std::move(masking_vector)});
222 }
223
229 debug_matrix & sub_matrix(size_t const new_rows, size_t const new_cols) noexcept
230 {
231 assert(new_rows <= rows());
232 assert(new_cols <= cols());
233 if (!_transpose)
234 {
235 _rows = new_rows;
236 _cols = new_cols;
237 }
238 else
239 {
240 _rows = new_cols;
241 _cols = new_rows;
242 }
243 return *this;
244 }
245
249 debug_matrix & transpose_matrix() noexcept
250 {
251 _transpose = !_transpose;
252 return *this;
253 }
254
255protected:
257 struct format_type; // forward declaration
259
260public:
270 template <typename ostream_t>
271 void stream_matrix(ostream_t & cout, fmtflags2 const flags) const noexcept
272 {
273 format_type const & symbols = (flags & fmtflags2::utf8) == fmtflags2::utf8 ? unicode : csv;
274 size_t const column_width =
275 this->column_width.has_value() ? this->column_width.value() : auto_column_width(flags);
276
277 auto char_first_sequence = [&]([[maybe_unused]] size_t const i) -> std::string
278 {
279 if constexpr (!has_first_sequence)
280 return " ";
281 else
282 return as_string(first_sequence()[i], flags);
283 };
284
285 auto char_second_sequence = [&]([[maybe_unused]] size_t const i) -> std::string
286 {
287 if constexpr (!has_second_sequence)
288 return " ";
289 else
290 return as_string(second_sequence()[i], flags);
291 };
292
293 auto print_cell = [&](std::string const & symbol)
294 {
295 // deal with unicode chars that mess up std::setw
296 size_t const length_bytes = symbol.size();
297 size_t const length = unicode_str_length(symbol);
298 size_t const offset = length_bytes - length;
299
300 cout << std::left << std::setw(column_width + offset) << symbol << symbols.col_sep;
301 };
302
303 auto print_first_cell = [&](std::string const & symbol)
304 {
305 cout << symbol << symbols.col_sep;
306 };
307
308 // |_|d|a|t|a|b|a|s|e|
309 auto print_first_row = [&]
310 {
311 print_first_cell(" ");
312 print_cell(symbols.epsilon);
313
314 for (size_t col = 0; col < cols() - 1; ++col)
315 print_cell(char_first_sequence(col));
316
317 cout << "\n";
318 };
319
320 // |-|-|-|-|-|-|-|-|-|
321 auto print_divider = [&]
322 {
323 cout << " " << symbols.row_col_sep;
324 for (size_t col = 0; col < cols(); ++col)
325 {
326 for (size_t i = 0; i < column_width; ++i)
327 cout << symbols.row_sep;
328
329 cout << symbols.row_col_sep;
330 }
331 cout << "\n";
332 };
333
334 print_first_row();
335 for (size_t row = 0; row < rows(); ++row)
336 {
337 if (symbols.row_sep[0] != '\0')
338 print_divider();
339
340 // one query letter + one row of scores / traces
341 if (row == 0)
342 print_first_cell(symbols.epsilon);
343 else
344 print_first_cell(char_second_sequence(row - 1));
345
346 for (size_t col = 0; col < cols(); ++col)
347 print_cell(entry_at({row_index_type{row}, column_index_type{col}}, flags));
348
349 cout << "\n";
350 }
351 }
352
354 size_t auto_column_width(fmtflags2 const flags) const noexcept
355 {
356 size_t col_width = 1;
357 for (size_t row = 0; row < rows(); ++row)
358 for (size_t col = 0; col < cols(); ++col)
359 col_width =
360 std::max(col_width,
361 unicode_str_length(entry_at({row_index_type{row}, column_index_type{col}}, flags)));
362
363 return col_width;
364 }
365
366protected:
368 std::string entry_at(matrix_coordinate const coordinate, fmtflags2 flags) const noexcept
369 {
370 format_type const & symbols = (flags & fmtflags2::utf8) == fmtflags2::utf8 ? unicode : csv;
371
372 value_type const & entry = at(coordinate);
373 if (!is_traceback_matrix && entry == matrix_inf<value_type>)
374 return symbols.inf;
375
376 return as_string(entry, flags);
377 }
378
380 template <typename value_type>
381 static std::string as_string(value_type && entry, fmtflags2 const flags) noexcept
382 {
383 std::stringstream strstream;
384 debug_stream_type stream{strstream};
385 stream << flags << entry;
386 return strstream.str();
387 }
388
391 static size_t unicode_str_length(std::string const & str) noexcept
392 {
393 size_t length = 0u;
394 for (auto it = str.cbegin(); it < str.cend(); ++it, ++length)
395 {
396 uint8_t v = *it;
397 if ((v & 0b1110'0000) == 0b1100'0000)
398 ++it;
399 else if ((v & 0b1111'0000) == 0b1110'0000)
400 it += 2;
401 else if ((v & 0b1111'1000) == 0b1111'0000)
402 it += 3;
403 }
404 return length;
405 }
406
408 struct format_type
409 {
411 char const * epsilon{};
413 char const * col_sep{};
415 char const * row_sep{};
417 char const * row_col_sep{};
419 char const * inf{};
420 };
421
423 static constexpr format_type csv{" ", ";", "", "", ""};
425 static constexpr format_type unicode{"ε", "║", "═", "╬", "∞"};
426
427public:
429 std::optional<size_t> column_width{std::nullopt};
430
431protected:
433 matrix_t _matrix;
435 first_sequence_t _first_sequence;
437 second_sequence_t _second_sequence;
439 std::optional<size_t> _rows{};
441 std::optional<size_t> _cols{};
443 std::optional<row_wise_matrix<bool>> _masking_matrix{};
445 bool _transpose{};
447 bool _transpose_mask{};
448};
449
455template <matrix matrix_t>
456debug_matrix(matrix_t &&) -> debug_matrix<matrix_t>;
457
460template <matrix matrix_t, typename first_sequence_t, typename second_sequence_t>
461debug_matrix(matrix_t &&,
462 first_sequence_t &&,
463 second_sequence_t &&) -> debug_matrix<matrix_t, first_sequence_t, second_sequence_t>;
465
466} // namespace seqan3::detail
467
468namespace seqan3
469{
470
478template <detail::matrix alignment_matrix_t>
479struct alignment_matrix_printer<alignment_matrix_t>
480{
493 template <typename stream_t, typename arg_t>
494 requires detail::is_type_specialisation_of_v<stream_t, debug_stream_type>
495 constexpr void operator()(stream_t & stream, arg_t && arg) const
496 {
497 print_impl(stream.get_underlying_stream(), stream.flags2(), std::forward<arg_t>(arg));
498 }
499
510 template <typename stream_t, typename arg_t>
511 constexpr void operator()(stream_t & stream, arg_t && arg) const
512 {
513 print_impl(stream, fmtflags2::none, std::forward<arg_t>(arg));
514 }
515
516private:
524 template <typename stream_t, typename arg_t>
525 void print_impl(stream_t & stream, fmtflags2 const flags, arg_t && arg) const
526 {
527 detail::debug_matrix debug{std::forward<arg_t>(arg)};
528
529 debug.stream_matrix(stream, flags);
530 }
531};
532
533} // namespace seqan3
Provides seqan3::debug_stream and related types.
Provides seqan3::debug_stream and related types.
T forward(T... args)
fmtflags2
Flags that change the behaviour of the seqan3::debug_stream.
Definition debug_stream_type.hpp:32
@ utf8
Enables use of non-ASCII UTF8 characters in formatted output.
Definition debug_stream_type.hpp:34
@ none
No flag is set.
Definition debug_stream_type.hpp:33
@ 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)
Provides seqan3::detail::matrix.
T max(T... args)
The main SeqAn3 namespace.
Definition aligned_sequence_concept.hpp:26
SeqAn specific customisations in the standard namespace.
Provides seqan3::debug_stream and related types.
Provides seqan3::debug_stream and related types.
T reverse(T... args)
Provides seqan3::detail::row_wise_matrix.
T setw(T... args)
T str(T... args)
constexpr void operator()(stream_t &stream, arg_t &&arg) const
Prints the alignment matrix into the given stream using ascii formatting.
Definition debug_matrix.hpp:511
constexpr void operator()(stream_t &stream, arg_t &&arg) const
Prints the alignment matrix into the given stream using formatting specified by seqan3::fmtflags2.
Definition debug_matrix.hpp:495
Definition default_printer.hpp:28
Provides type traits for working with templates.
Provides the declaration of seqan3::detail::trace_directions.
Hide me