BFGraph: src/minHashIterator.hpp Source File

BFGraph

minHashIterator.hpp
1 #ifndef MINHASHITERATOR_H
2 #define MINHASHITERATOR_H
3
4 #include <stdint.h>
5 #include <deque>
6 #include <vector>
7
8 #include <iostream>
9 using namespace std;
10
11 //using std::vector;
12
13 struct minHashResult {
14
15 minHashResult() : hash((uint64_t) -1),pos(-1) {}
16 minHashResult(const uint64_t h, const int p) : hash(h), pos(p) {}
17 minHashResult(const minHashResult& o) : hash(o.hash), pos(o.pos) {}
18 uint64_t hash;
19 int pos;
20 };
21
22 template<class HF>
23 struct minHashResultIterator;
24
25 // TODO: return current position as well as minimum
26 // templated?
27 template<class HF>
28 class minHashIterator {
29
30 public:
31
32 minHashIterator(int _k, int _g, HF _h) : s(NULL), n(0), k(_k), g(_g), hf(_h), v(k-g+1), p(-1), invalid(true), nh(false) {
33 hf.setK(g);
34 }
35
36 minHashIterator(const char* _s, int _length, int _k, int _g, HF _h, bool _nh) : k(_k), g(_g), hf(_h), v(k-g+1), p(-1), invalid(true), nh(_nh) {
37 hf.setK(g);
38 initString(_s,_length);
39 }
40
41 minHashIterator() : s(NULL), n(0), k(0), g(0), hf(HF(0)), invalid(true), nh(false) {}
42
43 void seed(HF &ohf) {
44 hf = ohf;
45 invalid=true;
46 }
47
48 void initString(const char* _s, int _length) {
49
50 n = _length;
51 s = _s;
52 p = -1;// reset position
53 invalid = false;
54 v.clear();
55
56 // advance to first position or set to invalid
57 if (n < k || k < g) invalid = true;
58 else operator++();
59 }
60
61
62 bool operator==(const minHashIterator& o) {
63
64 if (invalid || o.invalid) return invalid && o.invalid;
65 return s==o.s && n==o.n && g==o.g && k==o.k && nh==o.nh;
66 }
67
68 bool operator!=(const minHashIterator& o) { return !this->operator==(o); }
69
70 // invariant:
71 // v[0..sz] contains only ascending elements in s from [p,p+k-g+1)
72 //
73 // there exists no a<b s.t. v[a] > v[b].
74 minHashIterator& operator++() {
75
76 if (invalid) return *this;
77
78 ++p; // advance to next k-mer
79
80 if (p >= n-k+1 || s[p+k-1] == 0) {
81 // out of bounds
82 invalid = true;
83 return *this;
84 }
85
86 const int shift = nh ? 1 : 0;
87
88 if (p==0) {
89
90 hf.init(&s[shift]);
91
92 v.push_back(minHashResult(hf.hash(), shift));
93
94 for (int j = shift; j < k-g-shift;) {
95
96 hf.update(s[j],s[j+g]);
97
98 uint64_t h = hf.hash();
99 int t = ((int)v.size())-1;
100
101 while (t >= 0 && v[t].hash > h) {
102
103 v.pop_back();
104 t--;
105 }
106
107 j++;
108 v.push_back(minHashResult(h,j));
109 }
110 }
111 else {
112
113 if (v[0].pos < p + shift) v.pop_front(); // remove first element, fell outside of window
114
115 hf.update(s[p+k-g-1-shift],s[p+k-1-shift]);
116
117 uint64_t h = hf.hash();
118 int t = ((int) v.size())-1;
119
120 while (t >= 0 && v[t].hash > h) {
121
122 v.pop_back();
123 t--;
124 }
125
126 v.push_back(minHashResult(h,p+k-g-shift));
127 }
128
129 return *this;
130 }
131
132 minHashIterator operator++(int) {
133
134 minHashIterator tmp(*this);
135 operator++();
136
137 return tmp;
138 }
139
140 minHashIterator& operator+=(int i) {
141
142 for (; i > 0; i--) operator++();
143 return *this;
144 }
145
146 minHashResult getNewMin(const minHashResult& mhr_discard) const {
147
148 if (invalid) return minHashResult();
149
150 const int shift = nh ? 1 : 0;
151 const int end = p+k-g-shift;
152
153 int j = p + shift;
154
155 uint64_t h;
156
157 HF hf_tmp;
158
159 hf_tmp.setK(g);
160 hf_tmp.init(&s[j]);
161
162 while ((hf_tmp.hash() <= mhr_discard.hash) && (j < end)){
163
164 hf_tmp.update(s[j],s[j+g]);
165 j++;
166 }
167
168 if ((j == end) && (hf_tmp.hash() <= mhr_discard.hash)) return /*v[0]*/mhr_discard; //No other minimizer can be found
169
170 minHashResult mhr = minHashResult(hf_tmp.hash(), j);
171
172 while (j < end) {
173
174 hf_tmp.update(s[j],s[j+g]);
175 j++;
176
177 h = hf_tmp.hash();
178
179 if ((h <= mhr.hash) && (h > mhr_discard.hash)){
180
181 if (h == mhr.hash){ // break ties if two minimizers have same hash
182
183 if (Minimizer(&s[j]).rep() < Minimizer(&s[mhr.pos]).rep()){
184
185 mhr.hash = hf_tmp.hash();
186 mhr.pos = j;
187 }
188 }
189 else {
190
191 mhr.hash = hf_tmp.hash();
192 mhr.pos = j;
193 }
194 }
195 }
196
197 return mhr;
198 }
199
200 minHashResultIterator<HF> operator*() const {return minHashResultIterator<HF>(this);}
201
202 inline uint64_t getHash() const { return invalid ? 0 : v[0].hash; }
203
204 inline int getPosition() const { return invalid ? 0 : v[0].pos; }
205
206 inline int getKmerPosition() const { return p; }
207
208 const char *s; //Minimizers are from k-mers, k-mers are from a sequence s
209 int n; // Length of sequence s
210 int k; // Length of k-mers
211 int g; // Length of minimizers
212 HF hf; // Rolling hash function
213 deque<minHashResult> v; //Hash values and positions of a same minimizer with k-mer at position p
214 int p; // Position of current k-mer traversed in the sequence
215 bool invalid; // If sequence is invalid (iterating on k-mers out of bounds, etc.)
216 bool nh; // If true, minimizer of k-mers km cannot start at position 0 or k-g
217
218 // private copy constructor
219 minHashIterator(const minHashIterator& o) : s(o.s), n(o.n), k(o.k), g(o.g), hf(o.hf), v(o.v), p(o.p), invalid(o.invalid), nh(o.nh) {}
220 };
221
222 template <class HF>
223 struct minHashResultIterator {
224
225 minHashResultIterator(const minHashIterator<HF> *p) : p(p), invalid(false), pos(0), p_pos(p->p), p_s(p->s) {}
226 minHashResultIterator() : invalid(true), p_pos(-1), p_s(NULL) {}
227
228 bool operator==(const minHashResultIterator& o) {
229
230 if (o.invalid || invalid) return o.invalid && invalid;
231 return p_pos == o.p_pos && p_s == o.p_s && pos==o.pos;
232
233 }
234
235 bool operator!=(const minHashResultIterator& o) {
236 return !this->operator==(o);
237 }
238
239 minHashResultIterator& operator++() {
240
241 if (invalid) return *this;
242
243 if ((p_pos != p->p || p_s != p->s) // check if parent iterator has moved
244 || (pos>=p->v.size()-1) // or if we advance past the end
245 || (p->v[pos+1].hash != p->v[pos].hash)) { // or if the next position doesn't share the hash value
246 // invalidate the iterator
247 invalid = true;
248 return *this;
249 }
250 else pos++; // advance to next equal hash value
251
252 return *this;
253 }
254
255
256 minHashResultIterator operator++(int) {
257
258 minHashResultIterator tmp(*this);
259 operator++();
260
261 return tmp;
262 }
263
264 const minHashResult& operator*() const { return p->v[pos]; }
265 const minHashResult* operator->() const { return &(p->v[pos]); }
266
267 // pos points to a minHashIterator, all the values from p.v[0] to p.v[pos] have the
268 // same (minimum) hash value or the this.invalid is true
269 // at the time this was created p.s==p_s and p.p=p_pos
270 const minHashIterator<HF> *p;
271 bool invalid;
272 int pos;
273 const int p_pos;
274 const char *p_s;
275 };
276
277
278 template<class HF>
279 struct preAllocMinHashResultIterator;
280
281 template<class HF>
282 class preAllocMinHashIterator {
283
284 public:
285
286 preAllocMinHashIterator() : s(NULL), n(0), k(0), g(0), hf(HF(0)), p(-1), v(0), p_cur_start(0), p_cur_end(0), invalid(true), nh(false) {}
287
288 preAllocMinHashIterator(const char* _s, int _n, int _k, int _g, HF _h, bool _nh) :
289 s(_s), n(_n), k(_k), g(_g), hf(_h), p(-1), p_cur_start(0), p_cur_end(0), invalid(true), nh(_nh) {
290
291 if ((s != NULL) && (n >= k) && (k >= g)){
292
293 invalid = false;
294
295 v = vector<minHashResult>(n-g+1);
296
297 hf.setK(g);
298 operator++();
299 }
300 }
301
302 bool operator==(const preAllocMinHashIterator& o) {
303
304 if (invalid || o.invalid) return invalid && o.invalid;
305 return s==o.s && n==o.n && g==o.g && k==o.k && nh==o.nh;
306 }
307
308 bool operator!=(const preAllocMinHashIterator& o) { return !this->operator==(o); }
309
310 // invariant:
311 // v[0..sz] contains only ascending elements in s from [p,p+k-g+1)
312 //
313 // there exists no a<b s.t. v[a] > v[b].
314 preAllocMinHashIterator& operator++() {
315 //cerr << "operator++";
316 if (invalid) return *this;
317
318 ++p; // advance to next k-mer
319
320 if (p >= n-k+1 || s[p+k-1] == 0) {
321 // out of bounds
322 invalid = true;
323 return *this;
324 }
325
326 const int shift = nh ? 1 : 0;
327
328 if (p == 0) {
329
330 hf.init(&s[shift]);
331
332 v[p_cur_end] = minHashResult(hf.hash(), shift);
333 p_cur_end++;
334
335 for (int j = shift; j < k-g-shift;) {
336
337 hf.update(s[j], s[j+g]);
338
339 uint64_t h = hf.hash();
340
341 while (p_cur_end > p_cur_start && v[p_cur_end-1].hash > h) p_cur_end--;
342
343 j++;
344
345 v[p_cur_end] = minHashResult(h,j);
346 p_cur_end++;
347 }
348 }
349 else {
350
351 if (v[p_cur_start].pos < p + shift) p_cur_start++; // remove first element, fell outside of window
352
353 hf.update(s[p+k-g-1-shift], s[p+k-1-shift]);
354
355 uint64_t h = hf.hash();
356
357 while (p_cur_end > p_cur_start && v[p_cur_end-1].hash > h) p_cur_end--;
358
359 v[p_cur_end] = minHashResult(h,p+k-g-shift);
360 p_cur_end++;
361 }
362
363 return *this;
364 }
365
366 preAllocMinHashIterator operator++(int) {
367
368 preAllocMinHashIterator tmp(*this);
369 operator++();
370
371 return tmp;
372 }
373
374 preAllocMinHashIterator& operator+=(int i) {
375
376 for (; i > 0; i--) operator++();
377 return *this;
378 }
379
380 preAllocMinHashResultIterator<HF> operator*() const {return preAllocMinHashResultIterator<HF>(*this);}
381
382 inline uint64_t getHash() const { return invalid ? 0 : v[p_cur_start].hash; }
383
384 inline int getPosition() const { return invalid ? 0 : v[p_cur_start].pos; }
385
386 inline int getNbMin() const { return p_cur_end - p_cur_start; }
387
388 inline int getKmerPosition() const { return p; }
389
390 minHashResult getNewMin(const minHashResult& mhr_discard) const {
391
392 if (invalid) return minHashResult();
393
394 const int shift = nh ? 1 : 0;
395 const int end = p+k-g-shift;
396
397 int j = p + shift;
398
399 uint64_t h;
400
401 HF hf_tmp;
402
403 hf_tmp.setK(g);
404 hf_tmp.init(&s[j]);
405
406 while ((hf_tmp.hash() <= mhr_discard.hash) && (j < end)){
407
408 hf_tmp.update(s[j],s[j+g]);
409 j++;
410 }
411
412 if ((j == end) && (hf_tmp.hash() <= mhr_discard.hash)) return /*v[p_cur_start]*/ mhr_discard;
413
414 minHashResult mhr = minHashResult(hf_tmp.hash(), j);
415
416 while (j < end) {
417
418 hf_tmp.update(s[j],s[j+g]);
419 j++;
420
421 h = hf_tmp.hash();
422
423 if ((h <= mhr.hash) && (h > mhr_discard.hash)){
424
425 if (h == mhr.hash){ // break ties if two minimizers have same hash
426
427 if (Minimizer(&s[j]).rep() < Minimizer(&s[mhr.pos]).rep()){
428
429 mhr.hash = hf_tmp.hash();
430 mhr.pos = j;
431 }
432 }
433 else {
434
435 mhr.hash = hf_tmp.hash();
436 mhr.pos = j;
437 }
438 }
439 }
440
441 if (mhr.hash <= mhr_discard.hash) cerr << "Problem here" << endl;
442
443 return mhr;
444 }
445
446 const char *s; //Minimizers are from k-mers, k-mers are from a sequence s
447 int n; // Length of sequence s
448 int k; // Length of k-mers
449 int g; // Length of minimizers
450 HF hf; // Rolling hash function
451 vector<minHashResult> v; //Hash values and positions of a same minimizer with k-mer at position p
452 size_t p_cur_start;
453 size_t p_cur_end;
454 int p; // Position of current k-mer traversed in the sequence
455 bool invalid; // If sequence is invalid (iterating on k-mers out of bounds, etc.)
456 bool nh;
457
458 // private copy constructor
459 preAllocMinHashIterator(const preAllocMinHashIterator& o) : s(o.s), n(o.n), k(o.k), g(o.g), hf(o.hf), v(o.v), p(o.p),
460 p_cur_start(o.p_cur_start), p_cur_end(o.p_cur_end), invalid(o.invalid), nh(o.nh) {}
461
462 preAllocMinHashIterator(const preAllocMinHashIterator& o, int len) : s(o.s + o.p), n(len), k(o.k), g(o.g), hf(o.hf), p(0), p_cur_start(0),
463 p_cur_end(o.p_cur_end - o.p_cur_start), invalid(o.invalid), nh(o.nh) {
464
465 if (!invalid && (o.p + n <= o.n)){
466
467 v = std::vector<minHashResult>(o.v.begin() + o.p_cur_start, o.v.begin() + o.p_cur_end);
468
469 for (auto& min_h : v) min_h.pos -= o.p;
470 }
471 else invalid = true;
472 }
473 };
474
475 template <class HF>
476 struct preAllocMinHashResultIterator {
477
478 preAllocMinHashResultIterator(const preAllocMinHashIterator<HF>& _p) : p(&_p), p_pos(_p.p), p_it(_p.p_cur_start), p_it_end(_p.p_cur_end), p_s(_p.s), invalid(false) {}
479 preAllocMinHashResultIterator() : invalid(true), p(NULL), p_pos(-1), p_s(NULL), p_it(0), p_it_end(0) {}
480
481 bool operator==(const preAllocMinHashResultIterator& o) const {
482
483 if (o.invalid || invalid) return o.invalid && invalid;
484 return p_pos == o.p_pos && p_s == o.p_s && p_it==o.p_it && p_it_end==o.p_it_end;
485 }
486
487 bool operator!=(const preAllocMinHashResultIterator& o) const {
488 return !this->operator==(o);
489 }
490
491 preAllocMinHashResultIterator& operator++() {
492
493 if (invalid) return *this;
494
495 if ((p_s != p->s || p_pos != p->p || p_it_end != p->p_cur_end) // check if parent iterator has moved
496 || (p_it >= p_it_end - 1) // or if we advance past the end
497 || (p->v[p_it + 1].hash != p->v[p_it].hash)) { // or if the next position doesn't share the hash value
498 // invalidate the iterator
499 invalid = true;
500 return *this;
501 }
502 else p_it++; // advance to next equal hash value
503
504 return *this;
505 }
506
507 preAllocMinHashResultIterator operator++(int) {
508
509 preAllocMinHashResultIterator tmp(*this);
510 operator++();
511
512 return tmp;
513 }
514
515 preAllocMinHashResultIterator& operator=(const preAllocMinHashResultIterator &o){
516
517 p_it = o.p_it;
518 p_it_end = o.p_it_end;
519 invalid = o.invalid;
520
521 if (operator!=(o)) invalid = true;
522
523 return *this;
524 }
525
526 const minHashResult& operator*() const { return p->v[p_it]; }
527 const minHashResult* operator->() const { return &(p->v[p_it]); }
528
529 // pos points to a minHashIterator, all the values from p.v[0] to p.v[pos] have the
530 // same (minimum) hash value or the this.invalid is true
531 // at the time this was created p.s==p_s and p.p=p_pos
532
533 const preAllocMinHashIterator<HF>* p;
534 bool invalid;
535 size_t p_it;
536 size_t p_it_end;
537 const int p_pos;
538 const char *p_s;
539 };
540
541
542
543
544
545
546
547
548
549
550 template <class HF>
551 struct minHashKmer {
552
553 public:
554
555 minHashKmer(const char* _s, int _k, int _g, HF _h, bool neighbor_hash) : s(_s), k(_k), g(_g), hf(_h), h(0), p(-1), invalid(true), nh(neighbor_hash) {
556
557 if ((s != NULL) && ((n = strlen(s)) >= k) && (k >= g)){
558
559 invalid = false;
560
561 hf.setK(g);
562 compute_min();
563 }
564 }
565
566 minHashKmer() : s(NULL), n(0), k(0), g(0), hf(HF(0)), h(0), p(-1), nb(0), invalid(true), nh(false) {}
567
568 minHashKmer(const preAllocMinHashIterator<HF>& o) : s(o.s), k(o.k), g(o.g), hf(o.hf), nh(o.nh), h(0), p(-1), nb(o.nb), invalid(o.invalid){
569
570 if (!invalid){
571
572 h = o.v[o.p_cur_start].hash;
573 p = o.v[o.p_cur_start].pos - o.p;
574 }
575 }
576
577 bool operator==(const minHashKmer& o) {
578
579 if(invalid || o.invalid) return invalid && o.invalid;
580 return s==o.s && n==o.n && g==o.g && k==o.k && nh==o.nh && h==o.h && p==o.p && nb==o.nb;
581 }
582
583 bool operator!=(const minHashKmer& o) { return !this->operator==(o); }
584
585 uint64_t getHash() const { return h; }
586
587 int getPosition() const { return p; }
588
589 int getNbMin() const { return nb; }
590
591 private:
592
593 void compute_min(){
594
595 if (invalid) return;
596
597 const int shift = nh ? 1 : 0;
598
599 hf.init(&s[shift]);
600
601 h = hf.hash();
602 p = shift;
603 nb = 1;
604
605 for (int j = shift; j < k-g-shift; j++) {
606
607 hf.update(s[j], s[j+g]);
608
609 if (hf.hash() <= h){
610
611 if (hf.hash() == h) nb++;
612 else {
613
614 h = hf.hash();
615 p = j + 1;
616 nb = 1;
617 }
618 }
619 }
620 }
621
622 const char* s;
623 HF hf;
624 uint64_t h;
625 int n;
626 int k;
627 int g;
628 int p;
629 int nb;
630 bool invalid;
631 bool nh;
632 };
633
634 #endif // MINHASHITERATOR_H
minHashResult
Definition: minHashIterator.hpp:13
std
minHashIterator
Definition: minHashIterator.hpp:28
preAllocMinHashIterator
Definition: minHashIterator.hpp:282
Minimizer
Definition: Kmer.hpp:114
minHashResultIterator
Definition: minHashIterator.hpp:23
preAllocMinHashResultIterator
Definition: minHashIterator.hpp:279
minHashKmer
Definition: minHashIterator.hpp:551