SeqAn3 3.1.0
The Modern C++ library for sequence analysis.
minimiser.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 <seqan3/std/algorithm>
16#include <deque>
17
23
24namespace seqan3::detail
25{
26// ---------------------------------------------------------------------------------------------------------------------
27// minimiser_view class
28// ---------------------------------------------------------------------------------------------------------------------
29
48template <std::ranges::view urng1_t,
49 std::ranges::view urng2_t = std::ranges::empty_view<seqan3::detail::empty_type>>
50class minimiser_view : public std::ranges::view_interface<minimiser_view<urng1_t, urng2_t>>
51{
52private:
53 static_assert(std::ranges::forward_range<urng1_t>, "The minimiser_view only works on forward_ranges.");
54 static_assert(std::ranges::forward_range<urng2_t>, "The minimiser_view only works on forward_ranges.");
55 static_assert(std::totally_ordered<std::ranges::range_reference_t<urng1_t>>,
56 "The reference type of the underlying range must model std::totally_ordered.");
57
59 using default_urng2_t = std::ranges::empty_view<seqan3::detail::empty_type>;
60
62 static constexpr bool second_range_is_given = !std::same_as<urng2_t, default_urng2_t>;
63
64 static_assert(!second_range_is_given || std::totally_ordered_with<std::ranges::range_reference_t<urng1_t>,
65 std::ranges::range_reference_t<urng2_t>>,
66 "The reference types of the underlying ranges must model std::totally_ordered_with.");
67
69 static constexpr bool const_iterable = seqan3::const_iterable_range<urng1_t> &&
71
73 urng1_t urange1{};
75 urng2_t urange2{};
76
78 size_t window_size{};
79
80 template <bool const_range>
81 class basic_iterator;
82
84 using sentinel = std::default_sentinel_t;
85
86public:
90 minimiser_view() = default;
91 minimiser_view(minimiser_view const & rhs) = default;
92 minimiser_view(minimiser_view && rhs) = default;
93 minimiser_view & operator=(minimiser_view const & rhs) = default;
94 minimiser_view & operator=(minimiser_view && rhs) = default;
95 ~minimiser_view() = default;
96
102 minimiser_view(urng1_t urange1, size_t const window_size) :
103 minimiser_view{std::move(urange1), default_urng2_t{}, window_size}
104 {}
105
113 template <typename other_urng1_t>
115 requires (std::ranges::viewable_range<other_urng1_t> &&
116 std::constructible_from<urng1_t, ranges::ref_view<std::remove_reference_t<other_urng1_t>>>)
118 minimiser_view(other_urng1_t && urange1, size_t const window_size) :
119 urange1{std::views::all(std::forward<other_urng1_t>(urange1))},
120 urange2{default_urng2_t{}},
121 window_size{window_size}
122 {}
123
131 minimiser_view(urng1_t urange1, urng2_t urange2, size_t const window_size) :
132 urange1{std::move(urange1)},
133 urange2{std::move(urange2)},
134 window_size{window_size}
135 {
136 if constexpr (second_range_is_given)
137 {
138 if (std::ranges::distance(urange1) != std::ranges::distance(urange2))
139 throw std::invalid_argument{"The two ranges do not have the same size."};
140 }
141 }
142
154 template <typename other_urng1_t, typename other_urng2_t>
156 requires (std::ranges::viewable_range<other_urng1_t> &&
157 std::constructible_from<urng1_t, std::views::all_t<other_urng1_t>> &&
158 std::ranges::viewable_range<other_urng2_t> &&
159 std::constructible_from<urng2_t, std::views::all_t<other_urng2_t>>)
161 minimiser_view(other_urng1_t && urange1, other_urng2_t && urange2, size_t const window_size) :
162 urange1{std::views::all(std::forward<other_urng1_t>(urange1))},
163 urange2{std::views::all(std::forward<other_urng2_t>(urange2))},
164 window_size{window_size}
165 {
166 if constexpr (second_range_is_given)
167 {
168 if (std::ranges::distance(urange1) != std::ranges::distance(urange2))
169 throw std::invalid_argument{"The two ranges do not have the same size."};
170 }
171 }
173
190 basic_iterator<false> begin()
191 {
192 return {std::ranges::begin(urange1),
193 std::ranges::end(urange1),
194 std::ranges::begin(urange2),
195 window_size};
196 }
197
199 basic_iterator<true> begin() const
201 requires const_iterable
203 {
204 return {std::ranges::cbegin(urange1),
205 std::ranges::cend(urange1),
206 std::ranges::cbegin(urange2),
207 window_size};
208 }
209
225 sentinel end() const
226 {
227 return {};
228 }
230};
231
233template <std::ranges::view urng1_t, std::ranges::view urng2_t>
234template <bool const_range>
235class minimiser_view<urng1_t, urng2_t>::basic_iterator
236{
237private:
239 using urng1_sentinel_t = maybe_const_sentinel_t<const_range, urng1_t>;
241 using urng1_iterator_t = maybe_const_iterator_t<const_range, urng1_t>;
243 using urng2_iterator_t = maybe_const_iterator_t<const_range, urng2_t>;
244
245 template <bool>
246 friend class basic_iterator;
247
248public:
253 using difference_type = std::ranges::range_difference_t<urng1_t>;
255 using value_type = std::ranges::range_value_t<urng1_t>;
257 using pointer = void;
259 using reference = value_type;
261 using iterator_category = std::forward_iterator_tag;
263 using iterator_concept = iterator_category;
265
269 basic_iterator() = default;
270 basic_iterator(basic_iterator const &) = default;
271 basic_iterator(basic_iterator &&) = default;
272 basic_iterator & operator=(basic_iterator const &) = default;
273 basic_iterator & operator=(basic_iterator &&) = default;
274 ~basic_iterator() = default;
275
277 basic_iterator(basic_iterator<!const_range> const & it)
279 requires const_range
281 : minimiser_value{std::move(it.minimiser_value)},
282 urng1_iterator{std::move(it.urng1_iterator)},
283 urng1_sentinel{std::move(it.urng1_sentinel)},
284 urng2_iterator{std::move(it.urng2_iterator)},
285 window_values{std::move(it.window_values)}
286 {}
287
301 basic_iterator(urng1_iterator_t urng1_iterator,
302 urng1_sentinel_t urng1_sentinel,
303 urng2_iterator_t urng2_iterator,
304 size_t window_size) :
305 urng1_iterator{std::move(urng1_iterator)},
306 urng1_sentinel{std::move(urng1_sentinel)},
307 urng2_iterator{std::move(urng2_iterator)}
308 {
309 size_t size = std::ranges::distance(urng1_iterator, urng1_sentinel);
310 window_size = std::min<size_t>(window_size, size);
311
312 window_first(window_size);
313 }
315
319
321 friend bool operator==(basic_iterator const & lhs, basic_iterator const & rhs)
322 {
323 return (lhs.urng1_iterator == rhs.urng1_iterator) &&
324 (rhs.urng2_iterator == rhs.urng2_iterator) &&
325 (lhs.window_values.size() == rhs.window_values.size());
326 }
327
329 friend bool operator!=(basic_iterator const & lhs, basic_iterator const & rhs)
330 {
331 return !(lhs == rhs);
332 }
333
335 friend bool operator==(basic_iterator const & lhs, sentinel const &)
336 {
337 return lhs.urng1_iterator == lhs.urng1_sentinel;
338 }
339
341 friend bool operator==(sentinel const & lhs, basic_iterator const & rhs)
342 {
343 return rhs == lhs;
344 }
345
347 friend bool operator!=(sentinel const & lhs, basic_iterator const & rhs)
348 {
349 return !(lhs == rhs);
350 }
351
353 friend bool operator!=(basic_iterator const & lhs, sentinel const & rhs)
354 {
355 return !(lhs == rhs);
356 }
358
360 basic_iterator & operator++() noexcept
361 {
362 next_unique_minimiser();
363 return *this;
364 }
365
367 basic_iterator operator++(int) noexcept
368 {
369 basic_iterator tmp{*this};
370 next_unique_minimiser();
371 return tmp;
372 }
373
375 value_type operator*() const noexcept
376 {
377 return minimiser_value;
378 }
379
380private:
382 value_type minimiser_value{};
383
385 size_t minimiser_position_offset{};
386
388 urng1_iterator_t urng1_iterator{};
390 urng1_sentinel_t urng1_sentinel{};
392 urng2_iterator_t urng2_iterator{};
393
395 std::deque<value_type> window_values{};
396
398 void next_unique_minimiser()
399 {
400 while (!next_minimiser()) {}
401 }
402
404 auto window_value() const
405 {
406 if constexpr (!second_range_is_given)
407 return *urng1_iterator;
408 else
409 return std::min(*urng1_iterator, *urng2_iterator);
410 }
411
413 void advance_window()
414 {
415 ++urng1_iterator;
416 if constexpr (second_range_is_given)
417 ++urng2_iterator;
418 }
419
421 void window_first(size_t const window_size)
422 {
423 if (window_size == 0u)
424 return;
425
426 for (size_t i = 0u; i < window_size - 1u; ++i)
427 {
428 window_values.push_back(window_value());
429 advance_window();
430 }
431 window_values.push_back(window_value());
432 auto minimiser_it = std::ranges::min_element(window_values, std::less_equal<value_type>{});
433 minimiser_value = *minimiser_it ;
434 minimiser_position_offset = std::distance(std::begin(window_values), minimiser_it);
435 }
436
443 bool next_minimiser()
444 {
445 advance_window();
446 if (urng1_iterator == urng1_sentinel)
447 return true;
448
449 value_type const new_value = window_value();
450
451 window_values.pop_front();
452 window_values.push_back(new_value);
453
454 if (minimiser_position_offset == 0)
455 {
456 auto minimiser_it = std::ranges::min_element(window_values, std::less_equal<value_type>{});
457 minimiser_value = *minimiser_it ;
458 minimiser_position_offset = std::distance(std::begin(window_values), minimiser_it);
459 return true;
460 }
461
462 if (new_value < minimiser_value)
463 {
464 minimiser_value = new_value;
465 minimiser_position_offset = window_values.size() - 1;
466 return true;
467 }
468
469 --minimiser_position_offset;
470 return false;
471 }
472};
473
475template <std::ranges::viewable_range rng1_t>
476minimiser_view(rng1_t &&, size_t const window_size) -> minimiser_view<std::views::all_t<rng1_t>>;
477
479template <std::ranges::viewable_range rng1_t, std::ranges::viewable_range rng2_t>
480minimiser_view(rng1_t &&, rng2_t &&, size_t const window_size) -> minimiser_view<std::views::all_t<rng1_t>,
481 std::views::all_t<rng2_t>>;
482
483// ---------------------------------------------------------------------------------------------------------------------
484// minimiser_fn (adaptor definition)
485// ---------------------------------------------------------------------------------------------------------------------
486
490struct minimiser_fn
491{
493 constexpr auto operator()(size_t const window_size) const
494 {
495 return adaptor_from_functor{*this, window_size};
496 }
497
506 template <std::ranges::range urng1_t>
507 constexpr auto operator()(urng1_t && urange1, size_t const window_size) const
508 {
509 static_assert(std::ranges::viewable_range<urng1_t>,
510 "The range parameter to views::minimiser cannot be a temporary of a non-view range.");
511 static_assert(std::ranges::forward_range<urng1_t>,
512 "The range parameter to views::minimiser must model std::ranges::forward_range.");
513
514 if (window_size == 1) // Would just return urange1 without any changes
515 throw std::invalid_argument{"The chosen window_size is not valid. "
516 "Please choose a value greater than 1 or use two ranges."};
517
518 return minimiser_view{urange1, window_size};
519 }
520};
522
523} // namespace seqan3::detail
524
525namespace seqan3::views
526{
585inline constexpr auto minimiser = detail::minimiser_fn{};
586
587} // namespace seqan3::views
Provides seqan3::detail::adaptor_from_functor.
The <algorithm> header from C++20's standard library.
T begin(T... args)
Provides various transformation traits used by the range module.
T distance(T... args)
Provides seqan3::detail::empty_type.
T end(T... args)
constexpr auto minimiser
Computes minimisers for a range of comparable values. A minimiser is the smallest value in a window.
Definition: minimiser.hpp:585
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:151
Specifies requirements of an input range type for which the const version of that type satisfies the ...
Provides lazy template instantiation traits.
T min(T... args)
The SeqAn namespace for views.
Definition: char_to.hpp:22
SeqAn specific customisations in the standard namespace.
T operator!=(T... args)
Additional non-standard concepts for ranges.