minibwa 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +119 -0
- data/ext/minibwa/extconf.rb +105 -0
- data/ext/minibwa/mb_buffer.c +113 -0
- data/ext/minibwa/mb_hit.c +192 -0
- data/ext/minibwa/mb_index.c +462 -0
- data/ext/minibwa/mb_index_build.c +174 -0
- data/ext/minibwa/mb_options.c +301 -0
- data/ext/minibwa/minibwa/LICENSE.txt +37 -0
- data/ext/minibwa/minibwa/align.c +930 -0
- data/ext/minibwa/minibwa/bseq.h +45 -0
- data/ext/minibwa/minibwa/bwt.c +715 -0
- data/ext/minibwa/minibwa/bwt.h +86 -0
- data/ext/minibwa/minibwa/cs.c +161 -0
- data/ext/minibwa/minibwa/format.c +356 -0
- data/ext/minibwa/minibwa/index.c +342 -0
- data/ext/minibwa/minibwa/kalloc.c +224 -0
- data/ext/minibwa/minibwa/kalloc.h +54 -0
- data/ext/minibwa/minibwa/ketopt.h +123 -0
- data/ext/minibwa/minibwa/kommon.c +374 -0
- data/ext/minibwa/minibwa/kommon.h +85 -0
- data/ext/minibwa/minibwa/kseq.h +256 -0
- data/ext/minibwa/minibwa/ksort.h +163 -0
- data/ext/minibwa/minibwa/ksw2.h +220 -0
- data/ext/minibwa/minibwa/ksw2_extd2_sse.c +403 -0
- data/ext/minibwa/minibwa/ksw2_extz2_sse.c +296 -0
- data/ext/minibwa/minibwa/ksw2_ll_sse.c +341 -0
- data/ext/minibwa/minibwa/kthread.h +15 -0
- data/ext/minibwa/minibwa/l2bit.c +479 -0
- data/ext/minibwa/minibwa/l2bit.h +72 -0
- data/ext/minibwa/minibwa/lchain.c +231 -0
- data/ext/minibwa/minibwa/libsais.c +6985 -0
- data/ext/minibwa/minibwa/libsais.h +106 -0
- data/ext/minibwa/minibwa/libsais64.c +7064 -0
- data/ext/minibwa/minibwa/libsais64.h +81 -0
- data/ext/minibwa/minibwa/map-algo.c +769 -0
- data/ext/minibwa/minibwa/mbpriv.h +148 -0
- data/ext/minibwa/minibwa/minibwa.h +176 -0
- data/ext/minibwa/minibwa/options.c +116 -0
- data/ext/minibwa/minibwa/pe.c +559 -0
- data/ext/minibwa/minibwa/s2n-lite.h +59 -0
- data/ext/minibwa/minibwa/seed.c +354 -0
- data/ext/minibwa/minibwa.c +67 -0
- data/ext/minibwa/minibwa.h +51 -0
- data/lib/minibwa/hit.rb +110 -0
- data/lib/minibwa/index.rb +77 -0
- data/lib/minibwa/options.rb +235 -0
- data/lib/minibwa/sam.rb +85 -0
- data/lib/minibwa/version.rb +6 -0
- data/lib/minibwa.rb +11 -0
- metadata +88 -0
|
@@ -0,0 +1,930 @@
|
|
|
1
|
+
#include <assert.h>
|
|
2
|
+
#include <string.h>
|
|
3
|
+
#include <stdlib.h>
|
|
4
|
+
#include <stdio.h>
|
|
5
|
+
#include <math.h>
|
|
6
|
+
#include "mbpriv.h"
|
|
7
|
+
#include "kommon.h"
|
|
8
|
+
#include "kalloc.h"
|
|
9
|
+
#include "ksw2.h"
|
|
10
|
+
|
|
11
|
+
static inline void update_max_zdrop(int32_t score, int i, int j, int32_t *max, int *max_i, int *max_j, int e, int *max_zdrop, int pos[2][2])
|
|
12
|
+
{
|
|
13
|
+
if (score < *max) {
|
|
14
|
+
int li = i - *max_i;
|
|
15
|
+
int lj = j - *max_j;
|
|
16
|
+
int diff = li > lj? li - lj : lj - li;
|
|
17
|
+
int z = *max - score - diff * e;
|
|
18
|
+
if (z > *max_zdrop) {
|
|
19
|
+
*max_zdrop = z;
|
|
20
|
+
pos[0][0] = *max_i, pos[0][1] = i;
|
|
21
|
+
pos[1][0] = *max_j, pos[1][1] = j;
|
|
22
|
+
}
|
|
23
|
+
} else *max = score, *max_i = i, *max_j = j;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static int mm_test_zdrop(void *km, const mb_opt_t *opt, const uint8_t *qseq, const uint8_t *tseq, uint32_t n_cigar, uint32_t *cigar, const int8_t *mat, int32_t is_sr)
|
|
27
|
+
{
|
|
28
|
+
uint32_t k;
|
|
29
|
+
int32_t score = 0, max = INT32_MIN, max_i = -1, max_j = -1, i = 0, j = 0, max_zdrop = 0;
|
|
30
|
+
int pos[2][2] = {{-1, -1}, {-1, -1}}, q_len, t_len;
|
|
31
|
+
|
|
32
|
+
// find the score and the region where score drops most along diagonal
|
|
33
|
+
for (k = 0, score = 0; k < n_cigar; ++k) {
|
|
34
|
+
uint32_t l, op = cigar[k]&0xf, len = cigar[k]>>4;
|
|
35
|
+
if (op == MB_CIGAR_MATCH) {
|
|
36
|
+
for (l = 0; l < len; ++l) {
|
|
37
|
+
score += mat[tseq[i + l] * 5 + qseq[j + l]];
|
|
38
|
+
update_max_zdrop(score, i+l, j+l, &max, &max_i, &max_j, opt->e, &max_zdrop, pos);
|
|
39
|
+
}
|
|
40
|
+
i += len, j += len;
|
|
41
|
+
} else if (op == MB_CIGAR_INS || op == MB_CIGAR_DEL || op == MB_CIGAR_N_SKIP) {
|
|
42
|
+
score -= opt->q + opt->e * len;
|
|
43
|
+
if (op == MB_CIGAR_INS) j += len;
|
|
44
|
+
else i += len;
|
|
45
|
+
update_max_zdrop(score, i, j, &max, &max_i, &max_j, opt->e, &max_zdrop, pos);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// test if there is an inversion in the most dropped region
|
|
50
|
+
q_len = pos[1][1] - pos[1][0], t_len = pos[0][1] - pos[0][0];
|
|
51
|
+
if (!is_sr && max_zdrop > opt->zdrop_inv && q_len < opt->max_gap && t_len < opt->max_gap) {
|
|
52
|
+
uint8_t *qseq2;
|
|
53
|
+
void *qp;
|
|
54
|
+
int q_off, t_off;
|
|
55
|
+
qseq2 = Kmalloc(km, uint8_t, q_len);
|
|
56
|
+
for (i = 0; i < q_len; ++i) {
|
|
57
|
+
int c = qseq[pos[1][1] - i - 1];
|
|
58
|
+
qseq2[i] = c >= 4? 4 : 3 - c;
|
|
59
|
+
}
|
|
60
|
+
qp = ksw_ll_qinit(km, 2, q_len, qseq2, 5, mat);
|
|
61
|
+
score = ksw_ll_i16(qp, t_len, tseq + pos[0][0], opt->q, opt->e, &q_off, &t_off);
|
|
62
|
+
kfree(km, qseq2);
|
|
63
|
+
kfree(km, qp);
|
|
64
|
+
if (score >= opt->min_chain_score * opt->a && score >= opt->min_dp_max * opt->a)
|
|
65
|
+
return 2; // there is a potential inversion
|
|
66
|
+
}
|
|
67
|
+
return max_zdrop > opt->zdrop? 1 : 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
static void mb_fix_cigar(mb_hit_t *r, const uint8_t *qseq, const uint8_t *tseq, int *qshift, int *tshift)
|
|
71
|
+
{
|
|
72
|
+
mb_extra_t *p = r->p;
|
|
73
|
+
int32_t toff = 0, qoff = 0, to_shrink = 0;
|
|
74
|
+
uint32_t k;
|
|
75
|
+
*qshift = *tshift = 0;
|
|
76
|
+
if (p->n_cigar <= 1) return;
|
|
77
|
+
for (k = 0; k < p->n_cigar; ++k) { // indel left alignment
|
|
78
|
+
uint32_t op = p->cigar[k]&0xf, len = p->cigar[k]>>4;
|
|
79
|
+
if (len == 0) to_shrink = 1;
|
|
80
|
+
if (op == MB_CIGAR_MATCH) {
|
|
81
|
+
toff += len, qoff += len;
|
|
82
|
+
} else if (op == MB_CIGAR_INS || op == MB_CIGAR_DEL) {
|
|
83
|
+
if (k > 0 && k < p->n_cigar - 1 && (p->cigar[k-1]&0xf) == 0 && (p->cigar[k+1]&0xf) == 0) {
|
|
84
|
+
int l, prev_len = p->cigar[k-1] >> 4;
|
|
85
|
+
if (op == MB_CIGAR_INS) {
|
|
86
|
+
for (l = 0; l < prev_len; ++l)
|
|
87
|
+
if (qseq[qoff - 1 - l] != qseq[qoff + len - 1 - l])
|
|
88
|
+
break;
|
|
89
|
+
} else {
|
|
90
|
+
for (l = 0; l < prev_len; ++l)
|
|
91
|
+
if (tseq[toff - 1 - l] != tseq[toff + len - 1 - l])
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
if (l > 0)
|
|
95
|
+
p->cigar[k-1] -= l<<4, p->cigar[k+1] += l<<4, qoff -= l, toff -= l;
|
|
96
|
+
if (l == prev_len) to_shrink = 1;
|
|
97
|
+
}
|
|
98
|
+
if (op == MB_CIGAR_INS) qoff += len;
|
|
99
|
+
else toff += len;
|
|
100
|
+
} else if (op == MB_CIGAR_N_SKIP) {
|
|
101
|
+
toff += len;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
assert(qoff == r->qe - r->qs && toff == r->te - r->ts);
|
|
105
|
+
for (k = 0; k < p->n_cigar - 2; ++k) { // fix CIGAR like 5I6D7I
|
|
106
|
+
if ((p->cigar[k]&0xf) > 0 && (p->cigar[k]&0xf) + (p->cigar[k+1]&0xf) == 3) {
|
|
107
|
+
uint32_t l, s[3] = {0,0,0};
|
|
108
|
+
for (l = k; l < p->n_cigar; ++l) { // count number of adjacent I and D
|
|
109
|
+
uint32_t op = p->cigar[l]&0xf;
|
|
110
|
+
if (op == MB_CIGAR_INS || op == MB_CIGAR_DEL || p->cigar[l]>>4 == 0)
|
|
111
|
+
s[op] += p->cigar[l] >> 4;
|
|
112
|
+
else break;
|
|
113
|
+
}
|
|
114
|
+
if (s[1] > 0 && s[2] > 0 && l - k > 2) { // turn to a single I and a single D
|
|
115
|
+
p->cigar[k] = s[1]<<4|MB_CIGAR_INS;
|
|
116
|
+
p->cigar[k+1] = s[2]<<4|MB_CIGAR_DEL;
|
|
117
|
+
for (k += 2; k < l; ++k)
|
|
118
|
+
p->cigar[k] &= 0xf;
|
|
119
|
+
to_shrink = 1;
|
|
120
|
+
}
|
|
121
|
+
k = l;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (to_shrink) { // squeeze out zero-length operations
|
|
125
|
+
int32_t l = 0;
|
|
126
|
+
for (k = 0; k < p->n_cigar; ++k) // squeeze out zero-length operations
|
|
127
|
+
if (p->cigar[k]>>4 != 0)
|
|
128
|
+
p->cigar[l++] = p->cigar[k];
|
|
129
|
+
p->n_cigar = l;
|
|
130
|
+
for (k = l = 0; k < p->n_cigar; ++k) // merge two adjacent operations if they are the same
|
|
131
|
+
if (k == p->n_cigar - 1 || (p->cigar[k]&0xf) != (p->cigar[k+1]&0xf))
|
|
132
|
+
p->cigar[l++] = p->cigar[k];
|
|
133
|
+
else p->cigar[k+1] += p->cigar[k]>>4<<4; // add length to the next CIGAR operator
|
|
134
|
+
p->n_cigar = l;
|
|
135
|
+
}
|
|
136
|
+
if ((p->cigar[0]&0xf) == MB_CIGAR_INS || (p->cigar[0]&0xf) == MB_CIGAR_DEL) { // get rid of leading I or D
|
|
137
|
+
int32_t l = p->cigar[0] >> 4;
|
|
138
|
+
if ((p->cigar[0]&0xf) == MB_CIGAR_INS) {
|
|
139
|
+
if (r->rev) r->qe -= l;
|
|
140
|
+
else r->qs += l;
|
|
141
|
+
*qshift = l;
|
|
142
|
+
} else r->ts += l, *tshift = l;
|
|
143
|
+
--p->n_cigar;
|
|
144
|
+
memmove(p->cigar, p->cigar + 1, p->n_cigar * 4);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static void mm_update_cigar_eqx(mb_hit_t *r, const uint8_t *qseq, const uint8_t *tseq) // written by @armintoepfer
|
|
149
|
+
{
|
|
150
|
+
uint32_t n_EQX = 0, n_X = 0;
|
|
151
|
+
uint32_t k, l, m, cap, toff = 0, qoff = 0, n_M = 0;
|
|
152
|
+
mb_extra_t *p;
|
|
153
|
+
if (r->p == 0) return;
|
|
154
|
+
for (k = 0; k < r->p->n_cigar; ++k) {
|
|
155
|
+
uint32_t op = r->p->cigar[k]&0xf, len = r->p->cigar[k]>>4;
|
|
156
|
+
if (op == MB_CIGAR_MATCH) {
|
|
157
|
+
while (len > 0) {
|
|
158
|
+
for (l = 0; l < len && qseq[qoff + l] == tseq[toff + l] && qseq[qoff + l] < 4; ++l) {} // run of "="; N is a mismatch (cf. e41830b for NM)
|
|
159
|
+
if (l > 0) { ++n_EQX; len -= l; toff += l; qoff += l; }
|
|
160
|
+
for (l = 0; l < len && !(qseq[qoff + l] == tseq[toff + l] && qseq[qoff + l] < 4); ++l) {} // run of "X" (includes N<=>N)
|
|
161
|
+
if (l > 0) { ++n_EQX; ++n_X; len -= l; toff += l; qoff += l; }
|
|
162
|
+
}
|
|
163
|
+
++n_M;
|
|
164
|
+
} else if (op == MB_CIGAR_INS) {
|
|
165
|
+
qoff += len;
|
|
166
|
+
} else if (op == MB_CIGAR_DEL) {
|
|
167
|
+
toff += len;
|
|
168
|
+
} else if (op == MB_CIGAR_N_SKIP) {
|
|
169
|
+
toff += len;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// update in-place only if every M op is a single pure "=" run (no "X",
|
|
173
|
+
// hence no mismatch or N); otherwise the emission pass below is needed
|
|
174
|
+
if (n_X == 0) {
|
|
175
|
+
for (k = 0; k < r->p->n_cigar; ++k) {
|
|
176
|
+
uint32_t op = r->p->cigar[k]&0xf, len = r->p->cigar[k]>>4;
|
|
177
|
+
if (op == MB_CIGAR_MATCH) r->p->cigar[k] = len << 4 | MB_CIGAR_EQ_MATCH;
|
|
178
|
+
}
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
// allocate new storage
|
|
182
|
+
cap = r->p->n_cigar + (n_EQX - n_M) + sizeof(mb_extra_t);
|
|
183
|
+
kom_roundup32(cap);
|
|
184
|
+
p = (mb_extra_t*)calloc(cap, 4);
|
|
185
|
+
memcpy(p, r->p, sizeof(mb_extra_t));
|
|
186
|
+
p->cap = cap;
|
|
187
|
+
// update cigar while copying
|
|
188
|
+
toff = qoff = m = 0;
|
|
189
|
+
for (k = 0; k < r->p->n_cigar; ++k) {
|
|
190
|
+
uint32_t op = r->p->cigar[k]&0xf, len = r->p->cigar[k]>>4;
|
|
191
|
+
if (op == MB_CIGAR_MATCH) {
|
|
192
|
+
while (len > 0) {
|
|
193
|
+
// match ("="); N is a mismatch, so require both bases < 4
|
|
194
|
+
for (l = 0; l < len && qseq[qoff + l] == tseq[toff + l] && qseq[qoff + l] < 4; ++l) {}
|
|
195
|
+
if (l > 0) p->cigar[m++] = l << 4 | MB_CIGAR_EQ_MATCH;
|
|
196
|
+
len -= l;
|
|
197
|
+
toff += l, qoff += l;
|
|
198
|
+
// mismatch ("X"); includes N<=>N
|
|
199
|
+
for (l = 0; l < len && !(qseq[qoff + l] == tseq[toff + l] && qseq[qoff + l] < 4); ++l) {}
|
|
200
|
+
if (l > 0) p->cigar[m++] = l << 4 | MB_CIGAR_X_MISMATCH;
|
|
201
|
+
len -= l;
|
|
202
|
+
toff += l, qoff += l;
|
|
203
|
+
}
|
|
204
|
+
continue;
|
|
205
|
+
} else if (op == MB_CIGAR_INS) {
|
|
206
|
+
qoff += len;
|
|
207
|
+
} else if (op == MB_CIGAR_DEL) {
|
|
208
|
+
toff += len;
|
|
209
|
+
} else if (op == MB_CIGAR_N_SKIP) {
|
|
210
|
+
toff += len;
|
|
211
|
+
}
|
|
212
|
+
p->cigar[m++] = r->p->cigar[k];
|
|
213
|
+
}
|
|
214
|
+
p->n_cigar = m;
|
|
215
|
+
free(r->p);
|
|
216
|
+
r->p = p;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
void mb_update_extra(void *km, mb_hit_t *r, const uint8_t *qseq, const uint8_t *tseq, const int8_t *mat, int8_t q, int8_t e, uint64_t opt_flag, int log_gap)
|
|
220
|
+
{
|
|
221
|
+
uint32_t k, l;
|
|
222
|
+
int32_t qshift, tshift, toff = 0, qoff = 0, len4;
|
|
223
|
+
double s = 0.0, max = 0.0;
|
|
224
|
+
mb_extra_t *p = r->p;
|
|
225
|
+
if (p == 0) return;
|
|
226
|
+
mb_fix_cigar(r, qseq, tseq, &qshift, &tshift);
|
|
227
|
+
qseq += qshift, tseq += tshift; // qseq and tseq may be shifted due to the removal of leading I/D
|
|
228
|
+
r->blen = r->mlen = 0;
|
|
229
|
+
for (k = 0; k < p->n_cigar; ++k) {
|
|
230
|
+
uint32_t op = p->cigar[k]&0xf, len = p->cigar[k]>>4;
|
|
231
|
+
if (op == MB_CIGAR_MATCH) {
|
|
232
|
+
int n_ambi = 0, n_diff = 0;
|
|
233
|
+
for (l = 0; l < len; ++l) {
|
|
234
|
+
int cq = qseq[qoff + l], ct = tseq[toff + l];
|
|
235
|
+
if (ct > 3 || cq > 3) ++n_ambi;
|
|
236
|
+
else if (ct != cq) n_diff += (mat[ct * 5 + cq] < 0);
|
|
237
|
+
s += mat[ct * 5 + cq];
|
|
238
|
+
if (s < 0) s = 0;
|
|
239
|
+
else max = max > s? max : s;
|
|
240
|
+
}
|
|
241
|
+
r->blen += len - n_ambi, r->mlen += len - (n_ambi + n_diff), p->n_ambi += n_ambi;
|
|
242
|
+
toff += len, qoff += len;
|
|
243
|
+
} else if (op == MB_CIGAR_INS) {
|
|
244
|
+
int n_ambi = 0;
|
|
245
|
+
for (l = 0; l < len; ++l)
|
|
246
|
+
if (qseq[qoff + l] > 3) ++n_ambi;
|
|
247
|
+
r->blen += len - n_ambi, p->n_ambi += n_ambi;
|
|
248
|
+
if (log_gap) s -= q + (double)e * mb_log2(1.0 + len);
|
|
249
|
+
else s -= q + e;
|
|
250
|
+
if (s < 0) s = 0;
|
|
251
|
+
qoff += len;
|
|
252
|
+
} else if (op == MB_CIGAR_DEL) {
|
|
253
|
+
int n_ambi = 0;
|
|
254
|
+
for (l = 0; l < len; ++l)
|
|
255
|
+
if (tseq[toff + l] > 3) ++n_ambi;
|
|
256
|
+
r->blen += len - n_ambi, p->n_ambi += n_ambi;
|
|
257
|
+
if (log_gap) s -= q + (double)e * mb_log2(1.0 + len);
|
|
258
|
+
else s -= q + e;
|
|
259
|
+
if (s < 0) s = 0;
|
|
260
|
+
toff += len;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
p->dp_max0 = p->dp_max = (int32_t)(max + .499);
|
|
264
|
+
assert(qoff == r->qe - r->qs && toff == r->te - r->ts);
|
|
265
|
+
if (opt_flag & MB_F_EQX) mm_update_cigar_eqx(r, qseq, tseq); // NB: it has to be called here as changes to qseq and tseq are not returned
|
|
266
|
+
if (opt_flag & (MB_F_WRITE_DS|MB_F_WRITE_CS|MB_F_WRITE_MD)) {
|
|
267
|
+
kstring_t str = {0,0,0};
|
|
268
|
+
str.m = 256;
|
|
269
|
+
str.s = kmalloc(km, str.m);
|
|
270
|
+
if (opt_flag & (MB_F_WRITE_DS|MB_F_WRITE_CS))
|
|
271
|
+
mb_write_cs_ds(km, &str, tseq, qseq, r, !!(opt_flag & MB_F_WRITE_DS));
|
|
272
|
+
else
|
|
273
|
+
mb_write_MD(km, &str, tseq, qseq, r);
|
|
274
|
+
r->p->cs = 1;
|
|
275
|
+
len4 = r->p->n_cigar + sizeof(mb_extra_t)/4 + (str.l + 1 + 3) / 4;
|
|
276
|
+
if (len4 > r->p->cap) {
|
|
277
|
+
r->p->cap = len4;
|
|
278
|
+
r->p = (mb_extra_t*)realloc(r->p, r->p->cap * 4);
|
|
279
|
+
}
|
|
280
|
+
memcpy(&r->p->cigar[r->p->n_cigar], str.s, str.l + 1);
|
|
281
|
+
kfree(km, str.s);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
static void mb_enlarge_cigar(mb_hit_t *r, uint32_t n_cigar) // TODO: this calls the libc realloc()
|
|
286
|
+
{
|
|
287
|
+
if (n_cigar == 0) return;
|
|
288
|
+
if (r->p == 0) {
|
|
289
|
+
uint32_t cap = n_cigar + sizeof(mb_extra_t)/4;
|
|
290
|
+
kom_roundup32(cap);
|
|
291
|
+
r->p = (mb_extra_t*)calloc(cap, 4);
|
|
292
|
+
r->p->cap = cap;
|
|
293
|
+
} else if (r->p->n_cigar + n_cigar + sizeof(mb_extra_t)/4 > r->p->cap) {
|
|
294
|
+
r->p->cap = r->p->n_cigar + n_cigar + sizeof(mb_extra_t)/4;
|
|
295
|
+
kom_roundup32(r->p->cap);
|
|
296
|
+
r->p = (mb_extra_t*)realloc(r->p, r->p->cap * 4);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
void mb_append_cigar(mb_hit_t *r, uint32_t n_cigar, const uint32_t *cigar)
|
|
301
|
+
{
|
|
302
|
+
mb_extra_t *p;
|
|
303
|
+
if (n_cigar == 0) return;
|
|
304
|
+
mb_enlarge_cigar(r, n_cigar);
|
|
305
|
+
p = r->p;
|
|
306
|
+
if (p->n_cigar > 0 && (p->cigar[p->n_cigar-1]&0xf) == (cigar[0]&0xf)) { // same CIGAR op at the boundary
|
|
307
|
+
p->cigar[p->n_cigar-1] += cigar[0]>>4<<4;
|
|
308
|
+
if (n_cigar > 1) memcpy(p->cigar + p->n_cigar, cigar + 1, (n_cigar - 1) * 4);
|
|
309
|
+
p->n_cigar += n_cigar - 1;
|
|
310
|
+
} else {
|
|
311
|
+
memcpy(p->cigar + p->n_cigar, cigar, n_cigar * 4);
|
|
312
|
+
p->n_cigar += n_cigar;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
static inline int32_t mb_min_int32(int32_t a, int32_t b)
|
|
317
|
+
{
|
|
318
|
+
return a < b? a : b;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
static inline int32_t max_bw_from_mm(const mb_opt_t *opt, int32_t mm)
|
|
322
|
+
{
|
|
323
|
+
int32_t x = mm * (opt->a + opt->b), max2 = 0, max1 = 0;
|
|
324
|
+
if (x >= opt->q + opt->e) max1 = (x - opt->q + opt->e - 1) / opt->e;
|
|
325
|
+
if (x >= opt->q2 + opt->e2) max2 = (x - opt->q2 + opt->e2 - 1) / opt->e2;
|
|
326
|
+
return max1 > max2? max1 : max2;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
static void mb_align_pair(void *km, const mb_opt_t *opt, int qlen, const uint8_t *qseq, int tlen, const uint8_t *tseq,
|
|
330
|
+
const int8_t *mat, int w, int end_bonus, int zdrop, int ksw_flag, ksw_extz_t *ez)
|
|
331
|
+
{
|
|
332
|
+
const int max_bw_adj_len = 100; // don't adjust bandwidth if sequences are too long
|
|
333
|
+
int32_t j, n_mm = -1;
|
|
334
|
+
if ((opt->b_ts != 0 && opt->b != opt->b_ts) || (opt->flag&MB_F_METH))
|
|
335
|
+
ksw_flag |= KSW_EZ_GENERIC_SC;
|
|
336
|
+
if ((ksw_flag & KSW_EZ_EXTZ_ONLY) && tlen >= qlen) { // ungapped extension
|
|
337
|
+
ksw_reset_extz(ez);
|
|
338
|
+
for (j = 0, ez->score = ez->max = 0; j < qlen; ++j) {
|
|
339
|
+
ez->score += mat[tseq[j] * 5 + qseq[j]];
|
|
340
|
+
n_mm += (tseq[j] > 3 || qseq[j] > 3 || mat[tseq[j] * 5 + qseq[j]] < 0);
|
|
341
|
+
if (ez->max < ez->score) ez->max = ez->score, ez->max_q = ez->max_t = j;
|
|
342
|
+
}
|
|
343
|
+
if (n_mm <= 2) {
|
|
344
|
+
ez->mqe = ez->score, ez->mqe_t = qlen - 1;
|
|
345
|
+
if (ez->mqe + end_bonus >= ez->max) {
|
|
346
|
+
ez->reach_end = 1;
|
|
347
|
+
ez->cigar = ksw_push_cigar(km, &ez->n_cigar, &ez->m_cigar, ez->cigar, MB_CIGAR_MATCH, qlen);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
} else if (qlen == tlen && !(ksw_flag & KSW_EZ_EXTZ_ONLY)) { // ungapped alignment
|
|
352
|
+
int32_t max_gapped_score = (qlen - 2) * opt->a - 2 * (opt->q + opt->e);
|
|
353
|
+
ksw_reset_extz(ez);
|
|
354
|
+
for (j = 0, ez->score = 0; j < qlen; ++j) {
|
|
355
|
+
ez->score += mat[tseq[j] * 5 + qseq[j]];
|
|
356
|
+
n_mm += (tseq[j] > 3 || qseq[j] > 3 || mat[tseq[j] * 5 + qseq[j]] < 0);
|
|
357
|
+
}
|
|
358
|
+
if (n_mm <= 3 || ez->score > max_gapped_score) {
|
|
359
|
+
ez->cigar = ksw_push_cigar(km, &ez->n_cigar, &ez->m_cigar, ez->cigar, MB_CIGAR_MATCH, qlen);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (n_mm >= 0 && mb_min_int32(qlen, tlen) < max_bw_adj_len) { // n_mm >= 0 => ungapped alignment attempted
|
|
365
|
+
int32_t max_bw;
|
|
366
|
+
max_bw = max_bw_from_mm(opt, n_mm);
|
|
367
|
+
if (w > max_bw + 4) w = max_bw + 4;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (opt->max_sw_mat > 0 && (int64_t)tlen * qlen > opt->max_sw_mat) { // too much memory; skip alignment
|
|
371
|
+
ksw_reset_extz(ez);
|
|
372
|
+
ez->zdropped = 1;
|
|
373
|
+
} else if (opt->q == opt->q2 && opt->e == opt->e2) { // affine gap
|
|
374
|
+
ksw_extz2_sse(km, qlen, qseq, tlen, tseq, 5, mat, opt->q, opt->e, w, zdrop * opt->a, end_bonus, ksw_flag, ez);
|
|
375
|
+
} else { // dual affine gap
|
|
376
|
+
ksw_extd2_sse(km, qlen, qseq, tlen, tseq, 5, mat, opt->q, opt->e, opt->q2, opt->e2, w, zdrop * opt->a, end_bonus, ksw_flag, ez);
|
|
377
|
+
//fprintf(stderr, "D2\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", tlen, qlen, !!(ksw_flag&KSW_EZ_EXTZ_ONLY), ez->max_t, ez->max_q, ez->max, ez->zdropped);
|
|
378
|
+
}
|
|
379
|
+
if (kom_dbg_flag & MB_DBG_ALN_SEQ) {
|
|
380
|
+
int i;
|
|
381
|
+
fprintf(stderr, "===> q=(%d,%d), e=(%d,%d), bw=%d, ksw_flag=0x%x, zdrop=%d, end_bonus=%d <===\n", opt->q, opt->q2, opt->e, opt->e2, w, ksw_flag, opt->zdrop, end_bonus);
|
|
382
|
+
for (i = 0; i < tlen; ++i) fputc("ACGTN"[tseq[i]], stderr);
|
|
383
|
+
fputc('\n', stderr);
|
|
384
|
+
for (i = 0; i < qlen; ++i) fputc("ACGTN"[qseq[i]], stderr);
|
|
385
|
+
fputc('\n', stderr);
|
|
386
|
+
fprintf(stderr, "score=%d, max=%d, cigar=", ez->score, ez->max);
|
|
387
|
+
for (i = 0; i < ez->n_cigar; ++i) fprintf(stderr, "%d%c", ez->cigar[i]>>4, MB_CIGAR_STR[ez->cigar[i]&0xf]);
|
|
388
|
+
fprintf(stderr, "\n");
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
static int *collect_long_gaps(void *km, int as1, int cnt1, mb_anchor_t *a, int min_gap, int *n_)
|
|
393
|
+
{
|
|
394
|
+
int i, n, *K;
|
|
395
|
+
*n_ = 0;
|
|
396
|
+
for (i = 1, n = 0; i < cnt1; ++i) { // count the number of gaps longer than min_gap
|
|
397
|
+
int64_t gap = (a[as1 + i].qpos - a[as1 + i - 1].qpos) - (a[as1 + i].tpos - a[as1 + i - 1].tpos);
|
|
398
|
+
if (gap < -min_gap || gap > min_gap) ++n;
|
|
399
|
+
}
|
|
400
|
+
if (n <= 1) return 0;
|
|
401
|
+
K = Kmalloc(km, int, n);
|
|
402
|
+
for (i = 1, n = 0; i < cnt1; ++i) { // store the positions of long gaps
|
|
403
|
+
int64_t gap = (a[as1 + i].qpos - a[as1 + i - 1].qpos) - (a[as1 + i].tpos - a[as1 + i - 1].tpos);
|
|
404
|
+
if (gap < -min_gap || gap > min_gap)
|
|
405
|
+
K[n++] = i;
|
|
406
|
+
}
|
|
407
|
+
*n_ = n;
|
|
408
|
+
return K;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
static void mm_filter_bad_seeds(void *km, int as1, int cnt1, mb_anchor_t *a, int min_gap, int diff_thres, int max_ext_len, int max_ext_cnt)
|
|
412
|
+
{ // this function deals with e.g. 1000I20M1000D
|
|
413
|
+
int max_st, max_en, n, i, k, max, *K;
|
|
414
|
+
K = collect_long_gaps(km, as1, cnt1, a, min_gap, &n);
|
|
415
|
+
if (K == 0) return;
|
|
416
|
+
max = 0, max_st = max_en = -1;
|
|
417
|
+
for (k = 0;; ++k) { // traverse long gaps
|
|
418
|
+
int gap, l, n_ins = 0, n_del = 0, qs, max_diff = 0, max_diff_l = -1;
|
|
419
|
+
int64_t ts;
|
|
420
|
+
if (k == n || k >= max_en) {
|
|
421
|
+
if (max_en > 0)
|
|
422
|
+
for (i = K[max_st]; i < K[max_en]; ++i)
|
|
423
|
+
a[as1 + i].flag |= MB_SEED_IGNORE;
|
|
424
|
+
max = 0, max_st = max_en = -1;
|
|
425
|
+
if (k == n) break;
|
|
426
|
+
}
|
|
427
|
+
i = K[k];
|
|
428
|
+
gap = (a[as1 + i].qpos - a[as1 + i - 1].qpos) - (a[as1 + i].tpos - a[as1 + i - 1].tpos);
|
|
429
|
+
if (gap > 0) n_ins += gap;
|
|
430
|
+
else n_del += -gap;
|
|
431
|
+
qs = a[as1 + i - 1].qpos;
|
|
432
|
+
ts = a[as1 + i - 1].tpos;
|
|
433
|
+
for (l = k + 1; l < n && l <= k + max_ext_cnt; ++l) {
|
|
434
|
+
int j = K[l], diff;
|
|
435
|
+
if (a[as1 + j].qpos - a[as1 + j].len - qs > max_ext_len || a[as1 + j].tpos - a[as1 + j].len - ts > max_ext_len) break;
|
|
436
|
+
gap = (a[as1 + j].qpos - a[as1 + j - 1].qpos) - (a[as1 + j].tpos - a[as1 + j - 1].tpos);
|
|
437
|
+
if (gap > 0) n_ins += gap;
|
|
438
|
+
else n_del += -gap;
|
|
439
|
+
diff = n_ins + n_del - abs(n_ins - n_del);
|
|
440
|
+
if (max_diff < diff)
|
|
441
|
+
max_diff = diff, max_diff_l = l;
|
|
442
|
+
}
|
|
443
|
+
if (max_diff > diff_thres && max_diff > max)
|
|
444
|
+
max = max_diff, max_st = k, max_en = max_diff_l;
|
|
445
|
+
}
|
|
446
|
+
kfree(km, K);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
static void mm_filter_bad_seeds_alt(void *km, int as1, int cnt1, mb_anchor_t *a, int min_gap, int max_ext)
|
|
450
|
+
{ // this function deals with e.g. 1000I20M2000I
|
|
451
|
+
int n, k, *K;
|
|
452
|
+
K = collect_long_gaps(km, as1, cnt1, a, min_gap, &n);
|
|
453
|
+
if (K == 0) return;
|
|
454
|
+
for (k = 0; k < n;) {
|
|
455
|
+
int i = K[k], l;
|
|
456
|
+
int gap1 = (a[as1 + i].qpos - a[as1 + i - 1].qpos) - (a[as1 + i].tpos - a[as1 + i - 1].tpos);
|
|
457
|
+
int64_t te1 = a[as1 + i].tpos;
|
|
458
|
+
int32_t qe1 = a[as1 + i].qpos;
|
|
459
|
+
int32_t left_len = a[as1 + i].len;
|
|
460
|
+
gap1 = gap1 > 0? gap1 : -gap1;
|
|
461
|
+
for (l = k + 1; l < n; ++l) {
|
|
462
|
+
int j = K[l], gap2, m;
|
|
463
|
+
if (a[as1 + j].qpos - qe1 > max_ext || a[as1 + j].tpos - te1 > max_ext) break;
|
|
464
|
+
gap2 = (a[as1 + j].qpos - a[as1 + j - 1].qpos) - (a[as1 + j].tpos - a[as1 + j - 1].tpos);
|
|
465
|
+
int64_t m_t = a[as1 + j - 1].tpos - te1 + left_len;
|
|
466
|
+
int32_t m_q = a[as1 + j - 1].qpos - qe1 + left_len;
|
|
467
|
+
m = m_t < m_q? m_t : m_q;
|
|
468
|
+
gap2 = gap2 > 0? gap2 : -gap2;
|
|
469
|
+
if (m > gap1 + gap2) break;
|
|
470
|
+
te1 = a[as1 + j].tpos;
|
|
471
|
+
qe1 = a[as1 + j].qpos;
|
|
472
|
+
left_len = a[as1 + j].len;
|
|
473
|
+
gap1 = gap2;
|
|
474
|
+
}
|
|
475
|
+
if (l > k + 1) {
|
|
476
|
+
int j, end = K[l - 1];
|
|
477
|
+
for (j = K[k]; j < end; ++j)
|
|
478
|
+
a[as1 + j].flag |= MB_SEED_IGNORE;
|
|
479
|
+
a[as1 + end].flag |= MB_SEED_LONG_JOIN;
|
|
480
|
+
}
|
|
481
|
+
k = l;
|
|
482
|
+
}
|
|
483
|
+
kfree(km, K);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
static void mm_fix_bad_ends(const mb_hit_t *r, const mb_anchor_t *a, int bw, int min_match, int32_t *as, int32_t *cnt)
|
|
487
|
+
{
|
|
488
|
+
int32_t i, l, m;
|
|
489
|
+
*as = r->as, *cnt = r->cnt;
|
|
490
|
+
if (r->cnt < 3) return;
|
|
491
|
+
m = l = a[r->as].len;
|
|
492
|
+
for (i = r->as + 1; i < r->as + r->cnt - 1; ++i) {
|
|
493
|
+
int32_t lq, lr, min, max;
|
|
494
|
+
int32_t q_span = a[i].len;
|
|
495
|
+
if (a[i].flag & MB_SEED_LONG_JOIN) break;
|
|
496
|
+
lr = a[i].tpos - a[i-1].tpos;
|
|
497
|
+
lq = a[i].qpos - a[i-1].qpos;
|
|
498
|
+
min = lr < lq? lr : lq;
|
|
499
|
+
max = lr > lq? lr : lq;
|
|
500
|
+
if (max - min > l >> 1) *as = i;
|
|
501
|
+
l += min;
|
|
502
|
+
m += min < q_span? min : q_span;
|
|
503
|
+
if (l >= bw << 1 || (m >= min_match && m >= bw) || m >= r->mlen >> 1) break;
|
|
504
|
+
}
|
|
505
|
+
*cnt = r->as + r->cnt - *as;
|
|
506
|
+
m = l = a[r->as + r->cnt - 1].len;
|
|
507
|
+
for (i = r->as + r->cnt - 2; i > *as; --i) {
|
|
508
|
+
int32_t lq, lr, min, max;
|
|
509
|
+
int32_t q_span = a[i].len;
|
|
510
|
+
if (a[i+1].flag & MB_SEED_LONG_JOIN) break;
|
|
511
|
+
lr = a[i+1].tpos - a[i].tpos - a[i+1].len + a[i].len;
|
|
512
|
+
lq = a[i+1].qpos - a[i].qpos - a[i+1].len + a[i].len;
|
|
513
|
+
min = lr < lq? lr : lq;
|
|
514
|
+
max = lr > lq? lr : lq;
|
|
515
|
+
if (max - min > l >> 1) *cnt = i + 1 - *as;
|
|
516
|
+
l += min;
|
|
517
|
+
m += min < q_span? min : q_span;
|
|
518
|
+
if (l >= bw << 1 || (m >= min_match && m >= bw) || m >= r->mlen >> 1) break;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
static void mb_max_stretch(const mb_hit_t *r, const mb_anchor_t *a, int32_t *as, int32_t *cnt)
|
|
523
|
+
{ // find the max ungapped chain
|
|
524
|
+
int32_t i, score, max_score, len, max_i, max_len;
|
|
525
|
+
|
|
526
|
+
*as = r->as, *cnt = r->cnt;
|
|
527
|
+
if (r->cnt < 2) return;
|
|
528
|
+
|
|
529
|
+
max_score = -1, max_i = -1, max_len = 0;
|
|
530
|
+
score = a[r->as].len, len = 1;
|
|
531
|
+
for (i = r->as + 1; i < r->as + r->cnt; ++i) {
|
|
532
|
+
int32_t lr = a[i].tpos - a[i-1].tpos;
|
|
533
|
+
int32_t lq = a[i].qpos - a[i-1].qpos;
|
|
534
|
+
if (lq == lr) { // ungapped
|
|
535
|
+
score += lq < a[i].len? lq : a[i].len; // in theory, "lq > a[i].len" should always stand
|
|
536
|
+
++len;
|
|
537
|
+
} else { // a gap
|
|
538
|
+
if (score > max_score)
|
|
539
|
+
max_score = score, max_len = len, max_i = i - len;
|
|
540
|
+
score = a[i].len, len = 1;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
if (score > max_score)
|
|
544
|
+
max_score = score, max_len = len, max_i = i - len;
|
|
545
|
+
*as = max_i, *cnt = max_len;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
static void mb_align1(void *km, const mb_opt_t *opt, const mb_idx_t *mi, int qlen, uint8_t *qseq0[2], l2b_meth_t mt, mb_hit_t *r, mb_hit_t *r2, int n_a, mb_anchor_t *a, ksw_extz_t *ez)
|
|
549
|
+
{
|
|
550
|
+
int32_t is_sr, max_back, rev = a[r->as].sid&1, as1, cnt1;
|
|
551
|
+
uint8_t *tseq = 0, *qseq;
|
|
552
|
+
int32_t i, bw, bw_long, dropped = 0, ksw_flag = 0;
|
|
553
|
+
int64_t tid = a[r->as].sid >> 1, l;
|
|
554
|
+
int64_t ts0, te0, ts1, te1, ts, te; // ts0/te0: range of extracted sequence; ts1/te1: range of alignment; ts/te: moving temporary
|
|
555
|
+
int32_t qs0, qe0, qs1, qe1, qs, qe;
|
|
556
|
+
int8_t mat[25];
|
|
557
|
+
|
|
558
|
+
is_sr = mb_is_sr_mode(opt, qlen);
|
|
559
|
+
max_back = is_sr? 0 : 10; // for long reads, allow up to 10bp "edges" from chain ends
|
|
560
|
+
r2->cnt = 0;
|
|
561
|
+
if (r->cnt == 0) return;
|
|
562
|
+
if (r->rev) mt = l2b_meth_rev(mt);
|
|
563
|
+
ksw_gen_nt4_mat(mat, opt->a, opt->b, opt->b_ts, opt->b_ambi, (int)mt);
|
|
564
|
+
bw = (int)(opt->bw * 1.5 + 1.);
|
|
565
|
+
if (!is_sr) {
|
|
566
|
+
bw_long = (int)(opt->bw_long * 1.5 + 1.);
|
|
567
|
+
if (bw_long < bw) bw_long = bw;
|
|
568
|
+
} else bw_long = bw; // disable long gap in the short-read mode
|
|
569
|
+
|
|
570
|
+
if (is_sr) {
|
|
571
|
+
mb_max_stretch(r, a, &as1, &cnt1);
|
|
572
|
+
} else {
|
|
573
|
+
mm_fix_bad_ends(r, a, opt->bw, opt->min_chain_score * 2, &as1, &cnt1);
|
|
574
|
+
mm_filter_bad_seeds(km, as1, cnt1, a, 10, 40, opt->max_gap>>1, 10);
|
|
575
|
+
mm_filter_bad_seeds_alt(km, as1, cnt1, a, 30, opt->max_gap>>1);
|
|
576
|
+
}
|
|
577
|
+
ts = a[as1].tpos + 1 - a[as1].len + mb_min_int32(a[as1].len>>1, max_back);
|
|
578
|
+
qs = a[as1].qpos + 1 - a[as1].len + mb_min_int32(a[as1].len>>1, max_back);
|
|
579
|
+
te = a[as1+cnt1-1].tpos + 1 - mb_min_int32(a[as1+cnt1-1].len>>1, max_back);
|
|
580
|
+
qe = a[as1+cnt1-1].qpos + 1 - mb_min_int32(a[as1+cnt1-1].len>>1, max_back);
|
|
581
|
+
assert(cnt1 > 0);
|
|
582
|
+
|
|
583
|
+
if (kom_dbg_flag & MB_DBG_AN_POS) {
|
|
584
|
+
for (i = 0; i < r->cnt; ++i) {
|
|
585
|
+
int32_t gap = i == 0? 0 : (a[r->as+i].qpos - a[r->as+i-1].qpos) - (a[r->as+i].tpos - a[r->as+i-1].tpos);
|
|
586
|
+
fprintf(stderr, "AF\t%d\t%s\t%ld\t%d\t%d\t%ld\n", r->as, mi->l2b->ctg[tid].name, (long)a[r->as + i].tpos, a[r->as + i].qpos, gap, (long)a[r->as + i].len);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/* Look for the start and end of regions to perform DP. This sounds easy
|
|
591
|
+
* but is in fact tricky. Excessively small regions lead to unnecessary
|
|
592
|
+
* clippings and lose alignable sequences. Excessively large regions
|
|
593
|
+
* occasionally lead to large overlaps between two chains and may cause
|
|
594
|
+
* loss of alignments in corner cases. */
|
|
595
|
+
if (is_sr) {
|
|
596
|
+
qs0 = 0, qe0 = qlen;
|
|
597
|
+
l = qs;
|
|
598
|
+
l += l * opt->a + opt->end_bonus > opt->q? (l * opt->a + opt->end_bonus - opt->q) / opt->e : 0;
|
|
599
|
+
ts0 = ts - l > 0? ts - l : 0;
|
|
600
|
+
l = qlen - qe;
|
|
601
|
+
l += l * opt->a + opt->end_bonus > opt->q? (l * opt->a + opt->end_bonus - opt->q) / opt->e : 0;
|
|
602
|
+
te0 = te + l < mi->l2b->ctg[tid].len? te + l : mi->l2b->ctg[tid].len;
|
|
603
|
+
} else {
|
|
604
|
+
// compute ts0 and qs0
|
|
605
|
+
ts0 = a[r->as].tpos + 1 - a[r->as].len;
|
|
606
|
+
qs0 = a[r->as].qpos + 1 - a[r->as].len;
|
|
607
|
+
if (ts0 < 0) ts0 = 0;
|
|
608
|
+
assert(qs0 >= 0); // this should never happen, or it is logic error
|
|
609
|
+
ts1 = qs1 = 0;
|
|
610
|
+
if (qs > 0 && ts > 0) {
|
|
611
|
+
l = qs < opt->max_gap? qs : opt->max_gap;
|
|
612
|
+
qs1 = qs1 > qs - l? qs1 : qs - l;
|
|
613
|
+
qs0 = qs0 < qs1? qs0 : qs1; // at least include qs0
|
|
614
|
+
l += l * opt->a > opt->q? (l * opt->a - opt->q) / opt->e : 0;
|
|
615
|
+
l = l < opt->max_gap? l : opt->max_gap;
|
|
616
|
+
l = l < ts? l : ts;
|
|
617
|
+
ts1 = ts1 > ts - l? ts1 : ts - l;
|
|
618
|
+
ts0 = ts0 < ts1? ts0 : ts1;
|
|
619
|
+
ts0 = ts0 < ts? ts0 : ts;
|
|
620
|
+
} else ts0 = ts, qs0 = qs;
|
|
621
|
+
// compute te0 and qe0
|
|
622
|
+
te0 = a[r->as + r->cnt - 1].tpos + 1;
|
|
623
|
+
qe0 = a[r->as + r->cnt - 1].qpos + 1;
|
|
624
|
+
te1 = mi->l2b->ctg[tid].len, qe1 = qlen;
|
|
625
|
+
if (qe < qlen && te < mi->l2b->ctg[tid].len) {
|
|
626
|
+
l = qlen - qe < opt->max_gap? qlen - qe : opt->max_gap;
|
|
627
|
+
qe1 = qe1 < qe + l? qe1 : qe + l;
|
|
628
|
+
qe0 = qe0 > qe1? qe0 : qe1; // at least include qe0
|
|
629
|
+
l += l * opt->a > opt->q? (l * opt->a - opt->q) / opt->e : 0;
|
|
630
|
+
l = l < opt->max_gap? l : opt->max_gap;
|
|
631
|
+
l = l < mi->l2b->ctg[tid].len - te? l : mi->l2b->ctg[tid].len - te;
|
|
632
|
+
te1 = te1 < te + l? te1 : te + l;
|
|
633
|
+
te0 = te0 > te1? te0 : te1;
|
|
634
|
+
} else te0 = te, qe0 = qe;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
assert(te0 > ts0);
|
|
638
|
+
tseq = Kmalloc(km, uint8_t, te0 - ts0);
|
|
639
|
+
|
|
640
|
+
if (qs > 0 && ts > 0) { // left extension; probably the condition can be changed to "qs > qs0 && ts > ts0"
|
|
641
|
+
qseq = &qseq0[rev][qs0];
|
|
642
|
+
l2b_getseq(mi->l2b, tid, ts0, ts, tseq);
|
|
643
|
+
mb_seq_rev(qs - qs0, qseq);
|
|
644
|
+
mb_seq_rev(ts - ts0, tseq);
|
|
645
|
+
mb_align_pair(km, opt, qs - qs0, qseq, ts - ts0, tseq, mat, bw, opt->end_bonus, r->split_inv? opt->zdrop_inv : opt->zdrop, ksw_flag|KSW_EZ_EXTZ_ONLY|KSW_EZ_RIGHT|KSW_EZ_REV_CIGAR, ez);
|
|
646
|
+
if (ez->n_cigar > 0) {
|
|
647
|
+
mb_append_cigar(r, ez->n_cigar, ez->cigar);
|
|
648
|
+
r->p->dp_score += ez->reach_end? ez->mqe : ez->max;
|
|
649
|
+
}
|
|
650
|
+
ts1 = ts - (ez->reach_end? ez->mqe_t + 1 : ez->max_t + 1);
|
|
651
|
+
qs1 = qs - (ez->reach_end? qs - qs0 : ez->max_q + 1);
|
|
652
|
+
mb_seq_rev(qs - qs0, qseq);
|
|
653
|
+
} else ts1 = ts, qs1 = qs;
|
|
654
|
+
te1 = ts, qe1 = qs;
|
|
655
|
+
assert(qs1 >= 0 && ts1 >= 0);
|
|
656
|
+
|
|
657
|
+
{ // adding exact match on the first unfiltered anchor
|
|
658
|
+
te = te1 = a[as1].tpos + 1 - mb_min_int32(a[as1].len>>1, max_back);
|
|
659
|
+
qe = qe1 = a[as1].qpos + 1 - mb_min_int32(a[as1].len>>1, max_back);
|
|
660
|
+
assert(te - ts == qe - qs && te >= ts);
|
|
661
|
+
uint32_t cigar0 = (te - ts) << 4 | MB_CIGAR_MATCH;
|
|
662
|
+
mb_append_cigar(r, 1, &cigar0);
|
|
663
|
+
r->p->dp_score += opt->a * (te - ts);
|
|
664
|
+
ts = te, qs = qe;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
for (i = 1; i < cnt1; ++i) { // gap filling
|
|
668
|
+
const mb_anchor_t *ai = &a[as1 + i];
|
|
669
|
+
if ((ai->flag & MB_SEED_IGNORE) && i != cnt1 - 1) continue;
|
|
670
|
+
te1 = ai->tpos + 1 - mb_min_int32(ai->len>>1, max_back);
|
|
671
|
+
qe1 = ai->qpos + 1 - mb_min_int32(ai->len>>1, max_back);
|
|
672
|
+
if (i == cnt1 - 1 || (a[as1+i].flag&MB_SEED_LONG_JOIN) || (qe1 - qs >= opt->min_ksw_len && te1 - ts >= opt->min_ksw_len)) { // gap filling
|
|
673
|
+
int32_t j, bw1 = bw_long, zdrop_code;
|
|
674
|
+
int64_t d1 = 0; // distance from (qe1,te1) to trim
|
|
675
|
+
// compute ts and te
|
|
676
|
+
if (ai->len > opt->min_len * 2) {
|
|
677
|
+
d1 = te1 - (ai->tpos + 1 - ai->len); // distance to the start of the anchor
|
|
678
|
+
d1 = d1 < qe1 - qs? d1 : qe1 - qs;
|
|
679
|
+
d1 = d1 < te1 - ts? d1 : te1 - ts;
|
|
680
|
+
d1 -= opt->min_len;
|
|
681
|
+
if (d1 < opt->min_len) d1 = 0;
|
|
682
|
+
}
|
|
683
|
+
te = te1 - d1, qe = qe1 - d1;
|
|
684
|
+
// update bandwidth
|
|
685
|
+
if (a[as1+i].flag & MB_SEED_LONG_JOIN)
|
|
686
|
+
bw1 = qe - qs > te - ts? qe - qs : te - ts;
|
|
687
|
+
// perform alignment
|
|
688
|
+
qseq = &qseq0[rev][qs];
|
|
689
|
+
l2b_getseq(mi->l2b, tid, ts, te, tseq);
|
|
690
|
+
mb_align_pair(km, opt, qe - qs, qseq, te - ts, tseq, mat, bw1, -1, opt->zdrop, ksw_flag|KSW_EZ_APPROX_MAX, ez); // first pass: with approximate Z-drop
|
|
691
|
+
// test Z-drop and inversion Z-drop
|
|
692
|
+
if ((zdrop_code = mm_test_zdrop(km, opt, qseq, tseq, ez->n_cigar, ez->cigar, mat, is_sr)) != 0)
|
|
693
|
+
mb_align_pair(km, opt, qe - qs, qseq, te - ts, tseq, mat, bw1, -1, zdrop_code == 2? opt->zdrop_inv : opt->zdrop, ksw_flag, ez); // second pass: lift approximate
|
|
694
|
+
if (kom_dbg_flag & MB_DBG_AN_POS) fprintf(stderr, "AD\t%d\t%ld\t%ld\t%d\t%d\t%d\t%d\n", r->as, (long)ts, (long)te, qs, qe, zdrop_code, ez->zdropped);
|
|
695
|
+
// update CIGAR
|
|
696
|
+
if (ez->n_cigar > 0)
|
|
697
|
+
mb_append_cigar(r, ez->n_cigar, ez->cigar);
|
|
698
|
+
if (ez->zdropped) { // truncated by Z-drop; TODO: sometimes Z-drop kicks in because the next seed placement is wrong. This can be fixed in principle.
|
|
699
|
+
int32_t mlen, blen;
|
|
700
|
+
if (!r->p) {
|
|
701
|
+
assert(ez->n_cigar == 0);
|
|
702
|
+
uint32_t cap = sizeof(mb_extra_t)/4;
|
|
703
|
+
kom_roundup32(cap);
|
|
704
|
+
r->p = (mb_extra_t*)calloc(cap, 4);
|
|
705
|
+
r->p->cap = cap;
|
|
706
|
+
}
|
|
707
|
+
for (j = i - 1; j >= 0; --j)
|
|
708
|
+
if (a[as1 + j].tpos <= ts + ez->max_t)
|
|
709
|
+
break;
|
|
710
|
+
dropped = 1;
|
|
711
|
+
if (j < 0) j = 0;
|
|
712
|
+
r->p->dp_score += ez->max;
|
|
713
|
+
te1 = ts + (ez->max_t + 1);
|
|
714
|
+
qe1 = qs + (ez->max_q + 1);
|
|
715
|
+
mlen = mb_cal_mblen(cnt1 - (j + 1), &a[as1 + j + 1], &blen);
|
|
716
|
+
if (mlen >= opt->min_chain_score) { // TODO: check if this is correct
|
|
717
|
+
mb_split_hit(r, r2, as1 + j + 1 - r->as, qlen, a, mi->l2b);
|
|
718
|
+
if (zdrop_code == 2) r2->split_inv = 1;
|
|
719
|
+
}
|
|
720
|
+
break;
|
|
721
|
+
} else r->p->dp_score += ez->score;
|
|
722
|
+
if (d1 > 0) {
|
|
723
|
+
uint32_t cigar0 = d1 << 4 | MB_CIGAR_MATCH;
|
|
724
|
+
mb_append_cigar(r, 1, &cigar0);
|
|
725
|
+
r->p->dp_score += opt->a * d1;
|
|
726
|
+
te = te1, qe = qe1;
|
|
727
|
+
}
|
|
728
|
+
ts = te, qs = qe;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
if (!dropped && qe < qe0 && te < te0) { // right extension
|
|
733
|
+
qseq = &qseq0[rev][qe];
|
|
734
|
+
l2b_getseq(mi->l2b, tid, te, te0, tseq);
|
|
735
|
+
mb_align_pair(km, opt, qe0 - qe, qseq, te0 - te, tseq, mat, bw, opt->end_bonus, opt->zdrop, ksw_flag|KSW_EZ_EXTZ_ONLY, ez);
|
|
736
|
+
if (ez->n_cigar > 0) {
|
|
737
|
+
mb_append_cigar(r, ez->n_cigar, ez->cigar);
|
|
738
|
+
r->p->dp_score += ez->reach_end? ez->mqe : ez->max;
|
|
739
|
+
}
|
|
740
|
+
te1 = te + (ez->reach_end? ez->mqe_t + 1 : ez->max_t + 1);
|
|
741
|
+
qe1 = qe + (ez->reach_end? qe0 - qe : ez->max_q + 1);
|
|
742
|
+
}
|
|
743
|
+
assert(qe1 <= qlen);
|
|
744
|
+
|
|
745
|
+
r->ts = ts1, r->te = te1;
|
|
746
|
+
if (!rev) r->qs = qs1, r->qe = qe1;
|
|
747
|
+
else r->qs = qlen - qe1, r->qe = qlen - qs1;
|
|
748
|
+
|
|
749
|
+
assert(te1 - ts1 <= te0 - ts0);
|
|
750
|
+
if (r->p) {
|
|
751
|
+
l2b_getseq(mi->l2b, tid, ts1, te1, tseq);
|
|
752
|
+
qseq = &qseq0[r->rev][qs1];
|
|
753
|
+
mb_update_extra(km, r, qseq, tseq, mat, opt->q, opt->e, opt->flag, !is_sr);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
kfree(km, tseq);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
static int mb_align1_inv(void *km, const mb_opt_t *opt, const mb_idx_t *mi, int qlen, uint8_t *qseq0[2], l2b_meth_t mt, const mb_hit_t *r1, const mb_hit_t *r2, mb_hit_t *r_inv, ksw_extz_t *ez)
|
|
760
|
+
{ // NB: this doesn't work with the qstrand mode
|
|
761
|
+
int tl, ql, score, ret = 0, q_off, t_off;
|
|
762
|
+
uint8_t *tseq, *qseq;
|
|
763
|
+
int8_t mat[25];
|
|
764
|
+
void *qp;
|
|
765
|
+
|
|
766
|
+
memset(r_inv, 0, sizeof(mb_hit_t));
|
|
767
|
+
if (!(r1->split&1) || !(r2->split&2)) return 0;
|
|
768
|
+
if (r1->id != r1->parent && r1->parent != MB_PARENT_TMP_PRI) return 0;
|
|
769
|
+
if (r2->id != r2->parent && r2->parent != MB_PARENT_TMP_PRI) return 0;
|
|
770
|
+
if (r1->tid != r2->tid || r1->rev != r2->rev) return 0;
|
|
771
|
+
ql = r1->rev? r1->qs - r2->qe : r2->qs - r1->qe;
|
|
772
|
+
tl = r2->ts - r1->te;
|
|
773
|
+
if (ql < opt->min_chain_score || ql > opt->max_gap) return 0;
|
|
774
|
+
if (tl < opt->min_chain_score || tl > opt->max_gap) return 0;
|
|
775
|
+
|
|
776
|
+
if (!r1->rev) mt = l2b_meth_rev(mt); // TODO: check if this is correct
|
|
777
|
+
ksw_gen_nt4_mat(mat, opt->a, opt->b, opt->b_ts, opt->b_ambi, (int)mt);
|
|
778
|
+
|
|
779
|
+
tseq = (uint8_t*)kmalloc(km, tl);
|
|
780
|
+
l2b_getseq(mi->l2b, r1->tid, r1->te, r2->ts, tseq);
|
|
781
|
+
qseq = r1->rev? &qseq0[0][r2->qe] : &qseq0[1][qlen - r2->qs];
|
|
782
|
+
|
|
783
|
+
mb_seq_rev(ql, qseq);
|
|
784
|
+
mb_seq_rev(tl, tseq);
|
|
785
|
+
qp = ksw_ll_qinit(km, 2, ql, qseq, 5, mat);
|
|
786
|
+
score = ksw_ll_i16(qp, tl, tseq, opt->q, opt->e, &q_off, &t_off);
|
|
787
|
+
kfree(km, qp);
|
|
788
|
+
mb_seq_rev(ql, qseq);
|
|
789
|
+
mb_seq_rev(tl, tseq);
|
|
790
|
+
if (score < opt->min_dp_max * opt->a) goto end_align1_inv;
|
|
791
|
+
q_off = ql - (q_off + 1), t_off = tl - (t_off + 1);
|
|
792
|
+
mb_align_pair(km, opt, ql - q_off, qseq + q_off, tl - t_off, tseq + t_off, mat, (int)(opt->bw * 1.5), -1, opt->zdrop, KSW_EZ_EXTZ_ONLY, ez);
|
|
793
|
+
if (ez->n_cigar == 0) goto end_align1_inv; // should never be here
|
|
794
|
+
mb_append_cigar(r_inv, ez->n_cigar, ez->cigar);
|
|
795
|
+
r_inv->p->dp_score = ez->max;
|
|
796
|
+
r_inv->id = -1;
|
|
797
|
+
r_inv->parent = MB_PARENT_UNSET;
|
|
798
|
+
r_inv->inv = 1;
|
|
799
|
+
r_inv->rev = !r1->rev;
|
|
800
|
+
r_inv->tid = r1->tid;
|
|
801
|
+
if (r_inv->rev == 0) {
|
|
802
|
+
r_inv->qs = r2->qe + q_off;
|
|
803
|
+
r_inv->qe = r_inv->qs + ez->max_q + 1;
|
|
804
|
+
} else {
|
|
805
|
+
r_inv->qe = r2->qs - q_off;
|
|
806
|
+
r_inv->qs = r_inv->qe - (ez->max_q + 1);
|
|
807
|
+
}
|
|
808
|
+
r_inv->ts = r1->te + t_off;
|
|
809
|
+
r_inv->te = r_inv->ts + ez->max_t + 1;
|
|
810
|
+
mb_update_extra(km, r_inv, &qseq[q_off], &tseq[t_off], mat, opt->q, opt->e, opt->flag, mb_is_sr_mode(opt, qlen));
|
|
811
|
+
ret = 1;
|
|
812
|
+
end_align1_inv:
|
|
813
|
+
kfree(km, tseq);
|
|
814
|
+
return ret;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
static inline mb_hit_t *mb_insert_reg(const mb_hit_t *r, int i, int *n_regs, mb_hit_t *regs)
|
|
818
|
+
{
|
|
819
|
+
regs = (mb_hit_t*)realloc(regs, (*n_regs + 1) * sizeof(mb_hit_t));
|
|
820
|
+
if (i + 1 != *n_regs)
|
|
821
|
+
memmove(®s[i + 2], ®s[i + 1], sizeof(mb_hit_t) * (*n_regs - i - 1));
|
|
822
|
+
regs[i + 1] = *r;
|
|
823
|
+
++*n_regs;
|
|
824
|
+
return regs;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
static inline void mb_count_gaps(const mb_hit_t *r, int32_t *n_gap_, int32_t *n_gapo_)
|
|
828
|
+
{
|
|
829
|
+
uint32_t i;
|
|
830
|
+
int32_t n_gapo = 0, n_gap = 0;
|
|
831
|
+
*n_gap_ = *n_gapo_ = -1;
|
|
832
|
+
if (r->p == 0) return;
|
|
833
|
+
for (i = 0; i < r->p->n_cigar; ++i) {
|
|
834
|
+
int32_t op = r->p->cigar[i] & 0xf, len = r->p->cigar[i] >> 4;
|
|
835
|
+
if (op == MB_CIGAR_INS || op == MB_CIGAR_DEL)
|
|
836
|
+
++n_gapo, n_gap += len;
|
|
837
|
+
}
|
|
838
|
+
*n_gap_ = n_gap, *n_gapo_ = n_gapo;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
static double mb_event_identity(const mb_hit_t *r)
|
|
842
|
+
{
|
|
843
|
+
int32_t n_gap, n_gapo;
|
|
844
|
+
if (r->p == 0) return -1.0f;
|
|
845
|
+
mb_count_gaps(r, &n_gap, &n_gapo);
|
|
846
|
+
return (double)r->mlen / (r->blen + r->p->n_ambi - n_gap + n_gapo);
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
static int32_t mb_recal_max_dp(const mb_hit_t *r, double b2, int32_t match_sc, int32_t qlen)
|
|
850
|
+
{
|
|
851
|
+
uint32_t i;
|
|
852
|
+
int32_t n_gap = 0, n_mis;
|
|
853
|
+
double gap_cost = 0.0;
|
|
854
|
+
if (r->p == 0) return -1;
|
|
855
|
+
for (i = 0; i < r->p->n_cigar; ++i) {
|
|
856
|
+
int32_t op = r->p->cigar[i] & 0xf, len = r->p->cigar[i] >> 4;
|
|
857
|
+
if (op == MB_CIGAR_INS || op == MB_CIGAR_DEL) {
|
|
858
|
+
gap_cost += b2 * mb_log2(1.0 + len);
|
|
859
|
+
n_gap += len;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
n_mis = r->blen + r->p->n_ambi - r->mlen - n_gap;
|
|
863
|
+
n_mis += (int32_t)((qlen - (r->qe - r->qs)) / b2 + .499);
|
|
864
|
+
return (int32_t)(match_sc * (r->mlen - b2 * n_mis - gap_cost) + .499);
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
void mb_update_dp_max(int qlen, int n_regs, mb_hit_t *regs, double frac, int a, int b)
|
|
868
|
+
{
|
|
869
|
+
int32_t max = -1, max2 = -1, i, max_i = -1, max2_i = -1;
|
|
870
|
+
double div, b2;
|
|
871
|
+
if (n_regs < 2) return;
|
|
872
|
+
for (i = 0; i < n_regs; ++i) {
|
|
873
|
+
mb_hit_t *r = ®s[i];
|
|
874
|
+
if (r->p == 0) continue;
|
|
875
|
+
if (r->p->dp_max > max) max2 = max, max2_i = max_i, max = r->p->dp_max, max_i = i;
|
|
876
|
+
else if (r->p->dp_max > max2) max2 = r->p->dp_max, max2_i = i;
|
|
877
|
+
}
|
|
878
|
+
if (max_i < 0 || max2_i < 0) return;
|
|
879
|
+
if (regs[max_i].qe - regs[max_i].qs < qlen * frac) return;
|
|
880
|
+
if (regs[max2_i].qe - regs[max2_i].qs < (regs[max_i].qe - regs[max_i].qs) * sqrt(frac)) return;
|
|
881
|
+
div = 1. - mb_event_identity(®s[max_i]);
|
|
882
|
+
if (div < 0.02) div = 0.02;
|
|
883
|
+
b2 = 0.5 / div; // max value: 25
|
|
884
|
+
if (b2 * a < b) b2 = (double)a / b;
|
|
885
|
+
for (i = 0, max = -1, max_i = -1; i < n_regs; ++i) {
|
|
886
|
+
mb_hit_t *r = ®s[i];
|
|
887
|
+
if (r->p == 0) continue;
|
|
888
|
+
r->p->dp_max = mb_recal_max_dp(r, b2, a, qlen);
|
|
889
|
+
if (r->p->dp_max < 0) r->p->dp_max = 0;
|
|
890
|
+
if (max < r->p->dp_max) max = r->p->dp_max, max_i = i;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
mb_hit_t *mb_align_skeleton(void *km, const mb_opt_t *opt, const mb_idx_t *mi, int qlen, const uint8_t *qseq, l2b_meth_t mt, int *n_regs_, mb_hit_t *regs, mb_anchor_t *a)
|
|
895
|
+
{
|
|
896
|
+
int32_t i, n_regs = *n_regs_, n_a;
|
|
897
|
+
uint8_t *qseq0[2];
|
|
898
|
+
ksw_extz_t ez;
|
|
899
|
+
|
|
900
|
+
// encode the query sequence
|
|
901
|
+
qseq0[0] = Kmalloc(km, uint8_t, qlen * 2);
|
|
902
|
+
qseq0[1] = qseq0[0] + qlen;
|
|
903
|
+
for (i = 0; i < qlen; ++i)
|
|
904
|
+
qseq0[0][i] = qseq[i], qseq0[1][qlen - 1 - i] = qseq0[0][i] < 4? 3 - qseq0[0][i] : 4;
|
|
905
|
+
|
|
906
|
+
// align through seed hits
|
|
907
|
+
n_a = mb_squeeze_a(km, n_regs, regs, a);
|
|
908
|
+
memset(&ez, 0, sizeof(ksw_extz_t));
|
|
909
|
+
for (i = 0; i < n_regs; ++i) {
|
|
910
|
+
mb_hit_t r2; // only used for inversion
|
|
911
|
+
mb_align1(km, opt, mi, qlen, qseq0, mt, ®s[i], &r2, n_a, a, &ez);
|
|
912
|
+
if (r2.cnt > 0) regs = mb_insert_reg(&r2, i, &n_regs, regs);
|
|
913
|
+
if (i > 0 && regs[i].split_inv) {
|
|
914
|
+
if (mb_align1_inv(km, opt, mi, qlen, qseq0, mt, ®s[i-1], ®s[i], &r2, &ez)) {
|
|
915
|
+
regs = mb_insert_reg(&r2, i, &n_regs, regs);
|
|
916
|
+
++i; // skip the inserted INV alignment
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
kfree(km, qseq0[0]);
|
|
921
|
+
kfree(km, ez.cigar);
|
|
922
|
+
mb_filter_hits(opt, qlen, &n_regs, regs);
|
|
923
|
+
if (!mb_is_sr_mode(opt, qlen)) {
|
|
924
|
+
mb_update_dp_max(qlen, n_regs, regs, 0.9, opt->a, opt->b);
|
|
925
|
+
mb_filter_hits(opt, qlen, &n_regs, regs);
|
|
926
|
+
}
|
|
927
|
+
mb_hit_sort(km, &n_regs, regs);
|
|
928
|
+
*n_regs_ = n_regs;
|
|
929
|
+
return regs;
|
|
930
|
+
}
|