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>
24 
25 // TODO: return current position as well as minimum
26 // templated?
27 template<class HF>
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>
280 
281 template<class HF>
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 
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>
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 
510  operator++();
511 
512  return tmp;
513  }
514 
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 
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
Definition: minHashIterator.hpp:13
Definition: minHashIterator.hpp:28
Definition: minHashIterator.hpp:282
Definition: Kmer.hpp:114
Definition: minHashIterator.hpp:23
Definition: minHashIterator.hpp:279
Definition: minHashIterator.hpp:551