btllib
Loading...
Searching...
No Matches
nthash_kmer.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/hashing_internals.hpp>
12#include <btllib/status.hpp>
13
14namespace btllib::hashing_internals {
15
22inline uint64_t
23base_forward_hash(const char* seq,
24 unsigned k,
25 const uint64_t* primitive_tab = SEED_TAB,
26 const uint64_t* dimer_tab = DIMER_TAB,
27 const uint64_t* trimer_tab = TRIMER_TAB,
28 const uint64_t* tetramer_tab = TETRAMER_TAB,
29 const uint8_t* convert_tab = CONVERT_TAB)
30{
31 uint64_t h_val = 0;
32 for (unsigned i = 0; i < k - 3; i += 4) {
33 h_val = srol(h_val, 4);
34 uint8_t loc = 0;
35 loc += 64 * convert_tab[(unsigned char)seq[i]]; // NOLINT
36 loc += 16 * convert_tab[(unsigned char)seq[i + 1]]; // NOLINT
37 loc += 4 * convert_tab[(unsigned char)seq[i + 2]];
38 loc += convert_tab[(unsigned char)seq[i + 3]];
39 h_val ^= tetramer_tab[loc];
40 }
41 const unsigned remainder = k % 4;
42 if (remainder > 0) {
43 h_val = srol(h_val, remainder);
44 }
45 if (remainder == 3) {
46 uint8_t trimer_loc = 0;
47 trimer_loc += 16 * convert_tab[(unsigned char)seq[k - 3]]; // NOLINT
48 trimer_loc += 4 * convert_tab[(unsigned char)seq[k - 2]];
49 trimer_loc += convert_tab[(unsigned char)seq[k - 1]];
50 h_val ^= trimer_tab[trimer_loc];
51 } else if (remainder == 2) {
52 uint8_t dimer_loc = 0;
53 dimer_loc += 4 * convert_tab[(unsigned char)seq[k - 2]];
54 dimer_loc += convert_tab[(unsigned char)seq[k - 1]];
55 h_val ^= dimer_tab[dimer_loc];
56 } else if (remainder == 1) {
57 h_val ^= primitive_tab[(unsigned char)seq[k - 1]];
58 }
59 return h_val;
60}
61
71inline uint64_t
72next_forward_hash(uint64_t fh_val,
73 unsigned k,
74 unsigned char char_out,
75 unsigned char char_in,
76 const uint64_t* primitive_tab = SEED_TAB,
77 const uint64_t* const* right_table = MS_TAB_33R,
78 const uint64_t* const* left_table = MS_TAB_31L)
79{
80 uint64_t h_val = srol(fh_val);
81 h_val ^= primitive_tab[char_in];
82 h_val ^= srol_table(char_out, k, right_table, left_table);
83 return h_val;
84}
85
94inline uint64_t
95prev_forward_hash(uint64_t fh_val,
96 unsigned k,
97 unsigned char char_out,
98 unsigned char char_in,
99 const uint64_t* primitive_tab = SEED_TAB,
100 const uint64_t* const* right_table = MS_TAB_33R,
101 const uint64_t* const* left_table = MS_TAB_31L)
102{
103 uint64_t h_val = fh_val ^ srol_table(char_in, k, right_table, left_table);
104 h_val ^= primitive_tab[char_out];
105 h_val = sror(h_val);
106 return h_val;
107}
108
116inline uint64_t
117base_reverse_hash(const char* seq,
118 unsigned k,
119 const uint64_t* primitive_tab = SEED_TAB,
120 const uint64_t* dimer_tab = DIMER_TAB,
121 const uint64_t* trimer_tab = TRIMER_TAB,
122 const uint64_t* tetramer_tab = TETRAMER_TAB,
123 const uint8_t* rc_convert_tab = RC_CONVERT_TAB)
124{
125 uint64_t h_val = 0;
126 const unsigned remainder = k % 4;
127 if (remainder == 3) {
128 uint8_t trimer_loc = 0;
129 trimer_loc += 16 * rc_convert_tab[(unsigned char)seq[k - 1]]; // NOLINT
130 trimer_loc += 4 * rc_convert_tab[(unsigned char)seq[k - 2]];
131 trimer_loc += rc_convert_tab[(unsigned char)seq[k - 3]];
132 h_val ^= trimer_tab[trimer_loc];
133 } else if (remainder == 2) {
134 uint8_t dimer_loc = 0;
135 dimer_loc += 4 * rc_convert_tab[(unsigned char)seq[k - 1]];
136 dimer_loc += rc_convert_tab[(unsigned char)seq[k - 2]];
137 h_val ^= dimer_tab[dimer_loc];
138 } else if (remainder == 1) {
139 h_val ^= primitive_tab[(unsigned char)seq[k - 1] & CP_OFF];
140 }
141 for (int i = (int)(k - remainder) - 1; i >= 3; i -= 4) {
142 h_val = srol(h_val, 4);
143 uint8_t loc = 0;
144 loc += 64 * rc_convert_tab[(unsigned char)seq[i]]; // NOLINT
145 loc += 16 * rc_convert_tab[(unsigned char)seq[i - 1]]; // NOLINT
146 loc += 4 * rc_convert_tab[(unsigned char)seq[i - 2]];
147 loc += rc_convert_tab[(unsigned char)seq[i - 3]];
148 h_val ^= tetramer_tab[loc];
149 }
150 return h_val;
151}
152
163inline uint64_t
164next_reverse_hash(uint64_t rh_val,
165 unsigned k,
166 unsigned char char_out,
167 unsigned char char_in,
168 const uint64_t* primitive_tab = SEED_TAB,
169 const uint64_t* const* right_table = MS_TAB_33R,
170 const uint64_t* const* left_table = MS_TAB_31L)
171{
172 uint64_t h_val =
173 rh_val ^ srol_table(char_in & CP_OFF, k, right_table, left_table);
174 h_val ^= primitive_tab[char_out & CP_OFF];
175 h_val = sror(h_val);
176 return h_val;
177}
178
187inline uint64_t
188prev_reverse_hash(uint64_t rh_val,
189 unsigned k,
190 unsigned char char_out,
191 unsigned char char_in,
192 const uint64_t* primitive_tab = SEED_TAB,
193 const uint64_t* const* right_table = MS_TAB_33R,
194 const uint64_t* const* left_table = MS_TAB_31L)
195{
196 uint64_t h_val = srol(rh_val);
197 h_val ^= primitive_tab[char_in & CP_OFF];
198 h_val ^= srol_table(char_out & CP_OFF, k, right_table, left_table);
199 return h_val;
200}
201
216inline void
217sub_hash(uint64_t fh_val,
218 uint64_t rh_val,
219 const char* kmer_seq,
220 const std::vector<unsigned>& positions,
221 const std::vector<unsigned char>& new_bases,
222 unsigned k,
223 unsigned m,
224 uint64_t* h_val,
225 const uint64_t* const* right_table = MS_TAB_33R,
226 const uint64_t* const* left_table = MS_TAB_31L)
227{
228 uint64_t b_val = 0;
229
230 for (size_t i = 0; i < positions.size(); i++) {
231 const auto pos = positions[i];
232 const auto new_base = new_bases[i];
233
234 fh_val ^= srol_table(
235 (unsigned char)kmer_seq[pos], k - 1 - pos, right_table, left_table);
236 fh_val ^= srol_table(new_base, k - 1 - pos, right_table, left_table);
237
238 rh_val ^= srol_table(
239 (unsigned char)kmer_seq[pos] & CP_OFF, pos, right_table, left_table);
240 rh_val ^= srol_table(new_base & CP_OFF, pos, right_table, left_table);
241 }
242
243 b_val = canonical(fh_val, rh_val);
244 extend_hashes(b_val, k, m, h_val);
245}
246
247} // namespace btllib::hashing_internals
248
249namespace btllib {
250
251using hashing_internals::base_forward_hash;
252using hashing_internals::base_reverse_hash;
253using hashing_internals::extend_hashes;
254using hashing_internals::next_forward_hash;
255using hashing_internals::next_reverse_hash;
256using hashing_internals::prev_forward_hash;
257using hashing_internals::prev_reverse_hash;
258using hashing_internals::SEED_N;
259using hashing_internals::SEED_TAB;
260using hashing_internals::sub_hash;
261
266{
267
268public:
277 NtHash(const char* seq,
278 size_t seq_len,
279 hashing_internals::NUM_HASHES_TYPE num_hashes,
280 hashing_internals::K_TYPE k,
281 size_t pos = 0)
282 : seq(seq)
283 , seq_len(seq_len)
284 , num_hashes(num_hashes)
285 , k(k)
286 , pos(pos)
287 , initialized(false)
288 , hash_arr(new uint64_t[num_hashes])
289 {
290 check_error(k == 0, "NtHash: k must be greater than 0");
291 check_error(this->seq_len < k,
292 "NtHash: sequence length (" + std::to_string(this->seq_len) +
293 ") is smaller than k (" + std::to_string(k) + ")");
294 check_error(pos > this->seq_len - k,
295 "NtHash: passed position (" + std::to_string(pos) +
296 ") is larger than sequence length (" +
297 std::to_string(this->seq_len) + ")");
298 }
299
307 NtHash(const std::string& seq,
308 hashing_internals::NUM_HASHES_TYPE num_hashes,
309 hashing_internals::K_TYPE k,
310 size_t pos = 0)
311 : NtHash(seq.data(), seq.size(), num_hashes, k, pos)
312 {
313 }
314
315 NtHash(const NtHash& obj)
316 : seq(obj.seq)
317 , seq_len(obj.seq_len)
318 , num_hashes(obj.num_hashes)
319 , k(obj.k)
320 , pos(obj.pos)
321 , initialized(obj.initialized)
322 , fwd_hash(obj.fwd_hash)
323 , rev_hash(obj.rev_hash)
324 , hash_arr(new uint64_t[obj.num_hashes])
325 {
326 std::memcpy(
327 hash_arr.get(), obj.hash_arr.get(), num_hashes * sizeof(uint64_t));
328 }
329
330 NtHash(NtHash&&) = default;
331
344 bool roll()
345 {
346 if (!initialized) {
347 return init();
348 }
349 if (pos >= seq_len - k) {
350 return false;
351 }
352 if (hashing_internals::SEED_TAB[(unsigned char)seq[pos + k]] ==
353 hashing_internals::SEED_N) {
354 pos += k;
355 return init();
356 }
357 fwd_hash = next_forward_hash(fwd_hash, k, seq[pos], seq[pos + k]);
358 rev_hash = next_reverse_hash(rev_hash, k, seq[pos], seq[pos + k]);
359 extend_hashes(fwd_hash, rev_hash, k, num_hashes, hash_arr.get());
360 ++pos;
361 return true;
362 }
363
369 {
370 if (!initialized) {
371 return init();
372 }
373 if (pos == 0) {
374 return false;
375 }
376 if (SEED_TAB[(unsigned char)seq[pos - 1]] == SEED_N && pos >= k) {
377 pos -= k;
378 return init();
379 }
380 if (SEED_TAB[(unsigned char)seq[pos - 1]] == SEED_N) {
381 return false;
382 }
383 fwd_hash = prev_forward_hash(fwd_hash, k, seq[pos + k - 1], seq[pos - 1]);
384 rev_hash = prev_reverse_hash(rev_hash, k, seq[pos + k - 1], seq[pos - 1]);
385 extend_hashes(fwd_hash, rev_hash, k, num_hashes, hash_arr.get());
386 --pos;
387 return true;
388 }
389
396 bool peek()
397 {
398 if (pos >= seq_len - k) {
399 return false;
400 }
401 return peek(seq[pos + k]);
402 }
403
409 {
410 if (pos == 0) {
411 return false;
412 }
413 return peek_back(seq[pos - 1]);
414 }
415
422 bool peek(char char_in)
423 {
424 if (!initialized) {
425 return init();
426 }
427 if (SEED_TAB[(unsigned char)char_in] == SEED_N) {
428 return false;
429 }
430 const uint64_t fwd = next_forward_hash(fwd_hash, k, seq[pos], char_in);
431 const uint64_t rev = next_reverse_hash(rev_hash, k, seq[pos], char_in);
432 extend_hashes(fwd, rev, k, num_hashes, hash_arr.get());
433 return true;
434 }
435
440 bool peek_back(char char_in)
441 {
442 if (!initialized) {
443 return init();
444 }
445 if (SEED_TAB[(unsigned char)char_in] == SEED_N) {
446 return false;
447 }
448 const unsigned char char_out = seq[pos + k - 1];
449 const uint64_t fwd = prev_forward_hash(fwd_hash, k, char_out, char_in);
450 const uint64_t rev = prev_reverse_hash(rev_hash, k, char_out, char_in);
451 extend_hashes(fwd, rev, k, num_hashes, hash_arr.get());
452 return true;
453 }
454
455 void sub(const std::vector<unsigned>& positions,
456 const std::vector<unsigned char>& new_bases)
457 {
458 sub_hash(fwd_hash,
459 rev_hash,
460 seq + pos,
461 positions,
462 new_bases,
463 get_k(),
464 get_hash_num(),
465 hash_arr.get());
466 }
467
472 const uint64_t* hashes() const { return hash_arr.get(); }
473
479 size_t get_pos() const { return pos; }
480
485 hashing_internals::NUM_HASHES_TYPE get_hash_num() const { return num_hashes; }
486
491 hashing_internals::K_TYPE get_k() const { return k; }
492
497 uint64_t get_forward_hash() const { return fwd_hash; }
498
503 uint64_t get_reverse_hash() const { return rev_hash; }
504
505private:
506 const char* seq;
507 const size_t seq_len;
508 hashing_internals::NUM_HASHES_TYPE num_hashes;
509 hashing_internals::K_TYPE k;
510 size_t pos;
511 bool initialized;
512 uint64_t fwd_hash = 0;
513 uint64_t rev_hash = 0;
514 std::unique_ptr<uint64_t[]> hash_arr;
515
520 bool init()
521 {
522 bool has_n = true;
523 while (pos <= seq_len - k + 1 && has_n) {
524 has_n = false;
525 for (unsigned i = 0; i < k && pos <= seq_len - k + 1; i++) {
526 if (SEED_TAB[(unsigned char)seq[pos + k - i - 1]] == SEED_N) {
527 pos += k - i;
528 has_n = true;
529 }
530 }
531 }
532 if (pos > seq_len - k) {
533 return false;
534 }
535 fwd_hash = base_forward_hash(seq + pos, k);
536 rev_hash = base_reverse_hash(seq + pos, k);
537 extend_hashes(fwd_hash, rev_hash, k, num_hashes, hash_arr.get());
538 initialized = true;
539 return true;
540 }
541};
542
550{
551
552public:
561 BlindNtHash(const std::string& seq,
562 hashing_internals::NUM_HASHES_TYPE num_hashes,
563 hashing_internals::K_TYPE k,
564 long pos = 0)
565 : seq(seq.data() + pos, seq.data() + pos + k)
566 , num_hashes(num_hashes)
567 , pos(pos)
568 , fwd_hash(base_forward_hash(seq.data(), k))
569 , rev_hash(base_reverse_hash(seq.data(), k))
570 , hash_arr(new uint64_t[num_hashes])
571 {
572 check_error(k == 0, "BlindNtHash: k must be greater than 0");
573 extend_hashes(fwd_hash, rev_hash, k, num_hashes, hash_arr.get());
574 }
575
576 BlindNtHash(const BlindNtHash& obj)
577 : seq(obj.seq)
578 , num_hashes(obj.num_hashes)
579 , pos(obj.pos)
580 , fwd_hash(obj.fwd_hash)
581 , rev_hash(obj.rev_hash)
582 , hash_arr(new uint64_t[obj.num_hashes])
583 {
584 std::memcpy(
585 hash_arr.get(), obj.hash_arr.get(), num_hashes * sizeof(uint64_t));
586 }
587
588 BlindNtHash(BlindNtHash&&) = default;
589
596 void roll(char char_in)
597 {
598 fwd_hash = next_forward_hash(fwd_hash, seq.size(), seq.front(), char_in);
599 rev_hash = next_reverse_hash(rev_hash, seq.size(), seq.front(), char_in);
600 extend_hashes(fwd_hash, rev_hash, seq.size(), num_hashes, hash_arr.get());
601 seq.pop_front();
602 seq.push_back(char_in);
603 ++pos;
604 }
605
609 void roll_back(char char_in)
610 {
611 fwd_hash = prev_forward_hash(fwd_hash, seq.size(), seq.back(), char_in);
612 rev_hash = prev_reverse_hash(rev_hash, seq.size(), seq.back(), char_in);
613 extend_hashes(fwd_hash, rev_hash, seq.size(), num_hashes, hash_arr.get());
614 seq.pop_back();
615 seq.push_front(char_in);
616 --pos;
617 }
618
622 void peek(char char_in)
623 {
624 const hashing_internals::K_TYPE k = seq.size();
625 const uint64_t fwd = next_forward_hash(fwd_hash, k, seq.front(), char_in);
626 const uint64_t rev = next_reverse_hash(rev_hash, k, seq.front(), char_in);
627 extend_hashes(fwd, rev, seq.size(), num_hashes, hash_arr.get());
628 }
629
633 void peek_back(char char_in)
634 {
635 const hashing_internals::K_TYPE k = seq.size();
636 const uint64_t fwd = prev_forward_hash(fwd_hash, k, seq.back(), char_in);
637 const uint64_t rev = prev_reverse_hash(rev_hash, k, seq.back(), char_in);
638 extend_hashes(fwd, rev, seq.size(), num_hashes, hash_arr.get());
639 }
640
645 const uint64_t* hashes() const { return hash_arr.get(); }
646
652 long get_pos() const { return pos; }
653
658 hashing_internals::NUM_HASHES_TYPE get_hash_num() const { return num_hashes; }
659
664 hashing_internals::K_TYPE get_k() const { return seq.size(); }
665
670 uint64_t get_forward_hash() const { return fwd_hash; }
671
676 uint64_t get_reverse_hash() const { return rev_hash; }
677
678private:
679 std::deque<char> seq;
680 hashing_internals::NUM_HASHES_TYPE num_hashes;
681 long pos;
682 uint64_t fwd_hash;
683 uint64_t rev_hash;
684 std::unique_ptr<uint64_t[]> hash_arr;
685};
686
687} // namespace btllib
Definition nthash_kmer.hpp:550
long get_pos() const
Definition nthash_kmer.hpp:652
uint64_t get_forward_hash() const
Definition nthash_kmer.hpp:670
hashing_internals::K_TYPE get_k() const
Definition nthash_kmer.hpp:664
void peek(char char_in)
Definition nthash_kmer.hpp:622
uint64_t get_reverse_hash() const
Definition nthash_kmer.hpp:676
void roll(char char_in)
Definition nthash_kmer.hpp:596
const uint64_t * hashes() const
Definition nthash_kmer.hpp:645
hashing_internals::NUM_HASHES_TYPE get_hash_num() const
Definition nthash_kmer.hpp:658
BlindNtHash(const std::string &seq, hashing_internals::NUM_HASHES_TYPE num_hashes, hashing_internals::K_TYPE k, long pos=0)
Definition nthash_kmer.hpp:561
void peek_back(char char_in)
Definition nthash_kmer.hpp:633
void roll_back(char char_in)
Definition nthash_kmer.hpp:609
Definition nthash_kmer.hpp:266
bool peek()
Definition nthash_kmer.hpp:396
bool peek_back()
Definition nthash_kmer.hpp:408
bool peek(char char_in)
Definition nthash_kmer.hpp:422
bool roll()
Definition nthash_kmer.hpp:344
const uint64_t * hashes() const
Definition nthash_kmer.hpp:472
hashing_internals::NUM_HASHES_TYPE get_hash_num() const
Definition nthash_kmer.hpp:485
hashing_internals::K_TYPE get_k() const
Definition nthash_kmer.hpp:491
NtHash(const char *seq, size_t seq_len, hashing_internals::NUM_HASHES_TYPE num_hashes, hashing_internals::K_TYPE k, size_t pos=0)
Definition nthash_kmer.hpp:277
bool peek_back(char char_in)
Definition nthash_kmer.hpp:440
uint64_t get_reverse_hash() const
Definition nthash_kmer.hpp:503
size_t get_pos() const
Definition nthash_kmer.hpp:479
NtHash(const std::string &seq, hashing_internals::NUM_HASHES_TYPE num_hashes, hashing_internals::K_TYPE k, size_t pos=0)
Definition nthash_kmer.hpp:307
bool roll_back()
Definition nthash_kmer.hpp:368
uint64_t get_forward_hash() const
Definition nthash_kmer.hpp:497
Definition aahash.hpp:12
void check_error(bool condition, const std::string &msg)