btllib
Loading...
Searching...
No Matches
bihash_kmer_directional.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_CT_SEED_TAB;
30using hashing_internals::BI_GA_SEED_TAB;
31
32using hashing_internals::BI_CT_MS_TAB_33R;
33using hashing_internals::BI_GA_MS_TAB_33R;
34
35using hashing_internals::BI_CT_MS_TAB_31L;
36using hashing_internals::BI_GA_MS_TAB_31L;
37
38using hashing_internals::BI_CT_CONVERT_TAB;
39using hashing_internals::BI_GA_CONVERT_TAB;
40
41using hashing_internals::BI_CT_RC_CONVERT_TAB;
42using hashing_internals::BI_GA_RC_CONVERT_TAB;
43
44using hashing_internals::BI_CT_DIMER_TAB;
45using hashing_internals::BI_CT_TETRAMER_TAB;
46using hashing_internals::BI_CT_TRIMER_TAB;
47using hashing_internals::BI_GA_DIMER_TAB;
48using hashing_internals::BI_GA_TETRAMER_TAB;
49using hashing_internals::BI_GA_TRIMER_TAB;
50
55{
56
57public:
68 BiHashDirectional(const char* seq,
69 size_t seq_len,
70 hashing_internals::NUM_HASHES_TYPE num_hashes,
71 hashing_internals::K_TYPE k,
72 std::string conversion_type,
73 size_t pos = 0)
74 : seq(seq)
75 , seq_len(seq_len)
76 , num_hashes(num_hashes)
77 , k(k)
78 , conversion_type(conversion_type)
79 , pos(pos)
80 , initialized(false)
81 , hash_arr(new uint64_t[num_hashes])
82 {
83 check_error(k == 0, "BiHash: k must be greater than 0");
84 check_error(k % 2 == 1, "BiHash: k must be even");
85 check_error((k / 2) % 2 == 0, "BiHash: k must have odd number of dimers");
86 check_error(this->seq_len < k,
87 "BiHash: sequence length (" + std::to_string(this->seq_len) +
88 ") is smaller than k (" + std::to_string(k) + ")");
89 check_error(pos > this->seq_len - k,
90 "BiHash: passed position (" + std::to_string(pos) +
91 ") is larger than sequence length (" +
92 std::to_string(this->seq_len) + ")");
93
94 size_t num_dimers = k / 2;
95 size_t center_dimer_start = (num_dimers / 2) * 2;
96 if (conversion_type == "CT") {
97 meth_base_idx = center_dimer_start;
98
99 primitive_tab = BI_CT_SEED_TAB;
100
101 right_table = BI_CT_MS_TAB_33R;
102 left_table = BI_CT_MS_TAB_31L;
103
104 convert_tab = BI_CT_CONVERT_TAB;
105 rc_convert_tab = BI_CT_RC_CONVERT_TAB;
106
107 dimer_tab = BI_CT_DIMER_TAB;
108 rc_dimer_tab = BI_GA_DIMER_TAB;
109 trimer_tab = BI_CT_TRIMER_TAB;
110 rc_trimer_tab = BI_GA_TRIMER_TAB;
111 tetramer_tab = BI_CT_TETRAMER_TAB;
112 ;
113 rc_tetramer_tab = BI_GA_TETRAMER_TAB;
114 } else if (conversion_type == "GA") {
115 meth_base_idx = center_dimer_start + 1;
116
117 primitive_tab = BI_GA_SEED_TAB;
118
119 right_table = BI_GA_MS_TAB_33R;
120 left_table = BI_GA_MS_TAB_31L;
121
122 convert_tab = BI_GA_CONVERT_TAB;
123 rc_convert_tab = BI_GA_RC_CONVERT_TAB;
124
125 dimer_tab = BI_GA_DIMER_TAB;
126 rc_dimer_tab = BI_CT_DIMER_TAB;
127 trimer_tab = BI_GA_TRIMER_TAB;
128 rc_trimer_tab = BI_CT_TRIMER_TAB;
129 tetramer_tab = BI_GA_TETRAMER_TAB;
130 rc_tetramer_tab = BI_CT_TETRAMER_TAB;
131 } else {
133 true, "Unsupported conversion_type. Must be CT or GA, as capitalized.");
134 }
135 }
136
146 BiHashDirectional(const std::string& seq,
147 hashing_internals::NUM_HASHES_TYPE num_hashes,
148 hashing_internals::K_TYPE k,
149 std::string conversion_type,
150 size_t pos = 0)
151 : BiHashDirectional(seq.data(),
152 seq.size(),
153 num_hashes,
154 k,
155 conversion_type,
156 pos)
157 {
158 }
159
161 : seq(obj.seq)
162 , seq_len(obj.seq_len)
163 , num_hashes(obj.num_hashes)
164 , k(obj.k)
165 , conversion_type(obj.conversion_type)
166 , pos(obj.pos)
167 , initialized(obj.initialized)
168 , fwd_hash(obj.fwd_hash)
169 , rev_hash(obj.rev_hash)
170 , hash_arr(new uint64_t[obj.num_hashes])
171 , primitive_tab(obj.primitive_tab)
172 , right_table(obj.right_table)
173 , left_table(obj.left_table)
174 , convert_tab(obj.convert_tab)
175 , rc_convert_tab(obj.rc_convert_tab)
176 , dimer_tab(obj.dimer_tab)
177 , rc_dimer_tab(obj.rc_dimer_tab)
178 , trimer_tab(obj.trimer_tab)
179 , rc_trimer_tab(obj.rc_trimer_tab)
180 , tetramer_tab(obj.tetramer_tab)
181 , rc_tetramer_tab(obj.rc_tetramer_tab)
182 {
183 std::memcpy(
184 hash_arr.get(), obj.hash_arr.get(), num_hashes * sizeof(uint64_t));
185 }
186
200 bool roll()
201 {
202 if (!initialized) {
203 return init();
204 }
205 if (pos >= seq_len - k) {
206 return false;
207 }
208 if (hashing_internals::SEED_TAB[(unsigned char)seq[pos + k]] ==
209 hashing_internals::SEED_N) {
210 pos += k;
211 return init();
212 }
213 fwd_hash = next_forward_hash(fwd_hash,
214 k,
215 seq[pos],
216 seq[pos + k],
217 primitive_tab,
218 right_table,
219 left_table);
220 rev_hash = next_reverse_hash(rev_hash,
221 k,
222 seq[pos],
223 seq[pos + k],
224 primitive_tab,
225 right_table,
226 left_table);
227 extend_hashes(fwd_hash, rev_hash, k, num_hashes, hash_arr.get());
228 ++pos;
229 return true;
230 }
231
237 {
238 if (!initialized) {
239 return init();
240 }
241 if (pos == 0) {
242 return false;
243 }
244 if (SEED_TAB[(unsigned char)seq[pos - 1]] == SEED_N && pos >= k) {
245 pos -= k;
246 return init();
247 }
248 if (SEED_TAB[(unsigned char)seq[pos - 1]] == SEED_N) {
249 return false;
250 }
251 fwd_hash = prev_forward_hash(fwd_hash,
252 k,
253 seq[pos + k - 1],
254 seq[pos - 1],
255 primitive_tab,
256 right_table,
257 left_table);
258 rev_hash = prev_reverse_hash(rev_hash,
259 k,
260 seq[pos + k - 1],
261 seq[pos - 1],
262 primitive_tab,
263 right_table,
264 left_table);
265 extend_hashes(fwd_hash, rev_hash, k, num_hashes, hash_arr.get());
266 --pos;
267 return true;
268 }
269
276 bool peek()
277 {
278 if (pos >= seq_len - k) {
279 return false;
280 }
281 return peek(seq[pos + k]);
282 }
283
289 {
290 if (pos == 0) {
291 return false;
292 }
293 return peek_back(seq[pos - 1]);
294 }
295
302 bool peek(char char_in)
303 {
304 if (!initialized) {
305 return init();
306 }
307 if (SEED_TAB[(unsigned char)char_in] == SEED_N) {
308 return false;
309 }
310 const uint64_t fwd = next_forward_hash(
311 fwd_hash, k, seq[pos], char_in, primitive_tab, right_table, left_table);
312 const uint64_t rev = next_reverse_hash(
313 rev_hash, k, seq[pos], char_in, primitive_tab, right_table, left_table);
314 extend_hashes(fwd, rev, k, num_hashes, hash_arr.get());
315 return true;
316 }
317
322 bool peek_back(char char_in)
323 {
324 if (!initialized) {
325 return init();
326 }
327 if (SEED_TAB[(unsigned char)char_in] == SEED_N) {
328 return false;
329 }
330 const unsigned char char_out = seq[pos + k - 1];
331 const uint64_t fwd = prev_forward_hash(
332 fwd_hash, k, char_out, char_in, primitive_tab, right_table, left_table);
333 const uint64_t rev = prev_reverse_hash(
334 rev_hash, k, char_out, char_in, primitive_tab, right_table, left_table);
335 extend_hashes(fwd, rev, k, num_hashes, hash_arr.get());
336 return true;
337 }
338
349 {
350 char base = seq[pos + meth_base_idx];
351
352 if (conversion_type == "CT")
353 return base == 'C' || base == 'c';
354 else
355 return base == 'G' || base == 'g';
356 }
357
362 bool is_forward_higher() const { return fwd_hash > rev_hash; }
363
364 void sub(const std::vector<unsigned>& positions,
365 const std::vector<unsigned char>& new_bases)
366 {
367 sub_hash(fwd_hash,
368 rev_hash,
369 seq + pos,
370 positions,
371 new_bases,
372 get_k(),
373 get_hash_num(),
374 hash_arr.get(),
375 right_table,
376 left_table);
377 }
378
383 const uint64_t* hashes() const { return hash_arr.get(); }
384
390 size_t get_pos() const { return pos; }
391
396 hashing_internals::NUM_HASHES_TYPE get_hash_num() const { return num_hashes; }
397
402 hashing_internals::K_TYPE get_k() const { return k; }
403
408 uint64_t get_forward_hash() const { return fwd_hash; }
409
414 uint64_t get_reverse_hash() const { return rev_hash; }
415
416private:
417 const char* seq;
418 const size_t seq_len;
419 hashing_internals::NUM_HASHES_TYPE num_hashes;
420 hashing_internals::K_TYPE k;
421 std::string conversion_type;
422 size_t pos;
423 size_t meth_base_idx;
424 bool initialized;
425 uint64_t fwd_hash = 0;
426 uint64_t rev_hash = 0;
427 std::unique_ptr<uint64_t[]> hash_arr;
428
429 const uint64_t* primitive_tab;
430
431 const uint64_t* const* right_table;
432 const uint64_t* const* left_table;
433
434 const uint8_t* convert_tab;
435 const uint8_t* rc_convert_tab;
436
437 const uint64_t* dimer_tab;
438 const uint64_t* rc_dimer_tab;
439 const uint64_t* trimer_tab;
440 const uint64_t* rc_trimer_tab;
441 const uint64_t* tetramer_tab;
442 const uint64_t* rc_tetramer_tab;
443
448 bool init()
449 {
450 bool has_n = true;
451 while (pos <= seq_len - k + 1 && has_n) {
452 has_n = false;
453 for (unsigned i = 0; i < k && pos <= seq_len - k + 1; i++) {
454 if (SEED_TAB[(unsigned char)seq[pos + k - i - 1]] == SEED_N) {
455 pos += k - i;
456 has_n = true;
457 }
458 }
459 }
460 if (pos > seq_len - k) {
461 return false;
462 }
463 fwd_hash = base_forward_hash(seq + pos,
464 k,
465 primitive_tab,
466 dimer_tab,
467 trimer_tab,
468 tetramer_tab,
469 convert_tab);
470 rev_hash = base_reverse_hash(seq + pos,
471 k,
472 primitive_tab,
473 rc_dimer_tab,
474 rc_trimer_tab,
475 rc_tetramer_tab,
476 rc_convert_tab);
477 extend_hashes(fwd_hash, rev_hash, k, num_hashes, hash_arr.get());
478 initialized = true;
479 return true;
480 }
481};
482
483} // namespace btllib
Definition bihash_kmer_directional.hpp:55
BiHashDirectional(const std::string &seq, hashing_internals::NUM_HASHES_TYPE num_hashes, hashing_internals::K_TYPE k, std::string conversion_type, size_t pos=0)
Definition bihash_kmer_directional.hpp:146
bool peek()
Definition bihash_kmer_directional.hpp:276
uint64_t get_forward_hash() const
Definition bihash_kmer_directional.hpp:408
bool peek_back()
Definition bihash_kmer_directional.hpp:288
hashing_internals::NUM_HASHES_TYPE get_hash_num() const
Definition bihash_kmer_directional.hpp:396
size_t get_pos() const
Definition bihash_kmer_directional.hpp:390
hashing_internals::K_TYPE get_k() const
Definition bihash_kmer_directional.hpp:402
bool peek_back(char char_in)
Definition bihash_kmer_directional.hpp:322
bool roll()
Definition bihash_kmer_directional.hpp:200
bool peek(char char_in)
Definition bihash_kmer_directional.hpp:302
bool is_methylated()
Definition bihash_kmer_directional.hpp:348
BiHashDirectional(const char *seq, size_t seq_len, hashing_internals::NUM_HASHES_TYPE num_hashes, hashing_internals::K_TYPE k, std::string conversion_type, size_t pos=0)
Definition bihash_kmer_directional.hpp:68
bool is_forward_higher() const
Definition bihash_kmer_directional.hpp:362
const uint64_t * hashes() const
Definition bihash_kmer_directional.hpp:383
uint64_t get_reverse_hash() const
Definition bihash_kmer_directional.hpp:414
bool roll_back()
Definition bihash_kmer_directional.hpp:236
Definition aahash.hpp:12
void check_error(bool condition, const std::string &msg)