-
Notifications
You must be signed in to change notification settings - Fork 77
/
range_chaser.h
270 lines (251 loc) · 6.76 KB
/
range_chaser.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
/*
* range_chaser.h
*/
#ifndef RANGE_CHASER_H_
#define RANGE_CHASER_H_
#include <stdint.h>
#include "aligner_metrics.h"
#include "ds.h"
#include "ebwt.h"
#include "random_source.h"
#include "range_cache.h"
#include "row_chaser.h"
/**
* A class that statefully processes a range by picking one row
* randomly and then linearly scanning forward through the range,
* reporting reference offsets as we go.
*/
class RangeChaser {
typedef std::pair<TIndexOffU,TIndexOffU> UPair;
typedef EList<UPair> UPairVec;
public:
RangeChaser(uint32_t cacheThresh,
RangeCache* cacheFw, RangeCache* cacheBw,
AlignerMetrics *metrics = NULL) :
done(false),
ebwt_(NULL),
qlen_(0),
cacheThresh_(cacheThresh),
top_(OFF_MASK),
bot_(OFF_MASK),
irow_(OFF_MASK),
row_(OFF_MASK),
off_(make_pair(OFF_MASK, 0)),
tlen_(0),
chaser_(metrics),
cached_(false),
cacheFw_(cacheFw), cacheBw_(cacheBw),
metrics_(metrics)
{ }
~RangeChaser() { }
/**
* Set the row to chase
*/
void setRow(TIndexOffU row) {
// Must be within bounds of range
assert_lt(row, bot_);
assert_geq(row, top_);
row_ = row;
while(true) {
// First thing to try is the cache
if(cached_) {
assert(cacheEnt_.valid());
TIndexOffU cached = cacheEnt_.get(row_ - top_);
assert(cacheEnt_.valid());
if(cached != RANGE_NOT_SET) {
// Assert that it matches what we would have got...
ASSERT_ONLY(uint32_t sanity = RowChaser::toFlatRefOff(ebwt_, 1, row_));
assert_eq(sanity, cached);
// We have a cached result. Cached result is in the
// form of an offset into the joined reference string,
// so now we have to convert it to a tidx/toff pair.
ebwt_->joinedToTextOff(qlen_, cached, off_.first, off_.second, tlen_);
// Note: tidx may be 0xffffffff, if alignment overlaps a
// reference boundary
if(off_.first != OFF_MASK) {
// Bingo, we found a valid result using the cache
assert(foundOff());
return;
}
} else {
// Wasn't in the cache; use the RowChaser
}
}
// Second thing to try is the chaser
chaser_.setRow(row_, qlen_, ebwt_);
assert(chaser_.prepped_ || chaser_.done);
// It might be done immediately...
if(chaser_.done) {
// We're done immediately
off_ = chaser_.off();
if(off_.first != OFF_MASK) {
// This is a valid result
if(cached_) {
// Install the result in the cache
assert(cacheEnt_.valid());
cacheEnt_.install(row_ - top_, chaser_.flatOff());
//if(ebwt_->fw()) assert(cacheFw_->repOk());
//else assert(cacheBw_->repOk());
}
tlen_ = chaser_.tlen();
assert(foundOff());
return; // found result
}
} else {
// Pursue this row
break;
}
// That row didn't have a valid result, move to the next
row_++;
if(row_ == bot_) {
// Wrap back to top_
row_ = top_;
}
if(row_ == irow_) {
// Exhausted all possible rows
done = true;
assert_eq(OFF_MASK, off_.first);
return;
}
}
assert(chaser_.prepped_);
}
/**
* Set the next range for us to "chase" (i.e. convert row-by-row
* to reference loci).
*/
void setTopBot(TIndexOffU top,
TIndexOffU bot,
TIndexOffU qlen,
RandomSource& rand,
const Ebwt* ebwt)
{
assert_neq(OFF_MASK, top);
assert_neq(OFF_MASK, bot);
assert_gt(bot, top);
assert_gt(qlen, 0);
assert(ebwt != NULL);
ebwt_ = ebwt;
qlen_ = qlen;
top_ = top;
bot_ = bot;
TIndexOffU spread = bot - top;
irow_ = top + (rand.nextU32() % spread); // initial row
done = false;
cached_ = false;
reset();
if(cacheFw_ != NULL || cacheBw_ != NULL) {
if(spread > cacheThresh_) {
bool ret = false;
if(ebwt->fw() && cacheFw_ != NULL) {
ret = cacheFw_->lookup(top, bot, cacheEnt_);
if(ret) assert(cacheEnt_.ebwt()->fw());
} else if(!ebwt->fw() && cacheBw_ != NULL) {
ret = cacheBw_->lookup(top, bot, cacheEnt_);
if(ret) assert(!cacheEnt_.ebwt()->fw());
} else {
cacheEnt_.reset();
}
assert_eq(cacheEnt_.valid(), ret);
cached_ = ret;
} else {
cacheEnt_.reset();
}
}
setRow(irow_);
assert(chaser_.prepped_ || foundOff() || done);
}
/**
* Advance the step-left process by one step. Check if we're done.
*/
void advance() {
assert(!done);
assert(chaser_.prepped_ || chaser_.done);
reset();
if(chaser_.done) {
// chaser finished with this row
row_++;
if(row_ == bot_) {
row_ = top_;
}
if(row_ == irow_) {
// Exhausted all possible rows
done = true;
assert_eq(OFF_MASK, off_.first);
return;
}
setRow(row_);
assert(chaser_.prepped_ || foundOff() || done);
} else {
chaser_.advance();
assert(chaser_.prepped_ || chaser_.done);
if(chaser_.done) {
// We're done immediately
off_ = chaser_.off();
if(off_.first != OFF_MASK) {
if(cached_) {
// Install the result in the cache
assert(cacheEnt_.valid());
cacheEnt_.install(row_ - top_, chaser_.flatOff());
//if(ebwt_->fw()) assert(cacheFw_->repOk());
//else assert(cacheBw_->repOk());
}
// Found a reference position
tlen_ = chaser_.tlen();
assert(foundOff());
}
}
}
}
/**
* Prepare for the next call to advance() by prefetching relevant
* data. In this case, 'chaser_' is doing this for us.
*/
void prep() {
// nothing
}
/**
* Return true iff off_ contains a valid reference location for
* this range.
*/
bool foundOff() const {
return off_.first != OFF_MASK;
}
/**
* Reset the chaser so that 'off_' does not hold a valid offset and
* foundOff() returns false.
*/
void reset() {
off_.first = OFF_MASK;
}
/**
* Get the calculated offset.
*/
UPair off() const {
return off_;
}
/**
* Get the length of the hit reference.
*/
TIndexOffU tlen() const {
return tlen_;
}
bool done; /// true = chase is done & answer is in off_
protected:
const Ebwt* ebwt_; /// index to resolve row in
TIndexOffU qlen_; /// length of read; needed to convert to ref. coordinates
uint32_t cacheThresh_; /// ranges wider than thresh use cacheing
TIndexOffU top_; /// range top
TIndexOffU bot_; /// range bottom
TIndexOffU irow_; /// initial randomly-chosen row within range
TIndexOffU row_; /// current row within range
UPair off_; /// calculated offset (OFF_MASK if not done)
TIndexOffU tlen_; /// length of text hit
RowChaser chaser_; /// stateful row chaser
RangeCacheEntry cacheEnt_; /// current cache entry
bool cached_; /// cacheEnt is active for current range?
RangeCache* cacheFw_; /// cache for the forward index
RangeCache* cacheBw_; /// cache for the backward index
AlignerMetrics *metrics_;
};
#endif /* RANGE_CHASER_H_ */