SeqAn3  3.0.1
The Modern C++ library for sequence analysis.
search_trivial.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2020, 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 
14 #pragma once
15 
16 #include <type_traits>
17 
19 #include <seqan3/range/concept.hpp>
22 #include <seqan3/std/ranges>
23 
24 namespace seqan3::detail
25 {
26 
28 enum class error_type : uint8_t
29 {
30  deletion,
31  insertion,
32  matchmm,
33  none
34 };
35 
61 template <bool abort_on_hit, typename query_t, typename cursor_t, typename delegate_t>
62 inline bool search_trivial(cursor_t cur,
63  query_t & query,
64  typename cursor_t::size_type const query_pos,
65  search_param const error_left,
66  error_type const prev_error,
67  delegate_t && delegate) noexcept(noexcept(delegate))
68 {
69  // Exact case (end of query sequence or no errors left)
70  if (query_pos == std::ranges::size(query) || error_left.total == 0)
71  {
72  // If not at end of query sequence, try searching the remaining suffix without any errors.
73  if (query_pos == std::ranges::size(query) || cur.extend_right(views::drop(query, query_pos)))
74  {
75  delegate(cur);
76  return true;
77  }
78  }
79  // Approximate case
80  else
81  {
82  // Insertion
83  // Only allow insertions if there is no match and we are not at the beginning of the query.
84  bool const allow_insertion = (cur.query_length() > 0) ? cur.last_rank() != seqan3::to_rank(query[query_pos]) : true;
85 
86  if (allow_insertion && (prev_error != error_type::deletion || error_left.substitution == 0) &&
87  error_left.insertion > 0)
88  {
89  search_param error_left2{error_left};
90  error_left2.insertion--;
91  error_left2.total--;
92 
93  // Always perform a recursive call. Abort recursion if and only if recursive call found a hit and
94  // abort_on_hit is set to true.
95  if (search_trivial<abort_on_hit>(cur,
96  query, query_pos + 1,
97  error_left2,
98  error_type::insertion,
99  delegate) &&
100  abort_on_hit)
101  {
102  return true;
103  }
104  }
105 
106  // Do not allow deletions at the beginning of the query sequence
107  if (((query_pos > 0 && error_left.deletion > 0) || error_left.substitution > 0) && cur.extend_right())
108  {
109  do
110  {
111  // Match (when error_left.substitution > 0) and Mismatch
112  if (error_left.substitution > 0)
113  {
114  bool delta = cur.last_rank() != seqan3::to_rank(query[query_pos]);
115  search_param error_left2{error_left};
116  error_left2.total -= delta;
117  error_left2.substitution -= delta;
118 
119  if (search_trivial<abort_on_hit>(cur,
120  query,
121  query_pos + 1,
122  error_left2,
123  error_type::matchmm,
124  delegate) &&
125  abort_on_hit)
126  {
127  return true;
128  }
129  }
130 
131  // Deletion (Do not allow deletions at the beginning of the query sequence.)
132  if (query_pos > 0)
133  {
134  // Match (when error_left.substitution == 0)
135  if (error_left.substitution == 0 && cur.last_rank() == seqan3::to_rank(query[query_pos]))
136  {
137  if (search_trivial<abort_on_hit>(cur,
138  query,
139  query_pos + 1,
140  error_left,
141  error_type::matchmm,
142  delegate) &&
143  abort_on_hit)
144  {
145  return true;
146  }
147  }
148 
149  // Deletions at the end of the sequence are not allowed. When the algorithm
150  // arrives here, it cannot be at the end of the query and since deletions do not touch the query
151  // (i.e. increase query_pos) it won't be at the end of the query after the deletion.
152  // Do not allow deletions after an insertion.
153  if ((prev_error != error_type::insertion || error_left.substitution == 0) &&
154  error_left.deletion > 0)
155  {
156  search_param error_left2{error_left};
157  error_left2.total--;
158  error_left2.deletion--;
159  // Only search for characters different from the corresponding query character.
160  // (Same character is covered by a match.)
161  if (cur.last_rank() != seqan3::to_rank(query[query_pos]))
162  {
163  if (search_trivial<abort_on_hit>(cur,
164  query,
165  query_pos,
166  error_left2,
167  error_type::deletion,
168  delegate) &&
169  abort_on_hit)
170  {
171  return true;
172  }
173  }
174  }
175  }
176  } while (cur.cycle_back());
177  }
178  else
179  {
180  // Match (when error_left.substitution == 0)
181  if (cur.extend_right(query[query_pos]))
182  {
183  if (search_trivial<abort_on_hit>(cur,
184  query,
185  query_pos + 1,
186  error_left,
187  error_type::matchmm,
188  delegate) &&
189  abort_on_hit)
190  {
191  return true;
192  }
193  }
194  }
195  }
196 
197  return false;
198 }
199 
218 template <bool abort_on_hit, typename index_t, typename query_t, typename delegate_t>
219 inline void search_trivial(index_t const & index,
220  query_t & query,
221  search_param const error_left,
222  delegate_t && delegate) noexcept(noexcept(delegate))
223 {
224  search_trivial<abort_on_hit>(index.begin(), query, 0, error_left, error_type::none, delegate);
225 }
226 
228 
229 } // namespace seqan3::detail
drop.hpp
Provides seqan3::views::drop.
seqan3::to_rank
constexpr auto to_rank
Return the rank representation of a (semi-)alphabet object.
Definition: concept.hpp:142
concept.hpp
Additional non-standard concepts for ranges.
seqan3::pack_traits::size
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:116
ranges
Adaptations of concepts from the Ranges TS.
seqan3::views::drop
constexpr auto drop
A view adaptor that returns all elements after n from the underlying range (or an empty range if the ...
Definition: drop.hpp:168
seqan3::none
No flag is set.
Definition: debug_stream_type.hpp:30
search_common.hpp
Provides data structures used by different search algorithms.
concept.hpp
Core alphabet concept and free function/type trait wrappers.