btllib
Loading...
Searching...
No Matches
bihash_kmer_bi.hpp
1#pragma once
2
3#include <array>
4#include <cstdint>
5#include <cstring>
6#include <deque>
7#include <memory>
8#include <string>
9#include <vector>
10
11#include <btllib/bihash_hashing_internals.hpp>
12#include <btllib/hashing_internals.hpp>
13#include <btllib/nthash_kmer.hpp>
14#include <btllib/status.hpp>
15
16namespace btllib {
17
18using hashing_internals::base_forward_hash;
19using hashing_internals::base_reverse_hash;
20using hashing_internals::extend_hashes;
21using hashing_internals::next_forward_hash;
22using hashing_internals::next_reverse_hash;
23using hashing_internals::prev_forward_hash;
24using hashing_internals::prev_reverse_hash;
25using hashing_internals::SEED_N;
26using hashing_internals::SEED_TAB;
27using hashing_internals::sub_hash;
28
29using hashing_internals::BI_BI_SEED_TAB;
30
31using hashing_internals::BI_BI_MS_TAB_33R;
32
33using hashing_internals::BI_BI_MS_TAB_31L;
34
35using hashing_internals::BI_BI_CONVERT_TAB;
36
37using hashing_internals::BI_BI_RC_CONVERT_TAB;
38
39using hashing_internals::BI_BI_DIMER_TAB;
40using hashing_internals::BI_BI_TETRAMER_TAB;
41using hashing_internals::BI_BI_TRIMER_TAB;
42
47{
48
49public:
58 BiHashBi(const char* seq,
59 size_t seq_len,
60 hashing_internals::NUM_HASHES_TYPE num_hashes,
61 hashing_internals::K_TYPE k,
62 size_t pos = 0)
63 : seq(seq)
64 , seq_len(seq_len)
65 , num_hashes(num_hashes)
66 , k(k)
67 , pos(pos)
68 , initialized(false)
69 , hash_arr(new uint64_t[num_hashes])
70 {
71 check_error(k == 0, "BiHash: k must be greater than 0");
72 check_error(k % 2 == 1, "BiHash: k must be even");
73 check_error((k / 2) % 2 == 0, "BiHash: k must have odd number of dimers");
74 check_error(this->seq_len < k,
75 "BiHash: sequence length (" + std::to_string(this->seq_len) +
76 ") is smaller than k (" + std::to_string(k) + ")");
77 check_error(pos > this->seq_len - k,
78 "BiHash: passed position (" + std::to_string(pos) +
79 ") is larger than sequence length (" +
80 std::to_string(this->seq_len) + ")");
81
82 size_t num_dimers = k / 2;
83 size_t center_dimer_start = (num_dimers / 2) * 2;
84 meth_base_idx = center_dimer_start;
85
86 primitive_tab = BI_BI_SEED_TAB;
87
88 right_table = BI_BI_MS_TAB_33R;
89 left_table = BI_BI_MS_TAB_31L;
90
91 convert_tab = BI_BI_CONVERT_TAB;
92 rc_convert_tab = BI_BI_RC_CONVERT_TAB;
93
94 dimer_tab = BI_BI_DIMER_TAB;
95 trimer_tab = BI_BI_TRIMER_TAB;
96 tetramer_tab = BI_BI_TETRAMER_TAB;
97 }
98
106 BiHashBi(const std::string& seq,
107 hashing_internals::NUM_HASHES_TYPE num_hashes,
108 hashing_internals::K_TYPE k,
109 size_t pos = 0)
110 : BiHashBi(seq.data(), seq.size(), num_hashes, k, pos)
111 {
112 }
113
114 BiHashBi(const BiHashBi& obj)
115 : seq(obj.seq)
116 , seq_len(obj.seq_len)
117 , num_hashes(obj.num_hashes)
118 , k(obj.k)
119 , pos(obj.pos)
120 , initialized(obj.initialized)
121 , fwd_hash(obj.fwd_hash)
122 , rev_hash(obj.rev_hash)
123 , hash_arr(new uint64_t[obj.num_hashes])
124 , primitive_tab(obj.primitive_tab)
125 , right_table(obj.right_table)
126 , left_table(obj.left_table)
127 , convert_tab(obj.convert_tab)
128 , rc_convert_tab(obj.rc_convert_tab)
129 , dimer_tab(obj.dimer_tab)
130 , trimer_tab(obj.trimer_tab)
131 , tetramer_tab(obj.tetramer_tab)
132 {
133 std::memcpy(
134 hash_arr.get(), obj.hash_arr.get(), num_hashes * sizeof(uint64_t));
135 }
136
137 BiHashBi(BiHashBi&&) = default;
150 bool roll()
151 {
152 if (!initialized) {
153 return init();
154 }
155 if (pos >= seq_len - k) {
156 return false;
157 }
158 if (hashing_internals::SEED_TAB[(unsigned char)seq[pos + k]] ==
159 hashing_internals::SEED_N) {
160 pos += k;
161 return init();
162 }
163 fwd_hash = next_forward_hash(fwd_hash,
164 k,
165 seq[pos],
166 seq[pos + k],
167 primitive_tab,
168 right_table,
169 left_table);
170 rev_hash = next_reverse_hash(rev_hash,
171 k,
172 seq[pos],
173 seq[pos + k],
174 primitive_tab,
175 right_table,
176 left_table);
177 extend_hashes(fwd_hash, rev_hash, k, num_hashes, hash_arr.get());
178 ++pos;
179 return true;
180 }
181
187 {
188 if (!initialized) {
189 return init();
190 }
191 if (pos == 0) {
192 return false;
193 }
194 if (SEED_TAB[(unsigned char)seq[pos - 1]] == SEED_N && pos >= k) {
195 pos -= k;
196 return init();
197 }
198 if (SEED_TAB[(unsigned char)seq[pos - 1]] == SEED_N) {
199 return false;
200 }
201 fwd_hash = prev_forward_hash(fwd_hash,
202 k,
203 seq[pos + k - 1],
204 seq[pos - 1],
205 primitive_tab,
206 right_table,
207 left_table);
208 rev_hash = prev_reverse_hash(rev_hash,
209 k,
210 seq[pos + k - 1],
211 seq[pos - 1],
212 primitive_tab,
213 right_table,
214 left_table);
215 extend_hashes(fwd_hash, rev_hash, k, num_hashes, hash_arr.get());
216 --pos;
217 return true;
218 }
219
226 bool peek()
227 {
228 if (pos >= seq_len - k) {
229 return false;
230 }
231 return peek(seq[pos + k]);
232 }
233
239 {
240 if (pos == 0) {
241 return false;
242 }
243 return peek_back(seq[pos - 1]);
244 }
245
252 bool peek(char char_in)
253 {
254 if (!initialized) {
255 return init();
256 }
257 if (SEED_TAB[(unsigned char)char_in] == SEED_N) {
258 return false;
259 }
260 const uint64_t fwd = next_forward_hash(
261 fwd_hash, k, seq[pos], char_in, primitive_tab, right_table, left_table);
262 const uint64_t rev = next_reverse_hash(
263 rev_hash, k, seq[pos], char_in, primitive_tab, right_table, left_table);
264 extend_hashes(fwd, rev, k, num_hashes, hash_arr.get());
265 return true;
266 }
267
272 bool peek_back(char char_in)
273 {
274 if (!initialized) {
275 return init();
276 }
277 if (SEED_TAB[(unsigned char)char_in] == SEED_N) {
278 return false;
279 }
280 const unsigned char char_out = seq[pos + k - 1];
281 const uint64_t fwd = prev_forward_hash(
282 fwd_hash, k, char_out, char_in, primitive_tab, right_table, left_table);
283 const uint64_t rev = prev_reverse_hash(
284 rev_hash, k, char_out, char_in, primitive_tab, right_table, left_table);
285 extend_hashes(fwd, rev, k, num_hashes, hash_arr.get());
286 return true;
287 }
288
299 std::string_view center_dimer() const
300 {
301 constexpr size_t DIMER_LEN = 2;
302 const size_t center_idx = pos + (k / 4) * DIMER_LEN;
303 return std::string_view(seq + center_idx, DIMER_LEN);
304 }
305
315 bool is_methylated(int offset)
316 {
317 char base = seq[pos + meth_base_idx + offset];
318 if (offset == 0) {
319 return base == 'C' || base == 'c';
320 } else {
321 return base == 'G' || base == 'g';
322 }
323 }
324
329 bool is_forward_higher() const { return fwd_hash > rev_hash; }
330
331 void sub(const std::vector<unsigned>& positions,
332 const std::vector<unsigned char>& new_bases)
333 {
334 sub_hash(fwd_hash,
335 rev_hash,
336 seq + pos,
337 positions,
338 new_bases,
339 get_k(),
340 get_hash_num(),
341 hash_arr.get(),
342 right_table,
343 left_table);
344 }
345
350 const uint64_t* hashes() const { return hash_arr.get(); }
351
357 size_t get_pos() const { return pos; }
358
363 hashing_internals::NUM_HASHES_TYPE get_hash_num() const { return num_hashes; }
364
369 hashing_internals::K_TYPE get_k() const { return k; }
370
375 uint64_t get_forward_hash() const { return fwd_hash; }
376
381 uint64_t get_reverse_hash() const { return rev_hash; }
382
383private:
384 const char* seq;
385 const size_t seq_len;
386 hashing_internals::NUM_HASHES_TYPE num_hashes;
387 hashing_internals::K_TYPE k;
388 size_t pos;
389 size_t meth_base_idx;
390 bool initialized;
391 uint64_t fwd_hash = 0;
392 uint64_t rev_hash = 0;
393 std::unique_ptr<uint64_t[]> hash_arr;
394
395 const uint64_t* primitive_tab;
396
397 const uint64_t* const* right_table;
398 const uint64_t* const* left_table;
399
400 const uint8_t* convert_tab;
401 const uint8_t* rc_convert_tab;
402
403 const uint64_t* dimer_tab;
404 const uint64_t* trimer_tab;
405 const uint64_t* tetramer_tab;
406
411 bool init()
412 {
413 bool has_n = true;
414 while (pos <= seq_len - k + 1 && has_n) {
415 has_n = false;
416 for (unsigned i = 0; i < k && pos <= seq_len - k + 1; i++) {
417 if (SEED_TAB[(unsigned char)seq[pos + k - i - 1]] == SEED_N) {
418 pos += k - i;
419 has_n = true;
420 }
421 }
422 }
423 if (pos > seq_len - k) {
424 return false;
425 }
426 fwd_hash = base_forward_hash(seq + pos,
427 k,
428 primitive_tab,
429 dimer_tab,
430 trimer_tab,
431 tetramer_tab,
432 convert_tab);
433 rev_hash = base_reverse_hash(seq + pos,
434 k,
435 primitive_tab,
436 dimer_tab,
437 trimer_tab,
438 tetramer_tab,
439 rc_convert_tab);
440 extend_hashes(fwd_hash, rev_hash, k, num_hashes, hash_arr.get());
441 initialized = true;
442 return true;
443 }
444};
445
446} // namespace btllib
Definition bihash_kmer_bi.hpp:47
bool peek(char char_in)
Definition bihash_kmer_bi.hpp:252
size_t get_pos() const
Definition bihash_kmer_bi.hpp:357
bool roll()
Definition bihash_kmer_bi.hpp:150
bool roll_back()
Definition bihash_kmer_bi.hpp:186
BiHashBi(const std::string &seq, hashing_internals::NUM_HASHES_TYPE num_hashes, hashing_internals::K_TYPE k, size_t pos=0)
Definition bihash_kmer_bi.hpp:106
bool is_methylated(int offset)
Definition bihash_kmer_bi.hpp:315
bool peek_back(char char_in)
Definition bihash_kmer_bi.hpp:272
BiHashBi(const char *seq, size_t seq_len, hashing_internals::NUM_HASHES_TYPE num_hashes, hashing_internals::K_TYPE k, size_t pos=0)
Definition bihash_kmer_bi.hpp:58
hashing_internals::NUM_HASHES_TYPE get_hash_num() const
Definition bihash_kmer_bi.hpp:363
hashing_internals::K_TYPE get_k() const
Definition bihash_kmer_bi.hpp:369
bool is_forward_higher() const
Definition bihash_kmer_bi.hpp:329
std::string_view center_dimer() const
Definition bihash_kmer_bi.hpp:299
uint64_t get_forward_hash() const
Definition bihash_kmer_bi.hpp:375
const uint64_t * hashes() const
Definition bihash_kmer_bi.hpp:350
bool peek_back()
Definition bihash_kmer_bi.hpp:238
bool peek()
Definition bihash_kmer_bi.hpp:226
uint64_t get_reverse_hash() const
Definition bihash_kmer_bi.hpp:381
Definition aahash.hpp:12
void check_error(bool condition, const std::string &msg)