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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +119 -0
  4. data/ext/minibwa/extconf.rb +105 -0
  5. data/ext/minibwa/mb_buffer.c +113 -0
  6. data/ext/minibwa/mb_hit.c +192 -0
  7. data/ext/minibwa/mb_index.c +462 -0
  8. data/ext/minibwa/mb_index_build.c +174 -0
  9. data/ext/minibwa/mb_options.c +301 -0
  10. data/ext/minibwa/minibwa/LICENSE.txt +37 -0
  11. data/ext/minibwa/minibwa/align.c +930 -0
  12. data/ext/minibwa/minibwa/bseq.h +45 -0
  13. data/ext/minibwa/minibwa/bwt.c +715 -0
  14. data/ext/minibwa/minibwa/bwt.h +86 -0
  15. data/ext/minibwa/minibwa/cs.c +161 -0
  16. data/ext/minibwa/minibwa/format.c +356 -0
  17. data/ext/minibwa/minibwa/index.c +342 -0
  18. data/ext/minibwa/minibwa/kalloc.c +224 -0
  19. data/ext/minibwa/minibwa/kalloc.h +54 -0
  20. data/ext/minibwa/minibwa/ketopt.h +123 -0
  21. data/ext/minibwa/minibwa/kommon.c +374 -0
  22. data/ext/minibwa/minibwa/kommon.h +85 -0
  23. data/ext/minibwa/minibwa/kseq.h +256 -0
  24. data/ext/minibwa/minibwa/ksort.h +163 -0
  25. data/ext/minibwa/minibwa/ksw2.h +220 -0
  26. data/ext/minibwa/minibwa/ksw2_extd2_sse.c +403 -0
  27. data/ext/minibwa/minibwa/ksw2_extz2_sse.c +296 -0
  28. data/ext/minibwa/minibwa/ksw2_ll_sse.c +341 -0
  29. data/ext/minibwa/minibwa/kthread.h +15 -0
  30. data/ext/minibwa/minibwa/l2bit.c +479 -0
  31. data/ext/minibwa/minibwa/l2bit.h +72 -0
  32. data/ext/minibwa/minibwa/lchain.c +231 -0
  33. data/ext/minibwa/minibwa/libsais.c +6985 -0
  34. data/ext/minibwa/minibwa/libsais.h +106 -0
  35. data/ext/minibwa/minibwa/libsais64.c +7064 -0
  36. data/ext/minibwa/minibwa/libsais64.h +81 -0
  37. data/ext/minibwa/minibwa/map-algo.c +769 -0
  38. data/ext/minibwa/minibwa/mbpriv.h +148 -0
  39. data/ext/minibwa/minibwa/minibwa.h +176 -0
  40. data/ext/minibwa/minibwa/options.c +116 -0
  41. data/ext/minibwa/minibwa/pe.c +559 -0
  42. data/ext/minibwa/minibwa/s2n-lite.h +59 -0
  43. data/ext/minibwa/minibwa/seed.c +354 -0
  44. data/ext/minibwa/minibwa.c +67 -0
  45. data/ext/minibwa/minibwa.h +51 -0
  46. data/lib/minibwa/hit.rb +110 -0
  47. data/lib/minibwa/index.rb +77 -0
  48. data/lib/minibwa/options.rb +235 -0
  49. data/lib/minibwa/sam.rb +85 -0
  50. data/lib/minibwa/version.rb +6 -0
  51. data/lib/minibwa.rb +11 -0
  52. metadata +88 -0
@@ -0,0 +1,296 @@
1
+ #include <string.h>
2
+ #include <assert.h>
3
+ #include "ksw2.h"
4
+
5
+ #if defined(__ARM_NEON)
6
+ #define __SSE4_1__
7
+ #include "s2n-lite.h"
8
+ #elif defined(__SSE4_1__)
9
+ #include <smmintrin.h>
10
+ #elif defined(__SSE2__)
11
+ #include <xmmintrin.h>
12
+ #else
13
+ #error "Missing SSE2 or NEON intrinsics"
14
+ #endif
15
+
16
+ void ksw_extz2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat, int8_t q, int8_t e, int w, int zdrop, int end_bonus, int flag, ksw_extz_t *ez)
17
+ {
18
+ #define __dp_code_block1 \
19
+ z = _mm_add_epi8(_mm_load_si128(&s[t]), qe2_); \
20
+ xt1 = _mm_load_si128(&x[t]); /* xt1 <- x[r-1][t..t+15] */ \
21
+ tmp = _mm_srli_si128(xt1, 15); /* tmp <- x[r-1][t+15] */ \
22
+ xt1 = _mm_or_si128(_mm_slli_si128(xt1, 1), x1_); /* xt1 <- x[r-1][t-1..t+14] */ \
23
+ x1_ = tmp; \
24
+ vt1 = _mm_load_si128(&v[t]); /* vt1 <- v[r-1][t..t+15] */ \
25
+ tmp = _mm_srli_si128(vt1, 15); /* tmp <- v[r-1][t+15] */ \
26
+ vt1 = _mm_or_si128(_mm_slli_si128(vt1, 1), v1_); /* vt1 <- v[r-1][t-1..t+14] */ \
27
+ v1_ = tmp; \
28
+ a = _mm_add_epi8(xt1, vt1); /* a <- x[r-1][t-1..t+14] + v[r-1][t-1..t+14] */ \
29
+ ut = _mm_load_si128(&u[t]); /* ut <- u[t..t+15] */ \
30
+ b = _mm_add_epi8(_mm_load_si128(&y[t]), ut); /* b <- y[r-1][t..t+15] + u[r-1][t..t+15] */
31
+
32
+ #define __dp_code_block2 \
33
+ z = _mm_max_epu8(z, b); /* z = max(z, b); this works because both are non-negative */ \
34
+ z = _mm_min_epu8(z, max_sc_); \
35
+ _mm_store_si128(&u[t], _mm_sub_epi8(z, vt1)); /* u[r][t..t+15] <- z - v[r-1][t-1..t+14] */ \
36
+ _mm_store_si128(&v[t], _mm_sub_epi8(z, ut)); /* v[r][t..t+15] <- z - u[r-1][t..t+15] */ \
37
+ z = _mm_sub_epi8(z, q_); \
38
+ a = _mm_sub_epi8(a, z); \
39
+ b = _mm_sub_epi8(b, z);
40
+
41
+ int r, t, qe = q + e, n_col_, *off = 0, *off_end = 0, tlen_, qlen_, last_st, last_en, wl, wr, max_sc, min_sc;
42
+ int with_cigar = !(flag&KSW_EZ_SCORE_ONLY), approx_max = !!(flag&KSW_EZ_APPROX_MAX);
43
+ int32_t *H = 0, H0 = 0, last_H0_t = 0;
44
+ uint8_t *qr, *sf, *mem, *mem2 = 0;
45
+ __m128i q_, qe2_, zero_, flag1_, flag2_, flag8_, flag16_, sc_mch_, sc_mis_, sc_N_, m1_, max_sc_;
46
+ __m128i *u, *v, *x, *y, *s, *p = 0;
47
+
48
+ ksw_reset_extz(ez);
49
+ if (m <= 0 || qlen <= 0 || tlen <= 0) return;
50
+
51
+ zero_ = _mm_set1_epi8(0);
52
+ q_ = _mm_set1_epi8(q);
53
+ qe2_ = _mm_set1_epi8((q + e) * 2);
54
+ flag1_ = _mm_set1_epi8(1);
55
+ flag2_ = _mm_set1_epi8(2);
56
+ flag8_ = _mm_set1_epi8(0x08);
57
+ flag16_ = _mm_set1_epi8(0x10);
58
+ sc_mch_ = _mm_set1_epi8(mat[0]);
59
+ sc_mis_ = _mm_set1_epi8(mat[1]);
60
+ sc_N_ = mat[m*m-1] == 0? _mm_set1_epi8(-e) : _mm_set1_epi8(mat[m*m-1]);
61
+ m1_ = _mm_set1_epi8(m - 1); // wildcard
62
+ max_sc_ = _mm_set1_epi8(mat[0] + (q + e) * 2);
63
+
64
+ if (w < 0) w = tlen > qlen? tlen : qlen;
65
+ wl = wr = w;
66
+ tlen_ = (tlen + 15) / 16;
67
+ n_col_ = qlen < tlen? qlen : tlen;
68
+ n_col_ = ((n_col_ < w + 1? n_col_ : w + 1) + 15) / 16 + 1;
69
+ qlen_ = (qlen + 15) / 16;
70
+ for (t = 1, max_sc = mat[0], min_sc = mat[1]; t < m * m; ++t) {
71
+ max_sc = max_sc > mat[t]? max_sc : mat[t];
72
+ min_sc = min_sc < mat[t]? min_sc : mat[t];
73
+ }
74
+ if (-min_sc > 2 * (q + e)) return; // otherwise, we won't see any mismatches
75
+
76
+ mem = (uint8_t*)kcalloc(km, tlen_ * 6 + qlen_ + 1, 16);
77
+ u = (__m128i*)(((size_t)mem + 15) >> 4 << 4); // 16-byte aligned
78
+ v = u + tlen_, x = v + tlen_, y = x + tlen_, s = y + tlen_, sf = (uint8_t*)(s + tlen_), qr = sf + tlen_ * 16;
79
+ if (!approx_max) {
80
+ H = (int32_t*)kmalloc(km, tlen_ * 16 * 4);
81
+ for (t = 0; t < tlen_ * 16; ++t) H[t] = KSW_NEG_INF;
82
+ }
83
+ if (with_cigar) {
84
+ mem2 = (uint8_t*)kmalloc(km, ((size_t)(qlen + tlen - 1) * n_col_ + 1) * 16);
85
+ p = (__m128i*)(((size_t)mem2 + 15) >> 4 << 4);
86
+ off = (int*)kmalloc(km, (qlen + tlen - 1) * sizeof(int) * 2);
87
+ off_end = off + qlen + tlen - 1;
88
+ }
89
+
90
+ for (t = 0; t < qlen; ++t) qr[t] = query[qlen - 1 - t];
91
+ memcpy(sf, target, tlen);
92
+
93
+ for (r = 0, last_st = last_en = -1; r < qlen + tlen - 1; ++r) {
94
+ int st = 0, en = tlen - 1, st0, en0, st_, en_;
95
+ int8_t x1, v1;
96
+ uint8_t *qrr = qr + (qlen - 1 - r), *u8 = (uint8_t*)u, *v8 = (uint8_t*)v;
97
+ __m128i x1_, v1_;
98
+ // find the boundaries
99
+ if (st < r - qlen + 1) st = r - qlen + 1;
100
+ if (en > r) en = r;
101
+ if (st < (r-wr+1)>>1) st = (r-wr+1)>>1; // take the ceil
102
+ if (en > (r+wl)>>1) en = (r+wl)>>1; // take the floor
103
+ if (st > en) {
104
+ ez->zdropped = 1;
105
+ break;
106
+ }
107
+ st0 = st, en0 = en;
108
+ st = st / 16 * 16, en = (en + 16) / 16 * 16 - 1;
109
+ // set boundary conditions
110
+ if (st > 0) {
111
+ if (st - 1 >= last_st && st - 1 <= last_en)
112
+ x1 = ((uint8_t*)x)[st - 1], v1 = v8[st - 1]; // (r-1,s-1) calculated in the last round
113
+ else x1 = v1 = 0; // not calculated; set to zeros
114
+ } else x1 = 0, v1 = r? q : 0;
115
+ if (en >= r) ((uint8_t*)y)[r] = 0, u8[r] = r? q : 0;
116
+ // loop fission: set scores first
117
+ if (!(flag & KSW_EZ_GENERIC_SC)) {
118
+ for (t = st0; t <= en0; t += 16) {
119
+ __m128i sq, st, tmp, mask;
120
+ sq = _mm_loadu_si128((__m128i*)&sf[t]);
121
+ st = _mm_loadu_si128((__m128i*)&qrr[t]);
122
+ mask = _mm_or_si128(_mm_cmpeq_epi8(sq, m1_), _mm_cmpeq_epi8(st, m1_));
123
+ tmp = _mm_cmpeq_epi8(sq, st);
124
+ #ifdef __SSE4_1__
125
+ tmp = _mm_blendv_epi8(sc_mis_, sc_mch_, tmp);
126
+ tmp = _mm_blendv_epi8(tmp, sc_N_, mask);
127
+ #else
128
+ tmp = _mm_or_si128(_mm_andnot_si128(tmp, sc_mis_), _mm_and_si128(tmp, sc_mch_));
129
+ tmp = _mm_or_si128(_mm_andnot_si128(mask, tmp), _mm_and_si128(mask, sc_N_));
130
+ #endif
131
+ _mm_storeu_si128((__m128i*)((uint8_t*)s + t), tmp);
132
+ }
133
+ } else {
134
+ for (t = st0; t <= en0; ++t)
135
+ ((uint8_t*)s)[t] = mat[sf[t] * m + qrr[t]];
136
+ }
137
+ // core loop
138
+ x1_ = _mm_cvtsi32_si128(x1);
139
+ v1_ = _mm_cvtsi32_si128(v1);
140
+ st_ = st / 16, en_ = en / 16;
141
+ assert(en_ - st_ + 1 <= n_col_);
142
+ if (!with_cigar) { // score only
143
+ for (t = st_; t <= en_; ++t) {
144
+ __m128i z, a, b, xt1, vt1, ut, tmp;
145
+ __dp_code_block1;
146
+ #ifdef __SSE4_1__
147
+ z = _mm_max_epi8(z, a); // z = z > a? z : a (signed)
148
+ #else // we need to emulate SSE4.1 intrinsics _mm_max_epi8()
149
+ z = _mm_and_si128(z, _mm_cmpgt_epi8(z, zero_)); // z = z > 0? z : 0;
150
+ z = _mm_max_epu8(z, a); // z = max(z, a); this works because both are non-negative
151
+ #endif
152
+ __dp_code_block2;
153
+ #ifdef __SSE4_1__
154
+ _mm_store_si128(&x[t], _mm_max_epi8(a, zero_));
155
+ _mm_store_si128(&y[t], _mm_max_epi8(b, zero_));
156
+ #else
157
+ tmp = _mm_cmpgt_epi8(a, zero_);
158
+ _mm_store_si128(&x[t], _mm_and_si128(a, tmp));
159
+ tmp = _mm_cmpgt_epi8(b, zero_);
160
+ _mm_store_si128(&y[t], _mm_and_si128(b, tmp));
161
+ #endif
162
+ }
163
+ } else if (!(flag&KSW_EZ_RIGHT)) { // gap left-alignment
164
+ __m128i *pr = p + (size_t)r * n_col_ - st_;
165
+ off[r] = st, off_end[r] = en;
166
+ for (t = st_; t <= en_; ++t) {
167
+ __m128i d, z, a, b, xt1, vt1, ut, tmp;
168
+ __dp_code_block1;
169
+ d = _mm_and_si128(_mm_cmpgt_epi8(a, z), flag1_); // d = a > z? 1 : 0
170
+ #ifdef __SSE4_1__
171
+ z = _mm_max_epi8(z, a); // z = z > a? z : a (signed)
172
+ tmp = _mm_cmpgt_epi8(b, z);
173
+ d = _mm_blendv_epi8(d, flag2_, tmp); // d = b > z? 2 : d
174
+ #else // we need to emulate SSE4.1 intrinsics _mm_max_epi8() and _mm_blendv_epi8()
175
+ z = _mm_and_si128(z, _mm_cmpgt_epi8(z, zero_)); // z = z > 0? z : 0;
176
+ z = _mm_max_epu8(z, a); // z = max(z, a); this works because both are non-negative
177
+ tmp = _mm_cmpgt_epi8(b, z);
178
+ d = _mm_or_si128(_mm_andnot_si128(tmp, d), _mm_and_si128(tmp, flag2_)); // d = b > z? 2 : d; emulating blendv
179
+ #endif
180
+ __dp_code_block2;
181
+ tmp = _mm_cmpgt_epi8(a, zero_);
182
+ _mm_store_si128(&x[t], _mm_and_si128(tmp, a));
183
+ d = _mm_or_si128(d, _mm_and_si128(tmp, flag8_)); // d = a > 0? 0x08 : 0
184
+ tmp = _mm_cmpgt_epi8(b, zero_);
185
+ _mm_store_si128(&y[t], _mm_and_si128(tmp, b));
186
+ d = _mm_or_si128(d, _mm_and_si128(tmp, flag16_)); // d = b > 0? 0x10 : 0
187
+ _mm_store_si128(&pr[t], d);
188
+ }
189
+ } else { // gap right-alignment
190
+ __m128i *pr = p + (size_t)r * n_col_ - st_;
191
+ off[r] = st, off_end[r] = en;
192
+ for (t = st_; t <= en_; ++t) {
193
+ __m128i d, z, a, b, xt1, vt1, ut, tmp;
194
+ __dp_code_block1;
195
+ d = _mm_andnot_si128(_mm_cmpgt_epi8(z, a), flag1_); // d = z > a? 0 : 1
196
+ #ifdef __SSE4_1__
197
+ z = _mm_max_epi8(z, a); // z = z > a? z : a (signed)
198
+ tmp = _mm_cmpgt_epi8(z, b);
199
+ d = _mm_blendv_epi8(flag2_, d, tmp); // d = z > b? d : 2
200
+ #else // we need to emulate SSE4.1 intrinsics _mm_max_epi8() and _mm_blendv_epi8()
201
+ z = _mm_and_si128(z, _mm_cmpgt_epi8(z, zero_)); // z = z > 0? z : 0;
202
+ z = _mm_max_epu8(z, a); // z = max(z, a); this works because both are non-negative
203
+ tmp = _mm_cmpgt_epi8(z, b);
204
+ d = _mm_or_si128(_mm_andnot_si128(tmp, flag2_), _mm_and_si128(tmp, d)); // d = z > b? d : 2; emulating blendv
205
+ #endif
206
+ __dp_code_block2;
207
+ tmp = _mm_cmpgt_epi8(zero_, a);
208
+ _mm_store_si128(&x[t], _mm_andnot_si128(tmp, a));
209
+ d = _mm_or_si128(d, _mm_andnot_si128(tmp, flag8_)); // d = 0 > a? 0 : 0x08
210
+ tmp = _mm_cmpgt_epi8(zero_, b);
211
+ _mm_store_si128(&y[t], _mm_andnot_si128(tmp, b));
212
+ d = _mm_or_si128(d, _mm_andnot_si128(tmp, flag16_)); // d = 0 > b? 0 : 0x10
213
+ _mm_store_si128(&pr[t], d);
214
+ }
215
+ }
216
+ if (!approx_max) { // find the exact max with a 32-bit score array
217
+ int32_t max_H, max_t;
218
+ // compute H[], max_H and max_t
219
+ if (r > 0) {
220
+ int32_t HH[4], tt[4], en1 = st0 + (en0 - st0) / 4 * 4, i;
221
+ __m128i max_H_, max_t_, qe_;
222
+ max_H = H[en0] = en0 > 0? H[en0-1] + u8[en0] - qe : H[en0] + v8[en0] - qe; // special casing the last element
223
+ max_t = en0;
224
+ max_H_ = _mm_set1_epi32(max_H);
225
+ max_t_ = _mm_set1_epi32(max_t);
226
+ qe_ = _mm_set1_epi32(q + e);
227
+ for (t = st0; t < en1; t += 4) { // this implements: H[t]+=v8[t]-qe; if(H[t]>max_H) max_H=H[t],max_t=t;
228
+ __m128i H1, tmp, t_;
229
+ H1 = _mm_loadu_si128((__m128i*)&H[t]);
230
+ t_ = _mm_setr_epi32(v8[t], v8[t+1], v8[t+2], v8[t+3]);
231
+ H1 = _mm_add_epi32(H1, t_);
232
+ H1 = _mm_sub_epi32(H1, qe_);
233
+ _mm_storeu_si128((__m128i*)&H[t], H1);
234
+ t_ = _mm_set1_epi32(t);
235
+ tmp = _mm_cmpgt_epi32(H1, max_H_);
236
+ #ifdef __SSE4_1__
237
+ max_H_ = _mm_blendv_epi8(max_H_, H1, tmp);
238
+ max_t_ = _mm_blendv_epi8(max_t_, t_, tmp);
239
+ #else
240
+ max_H_ = _mm_or_si128(_mm_and_si128(tmp, H1), _mm_andnot_si128(tmp, max_H_));
241
+ max_t_ = _mm_or_si128(_mm_and_si128(tmp, t_), _mm_andnot_si128(tmp, max_t_));
242
+ #endif
243
+ }
244
+ _mm_storeu_si128((__m128i*)HH, max_H_);
245
+ _mm_storeu_si128((__m128i*)tt, max_t_);
246
+ for (i = 0; i < 4; ++i)
247
+ if (max_H < HH[i]) max_H = HH[i], max_t = tt[i] + i;
248
+ for (; t < en0; ++t) { // for the rest of values that haven't been computed with SSE
249
+ H[t] += (int32_t)v8[t] - qe;
250
+ if (H[t] > max_H)
251
+ max_H = H[t], max_t = t;
252
+ }
253
+ } else H[0] = v8[0] - qe - qe, max_H = H[0], max_t = 0; // special casing r==0
254
+ // update ez
255
+ if (en0 == tlen - 1 && H[en0] > ez->mte)
256
+ ez->mte = H[en0], ez->mte_q = r - en0;
257
+ if (r - st0 == qlen - 1 && H[st0] > ez->mqe)
258
+ ez->mqe = H[st0], ez->mqe_t = st0;
259
+ if (ksw_apply_zdrop(ez, 1, max_H, r, max_t, zdrop, e)) break;
260
+ if (r == qlen + tlen - 2 && en0 == tlen - 1)
261
+ ez->score = H[tlen - 1];
262
+ } else { // find approximate max; Z-drop might be inaccurate, too.
263
+ if (r > 0) {
264
+ if (last_H0_t >= st0 && last_H0_t <= en0 && last_H0_t + 1 >= st0 && last_H0_t + 1 <= en0) {
265
+ int32_t d0 = v8[last_H0_t] - qe;
266
+ int32_t d1 = u8[last_H0_t + 1] - qe;
267
+ if (d0 > d1) H0 += d0;
268
+ else H0 += d1, ++last_H0_t;
269
+ } else if (last_H0_t >= st0 && last_H0_t <= en0) {
270
+ H0 += v8[last_H0_t] - qe;
271
+ } else {
272
+ ++last_H0_t, H0 += u8[last_H0_t] - qe;
273
+ }
274
+ if ((flag & KSW_EZ_APPROX_DROP) && ksw_apply_zdrop(ez, 1, H0, r, last_H0_t, zdrop, e)) break;
275
+ } else H0 = v8[0] - qe - qe, last_H0_t = 0;
276
+ if (r == qlen + tlen - 2 && en0 == tlen - 1)
277
+ ez->score = H0;
278
+ }
279
+ last_st = st, last_en = en;
280
+ //for (t = st0; t <= en0; ++t) printf("(%d,%d)\t(%d,%d,%d,%d)\t%d\n", r, t, ((int8_t*)u)[t], ((int8_t*)v)[t], ((int8_t*)x)[t], ((int8_t*)y)[t], H[t]); // for debugging
281
+ }
282
+ kfree(km, mem);
283
+ if (!approx_max) kfree(km, H);
284
+ if (with_cigar) { // backtrack
285
+ int rev_cigar = !!(flag & KSW_EZ_REV_CIGAR);
286
+ if (!ez->zdropped && !(flag&KSW_EZ_EXTZ_ONLY)) {
287
+ ksw_backtrack(km, 1, rev_cigar, 0, (uint8_t*)p, off, off_end, n_col_*16, tlen-1, qlen-1, &ez->m_cigar, &ez->n_cigar, &ez->cigar);
288
+ } else if ((flag&KSW_EZ_EXTZ_ONLY) && ez->mqe + end_bonus > (int)ez->max) {
289
+ ez->reach_end = 1;
290
+ ksw_backtrack(km, 1, rev_cigar, 0, (uint8_t*)p, off, off_end, n_col_*16, ez->mqe_t, qlen-1, &ez->m_cigar, &ez->n_cigar, &ez->cigar);
291
+ } else if (ez->max_t >= 0 && ez->max_q >= 0) {
292
+ ksw_backtrack(km, 1, rev_cigar, 0, (uint8_t*)p, off, off_end, n_col_*16, ez->max_t, ez->max_q, &ez->m_cigar, &ez->n_cigar, &ez->cigar);
293
+ }
294
+ kfree(km, mem2); kfree(km, off);
295
+ }
296
+ }
@@ -0,0 +1,341 @@
1
+ #include <stdlib.h>
2
+ #include <stdint.h>
3
+ #include <string.h>
4
+ #include "ksw2.h"
5
+
6
+ #if defined(__ARM_NEON)
7
+ #include "s2n-lite.h"
8
+ #elif defined(__SSE2__)
9
+ #include <xmmintrin.h>
10
+ #else
11
+ #error "Missing SSE2 or NEON intrinsics"
12
+ #endif
13
+
14
+ #ifdef __GNUC__
15
+ #define LIKELY(x) __builtin_expect((x),1)
16
+ #define UNLIKELY(x) __builtin_expect((x),0)
17
+ #else
18
+ #define LIKELY(x) (x)
19
+ #define UNLIKELY(x) (x)
20
+ #endif
21
+
22
+ #ifndef Kgrow
23
+ #define Kgrow(km, type, ptr, __i, __m) do { \
24
+ if ((__i) >= (__m)) { \
25
+ (__m) = (__i) + 1; \
26
+ (__m) += ((__m)>>1) + 16; \
27
+ (ptr) = (type*)krealloc(km, ptr, (__m) * sizeof(type)); \
28
+ } \
29
+ } while (0)
30
+ #endif
31
+
32
+ typedef struct {
33
+ int qlen, slen;
34
+ uint8_t shift, mdiff, max, size;
35
+ __m128i *qp, *H0, *H1, *E, *Hmax;
36
+ void *km;
37
+ } kswq_t;
38
+
39
+ /**
40
+ * Initialize the query data structure
41
+ *
42
+ * @param size Number of bytes used to store a score; valid valures are 1 or 2
43
+ * @param qlen Length of the query sequence
44
+ * @param query Query sequence
45
+ * @param m Size of the alphabet
46
+ * @param mat Scoring matrix in a one-dimension array
47
+ *
48
+ * @return Query data structure
49
+ */
50
+ void *ksw_ll_qinit(void *km, int size, int qlen, const uint8_t *query, int m, const int8_t *mat)
51
+ {
52
+ kswq_t *q;
53
+ int slen, a, tmp, p;
54
+
55
+ size = size > 1? 2 : 1;
56
+ p = 8 * (3 - size); // # values per __m128i
57
+ slen = (qlen + p - 1) / p; // segmented length
58
+ q = (kswq_t*)kmalloc(km, sizeof(kswq_t) + 256 + 16 * slen * (m + 4)); // a single block of memory
59
+ q->qp = (__m128i*)(((size_t)q + sizeof(kswq_t) + 15) >> 4 << 4); // align memory
60
+ q->H0 = q->qp + slen * m;
61
+ q->H1 = q->H0 + slen;
62
+ q->E = q->H1 + slen;
63
+ q->Hmax = q->E + slen;
64
+ q->slen = slen; q->qlen = qlen; q->size = size;
65
+ q->km = km;
66
+ // compute shift
67
+ tmp = m * m;
68
+ for (a = 0, q->shift = 127, q->mdiff = 0; a < tmp; ++a) { // find the minimum and maximum score
69
+ if (mat[a] < (int8_t)q->shift) q->shift = mat[a];
70
+ if (mat[a] > (int8_t)q->mdiff) q->mdiff = mat[a];
71
+ }
72
+ q->max = q->mdiff;
73
+ q->shift = 256 - q->shift; // NB: q->shift is uint8_t
74
+ q->mdiff += q->shift; // this is the difference between the min and max scores
75
+ // An example: p=8, qlen=19, slen=3 and segmentation:
76
+ // {{0,3,6,9,12,15,18,-1},{1,4,7,10,13,16,-1,-1},{2,5,8,11,14,17,-1,-1}}
77
+ if (size == 1) {
78
+ int8_t *t = (int8_t*)q->qp;
79
+ for (a = 0; a < m; ++a) {
80
+ int i, k, nlen = slen * p;
81
+ const int8_t *ma = mat + a * m;
82
+ for (i = 0; i < slen; ++i)
83
+ for (k = i; k < nlen; k += slen) // p iterations
84
+ *t++ = (k >= qlen? -1 : ma[query[k]]) + q->shift;
85
+ }
86
+ } else {
87
+ int16_t *t = (int16_t*)q->qp;
88
+ for (a = 0; a < m; ++a) {
89
+ int i, k, nlen = slen * p;
90
+ const int8_t *ma = mat + a * m;
91
+ for (i = 0; i < slen; ++i)
92
+ for (k = i; k < nlen; k += slen) // p iterations
93
+ *t++ = (k >= qlen? -1 : ma[query[k]]);
94
+ }
95
+ }
96
+ return q;
97
+ }
98
+
99
+ static inline int ksw_le_u8(__m128i a, __m128i b)
100
+ {
101
+ #if defined(__ARM_NEON)
102
+ return vmaxvq_u8(vqsubq_u8(a, b)) == 0;
103
+ #elif defined(__SSE2__)
104
+ return _mm_movemask_epi8(_mm_cmpeq_epi8(_mm_subs_epu8(a, b), _mm_setzero_si128())) == 0xffff;
105
+ #endif
106
+ }
107
+
108
+ static inline int ksw_max_u8(__m128i x)
109
+ {
110
+ #if defined(__ARM_NEON)
111
+ return vmaxvq_u8(x);
112
+ #elif defined(__SSE2__)
113
+ x = _mm_max_epu8(x, _mm_srli_si128(x, 8));
114
+ x = _mm_max_epu8(x, _mm_srli_si128(x, 4));
115
+ x = _mm_max_epu8(x, _mm_srli_si128(x, 2));
116
+ x = _mm_max_epu8(x, _mm_srli_si128(x, 1));
117
+ return _mm_extract_epi16(x, 0) & 0x00ff;
118
+ #endif
119
+ }
120
+
121
+ ksw_llrst_t ksw_ll_u8_core(void *q_, int tlen, const uint8_t *target, int _gapo, int _gape, int xtra)
122
+ {
123
+ kswq_t *q = (kswq_t*)q_;
124
+ int slen, i, m_b, n_b, te = -1, gmax = 0, minsc, endsc;
125
+ uint64_t *b;
126
+ __m128i gapoe, gape, shift, *H0, *H1, *E, *Hmax;
127
+ ksw_llrst_t r = { 0, -1, -1, -1, -1 };
128
+
129
+ // initialization
130
+ minsc = (xtra&KSW_LL_SUBO)? xtra&0xffff : 0x10000;
131
+ endsc = (xtra&KSW_LL_STOP)? xtra&0xffff : 0x10000;
132
+ m_b = n_b = 0; b = 0;
133
+ gapoe = _mm_set1_epi8(_gapo + _gape);
134
+ gape = _mm_set1_epi8(_gape);
135
+ shift = _mm_set1_epi8(q->shift);
136
+ H0 = q->H0; H1 = q->H1; E = q->E; Hmax = q->Hmax;
137
+ slen = q->slen;
138
+ memset(E, 0, slen * sizeof(__m128i));
139
+ memset(H0, 0, slen * sizeof(__m128i));
140
+ memset(Hmax, 0, slen * sizeof(__m128i));
141
+ // the core loop
142
+ for (i = 0; i < tlen; ++i) {
143
+ int j, k, imax;
144
+ __m128i e, h, t, f, max, *S = q->qp + target[i] * slen; // s is the 1st score vector
145
+ f = max = _mm_setzero_si128();
146
+ h = _mm_load_si128(H0 + slen - 1); // h={2,5,8,11,14,17,-1,-1} in the above example
147
+ h = _mm_slli_si128(h, 1); // h=H(i-1,-1); << instead of >> because x64 is little-endian
148
+ for (j = 0; LIKELY(j < slen); ++j) {
149
+ /* SW cells are computed in the following order:
150
+ * H(i,j) = max{H(i-1,j-1)+S(i,j), E(i,j), F(i,j)}
151
+ * E(i+1,j) = max{H(i,j)-q, E(i,j)-r}
152
+ * F(i,j+1) = max{H(i,j)-q, F(i,j)-r}
153
+ */
154
+ // compute H'(i,j); note that at the beginning, h=H'(i-1,j-1)
155
+ h = _mm_adds_epu8(h, _mm_load_si128(S + j));
156
+ h = _mm_subs_epu8(h, shift); // h=H'(i-1,j-1)+S(i,j)
157
+ e = _mm_load_si128(E + j); // e=E'(i,j)
158
+ h = _mm_max_epu8(h, e);
159
+ h = _mm_max_epu8(h, f); // h=H'(i,j)
160
+ max = _mm_max_epu8(max, h); // set max
161
+ _mm_store_si128(H1 + j, h); // save to H'(i,j)
162
+ // now compute E'(i+1,j)
163
+ e = _mm_subs_epu8(e, gape); // e=E'(i,j) - e_del
164
+ t = _mm_subs_epu8(h, gapoe); // h=H'(i,j) - o_del - e_del
165
+ e = _mm_max_epu8(e, t); // e=E'(i+1,j)
166
+ _mm_store_si128(E + j, e); // save to E'(i+1,j)
167
+ // now compute F'(i,j+1)
168
+ f = _mm_subs_epu8(f, gape);
169
+ t = _mm_subs_epu8(h, gapoe); // h=H'(i,j) - o_ins - e_ins
170
+ f = _mm_max_epu8(f, t);
171
+ // get H'(i-1,j) and prepare for the next j
172
+ h = _mm_load_si128(H0 + j); // h=H'(i-1,j)
173
+ }
174
+ // NB: we do not need to set E(i,j) as we disallow adjecent insertion and then deletion
175
+ for (k = 0; LIKELY(k < 16); ++k) { // this block mimics SWPS3; NB: H(i,j) updated in the lazy-F loop cannot exceed max
176
+ f = _mm_slli_si128(f, 1);
177
+ for (j = 0; LIKELY(j < slen); ++j) {
178
+ h = _mm_load_si128(H1 + j);
179
+ h = _mm_max_epu8(h, f); // h=H'(i,j)
180
+ _mm_store_si128(H1 + j, h);
181
+ h = _mm_subs_epu8(h, gapoe);
182
+ f = _mm_subs_epu8(f, gape);
183
+ if (UNLIKELY(ksw_le_u8(f, h))) goto end_loop_u8;
184
+ }
185
+ }
186
+ end_loop_u8:
187
+ imax = ksw_max_u8(max); // imax is the maximum number in max
188
+ if (imax >= minsc) { // write the b array; this condition adds branching unfornately
189
+ if (n_b == 0 || (int32_t)b[n_b-1] + 1 != i) { // then append
190
+ if (n_b == m_b) Kgrow(q->km, uint64_t, b, n_b, m_b);
191
+ b[n_b++] = (uint64_t)imax<<32 | i;
192
+ } else if ((int)(b[n_b-1]>>32) < imax) b[n_b-1] = (uint64_t)imax<<32 | i; // modify the last
193
+ }
194
+ if (imax > gmax) {
195
+ gmax = imax; te = i; // te is the end position on the target
196
+ for (j = 0; LIKELY(j < slen); ++j) // keep the H1 vector
197
+ _mm_store_si128(Hmax + j, _mm_load_si128(H1 + j));
198
+ if (gmax + q->shift >= 255 || gmax >= endsc) break;
199
+ }
200
+ S = H1; H1 = H0; H0 = S; // swap H0 and H1
201
+ }
202
+ r.score = gmax + q->shift < 255? gmax : 255;
203
+ r.te = te;
204
+ if (r.score != 255) { // get a->qe, the end of query match; find the 2nd best score
205
+ int max = -1, tmp, low, high, qlen = slen * 16;
206
+ uint8_t *t = (uint8_t*)Hmax;
207
+ for (i = 0; i < qlen; ++i, ++t)
208
+ if ((int)*t > max) max = *t, r.qe = i / 16 + i % 16 * slen;
209
+ else if ((int)*t == max && (tmp = i / 16 + i % 16 * slen) < r.qe) r.qe = tmp;
210
+ if (b) {
211
+ i = (r.score + q->max - 1) / q->max;
212
+ low = te - i; high = te + i;
213
+ for (i = 0; i < n_b; ++i) {
214
+ int e = (int32_t)b[i];
215
+ if ((e < low || e > high) && (int)(b[i]>>32) > r.score2)
216
+ r.score2 = b[i]>>32, r.te2 = e;
217
+ }
218
+ }
219
+ }
220
+ kfree(q->km, b);
221
+ return r;
222
+ }
223
+
224
+ static inline int ksw_le_epi16(__m128i a, __m128i b)
225
+ {
226
+ #if defined(__ARM_NEON)
227
+ return vmaxvq_u16(vcgtq_s16(vreinterpretq_s16_u8(a), vreinterpretq_s16_u8(b))) == 0;
228
+ #elif defined(__SSE2__)
229
+ return _mm_movemask_epi8(_mm_cmpgt_epi16(a, b)) == 0;
230
+ #endif
231
+ }
232
+
233
+ static inline int ksw_max_i16(__m128i x)
234
+ {
235
+ #if defined(__ARM_NEON)
236
+ return vmaxvq_s16(vreinterpretq_s16_u8(x));
237
+ #elif defined(__SSE2__)
238
+ x = _mm_max_epi16(x, _mm_srli_si128(x, 8));
239
+ x = _mm_max_epi16(x, _mm_srli_si128(x, 4));
240
+ x = _mm_max_epi16(x, _mm_srli_si128(x, 2));
241
+ return _mm_extract_epi16(x, 0);
242
+ #endif
243
+ }
244
+
245
+ ksw_llrst_t ksw_ll_i16_core(void *q_, int tlen, const uint8_t *target, int _gapo, int _gape, int xtra)
246
+ {
247
+ kswq_t *q = (kswq_t*)q_;
248
+ int slen, i, m_b, n_b, te = -1, gmax = 0, minsc, endsc;
249
+ uint64_t *b;
250
+ __m128i gapoe, gape, *H0, *H1, *E, *Hmax;
251
+ ksw_llrst_t r = { 0, -1, -1, -1, -1 };
252
+
253
+ // initialization
254
+ minsc = (xtra&KSW_LL_SUBO)? xtra&0xffff : 0x10000;
255
+ endsc = (xtra&KSW_LL_STOP)? xtra&0xffff : 0x10000;
256
+ m_b = n_b = 0; b = 0;
257
+ gapoe = _mm_set1_epi16(_gapo + _gape);
258
+ gape = _mm_set1_epi16(_gape);
259
+ H0 = q->H0; H1 = q->H1; E = q->E; Hmax = q->Hmax;
260
+ slen = q->slen;
261
+ memset(E, 0, slen * sizeof(__m128i));
262
+ memset(H0, 0, slen * sizeof(__m128i));
263
+ memset(Hmax, 0, slen * sizeof(__m128i));
264
+ // the core loop
265
+ for (i = 0; i < tlen; ++i) {
266
+ int j, k, imax;
267
+ __m128i e, t, h, f, max, *S = q->qp + target[i] * slen; // s is the 1st score vector
268
+ f = max = _mm_setzero_si128();
269
+ h = _mm_load_si128(H0 + slen - 1); // h={2,5,8,11,14,17,-1,-1} in the above example
270
+ h = _mm_slli_si128(h, 2);
271
+ for (j = 0; LIKELY(j < slen); ++j) {
272
+ h = _mm_adds_epi16(h, _mm_load_si128(S++));
273
+ e = _mm_load_si128(E + j);
274
+ h = _mm_max_epi16(h, e);
275
+ h = _mm_max_epi16(h, f);
276
+ max = _mm_max_epi16(max, h);
277
+ _mm_store_si128(H1 + j, h);
278
+ e = _mm_subs_epu16(e, gape);
279
+ t = _mm_subs_epu16(h, gapoe);
280
+ e = _mm_max_epi16(e, t);
281
+ _mm_store_si128(E + j, e);
282
+ f = _mm_subs_epu16(f, gape);
283
+ t = _mm_subs_epu16(h, gapoe);
284
+ f = _mm_max_epi16(f, t);
285
+ h = _mm_load_si128(H0 + j);
286
+ }
287
+ for (k = 0; LIKELY(k < 16); ++k) {
288
+ f = _mm_slli_si128(f, 2);
289
+ for (j = 0; LIKELY(j < slen); ++j) {
290
+ h = _mm_load_si128(H1 + j);
291
+ h = _mm_max_epi16(h, f);
292
+ _mm_store_si128(H1 + j, h);
293
+ h = _mm_subs_epu16(h, gapoe);
294
+ f = _mm_subs_epu16(f, gape);
295
+ if (UNLIKELY(ksw_le_epi16(f, h))) goto end_loop_i16;
296
+ }
297
+ }
298
+ end_loop_i16:
299
+ imax = ksw_max_i16(max);
300
+ if (imax >= minsc) {
301
+ if (n_b == 0 || (int32_t)b[n_b-1] + 1 != i) {
302
+ if (n_b == m_b) Kgrow(q->km, uint64_t, b, n_b, m_b);
303
+ b[n_b++] = (uint64_t)imax<<32 | i;
304
+ } else if ((int)(b[n_b-1]>>32) < imax) b[n_b-1] = (uint64_t)imax<<32 | i; // modify the last
305
+ }
306
+ if (imax > gmax) {
307
+ gmax = imax; te = i;
308
+ for (j = 0; LIKELY(j < slen); ++j)
309
+ _mm_store_si128(Hmax + j, _mm_load_si128(H1 + j));
310
+ if (gmax >= endsc) break;
311
+ }
312
+ S = H1; H1 = H0; H0 = S;
313
+ }
314
+ r.score = gmax; r.te = te;
315
+ {
316
+ int max = -1, tmp, low, high, qlen = slen * 8;
317
+ uint16_t *t = (uint16_t*)Hmax;
318
+ for (i = 0, r.qe = -1; i < qlen; ++i, ++t)
319
+ if ((int)*t > max) max = *t, r.qe = i / 8 + i % 8 * slen;
320
+ else if ((int)*t == max && (tmp = i / 8 + i % 8 * slen) < r.qe) r.qe = tmp;
321
+ if (b) {
322
+ i = (r.score + q->max - 1) / q->max;
323
+ low = te - i; high = te + i;
324
+ for (i = 0; i < n_b; ++i) {
325
+ int e = (int32_t)b[i];
326
+ if ((e < low || e > high) && (int)(b[i]>>32) > r.score2)
327
+ r.score2 = b[i]>>32, r.te2 = e;
328
+ }
329
+ }
330
+ }
331
+ kfree(q->km, b);
332
+ return r;
333
+ }
334
+
335
+ int ksw_ll_i16(void *q_, int tlen, const uint8_t *target, int _gapo, int _gape, int *qe, int *te)
336
+ {
337
+ ksw_llrst_t r;
338
+ r = ksw_ll_i16_core(q_, tlen, target, _gapo, _gape, 0);
339
+ *qe = r.qe, *te = r.te;
340
+ return r.score;
341
+ }
@@ -0,0 +1,15 @@
1
+ #ifndef KTHREAD_H
2
+ #define KTHREAD_H
3
+
4
+ #ifdef __cplusplus
5
+ extern "C" {
6
+ #endif
7
+
8
+ void kt_for(int n_threads, void (*func)(void*,long,int), void *data, long n);
9
+ void kt_pipeline(int n_threads, void *(*func)(void*, int, void*), void *shared_data, int n_steps);
10
+
11
+ #ifdef __cplusplus
12
+ }
13
+ #endif
14
+
15
+ #endif